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