1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:typed_data';
import 'package:typed_data/typed_buffers.dart' show Uint8Buffer;
/// Write-only buffer for incrementally building a [ByteData] instance.
///
/// A WriteBuffer instance can be used only once. Attempts to reuse will result
/// in [NoSuchMethodError]s being thrown.
///
/// The byte order used is [Endian.host] throughout.
class WriteBuffer {
/// Creates an interface for incrementally building a [ByteData] instance.
WriteBuffer() {
_buffer = Uint8Buffer();
_eightBytes = ByteData(8);
_eightBytesAsList = _eightBytes.buffer.asUint8List();
}
Uint8Buffer _buffer;
ByteData _eightBytes;
Uint8List _eightBytesAsList;
/// Write a Uint8 into the buffer.
void putUint8(int byte) {
_buffer.add(byte);
}
/// Write a Uint16 into the buffer.
void putUint16(int value) {
_eightBytes.setUint16(0, value, Endian.host);
_buffer.addAll(_eightBytesAsList, 0, 2);
}
/// Write a Uint32 into the buffer.
void putUint32(int value) {
_eightBytes.setUint32(0, value, Endian.host);
_buffer.addAll(_eightBytesAsList, 0, 4);
}
/// Write an Int32 into the buffer.
void putInt32(int value) {
_eightBytes.setInt32(0, value, Endian.host);
_buffer.addAll(_eightBytesAsList, 0, 4);
}
/// Write an Int64 into the buffer.
void putInt64(int value) {
_eightBytes.setInt64(0, value, Endian.host);
_buffer.addAll(_eightBytesAsList, 0, 8);
}
/// Write an Float64 into the buffer.
void putFloat64(double value) {
_alignTo(8);
_eightBytes.setFloat64(0, value, Endian.host);
_buffer.addAll(_eightBytesAsList);
}
/// Write all the values from a [Uint8List] into the buffer.
void putUint8List(Uint8List list) {
_buffer.addAll(list);
}
/// Write all the values from an [Int32List] into the buffer.
void putInt32List(Int32List list) {
_alignTo(4);
_buffer.addAll(list.buffer.asUint8List(list.offsetInBytes, 4 * list.length));
}
/// Write all the values from an [Int64List] into the buffer.
void putInt64List(Int64List list) {
_alignTo(8);
_buffer.addAll(list.buffer.asUint8List(list.offsetInBytes, 8 * list.length));
}
/// Write all the values from a [Float64List] into the buffer.
void putFloat64List(Float64List list) {
_alignTo(8);
_buffer.addAll(list.buffer.asUint8List(list.offsetInBytes, 8 * list.length));
}
void _alignTo(int alignment) {
final int mod = _buffer.length % alignment;
if (mod != 0) {
for (int i = 0; i < alignment - mod; i++)
_buffer.add(0);
}
}
/// Finalize and return the written [ByteData].
ByteData done() {
final ByteData result = _buffer.buffer.asByteData(0, _buffer.lengthInBytes);
_buffer = null;
return result;
}
}
/// Read-only buffer for reading sequentially from a [ByteData] instance.
///
/// The byte order used is [Endian.host] throughout.
class ReadBuffer {
/// Creates a [ReadBuffer] for reading from the specified [data].
ReadBuffer(this.data)
: assert(data != null);
/// The underlying data being read.
final ByteData data;
/// The position to read next.
int _position = 0;
/// Whether the buffer has data remaining to read.
bool get hasRemaining => _position < data.lengthInBytes;
/// Reads a Uint8 from the buffer.
int getUint8() {
return data.getUint8(_position++);
}
/// Reads a Uint16 from the buffer.
int getUint16() {
final int value = data.getUint16(_position, Endian.host);
_position += 2;
return value;
}
/// Reads a Uint32 from the buffer.
int getUint32() {
final int value = data.getUint32(_position, Endian.host);
_position += 4;
return value;
}
/// Reads an Int32 from the buffer.
int getInt32() {
final int value = data.getInt32(_position, Endian.host);
_position += 4;
return value;
}
/// Reads an Int64 from the buffer.
int getInt64() {
final int value = data.getInt64(_position, Endian.host);
_position += 8;
return value;
}
/// Reads a Float64 from the buffer.
double getFloat64() {
_alignTo(8);
final double value = data.getFloat64(_position, Endian.host);
_position += 8;
return value;
}
/// Reads the given number of Uint8s from the buffer.
Uint8List getUint8List(int length) {
final Uint8List list = data.buffer.asUint8List(data.offsetInBytes + _position, length);
_position += length;
return list;
}
/// Reads the given number of Int32s from the buffer.
Int32List getInt32List(int length) {
_alignTo(4);
final Int32List list = data.buffer.asInt32List(data.offsetInBytes + _position, length);
_position += 4 * length;
return list;
}
/// Reads the given number of Int64s from the buffer.
Int64List getInt64List(int length) {
_alignTo(8);
final Int64List list = data.buffer.asInt64List(data.offsetInBytes + _position, length);
_position += 8 * length;
return list;
}
/// Reads the given number of Float64s from the buffer.
Float64List getFloat64List(int length) {
_alignTo(8);
final Float64List list = data.buffer.asFloat64List(data.offsetInBytes + _position, length);
_position += 8 * length;
return list;
}
void _alignTo(int alignment) {
final int mod = _position % alignment;
if (mod != 0)
_position += alignment - mod;
}
}