/*
|
* 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
|