1/*
2 * Copyright 2016 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
8#ifndef SkStreamBuffer_DEFINED
9#define SkStreamBuffer_DEFINED
10
11#include "include/core/SkData.h"
12#include "include/core/SkStream.h"
13#include "include/core/SkTypes.h"
14#include "include/private/SkTHash.h"
15
16/**
17 * Helper class for reading from a stream that may not have all its data
18 * available yet.
19 *
20 * Used by GIFImageReader, and currently set up for that use case.
21 *
22 * Buffers up to 256 * 3 bytes (256 colors, with 3 bytes each) to support GIF.
23 * FIXME (scroggo): Make this more general purpose?
24 */
25class SkStreamBuffer : SkNoncopyable {
26public:
27 SkStreamBuffer(std::unique_ptr<SkStream>);
28 ~SkStreamBuffer();
29
30 /**
31 * Return a pointer the buffered data.
32 *
33 * The number of bytes buffered is the number passed to buffer()
34 * after the last call to flush().
35 */
36 const char* get() const;
37
38 /**
39 * Buffer from the stream into our buffer.
40 *
41 * If this call returns true, get() can be used to access |bytes| bytes
42 * from the stream. In addition, markPosition() can be called to mark this
43 * position and enable calling getAtPosition() later to retrieve |bytes|
44 * bytes.
45 *
46 * @param bytes Total number of bytes desired.
47 *
48 * @return Whether all bytes were successfully buffered.
49 */
50 bool buffer(size_t bytes);
51
52 /**
53 * Flush the buffer.
54 *
55 * After this call, no bytes are buffered.
56 */
57 void flush() {
58 if (fHasLengthAndPosition) {
59 if (fTrulyBuffered < fBytesBuffered) {
60 fStream->move(fBytesBuffered - fTrulyBuffered);
61 }
62 fTrulyBuffered = 0;
63 }
64 fPosition += fBytesBuffered;
65 fBytesBuffered = 0;
66 }
67
68 /**
69 * Mark the current position in the stream to return to it later.
70 *
71 * This is the position of the start of the buffer. After this call, a
72 * a client can call getDataAtPosition to retrieve all the bytes currently
73 * buffered.
74 *
75 * @return size_t Position which can be passed to getDataAtPosition later
76 * to retrieve the data currently buffered.
77 */
78 size_t markPosition();
79
80 /**
81 * Retrieve data at position, as previously marked by markPosition().
82 *
83 * @param position Position to retrieve data, as marked by markPosition().
84 * @param length Amount of data required at position.
85 * @return SkData The data at position.
86 */
87 sk_sp<SkData> getDataAtPosition(size_t position, size_t length);
88
89private:
90 static constexpr size_t kMaxSize = 256 * 3;
91
92 std::unique_ptr<SkStream> fStream;
93 size_t fPosition;
94 char fBuffer[kMaxSize];
95 size_t fBytesBuffered;
96 // If the stream has a length and position, we can make two optimizations:
97 // - We can skip buffering
98 // - During parsing, we can store the position and size of data that is
99 // needed later during decoding.
100 const bool fHasLengthAndPosition;
101 // When fHasLengthAndPosition is true, we do not need to actually buffer
102 // inside buffer(). We'll buffer inside get(). This keeps track of how many
103 // bytes we've buffered inside get(), for the (non-existent) case of:
104 // buffer(n)
105 // get()
106 // buffer(n + u)
107 // get()
108 // The second call to get() needs to only truly buffer the part that was
109 // not already buffered.
110 mutable size_t fTrulyBuffered;
111 // Only used if !fHasLengthAndPosition. In that case, markPosition will
112 // copy into an SkData, stored here.
113 SkTHashMap<size_t, SkData*> fMarkedData;
114};
115#endif // SkStreamBuffer_DEFINED
116
117