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 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 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 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 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 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 70 SkWStream::~SkWStream() 71 { 72 } 73 74 void SkWStream::flush() 75 { 76 } 77 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 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 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 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 106 bool SkWStream::writeScalar(SkScalar value) { 107 return this->write(&value, sizeof(value)); 108 } 109 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 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 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 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 167 SkFILEStream::SkFILEStream(std::shared_ptr<FILE> file, size_t size, size_t offset) 168 : SkFILEStream(std::move(file), size, offset, offset) 169 { } 170 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 178 SkFILEStream::SkFILEStream(const char path[]) 179 : SkFILEStream(path ? sk_fopen(path, kRead_SkFILE_Flag) : nullptr) 180 { } 181 182 SkFILEStream::~SkFILEStream() { 183 this->close(); 184 } 185 186 void SkFILEStream::close() { 187 fFILE.reset(); 188 fSize = 0; 189 fOffset = 0; 190 } 191 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 207 bool SkFILEStream::isAtEnd() const { 208 if (fOffset == fSize) { 209 return true; 210 } 211 return fOffset >= sk_fgetsize(fFILE.get()); 212 } 213 214 bool SkFILEStream::rewind() { 215 // TODO: fOriginalOffset instead of 0. 216 fOffset = 0; 217 return true; 218 } 219 220 SkStreamAsset* SkFILEStream::duplicate() const { 221 // TODO: fOriginalOffset instead of 0. 222 return new SkFILEStream(fFILE, fSize, 0, fOriginalOffset); 223 } 224 225 size_t SkFILEStream::getPosition() const { 226 return fOffset; 227 } 228 229 bool SkFILEStream::seek(size_t position) { 230 fOffset = position > fSize ? fSize : position; 231 return true; 232 } 233 234 bool SkFILEStream::move(long offset) { 235 return this->seek(fOffset + offset); 236 } 237 238 SkStreamAsset* SkFILEStream::fork() const { 239 return new SkFILEStream(fFILE, fSize, fOffset, fOriginalOffset); 240 } 241 242 size_t SkFILEStream::getLength() const { 243 return fSize; 244 } 245 246 /////////////////////////////////////////////////////////////////////////////// 247 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 256 SkMemoryStream::SkMemoryStream() { 257 fData = SkData::MakeEmpty(); 258 fOffset = 0; 259 } 260 261 SkMemoryStream::SkMemoryStream(size_t size) { 262 fData = SkData::MakeUninitialized(size); 263 fOffset = 0; 264 } 265 266 SkMemoryStream::SkMemoryStream(const void* src, size_t size, bool copyData) { 267 fData = newFromParams(src, size, copyData); 268 fOffset = 0; 269 } 270 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 278 void SkMemoryStream::setMemoryOwned(const void* src, size_t size) { 279 fData = SkData::MakeFromMalloc(src, size); 280 fOffset = 0; 281 } 282 283 void SkMemoryStream::setMemory(const void* src, size_t size, bool copyData) { 284 fData = newFromParams(src, size, copyData); 285 fOffset = 0; 286 } 287 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 297 void SkMemoryStream::skipToAlign4() { 298 // cast to remove unary-minus warning 299 fOffset += -(int)fOffset & 0x03; 300 } 301 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 315 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 325 bool SkMemoryStream::isAtEnd() const { 326 return fOffset == fData->size(); 327 } 328 329 bool SkMemoryStream::rewind() { 330 fOffset = 0; 331 return true; 332 } 333 334 SkMemoryStream* SkMemoryStream::duplicate() const { return new SkMemoryStream(fData); } 335 336 size_t SkMemoryStream::getPosition() const { 337 return fOffset; 338 } 339 340 bool SkMemoryStream::seek(size_t position) { 341 fOffset = position > fData->size() 342 ? fData->size() 343 : position; 344 return true; 345 } 346 347 bool SkMemoryStream::move(long offset) { 348 return this->seek(fOffset + offset); 349 } 350 351 SkMemoryStream* SkMemoryStream::fork() const { 352 std::unique_ptr<SkMemoryStream> that(this->duplicate()); 353 that->seek(fOffset); 354 return that.release(); 355 } 356 357 size_t SkMemoryStream::getLength() const { 358 return fData->size(); 359 } 360 361 const void* SkMemoryStream::getMemoryBase() { 362 return fData->data(); 363 } 364 365 const void* SkMemoryStream::getAtPos() { 366 return fData->bytes() + fOffset; 367 } 368 369 ///////////////////////////////////////////////////////////////////////////////////////////////////////// 370 ///////////////////////////////////////////////////////////////////////////////////////////////////////// 371 372 SkFILEWStream::SkFILEWStream(const char path[]) 373 { 374 fFILE = sk_fopen(path, kWrite_SkFILE_Flag); 375 } 376 377 SkFILEWStream::~SkFILEWStream() 378 { 379 if (fFILE) { 380 sk_fclose(fFILE); 381 } 382 } 383 384 size_t SkFILEWStream::bytesWritten() const { 385 return sk_ftell(fFILE); 386 } 387 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 404 void SkFILEWStream::flush() 405 { 406 if (fFILE) { 407 sk_fflush(fFILE); 408 } 409 } 410 411 void SkFILEWStream::fsync() 412 { 413 flush(); 414 if (fFILE) { 415 sk_fsync(fFILE); 416 } 417 } 418 419 //////////////////////////////////////////////////////////////////////// 420 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 436 const char* start() const { return (const char*)(this + 1); } 437 char* start() { return (char*)(this + 1); } 438 size_t avail() const { return fStop - fCurr; } 439 size_t written() const { return fCurr - this->start(); } 440 441 void init(size_t size) { 442 fNext = nullptr; 443 fCurr = this->start(); 444 fStop = this->start() + size; 445 } 446 447 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 455 SkDynamicMemoryWStream::SkDynamicMemoryWStream() 456 : fHead(nullptr), fTail(nullptr), fBytesWrittenBeforeTail(0) 457 {} 458 459 SkDynamicMemoryWStream::~SkDynamicMemoryWStream() { 460 this->reset(); 461 } 462 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 474 size_t SkDynamicMemoryWStream::bytesWritten() const { 475 this->validate(); 476 477 if (fTail) { 478 return fBytesWrittenBeforeTail + fTail->written(); 479 } 480 return 0; 481 } 482 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 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 539 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 549 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 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 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 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 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 619 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: 645 explicit SkBlockMemoryRefCnt(SkDynamicMemoryWStream::Block* head) : fHead(head) { } 646 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: 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 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 692 bool isAtEnd() const override { 693 return fOffset == fSize; 694 } 695 696 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 717 bool rewind() override { 718 fCurrent = fBlockMemory->fHead; 719 fOffset = 0; 720 fCurrentOffset = 0; 721 return true; 722 } 723 724 SkBlockMemoryStream* duplicate() const override { 725 return new SkBlockMemoryStream(fBlockMemory, fSize); 726 } 727 728 size_t getPosition() const override { 729 return fOffset; 730 } 731 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 749 bool move(long offset) override { 750 return seek(fOffset + offset); 751 } 752 753 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 761 size_t getLength() const override { 762 return fSize; 763 } 764 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 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 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 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: 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 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