blob: 519609f1183317baea339aa6820ba6865019ffe0 [file] [log] [blame]
scroggo@google.com83fd2c72013-09-26 21:35:39 +00001/*
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
Leon Scroggins III63cfb362020-04-24 13:00:48 -04008#include "include/codec/SkCodec.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -05009#include "include/core/SkStream.h"
Leon Scroggins III63cfb362020-04-24 13:00:48 -040010#include "FrontBufferedStream.h"
scroggo@google.com09a53832013-11-12 20:53:05 +000011
Leon Scroggins III63cfb362020-04-24 13:00:48 -040012#include <algorithm>
13
14namespace {
scroggo@google.com09a53832013-11-12 20:53:05 +000015class FrontBufferedStream : public SkStreamRewindable {
16public:
Mike Reed98c5d922017-09-15 21:39:47 -040017 // Called by Make.
18 FrontBufferedStream(std::unique_ptr<SkStream>, size_t bufferSize);
Leon Scroggins III63cfb362020-04-24 13:00:48 -040019 ~FrontBufferedStream() override;
20
21 bool failedToAllocateBuffer() const { return !fBuffer; }
scroggo@google.com09a53832013-11-12 20:53:05 +000022
mtklein36352bf2015-03-25 18:17:31 -070023 size_t read(void* buffer, size_t size) override;
scroggo@google.com09a53832013-11-12 20:53:05 +000024
scroggod61c3842015-12-07 11:37:13 -080025 size_t peek(void* buffer, size_t size) const override;
scroggo028a4132015-04-02 13:19:51 -070026
mtklein36352bf2015-03-25 18:17:31 -070027 bool isAtEnd() const override;
scroggo@google.com09a53832013-11-12 20:53:05 +000028
mtklein36352bf2015-03-25 18:17:31 -070029 bool rewind() override;
scroggo@google.com09a53832013-11-12 20:53:05 +000030
mtklein36352bf2015-03-25 18:17:31 -070031 bool hasLength() const override { return fHasLength; }
scroggo@google.com09a53832013-11-12 20:53:05 +000032
mtklein36352bf2015-03-25 18:17:31 -070033 size_t getLength() const override { return fLength; }
scroggo@google.com09a53832013-11-12 20:53:05 +000034
scroggo@google.com09a53832013-11-12 20:53:05 +000035private:
Mike Reed98c5d922017-09-15 21:39:47 -040036 SkStreamRewindable* onDuplicate() const override { return nullptr; }
Mike Reed98c5d922017-09-15 21:39:47 -040037
Ben Wagner145dbcd2016-11-03 14:40:50 -040038 std::unique_ptr<SkStream> fStream;
39 const bool fHasLength;
40 const size_t fLength;
scroggo@google.com09a53832013-11-12 20:53:05 +000041 // Current offset into the stream. Always >= 0.
Ben Wagner145dbcd2016-11-03 14:40:50 -040042 size_t fOffset;
scroggo@google.com09a53832013-11-12 20:53:05 +000043 // Amount that has been buffered by calls to read. Will always be less than
44 // fBufferSize.
Ben Wagner145dbcd2016-11-03 14:40:50 -040045 size_t fBufferedSoFar;
scroggo@google.com09a53832013-11-12 20:53:05 +000046 // Total size of the buffer.
Ben Wagner145dbcd2016-11-03 14:40:50 -040047 const size_t fBufferSize;
Leon Scroggins III63cfb362020-04-24 13:00:48 -040048 char* fBuffer;
49 static constexpr size_t kStorageSize = SkCodec::MinBufferedBytesNeeded();
50 char fStorage[kStorageSize];
scroggo@google.com09a53832013-11-12 20:53:05 +000051
52 // Read up to size bytes from already buffered data, and copy to
halcanary96fcdcc2015-08-27 07:41:13 -070053 // dst, if non-nullptr. Updates fOffset. Assumes that fOffset is less
scroggo@google.com09a53832013-11-12 20:53:05 +000054 // than fBufferedSoFar.
55 size_t readFromBuffer(char* dst, size_t size);
56
57 // Buffer up to size bytes from the stream, and copy to dst if non-
halcanary96fcdcc2015-08-27 07:41:13 -070058 // nullptr. Updates fOffset and fBufferedSoFar. Assumes that fOffset is
scroggo@google.com09a53832013-11-12 20:53:05 +000059 // less than fBufferedSoFar, and size is greater than 0.
60 size_t bufferAndWriteTo(char* dst, size_t size);
61
62 // Read up to size bytes directly from the stream and into dst if non-
halcanary96fcdcc2015-08-27 07:41:13 -070063 // nullptr. Updates fOffset. Assumes fOffset is at or beyond the buffered
scroggo@google.com09a53832013-11-12 20:53:05 +000064 // data, and size is greater than 0.
65 size_t readDirectlyFromStream(char* dst, size_t size);
66
67 typedef SkStream INHERITED;
68};
Leon Scroggins III63cfb362020-04-24 13:00:48 -040069} // anonymous namespace
scroggo@google.com83fd2c72013-09-26 21:35:39 +000070
Leon Scroggins III63cfb362020-04-24 13:00:48 -040071namespace android {
72namespace skia {
73
74std::unique_ptr<SkStreamRewindable> FrontBufferedStream::Make(std::unique_ptr<SkStream> stream,
75 size_t bufferSize) {
Mike Reed98c5d922017-09-15 21:39:47 -040076 if (!stream) {
halcanary96fcdcc2015-08-27 07:41:13 -070077 return nullptr;
scroggo@google.com83fd2c72013-09-26 21:35:39 +000078 }
Leon Scroggins III63cfb362020-04-24 13:00:48 -040079 auto frontBufferedStream = std::unique_ptr<::FrontBufferedStream>(
80 new ::FrontBufferedStream(std::move(stream), bufferSize));
81 if (frontBufferedStream->failedToAllocateBuffer()) {
82 return nullptr;
83 }
Leon Scroggins III513720f2020-04-23 12:35:30 -040084
Leon Scroggins III63cfb362020-04-24 13:00:48 -040085 // Work around a warning regarding a copy on older compilers.
86 return std::move(frontBufferedStream);
87}
88} // namespace skia
89} // namespace android
90
91namespace {
Mike Reed98c5d922017-09-15 21:39:47 -040092FrontBufferedStream::FrontBufferedStream(std::unique_ptr<SkStream> stream, size_t bufferSize)
93 : fStream(std::move(stream))
94 , fHasLength(fStream->hasPosition() && fStream->hasLength())
95 , fLength(fStream->getLength() - fStream->getPosition())
scroggo@google.com83fd2c72013-09-26 21:35:39 +000096 , fOffset(0)
97 , fBufferedSoFar(0)
98 , fBufferSize(bufferSize)
Leon Scroggins III63cfb362020-04-24 13:00:48 -040099 , fBuffer(bufferSize <= kStorageSize ? fStorage
100 : reinterpret_cast<char*>(malloc(bufferSize))) {}
101
102FrontBufferedStream::~FrontBufferedStream() {
103 if (fBuffer != fStorage) {
104 free(fBuffer);
105 }
106}
scroggo@google.com83fd2c72013-09-26 21:35:39 +0000107
scroggo@google.com09a53832013-11-12 20:53:05 +0000108bool FrontBufferedStream::isAtEnd() const {
scroggo@google.com83fd2c72013-09-26 21:35:39 +0000109 if (fOffset < fBufferedSoFar) {
110 // Even if the underlying stream is at the end, this stream has been
111 // rewound after buffering, so it is not at the end.
112 return false;
113 }
114
115 return fStream->isAtEnd();
116}
117
scroggo@google.com09a53832013-11-12 20:53:05 +0000118bool FrontBufferedStream::rewind() {
scroggo@google.com83fd2c72013-09-26 21:35:39 +0000119 // Only allow a rewind if we have not exceeded the buffer.
120 if (fOffset <= fBufferSize) {
121 fOffset = 0;
122 return true;
123 }
124 return false;
125}
126
scroggo@google.com09a53832013-11-12 20:53:05 +0000127size_t FrontBufferedStream::readFromBuffer(char* dst, size_t size) {
scroggo@google.com83fd2c72013-09-26 21:35:39 +0000128 SkASSERT(fOffset < fBufferedSoFar);
129 // Some data has already been copied to fBuffer. Read up to the
130 // lesser of the size requested and the remainder of the buffered
131 // data.
Brian Osman788b9162020-02-07 10:36:46 -0500132 const size_t bytesToCopy = std::min(size, fBufferedSoFar - fOffset);
halcanary96fcdcc2015-08-27 07:41:13 -0700133 if (dst != nullptr) {
scroggo@google.com83fd2c72013-09-26 21:35:39 +0000134 memcpy(dst, fBuffer + fOffset, bytesToCopy);
135 }
136
137 // Update fOffset to the new position. It is guaranteed to be
138 // within the buffered data.
139 fOffset += bytesToCopy;
140 SkASSERT(fOffset <= fBufferedSoFar);
141
142 return bytesToCopy;
143}
144
scroggo@google.com09a53832013-11-12 20:53:05 +0000145size_t FrontBufferedStream::bufferAndWriteTo(char* dst, size_t size) {
scroggo@google.com83fd2c72013-09-26 21:35:39 +0000146 SkASSERT(size > 0);
147 SkASSERT(fOffset >= fBufferedSoFar);
mtklein1f66e452014-10-21 07:12:52 -0700148 SkASSERT(fBuffer);
scroggo@google.com83fd2c72013-09-26 21:35:39 +0000149 // Data needs to be buffered. Buffer up to the lesser of the size requested
150 // and the remainder of the max buffer size.
Brian Osman788b9162020-02-07 10:36:46 -0500151 const size_t bytesToBuffer = std::min(size, fBufferSize - fBufferedSoFar);
scroggo@google.com83fd2c72013-09-26 21:35:39 +0000152 char* buffer = fBuffer + fOffset;
153 const size_t buffered = fStream->read(buffer, bytesToBuffer);
154
155 fBufferedSoFar += buffered;
156 fOffset = fBufferedSoFar;
157 SkASSERT(fBufferedSoFar <= fBufferSize);
158
159 // Copy the buffer to the destination buffer and update the amount read.
halcanary96fcdcc2015-08-27 07:41:13 -0700160 if (dst != nullptr) {
scroggo@google.com83fd2c72013-09-26 21:35:39 +0000161 memcpy(dst, buffer, buffered);
162 }
163
164 return buffered;
165}
166
scroggo@google.com09a53832013-11-12 20:53:05 +0000167size_t FrontBufferedStream::readDirectlyFromStream(char* dst, size_t size) {
scroggo@google.com83fd2c72013-09-26 21:35:39 +0000168 SkASSERT(size > 0);
169 // If we get here, we have buffered all that can be buffered.
170 SkASSERT(fBufferSize == fBufferedSoFar && fOffset >= fBufferSize);
171
172 const size_t bytesReadDirectly = fStream->read(dst, size);
173 fOffset += bytesReadDirectly;
174
175 // If we have read past the end of the buffer, rewinding is no longer
176 // supported, so we can go ahead and free the memory.
Leon Scroggins III63cfb362020-04-24 13:00:48 -0400177 if (bytesReadDirectly > 0 && fBuffer != fStorage) {
178 free(fBuffer);
179 fBuffer = nullptr;
scroggo@google.com83fd2c72013-09-26 21:35:39 +0000180 }
181
182 return bytesReadDirectly;
183}
184
scroggod61c3842015-12-07 11:37:13 -0800185size_t FrontBufferedStream::peek(void* dst, size_t size) const {
scroggo028a4132015-04-02 13:19:51 -0700186 // Keep track of the offset so we can return to it.
187 const size_t start = fOffset;
scroggod61c3842015-12-07 11:37:13 -0800188
189 if (start >= fBufferSize) {
190 // This stream is not able to buffer.
191 return 0;
scroggo028a4132015-04-02 13:19:51 -0700192 }
scroggod61c3842015-12-07 11:37:13 -0800193
Brian Osman788b9162020-02-07 10:36:46 -0500194 size = std::min(size, fBufferSize - start);
scroggo028a4132015-04-02 13:19:51 -0700195 FrontBufferedStream* nonConstThis = const_cast<FrontBufferedStream*>(this);
scroggod61c3842015-12-07 11:37:13 -0800196 const size_t bytesRead = nonConstThis->read(dst, size);
scroggo028a4132015-04-02 13:19:51 -0700197 nonConstThis->fOffset = start;
scroggod61c3842015-12-07 11:37:13 -0800198 return bytesRead;
scroggo028a4132015-04-02 13:19:51 -0700199}
200
scroggo@google.com09a53832013-11-12 20:53:05 +0000201size_t FrontBufferedStream::read(void* voidDst, size_t size) {
scroggo@google.com83fd2c72013-09-26 21:35:39 +0000202 // Cast voidDst to a char* for easy addition.
203 char* dst = reinterpret_cast<char*>(voidDst);
204 SkDEBUGCODE(const size_t totalSize = size;)
205 const size_t start = fOffset;
206
207 // First, read any data that was previously buffered.
208 if (fOffset < fBufferedSoFar) {
209 const size_t bytesCopied = this->readFromBuffer(dst, size);
210
211 // Update the remaining number of bytes needed to read
212 // and the destination buffer.
213 size -= bytesCopied;
214 SkASSERT(size + (fOffset - start) == totalSize);
halcanary96fcdcc2015-08-27 07:41:13 -0700215 if (dst != nullptr) {
scroggo@google.com83fd2c72013-09-26 21:35:39 +0000216 dst += bytesCopied;
217 }
218 }
219
220 // Buffer any more data that should be buffered, and copy it to the
221 // destination.
scroggodd5a1e02014-10-21 08:06:05 -0700222 if (size > 0 && fBufferedSoFar < fBufferSize && !fStream->isAtEnd()) {
scroggo@google.com83fd2c72013-09-26 21:35:39 +0000223 const size_t buffered = this->bufferAndWriteTo(dst, size);
224
225 // Update the remaining number of bytes needed to read
226 // and the destination buffer.
227 size -= buffered;
228 SkASSERT(size + (fOffset - start) == totalSize);
halcanary96fcdcc2015-08-27 07:41:13 -0700229 if (dst != nullptr) {
scroggo@google.com83fd2c72013-09-26 21:35:39 +0000230 dst += buffered;
231 }
232 }
233
234 if (size > 0 && !fStream->isAtEnd()) {
scroggo@google.comfd67f2f2013-09-26 21:49:46 +0000235 SkDEBUGCODE(const size_t bytesReadDirectly =) this->readDirectlyFromStream(dst, size);
scroggo@google.com83fd2c72013-09-26 21:35:39 +0000236 SkDEBUGCODE(size -= bytesReadDirectly;)
237 SkASSERT(size + (fOffset - start) == totalSize);
238 }
239
240 return fOffset - start;
241}
Leon Scroggins III63cfb362020-04-24 13:00:48 -0400242} // anonymous namespace