Change SkStream.
https://codereview.chromium.org/15298009/


git-svn-id: http://skia.googlecode.com/svn/trunk@9312 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/include/core/SkStream.h b/include/core/SkStream.h
index 310f939..31ed7bc 100644
--- a/include/core/SkStream.h
+++ b/include/core/SkStream.h
@@ -13,6 +13,12 @@
 
 class SkData;
 
+class SkStream;
+class SkStreamRewindable;
+class SkStreamSeekable;
+class SkStreamAsset;
+class SkStreamMemory;
+
 /**
  *  SkStream -- abstraction for a source of bytes. Subclasses can be backed by
  *  memory, or a file, or something else.
@@ -30,50 +36,43 @@
  *  no more data (at EOF or hit an error). The caller should *not* call again
  *  in hopes of fulfilling more of the request.
  */
-class SK_API SkStream : public SkRefCnt {
+class SK_API SkStream : public SkRefCnt { //TODO: remove SkRefCnt
 public:
     /**
      *  Attempts to open the specified file, and return a stream to it (using
      *  mmap if available). On success, the caller must call unref() on the
      *  returned object. On failure, returns NULL.
      */
-    static SkStream* NewFromFile(const char path[]);
+    static SkStreamAsset* NewFromFile(const char path[]);
 
     SK_DECLARE_INST_COUNT(SkStream)
 
-    /** Called to rewind to the beginning of the stream. If this cannot be
-        done, return false.
-    */
-    virtual bool rewind() = 0;
-    /** If this stream represents a file, this method returns the file's name.
-        If it does not, it returns NULL (the default behavior).
-    */
-    virtual const char* getFileName();
-    /** Called to read or skip size number of bytes.
-        If buffer is NULL and size > 0, skip that many bytes, returning how many were skipped.
-        If buffer is NULL and size == 0, return the total length of the stream.
-        If buffer != NULL, copy the requested number of bytes into buffer, returning how many were copied.
-        @param buffer   If buffer is NULL, ignore and just skip size bytes, otherwise copy size bytes into buffer
-        @param size The number of bytes to skip or copy
-        @return bytes read on success
-    */
+    /** Reads or skips size number of bytes.
+     *  If buffer == NULL, skip size bytes, return how many were skipped.
+     *  If buffer != NULL, copy size bytes into buffer, return how many were copied.
+     *  @param buffer when NULL skip size bytes, otherwise copy size bytes into buffer
+     *  @param size the number of bytes to skip or copy
+     *  @return bytes read on success
+     */
     virtual size_t read(void* buffer, size_t size) = 0;
 
-    /** Return the total length of the stream.
-    */
-    size_t getLength() { return this->read(NULL, 0); }
+    /** Skip size number of bytes.
+     *  @return the actual number bytes that could be skipped.
+     */
+    size_t skip(size_t size) {
+        //return this->read(NULL, size);
+        //TODO: remove this old logic after updating existing implementations
+        return 0 == size ? 0 : this->read(NULL, size);
+    }
 
-    /** Skip the specified number of bytes, returning the actual number
-        of bytes that could be skipped.
-    */
-    size_t skip(size_t bytes);
-
-    /** If the stream is backed by RAM, this method returns the starting
-        address for the data. If not (i.e. it is backed by a file or other
-        structure), this method returns NULL.
-        The default implementation returns NULL.
-    */
-    virtual const void* getMemoryBase();
+    /** Returns true if there are no more bytes to be read.
+     *  In Progress: do not use until all implementations are updated.
+     *  TODO: after this is implemented everywhere, make pure virtual.
+     */
+    virtual bool isAtEnd() const {
+        SkASSERT(false);
+        return true;
+    }
 
     int8_t   readS8();
     int16_t  readS16();
@@ -93,10 +92,100 @@
      */
     SkData* readData();
 
+//SkStreamRewindable
+    /** Rewinds to the beginning of the stream. If this cannot be done, return false. */
+    virtual bool rewind() { return false; }
+
+    /** Duplicates this stream. If this cannot be done, returns NULL.
+     *  The returned stream will be positioned at the beginning of its data.
+     */
+    virtual SkStreamRewindable* duplicate() const { return NULL; }
+
+//SkStreamSeekable
+    /** Returns true if this stream can report it's current position. */
+    virtual bool hasPosition() const { return false; }
+    /** Returns the current position in the stream. If this cannot be done, returns 0. */
+    virtual size_t getPosition() const { return 0; }
+
+    /** Seeks to an absolute position in the stream. If this cannot be done, returns false.
+     *  If an attempt is made to seek past the end of the stream, the position will be set
+     *  to the end of the stream.
+     */
+    virtual bool seek(size_t position) { return false; }
+
+    /** Seeks to an relative offset in the stream. If this cannot be done, returns false.
+     *  If an attempt is made to move to a position outside the stream, the position will be set
+     *  to the closest point within the stream (beginning or end).
+     */
+    virtual bool move(long offset) { return false; }
+
+    /** Duplicates this stream. If this cannot be done, returns NULL.
+     *  The returned stream will be positioned the same as this stream.
+     */
+    virtual SkStreamSeekable* fork() const { return NULL; }
+
+//SkStreamAsset
+    /** Returns true if this stream can report it's total length. */
+    virtual bool hasLength() const { return false; }
+    /** Returns the total length of the stream. If this cannot be done, returns 0. */
+    virtual size_t getLength() const {
+        //return 0;
+        //TODO: remove the following after everyone is updated.
+        return ((SkStream*)this)->read(NULL, 0);
+    }
+
+//SkStreamMemory
+    /** Returns the starting address for the data. If this cannot be done, returns NULL. */
+    //TODO: replace with virtual const SkData* getData()
+    virtual const void* getMemoryBase() { return NULL; }
+
 private:
     typedef SkRefCnt INHERITED;
 };
 
+/** SkStreamRewindable is a SkStream for which rewind and duplicate are required. */
+class SK_API SkStreamRewindable : public SkStream {
+public:
+    //TODO: remove the following after everyone is updated (ensures new behavior on new classes).
+    virtual bool isAtEnd() const SK_OVERRIDE = 0;
+    //TODO: remove the following after everyone is updated (ensures new behavior on new classes).
+    virtual size_t getLength() const SK_OVERRIDE { return 0; }
+
+    virtual bool rewind() SK_OVERRIDE = 0;
+    virtual SkStreamRewindable* duplicate() const SK_OVERRIDE = 0;
+};
+
+/** SkStreamSeekable is a SkStreamRewindable for which position, seek, move, and fork are required. */
+class SK_API SkStreamSeekable : public SkStreamRewindable {
+public:
+    virtual SkStreamSeekable* duplicate() const SK_OVERRIDE = 0;
+
+    virtual bool hasPosition() const SK_OVERRIDE { return true; }
+    virtual size_t getPosition() const SK_OVERRIDE = 0;
+    virtual bool seek(size_t position) SK_OVERRIDE = 0;
+    virtual bool move(long offset) SK_OVERRIDE = 0;
+    virtual SkStreamSeekable* fork() const SK_OVERRIDE = 0;
+};
+
+/** SkStreamAsset is a SkStreamSeekable for which getLength is required. */
+class SK_API SkStreamAsset : public SkStreamSeekable {
+public:
+    virtual SkStreamAsset* duplicate() const SK_OVERRIDE = 0;
+    virtual SkStreamAsset* fork() const SK_OVERRIDE = 0;
+
+    virtual bool hasLength() const SK_OVERRIDE { return true; }
+    virtual size_t getLength() const SK_OVERRIDE = 0;
+};
+
+/** SkStreamMemory is a SkStreamAsset for which getMemoryBase is required. */
+class SK_API SkStreamMemory : public SkStreamAsset {
+public:
+    virtual SkStreamMemory* duplicate() const SK_OVERRIDE = 0;
+    virtual SkStreamMemory* fork() const SK_OVERRIDE = 0;
+
+    virtual const void* getMemoryBase() SK_OVERRIDE = 0;
+};
+
 class SK_API SkWStream : SkNoncopyable {
 public:
     SK_DECLARE_INST_COUNT_ROOT(SkWStream)
@@ -147,81 +236,76 @@
 
 struct SkFILE;
 
-/** A stream that reads from a FILE*, which is opened in the constructor and
-    closed in the destructor
- */
-class SK_API SkFILEStream : public SkStream {
+/** A stream that wraps a C FILE* file stream. */
+class SK_API SkFILEStream : public SkStreamAsset {
 public:
     SK_DECLARE_INST_COUNT(SkFILEStream)
 
-    /** Initialize the stream by calling fopen on the specified path. Will be
-        closed in the destructor.
+    /** Initialize the stream by calling sk_fopen on the specified path.
+     *  This internal stream will be closed in the destructor.
      */
     explicit SkFILEStream(const char path[] = NULL);
+
+    enum Ownership {
+        kCallerPasses_Ownership,
+        kCallerRetains_Ownership
+    };
+    /** Initialize the stream with an existing C file stream.
+     *  While this stream exists, it assumes exclusive access to the C file stream.
+     *  The C file stream will be closed in the destructor unless the caller specifies
+     *  kCallerRetains_Ownership.
+     */
+    explicit SkFILEStream(FILE* file, Ownership ownership = kCallerPasses_Ownership);
+
     virtual ~SkFILEStream();
 
-    /** Returns true if the current path could be opened.
-    */
+    /** Returns true if the current path could be opened. */
     bool isValid() const { return fFILE != NULL; }
-    /** Close the current file, and open a new file with the specified
-        path. If path is NULL, just close the current file.
-    */
+
+    /** Close the current file, and open a new file with the specified path.
+     *  If path is NULL, just close the current file.
+     */
     void setPath(const char path[]);
 
-    virtual bool rewind() SK_OVERRIDE;
     virtual size_t read(void* buffer, size_t size) SK_OVERRIDE;
-    virtual const char* getFileName() SK_OVERRIDE;
+    virtual bool isAtEnd() const SK_OVERRIDE;
+
+    virtual bool rewind() SK_OVERRIDE;
+    virtual SkStreamAsset* duplicate() const SK_OVERRIDE;
+
+    virtual size_t getPosition() const SK_OVERRIDE;
+    virtual bool seek(size_t position) SK_OVERRIDE;
+    virtual bool move(long offset) SK_OVERRIDE;
+    virtual SkStreamAsset* fork() const SK_OVERRIDE;
+
+    virtual size_t getLength() const SK_OVERRIDE;
+
+    const void* getMemoryBase() SK_OVERRIDE;
 
 private:
     SkFILE*     fFILE;
     SkString    fName;
+    Ownership   fOwnership;
+    // fData is lazilly initialized when needed.
+    mutable SkAutoTUnref<SkData> fData;
 
-    typedef SkStream INHERITED;
+    typedef SkStreamAsset INHERITED;
 };
 
-/** A stream that reads from a file descriptor
- */
-class SK_API SkFDStream : public SkStream {
-public:
-    SK_DECLARE_INST_COUNT(SkFDStream)
-
-    /** Initialize the stream with a dup() of the specified file descriptor.
-        If closeWhenDone is true, then the descriptor will be closed in the
-        destructor.
-     */
-    SkFDStream(int fileDesc, bool closeWhenDone);
-    virtual ~SkFDStream();
-
-    /** Returns true if the current path could be opened.
-     */
-    bool isValid() const { return fFD >= 0; }
-
-    virtual bool rewind() SK_OVERRIDE;
-    virtual size_t read(void* buffer, size_t size) SK_OVERRIDE;
-    virtual const char* getFileName() SK_OVERRIDE { return NULL; }
-
-private:
-    int     fFD;
-    bool    fCloseWhenDone;
-
-    typedef SkStream INHERITED;
-};
-
-class SK_API SkMemoryStream : public SkStream {
+class SK_API SkMemoryStream : public SkStreamMemory {
 public:
     SK_DECLARE_INST_COUNT(SkMemoryStream)
 
     SkMemoryStream();
-    /** We allocate (and free) the memory. Write to it via getMemoryBase()
-    */
+
+    /** We allocate (and free) the memory. Write to it via getMemoryBase() */
     SkMemoryStream(size_t length);
-    /** if copyData is true, the stream makes a private copy of the data
-    */
+
+    /** If copyData is true, the stream makes a private copy of the data. */
     SkMemoryStream(const void* data, size_t length, bool copyData = false);
 
-    /**
-     *  Use the specified data as the memory for this stream. The stream will
-     *  call ref() on the data (assuming it is not null).
+    /** Use the specified data as the memory for this stream.
+     *  The stream will call ref() on the data (assuming it is not NULL).
      */
     SkMemoryStream(SkData*);
 
@@ -239,81 +323,42 @@
     */
     void setMemoryOwned(const void* data, size_t length);
 
-    /**
-     *  Return the stream's data in a SkData. The caller must call unref() when
-     *  it is finished using the data.
+    /** Return the stream's data in a SkData.
+     *  The caller must call unref() when it is finished using the data.
      */
     SkData* copyToData() const;
 
     /**
-     *  Use the specified data as the memory for this stream. The stream will
-     *  call ref() on the data (assuming it is not null). The function returns
-     *  the data parameter as a convenience.
+     *  Use the specified data as the memory for this stream.
+     *  The stream will call ref() on the data (assuming it is not NULL).
+     *  The function returns the data parameter as a convenience.
      */
     SkData* setData(SkData*);
 
     void skipToAlign4();
-    virtual bool rewind() SK_OVERRIDE;
-    virtual size_t read(void* buffer, size_t size) SK_OVERRIDE;
-    virtual const void* getMemoryBase() SK_OVERRIDE;
     const void* getAtPos();
-    size_t seek(size_t offset);
     size_t peek() const { return fOffset; }
 
+    virtual size_t read(void* buffer, size_t size) SK_OVERRIDE;
+    virtual bool isAtEnd() const SK_OVERRIDE;
+
+    virtual bool rewind() SK_OVERRIDE;
+    virtual SkMemoryStream* duplicate() const SK_OVERRIDE;
+
+    virtual size_t getPosition() const SK_OVERRIDE;
+    virtual bool seek(size_t position) SK_OVERRIDE;
+    virtual bool move(long offset) SK_OVERRIDE;
+    virtual SkMemoryStream* fork() const SK_OVERRIDE;
+
+    virtual size_t getLength() const SK_OVERRIDE;
+
+    virtual const void* getMemoryBase() SK_OVERRIDE;
+
 private:
     SkData* fData;
     size_t  fOffset;
 
-    typedef SkStream INHERITED;
-};
-
-/** \class SkBufferStream
-    This is a wrapper class that adds buffering to another stream.
-    The caller can provide the buffer, or ask SkBufferStream to allocated/free
-    it automatically.
-*/
-class SK_API SkBufferStream : public SkStream {
-public:
-    SK_DECLARE_INST_COUNT(SkBufferStream)
-
-    /** Provide the stream to be buffered (proxy), and the size of the buffer that
-        should be used. This will be allocated and freed automatically. If bufferSize is 0,
-        a default buffer size will be used.
-        The proxy stream is referenced, and will be unreferenced in when the
-        bufferstream is destroyed.
-    */
-    SkBufferStream(SkStream* proxy, size_t bufferSize = 0);
-    /** Provide the stream to be buffered (proxy), and a buffer and size to be used.
-        This buffer is owned by the caller, and must be at least bufferSize bytes big.
-        Passing NULL for buffer will cause the buffer to be allocated/freed automatically.
-        If buffer is not NULL, it is an error for bufferSize to be 0.
-     The proxy stream is referenced, and will be unreferenced in when the
-     bufferstream is destroyed.
-    */
-    SkBufferStream(SkStream* proxy, void* buffer, size_t bufferSize);
-    virtual ~SkBufferStream();
-
-    virtual bool        rewind() SK_OVERRIDE;
-    virtual const char* getFileName() SK_OVERRIDE;
-    virtual size_t      read(void* buffer, size_t size) SK_OVERRIDE;
-    virtual const void* getMemoryBase() SK_OVERRIDE;
-
-private:
-    enum {
-        kDefaultBufferSize  = 128
-    };
-    // illegal
-    SkBufferStream(const SkBufferStream&);
-    SkBufferStream& operator=(const SkBufferStream&);
-
-    SkStream*   fProxy;
-    char*       fBuffer;
-    size_t      fOrigBufferSize, fBufferSize, fBufferOffset;
-    bool        fWeOwnTheBuffer;
-
-    void    init(void*, size_t);
-
-    typedef SkStream INHERITED;
+    typedef SkStreamMemory INHERITED;
 };
 
 /////////////////////////////////////////////////////////////////////////////////////////////