Home | History | Annotate | Download | only in lib
      1 // Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
      2 // for details. All rights reserved. Use of this source code is governed by a
      3 // BSD-style license that can be found in the LICENSE file.
      4 
      5 import 'dart:collection';
      6 import 'dart:convert';
      7 import 'dart:math';
      8 import 'dart:typed_data';
      9 
     10 const int _sizeofUint8 = 1;
     11 const int _sizeofUint16 = 2;
     12 const int _sizeofUint32 = 4;
     13 const int _sizeofUint64 = 8;
     14 const int _sizeofInt8 = 1;
     15 const int _sizeofInt16 = 2;
     16 const int _sizeofInt32 = 4;
     17 const int _sizeofInt64 = 8;
     18 const int _sizeofFloat32 = 4;
     19 const int _sizeofFloat64 = 8;
     20 
     21 /// Callback used to invoke a struct builder's finish method.
     22 ///
     23 /// This callback is used by other struct's `finish` methods to write the nested
     24 /// struct's fields inline.
     25 typedef void StructBuilder();
     26 
     27 /// Buffer with data and some context about it.
     28 class BufferContext {
     29   final ByteData _buffer;
     30 
     31   factory BufferContext.fromBytes(List<int> byteList) {
     32     Uint8List uint8List = _asUint8List(byteList);
     33     ByteData buf = new ByteData.view(uint8List.buffer, uint8List.offsetInBytes);
     34     return new BufferContext._(buf);
     35   }
     36 
     37   BufferContext._(this._buffer);
     38 
     39   int derefObject(int offset) {
     40     return offset + _getUint32(offset);
     41   }
     42 
     43   Uint8List _asUint8LIst(int offset, int length) =>
     44       _buffer.buffer.asUint8List(_buffer.offsetInBytes + offset, length);
     45 
     46   double _getFloat64(int offset) =>
     47       _buffer.getFloat64(offset, Endian.little);
     48 
     49   double _getFloat32(int offset) =>
     50       _buffer.getFloat32(offset, Endian.little);
     51 
     52   int _getInt64(int offset) =>
     53       _buffer.getInt64(offset, Endian.little);
     54 
     55   int _getInt32(int offset) =>
     56       _buffer.getInt32(offset, Endian.little);
     57 
     58   int _getInt16(int offset) =>
     59       _buffer.getInt16(offset, Endian.little);
     60 
     61   int _getInt8(int offset) => _buffer.getInt8(offset);
     62 
     63   int _getUint64(int offset) =>
     64       _buffer.getUint64(offset, Endian.little);
     65 
     66   int _getUint32(int offset) =>
     67       _buffer.getUint32(offset, Endian.little);
     68 
     69   int _getUint16(int offset) =>
     70       _buffer.getUint16(offset, Endian.little);
     71 
     72   int _getUint8(int offset) => _buffer.getUint8(offset);
     73 
     74   /// If the [byteList] is already a [Uint8List] return it.
     75   /// Otherwise return a [Uint8List] copy of the [byteList].
     76   static Uint8List _asUint8List(List<int> byteList) {
     77     if (byteList is Uint8List) {
     78       return byteList;
     79     } else {
     80       return new Uint8List.fromList(byteList);
     81     }
     82   }
     83 }
     84 
     85 /// Class implemented by typed builders generated by flatc.
     86 abstract class ObjectBuilder {
     87   int _firstOffset;
     88 
     89   /// Can be used to write the data represented by this builder to the [Builder]
     90   /// and reuse the offset created in multiple tables.
     91   ///
     92   /// Note that this method assumes you call it using the same [Builder] instance
     93   /// every time. The returned offset is only good for the [Builder] used in the
     94   /// first call to this method.
     95   int getOrCreateOffset(Builder fbBuilder) {
     96     _firstOffset ??= finish(fbBuilder);
     97     return _firstOffset;
     98   }
     99 
    100   /// Writes the data in this helper to the [Builder].
    101   int finish(Builder fbBuilder);
    102 
    103   /// Convenience method that will create a new [Builder], [finish]es the data,
    104   /// and returns the buffer as a [Uint8List] of bytes.
    105   Uint8List toBytes();
    106 }
    107 
    108 /// Class that helps building flat buffers.
    109 class Builder {
    110   final int initialSize;
    111 
    112   /// The list of existing VTable(s).
    113   //final List<_VTable> _vTables = <_VTable>[];
    114   final List<int> _vTables = <int>[];
    115 
    116   ByteData _buf;
    117 
    118   /// The maximum alignment that has been seen so far.  If [_buf] has to be
    119   /// reallocated in the future (to insert room at its start for more bytes) the
    120   /// reallocation will need to be a multiple of this many bytes.
    121   int _maxAlign;
    122 
    123   /// The number of bytes that have been written to the buffer so far.  The
    124   /// most recently written byte is this many bytes from the end of [_buf].
    125   int _tail;
    126 
    127   /// The location of the end of the current table, measured in bytes from the
    128   /// end of [_buf], or `null` if a table is not currently being built.
    129   int _currentTableEndTail;
    130 
    131   _VTable _currentVTable;
    132 
    133   /// Map containing all strings that have been written so far.  This allows us
    134   /// to avoid duplicating strings.
    135   ///
    136   /// Allocated only if `internStrings` is set to true on the constructor.
    137   Map<String, int> _strings;
    138 
    139   /// Creates a new FlatBuffers Builder.
    140   ///
    141   /// `initialSize` is the initial array size in bytes.  The [Builder] will
    142   /// automatically grow the array if/as needed.  `internStrings`, if set to
    143   /// true, will cause [writeString] to pool strings in the buffer so that
    144   /// identical strings will always use the same offset in tables.
    145   Builder({this.initialSize: 1024, bool internStrings = false}) {
    146     if (internStrings == true) {
    147       _strings = new Map<String, int>();
    148     }
    149     reset();
    150   }
    151 
    152   /// Add the [field] with the given boolean [value].  The field is not added if
    153   /// the [value] is equal to [def].  Booleans are stored as 8-bit fields with
    154   /// `0` for `false` and `1` for `true`.
    155   void addBool(int field, bool value, [bool def]) {
    156     _ensureCurrentVTable();
    157     if (value != null && value != def) {
    158       _prepare(_sizeofUint8, 1);
    159       _trackField(field);
    160       _buf.setInt8(_buf.lengthInBytes - _tail, value ? 1 : 0);
    161     }
    162   }
    163 
    164   /// Add the [field] with the given 32-bit signed integer [value].  The field is
    165   /// not added if the [value] is equal to [def].
    166   void addInt32(int field, int value, [int def]) {
    167     _ensureCurrentVTable();
    168     if (value != null && value != def) {
    169       _prepare(_sizeofInt32, 1);
    170       _trackField(field);
    171       _setInt32AtTail(_buf, _tail, value);
    172     }
    173   }
    174 
    175   /// Add the [field] with the given 32-bit signed integer [value].  The field is
    176   /// not added if the [value] is equal to [def].
    177   void addInt16(int field, int value, [int def]) {
    178     _ensureCurrentVTable();
    179     if (value != null && value != def) {
    180       _prepare(_sizeofInt16, 1);
    181       _trackField(field);
    182       _setInt16AtTail(_buf, _tail, value);
    183     }
    184   }
    185 
    186   /// Add the [field] with the given 8-bit signed integer [value].  The field is
    187   /// not added if the [value] is equal to [def].
    188   void addInt8(int field, int value, [int def]) {
    189     _ensureCurrentVTable();
    190     if (value != null && value != def) {
    191       _prepare(_sizeofInt8, 1);
    192       _trackField(field);
    193       _setInt8AtTail(_buf, _tail, value);
    194     }
    195   }
    196 
    197   void addStruct(int field, int offset) {
    198     _ensureCurrentVTable();
    199     _trackField(field);
    200     _currentVTable.addField(field, offset);
    201   }
    202 
    203   /// Add the [field] referencing an object with the given [offset].
    204   void addOffset(int field, int offset) {
    205     _ensureCurrentVTable();
    206     if (offset != null) {
    207       _prepare(_sizeofUint32, 1);
    208       _trackField(field);
    209       _setUint32AtTail(_buf, _tail, _tail - offset);
    210     }
    211   }
    212 
    213   /// Add the [field] with the given 32-bit unsigned integer [value].  The field
    214   /// is not added if the [value] is equal to [def].
    215   void addUint32(int field, int value, [int def]) {
    216     _ensureCurrentVTable();
    217     if (value != null && value != def) {
    218       _prepare(_sizeofUint32, 1);
    219       _trackField(field);
    220       _setUint32AtTail(_buf, _tail, value);
    221     }
    222   }
    223 
    224   /// Add the [field] with the given 32-bit unsigned integer [value].  The field
    225   /// is not added if the [value] is equal to [def].
    226   void addUint16(int field, int value, [int def]) {
    227     _ensureCurrentVTable();
    228     if (value != null && value != def) {
    229       _prepare(_sizeofUint16, 1);
    230       _trackField(field);
    231       _setUint16AtTail(_buf, _tail, value);
    232     }
    233   }
    234 
    235   /// Add the [field] with the given 8-bit unsigned integer [value].  The field
    236   /// is not added if the [value] is equal to [def].
    237   void addUint8(int field, int value, [int def]) {
    238     _ensureCurrentVTable();
    239     if (value != null && value != def) {
    240       _prepare(_sizeofUint8, 1);
    241       _trackField(field);
    242       _setUint8AtTail(_buf, _tail, value);
    243     }
    244   }
    245 
    246   /// Add the [field] with the given 32-bit float [value].  The field
    247   /// is not added if the [value] is equal to [def].
    248   void addFloat32(int field, double value, [double def]) {
    249     _ensureCurrentVTable();
    250     if (value != null && value != def) {
    251       _prepare(_sizeofFloat32, 1);
    252       _trackField(field);
    253       _setFloat32AtTail(_buf, _tail, value);
    254     }
    255   }
    256 
    257   /// Add the [field] with the given 64-bit double [value].  The field
    258   /// is not added if the [value] is equal to [def].
    259   void addFloat64(int field, double value, [double def]) {
    260     _ensureCurrentVTable();
    261     if (value != null && value != def) {
    262       _prepare(_sizeofFloat64, 1);
    263       _trackField(field);
    264       _setFloat64AtTail(_buf, _tail, value);
    265     }
    266   }
    267 
    268   /// Add the [field] with the given 64-bit unsigned integer [value].  The field
    269   /// is not added if the [value] is equal to [def].
    270   void addUint64(int field, int value, [double def]) {
    271     _ensureCurrentVTable();
    272     if (value != null && value != def) {
    273       _prepare(_sizeofUint64, 1);
    274       _trackField(field);
    275       _setUint64AtTail(_buf, _tail, value);
    276     }
    277   }
    278 
    279   /// Add the [field] with the given 64-bit unsigned integer [value].  The field
    280   /// is not added if the [value] is equal to [def].
    281   void addInt64(int field, int value, [double def]) {
    282     _ensureCurrentVTable();
    283     if (value != null && value != def) {
    284       _prepare(_sizeofInt64, 1);
    285       _trackField(field);
    286       _setInt64AtTail(_buf, _tail, value);
    287     }
    288   }
    289 
    290   /// End the current table and return its offset.
    291   int endTable() {
    292     if (_currentVTable == null) {
    293       throw new StateError('Start a table before ending it.');
    294     }
    295     // Prepare for writing the VTable.
    296     _prepare(_sizeofInt32, 1);
    297     int tableTail = _tail;
    298     // Prepare the size of the current table.
    299     _currentVTable.tableSize = tableTail - _currentTableEndTail;
    300     // Prepare the VTable to use for the current table.
    301     int vTableTail;
    302     {
    303       _currentVTable.computeFieldOffsets(tableTail);
    304       // Try to find an existing compatible VTable.
    305       // Search backward - more likely to have recently used one
    306       for (int i = _vTables.length - 1; i >= 0; i--) {
    307         final int vt2Offset = _vTables[i];
    308         final int vt2Start = _buf.lengthInBytes - vt2Offset;
    309         final int vt2Size = _buf.getUint16(vt2Start, Endian.little);
    310 
    311         if (_currentVTable._vTableSize == vt2Size &&
    312             _currentVTable._offsetsMatch(vt2Start, _buf)) {
    313           vTableTail = vt2Offset;
    314           break;
    315         }
    316       }
    317       // Write a new VTable.
    318       if (vTableTail == null) {
    319         _prepare(_sizeofUint16, _currentVTable.numOfUint16);
    320         vTableTail = _tail;
    321         _currentVTable.tail = vTableTail;
    322         _currentVTable.output(_buf, _buf.lengthInBytes - _tail);
    323         _vTables.add(_currentVTable.tail);
    324       }
    325     }
    326     // Set the VTable offset.
    327     _setInt32AtTail(_buf, tableTail, vTableTail - tableTail);
    328     // Done with this table.
    329     _currentVTable = null;
    330     return tableTail;
    331   }
    332 
    333   /// This method low level method can be used to return a raw piece of the buffer
    334   /// after using the the put* methods.
    335   ///
    336   /// Most clients should prefer calling [finish].
    337   Uint8List lowFinish() {
    338     int alignedTail = _tail + ((-_tail) % _maxAlign);
    339     return _buf.buffer.asUint8List(_buf.lengthInBytes - alignedTail);
    340   }
    341 
    342   /// Finish off the creation of the buffer.  The given [offset] is used as the
    343   /// root object offset, and usually references directly or indirectly every
    344   /// written object.  If [fileIdentifier] is specified (and not `null`), it is
    345   /// interpreted as a 4-byte Latin-1 encoded string that should be placed at
    346   /// bytes 4-7 of the file.
    347   Uint8List finish(int offset, [String fileIdentifier]) {
    348     _prepare(max(_sizeofUint32, _maxAlign), fileIdentifier == null ? 1 : 2);
    349     int alignedTail = _tail + ((-_tail) % _maxAlign);
    350     _setUint32AtTail(_buf, alignedTail, alignedTail - offset);
    351     if (fileIdentifier != null) {
    352       for (int i = 0; i < 4; i++) {
    353         _setUint8AtTail(_buf, alignedTail - _sizeofUint32 - i,
    354             fileIdentifier.codeUnitAt(i));
    355       }
    356     }
    357     return _buf.buffer.asUint8List(_buf.lengthInBytes - alignedTail);
    358   }
    359 
    360   /// Writes a Float64 to the tail of the buffer after preparing space for it.
    361   ///
    362   /// Updates the [offset] pointer.  This method is intended for use when writing structs to the buffer.
    363   void putFloat64(double value) {
    364     _prepare(_sizeofFloat64, 1);
    365     _setFloat32AtTail(_buf, _tail, value);
    366   }
    367 
    368   /// Writes a Float32 to the tail of the buffer after preparing space for it.
    369   ///
    370   /// Updates the [offset] pointer.  This method is intended for use when writing structs to the buffer.
    371   void putFloat32(double value) {
    372     _prepare(_sizeofFloat32, 1);
    373     _setFloat32AtTail(_buf, _tail, value);
    374   }
    375 
    376   /// Writes a Int64 to the tail of the buffer after preparing space for it.
    377   ///
    378   /// Updates the [offset] pointer.  This method is intended for use when writing structs to the buffer.
    379   void putInt64(int value) {
    380     _prepare(_sizeofInt64, 1);
    381     _setInt64AtTail(_buf, _tail, value);
    382   }
    383 
    384   /// Writes a Uint32 to the tail of the buffer after preparing space for it.
    385   ///
    386   /// Updates the [offset] pointer.  This method is intended for use when writing structs to the buffer.
    387   void putInt32(int value) {
    388     _prepare(_sizeofInt32, 1);
    389     _setInt32AtTail(_buf, _tail, value);
    390   }
    391 
    392   /// Writes a Uint16 to the tail of the buffer after preparing space for it.
    393   ///
    394   /// Updates the [offset] pointer.  This method is intended for use when writing structs to the buffer.
    395   void putInt16(int value) {
    396     _prepare(_sizeofInt16, 1);
    397     _setInt16AtTail(_buf, _tail, value);
    398   }
    399 
    400   /// Writes a Uint8 to the tail of the buffer after preparing space for it.
    401   ///
    402   /// Updates the [offset] pointer.  This method is intended for use when writing structs to the buffer.
    403   void putInt8(int value) {
    404     _prepare(_sizeofInt8, 1);
    405     _buf.setInt8(_buf.lengthInBytes - _tail, value);
    406   }
    407 
    408   /// Writes a Uint64 to the tail of the buffer after preparing space for it.
    409   ///
    410   /// Updates the [offset] pointer.  This method is intended for use when writing structs to the buffer.
    411   void putUint64(int value) {
    412     _prepare(_sizeofUint64, 1);
    413     _setUint64AtTail(_buf, _tail, value);
    414   }
    415 
    416   /// Writes a Uint32 to the tail of the buffer after preparing space for it.
    417   ///
    418   /// Updates the [offset] pointer.  This method is intended for use when writing structs to the buffer.
    419   void putUint32(int value) {
    420     _prepare(_sizeofUint32, 1);
    421     _setUint32AtTail(_buf, _tail, value);
    422   }
    423 
    424   /// Writes a Uint16 to the tail of the buffer after preparing space for it.
    425   ///
    426   /// Updates the [offset] pointer.  This method is intended for use when writing structs to the buffer.
    427   void putUint16(int value) {
    428     _prepare(_sizeofUint16, 1);
    429     _setUint16AtTail(_buf, _tail, value);
    430   }
    431 
    432   /// Writes a Uint8 to the tail of the buffer after preparing space for it.
    433   ///
    434   /// Updates the [offset] pointer.  This method is intended for use when writing structs to the buffer.
    435   void putUint8(int value) {
    436     _prepare(_sizeofUint8, 1);
    437     _buf.setUint8(_buf.lengthInBytes - _tail, value);
    438   }
    439 
    440   /// Reset the builder and make it ready for filling a new buffer.
    441   void reset() {
    442     _buf = new ByteData(initialSize);
    443     _maxAlign = 1;
    444     _tail = 0;
    445     _currentVTable = null;
    446     if (_strings != null) {
    447       _strings = new Map<String, int>();
    448     }
    449   }
    450 
    451   /// Start a new table.  Must be finished with [endTable] invocation.
    452   void startTable() {
    453     if (_currentVTable != null) {
    454       throw new StateError('Inline tables are not supported.');
    455     }
    456     _currentVTable = new _VTable();
    457     _currentTableEndTail = _tail;
    458   }
    459 
    460   /// Finish a Struct vector.  Most callers should preferto use [writeListOfStructs].
    461   ///
    462   /// Most callers should prefer [writeListOfStructs].
    463   int endStructVector(int count) {
    464     putUint32(count);
    465     return _tail;
    466   }
    467 
    468   /// Writes a list of Structs to the buffer, returning the offset
    469   int writeListOfStructs(List<ObjectBuilder> structBuilders) {
    470     _ensureNoVTable();
    471     for (int i = structBuilders.length - 1; i >= 0; i--) {
    472       structBuilders[i].finish(this);
    473     }
    474     return endStructVector(structBuilders.length);
    475   }
    476 
    477   /// Write the given list of [values].
    478   int writeList(List<int> values) {
    479     _ensureNoVTable();
    480     _prepare(_sizeofUint32, 1 + values.length);
    481     final int result = _tail;
    482     int tail = _tail;
    483     _setUint32AtTail(_buf, tail, values.length);
    484     tail -= _sizeofUint32;
    485     for (int value in values) {
    486       _setUint32AtTail(_buf, tail, tail - value);
    487       tail -= _sizeofUint32;
    488     }
    489     return result;
    490   }
    491 
    492   /// Write the given list of 64-bit float [values].
    493   int writeListFloat64(List<double> values) {
    494     _ensureNoVTable();
    495     _prepare(4, 1 + (2 * values.length));
    496     final int result = _tail;
    497     int tail = _tail;
    498     _setUint32AtTail(_buf, tail, values.length);
    499     tail -= _sizeofUint32;
    500     for (double value in values) {
    501       _setFloat64AtTail(_buf, tail, value);
    502       tail -= _sizeofFloat64;
    503     }
    504     return result;
    505   }
    506 
    507   /// Write the given list of 32-bit float [values].
    508   int writeListFloat32(List<double> values) {
    509     _ensureNoVTable();
    510     _prepare(_sizeofFloat32, 1 + values.length);
    511     final int result = _tail;
    512     int tail = _tail;
    513     _setUint32AtTail(_buf, tail, values.length);
    514     tail -= _sizeofUint32;
    515     for (double value in values) {
    516       _setFloat32AtTail(_buf, tail, value);
    517       tail -= _sizeofFloat32;
    518     }
    519     return result;
    520   }
    521 
    522   /// Write the given list of signed 64-bit integer [values].
    523   int writeListInt64(List<int> values) {
    524     _ensureNoVTable();
    525     _prepare(_sizeofUint32, 2 * values.length);
    526     final int result = _tail;
    527     int tail = _tail;
    528     _setUint32AtTail(_buf, tail, values.length);
    529     tail -= _sizeofUint32;
    530     for (int value in values) {
    531       _setInt64AtTail(_buf, tail, value);
    532       tail -= _sizeofInt64;
    533     }
    534     return result;
    535   }
    536 
    537   /// Write the given list of signed 64-bit integer [values].
    538   int writeListUint64(List<int> values) {
    539     _ensureNoVTable();
    540     _prepare(_sizeofUint32, 2 * values.length);
    541     final int result = _tail;
    542     int tail = _tail;
    543     _setUint32AtTail(_buf, tail, values.length);
    544     tail -= _sizeofUint32;
    545     for (int value in values) {
    546       _setUint64AtTail(_buf, tail, value);
    547       tail -= _sizeofUint64;
    548     }
    549     return result;
    550   }
    551 
    552   /// Write the given list of signed 32-bit integer [values].
    553   int writeListInt32(List<int> values) {
    554     _ensureNoVTable();
    555     _prepare(_sizeofUint32, 1 + values.length);
    556     final int result = _tail;
    557     int tail = _tail;
    558     _setUint32AtTail(_buf, tail, values.length);
    559     tail -= _sizeofUint32;
    560     for (int value in values) {
    561       _setInt32AtTail(_buf, tail, value);
    562       tail -= _sizeofInt32;
    563     }
    564     return result;
    565   }
    566 
    567   /// Write the given list of unsigned 32-bit integer [values].
    568   int writeListUint32(List<int> values) {
    569     _ensureNoVTable();
    570     _prepare(_sizeofUint32, 1 + values.length);
    571     final int result = _tail;
    572     int tail = _tail;
    573     _setUint32AtTail(_buf, tail, values.length);
    574     tail -= _sizeofUint32;
    575     for (int value in values) {
    576       _setUint32AtTail(_buf, tail, value);
    577       tail -= _sizeofUint32;
    578     }
    579     return result;
    580   }
    581 
    582   /// Write the given list of signed 16-bit integer [values].
    583   int writeListInt16(List<int> values) {
    584     _ensureNoVTable();
    585     _prepare(_sizeofUint32, 1, additionalBytes: 2 * values.length);
    586     final int result = _tail;
    587     int tail = _tail;
    588     _setUint32AtTail(_buf, tail, values.length);
    589     tail -= _sizeofUint32;
    590     for (int value in values) {
    591       _setInt16AtTail(_buf, tail, value);
    592       tail -= _sizeofInt16;
    593     }
    594     return result;
    595   }
    596 
    597   /// Write the given list of unsigned 16-bit integer [values].
    598   int writeListUint16(List<int> values) {
    599     _ensureNoVTable();
    600     _prepare(_sizeofUint32, 1, additionalBytes: 2 * values.length);
    601     final int result = _tail;
    602     int tail = _tail;
    603     _setUint32AtTail(_buf, tail, values.length);
    604     tail -= _sizeofUint32;
    605     for (int value in values) {
    606       _setUint16AtTail(_buf, tail, value);
    607       tail -= _sizeofUint16;
    608     }
    609     return result;
    610   }
    611 
    612   /// Write the given list of bools as unsigend 8-bit integer [values].
    613   int writeListBool(List<bool> values) {
    614     return writeListUint8(values?.map((b) => b ? 1 : 0)?.toList());
    615   }
    616 
    617   /// Write the given list of signed 8-bit integer [values].
    618   int writeListInt8(List<int> values) {
    619     _ensureNoVTable();
    620     _prepare(_sizeofUint32, 1, additionalBytes: values.length);
    621     final int result = _tail;
    622     int tail = _tail;
    623     _setUint32AtTail(_buf, tail, values.length);
    624     tail -= _sizeofUint32;
    625     for (int value in values) {
    626       _setInt8AtTail(_buf, tail, value);
    627       tail -= _sizeofUint8;
    628     }
    629     return result;
    630   }
    631 
    632   /// Write the given list of unsigned 8-bit integer [values].
    633   int writeListUint8(List<int> values) {
    634     _ensureNoVTable();
    635     _prepare(_sizeofUint32, 1, additionalBytes: values.length);
    636     final int result = _tail;
    637     int tail = _tail;
    638     _setUint32AtTail(_buf, tail, values.length);
    639     tail -= _sizeofUint32;
    640     for (int value in values) {
    641       _setUint8AtTail(_buf, tail, value);
    642       tail -= _sizeofUint8;
    643     }
    644     return result;
    645   }
    646 
    647   /// Write the given string [value] and return its offset, or `null` if
    648   /// the [value] is `null`.
    649   int writeString(String value) {
    650     _ensureNoVTable();
    651     if (value != null) {
    652       if (_strings != null) {
    653         return _strings.putIfAbsent(value, () => _writeString(value));
    654       } else {
    655         return _writeString(value);
    656       }
    657     }
    658     return null;
    659   }
    660 
    661   int _writeString(String value) {
    662     // TODO(scheglov) optimize for ASCII strings
    663     List<int> bytes = utf8.encode(value);
    664     int length = bytes.length;
    665     _prepare(4, 1, additionalBytes: length + 1);
    666     final int result = _tail;
    667     _setUint32AtTail(_buf, _tail, length);
    668     int offset = _buf.lengthInBytes - _tail + 4;
    669     for (int i = 0; i < length; i++) {
    670       _buf.setUint8(offset++, bytes[i]);
    671     }
    672     return result;
    673   }
    674 
    675   /// Throw an exception if there is not currently a vtable.
    676   void _ensureCurrentVTable() {
    677     if (_currentVTable == null) {
    678       throw new StateError('Start a table before adding values.');
    679     }
    680   }
    681 
    682   /// Throw an exception if there is currently a vtable.
    683   void _ensureNoVTable() {
    684     if (_currentVTable != null) {
    685       throw new StateError(
    686           'Cannot write a non-scalar value while writing a table.');
    687     }
    688   }
    689 
    690   /// The number of bytes that have been written to the buffer so far.  The
    691   /// most recently written byte is this many bytes from the end of the buffer.
    692   int get offset => _tail;
    693 
    694   /// Zero-pads the buffer, which may be required for some struct layouts.
    695   void pad(int howManyBytes) {
    696     for (int i = 0; i < howManyBytes; i++) putUint8(0);
    697   }
    698 
    699   /// Prepare for writing the given `count` of scalars of the given `size`.
    700   /// Additionally allocate the specified `additionalBytes`. Update the current
    701   /// tail pointer to point at the allocated space.
    702   void _prepare(int size, int count, {int additionalBytes = 0}) {
    703     // Update the alignment.
    704     if (_maxAlign < size) {
    705       _maxAlign = size;
    706     }
    707     // Prepare amount of required space.
    708     int dataSize = size * count + additionalBytes;
    709     int alignDelta = (-(_tail + dataSize)) % size;
    710     int bufSize = alignDelta + dataSize;
    711     // Ensure that we have the required amount of space.
    712     {
    713       int oldCapacity = _buf.lengthInBytes;
    714       if (_tail + bufSize > oldCapacity) {
    715         int desiredNewCapacity = (oldCapacity + bufSize) * 2;
    716         int deltaCapacity = desiredNewCapacity - oldCapacity;
    717         deltaCapacity += (-deltaCapacity) % _maxAlign;
    718         int newCapacity = oldCapacity + deltaCapacity;
    719         ByteData newBuf = new ByteData(newCapacity);
    720         newBuf.buffer
    721             .asUint8List()
    722             .setAll(deltaCapacity, _buf.buffer.asUint8List());
    723         _buf = newBuf;
    724       }
    725     }
    726     // Update the tail pointer.
    727     _tail += bufSize;
    728   }
    729 
    730   /// Record the offset of the given [field].
    731   void _trackField(int field) {
    732     _currentVTable.addField(field, _tail);
    733   }
    734 
    735   static void _setFloat64AtTail(ByteData _buf, int tail, double x) {
    736     _buf.setFloat64(_buf.lengthInBytes - tail, x, Endian.little);
    737   }
    738 
    739   static void _setFloat32AtTail(ByteData _buf, int tail, double x) {
    740     _buf.setFloat32(_buf.lengthInBytes - tail, x, Endian.little);
    741   }
    742 
    743   static void _setUint64AtTail(ByteData _buf, int tail, int x) {
    744     _buf.setUint64(_buf.lengthInBytes - tail, x, Endian.little);
    745   }
    746 
    747   static void _setInt64AtTail(ByteData _buf, int tail, int x) {
    748     _buf.setInt64(_buf.lengthInBytes - tail, x, Endian.little);
    749   }
    750 
    751   static void _setInt32AtTail(ByteData _buf, int tail, int x) {
    752     _buf.setInt32(_buf.lengthInBytes - tail, x, Endian.little);
    753   }
    754 
    755   static void _setUint32AtTail(ByteData _buf, int tail, int x) {
    756     _buf.setUint32(_buf.lengthInBytes - tail, x, Endian.little);
    757   }
    758 
    759   static void _setInt16AtTail(ByteData _buf, int tail, int x) {
    760     _buf.setInt16(_buf.lengthInBytes - tail, x, Endian.little);
    761   }
    762 
    763   static void _setUint16AtTail(ByteData _buf, int tail, int x) {
    764     _buf.setUint16(_buf.lengthInBytes - tail, x, Endian.little);
    765   }
    766 
    767   static void _setInt8AtTail(ByteData _buf, int tail, int x) {
    768     _buf.setInt8(_buf.lengthInBytes - tail, x);
    769   }
    770 
    771   static void _setUint8AtTail(ByteData _buf, int tail, int x) {
    772     _buf.setUint8(_buf.lengthInBytes - tail, x);
    773   }
    774 }
    775 
    776 /// Reader of lists of boolean values.
    777 ///
    778 /// The returned unmodifiable lists lazily read values on access.
    779 class BoolListReader extends Reader<List<bool>> {
    780   const BoolListReader();
    781 
    782   @override
    783   int get size => _sizeofUint32;
    784 
    785   @override
    786   List<bool> read(BufferContext bc, int offset) =>
    787       new _FbBoolList(bc, bc.derefObject(offset));
    788 }
    789 
    790 /// The reader of booleans.
    791 class BoolReader extends Reader<bool> {
    792   const BoolReader() : super();
    793 
    794   @override
    795   int get size => _sizeofUint8;
    796 
    797   @override
    798   bool read(BufferContext bc, int offset) => bc._getInt8(offset) != 0;
    799 }
    800 
    801 /// The reader of lists of 64-bit float values.
    802 ///
    803 /// The returned unmodifiable lists lazily read values on access.
    804 class Float64ListReader extends Reader<List<double>> {
    805   const Float64ListReader();
    806 
    807   @override
    808   int get size => _sizeofFloat64;
    809 
    810   @override
    811   List<double> read(BufferContext bc, int offset) =>
    812       new _FbFloat64List(bc, bc.derefObject(offset));
    813 }
    814 
    815 class Float32ListReader extends Reader<List<double>> {
    816   const Float32ListReader();
    817 
    818   @override
    819   int get size => _sizeofFloat32;
    820 
    821   @override
    822   List<double> read(BufferContext bc, int offset) =>
    823       new _FbFloat32List(bc, bc.derefObject(offset));
    824 }
    825 
    826 class Float64Reader extends Reader<double> {
    827   const Float64Reader();
    828 
    829   @override
    830   int get size => _sizeofFloat64;
    831 
    832   @override
    833   double read(BufferContext bc, int offset) => bc._getFloat64(offset);
    834 }
    835 
    836 class Float32Reader extends Reader<double> {
    837   const Float32Reader();
    838 
    839   @override
    840   int get size => _sizeofFloat32;
    841 
    842   @override
    843   double read(BufferContext bc, int offset) => bc._getFloat32(offset);
    844 }
    845 
    846 class Int64Reader extends Reader<int> {
    847   const Int64Reader() : super();
    848   @override
    849   int get size => _sizeofInt64;
    850 
    851   @override
    852   int read(BufferContext bc, int offset) => bc._getInt64(offset);
    853 }
    854 
    855 /// The reader of signed 32-bit integers.
    856 class Int32Reader extends Reader<int> {
    857   const Int32Reader() : super();
    858 
    859   @override
    860   int get size => _sizeofInt32;
    861 
    862   @override
    863   int read(BufferContext bc, int offset) => bc._getInt32(offset);
    864 }
    865 
    866 /// The reader of signed 32-bit integers.
    867 class Int16Reader extends Reader<int> {
    868   const Int16Reader() : super();
    869 
    870   @override
    871   int get size => _sizeofInt16;
    872 
    873   @override
    874   int read(BufferContext bc, int offset) => bc._getInt16(offset);
    875 }
    876 
    877 /// The reader of 8-bit signed integers.
    878 class Int8Reader extends Reader<int> {
    879   const Int8Reader() : super();
    880 
    881   @override
    882   int get size => _sizeofInt8;
    883 
    884   @override
    885   int read(BufferContext bc, int offset) => bc._getInt8(offset);
    886 }
    887 
    888 /// The reader of lists of objects.
    889 ///
    890 /// The returned unmodifiable lists lazily read objects on access.
    891 class ListReader<E> extends Reader<List<E>> {
    892   final Reader<E> _elementReader;
    893 
    894   const ListReader(this._elementReader);
    895 
    896   @override
    897   int get size => _sizeofUint32;
    898 
    899   @override
    900   List<E> read(BufferContext bc, int offset) =>
    901       new _FbGenericList<E>(_elementReader, bc, bc.derefObject(offset));
    902 }
    903 
    904 /// Object that can read a value at a [BufferContext].
    905 abstract class Reader<T> {
    906   const Reader();
    907 
    908   /// The size of the value in bytes.
    909   int get size;
    910 
    911   /// Read the value at the given [offset] in [bc].
    912   T read(BufferContext bc, int offset);
    913 
    914   /// Read the value of the given [field] in the given [object].
    915   T vTableGet(BufferContext object, int offset, int field, [T defaultValue]) {
    916     int vTableSOffset = object._getInt32(offset);
    917     int vTableOffset = offset - vTableSOffset;
    918     int vTableSize = object._getUint16(vTableOffset);
    919     int vTableFieldOffset = field;
    920     if (vTableFieldOffset < vTableSize) {
    921       int fieldOffsetInObject =
    922           object._getUint16(vTableOffset + vTableFieldOffset);
    923       if (fieldOffsetInObject != 0) {
    924         return read(object, offset + fieldOffsetInObject);
    925       }
    926     }
    927     return defaultValue;
    928   }
    929 }
    930 
    931 /// The reader of string values.
    932 class StringReader extends Reader<String> {
    933   const StringReader() : super();
    934 
    935   @override
    936   int get size => 4;
    937 
    938   @override
    939   String read(BufferContext bc, int offset) {
    940     int strOffset = bc.derefObject(offset);
    941     int length = bc._getUint32(strOffset);
    942     Uint8List bytes = bc._asUint8LIst(strOffset + 4, length);
    943     if (_isLatin(bytes)) {
    944       return new String.fromCharCodes(bytes);
    945     }
    946     return utf8.decode(bytes);
    947   }
    948 
    949   static bool _isLatin(Uint8List bytes) {
    950     int length = bytes.length;
    951     for (int i = 0; i < length; i++) {
    952       if (bytes[i] > 127) {
    953         return false;
    954       }
    955     }
    956     return true;
    957   }
    958 }
    959 
    960 /// An abstract reader for structs.
    961 abstract class StructReader<T> extends Reader<T> {
    962   const StructReader();
    963 
    964   /// Return the object at `offset`.
    965   T createObject(BufferContext bc, int offset);
    966 
    967   T read(BufferContext bp, int offset) {
    968     return createObject(bp, offset);
    969   }
    970 }
    971 
    972 /// An abstract reader for tables.
    973 abstract class TableReader<T> extends Reader<T> {
    974   const TableReader();
    975 
    976   @override
    977   int get size => 4;
    978 
    979   /// Return the object at [offset].
    980   T createObject(BufferContext bc, int offset);
    981 
    982   @override
    983   T read(BufferContext bp, int offset) {
    984     int objectOffset = bp.derefObject(offset);
    985     return createObject(bp, objectOffset);
    986   }
    987 }
    988 
    989 /// Reader of lists of unsigned 32-bit integer values.
    990 ///
    991 /// The returned unmodifiable lists lazily read values on access.
    992 class Uint32ListReader extends Reader<List<int>> {
    993   const Uint32ListReader();
    994 
    995   @override
    996   int get size => _sizeofUint32;
    997 
    998   @override
    999   List<int> read(BufferContext bc, int offset) =>
   1000       new _FbUint32List(bc, bc.derefObject(offset));
   1001 }
   1002 
   1003 /// The reader of unsigned 64-bit integers.
   1004 ///
   1005 /// WARNING: May have compatibility issues with JavaScript
   1006 class Uint64Reader extends Reader<int> {
   1007   const Uint64Reader() : super();
   1008 
   1009   @override
   1010   int get size => _sizeofUint64;
   1011 
   1012   @override
   1013   int read(BufferContext bc, int offset) => bc._getUint64(offset);
   1014 }
   1015 
   1016 /// The reader of unsigned 32-bit integers.
   1017 class Uint32Reader extends Reader<int> {
   1018   const Uint32Reader() : super();
   1019 
   1020   @override
   1021   int get size => _sizeofUint32;
   1022 
   1023   @override
   1024   int read(BufferContext bc, int offset) => bc._getUint32(offset);
   1025 }
   1026 
   1027 /// Reader of lists of unsigned 32-bit integer values.
   1028 ///
   1029 /// The returned unmodifiable lists lazily read values on access.
   1030 class Uint16ListReader extends Reader<List<int>> {
   1031   const Uint16ListReader();
   1032 
   1033   @override
   1034   int get size => _sizeofUint32;
   1035 
   1036   @override
   1037   List<int> read(BufferContext bc, int offset) =>
   1038       new _FbUint16List(bc, bc.derefObject(offset));
   1039 }
   1040 
   1041 /// The reader of unsigned 32-bit integers.
   1042 class Uint16Reader extends Reader<int> {
   1043   const Uint16Reader() : super();
   1044 
   1045   @override
   1046   int get size => _sizeofUint16;
   1047 
   1048   @override
   1049   int read(BufferContext bc, int offset) => bc._getUint16(offset);
   1050 }
   1051 
   1052 /// Reader of lists of unsigned 8-bit integer values.
   1053 ///
   1054 /// The returned unmodifiable lists lazily read values on access.
   1055 class Uint8ListReader extends Reader<List<int>> {
   1056   const Uint8ListReader();
   1057 
   1058   @override
   1059   int get size => _sizeofUint32;
   1060 
   1061   @override
   1062   List<int> read(BufferContext bc, int offset) =>
   1063       new _FbUint8List(bc, bc.derefObject(offset));
   1064 }
   1065 
   1066 /// The reader of unsigned 8-bit integers.
   1067 class Uint8Reader extends Reader<int> {
   1068   const Uint8Reader() : super();
   1069 
   1070   @override
   1071   int get size => _sizeofUint8;
   1072 
   1073   @override
   1074   int read(BufferContext bc, int offset) => bc._getUint8(offset);
   1075 }
   1076 
   1077 /// The list backed by 64-bit values - Uint64 length and Float64.
   1078 class _FbFloat64List extends _FbList<double> {
   1079   _FbFloat64List(BufferContext bc, int offset) : super(bc, offset);
   1080 
   1081   @override
   1082   double operator [](int i) {
   1083     return bc._getFloat64(offset + 4 + 8 * i);
   1084   }
   1085 }
   1086 
   1087 /// The list backed by 32-bit values - Float32.
   1088 class _FbFloat32List extends _FbList<double> {
   1089   _FbFloat32List(BufferContext bc, int offset) : super(bc, offset);
   1090 
   1091   @override
   1092   double operator [](int i) {
   1093     return bc._getFloat32(offset + 4 + 4 * i);
   1094   }
   1095 }
   1096 
   1097 /// List backed by a generic object which may have any size.
   1098 class _FbGenericList<E> extends _FbList<E> {
   1099   final Reader<E> elementReader;
   1100 
   1101   List<E> _items;
   1102 
   1103   _FbGenericList(this.elementReader, BufferContext bp, int offset)
   1104       : super(bp, offset);
   1105 
   1106   @override
   1107   E operator [](int i) {
   1108     _items ??= new List<E>(length);
   1109     E item = _items[i];
   1110     if (item == null) {
   1111       item = elementReader.read(bc, offset + 4 + elementReader.size * i);
   1112       _items[i] = item;
   1113     }
   1114     return item;
   1115   }
   1116 }
   1117 
   1118 /// The base class for immutable lists read from flat buffers.
   1119 abstract class _FbList<E> extends Object with ListMixin<E> implements List<E> {
   1120   final BufferContext bc;
   1121   final int offset;
   1122   int _length;
   1123 
   1124   _FbList(this.bc, this.offset);
   1125 
   1126   @override
   1127   int get length {
   1128     _length ??= bc._getUint32(offset);
   1129     return _length;
   1130   }
   1131 
   1132   @override
   1133   void set length(int i) =>
   1134       throw new StateError('Attempt to modify immutable list');
   1135 
   1136   @override
   1137   void operator []=(int i, E e) =>
   1138       throw new StateError('Attempt to modify immutable list');
   1139 }
   1140 
   1141 /// List backed by 32-bit unsigned integers.
   1142 class _FbUint32List extends _FbList<int> {
   1143   _FbUint32List(BufferContext bc, int offset) : super(bc, offset);
   1144 
   1145   @override
   1146   int operator [](int i) {
   1147     return bc._getUint32(offset + 4 + 4 * i);
   1148   }
   1149 }
   1150 
   1151 /// List backed by 16-bit unsigned integers.
   1152 class _FbUint16List extends _FbList<int> {
   1153   _FbUint16List(BufferContext bc, int offset) : super(bc, offset);
   1154 
   1155   @override
   1156   int operator [](int i) {
   1157     return bc._getUint16(offset + 4 + 2 * i);
   1158   }
   1159 }
   1160 
   1161 /// List backed by 8-bit unsigned integers.
   1162 class _FbUint8List extends _FbList<int> {
   1163   _FbUint8List(BufferContext bc, int offset) : super(bc, offset);
   1164 
   1165   @override
   1166   int operator [](int i) {
   1167     return bc._getUint8(offset + 4 + i);
   1168   }
   1169 }
   1170 
   1171 /// List backed by 8-bit unsigned integers.
   1172 class _FbBoolList extends _FbList<bool> {
   1173   _FbBoolList(BufferContext bc, int offset) : super(bc, offset);
   1174 
   1175   @override
   1176   bool operator [](int i) {
   1177     return bc._getUint8(offset + 4 + i) == 1 ? true : false;
   1178   }
   1179 }
   1180 
   1181 /// Class that describes the structure of a table.
   1182 class _VTable {
   1183   static const int _metadataLength = 4;
   1184 
   1185   final List<int> fieldTails = <int>[];
   1186   final List<int> fieldOffsets = <int>[];
   1187 
   1188   /// The size of the table that uses this VTable.
   1189   int tableSize;
   1190 
   1191   /// The tail of this VTable.  It is used to share the same VTable between
   1192   /// multiple tables of identical structure.
   1193   int tail;
   1194 
   1195   int get _vTableSize => numOfUint16 * _sizeofUint16;
   1196 
   1197   int get numOfUint16 => 1 + 1 + fieldTails.length;
   1198 
   1199   void addField(int field, int offset) {
   1200     while (fieldTails.length <= field) {
   1201       fieldTails.add(null);
   1202     }
   1203     fieldTails[field] = offset;
   1204   }
   1205 
   1206   bool _offsetsMatch(int vt2Start, ByteData buf) {
   1207     for (int i = 0; i < fieldOffsets.length; i++) {
   1208       if (fieldOffsets[i] !=
   1209           buf.getUint16(
   1210               vt2Start + _metadataLength + (2 * i), Endian.little)) {
   1211         return false;
   1212       }
   1213     }
   1214     return true;
   1215   }
   1216 
   1217   /// Fill the [fieldOffsets] field.
   1218   void computeFieldOffsets(int tableTail) {
   1219     assert(fieldOffsets.isEmpty);
   1220     for (int fieldTail in fieldTails) {
   1221       int fieldOffset = fieldTail == null ? 0 : tableTail - fieldTail;
   1222       fieldOffsets.add(fieldOffset);
   1223     }
   1224   }
   1225 
   1226   /// Outputs this VTable to [buf], which is is expected to be aligned to 16-bit
   1227   /// and have at least [numOfUint16] 16-bit words available.
   1228   void output(ByteData buf, int bufOffset) {
   1229     // VTable size.
   1230     buf.setUint16(bufOffset, numOfUint16 * 2, Endian.little);
   1231     bufOffset += 2;
   1232     // Table size.
   1233     buf.setUint16(bufOffset, tableSize, Endian.little);
   1234     bufOffset += 2;
   1235     // Field offsets.
   1236     for (int fieldOffset in fieldOffsets) {
   1237       buf.setUint16(bufOffset, fieldOffset, Endian.little);
   1238       bufOffset += 2;
   1239     }
   1240   }
   1241 }
   1242