• 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 "include/codec/SkCodec.h"
9 #include "include/core/SkStream.h"
10 #include "FrontBufferedStream.h"
11 
12 #include <algorithm>
13 #include <memory>
14 
15 namespace {
16 class FrontBufferedStream : public SkStreamRewindable {
17 public:
18     // Called by Make.
19     FrontBufferedStream(std::unique_ptr<SkStream>, size_t bufferSize);
20     ~FrontBufferedStream() override;
21 
failedToAllocateBuffer() const22     bool failedToAllocateBuffer() const { return !fBuffer; }
23 
24     size_t read(void* buffer, size_t size) override;
25 
26     size_t peek(void* buffer, size_t size) const override;
27 
28     bool isAtEnd() const override;
29 
30     bool rewind() override;
31 
hasLength() const32     bool hasLength() const override { return fHasLength; }
33 
getLength() const34     size_t getLength() const override { return fLength; }
35 
36 private:
onDuplicate() const37     SkStreamRewindable* onDuplicate() const override { return nullptr; }
38 
39     std::unique_ptr<SkStream>        fStream;
40     const bool                       fHasLength;
41     const size_t                     fLength;
42     // Current offset into the stream. Always >= 0.
43     size_t                           fOffset;
44     // Amount that has been buffered by calls to read. Will always be less than
45     // fBufferSize.
46     size_t                           fBufferedSoFar;
47     // Total size of the buffer.
48     const size_t                     fBufferSize;
49     char*                            fBuffer;
50     inline static constexpr size_t   kStorageSize = SkCodec::MinBufferedBytesNeeded();
51     char                             fStorage[kStorageSize];
52 
53     // Read up to size bytes from already buffered data, and copy to
54     // dst, if non-nullptr. Updates fOffset. Assumes that fOffset is less
55     // than fBufferedSoFar.
56     size_t readFromBuffer(char* dst, size_t size);
57 
58     // Buffer up to size bytes from the stream, and copy to dst if non-
59     // nullptr. Updates fOffset and fBufferedSoFar. Assumes that fOffset is
60     // less than fBufferedSoFar, and size is greater than 0.
61     size_t bufferAndWriteTo(char* dst, size_t size);
62 
63     // Read up to size bytes directly from the stream and into dst if non-
64     // nullptr. Updates fOffset. Assumes fOffset is at or beyond the buffered
65     // data, and size is greater than 0.
66     size_t readDirectlyFromStream(char* dst, size_t size);
67 
68     using INHERITED = SkStream;
69 };
70 } // anonymous namespace
71 
72 namespace android {
73 namespace skia {
74 
Make(std::unique_ptr<SkStream> stream,size_t bufferSize)75 std::unique_ptr<SkStreamRewindable> FrontBufferedStream::Make(std::unique_ptr<SkStream> stream,
76                                                               size_t bufferSize) {
77     if (!stream) {
78         return nullptr;
79     }
80     auto frontBufferedStream = std::make_unique<::FrontBufferedStream>(
81             std::move(stream), bufferSize);
82     if (frontBufferedStream->failedToAllocateBuffer()) {
83         return nullptr;
84     }
85 
86     // Work around a warning regarding a copy on older compilers.
87     return std::move(frontBufferedStream);
88 }
89 } // namespace skia
90 } // namespace android
91 
92 namespace {
FrontBufferedStream(std::unique_ptr<SkStream> stream,size_t bufferSize)93 FrontBufferedStream::FrontBufferedStream(std::unique_ptr<SkStream> stream, size_t bufferSize)
94     : fStream(std::move(stream))
95     , fHasLength(fStream->hasPosition() && fStream->hasLength())
96     , fLength(fStream->getLength() - fStream->getPosition())
97     , fOffset(0)
98     , fBufferedSoFar(0)
99     , fBufferSize(bufferSize)
100     , fBuffer(bufferSize <= kStorageSize ? fStorage
101                                          : reinterpret_cast<char*>(malloc(bufferSize))) {}
102 
~FrontBufferedStream()103 FrontBufferedStream::~FrontBufferedStream() {
104     if (fBuffer != fStorage) {
105         free(fBuffer);
106     }
107 }
108 
isAtEnd() const109 bool FrontBufferedStream::isAtEnd() const {
110     if (fOffset < fBufferedSoFar) {
111         // Even if the underlying stream is at the end, this stream has been
112         // rewound after buffering, so it is not at the end.
113         return false;
114     }
115 
116     return fStream->isAtEnd();
117 }
118 
rewind()119 bool FrontBufferedStream::rewind() {
120     // Only allow a rewind if we have not exceeded the buffer.
121     if (fOffset <= fBufferSize) {
122         fOffset = 0;
123         return true;
124     }
125     return false;
126 }
127 
readFromBuffer(char * dst,size_t size)128 size_t FrontBufferedStream::readFromBuffer(char* dst, size_t size) {
129     SkASSERT(fOffset < fBufferedSoFar);
130     // Some data has already been copied to fBuffer. Read up to the
131     // lesser of the size requested and the remainder of the buffered
132     // data.
133     const size_t bytesToCopy = std::min(size, fBufferedSoFar - fOffset);
134     if (dst != nullptr) {
135         memcpy(dst, fBuffer + fOffset, bytesToCopy);
136     }
137 
138     // Update fOffset to the new position. It is guaranteed to be
139     // within the buffered data.
140     fOffset += bytesToCopy;
141     SkASSERT(fOffset <= fBufferedSoFar);
142 
143     return bytesToCopy;
144 }
145 
bufferAndWriteTo(char * dst,size_t size)146 size_t FrontBufferedStream::bufferAndWriteTo(char* dst, size_t size) {
147     SkASSERT(size > 0);
148     SkASSERT(fOffset >= fBufferedSoFar);
149     SkASSERT(fBuffer);
150     // Data needs to be buffered. Buffer up to the lesser of the size requested
151     // and the remainder of the max buffer size.
152     const size_t bytesToBuffer = std::min(size, fBufferSize - fBufferedSoFar);
153     char* buffer = fBuffer + fOffset;
154     const size_t buffered = fStream->read(buffer, bytesToBuffer);
155 
156     fBufferedSoFar += buffered;
157     fOffset = fBufferedSoFar;
158     SkASSERT(fBufferedSoFar <= fBufferSize);
159 
160     // Copy the buffer to the destination buffer and update the amount read.
161     if (dst != nullptr) {
162         memcpy(dst, buffer, buffered);
163     }
164 
165     return buffered;
166 }
167 
readDirectlyFromStream(char * dst,size_t size)168 size_t FrontBufferedStream::readDirectlyFromStream(char* dst, size_t size) {
169     SkASSERT(size > 0);
170     // If we get here, we have buffered all that can be buffered.
171     SkASSERT(fBufferSize == fBufferedSoFar && fOffset >= fBufferSize);
172 
173     const size_t bytesReadDirectly = fStream->read(dst, size);
174     fOffset += bytesReadDirectly;
175 
176     // If we have read past the end of the buffer, rewinding is no longer
177     // supported, so we can go ahead and free the memory.
178     if (bytesReadDirectly > 0 && fBuffer != fStorage) {
179         free(fBuffer);
180         fBuffer = nullptr;
181     }
182 
183     return bytesReadDirectly;
184 }
185 
peek(void * dst,size_t size) const186 size_t FrontBufferedStream::peek(void* dst, size_t size) const {
187     // Keep track of the offset so we can return to it.
188     const size_t start = fOffset;
189 
190     if (start >= fBufferSize) {
191         // This stream is not able to buffer.
192         return 0;
193     }
194 
195     size = std::min(size, fBufferSize - start);
196     FrontBufferedStream* nonConstThis = const_cast<FrontBufferedStream*>(this);
197     const size_t bytesRead = nonConstThis->read(dst, size);
198     nonConstThis->fOffset = start;
199     return bytesRead;
200 }
201 
read(void * voidDst,size_t size)202 size_t FrontBufferedStream::read(void* voidDst, size_t size) {
203     // Cast voidDst to a char* for easy addition.
204     char* dst = reinterpret_cast<char*>(voidDst);
205     SkDEBUGCODE(const size_t totalSize = size;)
206     const size_t start = fOffset;
207 
208     // First, read any data that was previously buffered.
209     if (fOffset < fBufferedSoFar) {
210         const size_t bytesCopied = this->readFromBuffer(dst, size);
211 
212         // Update the remaining number of bytes needed to read
213         // and the destination buffer.
214         size -= bytesCopied;
215         SkASSERT(size + (fOffset - start) == totalSize);
216         if (dst != nullptr) {
217             dst += bytesCopied;
218         }
219     }
220 
221     // Buffer any more data that should be buffered, and copy it to the
222     // destination.
223     if (size > 0 && fBufferedSoFar < fBufferSize && !fStream->isAtEnd()) {
224         const size_t buffered = this->bufferAndWriteTo(dst, size);
225 
226         // Update the remaining number of bytes needed to read
227         // and the destination buffer.
228         size -= buffered;
229         SkASSERT(size + (fOffset - start) == totalSize);
230         if (dst != nullptr) {
231             dst += buffered;
232         }
233     }
234 
235     if (size > 0 && !fStream->isAtEnd()) {
236         SkDEBUGCODE(const size_t bytesReadDirectly =) this->readDirectlyFromStream(dst, size);
237         SkDEBUGCODE(size -= bytesReadDirectly;)
238         SkASSERT(size + (fOffset - start) == totalSize);
239     }
240 
241     return fOffset - start;
242 }
243 } // anonymous namespace
244