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