SkStream.h revision 2b34fe01d7b5736b212eb4886afc723a7b9241ae
1/*
2 * Copyright 2006 The Android Open Source Project
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#ifndef SkStream_DEFINED
9#define SkStream_DEFINED
10
11#include "SkRefCnt.h"
12#include "SkScalar.h"
13
14class SkData;
15
16/**
17 *  SkStream -- abstraction for a source of bytes. Subclasses can be backed by
18 *  memory, or a file, or something else.
19 *
20 *  NOTE:
21 *
22 *  Classic "streams" APIs are sort of async, in that on a request for N
23 *  bytes, they may return fewer than N bytes on a given call, in which case
24 *  the caller can "try again" to get more bytes, eventually (modulo an error)
25 *  receiving their total N bytes.
26 *
27 *  Skia streams behave differently. They are effectively synchronous, and will
28 *  always return all N bytes of the request if possible. If they return fewer
29 *  (the read() call returns the number of bytes read) then that means there is
30 *  no more data (at EOF or hit an error). The caller should *not* call again
31 *  in hopes of fulfilling more of the request.
32 */
33class SK_API SkStream : public SkRefCnt {
34public:
35    /**
36     *  Attempts to open the specified file, and return a stream to it (using
37     *  mmap if available). On success, the caller must call unref() on the
38     *  returned object. On failure, returns NULL.
39     */
40    static SkStream* NewFromFile(const char path[]);
41
42    SK_DECLARE_INST_COUNT(SkStream)
43
44    /** Called to rewind to the beginning of the stream. If this cannot be
45        done, return false.
46    */
47    virtual bool rewind() = 0;
48    /** If this stream represents a file, this method returns the file's name.
49        If it does not, it returns NULL (the default behavior).
50    */
51    virtual const char* getFileName();
52    /** Called to read or skip size number of bytes.
53        If buffer is NULL and size > 0, skip that many bytes, returning how many were skipped.
54        If buffer is NULL and size == 0, return the total length of the stream.
55        If buffer != NULL, copy the requested number of bytes into buffer, returning how many were copied.
56        @param buffer   If buffer is NULL, ignore and just skip size bytes, otherwise copy size bytes into buffer
57        @param size The number of bytes to skip or copy
58        @return bytes read on success
59    */
60    virtual size_t read(void* buffer, size_t size) = 0;
61
62    /** Return the total length of the stream.
63    */
64    size_t getLength() { return this->read(NULL, 0); }
65
66    /** Skip the specified number of bytes, returning the actual number
67        of bytes that could be skipped.
68    */
69    size_t skip(size_t bytes);
70
71    /** If the stream is backed by RAM, this method returns the starting
72        address for the data. If not (i.e. it is backed by a file or other
73        structure), this method returns NULL.
74        The default implementation returns NULL.
75    */
76    virtual const void* getMemoryBase();
77
78    int8_t   readS8();
79    int16_t  readS16();
80    int32_t  readS32();
81
82    uint8_t  readU8() { return (uint8_t)this->readS8(); }
83    uint16_t readU16() { return (uint16_t)this->readS16(); }
84    uint32_t readU32() { return (uint32_t)this->readS32(); }
85
86    bool     readBool() { return this->readU8() != 0; }
87    SkScalar readScalar();
88    size_t   readPackedUInt();
89
90    /**
91     *  Reconstitute an SkData object that was written to the stream
92     *  using SkWStream::writeData().
93     */
94    SkData* readData();
95
96private:
97    typedef SkRefCnt INHERITED;
98};
99
100class SK_API SkWStream : SkNoncopyable {
101public:
102    SK_DECLARE_INST_COUNT_ROOT(SkWStream)
103
104    virtual ~SkWStream();
105
106    /** Called to write bytes to a SkWStream. Returns true on success
107        @param buffer the address of at least size bytes to be written to the stream
108        @param size The number of bytes in buffer to write to the stream
109        @return true on success
110    */
111    virtual bool write(const void* buffer, size_t size) = 0;
112    virtual void newline();
113    virtual void flush();
114
115    // helpers
116
117    bool    write8(U8CPU);
118    bool    write16(U16CPU);
119    bool    write32(uint32_t);
120
121    bool    writeText(const char text[]);
122    bool    writeDecAsText(int32_t);
123    bool    writeBigDecAsText(int64_t, int minDigits = 0);
124    bool    writeHexAsText(uint32_t, int minDigits = 0);
125    bool    writeScalarAsText(SkScalar);
126
127    bool    writeBool(bool v) { return this->write8(v); }
128    bool    writeScalar(SkScalar);
129    bool    writePackedUInt(size_t);
130
131    bool writeStream(SkStream* input, size_t length);
132
133    /**
134     * Append an SkData object to the stream, such that it can be read
135     * out of the stream using SkStream::readData().
136     *
137     * Note that the encoding method used to write the SkData object
138     * to the stream may change over time.  This method DOES NOT
139     * just write the raw content of the SkData object to the stream.
140     */
141    bool writeData(const SkData*);
142};
143
144////////////////////////////////////////////////////////////////////////////////////////
145
146#include "SkString.h"
147
148struct SkFILE;
149
150/** A stream that reads from a FILE*, which is opened in the constructor and
151    closed in the destructor
152 */
153class SK_API SkFILEStream : public SkStream {
154public:
155    SK_DECLARE_INST_COUNT(SkFILEStream)
156
157    /** Initialize the stream by calling fopen on the specified path. Will be
158        closed in the destructor.
159     */
160    explicit SkFILEStream(const char path[] = NULL);
161    virtual ~SkFILEStream();
162
163    /** Returns true if the current path could be opened.
164    */
165    bool isValid() const { return fFILE != NULL; }
166    /** Close the current file, and open a new file with the specified
167        path. If path is NULL, just close the current file.
168    */
169    void setPath(const char path[]);
170
171    virtual bool rewind() SK_OVERRIDE;
172    virtual size_t read(void* buffer, size_t size) SK_OVERRIDE;
173    virtual const char* getFileName() SK_OVERRIDE;
174
175private:
176    SkFILE*     fFILE;
177    SkString    fName;
178
179    typedef SkStream INHERITED;
180};
181
182/** A stream that reads from a file descriptor
183 */
184class SK_API SkFDStream : public SkStream {
185public:
186    SK_DECLARE_INST_COUNT(SkFDStream)
187
188    /** Initialize the stream with a dup() of the specified file descriptor.
189        If closeWhenDone is true, then the descriptor will be closed in the
190        destructor.
191     */
192    SkFDStream(int fileDesc, bool closeWhenDone);
193    virtual ~SkFDStream();
194
195    /** Returns true if the current path could be opened.
196     */
197    bool isValid() const { return fFD >= 0; }
198
199    virtual bool rewind() SK_OVERRIDE;
200    virtual size_t read(void* buffer, size_t size) SK_OVERRIDE;
201    virtual const char* getFileName() SK_OVERRIDE { return NULL; }
202
203private:
204    int     fFD;
205    bool    fCloseWhenDone;
206
207    typedef SkStream INHERITED;
208};
209
210class SK_API SkMemoryStream : public SkStream {
211public:
212    SK_DECLARE_INST_COUNT(SkMemoryStream)
213
214    SkMemoryStream();
215    /** We allocate (and free) the memory. Write to it via getMemoryBase()
216    */
217    SkMemoryStream(size_t length);
218    /** if copyData is true, the stream makes a private copy of the data
219    */
220    SkMemoryStream(const void* data, size_t length, bool copyData = false);
221
222    /**
223     *  Use the specified data as the memory for this stream. The stream will
224     *  call ref() on the data (assuming it is not null).
225     */
226    SkMemoryStream(SkData*);
227
228    virtual ~SkMemoryStream();
229
230    /** Resets the stream to the specified data and length,
231        just like the constructor.
232        if copyData is true, the stream makes a private copy of the data
233    */
234    virtual void setMemory(const void* data, size_t length,
235                           bool copyData = false);
236    /** Replace any memory buffer with the specified buffer. The caller
237        must have allocated data with sk_malloc or sk_realloc, since it
238        will be freed with sk_free.
239    */
240    void setMemoryOwned(const void* data, size_t length);
241
242    /**
243     *  Return the stream's data in a SkData. The caller must call unref() when
244     *  it is finished using the data.
245     */
246    SkData* copyToData() const;
247
248    /**
249     *  Use the specified data as the memory for this stream. The stream will
250     *  call ref() on the data (assuming it is not null). The function returns
251     *  the data parameter as a convenience.
252     */
253    SkData* setData(SkData*);
254
255    void skipToAlign4();
256    virtual bool rewind() SK_OVERRIDE;
257    virtual size_t read(void* buffer, size_t size) SK_OVERRIDE;
258    virtual const void* getMemoryBase() SK_OVERRIDE;
259    const void* getAtPos();
260    size_t seek(size_t offset);
261    size_t peek() const { return fOffset; }
262
263private:
264    SkData* fData;
265    size_t  fOffset;
266
267    typedef SkStream INHERITED;
268};
269
270/** \class SkBufferStream
271    This is a wrapper class that adds buffering to another stream.
272    The caller can provide the buffer, or ask SkBufferStream to allocated/free
273    it automatically.
274*/
275class SK_API SkBufferStream : public SkStream {
276public:
277    SK_DECLARE_INST_COUNT(SkBufferStream)
278
279    /** Provide the stream to be buffered (proxy), and the size of the buffer that
280        should be used. This will be allocated and freed automatically. If bufferSize is 0,
281        a default buffer size will be used.
282        The proxy stream is referenced, and will be unreferenced in when the
283        bufferstream is destroyed.
284    */
285    SkBufferStream(SkStream* proxy, size_t bufferSize = 0);
286    /** Provide the stream to be buffered (proxy), and a buffer and size to be used.
287        This buffer is owned by the caller, and must be at least bufferSize bytes big.
288        Passing NULL for buffer will cause the buffer to be allocated/freed automatically.
289        If buffer is not NULL, it is an error for bufferSize to be 0.
290     The proxy stream is referenced, and will be unreferenced in when the
291     bufferstream is destroyed.
292    */
293    SkBufferStream(SkStream* proxy, void* buffer, size_t bufferSize);
294    virtual ~SkBufferStream();
295
296    virtual bool        rewind() SK_OVERRIDE;
297    virtual const char* getFileName() SK_OVERRIDE;
298    virtual size_t      read(void* buffer, size_t size) SK_OVERRIDE;
299    virtual const void* getMemoryBase() SK_OVERRIDE;
300
301private:
302    enum {
303        kDefaultBufferSize  = 128
304    };
305    // illegal
306    SkBufferStream(const SkBufferStream&);
307    SkBufferStream& operator=(const SkBufferStream&);
308
309    SkStream*   fProxy;
310    char*       fBuffer;
311    size_t      fOrigBufferSize, fBufferSize, fBufferOffset;
312    bool        fWeOwnTheBuffer;
313
314    void    init(void*, size_t);
315
316    typedef SkStream INHERITED;
317};
318
319/////////////////////////////////////////////////////////////////////////////////////////////
320
321class SK_API SkFILEWStream : public SkWStream {
322public:
323    SK_DECLARE_INST_COUNT(SkFILEWStream)
324
325    SkFILEWStream(const char path[]);
326    virtual ~SkFILEWStream();
327
328    /** Returns true if the current path could be opened.
329    */
330    bool isValid() const { return fFILE != NULL; }
331
332    virtual bool write(const void* buffer, size_t size) SK_OVERRIDE;
333    virtual void flush() SK_OVERRIDE;
334
335private:
336    SkFILE* fFILE;
337
338    typedef SkWStream INHERITED;
339};
340
341class SkMemoryWStream : public SkWStream {
342public:
343    SK_DECLARE_INST_COUNT(SkMemoryWStream)
344
345    SkMemoryWStream(void* buffer, size_t size);
346    virtual bool write(const void* buffer, size_t size) SK_OVERRIDE;
347    size_t bytesWritten() const { return fBytesWritten; }
348
349private:
350    char*   fBuffer;
351    size_t  fMaxLength;
352    size_t  fBytesWritten;
353
354    typedef SkWStream INHERITED;
355};
356
357class SK_API SkDynamicMemoryWStream : public SkWStream {
358public:
359    SK_DECLARE_INST_COUNT(SkDynamicMemoryWStream)
360
361    SkDynamicMemoryWStream();
362    virtual ~SkDynamicMemoryWStream();
363
364    virtual bool write(const void* buffer, size_t size) SK_OVERRIDE;
365    // random access write
366    // modifies stream and returns true if offset + size is less than or equal to getOffset()
367    bool write(const void* buffer, size_t offset, size_t size);
368    bool read(void* buffer, size_t offset, size_t size);
369    size_t getOffset() const { return fBytesWritten; }
370    size_t bytesWritten() const { return fBytesWritten; }
371
372    // copy what has been written to the stream into dst
373    void copyTo(void* dst) const;
374
375    /**
376     *  Return a copy of the data written so far. This call is responsible for
377     *  calling unref() when they are finished with the data.
378     */
379    SkData* copyToData() const;
380
381    // reset the stream to its original state
382    void reset();
383    void padToAlign4();
384private:
385    struct Block;
386    Block*  fHead;
387    Block*  fTail;
388    size_t  fBytesWritten;
389    mutable SkData* fCopy;  // is invalidated if we write after it is created
390
391    void invalidateCopy();
392
393    typedef SkWStream INHERITED;
394};
395
396
397class SK_API SkDebugWStream : public SkWStream {
398public:
399    SK_DECLARE_INST_COUNT(SkDebugWStream)
400
401    // overrides
402    virtual bool write(const void* buffer, size_t size) SK_OVERRIDE;
403    virtual void newline() SK_OVERRIDE;
404
405private:
406    typedef SkWStream INHERITED;
407};
408
409// for now
410typedef SkFILEStream SkURLStream;
411
412#endif
413