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
5import 'dart:math' as math;
6import 'dart:typed_data';
7
8export '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.
17class 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.
172class 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

Provided by KDAB

Privacy Policy
Learn more about Flutter for embedded and desktop on industrialflutter.com