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