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