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