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 "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 
     23 int8_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 
     30 int16_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 
     37 int32_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 
     44 SkScalar 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 
     55 size_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 
     71 SkWStream::~SkWStream()
     72 {
     73 }
     74 
     75 void SkWStream::flush()
     76 {
     77 }
     78 
     79 bool 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 
     86 bool 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 
     93 bool 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 
    100 bool 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 
    107 bool SkWStream::writeScalar(SkScalar value) {
    108     return this->write(&value, sizeof(value));
    109 }
    110 
    111 int 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 
    120 bool 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 
    140 bool 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 
    160 SkFILEStream::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 
    168 SkFILEStream::SkFILEStream(std::shared_ptr<FILE> file, size_t size, size_t offset)
    169     : SkFILEStream(std::move(file), size, offset, offset)
    170 { }
    171 
    172 SkFILEStream::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 
    179 SkFILEStream::SkFILEStream(const char path[])
    180     : SkFILEStream(path ? sk_fopen(path, kRead_SkFILE_Flag) : nullptr)
    181 { }
    182 
    183 SkFILEStream::~SkFILEStream() {
    184     this->close();
    185 }
    186 
    187 void SkFILEStream::close() {
    188     fFILE.reset();
    189     fSize = 0;
    190     fOffset = 0;
    191 }
    192 
    193 size_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 
    208 bool SkFILEStream::isAtEnd() const {
    209     if (fOffset == fSize) {
    210         return true;
    211     }
    212     return fOffset >= sk_fgetsize(fFILE.get());
    213 }
    214 
    215 bool SkFILEStream::rewind() {
    216     fOffset = fOriginalOffset;
    217     return true;
    218 }
    219 
    220 SkStreamAsset* SkFILEStream::onDuplicate() const {
    221     return new SkFILEStream(fFILE, fSize, fOriginalOffset, fOriginalOffset);
    222 }
    223 
    224 size_t SkFILEStream::getPosition() const {
    225     SkASSERT(fOffset >= fOriginalOffset);
    226     return fOffset - fOriginalOffset;
    227 }
    228 
    229 bool SkFILEStream::seek(size_t position) {
    230     fOffset = SkTMin(SkSafeMath::Add(position, fOriginalOffset), fSize);
    231     return true;
    232 }
    233 
    234 bool 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 
    253 SkStreamAsset* SkFILEStream::onFork() const {
    254     return new SkFILEStream(fFILE, fSize, fOffset, fOriginalOffset);
    255 }
    256 
    257 size_t SkFILEStream::getLength() const {
    258     return fSize - fOriginalOffset;
    259 }
    260 
    261 ///////////////////////////////////////////////////////////////////////////////
    262 
    263 static 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 
    271 SkMemoryStream::SkMemoryStream() {
    272     fData = SkData::MakeEmpty();
    273     fOffset = 0;
    274 }
    275 
    276 SkMemoryStream::SkMemoryStream(size_t size) {
    277     fData = SkData::MakeUninitialized(size);
    278     fOffset = 0;
    279 }
    280 
    281 SkMemoryStream::SkMemoryStream(const void* src, size_t size, bool copyData) {
    282     fData = newFromParams(src, size, copyData);
    283     fOffset = 0;
    284 }
    285 
    286 SkMemoryStream::SkMemoryStream(sk_sp<SkData> data) : fData(std::move(data)) {
    287     if (nullptr == fData) {
    288         fData = SkData::MakeEmpty();
    289     }
    290     fOffset = 0;
    291 }
    292 
    293 std::unique_ptr<SkMemoryStream> SkMemoryStream::MakeCopy(const void* data, size_t length) {
    294     return skstd::make_unique<SkMemoryStream>(data, length, true);
    295 }
    296 
    297 std::unique_ptr<SkMemoryStream> SkMemoryStream::MakeDirect(const void* data, size_t length) {
    298     return skstd::make_unique<SkMemoryStream>(data, length, false);
    299 }
    300 
    301 std::unique_ptr<SkMemoryStream> SkMemoryStream::Make(sk_sp<SkData> data) {
    302     return skstd::make_unique<SkMemoryStream>(std::move(data));
    303 }
    304 
    305 void SkMemoryStream::setMemoryOwned(const void* src, size_t size) {
    306     fData = SkData::MakeFromMalloc(src, size);
    307     fOffset = 0;
    308 }
    309 
    310 void SkMemoryStream::setMemory(const void* src, size_t size, bool copyData) {
    311     fData = newFromParams(src, size, copyData);
    312     fOffset = 0;
    313 }
    314 
    315 void 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 
    324 void SkMemoryStream::skipToAlign4() {
    325     // cast to remove unary-minus warning
    326     fOffset += -(int)fOffset & 0x03;
    327 }
    328 
    329 size_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 
    342 size_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 
    352 bool SkMemoryStream::isAtEnd() const {
    353     return fOffset == fData->size();
    354 }
    355 
    356 bool SkMemoryStream::rewind() {
    357     fOffset = 0;
    358     return true;
    359 }
    360 
    361 SkMemoryStream* SkMemoryStream::onDuplicate() const {
    362     return new SkMemoryStream(fData);
    363 }
    364 
    365 size_t SkMemoryStream::getPosition() const {
    366     return fOffset;
    367 }
    368 
    369 bool SkMemoryStream::seek(size_t position) {
    370     fOffset = position > fData->size()
    371             ? fData->size()
    372             : position;
    373     return true;
    374 }
    375 
    376 bool SkMemoryStream::move(long offset) {
    377     return this->seek(fOffset + offset);
    378 }
    379 
    380 SkMemoryStream* SkMemoryStream::onFork() const {
    381     std::unique_ptr<SkMemoryStream> that(this->duplicate());
    382     that->seek(fOffset);
    383     return that.release();
    384 }
    385 
    386 size_t SkMemoryStream::getLength() const {
    387     return fData->size();
    388 }
    389 
    390 const void* SkMemoryStream::getMemoryBase() {
    391     return fData->data();
    392 }
    393 
    394 const void* SkMemoryStream::getAtPos() {
    395     return fData->bytes() + fOffset;
    396 }
    397 
    398 /////////////////////////////////////////////////////////////////////////////////////////////////////////
    399 /////////////////////////////////////////////////////////////////////////////////////////////////////////
    400 
    401 SkFILEWStream::SkFILEWStream(const char path[])
    402 {
    403     fFILE = sk_fopen(path, kWrite_SkFILE_Flag);
    404 }
    405 
    406 SkFILEWStream::~SkFILEWStream()
    407 {
    408     if (fFILE) {
    409         sk_fclose(fFILE);
    410     }
    411 }
    412 
    413 size_t SkFILEWStream::bytesWritten() const {
    414     return sk_ftell(fFILE);
    415 }
    416 
    417 bool 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 
    433 void SkFILEWStream::flush()
    434 {
    435     if (fFILE) {
    436         sk_fflush(fFILE);
    437     }
    438 }
    439 
    440 void SkFILEWStream::fsync()
    441 {
    442     flush();
    443     if (fFILE) {
    444         sk_fsync(fFILE);
    445     }
    446 }
    447 
    448 ////////////////////////////////////////////////////////////////////////
    449 
    450 static 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 
    460 struct 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 
    484 SkDynamicMemoryWStream::SkDynamicMemoryWStream()
    485     : fHead(nullptr), fTail(nullptr), fBytesWrittenBeforeTail(0)
    486 {}
    487 
    488 SkDynamicMemoryWStream::~SkDynamicMemoryWStream() {
    489     this->reset();
    490 }
    491 
    492 void 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 
    503 size_t SkDynamicMemoryWStream::bytesWritten() const {
    504     this->validate();
    505 
    506     if (fTail) {
    507         return fBytesWrittenBeforeTail + fTail->written();
    508     }
    509     return 0;
    510 }
    511 
    512 bool 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 
    547 bool 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 
    568 void 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 
    578 bool 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 
    587 void 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 
    603 void 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 
    620 bool 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 
    637 sk_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
    648 void 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 
    672 class SkBlockMemoryRefCnt : public SkRefCnt {
    673 public:
    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 
    688 class SkBlockMemoryStream : public SkStreamAsset {
    689 public:
    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 
    800 private:
    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 
    808 std::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 
    820 static 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 
    831 std::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:
    846 sk_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 
    863 bool 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