1 | // Copyright 2014 The Flutter Authors. All rights reserved. |
---|---|
2 | // Use of this source code is governed by a BSD-style license that can be |
3 | // found in the LICENSE file. |
4 | |
5 | import 'dart:math' as math; |
6 | import 'dart:typed_data'; |
7 | |
8 | export 'dart:typed_data' |
9 | show ByteData, Endian, Float32List, Float64List, Int32List, Int64List, Uint8List; |
10 | |
11 | /// Write-only buffer for incrementally building a [ByteData] instance. |
12 | /// |
13 | /// A WriteBuffer instance can be used only once. Attempts to reuse will result |
14 | /// in [StateError]s being thrown. |
15 | /// |
16 | /// The byte order used is [Endian.host] throughout. |
17 | class WriteBuffer { |
18 | /// Creates an interface for incrementally building a [ByteData] instance. |
19 | /// [startCapacity] determines the start size of the [WriteBuffer] in bytes. |
20 | /// The closer that value is to the real size used, the better the |
21 | /// performance. |
22 | factory WriteBuffer({int startCapacity = 8}) { |
23 | assert(startCapacity > 0); |
24 | final ByteData eightBytes = ByteData(8); |
25 | final Uint8List eightBytesAsList = eightBytes.buffer.asUint8List(); |
26 | return WriteBuffer._(Uint8List(startCapacity), eightBytes, eightBytesAsList); |
27 | } |
28 | |
29 | WriteBuffer._(this._buffer, this._eightBytes, this._eightBytesAsList); |
30 | |
31 | Uint8List _buffer; |
32 | int _currentSize = 0; |
33 | bool _isDone = false; |
34 | final ByteData _eightBytes; |
35 | final Uint8List _eightBytesAsList; |
36 | static final Uint8List _zeroBuffer = Uint8List(8); |
37 | |
38 | void _add(int byte) { |
39 | if (_currentSize == _buffer.length) { |
40 | _resize(); |
41 | } |
42 | _buffer[_currentSize] = byte; |
43 | _currentSize += 1; |
44 | } |
45 | |
46 | void _append(Uint8List other) { |
47 | final int newSize = _currentSize + other.length; |
48 | if (newSize >= _buffer.length) { |
49 | _resize(newSize); |
50 | } |
51 | _buffer.setRange(_currentSize, newSize, other); |
52 | _currentSize += other.length; |
53 | } |
54 | |
55 | void _addAll(Uint8List data, [int start = 0, int? end]) { |
56 | final int newEnd = end ?? _eightBytesAsList.length; |
57 | final int newSize = _currentSize + (newEnd - start); |
58 | if (newSize >= _buffer.length) { |
59 | _resize(newSize); |
60 | } |
61 | _buffer.setRange(_currentSize, newSize, data); |
62 | _currentSize = newSize; |
63 | } |
64 | |
65 | void _resize([int? requiredLength]) { |
66 | final int doubleLength = _buffer.length * 2; |
67 | final int newLength = math.max(requiredLength ?? 0, doubleLength); |
68 | final Uint8List newBuffer = Uint8List(newLength); |
69 | newBuffer.setRange(0, _buffer.length, _buffer); |
70 | _buffer = newBuffer; |
71 | } |
72 | |
73 | /// Write a Uint8 into the buffer. |
74 | void putUint8(int byte) { |
75 | assert(!_isDone); |
76 | _add(byte); |
77 | } |
78 | |
79 | /// Write a Uint16 into the buffer. |
80 | void putUint16(int value, {Endian? endian}) { |
81 | assert(!_isDone); |
82 | _eightBytes.setUint16(0, value, endian ?? Endian.host); |
83 | _addAll(_eightBytesAsList, 0, 2); |
84 | } |
85 | |
86 | /// Write a Uint32 into the buffer. |
87 | void putUint32(int value, {Endian? endian}) { |
88 | assert(!_isDone); |
89 | _eightBytes.setUint32(0, value, endian ?? Endian.host); |
90 | _addAll(_eightBytesAsList, 0, 4); |
91 | } |
92 | |
93 | /// Write an Int32 into the buffer. |
94 | void putInt32(int value, {Endian? endian}) { |
95 | assert(!_isDone); |
96 | _eightBytes.setInt32(0, value, endian ?? Endian.host); |
97 | _addAll(_eightBytesAsList, 0, 4); |
98 | } |
99 | |
100 | /// Write an Int64 into the buffer. |
101 | void putInt64(int value, {Endian? endian}) { |
102 | assert(!_isDone); |
103 | _eightBytes.setInt64(0, value, endian ?? Endian.host); |
104 | _addAll(_eightBytesAsList, 0, 8); |
105 | } |
106 | |
107 | /// Write an Float64 into the buffer. |
108 | void putFloat64(double value, {Endian? endian}) { |
109 | assert(!_isDone); |
110 | _alignTo(8); |
111 | _eightBytes.setFloat64(0, value, endian ?? Endian.host); |
112 | _addAll(_eightBytesAsList); |
113 | } |
114 | |
115 | /// Write all the values from a [Uint8List] into the buffer. |
116 | void putUint8List(Uint8List list) { |
117 | assert(!_isDone); |
118 | _append(list); |
119 | } |
120 | |
121 | /// Write all the values from an [Int32List] into the buffer. |
122 | void putInt32List(Int32List list) { |
123 | assert(!_isDone); |
124 | _alignTo(4); |
125 | _append(list.buffer.asUint8List(list.offsetInBytes, 4 * list.length)); |
126 | } |
127 | |
128 | /// Write all the values from an [Int64List] into the buffer. |
129 | void putInt64List(Int64List list) { |
130 | assert(!_isDone); |
131 | _alignTo(8); |
132 | _append(list.buffer.asUint8List(list.offsetInBytes, 8 * list.length)); |
133 | } |
134 | |
135 | /// Write all the values from a [Float32List] into the buffer. |
136 | void putFloat32List(Float32List list) { |
137 | assert(!_isDone); |
138 | _alignTo(4); |
139 | _append(list.buffer.asUint8List(list.offsetInBytes, 4 * list.length)); |
140 | } |
141 | |
142 | /// Write all the values from a [Float64List] into the buffer. |
143 | void putFloat64List(Float64List list) { |
144 | assert(!_isDone); |
145 | _alignTo(8); |
146 | _append(list.buffer.asUint8List(list.offsetInBytes, 8 * list.length)); |
147 | } |
148 | |
149 | void _alignTo(int alignment) { |
150 | assert(!_isDone); |
151 | final int mod = _currentSize % alignment; |
152 | if (mod != 0) { |
153 | _addAll(_zeroBuffer, 0, alignment - mod); |
154 | } |
155 | } |
156 | |
157 | /// Finalize and return the written [ByteData]. |
158 | ByteData done() { |
159 | if (_isDone) { |
160 | throw StateError('done() must not be called more than once on the same$runtimeType .'); |
161 | } |
162 | final ByteData result = _buffer.buffer.asByteData(0, _currentSize); |
163 | _buffer = Uint8List(0); |
164 | _isDone = true; |
165 | return result; |
166 | } |
167 | } |
168 | |
169 | /// Read-only buffer for reading sequentially from a [ByteData] instance. |
170 | /// |
171 | /// The byte order used is [Endian.host] throughout. |
172 | class ReadBuffer { |
173 | /// Creates a [ReadBuffer] for reading from the specified [data]. |
174 | ReadBuffer(this.data); |
175 | |
176 | /// The underlying data being read. |
177 | final ByteData data; |
178 | |
179 | /// The position to read next. |
180 | int _position = 0; |
181 | |
182 | /// Whether the buffer has data remaining to read. |
183 | bool get hasRemaining => _position < data.lengthInBytes; |
184 | |
185 | /// Reads a Uint8 from the buffer. |
186 | int getUint8() { |
187 | return data.getUint8(_position++); |
188 | } |
189 | |
190 | /// Reads a Uint16 from the buffer. |
191 | int getUint16({Endian? endian}) { |
192 | final int value = data.getUint16(_position, endian ?? Endian.host); |
193 | _position += 2; |
194 | return value; |
195 | } |
196 | |
197 | /// Reads a Uint32 from the buffer. |
198 | int getUint32({Endian? endian}) { |
199 | final int value = data.getUint32(_position, endian ?? Endian.host); |
200 | _position += 4; |
201 | return value; |
202 | } |
203 | |
204 | /// Reads an Int32 from the buffer. |
205 | int getInt32({Endian? endian}) { |
206 | final int value = data.getInt32(_position, endian ?? Endian.host); |
207 | _position += 4; |
208 | return value; |
209 | } |
210 | |
211 | /// Reads an Int64 from the buffer. |
212 | int getInt64({Endian? endian}) { |
213 | final int value = data.getInt64(_position, endian ?? Endian.host); |
214 | _position += 8; |
215 | return value; |
216 | } |
217 | |
218 | /// Reads a Float64 from the buffer. |
219 | double getFloat64({Endian? endian}) { |
220 | _alignTo(8); |
221 | final double value = data.getFloat64(_position, endian ?? Endian.host); |
222 | _position += 8; |
223 | return value; |
224 | } |
225 | |
226 | /// Reads the given number of Uint8s from the buffer. |
227 | Uint8List getUint8List(int length) { |
228 | final Uint8List list = data.buffer.asUint8List(data.offsetInBytes + _position, length); |
229 | _position += length; |
230 | return list; |
231 | } |
232 | |
233 | /// Reads the given number of Int32s from the buffer. |
234 | Int32List getInt32List(int length) { |
235 | _alignTo(4); |
236 | final Int32List list = data.buffer.asInt32List(data.offsetInBytes + _position, length); |
237 | _position += 4 * length; |
238 | return list; |
239 | } |
240 | |
241 | /// Reads the given number of Int64s from the buffer. |
242 | Int64List getInt64List(int length) { |
243 | _alignTo(8); |
244 | final Int64List list = data.buffer.asInt64List(data.offsetInBytes + _position, length); |
245 | _position += 8 * length; |
246 | return list; |
247 | } |
248 | |
249 | /// Reads the given number of Float32s from the buffer |
250 | Float32List getFloat32List(int length) { |
251 | _alignTo(4); |
252 | final Float32List list = data.buffer.asFloat32List(data.offsetInBytes + _position, length); |
253 | _position += 4 * length; |
254 | return list; |
255 | } |
256 | |
257 | /// Reads the given number of Float64s from the buffer. |
258 | Float64List getFloat64List(int length) { |
259 | _alignTo(8); |
260 | final Float64List list = data.buffer.asFloat64List(data.offsetInBytes + _position, length); |
261 | _position += 8 * length; |
262 | return list; |
263 | } |
264 | |
265 | void _alignTo(int alignment) { |
266 | final int mod = _position % alignment; |
267 | if (mod != 0) { |
268 | _position += alignment - mod; |
269 | } |
270 | } |
271 | } |
272 |
Definitions
- WriteBuffer
- WriteBuffer
- _
- _add
- _append
- _addAll
- _resize
- putUint8
- putUint16
- putUint32
- putInt32
- putInt64
- putFloat64
- putUint8List
- putInt32List
- putInt64List
- putFloat32List
- putFloat64List
- _alignTo
- done
- ReadBuffer
- ReadBuffer
- hasRemaining
- getUint8
- getUint16
- getUint32
- getInt32
- getInt64
- getFloat64
- getUint8List
- getInt32List
- getInt64List
- getFloat32List
- getFloat64List
Learn more about Flutter for embedded and desktop on industrialflutter.com