xref: /third_party/skia/src/core/SkStream.cpp (revision cb93a386)
1/*
2 * Copyright 2006 The Android Open Source Project
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#include "include/core/SkStream.h"
9
10#include "include/core/SkData.h"
11#include "include/core/SkString.h"
12#include "include/core/SkTypes.h"
13#include "include/private/SkFixed.h"
14#include "include/private/SkTFitsIn.h"
15#include "include/private/SkTPin.h"
16#include "include/private/SkTo.h"
17#include "src/core/SkOSFile.h"
18#include "src/core/SkSafeMath.h"
19#include "src/core/SkStreamPriv.h"
20
21#include <limits>
22
23///////////////////////////////////////////////////////////////////////////////
24
25bool SkStream::readS8(int8_t* i) {
26    return this->read(i, sizeof(*i)) == sizeof(*i);
27}
28
29bool SkStream::readS16(int16_t* i) {
30    return this->read(i, sizeof(*i)) == sizeof(*i);
31}
32
33bool SkStream::readS32(int32_t* i) {
34    return this->read(i, sizeof(*i)) == sizeof(*i);
35}
36
37bool SkStream::readScalar(SkScalar* i) {
38    return this->read(i, sizeof(*i)) == sizeof(*i);
39}
40
41#define SK_MAX_BYTE_FOR_U8          0xFD
42#define SK_BYTE_SENTINEL_FOR_U16    0xFE
43#define SK_BYTE_SENTINEL_FOR_U32    0xFF
44
45bool SkStream::readPackedUInt(size_t* i) {
46    uint8_t byte;
47    if (!this->read(&byte, 1)) {
48        return false;
49    }
50    if (SK_BYTE_SENTINEL_FOR_U16 == byte) {
51        uint16_t i16;
52        if (!this->readU16(&i16)) { return false; }
53        *i = i16;
54    } else if (SK_BYTE_SENTINEL_FOR_U32 == byte) {
55        uint32_t i32;
56        if (!this->readU32(&i32)) { return false; }
57        *i = i32;
58    } else {
59        *i = byte;
60    }
61    return true;
62}
63
64//////////////////////////////////////////////////////////////////////////////////////
65
66SkWStream::~SkWStream()
67{
68}
69
70void SkWStream::flush()
71{
72}
73
74bool SkWStream::writeDecAsText(int32_t dec)
75{
76    char buffer[kSkStrAppendS32_MaxSize];
77    char* stop = SkStrAppendS32(buffer, dec);
78    return this->write(buffer, stop - buffer);
79}
80
81bool SkWStream::writeBigDecAsText(int64_t dec, int minDigits)
82{
83    char buffer[kSkStrAppendU64_MaxSize];
84    char* stop = SkStrAppendU64(buffer, dec, minDigits);
85    return this->write(buffer, stop - buffer);
86}
87
88bool SkWStream::writeHexAsText(uint32_t hex, int digits)
89{
90    SkString    tmp;
91    tmp.appendHex(hex, digits);
92    return this->write(tmp.c_str(), tmp.size());
93}
94
95bool SkWStream::writeScalarAsText(SkScalar value)
96{
97    char buffer[kSkStrAppendScalar_MaxSize];
98    char* stop = SkStrAppendScalar(buffer, value);
99    return this->write(buffer, stop - buffer);
100}
101
102bool SkWStream::writeScalar(SkScalar value) {
103    return this->write(&value, sizeof(value));
104}
105
106int SkWStream::SizeOfPackedUInt(size_t value) {
107    if (value <= SK_MAX_BYTE_FOR_U8) {
108        return 1;
109    } else if (value <= 0xFFFF) {
110        return 3;
111    }
112    return 5;
113}
114
115bool SkWStream::writePackedUInt(size_t value) {
116    uint8_t data[5];
117    size_t len = 1;
118    if (value <= SK_MAX_BYTE_FOR_U8) {
119        data[0] = value;
120        len = 1;
121    } else if (value <= 0xFFFF) {
122        uint16_t value16 = value;
123        data[0] = SK_BYTE_SENTINEL_FOR_U16;
124        memcpy(&data[1], &value16, 2);
125        len = 3;
126    } else {
127        uint32_t value32 = SkToU32(value);
128        data[0] = SK_BYTE_SENTINEL_FOR_U32;
129        memcpy(&data[1], &value32, 4);
130        len = 5;
131    }
132    return this->write(data, len);
133}
134
135bool SkWStream::writeStream(SkStream* stream, size_t length) {
136    char scratch[1024];
137    const size_t MAX = sizeof(scratch);
138
139    while (length != 0) {
140        size_t n = length;
141        if (n > MAX) {
142            n = MAX;
143        }
144        stream->read(scratch, n);
145        if (!this->write(scratch, n)) {
146            return false;
147        }
148        length -= n;
149    }
150    return true;
151}
152
153///////////////////////////////////////////////////////////////////////////////
154
155SkFILEStream::SkFILEStream(std::shared_ptr<FILE> file, size_t end, size_t start, size_t current)
156    : fFILE(std::move(file))
157    , fEnd(end)
158    , fStart(std::min(start, fEnd))
159    , fCurrent(SkTPin(current, fStart, fEnd))
160{
161    SkASSERT(fStart == start);
162    SkASSERT(fCurrent == current);
163}
164
165SkFILEStream::SkFILEStream(std::shared_ptr<FILE> file, size_t end, size_t start)
166    : SkFILEStream(std::move(file), end, start, start)
167{ }
168
169SkFILEStream::SkFILEStream(FILE* file, size_t size, size_t start)
170    : SkFILEStream(std::shared_ptr<FILE>(file, sk_fclose), SkSafeMath::Add(start, size), start)
171{ }
172
173SkFILEStream::SkFILEStream(FILE* file, size_t size)
174    : SkFILEStream(file, size, file ? sk_ftell(file) : 0)
175{ }
176
177SkFILEStream::SkFILEStream(FILE* file)
178    : SkFILEStream(std::shared_ptr<FILE>(file, sk_fclose),
179                   file ? sk_fgetsize(file) : 0,
180                   file ? sk_ftell(file) : 0)
181{ }
182
183SkFILEStream::SkFILEStream(const char path[])
184    : SkFILEStream(path ? sk_fopen(path, kRead_SkFILE_Flag) : nullptr)
185{ }
186
187SkFILEStream::~SkFILEStream() {
188    this->close();
189}
190
191void SkFILEStream::close() {
192    fFILE.reset();
193    fEnd = 0;
194    fStart = 0;
195    fCurrent = 0;
196}
197
198size_t SkFILEStream::read(void* buffer, size_t size) {
199    if (size > fEnd - fCurrent) {
200        size = fEnd - fCurrent;
201    }
202    size_t bytesRead = size;
203    if (buffer) {
204        bytesRead = sk_qread(fFILE.get(), buffer, size, fCurrent);
205    }
206    if (bytesRead == SIZE_MAX) {
207        return 0;
208    }
209    fCurrent += bytesRead;
210    return bytesRead;
211}
212
213bool SkFILEStream::isAtEnd() const {
214    if (fCurrent == fEnd) {
215        return true;
216    }
217    return fCurrent >= sk_fgetsize(fFILE.get());
218}
219
220bool SkFILEStream::rewind() {
221    fCurrent = fStart;
222    return true;
223}
224
225SkStreamAsset* SkFILEStream::onDuplicate() const {
226    return new SkFILEStream(fFILE, fEnd, fStart, fStart);
227}
228
229size_t SkFILEStream::getPosition() const {
230    SkASSERT(fCurrent >= fStart);
231    return fCurrent - fStart;
232}
233
234bool SkFILEStream::seek(size_t position) {
235    fCurrent = std::min(SkSafeMath::Add(position, fStart), fEnd);
236    return true;
237}
238
239bool SkFILEStream::move(long offset) {
240    if (offset < 0) {
241        if (offset == std::numeric_limits<long>::min() ||
242            !SkTFitsIn<size_t>(-offset) ||
243            (size_t) (-offset) >= this->getPosition())
244        {
245            fCurrent = fStart;
246        } else {
247            fCurrent += offset;
248        }
249    } else if (!SkTFitsIn<size_t>(offset)) {
250        fCurrent = fEnd;
251    } else {
252        fCurrent = std::min(SkSafeMath::Add(fCurrent, (size_t) offset), fEnd);
253    }
254
255    SkASSERT(fCurrent >= fStart && fCurrent <= fEnd);
256    return true;
257}
258
259SkStreamAsset* SkFILEStream::onFork() const {
260    return new SkFILEStream(fFILE, fEnd, fStart, fCurrent);
261}
262
263size_t SkFILEStream::getLength() const {
264    return fEnd - fStart;
265}
266
267///////////////////////////////////////////////////////////////////////////////
268
269static sk_sp<SkData> newFromParams(const void* src, size_t size, bool copyData) {
270    if (copyData) {
271        return SkData::MakeWithCopy(src, size);
272    } else {
273        return SkData::MakeWithoutCopy(src, size);
274    }
275}
276
277SkMemoryStream::SkMemoryStream() {
278    fData = SkData::MakeEmpty();
279    fOffset = 0;
280}
281
282SkMemoryStream::SkMemoryStream(size_t size) {
283    fData = SkData::MakeUninitialized(size);
284    fOffset = 0;
285}
286
287SkMemoryStream::SkMemoryStream(const void* src, size_t size, bool copyData) {
288    fData = newFromParams(src, size, copyData);
289    fOffset = 0;
290}
291
292SkMemoryStream::SkMemoryStream(sk_sp<SkData> data) : fData(std::move(data)) {
293    if (nullptr == fData) {
294        fData = SkData::MakeEmpty();
295    }
296    fOffset = 0;
297}
298
299std::unique_ptr<SkMemoryStream> SkMemoryStream::MakeCopy(const void* data, size_t length) {
300    return std::make_unique<SkMemoryStream>(data, length, true);
301}
302
303std::unique_ptr<SkMemoryStream> SkMemoryStream::MakeDirect(const void* data, size_t length) {
304    return std::make_unique<SkMemoryStream>(data, length, false);
305}
306
307std::unique_ptr<SkMemoryStream> SkMemoryStream::Make(sk_sp<SkData> data) {
308    return std::make_unique<SkMemoryStream>(std::move(data));
309}
310
311void SkMemoryStream::setMemoryOwned(const void* src, size_t size) {
312    fData = SkData::MakeFromMalloc(src, size);
313    fOffset = 0;
314}
315
316void SkMemoryStream::setMemory(const void* src, size_t size, bool copyData) {
317    fData = newFromParams(src, size, copyData);
318    fOffset = 0;
319}
320
321void SkMemoryStream::setData(sk_sp<SkData> data) {
322    if (nullptr == data) {
323        fData = SkData::MakeEmpty();
324    } else {
325        fData = data;
326    }
327    fOffset = 0;
328}
329
330void SkMemoryStream::skipToAlign4() {
331    // cast to remove unary-minus warning
332    fOffset += -(int)fOffset & 0x03;
333}
334
335size_t SkMemoryStream::read(void* buffer, size_t size) {
336    size_t dataSize = fData->size();
337
338    if (size > dataSize - fOffset) {
339        size = dataSize - fOffset;
340    }
341    if (buffer) {
342        memcpy(buffer, fData->bytes() + fOffset, size);
343    }
344    fOffset += size;
345    return size;
346}
347
348size_t SkMemoryStream::peek(void* buffer, size_t size) const {
349    SkASSERT(buffer != nullptr);
350
351    const size_t currentOffset = fOffset;
352    SkMemoryStream* nonConstThis = const_cast<SkMemoryStream*>(this);
353    const size_t bytesRead = nonConstThis->read(buffer, size);
354    nonConstThis->fOffset = currentOffset;
355    return bytesRead;
356}
357
358bool SkMemoryStream::isAtEnd() const {
359    return fOffset == fData->size();
360}
361
362bool SkMemoryStream::rewind() {
363    fOffset = 0;
364    return true;
365}
366
367SkMemoryStream* SkMemoryStream::onDuplicate() const {
368    return new SkMemoryStream(fData);
369}
370
371size_t SkMemoryStream::getPosition() const {
372    return fOffset;
373}
374
375bool SkMemoryStream::seek(size_t position) {
376    fOffset = position > fData->size()
377            ? fData->size()
378            : position;
379    return true;
380}
381
382bool SkMemoryStream::move(long offset) {
383    return this->seek(fOffset + offset);
384}
385
386SkMemoryStream* SkMemoryStream::onFork() const {
387    std::unique_ptr<SkMemoryStream> that(this->duplicate());
388    that->seek(fOffset);
389    return that.release();
390}
391
392size_t SkMemoryStream::getLength() const {
393    return fData->size();
394}
395
396const void* SkMemoryStream::getMemoryBase() {
397    return fData->data();
398}
399
400const void* SkMemoryStream::getAtPos() {
401    return fData->bytes() + fOffset;
402}
403
404/////////////////////////////////////////////////////////////////////////////////////////////////////////
405/////////////////////////////////////////////////////////////////////////////////////////////////////////
406
407SkFILEWStream::SkFILEWStream(const char path[])
408{
409    fFILE = sk_fopen(path, kWrite_SkFILE_Flag);
410}
411
412SkFILEWStream::~SkFILEWStream()
413{
414    if (fFILE) {
415        sk_fclose(fFILE);
416    }
417}
418
419size_t SkFILEWStream::bytesWritten() const {
420    return sk_ftell(fFILE);
421}
422
423bool SkFILEWStream::write(const void* buffer, size_t size)
424{
425    if (fFILE == nullptr) {
426        return false;
427    }
428
429    if (sk_fwrite(buffer, size, fFILE) != size)
430    {
431        SkDEBUGCODE(SkDebugf("SkFILEWStream failed writing %zu bytes\n", size);)
432        sk_fclose(fFILE);
433        fFILE = nullptr;
434        return false;
435    }
436    return true;
437}
438
439void SkFILEWStream::flush()
440{
441    if (fFILE) {
442        sk_fflush(fFILE);
443    }
444}
445
446void SkFILEWStream::fsync()
447{
448    flush();
449    if (fFILE) {
450        sk_fsync(fFILE);
451    }
452}
453
454////////////////////////////////////////////////////////////////////////
455
456static inline void sk_memcpy_4bytes(void* dst, const void* src, size_t size) {
457    if (size == 4) {
458        memcpy(dst, src, 4);
459    } else {
460        memcpy(dst, src, size);
461    }
462}
463
464#define SkDynamicMemoryWStream_MinBlockSize   4096
465
466struct SkDynamicMemoryWStream::Block {
467    Block*  fNext;
468    char*   fCurr;
469    char*   fStop;
470
471    const char* start() const { return (const char*)(this + 1); }
472    char*   start() { return (char*)(this + 1); }
473    size_t  avail() const { return fStop - fCurr; }
474    size_t  written() const { return fCurr - this->start(); }
475
476    void init(size_t size) {
477        fNext = nullptr;
478        fCurr = this->start();
479        fStop = this->start() + size;
480    }
481
482    const void* append(const void* data, size_t size) {
483        SkASSERT((size_t)(fStop - fCurr) >= size);
484        sk_memcpy_4bytes(fCurr, data, size);
485        fCurr += size;
486        return (const void*)((const char*)data + size);
487    }
488};
489
490SkDynamicMemoryWStream::SkDynamicMemoryWStream(SkDynamicMemoryWStream&& other)
491    : fHead(other.fHead)
492    , fTail(other.fTail)
493    , fBytesWrittenBeforeTail(other.fBytesWrittenBeforeTail)
494{
495    other.fHead = nullptr;
496    other.fTail = nullptr;
497    other.fBytesWrittenBeforeTail = 0;
498}
499
500SkDynamicMemoryWStream& SkDynamicMemoryWStream::operator=(SkDynamicMemoryWStream&& other) {
501    if (this != &other) {
502        this->~SkDynamicMemoryWStream();
503        new (this) SkDynamicMemoryWStream(std::move(other));
504    }
505    return *this;
506}
507
508SkDynamicMemoryWStream::~SkDynamicMemoryWStream() {
509    this->reset();
510}
511
512void SkDynamicMemoryWStream::reset() {
513    Block* block = fHead;
514    while (block != nullptr) {
515        Block* next = block->fNext;
516        sk_free(block);
517        block = next;
518    }
519    fHead = fTail = nullptr;
520    fBytesWrittenBeforeTail = 0;
521}
522
523size_t SkDynamicMemoryWStream::bytesWritten() const {
524    this->validate();
525
526    if (fTail) {
527        return fBytesWrittenBeforeTail + fTail->written();
528    }
529    return 0;
530}
531
532bool SkDynamicMemoryWStream::write(const void* buffer, size_t count) {
533    if (count > 0) {
534        SkASSERT(buffer);
535        size_t size;
536
537        if (fTail) {
538            if (fTail->avail() > 0) {
539                size = std::min(fTail->avail(), count);
540                buffer = fTail->append(buffer, size);
541                SkASSERT(count >= size);
542                count -= size;
543                if (count == 0) {
544                    return true;
545                }
546            }
547            // If we get here, we've just exhausted fTail, so update our tracker
548            fBytesWrittenBeforeTail += fTail->written();
549        }
550
551        size = std::max<size_t>(count, SkDynamicMemoryWStream_MinBlockSize - sizeof(Block));
552        size = SkAlign4(size);  // ensure we're always a multiple of 4 (see padToAlign4())
553
554        Block* block = (Block*)sk_malloc_throw(sizeof(Block) + size);
555        block->init(size);
556        block->append(buffer, count);
557
558        if (fTail != nullptr) {
559            fTail->fNext = block;
560        } else {
561            fHead = fTail = block;
562        }
563        fTail = block;
564        this->validate();
565    }
566    return true;
567}
568
569bool SkDynamicMemoryWStream::writeToAndReset(SkDynamicMemoryWStream* dst) {
570    SkASSERT(dst);
571    SkASSERT(dst != this);
572    if (0 == this->bytesWritten()) {
573        return true;
574    }
575    if (0 == dst->bytesWritten()) {
576        *dst = std::move(*this);
577        return true;
578    }
579    dst->fTail->fNext = fHead;
580    dst->fBytesWrittenBeforeTail += fBytesWrittenBeforeTail + dst->fTail->written();
581    dst->fTail = fTail;
582    fHead = fTail = nullptr;
583    fBytesWrittenBeforeTail = 0;
584    return true;
585}
586
587void SkDynamicMemoryWStream::prependToAndReset(SkDynamicMemoryWStream* dst) {
588    SkASSERT(dst);
589    SkASSERT(dst != this);
590    if (0 == this->bytesWritten()) {
591        return;
592    }
593    if (0 == dst->bytesWritten()) {
594        *dst = std::move(*this);
595        return;
596    }
597    fTail->fNext = dst->fHead;
598    dst->fHead = fHead;
599    dst->fBytesWrittenBeforeTail += fBytesWrittenBeforeTail + fTail->written();
600    fHead = fTail = nullptr;
601    fBytesWrittenBeforeTail = 0;
602    return;
603}
604
605
606bool SkDynamicMemoryWStream::read(void* buffer, size_t offset, size_t count) {
607    if (offset + count > this->bytesWritten()) {
608        return false; // test does not partially modify
609    }
610    Block* block = fHead;
611    while (block != nullptr) {
612        size_t size = block->written();
613        if (offset < size) {
614            size_t part = offset + count > size ? size - offset : count;
615            memcpy(buffer, block->start() + offset, part);
616            if (count <= part) {
617                return true;
618            }
619            count -= part;
620            buffer = (void*) ((char* ) buffer + part);
621        }
622        offset = offset > size ? offset - size : 0;
623        block = block->fNext;
624    }
625    return false;
626}
627
628void SkDynamicMemoryWStream::copyTo(void* dst) const {
629    SkASSERT(dst);
630    Block* block = fHead;
631    while (block != nullptr) {
632        size_t size = block->written();
633        memcpy(dst, block->start(), size);
634        dst = (void*)((char*)dst + size);
635        block = block->fNext;
636    }
637}
638
639bool SkDynamicMemoryWStream::writeToStream(SkWStream* dst) const {
640    SkASSERT(dst);
641    for (Block* block = fHead; block != nullptr; block = block->fNext) {
642        if (!dst->write(block->start(), block->written())) {
643            return false;
644        }
645    }
646    return true;
647}
648
649void SkDynamicMemoryWStream::padToAlign4() {
650    // The contract is to write zeros until the entire stream has written a multiple of 4 bytes.
651    // Our Blocks are guaranteed always be (a) full (except the tail) and (b) a multiple of 4
652    // so it is sufficient to just examine the tail (if present).
653
654    if (fTail) {
655        // cast to remove unary-minus warning
656        int padBytes = -(int)fTail->written() & 0x03;
657        if (padBytes) {
658            int zero = 0;
659            fTail->append(&zero, padBytes);
660        }
661    }
662}
663
664
665void SkDynamicMemoryWStream::copyToAndReset(void* ptr) {
666    if (!ptr) {
667        this->reset();
668        return;
669    }
670    // By looping through the source and freeing as we copy, we
671    // can reduce real memory use with large streams.
672    char* dst = reinterpret_cast<char*>(ptr);
673    Block* block = fHead;
674    while (block != nullptr) {
675        size_t len = block->written();
676        memcpy(dst, block->start(), len);
677        dst += len;
678        Block* next = block->fNext;
679        sk_free(block);
680        block = next;
681    }
682    fHead = fTail = nullptr;
683    fBytesWrittenBeforeTail = 0;
684}
685
686bool SkDynamicMemoryWStream::writeToAndReset(SkWStream* dst) {
687    SkASSERT(dst);
688    // By looping through the source and freeing as we copy, we
689    // can reduce real memory use with large streams.
690    bool dstStreamGood = true;
691    for (Block* block = fHead; block != nullptr; ) {
692        if (dstStreamGood && !dst->write(block->start(), block->written())) {
693            dstStreamGood = false;
694        }
695        Block* next = block->fNext;
696        sk_free(block);
697        block = next;
698    }
699    fHead = fTail = nullptr;
700    fBytesWrittenBeforeTail = 0;
701    return dstStreamGood;
702}
703
704sk_sp<SkData> SkDynamicMemoryWStream::detachAsData() {
705    const size_t size = this->bytesWritten();
706    if (0 == size) {
707        return SkData::MakeEmpty();
708    }
709    sk_sp<SkData> data = SkData::MakeUninitialized(size);
710    this->copyToAndReset(data->writable_data());
711    return data;
712}
713
714#ifdef SK_DEBUG
715void SkDynamicMemoryWStream::validate() const {
716    if (!fHead) {
717        SkASSERT(!fTail);
718        SkASSERT(fBytesWrittenBeforeTail == 0);
719        return;
720    }
721    SkASSERT(fTail);
722
723    size_t bytes = 0;
724    const Block* block = fHead;
725    while (block) {
726        if (block->fNext) {
727            bytes += block->written();
728        }
729        block = block->fNext;
730    }
731    SkASSERT(bytes == fBytesWrittenBeforeTail);
732}
733#endif
734
735////////////////////////////////////////////////////////////////////////////////////////////////
736
737class SkBlockMemoryRefCnt : public SkRefCnt {
738public:
739    explicit SkBlockMemoryRefCnt(SkDynamicMemoryWStream::Block* head) : fHead(head) { }
740
741    ~SkBlockMemoryRefCnt() override {
742        SkDynamicMemoryWStream::Block* block = fHead;
743        while (block != nullptr) {
744            SkDynamicMemoryWStream::Block* next = block->fNext;
745            sk_free(block);
746            block = next;
747        }
748    }
749
750    SkDynamicMemoryWStream::Block* const fHead;
751};
752
753class SkBlockMemoryStream : public SkStreamAsset {
754public:
755    SkBlockMemoryStream(sk_sp<SkBlockMemoryRefCnt> headRef, size_t size)
756        : fBlockMemory(std::move(headRef)), fCurrent(fBlockMemory->fHead)
757        , fSize(size) , fOffset(0), fCurrentOffset(0) { }
758
759    size_t read(void* buffer, size_t rawCount) override {
760        size_t count = rawCount;
761        if (fOffset + count > fSize) {
762            count = fSize - fOffset;
763        }
764        size_t bytesLeftToRead = count;
765        while (fCurrent != nullptr) {
766            size_t bytesLeftInCurrent = fCurrent->written() - fCurrentOffset;
767            size_t bytesFromCurrent = std::min(bytesLeftToRead, bytesLeftInCurrent);
768            if (buffer) {
769                memcpy(buffer, fCurrent->start() + fCurrentOffset, bytesFromCurrent);
770                buffer = SkTAddOffset<void>(buffer, bytesFromCurrent);
771            }
772            if (bytesLeftToRead <= bytesFromCurrent) {
773                fCurrentOffset += bytesFromCurrent;
774                fOffset += count;
775                return count;
776            }
777            bytesLeftToRead -= bytesFromCurrent;
778            fCurrent = fCurrent->fNext;
779            fCurrentOffset = 0;
780        }
781        SkASSERT(false);
782        return 0;
783    }
784
785    bool isAtEnd() const override {
786        return fOffset == fSize;
787    }
788
789    size_t peek(void* buff, size_t bytesToPeek) const override {
790        SkASSERT(buff != nullptr);
791
792        bytesToPeek = std::min(bytesToPeek, fSize - fOffset);
793
794        size_t bytesLeftToPeek = bytesToPeek;
795        char* buffer = static_cast<char*>(buff);
796        const SkDynamicMemoryWStream::Block* current = fCurrent;
797        size_t currentOffset = fCurrentOffset;
798        while (bytesLeftToPeek) {
799            SkASSERT(current);
800            size_t bytesFromCurrent = std::min(current->written() - currentOffset, bytesLeftToPeek);
801            memcpy(buffer, current->start() + currentOffset, bytesFromCurrent);
802            bytesLeftToPeek -= bytesFromCurrent;
803            buffer += bytesFromCurrent;
804            current = current->fNext;
805            currentOffset = 0;
806        }
807        return bytesToPeek;
808    }
809
810    bool rewind() override {
811        fCurrent = fBlockMemory->fHead;
812        fOffset = 0;
813        fCurrentOffset = 0;
814        return true;
815    }
816
817    SkBlockMemoryStream* onDuplicate() const override {
818        return new SkBlockMemoryStream(fBlockMemory, fSize);
819    }
820
821    size_t getPosition() const override {
822        return fOffset;
823    }
824
825    bool seek(size_t position) override {
826        // If possible, skip forward.
827        if (position >= fOffset) {
828            size_t skipAmount = position - fOffset;
829            return this->skip(skipAmount) == skipAmount;
830        }
831        // If possible, move backward within the current block.
832        size_t moveBackAmount = fOffset - position;
833        if (moveBackAmount <= fCurrentOffset) {
834            fCurrentOffset -= moveBackAmount;
835            fOffset -= moveBackAmount;
836            return true;
837        }
838        // Otherwise rewind and move forward.
839        return this->rewind() && this->skip(position) == position;
840    }
841
842    bool move(long offset) override {
843        return seek(fOffset + offset);
844    }
845
846    SkBlockMemoryStream* onFork() const override {
847        SkBlockMemoryStream* that = this->onDuplicate();
848        that->fCurrent = this->fCurrent;
849        that->fOffset = this->fOffset;
850        that->fCurrentOffset = this->fCurrentOffset;
851        return that;
852    }
853
854    size_t getLength() const override {
855        return fSize;
856    }
857
858    const void* getMemoryBase() override {
859        if (fBlockMemory->fHead && !fBlockMemory->fHead->fNext) {
860            return fBlockMemory->fHead->start();
861        }
862        return nullptr;
863    }
864
865private:
866    sk_sp<SkBlockMemoryRefCnt> const fBlockMemory;
867    SkDynamicMemoryWStream::Block const * fCurrent;
868    size_t const fSize;
869    size_t fOffset;
870    size_t fCurrentOffset;
871};
872
873std::unique_ptr<SkStreamAsset> SkDynamicMemoryWStream::detachAsStream() {
874    if (nullptr == fHead) {
875        // no need to reset.
876        return SkMemoryStream::Make(nullptr);
877    }
878    if (fHead == fTail) {  // one block, may be worth shrinking.
879        ptrdiff_t used = fTail->fCurr - (char*)fTail;
880        fHead = fTail = (SkDynamicMemoryWStream::Block*)sk_realloc_throw(fTail, SkToSizeT(used));
881        fTail->fStop = fTail->fCurr = (char*)fTail + used;  // Update pointers.
882        SkASSERT(nullptr == fTail->fNext);
883        SkASSERT(0 == fBytesWrittenBeforeTail);
884    }
885    std::unique_ptr<SkStreamAsset> stream
886            = std::make_unique<SkBlockMemoryStream>(sk_make_sp<SkBlockMemoryRefCnt>(fHead),
887                                                      this->bytesWritten());
888    fHead = nullptr;    // signal reset() to not free anything
889    this->reset();
890    return stream;
891}
892
893///////////////////////////////////////////////////////////////////////////////
894///////////////////////////////////////////////////////////////////////////////
895
896static sk_sp<SkData> mmap_filename(const char path[]) {
897    FILE* file = sk_fopen(path, kRead_SkFILE_Flag);
898    if (nullptr == file) {
899        return nullptr;
900    }
901
902    auto data = SkData::MakeFromFILE(file);
903    sk_fclose(file);
904    return data;
905}
906
907std::unique_ptr<SkStreamAsset> SkStream::MakeFromFile(const char path[]) {
908    auto data(mmap_filename(path));
909    if (data) {
910        return std::make_unique<SkMemoryStream>(std::move(data));
911    }
912
913    // If we get here, then our attempt at using mmap failed, so try normal file access.
914    auto stream = std::make_unique<SkFILEStream>(path);
915    if (!stream->isValid()) {
916        return nullptr;
917    }
918    return std::move(stream);
919}
920
921// Declared in SkStreamPriv.h:
922sk_sp<SkData> SkCopyStreamToData(SkStream* stream) {
923    SkASSERT(stream != nullptr);
924
925    if (stream->hasLength()) {
926        return SkData::MakeFromStream(stream, stream->getLength());
927    }
928
929    SkDynamicMemoryWStream tempStream;
930    const size_t bufferSize = 4096;
931    char buffer[bufferSize];
932    do {
933        size_t bytesRead = stream->read(buffer, bufferSize);
934        tempStream.write(buffer, bytesRead);
935    } while (!stream->isAtEnd());
936    return tempStream.detachAsData();
937}
938
939bool SkStreamCopy(SkWStream* out, SkStream* input) {
940    const char* base = static_cast<const char*>(input->getMemoryBase());
941    if (base && input->hasPosition() && input->hasLength()) {
942        // Shortcut that avoids the while loop.
943        size_t position = input->getPosition();
944        size_t length = input->getLength();
945        SkASSERT(length >= position);
946        return out->write(&base[position], length - position);
947    }
948    char scratch[4096];
949    size_t count;
950    while (true) {
951        count = input->read(scratch, sizeof(scratch));
952        if (0 == count) {
953            return true;
954        }
955        if (!out->write(scratch, count)) {
956            return false;
957        }
958    }
959}
960