blob: 2b60775dd2c5c99bf9bb28d4ddb17ceb207f672f [file] [log] [blame]
scroggo19b91532016-10-24 09:03:26 -07001/*
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
Leon Scroggins III932efed2016-12-16 11:39:51 -050011#include "SkData.h"
scroggo19b91532016-10-24 09:03:26 -070012#include "SkStream.h"
13#include "SkTypes.h"
Leon Scroggins III932efed2016-12-16 11:39:51 -050014#include "../private/SkTHash.h"
scroggo19b91532016-10-24 09:03:26 -070015
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 // Takes ownership of the SkStream.
28 SkStreamBuffer(SkStream*);
29
Leon Scroggins III932efed2016-12-16 11:39:51 -050030 ~SkStreamBuffer();
31
scroggo19b91532016-10-24 09:03:26 -070032 /**
33 * Return a pointer the buffered data.
34 *
Leon Scroggins III932efed2016-12-16 11:39:51 -050035 * The number of bytes buffered is the number passed to buffer()
36 * after the last call to flush().
scroggo19b91532016-10-24 09:03:26 -070037 */
Leon Scroggins III932efed2016-12-16 11:39:51 -050038 const char* get() const;
scroggo19b91532016-10-24 09:03:26 -070039
40 /**
41 * Buffer from the stream into our buffer.
42 *
Leon Scroggins III932efed2016-12-16 11:39:51 -050043 * If this call returns true, get() can be used to access |bytes| bytes
44 * from the stream. In addition, markPosition() can be called to mark this
45 * position and enable calling getAtPosition() later to retrieve |bytes|
46 * bytes.
47 *
48 * @param bytes Total number of bytes desired.
49 *
50 * @return Whether all bytes were successfully buffered.
scroggo19b91532016-10-24 09:03:26 -070051 */
Leon Scroggins III932efed2016-12-16 11:39:51 -050052 bool buffer(size_t bytes);
scroggo19b91532016-10-24 09:03:26 -070053
54 /**
55 * Flush the buffer.
56 *
57 * After this call, no bytes are buffered.
58 */
59 void flush() {
Leon Scroggins III932efed2016-12-16 11:39:51 -050060 if (fHasLengthAndPosition) {
61 if (fTrulyBuffered < fBytesBuffered) {
62 fStream->move(fBytesBuffered - fTrulyBuffered);
63 }
64 fTrulyBuffered = 0;
65 }
66 fPosition += fBytesBuffered;
scroggo19b91532016-10-24 09:03:26 -070067 fBytesBuffered = 0;
68 }
69
Leon Scroggins III932efed2016-12-16 11:39:51 -050070 /**
71 * Mark the current position in the stream to return to it later.
72 *
73 * This is the position of the start of the buffer. After this call, a
74 * a client can call getDataAtPosition to retrieve all the bytes currently
75 * buffered.
76 *
77 * @return size_t Position which can be passed to getDataAtPosition later
78 * to retrieve the data currently buffered.
79 */
80 size_t markPosition();
81
82 /**
83 * Retrieve data at position, as previously marked by markPosition().
84 *
85 * @param position Position to retrieve data, as marked by markPosition().
86 * @param length Amount of data required at position.
87 * @return SkData The data at position.
88 */
89 sk_sp<SkData> getDataAtPosition(size_t position, size_t length);
90
scroggo19b91532016-10-24 09:03:26 -070091private:
92 static constexpr size_t kMaxSize = 256 * 3;
93
94 std::unique_ptr<SkStream> fStream;
Leon Scroggins III932efed2016-12-16 11:39:51 -050095 size_t fPosition;
scroggo19b91532016-10-24 09:03:26 -070096 char fBuffer[kMaxSize];
97 size_t fBytesBuffered;
Leon Scroggins III932efed2016-12-16 11:39:51 -050098 // If the stream has a length and position, we can make two optimizations:
99 // - We can skip buffering
100 // - During parsing, we can store the position and size of data that is
101 // needed later during decoding.
102 const bool fHasLengthAndPosition;
103 // When fHasLengthAndPosition is true, we do not need to actually buffer
104 // inside buffer(). We'll buffer inside get(). This keeps track of how many
105 // bytes we've buffered inside get(), for the (non-existent) case of:
106 // buffer(n)
107 // get()
108 // buffer(n + u)
109 // get()
110 // The second call to get() needs to only truly buffer the part that was
111 // not already buffered.
112 mutable size_t fTrulyBuffered;
113 // Only used if !fHasLengthAndPosition. In that case, markPosition will
114 // copy into an SkData, stored here.
115 SkTHashMap<size_t, SkData*> fMarkedData;
scroggo19b91532016-10-24 09:03:26 -0700116};
117#endif // SkStreamBuffer_DEFINED
118