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