blob: a5e229fa9cf7ba11ac338ac946dfb187f4f92f65 [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>
John Stilesfbd050b2020-08-03 13:21:46 -040013#include <memory>
Leon Scroggins III63cfb362020-04-24 13:00:48 -040014
15namespace {
scroggo@google.com09a53832013-11-12 20:53:05 +000016class FrontBufferedStream : public SkStreamRewindable {
17public:
Mike Reed98c5d922017-09-15 21:39:47 -040018 // Called by Make.
19 FrontBufferedStream(std::unique_ptr<SkStream>, size_t bufferSize);
Leon Scroggins III63cfb362020-04-24 13:00:48 -040020 ~FrontBufferedStream() override;
21
22 bool failedToAllocateBuffer() const { return !fBuffer; }
scroggo@google.com09a53832013-11-12 20:53:05 +000023
mtklein36352bf2015-03-25 18:17:31 -070024 size_t read(void* buffer, size_t size) override;
scroggo@google.com09a53832013-11-12 20:53:05 +000025
scroggod61c3842015-12-07 11:37:13 -080026 size_t peek(void* buffer, size_t size) const override;
scroggo028a4132015-04-02 13:19:51 -070027
mtklein36352bf2015-03-25 18:17:31 -070028 bool isAtEnd() const override;
scroggo@google.com09a53832013-11-12 20:53:05 +000029
mtklein36352bf2015-03-25 18:17:31 -070030 bool rewind() override;
scroggo@google.com09a53832013-11-12 20:53:05 +000031
mtklein36352bf2015-03-25 18:17:31 -070032 bool hasLength() const override { return fHasLength; }
scroggo@google.com09a53832013-11-12 20:53:05 +000033
mtklein36352bf2015-03-25 18:17:31 -070034 size_t getLength() const override { return fLength; }
scroggo@google.com09a53832013-11-12 20:53:05 +000035
scroggo@google.com09a53832013-11-12 20:53:05 +000036private:
Mike Reed98c5d922017-09-15 21:39:47 -040037 SkStreamRewindable* onDuplicate() const override { return nullptr; }
Mike Reed98c5d922017-09-15 21:39:47 -040038
Ben Wagner145dbcd2016-11-03 14:40:50 -040039 std::unique_ptr<SkStream> fStream;
40 const bool fHasLength;
41 const size_t fLength;
scroggo@google.com09a53832013-11-12 20:53:05 +000042 // Current offset into the stream. Always >= 0.
Ben Wagner145dbcd2016-11-03 14:40:50 -040043 size_t fOffset;
scroggo@google.com09a53832013-11-12 20:53:05 +000044 // Amount that has been buffered by calls to read. Will always be less than
45 // fBufferSize.
Ben Wagner145dbcd2016-11-03 14:40:50 -040046 size_t fBufferedSoFar;
scroggo@google.com09a53832013-11-12 20:53:05 +000047 // Total size of the buffer.
Ben Wagner145dbcd2016-11-03 14:40:50 -040048 const size_t fBufferSize;
Leon Scroggins III63cfb362020-04-24 13:00:48 -040049 char* fBuffer;
50 static constexpr size_t kStorageSize = SkCodec::MinBufferedBytesNeeded();
51 char fStorage[kStorageSize];
scroggo@google.com09a53832013-11-12 20:53:05 +000052
53 // Read up to size bytes from already buffered data, and copy to
halcanary96fcdcc2015-08-27 07:41:13 -070054 // dst, if non-nullptr. Updates fOffset. Assumes that fOffset is less
scroggo@google.com09a53832013-11-12 20:53:05 +000055 // 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-
halcanary96fcdcc2015-08-27 07:41:13 -070059 // nullptr. Updates fOffset and fBufferedSoFar. Assumes that fOffset is
scroggo@google.com09a53832013-11-12 20:53:05 +000060 // 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-
halcanary96fcdcc2015-08-27 07:41:13 -070064 // nullptr. Updates fOffset. Assumes fOffset is at or beyond the buffered
scroggo@google.com09a53832013-11-12 20:53:05 +000065 // data, and size is greater than 0.
66 size_t readDirectlyFromStream(char* dst, size_t size);
67
John Stiles7571f9e2020-09-02 22:42:33 -040068 using INHERITED = SkStream;
scroggo@google.com09a53832013-11-12 20:53:05 +000069};
Leon Scroggins III63cfb362020-04-24 13:00:48 -040070} // anonymous namespace
scroggo@google.com83fd2c72013-09-26 21:35:39 +000071
Leon Scroggins III63cfb362020-04-24 13:00:48 -040072namespace android {
73namespace skia {
74
75std::unique_ptr<SkStreamRewindable> FrontBufferedStream::Make(std::unique_ptr<SkStream> stream,
76 size_t bufferSize) {
Mike Reed98c5d922017-09-15 21:39:47 -040077 if (!stream) {
halcanary96fcdcc2015-08-27 07:41:13 -070078 return nullptr;
scroggo@google.com83fd2c72013-09-26 21:35:39 +000079 }
John Stilesfbd050b2020-08-03 13:21:46 -040080 auto frontBufferedStream = std::make_unique<::FrontBufferedStream>(
81 std::move(stream), bufferSize);
Leon Scroggins III63cfb362020-04-24 13:00:48 -040082 if (frontBufferedStream->failedToAllocateBuffer()) {
83 return nullptr;
84 }
Leon Scroggins III513720f2020-04-23 12:35:30 -040085
Leon Scroggins III63cfb362020-04-24 13:00:48 -040086 // Work around a warning regarding a copy on older compilers.
87 return std::move(frontBufferedStream);
88}
89} // namespace skia
90} // namespace android
91
92namespace {
Mike Reed98c5d922017-09-15 21:39:47 -040093FrontBufferedStream::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())
scroggo@google.com83fd2c72013-09-26 21:35:39 +000097 , fOffset(0)
98 , fBufferedSoFar(0)
99 , fBufferSize(bufferSize)
Leon Scroggins III63cfb362020-04-24 13:00:48 -0400100 , fBuffer(bufferSize <= kStorageSize ? fStorage
101 : reinterpret_cast<char*>(malloc(bufferSize))) {}
102
103FrontBufferedStream::~FrontBufferedStream() {
104 if (fBuffer != fStorage) {
105 free(fBuffer);
106 }
107}
scroggo@google.com83fd2c72013-09-26 21:35:39 +0000108
scroggo@google.com09a53832013-11-12 20:53:05 +0000109bool FrontBufferedStream::isAtEnd() const {
scroggo@google.com83fd2c72013-09-26 21:35:39 +0000110 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
scroggo@google.com09a53832013-11-12 20:53:05 +0000119bool FrontBufferedStream::rewind() {
scroggo@google.com83fd2c72013-09-26 21:35:39 +0000120 // 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
scroggo@google.com09a53832013-11-12 20:53:05 +0000128size_t FrontBufferedStream::readFromBuffer(char* dst, size_t size) {
scroggo@google.com83fd2c72013-09-26 21:35:39 +0000129 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.
Brian Osman788b9162020-02-07 10:36:46 -0500133 const size_t bytesToCopy = std::min(size, fBufferedSoFar - fOffset);
halcanary96fcdcc2015-08-27 07:41:13 -0700134 if (dst != nullptr) {
scroggo@google.com83fd2c72013-09-26 21:35:39 +0000135 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
scroggo@google.com09a53832013-11-12 20:53:05 +0000146size_t FrontBufferedStream::bufferAndWriteTo(char* dst, size_t size) {
scroggo@google.com83fd2c72013-09-26 21:35:39 +0000147 SkASSERT(size > 0);
148 SkASSERT(fOffset >= fBufferedSoFar);
mtklein1f66e452014-10-21 07:12:52 -0700149 SkASSERT(fBuffer);
scroggo@google.com83fd2c72013-09-26 21:35:39 +0000150 // Data needs to be buffered. Buffer up to the lesser of the size requested
151 // and the remainder of the max buffer size.
Brian Osman788b9162020-02-07 10:36:46 -0500152 const size_t bytesToBuffer = std::min(size, fBufferSize - fBufferedSoFar);
scroggo@google.com83fd2c72013-09-26 21:35:39 +0000153 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.
halcanary96fcdcc2015-08-27 07:41:13 -0700161 if (dst != nullptr) {
scroggo@google.com83fd2c72013-09-26 21:35:39 +0000162 memcpy(dst, buffer, buffered);
163 }
164
165 return buffered;
166}
167
scroggo@google.com09a53832013-11-12 20:53:05 +0000168size_t FrontBufferedStream::readDirectlyFromStream(char* dst, size_t size) {
scroggo@google.com83fd2c72013-09-26 21:35:39 +0000169 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.
Leon Scroggins III63cfb362020-04-24 13:00:48 -0400178 if (bytesReadDirectly > 0 && fBuffer != fStorage) {
179 free(fBuffer);
180 fBuffer = nullptr;
scroggo@google.com83fd2c72013-09-26 21:35:39 +0000181 }
182
183 return bytesReadDirectly;
184}
185
scroggod61c3842015-12-07 11:37:13 -0800186size_t FrontBufferedStream::peek(void* dst, size_t size) const {
scroggo028a4132015-04-02 13:19:51 -0700187 // Keep track of the offset so we can return to it.
188 const size_t start = fOffset;
scroggod61c3842015-12-07 11:37:13 -0800189
190 if (start >= fBufferSize) {
191 // This stream is not able to buffer.
192 return 0;
scroggo028a4132015-04-02 13:19:51 -0700193 }
scroggod61c3842015-12-07 11:37:13 -0800194
Brian Osman788b9162020-02-07 10:36:46 -0500195 size = std::min(size, fBufferSize - start);
scroggo028a4132015-04-02 13:19:51 -0700196 FrontBufferedStream* nonConstThis = const_cast<FrontBufferedStream*>(this);
scroggod61c3842015-12-07 11:37:13 -0800197 const size_t bytesRead = nonConstThis->read(dst, size);
scroggo028a4132015-04-02 13:19:51 -0700198 nonConstThis->fOffset = start;
scroggod61c3842015-12-07 11:37:13 -0800199 return bytesRead;
scroggo028a4132015-04-02 13:19:51 -0700200}
201
scroggo@google.com09a53832013-11-12 20:53:05 +0000202size_t FrontBufferedStream::read(void* voidDst, size_t size) {
scroggo@google.com83fd2c72013-09-26 21:35:39 +0000203 // 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);
halcanary96fcdcc2015-08-27 07:41:13 -0700216 if (dst != nullptr) {
scroggo@google.com83fd2c72013-09-26 21:35:39 +0000217 dst += bytesCopied;
218 }
219 }
220
221 // Buffer any more data that should be buffered, and copy it to the
222 // destination.
scroggodd5a1e02014-10-21 08:06:05 -0700223 if (size > 0 && fBufferedSoFar < fBufferSize && !fStream->isAtEnd()) {
scroggo@google.com83fd2c72013-09-26 21:35:39 +0000224 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);
halcanary96fcdcc2015-08-27 07:41:13 -0700230 if (dst != nullptr) {
scroggo@google.com83fd2c72013-09-26 21:35:39 +0000231 dst += buffered;
232 }
233 }
234
235 if (size > 0 && !fStream->isAtEnd()) {
scroggo@google.comfd67f2f2013-09-26 21:49:46 +0000236 SkDEBUGCODE(const size_t bytesReadDirectly =) this->readDirectlyFromStream(dst, size);
scroggo@google.com83fd2c72013-09-26 21:35:39 +0000237 SkDEBUGCODE(size -= bytesReadDirectly;)
238 SkASSERT(size + (fOffset - start) == totalSize);
239 }
240
241 return fOffset - start;
242}
Leon Scroggins III63cfb362020-04-24 13:00:48 -0400243} // anonymous namespace