• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2013 Google Inc.
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 #include "SkFrontBufferedStream.h"
9 #include "SkStream.h"
10 #include "SkTemplates.h"
11 
12 class FrontBufferedStream : public SkStreamRewindable {
13 public:
14     // Called by Create.
15     FrontBufferedStream(SkStream*, size_t bufferSize);
16 
17     virtual size_t read(void* buffer, size_t size) SK_OVERRIDE;
18 
19     virtual bool isAtEnd() const SK_OVERRIDE;
20 
21     virtual bool rewind() SK_OVERRIDE;
22 
hasPosition() const23     virtual bool hasPosition() const SK_OVERRIDE { return true; }
24 
getPosition() const25     virtual size_t getPosition() const SK_OVERRIDE { return fOffset; }
26 
hasLength() const27     virtual bool hasLength() const SK_OVERRIDE { return fHasLength; }
28 
getLength() const29     virtual size_t getLength() const SK_OVERRIDE { return fLength; }
30 
duplicate() const31     virtual SkStreamRewindable* duplicate() const SK_OVERRIDE { return NULL; }
32 
33 private:
34     SkAutoTUnref<SkStream>  fStream;
35     const bool              fHasLength;
36     const size_t            fLength;
37     // Current offset into the stream. Always >= 0.
38     size_t                  fOffset;
39     // Amount that has been buffered by calls to read. Will always be less than
40     // fBufferSize.
41     size_t                  fBufferedSoFar;
42     // Total size of the buffer.
43     const size_t            fBufferSize;
44     // FIXME: SkAutoTMalloc throws on failure. Instead, Create should return a
45     // NULL stream.
46     SkAutoTMalloc<char>     fBuffer;
47 
48     // Read up to size bytes from already buffered data, and copy to
49     // dst, if non-NULL. Updates fOffset. Assumes that fOffset is less
50     // than fBufferedSoFar.
51     size_t readFromBuffer(char* dst, size_t size);
52 
53     // Buffer up to size bytes from the stream, and copy to dst if non-
54     // NULL. Updates fOffset and fBufferedSoFar. Assumes that fOffset is
55     // less than fBufferedSoFar, and size is greater than 0.
56     size_t bufferAndWriteTo(char* dst, size_t size);
57 
58     // Read up to size bytes directly from the stream and into dst if non-
59     // NULL. Updates fOffset. Assumes fOffset is at or beyond the buffered
60     // data, and size is greater than 0.
61     size_t readDirectlyFromStream(char* dst, size_t size);
62 
63     typedef SkStream INHERITED;
64 };
65 
Create(SkStream * stream,size_t bufferSize)66 SkStreamRewindable* SkFrontBufferedStream::Create(SkStream* stream, size_t bufferSize) {
67     if (NULL == stream) {
68         return NULL;
69     }
70     return SkNEW_ARGS(FrontBufferedStream, (stream, bufferSize));
71 }
72 
FrontBufferedStream(SkStream * stream,size_t bufferSize)73 FrontBufferedStream::FrontBufferedStream(SkStream* stream, size_t bufferSize)
74     : fStream(SkRef(stream))
75     , fHasLength(stream->hasPosition() && stream->hasLength())
76     , fLength(stream->getLength() - stream->getPosition())
77     , fOffset(0)
78     , fBufferedSoFar(0)
79     , fBufferSize(bufferSize)
80     , fBuffer(bufferSize) {}
81 
isAtEnd() const82 bool FrontBufferedStream::isAtEnd() const {
83     if (fOffset < fBufferedSoFar) {
84         // Even if the underlying stream is at the end, this stream has been
85         // rewound after buffering, so it is not at the end.
86         return false;
87     }
88 
89     return fStream->isAtEnd();
90 }
91 
rewind()92 bool FrontBufferedStream::rewind() {
93     // Only allow a rewind if we have not exceeded the buffer.
94     if (fOffset <= fBufferSize) {
95         fOffset = 0;
96         return true;
97     }
98     return false;
99 }
100 
readFromBuffer(char * dst,size_t size)101 size_t FrontBufferedStream::readFromBuffer(char* dst, size_t size) {
102     SkASSERT(fOffset < fBufferedSoFar);
103     // Some data has already been copied to fBuffer. Read up to the
104     // lesser of the size requested and the remainder of the buffered
105     // data.
106     const size_t bytesToCopy = SkTMin(size, fBufferedSoFar - fOffset);
107     if (dst != NULL) {
108         memcpy(dst, fBuffer + fOffset, bytesToCopy);
109     }
110 
111     // Update fOffset to the new position. It is guaranteed to be
112     // within the buffered data.
113     fOffset += bytesToCopy;
114     SkASSERT(fOffset <= fBufferedSoFar);
115 
116     return bytesToCopy;
117 }
118 
bufferAndWriteTo(char * dst,size_t size)119 size_t FrontBufferedStream::bufferAndWriteTo(char* dst, size_t size) {
120     SkASSERT(size > 0);
121     SkASSERT(fOffset >= fBufferedSoFar);
122     // Data needs to be buffered. Buffer up to the lesser of the size requested
123     // and the remainder of the max buffer size.
124     const size_t bytesToBuffer = SkTMin(size, fBufferSize - fBufferedSoFar);
125     char* buffer = fBuffer + fOffset;
126     const size_t buffered = fStream->read(buffer, bytesToBuffer);
127 
128     fBufferedSoFar += buffered;
129     fOffset = fBufferedSoFar;
130     SkASSERT(fBufferedSoFar <= fBufferSize);
131 
132     // Copy the buffer to the destination buffer and update the amount read.
133     if (dst != NULL) {
134         memcpy(dst, buffer, buffered);
135     }
136 
137     return buffered;
138 }
139 
readDirectlyFromStream(char * dst,size_t size)140 size_t FrontBufferedStream::readDirectlyFromStream(char* dst, size_t size) {
141     SkASSERT(size > 0);
142     // If we get here, we have buffered all that can be buffered.
143     SkASSERT(fBufferSize == fBufferedSoFar && fOffset >= fBufferSize);
144 
145     const size_t bytesReadDirectly = fStream->read(dst, size);
146     fOffset += bytesReadDirectly;
147 
148     // If we have read past the end of the buffer, rewinding is no longer
149     // supported, so we can go ahead and free the memory.
150     if (bytesReadDirectly > 0) {
151         fBuffer.reset(0);
152     }
153 
154     return bytesReadDirectly;
155 }
156 
read(void * voidDst,size_t size)157 size_t FrontBufferedStream::read(void* voidDst, size_t size) {
158     // Cast voidDst to a char* for easy addition.
159     char* dst = reinterpret_cast<char*>(voidDst);
160     SkDEBUGCODE(const size_t totalSize = size;)
161     const size_t start = fOffset;
162 
163     // First, read any data that was previously buffered.
164     if (fOffset < fBufferedSoFar) {
165         const size_t bytesCopied = this->readFromBuffer(dst, size);
166 
167         // Update the remaining number of bytes needed to read
168         // and the destination buffer.
169         size -= bytesCopied;
170         SkASSERT(size + (fOffset - start) == totalSize);
171         if (dst != NULL) {
172             dst += bytesCopied;
173         }
174     }
175 
176     // Buffer any more data that should be buffered, and copy it to the
177     // destination.
178     if (size > 0 && fBufferedSoFar < fBufferSize && !fStream->isAtEnd()) {
179         const size_t buffered = this->bufferAndWriteTo(dst, size);
180 
181         // Update the remaining number of bytes needed to read
182         // and the destination buffer.
183         size -= buffered;
184         SkASSERT(size + (fOffset - start) == totalSize);
185         if (dst != NULL) {
186             dst += buffered;
187         }
188     }
189 
190     if (size > 0 && !fStream->isAtEnd()) {
191         SkDEBUGCODE(const size_t bytesReadDirectly =) this->readDirectlyFromStream(dst, size);
192         SkDEBUGCODE(size -= bytesReadDirectly;)
193         SkASSERT(size + (fOffset - start) == totalSize);
194     }
195 
196     return fOffset - start;
197 }
198