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