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: #ifndef SkStream_DEFINED michael@0: #define SkStream_DEFINED michael@0: michael@0: #include "SkRefCnt.h" michael@0: #include "SkScalar.h" michael@0: michael@0: class SkData; michael@0: michael@0: class SkStream; michael@0: class SkStreamRewindable; michael@0: class SkStreamSeekable; michael@0: class SkStreamAsset; michael@0: class SkStreamMemory; michael@0: michael@0: /** michael@0: * SkStream -- abstraction for a source of bytes. Subclasses can be backed by michael@0: * memory, or a file, or something else. michael@0: * michael@0: * NOTE: michael@0: * michael@0: * Classic "streams" APIs are sort of async, in that on a request for N michael@0: * bytes, they may return fewer than N bytes on a given call, in which case michael@0: * the caller can "try again" to get more bytes, eventually (modulo an error) michael@0: * receiving their total N bytes. michael@0: * michael@0: * Skia streams behave differently. They are effectively synchronous, and will michael@0: * always return all N bytes of the request if possible. If they return fewer michael@0: * (the read() call returns the number of bytes read) then that means there is michael@0: * no more data (at EOF or hit an error). The caller should *not* call again michael@0: * in hopes of fulfilling more of the request. michael@0: */ michael@0: class SK_API SkStream : public SkRefCnt { //TODO: remove SkRefCnt michael@0: public: michael@0: /** michael@0: * Attempts to open the specified file, and return a stream to it (using michael@0: * mmap if available). On success, the caller must call unref() on the michael@0: * returned object. On failure, returns NULL. michael@0: */ michael@0: static SkStreamAsset* NewFromFile(const char path[]); michael@0: michael@0: SK_DECLARE_INST_COUNT(SkStream) michael@0: michael@0: /** Reads or skips size number of bytes. michael@0: * If buffer == NULL, skip size bytes, return how many were skipped. michael@0: * If buffer != NULL, copy size bytes into buffer, return how many were copied. michael@0: * @param buffer when NULL skip size bytes, otherwise copy size bytes into buffer michael@0: * @param size the number of bytes to skip or copy michael@0: * @return the number of bytes actually read. michael@0: */ michael@0: virtual size_t read(void* buffer, size_t size) = 0; michael@0: michael@0: /** Skip size number of bytes. michael@0: * @return the actual number bytes that could be skipped. michael@0: */ michael@0: size_t skip(size_t size) { michael@0: return this->read(NULL, size); michael@0: } michael@0: michael@0: /** Returns true when all the bytes in the stream have been read. michael@0: * This may return true early (when there are no more bytes to be read) michael@0: * or late (after the first unsuccessful read). michael@0: */ michael@0: virtual bool isAtEnd() const = 0; michael@0: michael@0: int8_t readS8(); michael@0: int16_t readS16(); michael@0: int32_t readS32(); michael@0: michael@0: uint8_t readU8() { return (uint8_t)this->readS8(); } michael@0: uint16_t readU16() { return (uint16_t)this->readS16(); } michael@0: uint32_t readU32() { return (uint32_t)this->readS32(); } michael@0: michael@0: bool readBool() { return this->readU8() != 0; } michael@0: SkScalar readScalar(); michael@0: size_t readPackedUInt(); michael@0: michael@0: /** michael@0: * Reconstitute an SkData object that was written to the stream michael@0: * using SkWStream::writeData(). michael@0: */ michael@0: SkData* readData(); michael@0: michael@0: //SkStreamRewindable michael@0: /** Rewinds to the beginning of the stream. Returns true if the stream is known michael@0: * to be at the beginning after this call returns. michael@0: */ michael@0: virtual bool rewind() { return false; } michael@0: michael@0: /** Duplicates this stream. If this cannot be done, returns NULL. michael@0: * The returned stream will be positioned at the beginning of its data. michael@0: */ michael@0: virtual SkStreamRewindable* duplicate() const { return NULL; } michael@0: michael@0: //SkStreamSeekable michael@0: /** Returns true if this stream can report it's current position. */ michael@0: virtual bool hasPosition() const { return false; } michael@0: /** Returns the current position in the stream. If this cannot be done, returns 0. */ michael@0: virtual size_t getPosition() const { return 0; } michael@0: michael@0: /** Seeks to an absolute position in the stream. If this cannot be done, returns false. michael@0: * If an attempt is made to seek past the end of the stream, the position will be set michael@0: * to the end of the stream. michael@0: */ michael@0: virtual bool seek(size_t position) { return false; } michael@0: michael@0: /** Seeks to an relative offset in the stream. If this cannot be done, returns false. michael@0: * If an attempt is made to move to a position outside the stream, the position will be set michael@0: * to the closest point within the stream (beginning or end). michael@0: */ michael@0: virtual bool move(long offset) { return false; } michael@0: michael@0: /** Duplicates this stream. If this cannot be done, returns NULL. michael@0: * The returned stream will be positioned the same as this stream. michael@0: */ michael@0: virtual SkStreamSeekable* fork() const { return NULL; } michael@0: michael@0: //SkStreamAsset michael@0: /** Returns true if this stream can report it's total length. */ michael@0: virtual bool hasLength() const { return false; } michael@0: /** Returns the total length of the stream. If this cannot be done, returns 0. */ michael@0: virtual size_t getLength() const { return 0; } michael@0: michael@0: //SkStreamMemory michael@0: /** Returns the starting address for the data. If this cannot be done, returns NULL. */ michael@0: //TODO: replace with virtual const SkData* getData() michael@0: virtual const void* getMemoryBase() { return NULL; } michael@0: michael@0: private: michael@0: typedef SkRefCnt INHERITED; michael@0: }; michael@0: michael@0: /** SkStreamRewindable is a SkStream for which rewind and duplicate are required. */ michael@0: class SK_API SkStreamRewindable : public SkStream { michael@0: public: michael@0: virtual bool rewind() SK_OVERRIDE = 0; michael@0: virtual SkStreamRewindable* duplicate() const SK_OVERRIDE = 0; michael@0: }; michael@0: michael@0: /** SkStreamSeekable is a SkStreamRewindable for which position, seek, move, and fork are required. */ michael@0: class SK_API SkStreamSeekable : public SkStreamRewindable { michael@0: public: michael@0: virtual SkStreamSeekable* duplicate() const SK_OVERRIDE = 0; michael@0: michael@0: virtual bool hasPosition() const SK_OVERRIDE { return true; } michael@0: virtual size_t getPosition() const SK_OVERRIDE = 0; michael@0: virtual bool seek(size_t position) SK_OVERRIDE = 0; michael@0: virtual bool move(long offset) SK_OVERRIDE = 0; michael@0: virtual SkStreamSeekable* fork() const SK_OVERRIDE = 0; michael@0: }; michael@0: michael@0: /** SkStreamAsset is a SkStreamSeekable for which getLength is required. */ michael@0: class SK_API SkStreamAsset : public SkStreamSeekable { michael@0: public: michael@0: virtual SkStreamAsset* duplicate() const SK_OVERRIDE = 0; michael@0: virtual SkStreamAsset* fork() const SK_OVERRIDE = 0; michael@0: michael@0: virtual bool hasLength() const SK_OVERRIDE { return true; } michael@0: virtual size_t getLength() const SK_OVERRIDE = 0; michael@0: }; michael@0: michael@0: /** SkStreamMemory is a SkStreamAsset for which getMemoryBase is required. */ michael@0: class SK_API SkStreamMemory : public SkStreamAsset { michael@0: public: michael@0: virtual SkStreamMemory* duplicate() const SK_OVERRIDE = 0; michael@0: virtual SkStreamMemory* fork() const SK_OVERRIDE = 0; michael@0: michael@0: virtual const void* getMemoryBase() SK_OVERRIDE = 0; michael@0: }; michael@0: michael@0: class SK_API SkWStream : SkNoncopyable { michael@0: public: michael@0: SK_DECLARE_INST_COUNT_ROOT(SkWStream) michael@0: michael@0: virtual ~SkWStream(); michael@0: michael@0: /** Called to write bytes to a SkWStream. Returns true on success michael@0: @param buffer the address of at least size bytes to be written to the stream michael@0: @param size The number of bytes in buffer to write to the stream michael@0: @return true on success michael@0: */ michael@0: virtual bool write(const void* buffer, size_t size) = 0; michael@0: virtual void newline(); michael@0: virtual void flush(); michael@0: michael@0: virtual size_t bytesWritten() const = 0; michael@0: michael@0: // helpers michael@0: michael@0: bool write8(U8CPU); michael@0: bool write16(U16CPU); michael@0: bool write32(uint32_t); michael@0: michael@0: bool writeText(const char text[]); michael@0: bool writeDecAsText(int32_t); michael@0: bool writeBigDecAsText(int64_t, int minDigits = 0); michael@0: bool writeHexAsText(uint32_t, int minDigits = 0); michael@0: bool writeScalarAsText(SkScalar); michael@0: michael@0: bool writeBool(bool v) { return this->write8(v); } michael@0: bool writeScalar(SkScalar); michael@0: bool writePackedUInt(size_t); michael@0: michael@0: bool writeStream(SkStream* input, size_t length); michael@0: michael@0: /** michael@0: * Append an SkData object to the stream, such that it can be read michael@0: * out of the stream using SkStream::readData(). michael@0: * michael@0: * Note that the encoding method used to write the SkData object michael@0: * to the stream may change over time. This method DOES NOT michael@0: * just write the raw content of the SkData object to the stream. michael@0: */ michael@0: bool writeData(const SkData*); michael@0: michael@0: /** michael@0: * This returns the number of bytes in the stream required to store michael@0: * 'value'. michael@0: */ michael@0: static int SizeOfPackedUInt(size_t value); michael@0: }; michael@0: michael@0: //////////////////////////////////////////////////////////////////////////////////////// michael@0: michael@0: #include "SkString.h" michael@0: #include michael@0: michael@0: struct SkFILE; michael@0: michael@0: /** A stream that wraps a C FILE* file stream. */ michael@0: class SK_API SkFILEStream : public SkStreamAsset { michael@0: public: michael@0: SK_DECLARE_INST_COUNT(SkFILEStream) michael@0: michael@0: /** Initialize the stream by calling sk_fopen on the specified path. michael@0: * This internal stream will be closed in the destructor. michael@0: */ michael@0: explicit SkFILEStream(const char path[] = NULL); michael@0: michael@0: enum Ownership { michael@0: kCallerPasses_Ownership, michael@0: kCallerRetains_Ownership michael@0: }; michael@0: /** Initialize the stream with an existing C file stream. michael@0: * While this stream exists, it assumes exclusive access to the C file stream. michael@0: * The C file stream will be closed in the destructor unless the caller specifies michael@0: * kCallerRetains_Ownership. michael@0: */ michael@0: explicit SkFILEStream(FILE* file, Ownership ownership = kCallerPasses_Ownership); michael@0: michael@0: virtual ~SkFILEStream(); michael@0: michael@0: /** Returns true if the current path could be opened. */ michael@0: bool isValid() const { return fFILE != NULL; } michael@0: michael@0: /** Close the current file, and open a new file with the specified path. michael@0: * If path is NULL, just close the current file. michael@0: */ michael@0: void setPath(const char path[]); michael@0: michael@0: virtual size_t read(void* buffer, size_t size) SK_OVERRIDE; michael@0: virtual bool isAtEnd() const SK_OVERRIDE; michael@0: michael@0: virtual bool rewind() SK_OVERRIDE; michael@0: virtual SkStreamAsset* duplicate() const SK_OVERRIDE; michael@0: michael@0: virtual size_t getPosition() const SK_OVERRIDE; michael@0: virtual bool seek(size_t position) SK_OVERRIDE; michael@0: virtual bool move(long offset) SK_OVERRIDE; michael@0: virtual SkStreamAsset* fork() const SK_OVERRIDE; michael@0: michael@0: virtual size_t getLength() const SK_OVERRIDE; michael@0: michael@0: virtual const void* getMemoryBase() SK_OVERRIDE; michael@0: michael@0: private: michael@0: SkFILE* fFILE; michael@0: SkString fName; michael@0: Ownership fOwnership; michael@0: // fData is lazilly initialized when needed. michael@0: mutable SkAutoTUnref fData; michael@0: michael@0: typedef SkStreamAsset INHERITED; michael@0: }; michael@0: michael@0: class SK_API SkMemoryStream : public SkStreamMemory { michael@0: public: michael@0: SK_DECLARE_INST_COUNT(SkMemoryStream) michael@0: michael@0: SkMemoryStream(); michael@0: michael@0: /** We allocate (and free) the memory. Write to it via getMemoryBase() */ michael@0: SkMemoryStream(size_t length); michael@0: michael@0: /** If copyData is true, the stream makes a private copy of the data. */ michael@0: SkMemoryStream(const void* data, size_t length, bool copyData = false); michael@0: michael@0: /** Use the specified data as the memory for this stream. michael@0: * The stream will call ref() on the data (assuming it is not NULL). michael@0: */ michael@0: SkMemoryStream(SkData*); michael@0: michael@0: virtual ~SkMemoryStream(); michael@0: michael@0: /** Resets the stream to the specified data and length, michael@0: just like the constructor. michael@0: if copyData is true, the stream makes a private copy of the data michael@0: */ michael@0: virtual void setMemory(const void* data, size_t length, michael@0: bool copyData = false); michael@0: /** Replace any memory buffer with the specified buffer. The caller michael@0: must have allocated data with sk_malloc or sk_realloc, since it michael@0: will be freed with sk_free. michael@0: */ michael@0: void setMemoryOwned(const void* data, size_t length); michael@0: michael@0: /** Return the stream's data in a SkData. michael@0: * The caller must call unref() when it is finished using the data. michael@0: */ michael@0: SkData* copyToData() const; michael@0: michael@0: /** michael@0: * Use the specified data as the memory for this stream. michael@0: * The stream will call ref() on the data (assuming it is not NULL). michael@0: * The function returns the data parameter as a convenience. michael@0: */ michael@0: SkData* setData(SkData*); michael@0: michael@0: void skipToAlign4(); michael@0: const void* getAtPos(); michael@0: size_t peek() const { return fOffset; } michael@0: michael@0: virtual size_t read(void* buffer, size_t size) SK_OVERRIDE; michael@0: virtual bool isAtEnd() const SK_OVERRIDE; michael@0: michael@0: virtual bool rewind() SK_OVERRIDE; michael@0: virtual SkMemoryStream* duplicate() const SK_OVERRIDE; michael@0: michael@0: virtual size_t getPosition() const SK_OVERRIDE; michael@0: virtual bool seek(size_t position) SK_OVERRIDE; michael@0: virtual bool move(long offset) SK_OVERRIDE; michael@0: virtual SkMemoryStream* fork() const SK_OVERRIDE; michael@0: michael@0: virtual size_t getLength() const SK_OVERRIDE; michael@0: michael@0: virtual const void* getMemoryBase() SK_OVERRIDE; michael@0: michael@0: private: michael@0: SkData* fData; michael@0: size_t fOffset; michael@0: michael@0: typedef SkStreamMemory INHERITED; michael@0: }; michael@0: michael@0: ///////////////////////////////////////////////////////////////////////////////////////////// michael@0: michael@0: class SK_API SkFILEWStream : public SkWStream { michael@0: public: michael@0: SK_DECLARE_INST_COUNT(SkFILEWStream) michael@0: michael@0: SkFILEWStream(const char path[]); michael@0: virtual ~SkFILEWStream(); michael@0: michael@0: /** Returns true if the current path could be opened. michael@0: */ michael@0: bool isValid() const { return fFILE != NULL; } michael@0: michael@0: virtual bool write(const void* buffer, size_t size) SK_OVERRIDE; michael@0: virtual void flush() SK_OVERRIDE; michael@0: virtual size_t bytesWritten() const SK_OVERRIDE; michael@0: michael@0: private: michael@0: SkFILE* fFILE; michael@0: michael@0: typedef SkWStream INHERITED; michael@0: }; michael@0: michael@0: class SkMemoryWStream : public SkWStream { michael@0: public: michael@0: SK_DECLARE_INST_COUNT(SkMemoryWStream) michael@0: michael@0: SkMemoryWStream(void* buffer, size_t size); michael@0: virtual bool write(const void* buffer, size_t size) SK_OVERRIDE; michael@0: virtual size_t bytesWritten() const SK_OVERRIDE { return fBytesWritten; } michael@0: michael@0: private: michael@0: char* fBuffer; michael@0: size_t fMaxLength; michael@0: size_t fBytesWritten; michael@0: michael@0: typedef SkWStream INHERITED; michael@0: }; michael@0: michael@0: class SK_API SkDynamicMemoryWStream : public SkWStream { michael@0: public: michael@0: SK_DECLARE_INST_COUNT(SkDynamicMemoryWStream) michael@0: michael@0: SkDynamicMemoryWStream(); michael@0: virtual ~SkDynamicMemoryWStream(); michael@0: michael@0: virtual bool write(const void* buffer, size_t size) SK_OVERRIDE; michael@0: virtual size_t bytesWritten() const SK_OVERRIDE { return fBytesWritten; } michael@0: // random access write michael@0: // modifies stream and returns true if offset + size is less than or equal to getOffset() michael@0: bool write(const void* buffer, size_t offset, size_t size); michael@0: bool read(void* buffer, size_t offset, size_t size); michael@0: size_t getOffset() const { return fBytesWritten; } michael@0: michael@0: // copy what has been written to the stream into dst michael@0: void copyTo(void* dst) const; michael@0: michael@0: /** michael@0: * Return a copy of the data written so far. This call is responsible for michael@0: * calling unref() when they are finished with the data. michael@0: */ michael@0: SkData* copyToData() const; michael@0: michael@0: /** Reset, returning a reader stream with the current content. */ michael@0: SkStreamAsset* detachAsStream(); michael@0: michael@0: /** Reset the stream to its original, empty, state. */ michael@0: void reset(); michael@0: void padToAlign4(); michael@0: private: michael@0: struct Block; michael@0: Block* fHead; michael@0: Block* fTail; michael@0: size_t fBytesWritten; michael@0: mutable SkData* fCopy; // is invalidated if we write after it is created michael@0: michael@0: void invalidateCopy(); michael@0: michael@0: // For access to the Block type. michael@0: friend class SkBlockMemoryStream; michael@0: friend class SkBlockMemoryRefCnt; michael@0: michael@0: typedef SkWStream INHERITED; michael@0: }; michael@0: michael@0: michael@0: class SK_API SkDebugWStream : public SkWStream { michael@0: public: michael@0: SkDebugWStream() : fBytesWritten(0) {} michael@0: SK_DECLARE_INST_COUNT(SkDebugWStream) michael@0: michael@0: // overrides michael@0: virtual bool write(const void* buffer, size_t size) SK_OVERRIDE; michael@0: virtual void newline() SK_OVERRIDE; michael@0: virtual size_t bytesWritten() const SK_OVERRIDE { return fBytesWritten; } michael@0: michael@0: private: michael@0: size_t fBytesWritten; michael@0: typedef SkWStream INHERITED; michael@0: }; michael@0: michael@0: // for now michael@0: typedef SkFILEStream SkURLStream; michael@0: michael@0: #endif