serialization.dart 6.61 KB
Newer Older
Ian Hickson's avatar
Ian Hickson committed
1
// Copyright 2014 The Flutter Authors. All rights reserved.
2 3 4 5 6 7 8 9 10 11
// 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
12
/// in [StateError]s being thrown.
13
///
14
/// The byte order used is [Endian.host] throughout.
15
class WriteBuffer {
16
  /// Creates an interface for incrementally building a [ByteData] instance.
17 18
  WriteBuffer()
    : _buffer = Uint8Buffer(),
19
      _isDone = false,
20
      _eightBytes = ByteData(8) {
21 22 23
    _eightBytesAsList = _eightBytes.buffer.asUint8List();
  }

24 25
  Uint8Buffer _buffer;
  bool _isDone;
26 27
  final ByteData _eightBytes;
  late Uint8List _eightBytesAsList;
28
  static final Uint8List _zeroBuffer = Uint8List.fromList(<int>[0, 0, 0, 0, 0, 0, 0, 0]);
29

30
  /// Write a Uint8 into the buffer.
31
  void putUint8(int byte) {
32 33
    assert(!_isDone);
    _buffer.add(byte);
34 35
  }

36
  /// Write a Uint16 into the buffer.
37
  void putUint16(int value, {Endian? endian}) {
38
    assert(!_isDone);
39
    _eightBytes.setUint16(0, value, endian ?? Endian.host);
40
    _buffer.addAll(_eightBytesAsList, 0, 2);
41 42
  }

43
  /// Write a Uint32 into the buffer.
44
  void putUint32(int value, {Endian? endian}) {
45
    assert(!_isDone);
46
    _eightBytes.setUint32(0, value, endian ?? Endian.host);
47
    _buffer.addAll(_eightBytesAsList, 0, 4);
48 49
  }

50
  /// Write an Int32 into the buffer.
51
  void putInt32(int value, {Endian? endian}) {
52
    assert(!_isDone);
53
    _eightBytes.setInt32(0, value, endian ?? Endian.host);
54
    _buffer.addAll(_eightBytesAsList, 0, 4);
55 56
  }

57
  /// Write an Int64 into the buffer.
58
  void putInt64(int value, {Endian? endian}) {
59
    assert(!_isDone);
60
    _eightBytes.setInt64(0, value, endian ?? Endian.host);
61
    _buffer.addAll(_eightBytesAsList, 0, 8);
62 63
  }

64
  /// Write an Float64 into the buffer.
65
  void putFloat64(double value, {Endian? endian}) {
66
    assert(!_isDone);
67
    _alignTo(8);
68
    _eightBytes.setFloat64(0, value, endian ?? Endian.host);
69
    _buffer.addAll(_eightBytesAsList);
70 71
  }

72
  /// Write all the values from a [Uint8List] into the buffer.
73
  void putUint8List(Uint8List list) {
74 75
    assert(!_isDone);
    _buffer.addAll(list);
76 77
  }

78
  /// Write all the values from an [Int32List] into the buffer.
79
  void putInt32List(Int32List list) {
80
    assert(!_isDone);
81
    _alignTo(4);
82
    _buffer.addAll(list.buffer.asUint8List(list.offsetInBytes, 4 * list.length));
83 84
  }

85
  /// Write all the values from an [Int64List] into the buffer.
86
  void putInt64List(Int64List list) {
87
    assert(!_isDone);
88
    _alignTo(8);
89
    _buffer.addAll(list.buffer.asUint8List(list.offsetInBytes, 8 * list.length));
90 91
  }

92 93 94 95 96 97 98
  /// Write all the values from a [Float32List] into the buffer.
  void putFloat32List(Float32List list) {
    assert(!_isDone);
    _alignTo(4);
    _buffer.addAll(list.buffer.asUint8List(list.offsetInBytes, 4 * list.length));
  }

99
  /// Write all the values from a [Float64List] into the buffer.
100
  void putFloat64List(Float64List list) {
101
    assert(!_isDone);
102
    _alignTo(8);
103
    _buffer.addAll(list.buffer.asUint8List(list.offsetInBytes, 8 * list.length));
104 105 106
  }

  void _alignTo(int alignment) {
107 108
    assert(!_isDone);
    final int mod = _buffer.length % alignment;
109
    if (mod != 0) {
110
      _buffer.addAll(_zeroBuffer, 0, alignment - mod);
111 112 113
    }
  }

114
  /// Finalize and return the written [ByteData].
115
  ByteData done() {
116 117 118 119 120 121
    if (_isDone) {
      throw StateError('done() must not be called more than once on the same $runtimeType.');
    }
    final ByteData result = _buffer.buffer.asByteData(0, _buffer.lengthInBytes);
    _buffer = Uint8Buffer();
    _isDone = true;
122 123 124 125 126 127
    return result;
  }
}

/// Read-only buffer for reading sequentially from a [ByteData] instance.
///
128
/// The byte order used is [Endian.host] throughout.
129 130
class ReadBuffer {
  /// Creates a [ReadBuffer] for reading from the specified [data].
131 132
  ReadBuffer(this.data)
    : assert(data != null);
133

134 135 136 137 138 139 140 141 142 143
  /// 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.
144
  int getUint8() {
145
    return data.getUint8(_position++);
146 147
  }

148
  /// Reads a Uint16 from the buffer.
149
  int getUint16({Endian? endian}) {
150
    final int value = data.getUint16(_position, endian ?? Endian.host);
151
    _position += 2;
152 153 154
    return value;
  }

155
  /// Reads a Uint32 from the buffer.
156
  int getUint32({Endian? endian}) {
157
    final int value = data.getUint32(_position, endian ?? Endian.host);
158
    _position += 4;
159 160 161
    return value;
  }

162
  /// Reads an Int32 from the buffer.
163
  int getInt32({Endian? endian}) {
164
    final int value = data.getInt32(_position, endian ?? Endian.host);
165
    _position += 4;
166 167 168
    return value;
  }

169
  /// Reads an Int64 from the buffer.
170
  int getInt64({Endian? endian}) {
171
    final int value = data.getInt64(_position, endian ?? Endian.host);
172
    _position += 8;
173 174 175
    return value;
  }

176
  /// Reads a Float64 from the buffer.
177
  double getFloat64({Endian? endian}) {
178
    _alignTo(8);
179
    final double value = data.getFloat64(_position, endian ?? Endian.host);
180
    _position += 8;
181 182 183
    return value;
  }

184
  /// Reads the given number of Uint8s from the buffer.
185
  Uint8List getUint8List(int length) {
186 187
    final Uint8List list = data.buffer.asUint8List(data.offsetInBytes + _position, length);
    _position += length;
188 189 190
    return list;
  }

191
  /// Reads the given number of Int32s from the buffer.
192 193
  Int32List getInt32List(int length) {
    _alignTo(4);
194 195
    final Int32List list = data.buffer.asInt32List(data.offsetInBytes + _position, length);
    _position += 4 * length;
196 197 198
    return list;
  }

199
  /// Reads the given number of Int64s from the buffer.
200 201
  Int64List getInt64List(int length) {
    _alignTo(8);
202 203
    final Int64List list = data.buffer.asInt64List(data.offsetInBytes + _position, length);
    _position += 8 * length;
204 205 206
    return list;
  }

207 208 209 210 211 212 213 214
  /// Reads the given number of Float32s from the buffer
  Float32List getFloat32List(int length) {
    _alignTo(4);
    final Float32List list = data.buffer.asFloat32List(data.offsetInBytes + _position, length);
    _position += 4 * length;
    return list;
  }

215
  /// Reads the given number of Float64s from the buffer.
216 217
  Float64List getFloat64List(int length) {
    _alignTo(8);
218 219
    final Float64List list = data.buffer.asFloat64List(data.offsetInBytes + _position, length);
    _position += 8 * length;
220 221 222 223
    return list;
  }

  void _alignTo(int alignment) {
224
    final int mod = _position % alignment;
225
    if (mod != 0)
226
      _position += alignment - mod;
227 228
  }
}