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: #ifndef SkBuffer_DEFINED michael@0: #define SkBuffer_DEFINED michael@0: michael@0: #include "SkScalar.h" michael@0: michael@0: /** \class SkRBuffer michael@0: michael@0: Light weight class for reading data from a memory block. michael@0: The RBuffer is given the buffer to read from, with either a specified size michael@0: or no size (in which case no range checking is performed). It is iillegal michael@0: to attempt to read a value from an empty RBuffer (data == null). michael@0: */ michael@0: class SkRBuffer : SkNoncopyable { michael@0: public: michael@0: SkRBuffer() : fData(0), fPos(0), fStop(0) {} michael@0: /** Initialize RBuffer with a data pointer, but no specified length. michael@0: This signals the RBuffer to not perform range checks during reading. michael@0: */ michael@0: SkRBuffer(const void* data) { michael@0: fData = (const char*)data; michael@0: fPos = (const char*)data; michael@0: fStop = 0; // no bounds checking michael@0: } michael@0: /** Initialize RBuffer with a data point and length. michael@0: */ michael@0: SkRBuffer(const void* data, size_t size) { michael@0: SkASSERT(data != 0 || size == 0); michael@0: fData = (const char*)data; michael@0: fPos = (const char*)data; michael@0: fStop = (const char*)data + size; michael@0: } michael@0: michael@0: virtual ~SkRBuffer() { } michael@0: michael@0: /** Return the number of bytes that have been read from the beginning michael@0: of the data pointer. michael@0: */ michael@0: size_t pos() const { return fPos - fData; } michael@0: /** Return the total size of the data pointer. Only defined if the length was michael@0: specified in the constructor or in a call to reset(). michael@0: */ michael@0: size_t size() const { return fStop - fData; } michael@0: /** Return true if the buffer has read to the end of the data pointer. michael@0: Only defined if the length was specified in the constructor or in a call michael@0: to reset(). Always returns true if the length was not specified. michael@0: */ michael@0: bool eof() const { return fPos >= fStop; } michael@0: michael@0: /** Read the specified number of bytes from the data pointer. If buffer is not michael@0: null, copy those bytes into buffer. michael@0: */ michael@0: virtual bool read(void* buffer, size_t size) { michael@0: if (size) { michael@0: this->readNoSizeCheck(buffer, size); michael@0: } michael@0: return true; michael@0: } michael@0: michael@0: const void* skip(size_t size); // return start of skipped data michael@0: size_t skipToAlign4(); michael@0: michael@0: bool readPtr(void** ptr) { return read(ptr, sizeof(void*)); } michael@0: bool readScalar(SkScalar* x) { return read(x, 4); } michael@0: bool readU32(uint32_t* x) { return read(x, 4); } michael@0: bool readS32(int32_t* x) { return read(x, 4); } michael@0: bool readU16(uint16_t* x) { return read(x, 2); } michael@0: bool readS16(int16_t* x) { return read(x, 2); } michael@0: bool readU8(uint8_t* x) { return read(x, 1); } michael@0: bool readBool(bool* x) { michael@0: uint8_t u8; michael@0: if (this->readU8(&u8)) { michael@0: *x = (u8 != 0); michael@0: return true; michael@0: } michael@0: return false; michael@0: } michael@0: michael@0: protected: michael@0: void readNoSizeCheck(void* buffer, size_t size); michael@0: michael@0: const char* fData; michael@0: const char* fPos; michael@0: const char* fStop; michael@0: }; michael@0: michael@0: /** \class SkRBufferWithSizeCheck michael@0: michael@0: Same as SkRBuffer, except that a size check is performed before the read operation and an michael@0: error is set if the read operation is attempting to read past the end of the data. michael@0: */ michael@0: class SkRBufferWithSizeCheck : public SkRBuffer { michael@0: public: michael@0: SkRBufferWithSizeCheck(const void* data, size_t size) : SkRBuffer(data, size), fError(false) {} michael@0: michael@0: /** Read the specified number of bytes from the data pointer. If buffer is not michael@0: null and the number of bytes to read does not overflow this object's data, michael@0: copy those bytes into buffer. michael@0: */ michael@0: virtual bool read(void* buffer, size_t size) SK_OVERRIDE; michael@0: michael@0: /** Returns whether or not a read operation attempted to read past the end of the data. michael@0: */ michael@0: bool isValid() const { return !fError; } michael@0: private: michael@0: bool fError; michael@0: }; michael@0: michael@0: /** \class SkWBuffer michael@0: michael@0: Light weight class for writing data to a memory block. michael@0: The WBuffer is given the buffer to write into, with either a specified size michael@0: or no size, in which case no range checking is performed. An empty WBuffer michael@0: is legal, in which case no data is ever written, but the relative pos() michael@0: is updated. michael@0: */ michael@0: class SkWBuffer : SkNoncopyable { michael@0: public: michael@0: SkWBuffer() : fData(0), fPos(0), fStop(0) {} michael@0: SkWBuffer(void* data) { reset(data); } michael@0: SkWBuffer(void* data, size_t size) { reset(data, size); } michael@0: michael@0: void reset(void* data) { michael@0: fData = (char*)data; michael@0: fPos = (char*)data; michael@0: fStop = 0; // no bounds checking michael@0: } michael@0: michael@0: void reset(void* data, size_t size) { michael@0: SkASSERT(data != 0 || size == 0); michael@0: fData = (char*)data; michael@0: fPos = (char*)data; michael@0: fStop = (char*)data + size; michael@0: } michael@0: michael@0: size_t pos() const { return fPos - fData; } michael@0: void* skip(size_t size); // return start of skipped data michael@0: michael@0: void write(const void* buffer, size_t size) { michael@0: if (size) { michael@0: this->writeNoSizeCheck(buffer, size); michael@0: } michael@0: } michael@0: michael@0: size_t padToAlign4(); michael@0: michael@0: void writePtr(const void* x) { this->writeNoSizeCheck(&x, sizeof(x)); } michael@0: void writeScalar(SkScalar x) { this->writeNoSizeCheck(&x, 4); } michael@0: void write32(int32_t x) { this->writeNoSizeCheck(&x, 4); } michael@0: void write16(int16_t x) { this->writeNoSizeCheck(&x, 2); } michael@0: void write8(int8_t x) { this->writeNoSizeCheck(&x, 1); } michael@0: void writeBool(bool x) { this->write8(x); } michael@0: michael@0: private: michael@0: void writeNoSizeCheck(const void* buffer, size_t size); michael@0: michael@0: char* fData; michael@0: char* fPos; michael@0: char* fStop; michael@0: }; michael@0: michael@0: #endif