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