/* * Copyright 2016 Google Inc. * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #ifndef SkStreamBuffer_DEFINED #define SkStreamBuffer_DEFINED #include "SkData.h" #include "SkStream.h" #include "SkTypes.h" #include "../private/SkTHash.h" /** * Helper class for reading from a stream that may not have all its data * available yet. * * Used by GIFImageReader, and currently set up for that use case. * * Buffers up to 256 * 3 bytes (256 colors, with 3 bytes each) to support GIF. * FIXME (scroggo): Make this more general purpose? */ class SkStreamBuffer : SkNoncopyable { public: SkStreamBuffer(std::unique_ptr<SkStream>); ~SkStreamBuffer(); /** * Return a pointer the buffered data. * * The number of bytes buffered is the number passed to buffer() * after the last call to flush(). */ const char* get() const; /** * Buffer from the stream into our buffer. * * If this call returns true, get() can be used to access |bytes| bytes * from the stream. In addition, markPosition() can be called to mark this * position and enable calling getAtPosition() later to retrieve |bytes| * bytes. * * @param bytes Total number of bytes desired. * * @return Whether all bytes were successfully buffered. */ bool buffer(size_t bytes); /** * Flush the buffer. * * After this call, no bytes are buffered. */ void flush() { if (fHasLengthAndPosition) { if (fTrulyBuffered < fBytesBuffered) { fStream->move(fBytesBuffered - fTrulyBuffered); } fTrulyBuffered = 0; } fPosition += fBytesBuffered; fBytesBuffered = 0; } /** * Mark the current position in the stream to return to it later. * * This is the position of the start of the buffer. After this call, a * a client can call getDataAtPosition to retrieve all the bytes currently * buffered. * * @return size_t Position which can be passed to getDataAtPosition later * to retrieve the data currently buffered. */ size_t markPosition(); /** * Retrieve data at position, as previously marked by markPosition(). * * @param position Position to retrieve data, as marked by markPosition(). * @param length Amount of data required at position. * @return SkData The data at position. */ sk_sp<SkData> getDataAtPosition(size_t position, size_t length); private: static constexpr size_t kMaxSize = 256 * 3; std::unique_ptr<SkStream> fStream; size_t fPosition; char fBuffer[kMaxSize]; size_t fBytesBuffered; // If the stream has a length and position, we can make two optimizations: // - We can skip buffering // - During parsing, we can store the position and size of data that is // needed later during decoding. const bool fHasLengthAndPosition; // When fHasLengthAndPosition is true, we do not need to actually buffer // inside buffer(). We'll buffer inside get(). This keeps track of how many // bytes we've buffered inside get(), for the (non-existent) case of: // buffer(n) // get() // buffer(n + u) // get() // The second call to get() needs to only truly buffer the part that was // not already buffered. mutable size_t fTrulyBuffered; // Only used if !fHasLengthAndPosition. In that case, markPosition will // copy into an SkData, stored here. SkTHashMap<size_t, SkData*> fMarkedData; }; #endif // SkStreamBuffer_DEFINED