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