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