michael@0: michael@0: /* michael@0: * Copyright 2006 The Android Open Source Project michael@0: * michael@0: * Use of this source code is governed by a BSD-style license that can be michael@0: * found in the LICENSE file. michael@0: */ michael@0: michael@0: michael@0: #include "SkStream.h" michael@0: #include "SkData.h" michael@0: #include "SkFixed.h" michael@0: #include "SkString.h" michael@0: #include "SkOSFile.h" michael@0: michael@0: /////////////////////////////////////////////////////////////////////////////// michael@0: michael@0: michael@0: int8_t SkStream::readS8() { michael@0: int8_t value; michael@0: SkDEBUGCODE(size_t len =) this->read(&value, 1); michael@0: SkASSERT(1 == len); michael@0: return value; michael@0: } michael@0: michael@0: int16_t SkStream::readS16() { michael@0: int16_t value; michael@0: SkDEBUGCODE(size_t len =) this->read(&value, 2); michael@0: SkASSERT(2 == len); michael@0: return value; michael@0: } michael@0: michael@0: int32_t SkStream::readS32() { michael@0: int32_t value; michael@0: SkDEBUGCODE(size_t len =) this->read(&value, 4); michael@0: SkASSERT(4 == len); michael@0: return value; michael@0: } michael@0: michael@0: SkScalar SkStream::readScalar() { michael@0: SkScalar value; michael@0: SkDEBUGCODE(size_t len =) this->read(&value, sizeof(SkScalar)); michael@0: SkASSERT(sizeof(SkScalar) == len); michael@0: return value; michael@0: } michael@0: michael@0: #define SK_MAX_BYTE_FOR_U8 0xFD michael@0: #define SK_BYTE_SENTINEL_FOR_U16 0xFE michael@0: #define SK_BYTE_SENTINEL_FOR_U32 0xFF michael@0: michael@0: size_t SkStream::readPackedUInt() { michael@0: uint8_t byte; michael@0: if (!this->read(&byte, 1)) { michael@0: return 0; michael@0: } michael@0: if (SK_BYTE_SENTINEL_FOR_U16 == byte) { michael@0: return this->readU16(); michael@0: } else if (SK_BYTE_SENTINEL_FOR_U32 == byte) { michael@0: return this->readU32(); michael@0: } else { michael@0: return byte; michael@0: } michael@0: } michael@0: michael@0: SkData* SkStream::readData() { michael@0: size_t size = this->readU32(); michael@0: if (0 == size) { michael@0: return SkData::NewEmpty(); michael@0: } else { michael@0: void* buffer = sk_malloc_throw(size); michael@0: this->read(buffer, size); michael@0: return SkData::NewFromMalloc(buffer, size); michael@0: } michael@0: } michael@0: michael@0: ////////////////////////////////////////////////////////////////////////////////////// michael@0: michael@0: SkWStream::~SkWStream() michael@0: { michael@0: } michael@0: michael@0: void SkWStream::newline() michael@0: { michael@0: this->write("\n", 1); michael@0: } michael@0: michael@0: void SkWStream::flush() michael@0: { michael@0: } michael@0: michael@0: bool SkWStream::writeText(const char text[]) michael@0: { michael@0: SkASSERT(text); michael@0: return this->write(text, strlen(text)); michael@0: } michael@0: michael@0: bool SkWStream::writeDecAsText(int32_t dec) michael@0: { michael@0: SkString tmp; michael@0: tmp.appendS32(dec); michael@0: return this->write(tmp.c_str(), tmp.size()); michael@0: } michael@0: michael@0: bool SkWStream::writeBigDecAsText(int64_t dec, int minDigits) michael@0: { michael@0: SkString tmp; michael@0: tmp.appendS64(dec, minDigits); michael@0: return this->write(tmp.c_str(), tmp.size()); michael@0: } michael@0: michael@0: bool SkWStream::writeHexAsText(uint32_t hex, int digits) michael@0: { michael@0: SkString tmp; michael@0: tmp.appendHex(hex, digits); michael@0: return this->write(tmp.c_str(), tmp.size()); michael@0: } michael@0: michael@0: bool SkWStream::writeScalarAsText(SkScalar value) michael@0: { michael@0: SkString tmp; michael@0: tmp.appendScalar(value); michael@0: return this->write(tmp.c_str(), tmp.size()); michael@0: } michael@0: michael@0: bool SkWStream::write8(U8CPU value) { michael@0: uint8_t v = SkToU8(value); michael@0: return this->write(&v, 1); michael@0: } michael@0: michael@0: bool SkWStream::write16(U16CPU value) { michael@0: uint16_t v = SkToU16(value); michael@0: return this->write(&v, 2); michael@0: } michael@0: michael@0: bool SkWStream::write32(uint32_t value) { michael@0: return this->write(&value, 4); michael@0: } michael@0: michael@0: bool SkWStream::writeScalar(SkScalar value) { michael@0: return this->write(&value, sizeof(value)); michael@0: } michael@0: michael@0: int SkWStream::SizeOfPackedUInt(size_t value) { michael@0: if (value <= SK_MAX_BYTE_FOR_U8) { michael@0: return 1; michael@0: } else if (value <= 0xFFFF) { michael@0: return 3; michael@0: } michael@0: return 5; michael@0: } michael@0: michael@0: bool SkWStream::writePackedUInt(size_t value) { michael@0: uint8_t data[5]; michael@0: size_t len = 1; michael@0: if (value <= SK_MAX_BYTE_FOR_U8) { michael@0: data[0] = value; michael@0: len = 1; michael@0: } else if (value <= 0xFFFF) { michael@0: uint16_t value16 = value; michael@0: data[0] = SK_BYTE_SENTINEL_FOR_U16; michael@0: memcpy(&data[1], &value16, 2); michael@0: len = 3; michael@0: } else { michael@0: uint32_t value32 = value; michael@0: data[0] = SK_BYTE_SENTINEL_FOR_U32; michael@0: memcpy(&data[1], &value32, 4); michael@0: len = 5; michael@0: } michael@0: return this->write(data, len); michael@0: } michael@0: michael@0: bool SkWStream::writeStream(SkStream* stream, size_t length) { michael@0: char scratch[1024]; michael@0: const size_t MAX = sizeof(scratch); michael@0: michael@0: while (length != 0) { michael@0: size_t n = length; michael@0: if (n > MAX) { michael@0: n = MAX; michael@0: } michael@0: stream->read(scratch, n); michael@0: if (!this->write(scratch, n)) { michael@0: return false; michael@0: } michael@0: length -= n; michael@0: } michael@0: return true; michael@0: } michael@0: michael@0: bool SkWStream::writeData(const SkData* data) { michael@0: if (data) { michael@0: this->write32(data->size()); michael@0: this->write(data->data(), data->size()); michael@0: } else { michael@0: this->write32(0); michael@0: } michael@0: return true; michael@0: } michael@0: michael@0: /////////////////////////////////////////////////////////////////////////////// michael@0: michael@0: SkFILEStream::SkFILEStream(const char file[]) : fName(file), fOwnership(kCallerPasses_Ownership) { michael@0: fFILE = file ? sk_fopen(fName.c_str(), kRead_SkFILE_Flag) : NULL; michael@0: } michael@0: michael@0: SkFILEStream::SkFILEStream(FILE* file, Ownership ownership) michael@0: : fFILE((SkFILE*)file) michael@0: , fOwnership(ownership) { michael@0: } michael@0: michael@0: SkFILEStream::~SkFILEStream() { michael@0: if (fFILE && fOwnership != kCallerRetains_Ownership) { michael@0: sk_fclose(fFILE); michael@0: } michael@0: } michael@0: michael@0: void SkFILEStream::setPath(const char path[]) { michael@0: fName.set(path); michael@0: if (fFILE) { michael@0: sk_fclose(fFILE); michael@0: fFILE = NULL; michael@0: } michael@0: if (path) { michael@0: fFILE = sk_fopen(fName.c_str(), kRead_SkFILE_Flag); michael@0: } michael@0: } michael@0: michael@0: size_t SkFILEStream::read(void* buffer, size_t size) { michael@0: if (fFILE) { michael@0: return sk_fread(buffer, size, fFILE); michael@0: } michael@0: return 0; michael@0: } michael@0: michael@0: bool SkFILEStream::isAtEnd() const { michael@0: return sk_feof(fFILE); michael@0: } michael@0: michael@0: bool SkFILEStream::rewind() { michael@0: if (fFILE) { michael@0: if (sk_frewind(fFILE)) { michael@0: return true; michael@0: } michael@0: // we hit an error michael@0: sk_fclose(fFILE); michael@0: fFILE = NULL; michael@0: } michael@0: return false; michael@0: } michael@0: michael@0: SkStreamAsset* SkFILEStream::duplicate() const { michael@0: if (NULL == fFILE) { michael@0: return new SkMemoryStream(); michael@0: } michael@0: michael@0: if (NULL != fData.get()) { michael@0: return new SkMemoryStream(fData); michael@0: } michael@0: michael@0: if (!fName.isEmpty()) { michael@0: SkAutoTUnref that(new SkFILEStream(fName.c_str())); michael@0: if (sk_fidentical(that->fFILE, this->fFILE)) { michael@0: return that.detach(); michael@0: } michael@0: } michael@0: michael@0: fData.reset(SkData::NewFromFILE(fFILE)); michael@0: if (NULL == fData.get()) { michael@0: return NULL; michael@0: } michael@0: return new SkMemoryStream(fData); michael@0: } michael@0: michael@0: size_t SkFILEStream::getPosition() const { michael@0: return sk_ftell(fFILE); michael@0: } michael@0: michael@0: bool SkFILEStream::seek(size_t position) { michael@0: return sk_fseek(fFILE, position); michael@0: } michael@0: michael@0: bool SkFILEStream::move(long offset) { michael@0: return sk_fmove(fFILE, offset); michael@0: } michael@0: michael@0: SkStreamAsset* SkFILEStream::fork() const { michael@0: SkAutoTUnref that(this->duplicate()); michael@0: that->seek(this->getPosition()); michael@0: return that.detach(); michael@0: } michael@0: michael@0: size_t SkFILEStream::getLength() const { michael@0: return sk_fgetsize(fFILE); michael@0: } michael@0: michael@0: const void* SkFILEStream::getMemoryBase() { michael@0: if (NULL == fData.get()) { michael@0: return NULL; michael@0: } michael@0: return fData->data(); michael@0: } michael@0: michael@0: /////////////////////////////////////////////////////////////////////////////// michael@0: michael@0: static SkData* newFromParams(const void* src, size_t size, bool copyData) { michael@0: if (copyData) { michael@0: return SkData::NewWithCopy(src, size); michael@0: } else { michael@0: return SkData::NewWithProc(src, size, NULL, NULL); michael@0: } michael@0: } michael@0: michael@0: SkMemoryStream::SkMemoryStream() { michael@0: fData = SkData::NewEmpty(); michael@0: fOffset = 0; michael@0: } michael@0: michael@0: SkMemoryStream::SkMemoryStream(size_t size) { michael@0: fData = SkData::NewFromMalloc(sk_malloc_throw(size), size); michael@0: fOffset = 0; michael@0: } michael@0: michael@0: SkMemoryStream::SkMemoryStream(const void* src, size_t size, bool copyData) { michael@0: fData = newFromParams(src, size, copyData); michael@0: fOffset = 0; michael@0: } michael@0: michael@0: SkMemoryStream::SkMemoryStream(SkData* data) { michael@0: if (NULL == data) { michael@0: fData = SkData::NewEmpty(); michael@0: } else { michael@0: fData = data; michael@0: fData->ref(); michael@0: } michael@0: fOffset = 0; michael@0: } michael@0: michael@0: SkMemoryStream::~SkMemoryStream() { michael@0: fData->unref(); michael@0: } michael@0: michael@0: void SkMemoryStream::setMemoryOwned(const void* src, size_t size) { michael@0: fData->unref(); michael@0: fData = SkData::NewFromMalloc(src, size); michael@0: fOffset = 0; michael@0: } michael@0: michael@0: void SkMemoryStream::setMemory(const void* src, size_t size, bool copyData) { michael@0: fData->unref(); michael@0: fData = newFromParams(src, size, copyData); michael@0: fOffset = 0; michael@0: } michael@0: michael@0: SkData* SkMemoryStream::copyToData() const { michael@0: fData->ref(); michael@0: return fData; michael@0: } michael@0: michael@0: SkData* SkMemoryStream::setData(SkData* data) { michael@0: fData->unref(); michael@0: if (NULL == data) { michael@0: fData = SkData::NewEmpty(); michael@0: } else { michael@0: fData = data; michael@0: fData->ref(); michael@0: } michael@0: fOffset = 0; michael@0: return data; michael@0: } michael@0: michael@0: void SkMemoryStream::skipToAlign4() { michael@0: // cast to remove unary-minus warning michael@0: fOffset += -(int)fOffset & 0x03; michael@0: } michael@0: michael@0: size_t SkMemoryStream::read(void* buffer, size_t size) { michael@0: size_t dataSize = fData->size(); michael@0: michael@0: if (size > dataSize - fOffset) { michael@0: size = dataSize - fOffset; michael@0: } michael@0: if (buffer) { michael@0: memcpy(buffer, fData->bytes() + fOffset, size); michael@0: } michael@0: fOffset += size; michael@0: return size; michael@0: } michael@0: michael@0: bool SkMemoryStream::isAtEnd() const { michael@0: return fOffset == fData->size(); michael@0: } michael@0: michael@0: bool SkMemoryStream::rewind() { michael@0: fOffset = 0; michael@0: return true; michael@0: } michael@0: michael@0: SkMemoryStream* SkMemoryStream::duplicate() const { michael@0: return SkNEW_ARGS(SkMemoryStream, (fData)); michael@0: } michael@0: michael@0: size_t SkMemoryStream::getPosition() const { michael@0: return fOffset; michael@0: } michael@0: michael@0: bool SkMemoryStream::seek(size_t position) { michael@0: fOffset = position > fData->size() michael@0: ? fData->size() michael@0: : position; michael@0: return true; michael@0: } michael@0: michael@0: bool SkMemoryStream::move(long offset) { michael@0: return this->seek(fOffset + offset); michael@0: } michael@0: michael@0: SkMemoryStream* SkMemoryStream::fork() const { michael@0: SkAutoTUnref that(this->duplicate()); michael@0: that->seek(fOffset); michael@0: return that.detach(); michael@0: } michael@0: michael@0: size_t SkMemoryStream::getLength() const { michael@0: return fData->size(); michael@0: } michael@0: michael@0: const void* SkMemoryStream::getMemoryBase() { michael@0: return fData->data(); michael@0: } michael@0: michael@0: const void* SkMemoryStream::getAtPos() { michael@0: return fData->bytes() + fOffset; michael@0: } michael@0: michael@0: ///////////////////////////////////////////////////////////////////////////////////////////////////////// michael@0: ///////////////////////////////////////////////////////////////////////////////////////////////////////// michael@0: michael@0: SkFILEWStream::SkFILEWStream(const char path[]) michael@0: { michael@0: fFILE = sk_fopen(path, kWrite_SkFILE_Flag); michael@0: } michael@0: michael@0: SkFILEWStream::~SkFILEWStream() michael@0: { michael@0: if (fFILE) { michael@0: sk_fclose(fFILE); michael@0: } michael@0: } michael@0: michael@0: size_t SkFILEWStream::bytesWritten() const { michael@0: return sk_ftell(fFILE); michael@0: } michael@0: michael@0: bool SkFILEWStream::write(const void* buffer, size_t size) michael@0: { michael@0: if (fFILE == NULL) { michael@0: return false; michael@0: } michael@0: michael@0: if (sk_fwrite(buffer, size, fFILE) != size) michael@0: { michael@0: SkDEBUGCODE(SkDebugf("SkFILEWStream failed writing %d bytes\n", size);) michael@0: sk_fclose(fFILE); michael@0: fFILE = NULL; michael@0: return false; michael@0: } michael@0: return true; michael@0: } michael@0: michael@0: void SkFILEWStream::flush() michael@0: { michael@0: if (fFILE) { michael@0: sk_fflush(fFILE); michael@0: } michael@0: } michael@0: michael@0: //////////////////////////////////////////////////////////////////////// michael@0: michael@0: SkMemoryWStream::SkMemoryWStream(void* buffer, size_t size) michael@0: : fBuffer((char*)buffer), fMaxLength(size), fBytesWritten(0) michael@0: { michael@0: } michael@0: michael@0: bool SkMemoryWStream::write(const void* buffer, size_t size) michael@0: { michael@0: size = SkMin32(size, fMaxLength - fBytesWritten); michael@0: if (size > 0) michael@0: { michael@0: memcpy(fBuffer + fBytesWritten, buffer, size); michael@0: fBytesWritten += size; michael@0: return true; michael@0: } michael@0: return false; michael@0: } michael@0: michael@0: //////////////////////////////////////////////////////////////////////// michael@0: michael@0: #define SkDynamicMemoryWStream_MinBlockSize 256 michael@0: michael@0: struct SkDynamicMemoryWStream::Block { michael@0: Block* fNext; michael@0: char* fCurr; michael@0: char* fStop; michael@0: michael@0: const char* start() const { return (const char*)(this + 1); } michael@0: char* start() { return (char*)(this + 1); } michael@0: size_t avail() const { return fStop - fCurr; } michael@0: size_t written() const { return fCurr - this->start(); } michael@0: michael@0: void init(size_t size) michael@0: { michael@0: fNext = NULL; michael@0: fCurr = this->start(); michael@0: fStop = this->start() + size; michael@0: } michael@0: michael@0: const void* append(const void* data, size_t size) michael@0: { michael@0: SkASSERT((size_t)(fStop - fCurr) >= size); michael@0: memcpy(fCurr, data, size); michael@0: fCurr += size; michael@0: return (const void*)((const char*)data + size); michael@0: } michael@0: }; michael@0: michael@0: SkDynamicMemoryWStream::SkDynamicMemoryWStream() michael@0: : fHead(NULL), fTail(NULL), fBytesWritten(0), fCopy(NULL) michael@0: { michael@0: } michael@0: michael@0: SkDynamicMemoryWStream::~SkDynamicMemoryWStream() michael@0: { michael@0: reset(); michael@0: } michael@0: michael@0: void SkDynamicMemoryWStream::reset() michael@0: { michael@0: this->invalidateCopy(); michael@0: michael@0: Block* block = fHead; michael@0: michael@0: while (block != NULL) { michael@0: Block* next = block->fNext; michael@0: sk_free(block); michael@0: block = next; michael@0: } michael@0: fHead = fTail = NULL; michael@0: fBytesWritten = 0; michael@0: } michael@0: michael@0: bool SkDynamicMemoryWStream::write(const void* buffer, size_t count) michael@0: { michael@0: if (count > 0) { michael@0: this->invalidateCopy(); michael@0: michael@0: fBytesWritten += count; michael@0: michael@0: size_t size; michael@0: michael@0: if (fTail != NULL && fTail->avail() > 0) { michael@0: size = SkMin32(fTail->avail(), count); michael@0: buffer = fTail->append(buffer, size); michael@0: SkASSERT(count >= size); michael@0: count -= size; michael@0: if (count == 0) michael@0: return true; michael@0: } michael@0: michael@0: size = SkMax32(count, SkDynamicMemoryWStream_MinBlockSize); michael@0: Block* block = (Block*)sk_malloc_throw(sizeof(Block) + size); michael@0: block->init(size); michael@0: block->append(buffer, count); michael@0: michael@0: if (fTail != NULL) michael@0: fTail->fNext = block; michael@0: else michael@0: fHead = fTail = block; michael@0: fTail = block; michael@0: } michael@0: return true; michael@0: } michael@0: michael@0: bool SkDynamicMemoryWStream::write(const void* buffer, size_t offset, size_t count) michael@0: { michael@0: if (offset + count > fBytesWritten) { michael@0: return false; // test does not partially modify michael@0: } michael@0: michael@0: this->invalidateCopy(); michael@0: michael@0: Block* block = fHead; michael@0: while (block != NULL) { michael@0: size_t size = block->written(); michael@0: if (offset < size) { michael@0: size_t part = offset + count > size ? size - offset : count; michael@0: memcpy(block->start() + offset, buffer, part); michael@0: if (count <= part) michael@0: return true; michael@0: count -= part; michael@0: buffer = (const void*) ((char* ) buffer + part); michael@0: } michael@0: offset = offset > size ? offset - size : 0; michael@0: block = block->fNext; michael@0: } michael@0: return false; michael@0: } michael@0: michael@0: bool SkDynamicMemoryWStream::read(void* buffer, size_t offset, size_t count) michael@0: { michael@0: if (offset + count > fBytesWritten) michael@0: return false; // test does not partially modify michael@0: Block* block = fHead; michael@0: while (block != NULL) { michael@0: size_t size = block->written(); michael@0: if (offset < size) { michael@0: size_t part = offset + count > size ? size - offset : count; michael@0: memcpy(buffer, block->start() + offset, part); michael@0: if (count <= part) michael@0: return true; michael@0: count -= part; michael@0: buffer = (void*) ((char* ) buffer + part); michael@0: } michael@0: offset = offset > size ? offset - size : 0; michael@0: block = block->fNext; michael@0: } michael@0: return false; michael@0: } michael@0: michael@0: void SkDynamicMemoryWStream::copyTo(void* dst) const michael@0: { michael@0: if (fCopy) { michael@0: memcpy(dst, fCopy->data(), fBytesWritten); michael@0: } else { michael@0: Block* block = fHead; michael@0: michael@0: while (block != NULL) { michael@0: size_t size = block->written(); michael@0: memcpy(dst, block->start(), size); michael@0: dst = (void*)((char*)dst + size); michael@0: block = block->fNext; michael@0: } michael@0: } michael@0: } michael@0: michael@0: void SkDynamicMemoryWStream::padToAlign4() michael@0: { michael@0: // cast to remove unary-minus warning michael@0: int padBytes = -(int)fBytesWritten & 0x03; michael@0: if (padBytes == 0) michael@0: return; michael@0: int zero = 0; michael@0: write(&zero, padBytes); michael@0: } michael@0: michael@0: SkData* SkDynamicMemoryWStream::copyToData() const { michael@0: if (NULL == fCopy) { michael@0: void* buffer = sk_malloc_throw(fBytesWritten); michael@0: this->copyTo(buffer); michael@0: fCopy = SkData::NewFromMalloc(buffer, fBytesWritten); michael@0: } michael@0: fCopy->ref(); michael@0: return fCopy; michael@0: } michael@0: michael@0: void SkDynamicMemoryWStream::invalidateCopy() { michael@0: if (fCopy) { michael@0: fCopy->unref(); michael@0: fCopy = NULL; michael@0: } michael@0: } michael@0: michael@0: class SkBlockMemoryRefCnt : public SkRefCnt { michael@0: public: michael@0: explicit SkBlockMemoryRefCnt(SkDynamicMemoryWStream::Block* head) : fHead(head) { } michael@0: michael@0: virtual ~SkBlockMemoryRefCnt() { michael@0: SkDynamicMemoryWStream::Block* block = fHead; michael@0: while (block != NULL) { michael@0: SkDynamicMemoryWStream::Block* next = block->fNext; michael@0: sk_free(block); michael@0: block = next; michael@0: } michael@0: } michael@0: michael@0: SkDynamicMemoryWStream::Block* const fHead; michael@0: }; michael@0: michael@0: class SkBlockMemoryStream : public SkStreamAsset { michael@0: public: michael@0: SkBlockMemoryStream(SkDynamicMemoryWStream::Block* head, size_t size) michael@0: : fBlockMemory(SkNEW_ARGS(SkBlockMemoryRefCnt, (head))), fCurrent(head) michael@0: , fSize(size) , fOffset(0), fCurrentOffset(0) { } michael@0: michael@0: SkBlockMemoryStream(SkBlockMemoryRefCnt* headRef, size_t size) michael@0: : fBlockMemory(SkRef(headRef)), fCurrent(fBlockMemory->fHead) michael@0: , fSize(size) , fOffset(0), fCurrentOffset(0) { } michael@0: michael@0: virtual size_t read(void* buffer, size_t rawCount) SK_OVERRIDE { michael@0: size_t count = rawCount; michael@0: if (fOffset + count > fSize) { michael@0: count = fSize - fOffset; michael@0: } michael@0: size_t bytesLeftToRead = count; michael@0: while (fCurrent != NULL) { michael@0: size_t bytesLeftInCurrent = fCurrent->written() - fCurrentOffset; michael@0: size_t bytesFromCurrent = SkTMin(bytesLeftToRead, bytesLeftInCurrent); michael@0: if (buffer) { michael@0: memcpy(buffer, fCurrent->start() + fCurrentOffset, bytesFromCurrent); michael@0: buffer = SkTAddOffset(buffer, bytesFromCurrent); michael@0: } michael@0: if (bytesLeftToRead <= bytesFromCurrent) { michael@0: fCurrentOffset += bytesFromCurrent; michael@0: fOffset += count; michael@0: return count; michael@0: } michael@0: bytesLeftToRead -= bytesFromCurrent; michael@0: fCurrent = fCurrent->fNext; michael@0: fCurrentOffset = 0; michael@0: } michael@0: SkASSERT(false); michael@0: return 0; michael@0: } michael@0: michael@0: virtual bool isAtEnd() const SK_OVERRIDE { michael@0: return fOffset == fSize; michael@0: } michael@0: michael@0: virtual bool rewind() SK_OVERRIDE { michael@0: fCurrent = fBlockMemory->fHead; michael@0: fOffset = 0; michael@0: fCurrentOffset = 0; michael@0: return true; michael@0: } michael@0: michael@0: virtual SkBlockMemoryStream* duplicate() const SK_OVERRIDE { michael@0: return SkNEW_ARGS(SkBlockMemoryStream, (fBlockMemory.get(), fSize)); michael@0: } michael@0: michael@0: virtual size_t getPosition() const SK_OVERRIDE { michael@0: return fOffset; michael@0: } michael@0: michael@0: virtual bool seek(size_t position) SK_OVERRIDE { michael@0: // If possible, skip forward. michael@0: if (position >= fOffset) { michael@0: size_t skipAmount = position - fOffset; michael@0: return this->skip(skipAmount) == skipAmount; michael@0: } michael@0: // If possible, move backward within the current block. michael@0: size_t moveBackAmount = fOffset - position; michael@0: if (moveBackAmount <= fCurrentOffset) { michael@0: fCurrentOffset -= moveBackAmount; michael@0: fOffset -= moveBackAmount; michael@0: return true; michael@0: } michael@0: // Otherwise rewind and move forward. michael@0: return this->rewind() && this->skip(position) == position; michael@0: } michael@0: michael@0: virtual bool move(long offset) SK_OVERRIDE { michael@0: return seek(fOffset + offset); michael@0: } michael@0: michael@0: virtual SkBlockMemoryStream* fork() const SK_OVERRIDE { michael@0: SkAutoTUnref that(this->duplicate()); michael@0: that->fCurrent = this->fCurrent; michael@0: that->fOffset = this->fOffset; michael@0: that->fCurrentOffset = this->fCurrentOffset; michael@0: return that.detach(); michael@0: } michael@0: michael@0: virtual size_t getLength() const SK_OVERRIDE { michael@0: return fSize; michael@0: } michael@0: michael@0: virtual const void* getMemoryBase() SK_OVERRIDE { michael@0: if (NULL == fBlockMemory->fHead->fNext) { michael@0: return fBlockMemory->fHead->start(); michael@0: } michael@0: return NULL; michael@0: } michael@0: michael@0: private: michael@0: SkAutoTUnref const fBlockMemory; michael@0: SkDynamicMemoryWStream::Block const * fCurrent; michael@0: size_t const fSize; michael@0: size_t fOffset; michael@0: size_t fCurrentOffset; michael@0: }; michael@0: michael@0: SkStreamAsset* SkDynamicMemoryWStream::detachAsStream() { michael@0: if (fCopy) { michael@0: SkMemoryStream* stream = SkNEW_ARGS(SkMemoryStream, (fCopy)); michael@0: this->reset(); michael@0: return stream; michael@0: } michael@0: SkBlockMemoryStream* stream = SkNEW_ARGS(SkBlockMemoryStream, (fHead, fBytesWritten)); michael@0: fHead = 0; michael@0: this->reset(); michael@0: return stream; michael@0: } michael@0: michael@0: /////////////////////////////////////////////////////////////////////////////// michael@0: michael@0: void SkDebugWStream::newline() michael@0: { michael@0: #if defined(SK_DEBUG) || defined(SK_DEVELOPER) michael@0: SkDebugf("\n"); michael@0: fBytesWritten++; michael@0: #endif michael@0: } michael@0: michael@0: bool SkDebugWStream::write(const void* buffer, size_t size) michael@0: { michael@0: #if defined(SK_DEBUG) || defined(SK_DEVELOPER) michael@0: char* s = new char[size+1]; michael@0: memcpy(s, buffer, size); michael@0: s[size] = 0; michael@0: SkDebugf("%s", s); michael@0: delete[] s; michael@0: fBytesWritten += size; michael@0: #endif michael@0: return true; michael@0: } michael@0: michael@0: /////////////////////////////////////////////////////////////////////////////// michael@0: /////////////////////////////////////////////////////////////////////////////// michael@0: michael@0: michael@0: static SkData* mmap_filename(const char path[]) { michael@0: SkFILE* file = sk_fopen(path, kRead_SkFILE_Flag); michael@0: if (NULL == file) { michael@0: return NULL; michael@0: } michael@0: michael@0: SkData* data = SkData::NewFromFILE(file); michael@0: sk_fclose(file); michael@0: return data; michael@0: } michael@0: michael@0: SkStreamAsset* SkStream::NewFromFile(const char path[]) { michael@0: SkAutoTUnref data(mmap_filename(path)); michael@0: if (data.get()) { michael@0: return SkNEW_ARGS(SkMemoryStream, (data.get())); michael@0: } michael@0: michael@0: // If we get here, then our attempt at using mmap failed, so try normal michael@0: // file access. michael@0: SkFILEStream* stream = SkNEW_ARGS(SkFILEStream, (path)); michael@0: if (!stream->isValid()) { michael@0: stream->unref(); michael@0: stream = NULL; michael@0: } michael@0: return stream; michael@0: }