• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
readS8()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 
readS16()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 
readS32()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 
readScalar()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 
readPackedUInt()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 
~SkWStream()70 SkWStream::~SkWStream()
71 {
72 }
73 
flush()74 void SkWStream::flush()
75 {
76 }
77 
writeDecAsText(int32_t dec)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 
writeBigDecAsText(int64_t dec,int minDigits)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 
writeHexAsText(uint32_t hex,int digits)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 
writeScalarAsText(SkScalar value)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 
writeScalar(SkScalar value)106 bool SkWStream::writeScalar(SkScalar value) {
107     return this->write(&value, sizeof(value));
108 }
109 
SizeOfPackedUInt(size_t value)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 
writePackedUInt(size_t value)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 
writeStream(SkStream * stream,size_t length)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 
SkFILEStream(std::shared_ptr<FILE> file,size_t size,size_t offset,size_t originalOffset)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 
SkFILEStream(std::shared_ptr<FILE> file,size_t size,size_t offset)167 SkFILEStream::SkFILEStream(std::shared_ptr<FILE> file, size_t size, size_t offset)
168     : SkFILEStream(std::move(file), size, offset, offset)
169 { }
170 
SkFILEStream(FILE * file)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 
SkFILEStream(const char path[])178 SkFILEStream::SkFILEStream(const char path[])
179     : SkFILEStream(path ? sk_fopen(path, kRead_SkFILE_Flag) : nullptr)
180 { }
181 
~SkFILEStream()182 SkFILEStream::~SkFILEStream() {
183     this->close();
184 }
185 
close()186 void SkFILEStream::close() {
187     fFILE.reset();
188     fSize = 0;
189     fOffset = 0;
190 }
191 
read(void * buffer,size_t size)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 
isAtEnd() const207 bool SkFILEStream::isAtEnd() const {
208     if (fOffset == fSize) {
209         return true;
210     }
211     return fOffset >= sk_fgetsize(fFILE.get());
212 }
213 
rewind()214 bool SkFILEStream::rewind() {
215     // TODO: fOriginalOffset instead of 0.
216     fOffset = 0;
217     return true;
218 }
219 
duplicate() const220 SkStreamAsset* SkFILEStream::duplicate() const {
221     // TODO: fOriginalOffset instead of 0.
222     return new SkFILEStream(fFILE, fSize, 0, fOriginalOffset);
223 }
224 
getPosition() const225 size_t SkFILEStream::getPosition() const {
226     return fOffset;
227 }
228 
seek(size_t position)229 bool SkFILEStream::seek(size_t position) {
230     fOffset = position > fSize ? fSize : position;
231     return true;
232 }
233 
move(long offset)234 bool SkFILEStream::move(long offset) {
235     return this->seek(fOffset + offset);
236 }
237 
fork() const238 SkStreamAsset* SkFILEStream::fork() const {
239     return new SkFILEStream(fFILE, fSize, fOffset, fOriginalOffset);
240 }
241 
getLength() const242 size_t SkFILEStream::getLength() const {
243     return fSize;
244 }
245 
246 ///////////////////////////////////////////////////////////////////////////////
247 
newFromParams(const void * src,size_t size,bool copyData)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 
SkMemoryStream()256 SkMemoryStream::SkMemoryStream() {
257     fData = SkData::MakeEmpty();
258     fOffset = 0;
259 }
260 
SkMemoryStream(size_t size)261 SkMemoryStream::SkMemoryStream(size_t size) {
262     fData = SkData::MakeUninitialized(size);
263     fOffset = 0;
264 }
265 
SkMemoryStream(const void * src,size_t size,bool copyData)266 SkMemoryStream::SkMemoryStream(const void* src, size_t size, bool copyData) {
267     fData = newFromParams(src, size, copyData);
268     fOffset = 0;
269 }
270 
SkMemoryStream(sk_sp<SkData> data)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 
setMemoryOwned(const void * src,size_t size)278 void SkMemoryStream::setMemoryOwned(const void* src, size_t size) {
279     fData = SkData::MakeFromMalloc(src, size);
280     fOffset = 0;
281 }
282 
setMemory(const void * src,size_t size,bool copyData)283 void SkMemoryStream::setMemory(const void* src, size_t size, bool copyData) {
284     fData = newFromParams(src, size, copyData);
285     fOffset = 0;
286 }
287 
setData(sk_sp<SkData> data)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 
skipToAlign4()297 void SkMemoryStream::skipToAlign4() {
298     // cast to remove unary-minus warning
299     fOffset += -(int)fOffset & 0x03;
300 }
301 
read(void * buffer,size_t size)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 
peek(void * buffer,size_t size) const315 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 
isAtEnd() const325 bool SkMemoryStream::isAtEnd() const {
326     return fOffset == fData->size();
327 }
328 
rewind()329 bool SkMemoryStream::rewind() {
330     fOffset = 0;
331     return true;
332 }
333 
duplicate() const334 SkMemoryStream* SkMemoryStream::duplicate() const { return new SkMemoryStream(fData); }
335 
getPosition() const336 size_t SkMemoryStream::getPosition() const {
337     return fOffset;
338 }
339 
seek(size_t position)340 bool SkMemoryStream::seek(size_t position) {
341     fOffset = position > fData->size()
342             ? fData->size()
343             : position;
344     return true;
345 }
346 
move(long offset)347 bool SkMemoryStream::move(long offset) {
348     return this->seek(fOffset + offset);
349 }
350 
fork() const351 SkMemoryStream* SkMemoryStream::fork() const {
352     std::unique_ptr<SkMemoryStream> that(this->duplicate());
353     that->seek(fOffset);
354     return that.release();
355 }
356 
getLength() const357 size_t SkMemoryStream::getLength() const {
358     return fData->size();
359 }
360 
getMemoryBase()361 const void* SkMemoryStream::getMemoryBase() {
362     return fData->data();
363 }
364 
getAtPos()365 const void* SkMemoryStream::getAtPos() {
366     return fData->bytes() + fOffset;
367 }
368 
369 /////////////////////////////////////////////////////////////////////////////////////////////////////////
370 /////////////////////////////////////////////////////////////////////////////////////////////////////////
371 
SkFILEWStream(const char path[])372 SkFILEWStream::SkFILEWStream(const char path[])
373 {
374     fFILE = sk_fopen(path, kWrite_SkFILE_Flag);
375 }
376 
~SkFILEWStream()377 SkFILEWStream::~SkFILEWStream()
378 {
379     if (fFILE) {
380         sk_fclose(fFILE);
381     }
382 }
383 
bytesWritten() const384 size_t SkFILEWStream::bytesWritten() const {
385     return sk_ftell(fFILE);
386 }
387 
write(const void * buffer,size_t size)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 
flush()404 void SkFILEWStream::flush()
405 {
406     if (fFILE) {
407         sk_fflush(fFILE);
408     }
409 }
410 
fsync()411 void SkFILEWStream::fsync()
412 {
413     flush();
414     if (fFILE) {
415         sk_fsync(fFILE);
416     }
417 }
418 
419 ////////////////////////////////////////////////////////////////////////
420 
sk_memcpy_4bytes(void * dst,const void * src,size_t size)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 
startSkDynamicMemoryWStream::Block436     const char* start() const { return (const char*)(this + 1); }
startSkDynamicMemoryWStream::Block437     char*   start() { return (char*)(this + 1); }
availSkDynamicMemoryWStream::Block438     size_t  avail() const { return fStop - fCurr; }
writtenSkDynamicMemoryWStream::Block439     size_t  written() const { return fCurr - this->start(); }
440 
initSkDynamicMemoryWStream::Block441     void init(size_t size) {
442         fNext = nullptr;
443         fCurr = this->start();
444         fStop = this->start() + size;
445     }
446 
appendSkDynamicMemoryWStream::Block447     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 
SkDynamicMemoryWStream()455 SkDynamicMemoryWStream::SkDynamicMemoryWStream()
456     : fHead(nullptr), fTail(nullptr), fBytesWrittenBeforeTail(0)
457 {}
458 
~SkDynamicMemoryWStream()459 SkDynamicMemoryWStream::~SkDynamicMemoryWStream() {
460     this->reset();
461 }
462 
reset()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 
bytesWritten() const474 size_t SkDynamicMemoryWStream::bytesWritten() const {
475     this->validate();
476 
477     if (fTail) {
478         return fBytesWrittenBeforeTail + fTail->written();
479     }
480     return 0;
481 }
482 
write(const void * buffer,size_t count)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 
read(void * buffer,size_t offset,size_t count)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 
copyTo(void * dst) const539 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 
writeToStream(SkWStream * dst) const549 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 
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 
writeToAndReset(SkWStream * dst)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 
detachAsData()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
validate() const619 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:
SkBlockMemoryRefCnt(SkDynamicMemoryWStream::Block * head)645     explicit SkBlockMemoryRefCnt(SkDynamicMemoryWStream::Block* head) : fHead(head) { }
646 
~SkBlockMemoryRefCnt()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:
SkBlockMemoryStream(sk_sp<SkBlockMemoryRefCnt> headRef,size_t size)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 
read(void * buffer,size_t rawCount)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 
isAtEnd() const692     bool isAtEnd() const override {
693         return fOffset == fSize;
694     }
695 
peek(void * buff,size_t bytesToPeek) const696     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 
rewind()717     bool rewind() override {
718         fCurrent = fBlockMemory->fHead;
719         fOffset = 0;
720         fCurrentOffset = 0;
721         return true;
722     }
723 
duplicate() const724     SkBlockMemoryStream* duplicate() const override {
725         return new SkBlockMemoryStream(fBlockMemory, fSize);
726     }
727 
getPosition() const728     size_t getPosition() const override {
729         return fOffset;
730     }
731 
seek(size_t position)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 
move(long offset)749     bool move(long offset) override {
750         return seek(fOffset + offset);
751     }
752 
fork() const753     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 
getLength() const761     size_t getLength() const override {
762         return fSize;
763     }
764 
getMemoryBase()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 
detachAsStream()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 
mmap_filename(const char path[])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 
MakeFromFile(const char path[])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:
SkCopyStreamToData(SkStream * stream)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 
SkStreamCopy(SkWStream * out,SkStream * input)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