serialization.dart 5.62 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 12 13
// 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.
///
14
/// The byte order used is [Endian.host] throughout.
15
class WriteBuffer {
16
  /// Creates an interface for incrementally building a [ByteData] instance.
17
  WriteBuffer() {
18 19
    _buffer = Uint8Buffer();
    _eightBytes = ByteData(8);
20 21 22
    _eightBytesAsList = _eightBytes.buffer.asUint8List();
  }

23 24 25 26
  Uint8Buffer _buffer;
  ByteData _eightBytes;
  Uint8List _eightBytesAsList;

27
  /// Write a Uint8 into the buffer.
28 29 30 31
  void putUint8(int byte) {
    _buffer.add(byte);
  }

32
  /// Write a Uint16 into the buffer.
33 34
  void putUint16(int value, {Endian endian}) {
    _eightBytes.setUint16(0, value, endian ?? Endian.host);
35 36 37
    _buffer.addAll(_eightBytesAsList, 0, 2);
  }

38
  /// Write a Uint32 into the buffer.
39 40
  void putUint32(int value, {Endian endian}) {
    _eightBytes.setUint32(0, value, endian ?? Endian.host);
41 42 43
    _buffer.addAll(_eightBytesAsList, 0, 4);
  }

44
  /// Write an Int32 into the buffer.
45 46
  void putInt32(int value, {Endian endian}) {
    _eightBytes.setInt32(0, value, endian ?? Endian.host);
47
    _buffer.addAll(_eightBytesAsList, 0, 4);
48 49
  }

50
  /// Write an Int64 into the buffer.
51 52
  void putInt64(int value, {Endian endian}) {
    _eightBytes.setInt64(0, value, endian ?? Endian.host);
53
    _buffer.addAll(_eightBytesAsList, 0, 8);
54 55
  }

56
  /// Write an Float64 into the buffer.
57
  void putFloat64(double value, {Endian endian}) {
58
    _alignTo(8);
59
    _eightBytes.setFloat64(0, value, endian ?? Endian.host);
60 61 62
    _buffer.addAll(_eightBytesAsList);
  }

63
  /// Write all the values from a [Uint8List] into the buffer.
64 65 66 67
  void putUint8List(Uint8List list) {
    _buffer.addAll(list);
  }

68
  /// Write all the values from an [Int32List] into the buffer.
69 70
  void putInt32List(Int32List list) {
    _alignTo(4);
71
    _buffer.addAll(list.buffer.asUint8List(list.offsetInBytes, 4 * list.length));
72 73
  }

74
  /// Write all the values from an [Int64List] into the buffer.
75 76
  void putInt64List(Int64List list) {
    _alignTo(8);
77
    _buffer.addAll(list.buffer.asUint8List(list.offsetInBytes, 8 * list.length));
78 79
  }

80
  /// Write all the values from a [Float64List] into the buffer.
81 82
  void putFloat64List(Float64List list) {
    _alignTo(8);
83
    _buffer.addAll(list.buffer.asUint8List(list.offsetInBytes, 8 * list.length));
84 85 86 87 88
  }

  void _alignTo(int alignment) {
    final int mod = _buffer.length % alignment;
    if (mod != 0) {
89
      for (int i = 0; i < alignment - mod; i++)
90 91 92 93
        _buffer.add(0);
    }
  }

94
  /// Finalize and return the written [ByteData].
95 96 97 98 99 100 101 102 103
  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.
///
104
/// The byte order used is [Endian.host] throughout.
105 106
class ReadBuffer {
  /// Creates a [ReadBuffer] for reading from the specified [data].
107 108
  ReadBuffer(this.data)
    : assert(data != null);
109

110 111 112 113 114 115 116 117 118 119
  /// 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.
120
  int getUint8() {
121
    return data.getUint8(_position++);
122 123
  }

124
  /// Reads a Uint16 from the buffer.
125 126
  int getUint16({Endian endian}) {
    final int value = data.getUint16(_position, endian ?? Endian.host);
127
    _position += 2;
128 129 130
    return value;
  }

131
  /// Reads a Uint32 from the buffer.
132 133
  int getUint32({Endian endian}) {
    final int value = data.getUint32(_position, endian ?? Endian.host);
134
    _position += 4;
135 136 137
    return value;
  }

138
  /// Reads an Int32 from the buffer.
139 140
  int getInt32({Endian endian}) {
    final int value = data.getInt32(_position, endian ?? Endian.host);
141
    _position += 4;
142 143 144
    return value;
  }

145
  /// Reads an Int64 from the buffer.
146 147
  int getInt64({Endian endian}) {
    final int value = data.getInt64(_position, endian ?? Endian.host);
148
    _position += 8;
149 150 151
    return value;
  }

152
  /// Reads a Float64 from the buffer.
153
  double getFloat64({Endian endian}) {
154
    _alignTo(8);
155
    final double value = data.getFloat64(_position, endian ?? Endian.host);
156
    _position += 8;
157 158 159
    return value;
  }

160
  /// Reads the given number of Uint8s from the buffer.
161
  Uint8List getUint8List(int length) {
162 163
    final Uint8List list = data.buffer.asUint8List(data.offsetInBytes + _position, length);
    _position += length;
164 165 166
    return list;
  }

167
  /// Reads the given number of Int32s from the buffer.
168 169
  Int32List getInt32List(int length) {
    _alignTo(4);
170 171
    final Int32List list = data.buffer.asInt32List(data.offsetInBytes + _position, length);
    _position += 4 * length;
172 173 174
    return list;
  }

175
  /// Reads the given number of Int64s from the buffer.
176 177
  Int64List getInt64List(int length) {
    _alignTo(8);
178 179
    final Int64List list = data.buffer.asInt64List(data.offsetInBytes + _position, length);
    _position += 8 * length;
180 181 182
    return list;
  }

183
  /// Reads the given number of Float64s from the buffer.
184 185
  Float64List getFloat64List(int length) {
    _alignTo(8);
186 187
    final Float64List list = data.buffer.asFloat64List(data.offsetInBytes + _position, length);
    _position += 8 * length;
188 189 190 191
    return list;
  }

  void _alignTo(int alignment) {
192
    final int mod = _position % alignment;
193
    if (mod != 0)
194
      _position += alignment - mod;
195 196
  }
}