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 16/////////////////////////////////////////////////////////////////////////////// 17 18 19int8_t SkStream::readS8() { 20 int8_t value; 21 SkDEBUGCODE(size_t len =) this->read(&value, 1); 22 SkASSERT(1 == len); 23 return value; 24} 25 26int16_t SkStream::readS16() { 27 int16_t value; 28 SkDEBUGCODE(size_t len =) this->read(&value, 2); 29 SkASSERT(2 == len); 30 return value; 31} 32 33int32_t SkStream::readS32() { 34 int32_t value; 35 SkDEBUGCODE(size_t len =) this->read(&value, 4); 36 SkASSERT(4 == len); 37 return value; 38} 39 40SkScalar SkStream::readScalar() { 41 SkScalar value; 42 SkDEBUGCODE(size_t len =) this->read(&value, sizeof(SkScalar)); 43 SkASSERT(sizeof(SkScalar) == len); 44 return value; 45} 46 47#define SK_MAX_BYTE_FOR_U8 0xFD 48#define SK_BYTE_SENTINEL_FOR_U16 0xFE 49#define SK_BYTE_SENTINEL_FOR_U32 0xFF 50 51size_t SkStream::readPackedUInt() { 52 uint8_t byte; 53 if (!this->read(&byte, 1)) { 54 return 0; 55 } 56 if (SK_BYTE_SENTINEL_FOR_U16 == byte) { 57 return this->readU16(); 58 } else if (SK_BYTE_SENTINEL_FOR_U32 == byte) { 59 return this->readU32(); 60 } else { 61 return byte; 62 } 63} 64 65SkData* SkStream::readData() { 66 size_t size = this->readU32(); 67 if (0 == size) { 68 return SkData::NewEmpty(); 69 } else { 70 void* buffer = sk_malloc_throw(size); 71 this->read(buffer, size); 72 return SkData::NewFromMalloc(buffer, size); 73 } 74} 75 76////////////////////////////////////////////////////////////////////////////////////// 77 78SkWStream::~SkWStream() 79{ 80} 81 82void SkWStream::newline() 83{ 84 this->write("\n", 1); 85} 86 87void SkWStream::flush() 88{ 89} 90 91bool SkWStream::writeText(const char text[]) 92{ 93 SkASSERT(text); 94 return this->write(text, strlen(text)); 95} 96 97bool SkWStream::writeDecAsText(int32_t dec) 98{ 99 SkString tmp; 100 tmp.appendS32(dec); 101 return this->write(tmp.c_str(), tmp.size()); 102} 103 104bool SkWStream::writeBigDecAsText(int64_t dec, int minDigits) 105{ 106 SkString tmp; 107 tmp.appendS64(dec, minDigits); 108 return this->write(tmp.c_str(), tmp.size()); 109} 110 111bool SkWStream::writeHexAsText(uint32_t hex, int digits) 112{ 113 SkString tmp; 114 tmp.appendHex(hex, digits); 115 return this->write(tmp.c_str(), tmp.size()); 116} 117 118bool SkWStream::writeScalarAsText(SkScalar value) 119{ 120 SkString tmp; 121 tmp.appendScalar(value); 122 return this->write(tmp.c_str(), tmp.size()); 123} 124 125bool SkWStream::write8(U8CPU value) { 126 uint8_t v = SkToU8(value); 127 return this->write(&v, 1); 128} 129 130bool SkWStream::write16(U16CPU value) { 131 uint16_t v = SkToU16(value); 132 return this->write(&v, 2); 133} 134 135bool SkWStream::write32(uint32_t value) { 136 return this->write(&value, 4); 137} 138 139bool SkWStream::writeScalar(SkScalar value) { 140 return this->write(&value, sizeof(value)); 141} 142 143int SkWStream::SizeOfPackedUInt(size_t value) { 144 if (value <= SK_MAX_BYTE_FOR_U8) { 145 return 1; 146 } else if (value <= 0xFFFF) { 147 return 3; 148 } 149 return 5; 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 = SkToU32(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(SkToU32(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 fOffset = 0; 368 return data; 369} 370 371void SkMemoryStream::skipToAlign4() { 372 // cast to remove unary-minus warning 373 fOffset += -(int)fOffset & 0x03; 374} 375 376size_t SkMemoryStream::read(void* buffer, size_t size) { 377 size_t dataSize = fData->size(); 378 379 if (size > dataSize - fOffset) { 380 size = dataSize - fOffset; 381 } 382 if (buffer) { 383 memcpy(buffer, fData->bytes() + fOffset, size); 384 } 385 fOffset += size; 386 return size; 387} 388 389bool SkMemoryStream::isAtEnd() const { 390 return fOffset == fData->size(); 391} 392 393bool SkMemoryStream::rewind() { 394 fOffset = 0; 395 return true; 396} 397 398SkMemoryStream* SkMemoryStream::duplicate() const { 399 return SkNEW_ARGS(SkMemoryStream, (fData)); 400} 401 402size_t SkMemoryStream::getPosition() const { 403 return fOffset; 404} 405 406bool SkMemoryStream::seek(size_t position) { 407 fOffset = position > fData->size() 408 ? fData->size() 409 : position; 410 return true; 411} 412 413bool SkMemoryStream::move(long offset) { 414 return this->seek(fOffset + offset); 415} 416 417SkMemoryStream* SkMemoryStream::fork() const { 418 SkAutoTUnref<SkMemoryStream> that(this->duplicate()); 419 that->seek(fOffset); 420 return that.detach(); 421} 422 423size_t SkMemoryStream::getLength() const { 424 return fData->size(); 425} 426 427const void* SkMemoryStream::getMemoryBase() { 428 return fData->data(); 429} 430 431const void* SkMemoryStream::getAtPos() { 432 return fData->bytes() + fOffset; 433} 434 435///////////////////////////////////////////////////////////////////////////////////////////////////////// 436///////////////////////////////////////////////////////////////////////////////////////////////////////// 437 438SkFILEWStream::SkFILEWStream(const char path[]) 439{ 440 fFILE = sk_fopen(path, kWrite_SkFILE_Flag); 441} 442 443SkFILEWStream::~SkFILEWStream() 444{ 445 if (fFILE) { 446 sk_fclose(fFILE); 447 } 448} 449 450size_t SkFILEWStream::bytesWritten() const { 451 return sk_ftell(fFILE); 452} 453 454bool SkFILEWStream::write(const void* buffer, size_t size) 455{ 456 if (fFILE == NULL) { 457 return false; 458 } 459 460 if (sk_fwrite(buffer, size, fFILE) != size) 461 { 462 SkDEBUGCODE(SkDebugf("SkFILEWStream failed writing %d bytes\n", size);) 463 sk_fclose(fFILE); 464 fFILE = NULL; 465 return false; 466 } 467 return true; 468} 469 470void SkFILEWStream::flush() 471{ 472 if (fFILE) { 473 sk_fflush(fFILE); 474 } 475} 476 477//////////////////////////////////////////////////////////////////////// 478 479SkMemoryWStream::SkMemoryWStream(void* buffer, size_t size) 480 : fBuffer((char*)buffer), fMaxLength(size), fBytesWritten(0) 481{ 482} 483 484bool SkMemoryWStream::write(const void* buffer, size_t size) { 485 size = SkTMin(size, fMaxLength - fBytesWritten); 486 if (size > 0) { 487 memcpy(fBuffer + fBytesWritten, buffer, size); 488 fBytesWritten += size; 489 return true; 490 } 491 return false; 492} 493 494//////////////////////////////////////////////////////////////////////// 495 496#define SkDynamicMemoryWStream_MinBlockSize 256 497 498struct SkDynamicMemoryWStream::Block { 499 Block* fNext; 500 char* fCurr; 501 char* fStop; 502 503 const char* start() const { return (const char*)(this + 1); } 504 char* start() { return (char*)(this + 1); } 505 size_t avail() const { return fStop - fCurr; } 506 size_t written() const { return fCurr - this->start(); } 507 508 void init(size_t size) 509 { 510 fNext = NULL; 511 fCurr = this->start(); 512 fStop = this->start() + size; 513 } 514 515 const void* append(const void* data, size_t size) 516 { 517 SkASSERT((size_t)(fStop - fCurr) >= size); 518 memcpy(fCurr, data, size); 519 fCurr += size; 520 return (const void*)((const char*)data + size); 521 } 522}; 523 524SkDynamicMemoryWStream::SkDynamicMemoryWStream() 525 : fHead(NULL), fTail(NULL), fBytesWritten(0), fCopy(NULL) 526{ 527} 528 529SkDynamicMemoryWStream::~SkDynamicMemoryWStream() 530{ 531 reset(); 532} 533 534void SkDynamicMemoryWStream::reset() 535{ 536 this->invalidateCopy(); 537 538 Block* block = fHead; 539 540 while (block != NULL) { 541 Block* next = block->fNext; 542 sk_free(block); 543 block = next; 544 } 545 fHead = fTail = NULL; 546 fBytesWritten = 0; 547} 548 549bool SkDynamicMemoryWStream::write(const void* buffer, size_t count) 550{ 551 if (count > 0) { 552 this->invalidateCopy(); 553 554 fBytesWritten += count; 555 556 size_t size; 557 558 if (fTail != NULL && fTail->avail() > 0) { 559 size = SkTMin(fTail->avail(), count); 560 buffer = fTail->append(buffer, size); 561 SkASSERT(count >= size); 562 count -= size; 563 if (count == 0) 564 return true; 565 } 566 567 size = SkTMax<size_t>(count, SkDynamicMemoryWStream_MinBlockSize); 568 Block* block = (Block*)sk_malloc_throw(sizeof(Block) + size); 569 block->init(size); 570 block->append(buffer, count); 571 572 if (fTail != NULL) 573 fTail->fNext = block; 574 else 575 fHead = fTail = block; 576 fTail = block; 577 } 578 return true; 579} 580 581bool SkDynamicMemoryWStream::write(const void* buffer, size_t offset, size_t count) 582{ 583 if (offset + count > fBytesWritten) { 584 return false; // test does not partially modify 585 } 586 587 this->invalidateCopy(); 588 589 Block* block = fHead; 590 while (block != NULL) { 591 size_t size = block->written(); 592 if (offset < size) { 593 size_t part = offset + count > size ? size - offset : count; 594 memcpy(block->start() + offset, buffer, part); 595 if (count <= part) 596 return true; 597 count -= part; 598 buffer = (const void*) ((char* ) buffer + part); 599 } 600 offset = offset > size ? offset - size : 0; 601 block = block->fNext; 602 } 603 return false; 604} 605 606bool SkDynamicMemoryWStream::read(void* buffer, size_t offset, size_t count) 607{ 608 if (offset + count > fBytesWritten) 609 return false; // test does not partially modify 610 Block* block = fHead; 611 while (block != NULL) { 612 size_t size = block->written(); 613 if (offset < size) { 614 size_t part = offset + count > size ? size - offset : count; 615 memcpy(buffer, block->start() + offset, part); 616 if (count <= part) 617 return true; 618 count -= part; 619 buffer = (void*) ((char* ) buffer + part); 620 } 621 offset = offset > size ? offset - size : 0; 622 block = block->fNext; 623 } 624 return false; 625} 626 627void SkDynamicMemoryWStream::copyTo(void* dst) const 628{ 629 if (fCopy) { 630 memcpy(dst, fCopy->data(), fBytesWritten); 631 } else { 632 Block* block = fHead; 633 634 while (block != NULL) { 635 size_t size = block->written(); 636 memcpy(dst, block->start(), size); 637 dst = (void*)((char*)dst + size); 638 block = block->fNext; 639 } 640 } 641} 642 643void SkDynamicMemoryWStream::padToAlign4() 644{ 645 // cast to remove unary-minus warning 646 int padBytes = -(int)fBytesWritten & 0x03; 647 if (padBytes == 0) 648 return; 649 int zero = 0; 650 write(&zero, padBytes); 651} 652 653SkData* SkDynamicMemoryWStream::copyToData() const { 654 if (NULL == fCopy) { 655 void* buffer = sk_malloc_throw(fBytesWritten); 656 this->copyTo(buffer); 657 fCopy = SkData::NewFromMalloc(buffer, fBytesWritten); 658 } 659 fCopy->ref(); 660 return fCopy; 661} 662 663void SkDynamicMemoryWStream::invalidateCopy() { 664 if (fCopy) { 665 fCopy->unref(); 666 fCopy = NULL; 667 } 668} 669 670class SkBlockMemoryRefCnt : public SkRefCnt { 671public: 672 explicit SkBlockMemoryRefCnt(SkDynamicMemoryWStream::Block* head) : fHead(head) { } 673 674 virtual ~SkBlockMemoryRefCnt() { 675 SkDynamicMemoryWStream::Block* block = fHead; 676 while (block != NULL) { 677 SkDynamicMemoryWStream::Block* next = block->fNext; 678 sk_free(block); 679 block = next; 680 } 681 } 682 683 SkDynamicMemoryWStream::Block* const fHead; 684}; 685 686class SkBlockMemoryStream : public SkStreamAsset { 687public: 688 SkBlockMemoryStream(SkDynamicMemoryWStream::Block* head, size_t size) 689 : fBlockMemory(SkNEW_ARGS(SkBlockMemoryRefCnt, (head))), fCurrent(head) 690 , fSize(size) , fOffset(0), fCurrentOffset(0) { } 691 692 SkBlockMemoryStream(SkBlockMemoryRefCnt* headRef, size_t size) 693 : fBlockMemory(SkRef(headRef)), fCurrent(fBlockMemory->fHead) 694 , fSize(size) , fOffset(0), fCurrentOffset(0) { } 695 696 virtual size_t read(void* buffer, size_t rawCount) SK_OVERRIDE { 697 size_t count = rawCount; 698 if (fOffset + count > fSize) { 699 count = fSize - fOffset; 700 } 701 size_t bytesLeftToRead = count; 702 while (fCurrent != NULL) { 703 size_t bytesLeftInCurrent = fCurrent->written() - fCurrentOffset; 704 size_t bytesFromCurrent = SkTMin(bytesLeftToRead, bytesLeftInCurrent); 705 if (buffer) { 706 memcpy(buffer, fCurrent->start() + fCurrentOffset, bytesFromCurrent); 707 buffer = SkTAddOffset<void>(buffer, bytesFromCurrent); 708 } 709 if (bytesLeftToRead <= bytesFromCurrent) { 710 fCurrentOffset += bytesFromCurrent; 711 fOffset += count; 712 return count; 713 } 714 bytesLeftToRead -= bytesFromCurrent; 715 fCurrent = fCurrent->fNext; 716 fCurrentOffset = 0; 717 } 718 SkASSERT(false); 719 return 0; 720 } 721 722 virtual bool isAtEnd() const SK_OVERRIDE { 723 return fOffset == fSize; 724 } 725 726 virtual bool rewind() SK_OVERRIDE { 727 fCurrent = fBlockMemory->fHead; 728 fOffset = 0; 729 fCurrentOffset = 0; 730 return true; 731 } 732 733 virtual SkBlockMemoryStream* duplicate() const SK_OVERRIDE { 734 return SkNEW_ARGS(SkBlockMemoryStream, (fBlockMemory.get(), fSize)); 735 } 736 737 virtual size_t getPosition() const SK_OVERRIDE { 738 return fOffset; 739 } 740 741 virtual bool seek(size_t position) SK_OVERRIDE { 742 // If possible, skip forward. 743 if (position >= fOffset) { 744 size_t skipAmount = position - fOffset; 745 return this->skip(skipAmount) == skipAmount; 746 } 747 // If possible, move backward within the current block. 748 size_t moveBackAmount = fOffset - position; 749 if (moveBackAmount <= fCurrentOffset) { 750 fCurrentOffset -= moveBackAmount; 751 fOffset -= moveBackAmount; 752 return true; 753 } 754 // Otherwise rewind and move forward. 755 return this->rewind() && this->skip(position) == position; 756 } 757 758 virtual bool move(long offset) SK_OVERRIDE { 759 return seek(fOffset + offset); 760 } 761 762 virtual SkBlockMemoryStream* fork() const SK_OVERRIDE { 763 SkAutoTUnref<SkBlockMemoryStream> that(this->duplicate()); 764 that->fCurrent = this->fCurrent; 765 that->fOffset = this->fOffset; 766 that->fCurrentOffset = this->fCurrentOffset; 767 return that.detach(); 768 } 769 770 virtual size_t getLength() const SK_OVERRIDE { 771 return fSize; 772 } 773 774 virtual const void* getMemoryBase() SK_OVERRIDE { 775 if (NULL == fBlockMemory->fHead->fNext) { 776 return fBlockMemory->fHead->start(); 777 } 778 return NULL; 779 } 780 781private: 782 SkAutoTUnref<SkBlockMemoryRefCnt> const fBlockMemory; 783 SkDynamicMemoryWStream::Block const * fCurrent; 784 size_t const fSize; 785 size_t fOffset; 786 size_t fCurrentOffset; 787}; 788 789SkStreamAsset* SkDynamicMemoryWStream::detachAsStream() { 790 if (fCopy) { 791 SkMemoryStream* stream = SkNEW_ARGS(SkMemoryStream, (fCopy)); 792 this->reset(); 793 return stream; 794 } 795 SkBlockMemoryStream* stream = SkNEW_ARGS(SkBlockMemoryStream, (fHead, fBytesWritten)); 796 fHead = 0; 797 this->reset(); 798 return stream; 799} 800 801/////////////////////////////////////////////////////////////////////////////// 802 803void SkDebugWStream::newline() 804{ 805#if defined(SK_DEBUG) || defined(SK_DEVELOPER) 806 SkDebugf("\n"); 807 fBytesWritten++; 808#endif 809} 810 811bool SkDebugWStream::write(const void* buffer, size_t size) 812{ 813#if defined(SK_DEBUG) || defined(SK_DEVELOPER) 814 char* s = new char[size+1]; 815 memcpy(s, buffer, size); 816 s[size] = 0; 817 SkDebugf("%s", s); 818 delete[] s; 819 fBytesWritten += size; 820#endif 821 return true; 822} 823 824/////////////////////////////////////////////////////////////////////////////// 825/////////////////////////////////////////////////////////////////////////////// 826 827 828static SkData* mmap_filename(const char path[]) { 829 SkFILE* file = sk_fopen(path, kRead_SkFILE_Flag); 830 if (NULL == file) { 831 return NULL; 832 } 833 834 SkData* data = SkData::NewFromFILE(file); 835 sk_fclose(file); 836 return data; 837} 838 839SkStreamAsset* SkStream::NewFromFile(const char path[]) { 840 SkAutoTUnref<SkData> data(mmap_filename(path)); 841 if (data.get()) { 842 return SkNEW_ARGS(SkMemoryStream, (data.get())); 843 } 844 845 // If we get here, then our attempt at using mmap failed, so try normal 846 // file access. 847 SkFILEStream* stream = SkNEW_ARGS(SkFILEStream, (path)); 848 if (!stream->isValid()) { 849 stream->unref(); 850 stream = NULL; 851 } 852 return stream; 853} 854