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