2 * Copyright 2013 Google Inc.
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
8 #include "SkFrontBufferedStream.h"
10 #include "SkTemplates.h"
12 class FrontBufferedStream : public SkStreamRewindable {
15 FrontBufferedStream(SkStream*, size_t bufferSize);
17 size_t read(void* buffer, size_t size) override;
19 bool isAtEnd() const override;
21 bool rewind() override;
23 bool hasPosition() const override { return true; }
25 size_t getPosition() const override { return fOffset; }
27 bool hasLength() const override { return fHasLength; }
29 size_t getLength() const override { return fLength; }
31 SkStreamRewindable* duplicate() const override { return NULL; }
34 SkAutoTDelete<SkStream> fStream;
35 const bool fHasLength;
37 // Current offset into the stream. Always >= 0.
39 // Amount that has been buffered by calls to read. Will always be less than
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
46 SkAutoTMalloc<char> fBuffer;
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);
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);
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);
63 typedef SkStream INHERITED;
66 SkStreamRewindable* SkFrontBufferedStream::Create(SkStream* stream, size_t bufferSize) {
70 return SkNEW_ARGS(FrontBufferedStream, (stream, bufferSize));
73 FrontBufferedStream::FrontBufferedStream(SkStream* stream, size_t bufferSize)
75 , fHasLength(stream->hasPosition() && stream->hasLength())
76 , fLength(stream->getLength() - stream->getPosition())
79 , fBufferSize(bufferSize)
80 , fBuffer(bufferSize) {}
82 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.
89 return fStream->isAtEnd();
92 bool FrontBufferedStream::rewind() {
93 // Only allow a rewind if we have not exceeded the buffer.
94 if (fOffset <= fBufferSize) {
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
106 const size_t bytesToCopy = SkTMin(size, fBufferedSoFar - fOffset);
108 memcpy(dst, fBuffer + fOffset, bytesToCopy);
111 // Update fOffset to the new position. It is guaranteed to be
112 // within the buffered data.
113 fOffset += bytesToCopy;
114 SkASSERT(fOffset <= fBufferedSoFar);
119 size_t FrontBufferedStream::bufferAndWriteTo(char* dst, size_t size) {
121 SkASSERT(fOffset >= fBufferedSoFar);
123 // Data needs to be buffered. Buffer up to the lesser of the size requested
124 // and the remainder of the max buffer size.
125 const size_t bytesToBuffer = SkTMin(size, fBufferSize - fBufferedSoFar);
126 char* buffer = fBuffer + fOffset;
127 const size_t buffered = fStream->read(buffer, bytesToBuffer);
129 fBufferedSoFar += buffered;
130 fOffset = fBufferedSoFar;
131 SkASSERT(fBufferedSoFar <= fBufferSize);
133 // Copy the buffer to the destination buffer and update the amount read.
135 memcpy(dst, buffer, buffered);
141 size_t FrontBufferedStream::readDirectlyFromStream(char* dst, size_t size) {
143 // If we get here, we have buffered all that can be buffered.
144 SkASSERT(fBufferSize == fBufferedSoFar && fOffset >= fBufferSize);
146 const size_t bytesReadDirectly = fStream->read(dst, size);
147 fOffset += bytesReadDirectly;
149 // If we have read past the end of the buffer, rewinding is no longer
150 // supported, so we can go ahead and free the memory.
151 if (bytesReadDirectly > 0) {
152 sk_free(fBuffer.detach());
155 return bytesReadDirectly;
158 size_t FrontBufferedStream::read(void* voidDst, size_t size) {
159 // Cast voidDst to a char* for easy addition.
160 char* dst = reinterpret_cast<char*>(voidDst);
161 SkDEBUGCODE(const size_t totalSize = size;)
162 const size_t start = fOffset;
164 // First, read any data that was previously buffered.
165 if (fOffset < fBufferedSoFar) {
166 const size_t bytesCopied = this->readFromBuffer(dst, size);
168 // Update the remaining number of bytes needed to read
169 // and the destination buffer.
171 SkASSERT(size + (fOffset - start) == totalSize);
177 // Buffer any more data that should be buffered, and copy it to the
179 if (size > 0 && fBufferedSoFar < fBufferSize && !fStream->isAtEnd()) {
180 const size_t buffered = this->bufferAndWriteTo(dst, size);
182 // Update the remaining number of bytes needed to read
183 // and the destination buffer.
185 SkASSERT(size + (fOffset - start) == totalSize);
191 if (size > 0 && !fStream->isAtEnd()) {
192 SkDEBUGCODE(const size_t bytesReadDirectly =) this->readDirectlyFromStream(dst, size);
193 SkDEBUGCODE(size -= bytesReadDirectly;)
194 SkASSERT(size + (fOffset - start) == totalSize);
197 return fOffset - start;