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