1*890232f2SAndroid Build Coastguard Workerimport 'dart:collection'; 2*890232f2SAndroid Build Coastguard Workerimport 'dart:convert'; 3*890232f2SAndroid Build Coastguard Workerimport 'dart:math'; 4*890232f2SAndroid Build Coastguard Workerimport 'dart:typed_data'; 5*890232f2SAndroid Build Coastguard Worker 6*890232f2SAndroid Build Coastguard Workerconst int _sizeofUint8 = 1; 7*890232f2SAndroid Build Coastguard Workerconst int _sizeofUint16 = 2; 8*890232f2SAndroid Build Coastguard Workerconst int _sizeofUint32 = 4; 9*890232f2SAndroid Build Coastguard Workerconst int _sizeofUint64 = 8; 10*890232f2SAndroid Build Coastguard Workerconst int _sizeofInt8 = 1; 11*890232f2SAndroid Build Coastguard Workerconst int _sizeofInt16 = 2; 12*890232f2SAndroid Build Coastguard Workerconst int _sizeofInt32 = 4; 13*890232f2SAndroid Build Coastguard Workerconst int _sizeofInt64 = 8; 14*890232f2SAndroid Build Coastguard Workerconst int _sizeofFloat32 = 4; 15*890232f2SAndroid Build Coastguard Workerconst int _sizeofFloat64 = 8; 16*890232f2SAndroid Build Coastguard Worker 17*890232f2SAndroid Build Coastguard Worker/// Callback used to invoke a struct builder's finish method. 18*890232f2SAndroid Build Coastguard Worker/// 19*890232f2SAndroid Build Coastguard Worker/// This callback is used by other struct's `finish` methods to write the nested 20*890232f2SAndroid Build Coastguard Worker/// struct's fields inline. 21*890232f2SAndroid Build Coastguard Workertypedef StructBuilder = void Function(); 22*890232f2SAndroid Build Coastguard Worker 23*890232f2SAndroid Build Coastguard Worker/// Buffer with data and some context about it. 24*890232f2SAndroid Build Coastguard Workerclass BufferContext { 25*890232f2SAndroid Build Coastguard Worker final ByteData _buffer; 26*890232f2SAndroid Build Coastguard Worker 27*890232f2SAndroid Build Coastguard Worker ByteData get buffer => _buffer; 28*890232f2SAndroid Build Coastguard Worker 29*890232f2SAndroid Build Coastguard Worker /// Create from a FlatBuffer represented by a list of bytes (uint8). 30*890232f2SAndroid Build Coastguard Worker factory BufferContext.fromBytes(List<int> byteList) => 31*890232f2SAndroid Build Coastguard Worker BufferContext(byteList is Uint8List 32*890232f2SAndroid Build Coastguard Worker ? byteList.buffer.asByteData(byteList.offsetInBytes) 33*890232f2SAndroid Build Coastguard Worker : ByteData.view(Uint8List.fromList(byteList).buffer)); 34*890232f2SAndroid Build Coastguard Worker 35*890232f2SAndroid Build Coastguard Worker /// Create from a FlatBuffer represented by ByteData. 36*890232f2SAndroid Build Coastguard Worker BufferContext(this._buffer); 37*890232f2SAndroid Build Coastguard Worker 38*890232f2SAndroid Build Coastguard Worker @pragma('vm:prefer-inline') 39*890232f2SAndroid Build Coastguard Worker int derefObject(int offset) => offset + _getUint32(offset); 40*890232f2SAndroid Build Coastguard Worker 41*890232f2SAndroid Build Coastguard Worker @pragma('vm:prefer-inline') 42*890232f2SAndroid Build Coastguard Worker Uint8List _asUint8List(int offset, int length) => 43*890232f2SAndroid Build Coastguard Worker _buffer.buffer.asUint8List(_buffer.offsetInBytes + offset, length); 44*890232f2SAndroid Build Coastguard Worker 45*890232f2SAndroid Build Coastguard Worker @pragma('vm:prefer-inline') 46*890232f2SAndroid Build Coastguard Worker double _getFloat64(int offset) => _buffer.getFloat64(offset, Endian.little); 47*890232f2SAndroid Build Coastguard Worker 48*890232f2SAndroid Build Coastguard Worker @pragma('vm:prefer-inline') 49*890232f2SAndroid Build Coastguard Worker double _getFloat32(int offset) => _buffer.getFloat32(offset, Endian.little); 50*890232f2SAndroid Build Coastguard Worker 51*890232f2SAndroid Build Coastguard Worker @pragma('vm:prefer-inline') 52*890232f2SAndroid Build Coastguard Worker int _getInt64(int offset) => _buffer.getInt64(offset, Endian.little); 53*890232f2SAndroid Build Coastguard Worker 54*890232f2SAndroid Build Coastguard Worker @pragma('vm:prefer-inline') 55*890232f2SAndroid Build Coastguard Worker int _getInt32(int offset) => _buffer.getInt32(offset, Endian.little); 56*890232f2SAndroid Build Coastguard Worker 57*890232f2SAndroid Build Coastguard Worker @pragma('vm:prefer-inline') 58*890232f2SAndroid Build Coastguard Worker int _getInt16(int offset) => _buffer.getInt16(offset, Endian.little); 59*890232f2SAndroid Build Coastguard Worker 60*890232f2SAndroid Build Coastguard Worker @pragma('vm:prefer-inline') 61*890232f2SAndroid Build Coastguard Worker int _getInt8(int offset) => _buffer.getInt8(offset); 62*890232f2SAndroid Build Coastguard Worker 63*890232f2SAndroid Build Coastguard Worker @pragma('vm:prefer-inline') 64*890232f2SAndroid Build Coastguard Worker int _getUint64(int offset) => _buffer.getUint64(offset, Endian.little); 65*890232f2SAndroid Build Coastguard Worker 66*890232f2SAndroid Build Coastguard Worker @pragma('vm:prefer-inline') 67*890232f2SAndroid Build Coastguard Worker int _getUint32(int offset) => _buffer.getUint32(offset, Endian.little); 68*890232f2SAndroid Build Coastguard Worker 69*890232f2SAndroid Build Coastguard Worker @pragma('vm:prefer-inline') 70*890232f2SAndroid Build Coastguard Worker int _getUint16(int offset) => _buffer.getUint16(offset, Endian.little); 71*890232f2SAndroid Build Coastguard Worker 72*890232f2SAndroid Build Coastguard Worker @pragma('vm:prefer-inline') 73*890232f2SAndroid Build Coastguard Worker int _getUint8(int offset) => _buffer.getUint8(offset); 74*890232f2SAndroid Build Coastguard Worker} 75*890232f2SAndroid Build Coastguard Worker 76*890232f2SAndroid Build Coastguard Worker/// Interface implemented by the "object-api" classes (ending with "T"). 77*890232f2SAndroid Build Coastguard Workerabstract class Packable { 78*890232f2SAndroid Build Coastguard Worker /// Serialize the object using the given builder, returning the offset. 79*890232f2SAndroid Build Coastguard Worker int pack(Builder fbBuilder); 80*890232f2SAndroid Build Coastguard Worker} 81*890232f2SAndroid Build Coastguard Worker 82*890232f2SAndroid Build Coastguard Worker/// Class implemented by typed builders generated by flatc. 83*890232f2SAndroid Build Coastguard Workerabstract class ObjectBuilder { 84*890232f2SAndroid Build Coastguard Worker int? _firstOffset; 85*890232f2SAndroid Build Coastguard Worker 86*890232f2SAndroid Build Coastguard Worker /// Can be used to write the data represented by this builder to the [Builder] 87*890232f2SAndroid Build Coastguard Worker /// and reuse the offset created in multiple tables. 88*890232f2SAndroid Build Coastguard Worker /// 89*890232f2SAndroid Build Coastguard Worker /// Note that this method assumes you call it using the same [Builder] instance 90*890232f2SAndroid Build Coastguard Worker /// every time. The returned offset is only good for the [Builder] used in the 91*890232f2SAndroid Build Coastguard Worker /// first call to this method. 92*890232f2SAndroid Build Coastguard Worker int getOrCreateOffset(Builder fbBuilder) { 93*890232f2SAndroid Build Coastguard Worker _firstOffset ??= finish(fbBuilder); 94*890232f2SAndroid Build Coastguard Worker return _firstOffset!; 95*890232f2SAndroid Build Coastguard Worker } 96*890232f2SAndroid Build Coastguard Worker 97*890232f2SAndroid Build Coastguard Worker /// Writes the data in this helper to the [Builder]. 98*890232f2SAndroid Build Coastguard Worker int finish(Builder fbBuilder); 99*890232f2SAndroid Build Coastguard Worker 100*890232f2SAndroid Build Coastguard Worker /// Convenience method that will create a new [Builder], [finish]es the data, 101*890232f2SAndroid Build Coastguard Worker /// and returns the buffer as a [Uint8List] of bytes. 102*890232f2SAndroid Build Coastguard Worker Uint8List toBytes(); 103*890232f2SAndroid Build Coastguard Worker} 104*890232f2SAndroid Build Coastguard Worker 105*890232f2SAndroid Build Coastguard Worker/// Class that helps building flat buffers. 106*890232f2SAndroid Build Coastguard Workerclass Builder { 107*890232f2SAndroid Build Coastguard Worker bool _finished = false; 108*890232f2SAndroid Build Coastguard Worker 109*890232f2SAndroid Build Coastguard Worker final int initialSize; 110*890232f2SAndroid Build Coastguard Worker 111*890232f2SAndroid Build Coastguard Worker /// The list of existing VTable(s). 112*890232f2SAndroid Build Coastguard Worker final List<int> _vTables; 113*890232f2SAndroid Build Coastguard Worker 114*890232f2SAndroid Build Coastguard Worker final bool deduplicateTables; 115*890232f2SAndroid Build Coastguard Worker 116*890232f2SAndroid Build Coastguard Worker ByteData _buf; 117*890232f2SAndroid Build Coastguard Worker 118*890232f2SAndroid Build Coastguard Worker final Allocator _allocator; 119*890232f2SAndroid Build Coastguard Worker 120*890232f2SAndroid Build Coastguard Worker /// The maximum alignment that has been seen so far. If [_buf] has to be 121*890232f2SAndroid Build Coastguard Worker /// reallocated in the future (to insert room at its start for more bytes) the 122*890232f2SAndroid Build Coastguard Worker /// reallocation will need to be a multiple of this many bytes. 123*890232f2SAndroid Build Coastguard Worker int _maxAlign = 1; 124*890232f2SAndroid Build Coastguard Worker 125*890232f2SAndroid Build Coastguard Worker /// The number of bytes that have been written to the buffer so far. The 126*890232f2SAndroid Build Coastguard Worker /// most recently written byte is this many bytes from the end of [_buf]. 127*890232f2SAndroid Build Coastguard Worker int _tail = 0; 128*890232f2SAndroid Build Coastguard Worker 129*890232f2SAndroid Build Coastguard Worker /// The location of the end of the current table, measured in bytes from the 130*890232f2SAndroid Build Coastguard Worker /// end of [_buf]. 131*890232f2SAndroid Build Coastguard Worker int _currentTableEndTail = 0; 132*890232f2SAndroid Build Coastguard Worker 133*890232f2SAndroid Build Coastguard Worker _VTable? _currentVTable; 134*890232f2SAndroid Build Coastguard Worker 135*890232f2SAndroid Build Coastguard Worker /// Map containing all strings that have been written so far. This allows us 136*890232f2SAndroid Build Coastguard Worker /// to avoid duplicating strings. 137*890232f2SAndroid Build Coastguard Worker /// 138*890232f2SAndroid Build Coastguard Worker /// Allocated only if `internStrings` is set to true on the constructor. 139*890232f2SAndroid Build Coastguard Worker Map<String, int>? _strings; 140*890232f2SAndroid Build Coastguard Worker 141*890232f2SAndroid Build Coastguard Worker /// Creates a new FlatBuffers Builder. 142*890232f2SAndroid Build Coastguard Worker /// 143*890232f2SAndroid Build Coastguard Worker /// `initialSize` is the initial array size in bytes. The [Builder] will 144*890232f2SAndroid Build Coastguard Worker /// automatically grow the array if/as needed. `internStrings`, if set to 145*890232f2SAndroid Build Coastguard Worker /// true, will cause [writeString] to pool strings in the buffer so that 146*890232f2SAndroid Build Coastguard Worker /// identical strings will always use the same offset in tables. 147*890232f2SAndroid Build Coastguard Worker Builder({ 148*890232f2SAndroid Build Coastguard Worker this.initialSize = 1024, 149*890232f2SAndroid Build Coastguard Worker bool internStrings = false, 150*890232f2SAndroid Build Coastguard Worker Allocator allocator = const DefaultAllocator(), 151*890232f2SAndroid Build Coastguard Worker this.deduplicateTables = true, 152*890232f2SAndroid Build Coastguard Worker }) : _allocator = allocator, 153*890232f2SAndroid Build Coastguard Worker _buf = allocator.allocate(initialSize), 154*890232f2SAndroid Build Coastguard Worker _vTables = deduplicateTables ? [] : const [] { 155*890232f2SAndroid Build Coastguard Worker if (internStrings) { 156*890232f2SAndroid Build Coastguard Worker _strings = <String, int>{}; 157*890232f2SAndroid Build Coastguard Worker } 158*890232f2SAndroid Build Coastguard Worker } 159*890232f2SAndroid Build Coastguard Worker 160*890232f2SAndroid Build Coastguard Worker /// Calculate the finished buffer size (aligned). 161*890232f2SAndroid Build Coastguard Worker @pragma('vm:prefer-inline') 162*890232f2SAndroid Build Coastguard Worker int size() => _tail + ((-_tail) & (_maxAlign - 1)); 163*890232f2SAndroid Build Coastguard Worker 164*890232f2SAndroid Build Coastguard Worker /// Add the [field] with the given boolean [value]. The field is not added if 165*890232f2SAndroid Build Coastguard Worker /// the [value] is equal to [def]. Booleans are stored as 8-bit fields with 166*890232f2SAndroid Build Coastguard Worker /// `0` for `false` and `1` for `true`. 167*890232f2SAndroid Build Coastguard Worker void addBool(int field, bool? value, [bool? def]) { 168*890232f2SAndroid Build Coastguard Worker assert(_inVTable); 169*890232f2SAndroid Build Coastguard Worker if (value != null && value != def) { 170*890232f2SAndroid Build Coastguard Worker _prepare(_sizeofUint8, 1); 171*890232f2SAndroid Build Coastguard Worker _trackField(field); 172*890232f2SAndroid Build Coastguard Worker _buf.setInt8(_buf.lengthInBytes - _tail, value ? 1 : 0); 173*890232f2SAndroid Build Coastguard Worker } 174*890232f2SAndroid Build Coastguard Worker } 175*890232f2SAndroid Build Coastguard Worker 176*890232f2SAndroid Build Coastguard Worker /// Add the [field] with the given 32-bit signed integer [value]. The field is 177*890232f2SAndroid Build Coastguard Worker /// not added if the [value] is equal to [def]. 178*890232f2SAndroid Build Coastguard Worker void addInt32(int field, int? value, [int? def]) { 179*890232f2SAndroid Build Coastguard Worker assert(_inVTable); 180*890232f2SAndroid Build Coastguard Worker if (value != null && value != def) { 181*890232f2SAndroid Build Coastguard Worker _prepare(_sizeofInt32, 1); 182*890232f2SAndroid Build Coastguard Worker _trackField(field); 183*890232f2SAndroid Build Coastguard Worker _setInt32AtTail(_tail, value); 184*890232f2SAndroid Build Coastguard Worker } 185*890232f2SAndroid Build Coastguard Worker } 186*890232f2SAndroid Build Coastguard Worker 187*890232f2SAndroid Build Coastguard Worker /// Add the [field] with the given 32-bit signed integer [value]. The field is 188*890232f2SAndroid Build Coastguard Worker /// not added if the [value] is equal to [def]. 189*890232f2SAndroid Build Coastguard Worker void addInt16(int field, int? value, [int? def]) { 190*890232f2SAndroid Build Coastguard Worker assert(_inVTable); 191*890232f2SAndroid Build Coastguard Worker if (value != null && value != def) { 192*890232f2SAndroid Build Coastguard Worker _prepare(_sizeofInt16, 1); 193*890232f2SAndroid Build Coastguard Worker _trackField(field); 194*890232f2SAndroid Build Coastguard Worker _setInt16AtTail(_tail, value); 195*890232f2SAndroid Build Coastguard Worker } 196*890232f2SAndroid Build Coastguard Worker } 197*890232f2SAndroid Build Coastguard Worker 198*890232f2SAndroid Build Coastguard Worker /// Add the [field] with the given 8-bit signed integer [value]. The field is 199*890232f2SAndroid Build Coastguard Worker /// not added if the [value] is equal to [def]. 200*890232f2SAndroid Build Coastguard Worker void addInt8(int field, int? value, [int? def]) { 201*890232f2SAndroid Build Coastguard Worker assert(_inVTable); 202*890232f2SAndroid Build Coastguard Worker if (value != null && value != def) { 203*890232f2SAndroid Build Coastguard Worker _prepare(_sizeofInt8, 1); 204*890232f2SAndroid Build Coastguard Worker _trackField(field); 205*890232f2SAndroid Build Coastguard Worker _setInt8AtTail(_tail, value); 206*890232f2SAndroid Build Coastguard Worker } 207*890232f2SAndroid Build Coastguard Worker } 208*890232f2SAndroid Build Coastguard Worker 209*890232f2SAndroid Build Coastguard Worker void addStruct(int field, int offset) { 210*890232f2SAndroid Build Coastguard Worker assert(_inVTable); 211*890232f2SAndroid Build Coastguard Worker _trackField(field); 212*890232f2SAndroid Build Coastguard Worker _currentVTable!.addField(field, offset); 213*890232f2SAndroid Build Coastguard Worker } 214*890232f2SAndroid Build Coastguard Worker 215*890232f2SAndroid Build Coastguard Worker /// Add the [field] referencing an object with the given [offset]. 216*890232f2SAndroid Build Coastguard Worker void addOffset(int field, int? offset) { 217*890232f2SAndroid Build Coastguard Worker assert(_inVTable); 218*890232f2SAndroid Build Coastguard Worker if (offset != null) { 219*890232f2SAndroid Build Coastguard Worker _prepare(_sizeofUint32, 1); 220*890232f2SAndroid Build Coastguard Worker _trackField(field); 221*890232f2SAndroid Build Coastguard Worker _setUint32AtTail(_tail, _tail - offset); 222*890232f2SAndroid Build Coastguard Worker } 223*890232f2SAndroid Build Coastguard Worker } 224*890232f2SAndroid Build Coastguard Worker 225*890232f2SAndroid Build Coastguard Worker /// Add the [field] with the given 32-bit unsigned integer [value]. The field 226*890232f2SAndroid Build Coastguard Worker /// is not added if the [value] is equal to [def]. 227*890232f2SAndroid Build Coastguard Worker void addUint32(int field, int? value, [int? def]) { 228*890232f2SAndroid Build Coastguard Worker assert(_inVTable); 229*890232f2SAndroid Build Coastguard Worker if (value != null && value != def) { 230*890232f2SAndroid Build Coastguard Worker _prepare(_sizeofUint32, 1); 231*890232f2SAndroid Build Coastguard Worker _trackField(field); 232*890232f2SAndroid Build Coastguard Worker _setUint32AtTail(_tail, value); 233*890232f2SAndroid Build Coastguard Worker } 234*890232f2SAndroid Build Coastguard Worker } 235*890232f2SAndroid Build Coastguard Worker 236*890232f2SAndroid Build Coastguard Worker /// Add the [field] with the given 32-bit unsigned integer [value]. The field 237*890232f2SAndroid Build Coastguard Worker /// is not added if the [value] is equal to [def]. 238*890232f2SAndroid Build Coastguard Worker void addUint16(int field, int? value, [int? def]) { 239*890232f2SAndroid Build Coastguard Worker assert(_inVTable); 240*890232f2SAndroid Build Coastguard Worker if (value != null && value != def) { 241*890232f2SAndroid Build Coastguard Worker _prepare(_sizeofUint16, 1); 242*890232f2SAndroid Build Coastguard Worker _trackField(field); 243*890232f2SAndroid Build Coastguard Worker _setUint16AtTail(_tail, value); 244*890232f2SAndroid Build Coastguard Worker } 245*890232f2SAndroid Build Coastguard Worker } 246*890232f2SAndroid Build Coastguard Worker 247*890232f2SAndroid Build Coastguard Worker /// Add the [field] with the given 8-bit unsigned integer [value]. The field 248*890232f2SAndroid Build Coastguard Worker /// is not added if the [value] is equal to [def]. 249*890232f2SAndroid Build Coastguard Worker void addUint8(int field, int? value, [int? def]) { 250*890232f2SAndroid Build Coastguard Worker assert(_inVTable); 251*890232f2SAndroid Build Coastguard Worker if (value != null && value != def) { 252*890232f2SAndroid Build Coastguard Worker _prepare(_sizeofUint8, 1); 253*890232f2SAndroid Build Coastguard Worker _trackField(field); 254*890232f2SAndroid Build Coastguard Worker _setUint8AtTail(_tail, value); 255*890232f2SAndroid Build Coastguard Worker } 256*890232f2SAndroid Build Coastguard Worker } 257*890232f2SAndroid Build Coastguard Worker 258*890232f2SAndroid Build Coastguard Worker /// Add the [field] with the given 32-bit float [value]. The field 259*890232f2SAndroid Build Coastguard Worker /// is not added if the [value] is equal to [def]. 260*890232f2SAndroid Build Coastguard Worker void addFloat32(int field, double? value, [double? def]) { 261*890232f2SAndroid Build Coastguard Worker assert(_inVTable); 262*890232f2SAndroid Build Coastguard Worker if (value != null && value != def) { 263*890232f2SAndroid Build Coastguard Worker _prepare(_sizeofFloat32, 1); 264*890232f2SAndroid Build Coastguard Worker _trackField(field); 265*890232f2SAndroid Build Coastguard Worker _setFloat32AtTail(_tail, value); 266*890232f2SAndroid Build Coastguard Worker } 267*890232f2SAndroid Build Coastguard Worker } 268*890232f2SAndroid Build Coastguard Worker 269*890232f2SAndroid Build Coastguard Worker /// Add the [field] with the given 64-bit double [value]. The field 270*890232f2SAndroid Build Coastguard Worker /// is not added if the [value] is equal to [def]. 271*890232f2SAndroid Build Coastguard Worker void addFloat64(int field, double? value, [double? def]) { 272*890232f2SAndroid Build Coastguard Worker assert(_inVTable); 273*890232f2SAndroid Build Coastguard Worker if (value != null && value != def) { 274*890232f2SAndroid Build Coastguard Worker _prepare(_sizeofFloat64, 1); 275*890232f2SAndroid Build Coastguard Worker _trackField(field); 276*890232f2SAndroid Build Coastguard Worker _setFloat64AtTail(_tail, value); 277*890232f2SAndroid Build Coastguard Worker } 278*890232f2SAndroid Build Coastguard Worker } 279*890232f2SAndroid Build Coastguard Worker 280*890232f2SAndroid Build Coastguard Worker /// Add the [field] with the given 64-bit unsigned integer [value]. The field 281*890232f2SAndroid Build Coastguard Worker /// is not added if the [value] is equal to [def]. 282*890232f2SAndroid Build Coastguard Worker void addUint64(int field, int? value, [double? def]) { 283*890232f2SAndroid Build Coastguard Worker assert(_inVTable); 284*890232f2SAndroid Build Coastguard Worker if (value != null && value != def) { 285*890232f2SAndroid Build Coastguard Worker _prepare(_sizeofUint64, 1); 286*890232f2SAndroid Build Coastguard Worker _trackField(field); 287*890232f2SAndroid Build Coastguard Worker _setUint64AtTail(_tail, value); 288*890232f2SAndroid Build Coastguard Worker } 289*890232f2SAndroid Build Coastguard Worker } 290*890232f2SAndroid Build Coastguard Worker 291*890232f2SAndroid Build Coastguard Worker /// Add the [field] with the given 64-bit unsigned integer [value]. The field 292*890232f2SAndroid Build Coastguard Worker /// is not added if the [value] is equal to [def]. 293*890232f2SAndroid Build Coastguard Worker void addInt64(int field, int? value, [double? def]) { 294*890232f2SAndroid Build Coastguard Worker assert(_inVTable); 295*890232f2SAndroid Build Coastguard Worker if (value != null && value != def) { 296*890232f2SAndroid Build Coastguard Worker _prepare(_sizeofInt64, 1); 297*890232f2SAndroid Build Coastguard Worker _trackField(field); 298*890232f2SAndroid Build Coastguard Worker _setInt64AtTail(_tail, value); 299*890232f2SAndroid Build Coastguard Worker } 300*890232f2SAndroid Build Coastguard Worker } 301*890232f2SAndroid Build Coastguard Worker 302*890232f2SAndroid Build Coastguard Worker /// End the current table and return its offset. 303*890232f2SAndroid Build Coastguard Worker int endTable() { 304*890232f2SAndroid Build Coastguard Worker assert(_inVTable); 305*890232f2SAndroid Build Coastguard Worker // Prepare for writing the VTable. 306*890232f2SAndroid Build Coastguard Worker _prepare(_sizeofInt32, 1); 307*890232f2SAndroid Build Coastguard Worker var tableTail = _tail; 308*890232f2SAndroid Build Coastguard Worker // Prepare the size of the current table. 309*890232f2SAndroid Build Coastguard Worker final currentVTable = _currentVTable!; 310*890232f2SAndroid Build Coastguard Worker currentVTable.tableSize = tableTail - _currentTableEndTail; 311*890232f2SAndroid Build Coastguard Worker // Prepare the VTable to use for the current table. 312*890232f2SAndroid Build Coastguard Worker int? vTableTail; 313*890232f2SAndroid Build Coastguard Worker { 314*890232f2SAndroid Build Coastguard Worker currentVTable.computeFieldOffsets(tableTail); 315*890232f2SAndroid Build Coastguard Worker 316*890232f2SAndroid Build Coastguard Worker // Try to find an existing compatible VTable. 317*890232f2SAndroid Build Coastguard Worker if (deduplicateTables) { 318*890232f2SAndroid Build Coastguard Worker // Search backward - more likely to have recently used one 319*890232f2SAndroid Build Coastguard Worker for (var i = _vTables.length - 1; i >= 0; i--) { 320*890232f2SAndroid Build Coastguard Worker final vt2Offset = _vTables[i]; 321*890232f2SAndroid Build Coastguard Worker final vt2Start = _buf.lengthInBytes - vt2Offset; 322*890232f2SAndroid Build Coastguard Worker final vt2Size = _buf.getUint16(vt2Start, Endian.little); 323*890232f2SAndroid Build Coastguard Worker 324*890232f2SAndroid Build Coastguard Worker if (currentVTable._vTableSize == vt2Size && 325*890232f2SAndroid Build Coastguard Worker currentVTable._offsetsMatch(vt2Start, _buf)) { 326*890232f2SAndroid Build Coastguard Worker vTableTail = vt2Offset; 327*890232f2SAndroid Build Coastguard Worker break; 328*890232f2SAndroid Build Coastguard Worker } 329*890232f2SAndroid Build Coastguard Worker } 330*890232f2SAndroid Build Coastguard Worker } 331*890232f2SAndroid Build Coastguard Worker 332*890232f2SAndroid Build Coastguard Worker // Write a new VTable. 333*890232f2SAndroid Build Coastguard Worker if (vTableTail == null) { 334*890232f2SAndroid Build Coastguard Worker _prepare(_sizeofUint16, _currentVTable!.numOfUint16); 335*890232f2SAndroid Build Coastguard Worker vTableTail = _tail; 336*890232f2SAndroid Build Coastguard Worker currentVTable.tail = vTableTail; 337*890232f2SAndroid Build Coastguard Worker currentVTable.output(_buf, _buf.lengthInBytes - _tail); 338*890232f2SAndroid Build Coastguard Worker if (deduplicateTables) _vTables.add(currentVTable.tail); 339*890232f2SAndroid Build Coastguard Worker } 340*890232f2SAndroid Build Coastguard Worker } 341*890232f2SAndroid Build Coastguard Worker // Set the VTable offset. 342*890232f2SAndroid Build Coastguard Worker _setInt32AtTail(tableTail, vTableTail - tableTail); 343*890232f2SAndroid Build Coastguard Worker // Done with this table. 344*890232f2SAndroid Build Coastguard Worker _currentVTable = null; 345*890232f2SAndroid Build Coastguard Worker return tableTail; 346*890232f2SAndroid Build Coastguard Worker } 347*890232f2SAndroid Build Coastguard Worker 348*890232f2SAndroid Build Coastguard Worker /// Returns the finished buffer. You must call [finish] before accessing this. 349*890232f2SAndroid Build Coastguard Worker @pragma('vm:prefer-inline') 350*890232f2SAndroid Build Coastguard Worker Uint8List get buffer { 351*890232f2SAndroid Build Coastguard Worker assert(_finished); 352*890232f2SAndroid Build Coastguard Worker final finishedSize = size(); 353*890232f2SAndroid Build Coastguard Worker return _buf.buffer 354*890232f2SAndroid Build Coastguard Worker .asUint8List(_buf.lengthInBytes - finishedSize, finishedSize); 355*890232f2SAndroid Build Coastguard Worker } 356*890232f2SAndroid Build Coastguard Worker 357*890232f2SAndroid Build Coastguard Worker /// Finish off the creation of the buffer. The given [offset] is used as the 358*890232f2SAndroid Build Coastguard Worker /// root object offset, and usually references directly or indirectly every 359*890232f2SAndroid Build Coastguard Worker /// written object. If [fileIdentifier] is specified (and not `null`), it is 360*890232f2SAndroid Build Coastguard Worker /// interpreted as a 4-byte Latin-1 encoded string that should be placed at 361*890232f2SAndroid Build Coastguard Worker /// bytes 4-7 of the file. 362*890232f2SAndroid Build Coastguard Worker void finish(int offset, [String? fileIdentifier]) { 363*890232f2SAndroid Build Coastguard Worker final sizeBeforePadding = size(); 364*890232f2SAndroid Build Coastguard Worker final requiredBytes = _sizeofUint32 * (fileIdentifier == null ? 1 : 2); 365*890232f2SAndroid Build Coastguard Worker _prepare(max(requiredBytes, _maxAlign), 1); 366*890232f2SAndroid Build Coastguard Worker final finishedSize = size(); 367*890232f2SAndroid Build Coastguard Worker _setUint32AtTail(finishedSize, finishedSize - offset); 368*890232f2SAndroid Build Coastguard Worker if (fileIdentifier != null) { 369*890232f2SAndroid Build Coastguard Worker for (var i = 0; i < 4; i++) { 370*890232f2SAndroid Build Coastguard Worker _setUint8AtTail( 371*890232f2SAndroid Build Coastguard Worker finishedSize - _sizeofUint32 - i, fileIdentifier.codeUnitAt(i)); 372*890232f2SAndroid Build Coastguard Worker } 373*890232f2SAndroid Build Coastguard Worker } 374*890232f2SAndroid Build Coastguard Worker 375*890232f2SAndroid Build Coastguard Worker // zero out the added padding 376*890232f2SAndroid Build Coastguard Worker for (var i = sizeBeforePadding + 1; 377*890232f2SAndroid Build Coastguard Worker i <= finishedSize - requiredBytes; 378*890232f2SAndroid Build Coastguard Worker i++) { 379*890232f2SAndroid Build Coastguard Worker _setUint8AtTail(i, 0); 380*890232f2SAndroid Build Coastguard Worker } 381*890232f2SAndroid Build Coastguard Worker _finished = true; 382*890232f2SAndroid Build Coastguard Worker } 383*890232f2SAndroid Build Coastguard Worker 384*890232f2SAndroid Build Coastguard Worker /// Writes a Float64 to the tail of the buffer after preparing space for it. 385*890232f2SAndroid Build Coastguard Worker /// 386*890232f2SAndroid Build Coastguard Worker /// Updates the [offset] pointer. This method is intended for use when writing structs to the buffer. 387*890232f2SAndroid Build Coastguard Worker void putFloat64(double value) { 388*890232f2SAndroid Build Coastguard Worker _prepare(_sizeofFloat64, 1); 389*890232f2SAndroid Build Coastguard Worker _setFloat32AtTail(_tail, value); 390*890232f2SAndroid Build Coastguard Worker } 391*890232f2SAndroid Build Coastguard Worker 392*890232f2SAndroid Build Coastguard Worker /// Writes a Float32 to the tail of the buffer after preparing space for it. 393*890232f2SAndroid Build Coastguard Worker /// 394*890232f2SAndroid Build Coastguard Worker /// Updates the [offset] pointer. This method is intended for use when writing structs to the buffer. 395*890232f2SAndroid Build Coastguard Worker void putFloat32(double value) { 396*890232f2SAndroid Build Coastguard Worker _prepare(_sizeofFloat32, 1); 397*890232f2SAndroid Build Coastguard Worker _setFloat32AtTail(_tail, value); 398*890232f2SAndroid Build Coastguard Worker } 399*890232f2SAndroid Build Coastguard Worker 400*890232f2SAndroid Build Coastguard Worker /// Writes a bool to the tail of the buffer after preparing space for it. 401*890232f2SAndroid Build Coastguard Worker /// Bools are represented as a Uint8, with the value set to '1' for true, and '0' for false 402*890232f2SAndroid Build Coastguard Worker /// 403*890232f2SAndroid Build Coastguard Worker /// Updates the [offset] pointer. This method is intended for use when writing structs to the buffer. 404*890232f2SAndroid Build Coastguard Worker void putBool(bool value) { 405*890232f2SAndroid Build Coastguard Worker _prepare(_sizeofUint8, 1); 406*890232f2SAndroid Build Coastguard Worker _buf.setInt8(_buf.lengthInBytes - _tail, value ? 1 : 0); 407*890232f2SAndroid Build Coastguard Worker } 408*890232f2SAndroid Build Coastguard Worker 409*890232f2SAndroid Build Coastguard Worker /// Writes a Int64 to the tail of the buffer after preparing space for it. 410*890232f2SAndroid Build Coastguard Worker /// 411*890232f2SAndroid Build Coastguard Worker /// Updates the [offset] pointer. This method is intended for use when writing structs to the buffer. 412*890232f2SAndroid Build Coastguard Worker void putInt64(int value) { 413*890232f2SAndroid Build Coastguard Worker _prepare(_sizeofInt64, 1); 414*890232f2SAndroid Build Coastguard Worker _setInt64AtTail(_tail, value); 415*890232f2SAndroid Build Coastguard Worker } 416*890232f2SAndroid Build Coastguard Worker 417*890232f2SAndroid Build Coastguard Worker /// Writes a Uint32 to the tail of the buffer after preparing space for it. 418*890232f2SAndroid Build Coastguard Worker /// 419*890232f2SAndroid Build Coastguard Worker /// Updates the [offset] pointer. This method is intended for use when writing structs to the buffer. 420*890232f2SAndroid Build Coastguard Worker void putInt32(int value) { 421*890232f2SAndroid Build Coastguard Worker _prepare(_sizeofInt32, 1); 422*890232f2SAndroid Build Coastguard Worker _setInt32AtTail(_tail, value); 423*890232f2SAndroid Build Coastguard Worker } 424*890232f2SAndroid Build Coastguard Worker 425*890232f2SAndroid Build Coastguard Worker /// Writes a Uint16 to the tail of the buffer after preparing space for it. 426*890232f2SAndroid Build Coastguard Worker /// 427*890232f2SAndroid Build Coastguard Worker /// Updates the [offset] pointer. This method is intended for use when writing structs to the buffer. 428*890232f2SAndroid Build Coastguard Worker void putInt16(int value) { 429*890232f2SAndroid Build Coastguard Worker _prepare(_sizeofInt16, 1); 430*890232f2SAndroid Build Coastguard Worker _setInt16AtTail(_tail, value); 431*890232f2SAndroid Build Coastguard Worker } 432*890232f2SAndroid Build Coastguard Worker 433*890232f2SAndroid Build Coastguard Worker /// Writes a Uint8 to the tail of the buffer after preparing space for it. 434*890232f2SAndroid Build Coastguard Worker /// 435*890232f2SAndroid Build Coastguard Worker /// Updates the [offset] pointer. This method is intended for use when writing structs to the buffer. 436*890232f2SAndroid Build Coastguard Worker void putInt8(int value) { 437*890232f2SAndroid Build Coastguard Worker _prepare(_sizeofInt8, 1); 438*890232f2SAndroid Build Coastguard Worker _buf.setInt8(_buf.lengthInBytes - _tail, value); 439*890232f2SAndroid Build Coastguard Worker } 440*890232f2SAndroid Build Coastguard Worker 441*890232f2SAndroid Build Coastguard Worker /// Writes a Uint64 to the tail of the buffer after preparing space for it. 442*890232f2SAndroid Build Coastguard Worker /// 443*890232f2SAndroid Build Coastguard Worker /// Updates the [offset] pointer. This method is intended for use when writing structs to the buffer. 444*890232f2SAndroid Build Coastguard Worker void putUint64(int value) { 445*890232f2SAndroid Build Coastguard Worker _prepare(_sizeofUint64, 1); 446*890232f2SAndroid Build Coastguard Worker _setUint64AtTail(_tail, value); 447*890232f2SAndroid Build Coastguard Worker } 448*890232f2SAndroid Build Coastguard Worker 449*890232f2SAndroid Build Coastguard Worker /// Writes a Uint32 to the tail of the buffer after preparing space for it. 450*890232f2SAndroid Build Coastguard Worker /// 451*890232f2SAndroid Build Coastguard Worker /// Updates the [offset] pointer. This method is intended for use when writing structs to the buffer. 452*890232f2SAndroid Build Coastguard Worker void putUint32(int value) { 453*890232f2SAndroid Build Coastguard Worker _prepare(_sizeofUint32, 1); 454*890232f2SAndroid Build Coastguard Worker _setUint32AtTail(_tail, value); 455*890232f2SAndroid Build Coastguard Worker } 456*890232f2SAndroid Build Coastguard Worker 457*890232f2SAndroid Build Coastguard Worker /// Writes a Uint16 to the tail of the buffer after preparing space for it. 458*890232f2SAndroid Build Coastguard Worker /// 459*890232f2SAndroid Build Coastguard Worker /// Updates the [offset] pointer. This method is intended for use when writing structs to the buffer. 460*890232f2SAndroid Build Coastguard Worker void putUint16(int value) { 461*890232f2SAndroid Build Coastguard Worker _prepare(_sizeofUint16, 1); 462*890232f2SAndroid Build Coastguard Worker _setUint16AtTail(_tail, value); 463*890232f2SAndroid Build Coastguard Worker } 464*890232f2SAndroid Build Coastguard Worker 465*890232f2SAndroid Build Coastguard Worker /// Writes a Uint8 to the tail of the buffer after preparing space for it. 466*890232f2SAndroid Build Coastguard Worker /// 467*890232f2SAndroid Build Coastguard Worker /// Updates the [offset] pointer. This method is intended for use when writing structs to the buffer. 468*890232f2SAndroid Build Coastguard Worker void putUint8(int value) { 469*890232f2SAndroid Build Coastguard Worker _prepare(_sizeofUint8, 1); 470*890232f2SAndroid Build Coastguard Worker _buf.setUint8(_buf.lengthInBytes - _tail, value); 471*890232f2SAndroid Build Coastguard Worker } 472*890232f2SAndroid Build Coastguard Worker 473*890232f2SAndroid Build Coastguard Worker /// Reset the builder and make it ready for filling a new buffer. 474*890232f2SAndroid Build Coastguard Worker void reset() { 475*890232f2SAndroid Build Coastguard Worker _finished = false; 476*890232f2SAndroid Build Coastguard Worker _maxAlign = 1; 477*890232f2SAndroid Build Coastguard Worker _tail = 0; 478*890232f2SAndroid Build Coastguard Worker _currentVTable = null; 479*890232f2SAndroid Build Coastguard Worker if (deduplicateTables) _vTables.clear(); 480*890232f2SAndroid Build Coastguard Worker if (_strings != null) { 481*890232f2SAndroid Build Coastguard Worker _strings = <String, int>{}; 482*890232f2SAndroid Build Coastguard Worker } 483*890232f2SAndroid Build Coastguard Worker } 484*890232f2SAndroid Build Coastguard Worker 485*890232f2SAndroid Build Coastguard Worker /// Start a new table. Must be finished with [endTable] invocation. 486*890232f2SAndroid Build Coastguard Worker void startTable(int numFields) { 487*890232f2SAndroid Build Coastguard Worker assert(!_inVTable); // Inline tables are not supported. 488*890232f2SAndroid Build Coastguard Worker _currentVTable = _VTable(numFields); 489*890232f2SAndroid Build Coastguard Worker _currentTableEndTail = _tail; 490*890232f2SAndroid Build Coastguard Worker } 491*890232f2SAndroid Build Coastguard Worker 492*890232f2SAndroid Build Coastguard Worker /// Finish a Struct vector. Most callers should preferto use [writeListOfStructs]. 493*890232f2SAndroid Build Coastguard Worker /// 494*890232f2SAndroid Build Coastguard Worker /// Most callers should prefer [writeListOfStructs]. 495*890232f2SAndroid Build Coastguard Worker int endStructVector(int count) { 496*890232f2SAndroid Build Coastguard Worker putUint32(count); 497*890232f2SAndroid Build Coastguard Worker return _tail; 498*890232f2SAndroid Build Coastguard Worker } 499*890232f2SAndroid Build Coastguard Worker 500*890232f2SAndroid Build Coastguard Worker /// Writes a list of Structs to the buffer, returning the offset 501*890232f2SAndroid Build Coastguard Worker int writeListOfStructs(List<ObjectBuilder> structBuilders) { 502*890232f2SAndroid Build Coastguard Worker assert(!_inVTable); 503*890232f2SAndroid Build Coastguard Worker for (var i = structBuilders.length - 1; i >= 0; i--) { 504*890232f2SAndroid Build Coastguard Worker structBuilders[i].finish(this); 505*890232f2SAndroid Build Coastguard Worker } 506*890232f2SAndroid Build Coastguard Worker return endStructVector(structBuilders.length); 507*890232f2SAndroid Build Coastguard Worker } 508*890232f2SAndroid Build Coastguard Worker 509*890232f2SAndroid Build Coastguard Worker /// Write the given list of [values]. 510*890232f2SAndroid Build Coastguard Worker int writeList(List<int> values) { 511*890232f2SAndroid Build Coastguard Worker assert(!_inVTable); 512*890232f2SAndroid Build Coastguard Worker _prepare(_sizeofUint32, 1 + values.length); 513*890232f2SAndroid Build Coastguard Worker final result = _tail; 514*890232f2SAndroid Build Coastguard Worker var tail = _tail; 515*890232f2SAndroid Build Coastguard Worker _setUint32AtTail(tail, values.length); 516*890232f2SAndroid Build Coastguard Worker tail -= _sizeofUint32; 517*890232f2SAndroid Build Coastguard Worker for (var value in values) { 518*890232f2SAndroid Build Coastguard Worker _setUint32AtTail(tail, tail - value); 519*890232f2SAndroid Build Coastguard Worker tail -= _sizeofUint32; 520*890232f2SAndroid Build Coastguard Worker } 521*890232f2SAndroid Build Coastguard Worker return result; 522*890232f2SAndroid Build Coastguard Worker } 523*890232f2SAndroid Build Coastguard Worker 524*890232f2SAndroid Build Coastguard Worker /// Write the given list of 64-bit float [values]. 525*890232f2SAndroid Build Coastguard Worker int writeListFloat64(List<double> values) { 526*890232f2SAndroid Build Coastguard Worker assert(!_inVTable); 527*890232f2SAndroid Build Coastguard Worker _prepare(_sizeofFloat64, values.length, additionalBytes: _sizeofUint32); 528*890232f2SAndroid Build Coastguard Worker final result = _tail; 529*890232f2SAndroid Build Coastguard Worker var tail = _tail; 530*890232f2SAndroid Build Coastguard Worker _setUint32AtTail(tail, values.length); 531*890232f2SAndroid Build Coastguard Worker tail -= _sizeofUint32; 532*890232f2SAndroid Build Coastguard Worker for (var value in values) { 533*890232f2SAndroid Build Coastguard Worker _setFloat64AtTail(tail, value); 534*890232f2SAndroid Build Coastguard Worker tail -= _sizeofFloat64; 535*890232f2SAndroid Build Coastguard Worker } 536*890232f2SAndroid Build Coastguard Worker return result; 537*890232f2SAndroid Build Coastguard Worker } 538*890232f2SAndroid Build Coastguard Worker 539*890232f2SAndroid Build Coastguard Worker /// Write the given list of 32-bit float [values]. 540*890232f2SAndroid Build Coastguard Worker int writeListFloat32(List<double> values) { 541*890232f2SAndroid Build Coastguard Worker assert(!_inVTable); 542*890232f2SAndroid Build Coastguard Worker _prepare(_sizeofFloat32, 1 + values.length); 543*890232f2SAndroid Build Coastguard Worker final result = _tail; 544*890232f2SAndroid Build Coastguard Worker var tail = _tail; 545*890232f2SAndroid Build Coastguard Worker _setUint32AtTail(tail, values.length); 546*890232f2SAndroid Build Coastguard Worker tail -= _sizeofUint32; 547*890232f2SAndroid Build Coastguard Worker for (var value in values) { 548*890232f2SAndroid Build Coastguard Worker _setFloat32AtTail(tail, value); 549*890232f2SAndroid Build Coastguard Worker tail -= _sizeofFloat32; 550*890232f2SAndroid Build Coastguard Worker } 551*890232f2SAndroid Build Coastguard Worker return result; 552*890232f2SAndroid Build Coastguard Worker } 553*890232f2SAndroid Build Coastguard Worker 554*890232f2SAndroid Build Coastguard Worker /// Write the given list of signed 64-bit integer [values]. 555*890232f2SAndroid Build Coastguard Worker int writeListInt64(List<int> values) { 556*890232f2SAndroid Build Coastguard Worker assert(!_inVTable); 557*890232f2SAndroid Build Coastguard Worker _prepare(_sizeofInt64, values.length, additionalBytes: _sizeofUint32); 558*890232f2SAndroid Build Coastguard Worker final result = _tail; 559*890232f2SAndroid Build Coastguard Worker var tail = _tail; 560*890232f2SAndroid Build Coastguard Worker _setUint32AtTail(tail, values.length); 561*890232f2SAndroid Build Coastguard Worker tail -= _sizeofUint32; 562*890232f2SAndroid Build Coastguard Worker for (var value in values) { 563*890232f2SAndroid Build Coastguard Worker _setInt64AtTail(tail, value); 564*890232f2SAndroid Build Coastguard Worker tail -= _sizeofInt64; 565*890232f2SAndroid Build Coastguard Worker } 566*890232f2SAndroid Build Coastguard Worker return result; 567*890232f2SAndroid Build Coastguard Worker } 568*890232f2SAndroid Build Coastguard Worker 569*890232f2SAndroid Build Coastguard Worker /// Write the given list of signed 64-bit integer [values]. 570*890232f2SAndroid Build Coastguard Worker int writeListUint64(List<int> values) { 571*890232f2SAndroid Build Coastguard Worker assert(!_inVTable); 572*890232f2SAndroid Build Coastguard Worker _prepare(_sizeofUint64, values.length, additionalBytes: _sizeofUint32); 573*890232f2SAndroid Build Coastguard Worker final result = _tail; 574*890232f2SAndroid Build Coastguard Worker var tail = _tail; 575*890232f2SAndroid Build Coastguard Worker _setUint32AtTail(tail, values.length); 576*890232f2SAndroid Build Coastguard Worker tail -= _sizeofUint32; 577*890232f2SAndroid Build Coastguard Worker for (var value in values) { 578*890232f2SAndroid Build Coastguard Worker _setUint64AtTail(tail, value); 579*890232f2SAndroid Build Coastguard Worker tail -= _sizeofUint64; 580*890232f2SAndroid Build Coastguard Worker } 581*890232f2SAndroid Build Coastguard Worker return result; 582*890232f2SAndroid Build Coastguard Worker } 583*890232f2SAndroid Build Coastguard Worker 584*890232f2SAndroid Build Coastguard Worker /// Write the given list of signed 32-bit integer [values]. 585*890232f2SAndroid Build Coastguard Worker int writeListInt32(List<int> values) { 586*890232f2SAndroid Build Coastguard Worker assert(!_inVTable); 587*890232f2SAndroid Build Coastguard Worker _prepare(_sizeofUint32, 1 + values.length); 588*890232f2SAndroid Build Coastguard Worker final result = _tail; 589*890232f2SAndroid Build Coastguard Worker var tail = _tail; 590*890232f2SAndroid Build Coastguard Worker _setUint32AtTail(tail, values.length); 591*890232f2SAndroid Build Coastguard Worker tail -= _sizeofUint32; 592*890232f2SAndroid Build Coastguard Worker for (var value in values) { 593*890232f2SAndroid Build Coastguard Worker _setInt32AtTail(tail, value); 594*890232f2SAndroid Build Coastguard Worker tail -= _sizeofInt32; 595*890232f2SAndroid Build Coastguard Worker } 596*890232f2SAndroid Build Coastguard Worker return result; 597*890232f2SAndroid Build Coastguard Worker } 598*890232f2SAndroid Build Coastguard Worker 599*890232f2SAndroid Build Coastguard Worker /// Write the given list of unsigned 32-bit integer [values]. 600*890232f2SAndroid Build Coastguard Worker int writeListUint32(List<int> values) { 601*890232f2SAndroid Build Coastguard Worker assert(!_inVTable); 602*890232f2SAndroid Build Coastguard Worker _prepare(_sizeofUint32, 1 + values.length); 603*890232f2SAndroid Build Coastguard Worker final result = _tail; 604*890232f2SAndroid Build Coastguard Worker var tail = _tail; 605*890232f2SAndroid Build Coastguard Worker _setUint32AtTail(tail, values.length); 606*890232f2SAndroid Build Coastguard Worker tail -= _sizeofUint32; 607*890232f2SAndroid Build Coastguard Worker for (var value in values) { 608*890232f2SAndroid Build Coastguard Worker _setUint32AtTail(tail, value); 609*890232f2SAndroid Build Coastguard Worker tail -= _sizeofUint32; 610*890232f2SAndroid Build Coastguard Worker } 611*890232f2SAndroid Build Coastguard Worker return result; 612*890232f2SAndroid Build Coastguard Worker } 613*890232f2SAndroid Build Coastguard Worker 614*890232f2SAndroid Build Coastguard Worker /// Write the given list of signed 16-bit integer [values]. 615*890232f2SAndroid Build Coastguard Worker int writeListInt16(List<int> values) { 616*890232f2SAndroid Build Coastguard Worker assert(!_inVTable); 617*890232f2SAndroid Build Coastguard Worker _prepare(_sizeofUint32, 1, additionalBytes: 2 * values.length); 618*890232f2SAndroid Build Coastguard Worker final result = _tail; 619*890232f2SAndroid Build Coastguard Worker var tail = _tail; 620*890232f2SAndroid Build Coastguard Worker _setUint32AtTail(tail, values.length); 621*890232f2SAndroid Build Coastguard Worker tail -= _sizeofUint32; 622*890232f2SAndroid Build Coastguard Worker for (var value in values) { 623*890232f2SAndroid Build Coastguard Worker _setInt16AtTail(tail, value); 624*890232f2SAndroid Build Coastguard Worker tail -= _sizeofInt16; 625*890232f2SAndroid Build Coastguard Worker } 626*890232f2SAndroid Build Coastguard Worker return result; 627*890232f2SAndroid Build Coastguard Worker } 628*890232f2SAndroid Build Coastguard Worker 629*890232f2SAndroid Build Coastguard Worker /// Write the given list of unsigned 16-bit integer [values]. 630*890232f2SAndroid Build Coastguard Worker int writeListUint16(List<int> values) { 631*890232f2SAndroid Build Coastguard Worker assert(!_inVTable); 632*890232f2SAndroid Build Coastguard Worker _prepare(_sizeofUint32, 1, additionalBytes: 2 * values.length); 633*890232f2SAndroid Build Coastguard Worker final result = _tail; 634*890232f2SAndroid Build Coastguard Worker var tail = _tail; 635*890232f2SAndroid Build Coastguard Worker _setUint32AtTail(tail, values.length); 636*890232f2SAndroid Build Coastguard Worker tail -= _sizeofUint32; 637*890232f2SAndroid Build Coastguard Worker for (var value in values) { 638*890232f2SAndroid Build Coastguard Worker _setUint16AtTail(tail, value); 639*890232f2SAndroid Build Coastguard Worker tail -= _sizeofUint16; 640*890232f2SAndroid Build Coastguard Worker } 641*890232f2SAndroid Build Coastguard Worker return result; 642*890232f2SAndroid Build Coastguard Worker } 643*890232f2SAndroid Build Coastguard Worker 644*890232f2SAndroid Build Coastguard Worker /// Write the given list of bools as unsigend 8-bit integer [values]. 645*890232f2SAndroid Build Coastguard Worker int writeListBool(List<bool> values) { 646*890232f2SAndroid Build Coastguard Worker return writeListUint8(values.map((b) => b ? 1 : 0).toList()); 647*890232f2SAndroid Build Coastguard Worker } 648*890232f2SAndroid Build Coastguard Worker 649*890232f2SAndroid Build Coastguard Worker /// Write the given list of signed 8-bit integer [values]. 650*890232f2SAndroid Build Coastguard Worker int writeListInt8(List<int> values) { 651*890232f2SAndroid Build Coastguard Worker assert(!_inVTable); 652*890232f2SAndroid Build Coastguard Worker _prepare(_sizeofUint32, 1, additionalBytes: values.length); 653*890232f2SAndroid Build Coastguard Worker final result = _tail; 654*890232f2SAndroid Build Coastguard Worker var tail = _tail; 655*890232f2SAndroid Build Coastguard Worker _setUint32AtTail(tail, values.length); 656*890232f2SAndroid Build Coastguard Worker tail -= _sizeofUint32; 657*890232f2SAndroid Build Coastguard Worker for (var value in values) { 658*890232f2SAndroid Build Coastguard Worker _setInt8AtTail(tail, value); 659*890232f2SAndroid Build Coastguard Worker tail -= _sizeofUint8; 660*890232f2SAndroid Build Coastguard Worker } 661*890232f2SAndroid Build Coastguard Worker return result; 662*890232f2SAndroid Build Coastguard Worker } 663*890232f2SAndroid Build Coastguard Worker 664*890232f2SAndroid Build Coastguard Worker /// Write the given list of unsigned 8-bit integer [values]. 665*890232f2SAndroid Build Coastguard Worker int writeListUint8(List<int> values) { 666*890232f2SAndroid Build Coastguard Worker assert(!_inVTable); 667*890232f2SAndroid Build Coastguard Worker _prepare(_sizeofUint32, 1, additionalBytes: values.length); 668*890232f2SAndroid Build Coastguard Worker final result = _tail; 669*890232f2SAndroid Build Coastguard Worker var tail = _tail; 670*890232f2SAndroid Build Coastguard Worker _setUint32AtTail(tail, values.length); 671*890232f2SAndroid Build Coastguard Worker tail -= _sizeofUint32; 672*890232f2SAndroid Build Coastguard Worker for (var value in values) { 673*890232f2SAndroid Build Coastguard Worker _setUint8AtTail(tail, value); 674*890232f2SAndroid Build Coastguard Worker tail -= _sizeofUint8; 675*890232f2SAndroid Build Coastguard Worker } 676*890232f2SAndroid Build Coastguard Worker return result; 677*890232f2SAndroid Build Coastguard Worker } 678*890232f2SAndroid Build Coastguard Worker 679*890232f2SAndroid Build Coastguard Worker /// Write the given string [value] and return its offset. 680*890232f2SAndroid Build Coastguard Worker /// 681*890232f2SAndroid Build Coastguard Worker /// Dart strings are UTF-16 but must be stored as UTF-8 in FlatBuffers. 682*890232f2SAndroid Build Coastguard Worker /// If the given string consists only of ASCII characters, you can indicate 683*890232f2SAndroid Build Coastguard Worker /// enable [asciiOptimization]. In this mode, [writeString()] first tries to 684*890232f2SAndroid Build Coastguard Worker /// copy the ASCII string directly to the output buffer and if that fails 685*890232f2SAndroid Build Coastguard Worker /// (because there are no-ASCII characters in the string) it falls back and to 686*890232f2SAndroid Build Coastguard Worker /// the default UTF-16 -> UTF-8 conversion (with slight performance penalty). 687*890232f2SAndroid Build Coastguard Worker int writeString(String value, {bool asciiOptimization = false}) { 688*890232f2SAndroid Build Coastguard Worker assert(!_inVTable); 689*890232f2SAndroid Build Coastguard Worker if (_strings != null) { 690*890232f2SAndroid Build Coastguard Worker return _strings! 691*890232f2SAndroid Build Coastguard Worker .putIfAbsent(value, () => _writeString(value, asciiOptimization)); 692*890232f2SAndroid Build Coastguard Worker } else { 693*890232f2SAndroid Build Coastguard Worker return _writeString(value, asciiOptimization); 694*890232f2SAndroid Build Coastguard Worker } 695*890232f2SAndroid Build Coastguard Worker } 696*890232f2SAndroid Build Coastguard Worker 697*890232f2SAndroid Build Coastguard Worker int _writeString(String value, bool asciiOptimization) { 698*890232f2SAndroid Build Coastguard Worker if (asciiOptimization) { 699*890232f2SAndroid Build Coastguard Worker // [utf8.encode()] is slow (up to at least Dart SDK 2.13). If the given 700*890232f2SAndroid Build Coastguard Worker // string is ASCII we can just write it directly, without any conversion. 701*890232f2SAndroid Build Coastguard Worker final originalTail = _tail; 702*890232f2SAndroid Build Coastguard Worker if (_tryWriteASCIIString(value)) return _tail; 703*890232f2SAndroid Build Coastguard Worker // if non-ASCII: reset the output buffer position for [_writeUTFString()] 704*890232f2SAndroid Build Coastguard Worker _tail = originalTail; 705*890232f2SAndroid Build Coastguard Worker } 706*890232f2SAndroid Build Coastguard Worker _writeUTFString(value); 707*890232f2SAndroid Build Coastguard Worker return _tail; 708*890232f2SAndroid Build Coastguard Worker } 709*890232f2SAndroid Build Coastguard Worker 710*890232f2SAndroid Build Coastguard Worker // Try to write the string as ASCII, return false if there's a non-ascii char. 711*890232f2SAndroid Build Coastguard Worker @pragma('vm:prefer-inline') 712*890232f2SAndroid Build Coastguard Worker bool _tryWriteASCIIString(String value) { 713*890232f2SAndroid Build Coastguard Worker _prepare(4, 1, additionalBytes: value.length + 1); 714*890232f2SAndroid Build Coastguard Worker final length = value.length; 715*890232f2SAndroid Build Coastguard Worker var offset = _buf.lengthInBytes - _tail + 4; 716*890232f2SAndroid Build Coastguard Worker for (var i = 0; i < length; i++) { 717*890232f2SAndroid Build Coastguard Worker // utf16 code unit, e.g. for '†' it's [0x20 0x20], which is 8224 decimal. 718*890232f2SAndroid Build Coastguard Worker // ASCII characters go from 0x00 to 0x7F (which is 0 to 127 decimal). 719*890232f2SAndroid Build Coastguard Worker final char = value.codeUnitAt(i); 720*890232f2SAndroid Build Coastguard Worker if ((char & ~0x7F) != 0) { 721*890232f2SAndroid Build Coastguard Worker return false; 722*890232f2SAndroid Build Coastguard Worker } 723*890232f2SAndroid Build Coastguard Worker _buf.setUint8(offset++, char); 724*890232f2SAndroid Build Coastguard Worker } 725*890232f2SAndroid Build Coastguard Worker _buf.setUint8(offset, 0); // trailing zero 726*890232f2SAndroid Build Coastguard Worker _setUint32AtTail(_tail, value.length); 727*890232f2SAndroid Build Coastguard Worker return true; 728*890232f2SAndroid Build Coastguard Worker } 729*890232f2SAndroid Build Coastguard Worker 730*890232f2SAndroid Build Coastguard Worker @pragma('vm:prefer-inline') 731*890232f2SAndroid Build Coastguard Worker void _writeUTFString(String value) { 732*890232f2SAndroid Build Coastguard Worker final bytes = utf8.encode(value) as Uint8List; 733*890232f2SAndroid Build Coastguard Worker final length = bytes.length; 734*890232f2SAndroid Build Coastguard Worker _prepare(4, 1, additionalBytes: length + 1); 735*890232f2SAndroid Build Coastguard Worker _setUint32AtTail(_tail, length); 736*890232f2SAndroid Build Coastguard Worker var offset = _buf.lengthInBytes - _tail + 4; 737*890232f2SAndroid Build Coastguard Worker for (var i = 0; i < length; i++) { 738*890232f2SAndroid Build Coastguard Worker _buf.setUint8(offset++, bytes[i]); 739*890232f2SAndroid Build Coastguard Worker } 740*890232f2SAndroid Build Coastguard Worker _buf.setUint8(offset, 0); // trailing zero 741*890232f2SAndroid Build Coastguard Worker } 742*890232f2SAndroid Build Coastguard Worker 743*890232f2SAndroid Build Coastguard Worker /// Used to assert whether a "Table" is currently being built. 744*890232f2SAndroid Build Coastguard Worker /// 745*890232f2SAndroid Build Coastguard Worker /// If you hit `assert(!_inVTable())`, you're trying to add table fields 746*890232f2SAndroid Build Coastguard Worker /// without starting a table with [Builder.startTable()]. 747*890232f2SAndroid Build Coastguard Worker /// 748*890232f2SAndroid Build Coastguard Worker /// If you hit `assert(_inVTable())`, you're trying to construct a 749*890232f2SAndroid Build Coastguard Worker /// Table/Vector/String during the construction of its parent table, 750*890232f2SAndroid Build Coastguard Worker /// between the MyTableBuilder and [Builder.endTable()]. 751*890232f2SAndroid Build Coastguard Worker /// Move the creation of these sub-objects to before the MyTableBuilder to 752*890232f2SAndroid Build Coastguard Worker /// not get this assert. 753*890232f2SAndroid Build Coastguard Worker @pragma('vm:prefer-inline') 754*890232f2SAndroid Build Coastguard Worker bool get _inVTable => _currentVTable != null; 755*890232f2SAndroid Build Coastguard Worker 756*890232f2SAndroid Build Coastguard Worker /// The number of bytes that have been written to the buffer so far. The 757*890232f2SAndroid Build Coastguard Worker /// most recently written byte is this many bytes from the end of the buffer. 758*890232f2SAndroid Build Coastguard Worker @pragma('vm:prefer-inline') 759*890232f2SAndroid Build Coastguard Worker int get offset => _tail; 760*890232f2SAndroid Build Coastguard Worker 761*890232f2SAndroid Build Coastguard Worker /// Zero-pads the buffer, which may be required for some struct layouts. 762*890232f2SAndroid Build Coastguard Worker @pragma('vm:prefer-inline') 763*890232f2SAndroid Build Coastguard Worker void pad(int howManyBytes) { 764*890232f2SAndroid Build Coastguard Worker for (var i = 0; i < howManyBytes; i++) { 765*890232f2SAndroid Build Coastguard Worker putUint8(0); 766*890232f2SAndroid Build Coastguard Worker } 767*890232f2SAndroid Build Coastguard Worker } 768*890232f2SAndroid Build Coastguard Worker 769*890232f2SAndroid Build Coastguard Worker /// Prepare for writing the given `count` of scalars of the given `size`. 770*890232f2SAndroid Build Coastguard Worker /// Additionally allocate the specified `additionalBytes`. Update the current 771*890232f2SAndroid Build Coastguard Worker /// tail pointer to point at the allocated space. 772*890232f2SAndroid Build Coastguard Worker @pragma('vm:prefer-inline') 773*890232f2SAndroid Build Coastguard Worker void _prepare(int size, int count, {int additionalBytes = 0}) { 774*890232f2SAndroid Build Coastguard Worker assert(!_finished); 775*890232f2SAndroid Build Coastguard Worker // Update the alignment. 776*890232f2SAndroid Build Coastguard Worker if (_maxAlign < size) { 777*890232f2SAndroid Build Coastguard Worker _maxAlign = size; 778*890232f2SAndroid Build Coastguard Worker } 779*890232f2SAndroid Build Coastguard Worker // Prepare amount of required space. 780*890232f2SAndroid Build Coastguard Worker var dataSize = size * count + additionalBytes; 781*890232f2SAndroid Build Coastguard Worker var alignDelta = (-(_tail + dataSize)) & (size - 1); 782*890232f2SAndroid Build Coastguard Worker var bufSize = alignDelta + dataSize; 783*890232f2SAndroid Build Coastguard Worker // Ensure that we have the required amount of space. 784*890232f2SAndroid Build Coastguard Worker { 785*890232f2SAndroid Build Coastguard Worker var oldCapacity = _buf.lengthInBytes; 786*890232f2SAndroid Build Coastguard Worker if (_tail + bufSize > oldCapacity) { 787*890232f2SAndroid Build Coastguard Worker var desiredNewCapacity = (oldCapacity + bufSize) * 2; 788*890232f2SAndroid Build Coastguard Worker var deltaCapacity = desiredNewCapacity - oldCapacity; 789*890232f2SAndroid Build Coastguard Worker deltaCapacity += (-deltaCapacity) & (_maxAlign - 1); 790*890232f2SAndroid Build Coastguard Worker var newCapacity = oldCapacity + deltaCapacity; 791*890232f2SAndroid Build Coastguard Worker _buf = _allocator.resize(_buf, newCapacity, _tail, 0); 792*890232f2SAndroid Build Coastguard Worker } 793*890232f2SAndroid Build Coastguard Worker } 794*890232f2SAndroid Build Coastguard Worker 795*890232f2SAndroid Build Coastguard Worker // zero out the added padding 796*890232f2SAndroid Build Coastguard Worker for (var i = _tail + 1; i <= _tail + alignDelta; i++) { 797*890232f2SAndroid Build Coastguard Worker _setUint8AtTail(i, 0); 798*890232f2SAndroid Build Coastguard Worker } 799*890232f2SAndroid Build Coastguard Worker 800*890232f2SAndroid Build Coastguard Worker // Update the tail pointer. 801*890232f2SAndroid Build Coastguard Worker _tail += bufSize; 802*890232f2SAndroid Build Coastguard Worker } 803*890232f2SAndroid Build Coastguard Worker 804*890232f2SAndroid Build Coastguard Worker /// Record the offset of the given [field]. 805*890232f2SAndroid Build Coastguard Worker @pragma('vm:prefer-inline') 806*890232f2SAndroid Build Coastguard Worker void _trackField(int field) => _currentVTable!.addField(field, _tail); 807*890232f2SAndroid Build Coastguard Worker 808*890232f2SAndroid Build Coastguard Worker @pragma('vm:prefer-inline') 809*890232f2SAndroid Build Coastguard Worker void _setFloat64AtTail(int tail, double x) => 810*890232f2SAndroid Build Coastguard Worker _buf.setFloat64(_buf.lengthInBytes - tail, x, Endian.little); 811*890232f2SAndroid Build Coastguard Worker 812*890232f2SAndroid Build Coastguard Worker @pragma('vm:prefer-inline') 813*890232f2SAndroid Build Coastguard Worker void _setFloat32AtTail(int tail, double x) => 814*890232f2SAndroid Build Coastguard Worker _buf.setFloat32(_buf.lengthInBytes - tail, x, Endian.little); 815*890232f2SAndroid Build Coastguard Worker 816*890232f2SAndroid Build Coastguard Worker @pragma('vm:prefer-inline') 817*890232f2SAndroid Build Coastguard Worker void _setUint64AtTail(int tail, int x) => 818*890232f2SAndroid Build Coastguard Worker _buf.setUint64(_buf.lengthInBytes - tail, x, Endian.little); 819*890232f2SAndroid Build Coastguard Worker 820*890232f2SAndroid Build Coastguard Worker @pragma('vm:prefer-inline') 821*890232f2SAndroid Build Coastguard Worker void _setInt64AtTail(int tail, int x) => 822*890232f2SAndroid Build Coastguard Worker _buf.setInt64(_buf.lengthInBytes - tail, x, Endian.little); 823*890232f2SAndroid Build Coastguard Worker 824*890232f2SAndroid Build Coastguard Worker @pragma('vm:prefer-inline') 825*890232f2SAndroid Build Coastguard Worker void _setInt32AtTail(int tail, int x) => 826*890232f2SAndroid Build Coastguard Worker _buf.setInt32(_buf.lengthInBytes - tail, x, Endian.little); 827*890232f2SAndroid Build Coastguard Worker 828*890232f2SAndroid Build Coastguard Worker @pragma('vm:prefer-inline') 829*890232f2SAndroid Build Coastguard Worker void _setUint32AtTail(int tail, int x) => 830*890232f2SAndroid Build Coastguard Worker _buf.setUint32(_buf.lengthInBytes - tail, x, Endian.little); 831*890232f2SAndroid Build Coastguard Worker 832*890232f2SAndroid Build Coastguard Worker @pragma('vm:prefer-inline') 833*890232f2SAndroid Build Coastguard Worker void _setInt16AtTail(int tail, int x) => 834*890232f2SAndroid Build Coastguard Worker _buf.setInt16(_buf.lengthInBytes - tail, x, Endian.little); 835*890232f2SAndroid Build Coastguard Worker 836*890232f2SAndroid Build Coastguard Worker @pragma('vm:prefer-inline') 837*890232f2SAndroid Build Coastguard Worker void _setUint16AtTail(int tail, int x) => 838*890232f2SAndroid Build Coastguard Worker _buf.setUint16(_buf.lengthInBytes - tail, x, Endian.little); 839*890232f2SAndroid Build Coastguard Worker 840*890232f2SAndroid Build Coastguard Worker @pragma('vm:prefer-inline') 841*890232f2SAndroid Build Coastguard Worker void _setInt8AtTail(int tail, int x) => 842*890232f2SAndroid Build Coastguard Worker _buf.setInt8(_buf.lengthInBytes - tail, x); 843*890232f2SAndroid Build Coastguard Worker 844*890232f2SAndroid Build Coastguard Worker @pragma('vm:prefer-inline') 845*890232f2SAndroid Build Coastguard Worker void _setUint8AtTail(int tail, int x) => 846*890232f2SAndroid Build Coastguard Worker _buf.setUint8(_buf.lengthInBytes - tail, x); 847*890232f2SAndroid Build Coastguard Worker} 848*890232f2SAndroid Build Coastguard Worker 849*890232f2SAndroid Build Coastguard Worker/// Reader of lists of boolean values. 850*890232f2SAndroid Build Coastguard Worker/// 851*890232f2SAndroid Build Coastguard Worker/// The returned unmodifiable lists lazily read values on access. 852*890232f2SAndroid Build Coastguard Workerclass BoolListReader extends Reader<List<bool>> { 853*890232f2SAndroid Build Coastguard Worker const BoolListReader(); 854*890232f2SAndroid Build Coastguard Worker 855*890232f2SAndroid Build Coastguard Worker @override 856*890232f2SAndroid Build Coastguard Worker @pragma('vm:prefer-inline') 857*890232f2SAndroid Build Coastguard Worker int get size => _sizeofUint32; 858*890232f2SAndroid Build Coastguard Worker 859*890232f2SAndroid Build Coastguard Worker @override 860*890232f2SAndroid Build Coastguard Worker @pragma('vm:prefer-inline') 861*890232f2SAndroid Build Coastguard Worker List<bool> read(BufferContext bc, int offset) => 862*890232f2SAndroid Build Coastguard Worker _FbBoolList(bc, bc.derefObject(offset)); 863*890232f2SAndroid Build Coastguard Worker} 864*890232f2SAndroid Build Coastguard Worker 865*890232f2SAndroid Build Coastguard Worker/// The reader of booleans. 866*890232f2SAndroid Build Coastguard Workerclass BoolReader extends Reader<bool> { 867*890232f2SAndroid Build Coastguard Worker const BoolReader() : super(); 868*890232f2SAndroid Build Coastguard Worker 869*890232f2SAndroid Build Coastguard Worker @override 870*890232f2SAndroid Build Coastguard Worker @pragma('vm:prefer-inline') 871*890232f2SAndroid Build Coastguard Worker int get size => _sizeofUint8; 872*890232f2SAndroid Build Coastguard Worker 873*890232f2SAndroid Build Coastguard Worker @override 874*890232f2SAndroid Build Coastguard Worker @pragma('vm:prefer-inline') 875*890232f2SAndroid Build Coastguard Worker bool read(BufferContext bc, int offset) => bc._getInt8(offset) != 0; 876*890232f2SAndroid Build Coastguard Worker} 877*890232f2SAndroid Build Coastguard Worker 878*890232f2SAndroid Build Coastguard Worker/// The reader of lists of 64-bit float values. 879*890232f2SAndroid Build Coastguard Worker/// 880*890232f2SAndroid Build Coastguard Worker/// The returned unmodifiable lists lazily read values on access. 881*890232f2SAndroid Build Coastguard Workerclass Float64ListReader extends Reader<List<double>> { 882*890232f2SAndroid Build Coastguard Worker const Float64ListReader(); 883*890232f2SAndroid Build Coastguard Worker 884*890232f2SAndroid Build Coastguard Worker @override 885*890232f2SAndroid Build Coastguard Worker @pragma('vm:prefer-inline') 886*890232f2SAndroid Build Coastguard Worker int get size => _sizeofFloat64; 887*890232f2SAndroid Build Coastguard Worker 888*890232f2SAndroid Build Coastguard Worker @override 889*890232f2SAndroid Build Coastguard Worker @pragma('vm:prefer-inline') 890*890232f2SAndroid Build Coastguard Worker List<double> read(BufferContext bc, int offset) => 891*890232f2SAndroid Build Coastguard Worker _FbFloat64List(bc, bc.derefObject(offset)); 892*890232f2SAndroid Build Coastguard Worker} 893*890232f2SAndroid Build Coastguard Worker 894*890232f2SAndroid Build Coastguard Workerclass Float32ListReader extends Reader<List<double>> { 895*890232f2SAndroid Build Coastguard Worker const Float32ListReader(); 896*890232f2SAndroid Build Coastguard Worker 897*890232f2SAndroid Build Coastguard Worker @override 898*890232f2SAndroid Build Coastguard Worker @pragma('vm:prefer-inline') 899*890232f2SAndroid Build Coastguard Worker int get size => _sizeofFloat32; 900*890232f2SAndroid Build Coastguard Worker 901*890232f2SAndroid Build Coastguard Worker @override 902*890232f2SAndroid Build Coastguard Worker @pragma('vm:prefer-inline') 903*890232f2SAndroid Build Coastguard Worker List<double> read(BufferContext bc, int offset) => 904*890232f2SAndroid Build Coastguard Worker _FbFloat32List(bc, bc.derefObject(offset)); 905*890232f2SAndroid Build Coastguard Worker} 906*890232f2SAndroid Build Coastguard Worker 907*890232f2SAndroid Build Coastguard Workerclass Float64Reader extends Reader<double> { 908*890232f2SAndroid Build Coastguard Worker const Float64Reader(); 909*890232f2SAndroid Build Coastguard Worker 910*890232f2SAndroid Build Coastguard Worker @override 911*890232f2SAndroid Build Coastguard Worker @pragma('vm:prefer-inline') 912*890232f2SAndroid Build Coastguard Worker int get size => _sizeofFloat64; 913*890232f2SAndroid Build Coastguard Worker 914*890232f2SAndroid Build Coastguard Worker @override 915*890232f2SAndroid Build Coastguard Worker @pragma('vm:prefer-inline') 916*890232f2SAndroid Build Coastguard Worker double read(BufferContext bc, int offset) => bc._getFloat64(offset); 917*890232f2SAndroid Build Coastguard Worker} 918*890232f2SAndroid Build Coastguard Worker 919*890232f2SAndroid Build Coastguard Workerclass Float32Reader extends Reader<double> { 920*890232f2SAndroid Build Coastguard Worker const Float32Reader(); 921*890232f2SAndroid Build Coastguard Worker 922*890232f2SAndroid Build Coastguard Worker @override 923*890232f2SAndroid Build Coastguard Worker @pragma('vm:prefer-inline') 924*890232f2SAndroid Build Coastguard Worker int get size => _sizeofFloat32; 925*890232f2SAndroid Build Coastguard Worker 926*890232f2SAndroid Build Coastguard Worker @override 927*890232f2SAndroid Build Coastguard Worker @pragma('vm:prefer-inline') 928*890232f2SAndroid Build Coastguard Worker double read(BufferContext bc, int offset) => bc._getFloat32(offset); 929*890232f2SAndroid Build Coastguard Worker} 930*890232f2SAndroid Build Coastguard Worker 931*890232f2SAndroid Build Coastguard Workerclass Int64Reader extends Reader<int> { 932*890232f2SAndroid Build Coastguard Worker const Int64Reader() : super(); 933*890232f2SAndroid Build Coastguard Worker 934*890232f2SAndroid Build Coastguard Worker @override 935*890232f2SAndroid Build Coastguard Worker @pragma('vm:prefer-inline') 936*890232f2SAndroid Build Coastguard Worker int get size => _sizeofInt64; 937*890232f2SAndroid Build Coastguard Worker 938*890232f2SAndroid Build Coastguard Worker @override 939*890232f2SAndroid Build Coastguard Worker @pragma('vm:prefer-inline') 940*890232f2SAndroid Build Coastguard Worker int read(BufferContext bc, int offset) => bc._getInt64(offset); 941*890232f2SAndroid Build Coastguard Worker} 942*890232f2SAndroid Build Coastguard Worker 943*890232f2SAndroid Build Coastguard Worker/// The reader of signed 32-bit integers. 944*890232f2SAndroid Build Coastguard Workerclass Int32Reader extends Reader<int> { 945*890232f2SAndroid Build Coastguard Worker const Int32Reader() : super(); 946*890232f2SAndroid Build Coastguard Worker 947*890232f2SAndroid Build Coastguard Worker @override 948*890232f2SAndroid Build Coastguard Worker @pragma('vm:prefer-inline') 949*890232f2SAndroid Build Coastguard Worker int get size => _sizeofInt32; 950*890232f2SAndroid Build Coastguard Worker 951*890232f2SAndroid Build Coastguard Worker @override 952*890232f2SAndroid Build Coastguard Worker @pragma('vm:prefer-inline') 953*890232f2SAndroid Build Coastguard Worker int read(BufferContext bc, int offset) => bc._getInt32(offset); 954*890232f2SAndroid Build Coastguard Worker} 955*890232f2SAndroid Build Coastguard Worker 956*890232f2SAndroid Build Coastguard Worker/// The reader of signed 32-bit integers. 957*890232f2SAndroid Build Coastguard Workerclass Int16Reader extends Reader<int> { 958*890232f2SAndroid Build Coastguard Worker const Int16Reader() : super(); 959*890232f2SAndroid Build Coastguard Worker 960*890232f2SAndroid Build Coastguard Worker @override 961*890232f2SAndroid Build Coastguard Worker @pragma('vm:prefer-inline') 962*890232f2SAndroid Build Coastguard Worker int get size => _sizeofInt16; 963*890232f2SAndroid Build Coastguard Worker 964*890232f2SAndroid Build Coastguard Worker @override 965*890232f2SAndroid Build Coastguard Worker @pragma('vm:prefer-inline') 966*890232f2SAndroid Build Coastguard Worker int read(BufferContext bc, int offset) => bc._getInt16(offset); 967*890232f2SAndroid Build Coastguard Worker} 968*890232f2SAndroid Build Coastguard Worker 969*890232f2SAndroid Build Coastguard Worker/// The reader of 8-bit signed integers. 970*890232f2SAndroid Build Coastguard Workerclass Int8Reader extends Reader<int> { 971*890232f2SAndroid Build Coastguard Worker const Int8Reader() : super(); 972*890232f2SAndroid Build Coastguard Worker 973*890232f2SAndroid Build Coastguard Worker @override 974*890232f2SAndroid Build Coastguard Worker @pragma('vm:prefer-inline') 975*890232f2SAndroid Build Coastguard Worker int get size => _sizeofInt8; 976*890232f2SAndroid Build Coastguard Worker 977*890232f2SAndroid Build Coastguard Worker @override 978*890232f2SAndroid Build Coastguard Worker @pragma('vm:prefer-inline') 979*890232f2SAndroid Build Coastguard Worker int read(BufferContext bc, int offset) => bc._getInt8(offset); 980*890232f2SAndroid Build Coastguard Worker} 981*890232f2SAndroid Build Coastguard Worker 982*890232f2SAndroid Build Coastguard Worker/// The reader of lists of objects. Lazy by default - see [lazy]. 983*890232f2SAndroid Build Coastguard Workerclass ListReader<E> extends Reader<List<E>> { 984*890232f2SAndroid Build Coastguard Worker final Reader<E> _elementReader; 985*890232f2SAndroid Build Coastguard Worker 986*890232f2SAndroid Build Coastguard Worker /// Enables lazy reading of the list 987*890232f2SAndroid Build Coastguard Worker /// 988*890232f2SAndroid Build Coastguard Worker /// If true, the returned unmodifiable list lazily reads objects on access. 989*890232f2SAndroid Build Coastguard Worker /// Therefore, the underlying buffer must not change while accessing the list. 990*890232f2SAndroid Build Coastguard Worker /// 991*890232f2SAndroid Build Coastguard Worker /// If false, reads the whole list immediately on access. 992*890232f2SAndroid Build Coastguard Worker final bool lazy; 993*890232f2SAndroid Build Coastguard Worker 994*890232f2SAndroid Build Coastguard Worker const ListReader(this._elementReader, {this.lazy = true}); 995*890232f2SAndroid Build Coastguard Worker 996*890232f2SAndroid Build Coastguard Worker @override 997*890232f2SAndroid Build Coastguard Worker @pragma('vm:prefer-inline') 998*890232f2SAndroid Build Coastguard Worker int get size => _sizeofUint32; 999*890232f2SAndroid Build Coastguard Worker 1000*890232f2SAndroid Build Coastguard Worker @override 1001*890232f2SAndroid Build Coastguard Worker List<E> read(BufferContext bc, int offset) { 1002*890232f2SAndroid Build Coastguard Worker final listOffset = bc.derefObject(offset); 1003*890232f2SAndroid Build Coastguard Worker return lazy 1004*890232f2SAndroid Build Coastguard Worker ? _FbGenericList<E>(_elementReader, bc, listOffset) 1005*890232f2SAndroid Build Coastguard Worker : List<E>.generate( 1006*890232f2SAndroid Build Coastguard Worker bc.buffer.getUint32(listOffset, Endian.little), 1007*890232f2SAndroid Build Coastguard Worker (int index) => _elementReader.read( 1008*890232f2SAndroid Build Coastguard Worker bc, listOffset + size + _elementReader.size * index), 1009*890232f2SAndroid Build Coastguard Worker growable: true); 1010*890232f2SAndroid Build Coastguard Worker } 1011*890232f2SAndroid Build Coastguard Worker} 1012*890232f2SAndroid Build Coastguard Worker 1013*890232f2SAndroid Build Coastguard Worker/// Object that can read a value at a [BufferContext]. 1014*890232f2SAndroid Build Coastguard Workerabstract class Reader<T> { 1015*890232f2SAndroid Build Coastguard Worker const Reader(); 1016*890232f2SAndroid Build Coastguard Worker 1017*890232f2SAndroid Build Coastguard Worker /// The size of the value in bytes. 1018*890232f2SAndroid Build Coastguard Worker int get size; 1019*890232f2SAndroid Build Coastguard Worker 1020*890232f2SAndroid Build Coastguard Worker /// Read the value at the given [offset] in [bc]. 1021*890232f2SAndroid Build Coastguard Worker T read(BufferContext bc, int offset); 1022*890232f2SAndroid Build Coastguard Worker 1023*890232f2SAndroid Build Coastguard Worker /// Read the value of the given [field] in the given [object]. 1024*890232f2SAndroid Build Coastguard Worker @pragma('vm:prefer-inline') 1025*890232f2SAndroid Build Coastguard Worker T vTableGet(BufferContext object, int offset, int field, T defaultValue) { 1026*890232f2SAndroid Build Coastguard Worker var fieldOffset = _vTableFieldOffset(object, offset, field); 1027*890232f2SAndroid Build Coastguard Worker return fieldOffset == 0 ? defaultValue : read(object, offset + fieldOffset); 1028*890232f2SAndroid Build Coastguard Worker } 1029*890232f2SAndroid Build Coastguard Worker 1030*890232f2SAndroid Build Coastguard Worker /// Read the value of the given [field] in the given [object]. 1031*890232f2SAndroid Build Coastguard Worker @pragma('vm:prefer-inline') 1032*890232f2SAndroid Build Coastguard Worker T? vTableGetNullable(BufferContext object, int offset, int field) { 1033*890232f2SAndroid Build Coastguard Worker var fieldOffset = _vTableFieldOffset(object, offset, field); 1034*890232f2SAndroid Build Coastguard Worker return fieldOffset == 0 ? null : read(object, offset + fieldOffset); 1035*890232f2SAndroid Build Coastguard Worker } 1036*890232f2SAndroid Build Coastguard Worker 1037*890232f2SAndroid Build Coastguard Worker @pragma('vm:prefer-inline') 1038*890232f2SAndroid Build Coastguard Worker int _vTableFieldOffset(BufferContext object, int offset, int field) { 1039*890232f2SAndroid Build Coastguard Worker var vTableSOffset = object._getInt32(offset); 1040*890232f2SAndroid Build Coastguard Worker var vTableOffset = offset - vTableSOffset; 1041*890232f2SAndroid Build Coastguard Worker var vTableSize = object._getUint16(vTableOffset); 1042*890232f2SAndroid Build Coastguard Worker if (field >= vTableSize) return 0; 1043*890232f2SAndroid Build Coastguard Worker return object._getUint16(vTableOffset + field); 1044*890232f2SAndroid Build Coastguard Worker } 1045*890232f2SAndroid Build Coastguard Worker} 1046*890232f2SAndroid Build Coastguard Worker 1047*890232f2SAndroid Build Coastguard Worker/// The reader of string values. 1048*890232f2SAndroid Build Coastguard Workerclass StringReader extends Reader<String> { 1049*890232f2SAndroid Build Coastguard Worker final bool asciiOptimization; 1050*890232f2SAndroid Build Coastguard Worker 1051*890232f2SAndroid Build Coastguard Worker const StringReader({this.asciiOptimization = false}) : super(); 1052*890232f2SAndroid Build Coastguard Worker 1053*890232f2SAndroid Build Coastguard Worker @override 1054*890232f2SAndroid Build Coastguard Worker @pragma('vm:prefer-inline') 1055*890232f2SAndroid Build Coastguard Worker int get size => _sizeofUint32; 1056*890232f2SAndroid Build Coastguard Worker 1057*890232f2SAndroid Build Coastguard Worker @override 1058*890232f2SAndroid Build Coastguard Worker @pragma('vm:prefer-inline') 1059*890232f2SAndroid Build Coastguard Worker String read(BufferContext bc, int offset) { 1060*890232f2SAndroid Build Coastguard Worker var strOffset = bc.derefObject(offset); 1061*890232f2SAndroid Build Coastguard Worker var length = bc._getUint32(strOffset); 1062*890232f2SAndroid Build Coastguard Worker var bytes = bc._asUint8List(strOffset + _sizeofUint32, length); 1063*890232f2SAndroid Build Coastguard Worker if (asciiOptimization && _isLatin(bytes)) { 1064*890232f2SAndroid Build Coastguard Worker return String.fromCharCodes(bytes); 1065*890232f2SAndroid Build Coastguard Worker } 1066*890232f2SAndroid Build Coastguard Worker return utf8.decode(bytes); 1067*890232f2SAndroid Build Coastguard Worker } 1068*890232f2SAndroid Build Coastguard Worker 1069*890232f2SAndroid Build Coastguard Worker @pragma('vm:prefer-inline') 1070*890232f2SAndroid Build Coastguard Worker static bool _isLatin(Uint8List bytes) { 1071*890232f2SAndroid Build Coastguard Worker var length = bytes.length; 1072*890232f2SAndroid Build Coastguard Worker for (var i = 0; i < length; i++) { 1073*890232f2SAndroid Build Coastguard Worker if (bytes[i] > 127) { 1074*890232f2SAndroid Build Coastguard Worker return false; 1075*890232f2SAndroid Build Coastguard Worker } 1076*890232f2SAndroid Build Coastguard Worker } 1077*890232f2SAndroid Build Coastguard Worker return true; 1078*890232f2SAndroid Build Coastguard Worker } 1079*890232f2SAndroid Build Coastguard Worker} 1080*890232f2SAndroid Build Coastguard Worker 1081*890232f2SAndroid Build Coastguard Worker/// An abstract reader for structs. 1082*890232f2SAndroid Build Coastguard Workerabstract class StructReader<T> extends Reader<T> { 1083*890232f2SAndroid Build Coastguard Worker const StructReader(); 1084*890232f2SAndroid Build Coastguard Worker 1085*890232f2SAndroid Build Coastguard Worker /// Return the object at `offset`. 1086*890232f2SAndroid Build Coastguard Worker T createObject(BufferContext bc, int offset); 1087*890232f2SAndroid Build Coastguard Worker 1088*890232f2SAndroid Build Coastguard Worker @override 1089*890232f2SAndroid Build Coastguard Worker T read(BufferContext bc, int offset) { 1090*890232f2SAndroid Build Coastguard Worker return createObject(bc, offset); 1091*890232f2SAndroid Build Coastguard Worker } 1092*890232f2SAndroid Build Coastguard Worker} 1093*890232f2SAndroid Build Coastguard Worker 1094*890232f2SAndroid Build Coastguard Worker/// An abstract reader for tables. 1095*890232f2SAndroid Build Coastguard Workerabstract class TableReader<T> extends Reader<T> { 1096*890232f2SAndroid Build Coastguard Worker const TableReader(); 1097*890232f2SAndroid Build Coastguard Worker 1098*890232f2SAndroid Build Coastguard Worker @override 1099*890232f2SAndroid Build Coastguard Worker @pragma('vm:prefer-inline') 1100*890232f2SAndroid Build Coastguard Worker int get size => 4; 1101*890232f2SAndroid Build Coastguard Worker 1102*890232f2SAndroid Build Coastguard Worker /// Return the object at [offset]. 1103*890232f2SAndroid Build Coastguard Worker T createObject(BufferContext bc, int offset); 1104*890232f2SAndroid Build Coastguard Worker 1105*890232f2SAndroid Build Coastguard Worker @override 1106*890232f2SAndroid Build Coastguard Worker T read(BufferContext bc, int offset) { 1107*890232f2SAndroid Build Coastguard Worker var objectOffset = bc.derefObject(offset); 1108*890232f2SAndroid Build Coastguard Worker return createObject(bc, objectOffset); 1109*890232f2SAndroid Build Coastguard Worker } 1110*890232f2SAndroid Build Coastguard Worker} 1111*890232f2SAndroid Build Coastguard Worker 1112*890232f2SAndroid Build Coastguard Worker/// Reader of lists of unsigned 32-bit integer values. 1113*890232f2SAndroid Build Coastguard Worker/// 1114*890232f2SAndroid Build Coastguard Worker/// The returned unmodifiable lists lazily read values on access. 1115*890232f2SAndroid Build Coastguard Workerclass Uint32ListReader extends Reader<List<int>> { 1116*890232f2SAndroid Build Coastguard Worker const Uint32ListReader(); 1117*890232f2SAndroid Build Coastguard Worker 1118*890232f2SAndroid Build Coastguard Worker @override 1119*890232f2SAndroid Build Coastguard Worker @pragma('vm:prefer-inline') 1120*890232f2SAndroid Build Coastguard Worker int get size => _sizeofUint32; 1121*890232f2SAndroid Build Coastguard Worker 1122*890232f2SAndroid Build Coastguard Worker @override 1123*890232f2SAndroid Build Coastguard Worker @pragma('vm:prefer-inline') 1124*890232f2SAndroid Build Coastguard Worker List<int> read(BufferContext bc, int offset) => 1125*890232f2SAndroid Build Coastguard Worker _FbUint32List(bc, bc.derefObject(offset)); 1126*890232f2SAndroid Build Coastguard Worker} 1127*890232f2SAndroid Build Coastguard Worker 1128*890232f2SAndroid Build Coastguard Worker/// The reader of unsigned 64-bit integers. 1129*890232f2SAndroid Build Coastguard Worker/// 1130*890232f2SAndroid Build Coastguard Worker/// WARNING: May have compatibility issues with JavaScript 1131*890232f2SAndroid Build Coastguard Workerclass Uint64Reader extends Reader<int> { 1132*890232f2SAndroid Build Coastguard Worker const Uint64Reader() : super(); 1133*890232f2SAndroid Build Coastguard Worker 1134*890232f2SAndroid Build Coastguard Worker @override 1135*890232f2SAndroid Build Coastguard Worker @pragma('vm:prefer-inline') 1136*890232f2SAndroid Build Coastguard Worker int get size => _sizeofUint64; 1137*890232f2SAndroid Build Coastguard Worker 1138*890232f2SAndroid Build Coastguard Worker @override 1139*890232f2SAndroid Build Coastguard Worker @pragma('vm:prefer-inline') 1140*890232f2SAndroid Build Coastguard Worker int read(BufferContext bc, int offset) => bc._getUint64(offset); 1141*890232f2SAndroid Build Coastguard Worker} 1142*890232f2SAndroid Build Coastguard Worker 1143*890232f2SAndroid Build Coastguard Worker/// The reader of unsigned 32-bit integers. 1144*890232f2SAndroid Build Coastguard Workerclass Uint32Reader extends Reader<int> { 1145*890232f2SAndroid Build Coastguard Worker const Uint32Reader() : super(); 1146*890232f2SAndroid Build Coastguard Worker 1147*890232f2SAndroid Build Coastguard Worker @override 1148*890232f2SAndroid Build Coastguard Worker @pragma('vm:prefer-inline') 1149*890232f2SAndroid Build Coastguard Worker int get size => _sizeofUint32; 1150*890232f2SAndroid Build Coastguard Worker 1151*890232f2SAndroid Build Coastguard Worker @override 1152*890232f2SAndroid Build Coastguard Worker @pragma('vm:prefer-inline') 1153*890232f2SAndroid Build Coastguard Worker int read(BufferContext bc, int offset) => bc._getUint32(offset); 1154*890232f2SAndroid Build Coastguard Worker} 1155*890232f2SAndroid Build Coastguard Worker 1156*890232f2SAndroid Build Coastguard Worker/// Reader of lists of unsigned 32-bit integer values. 1157*890232f2SAndroid Build Coastguard Worker/// 1158*890232f2SAndroid Build Coastguard Worker/// The returned unmodifiable lists lazily read values on access. 1159*890232f2SAndroid Build Coastguard Workerclass Uint16ListReader extends Reader<List<int>> { 1160*890232f2SAndroid Build Coastguard Worker const Uint16ListReader(); 1161*890232f2SAndroid Build Coastguard Worker 1162*890232f2SAndroid Build Coastguard Worker @override 1163*890232f2SAndroid Build Coastguard Worker @pragma('vm:prefer-inline') 1164*890232f2SAndroid Build Coastguard Worker int get size => _sizeofUint32; 1165*890232f2SAndroid Build Coastguard Worker 1166*890232f2SAndroid Build Coastguard Worker @override 1167*890232f2SAndroid Build Coastguard Worker @pragma('vm:prefer-inline') 1168*890232f2SAndroid Build Coastguard Worker List<int> read(BufferContext bc, int offset) => 1169*890232f2SAndroid Build Coastguard Worker _FbUint16List(bc, bc.derefObject(offset)); 1170*890232f2SAndroid Build Coastguard Worker} 1171*890232f2SAndroid Build Coastguard Worker 1172*890232f2SAndroid Build Coastguard Worker/// The reader of unsigned 32-bit integers. 1173*890232f2SAndroid Build Coastguard Workerclass Uint16Reader extends Reader<int> { 1174*890232f2SAndroid Build Coastguard Worker const Uint16Reader() : super(); 1175*890232f2SAndroid Build Coastguard Worker 1176*890232f2SAndroid Build Coastguard Worker @override 1177*890232f2SAndroid Build Coastguard Worker @pragma('vm:prefer-inline') 1178*890232f2SAndroid Build Coastguard Worker int get size => _sizeofUint16; 1179*890232f2SAndroid Build Coastguard Worker 1180*890232f2SAndroid Build Coastguard Worker @override 1181*890232f2SAndroid Build Coastguard Worker @pragma('vm:prefer-inline') 1182*890232f2SAndroid Build Coastguard Worker int read(BufferContext bc, int offset) => bc._getUint16(offset); 1183*890232f2SAndroid Build Coastguard Worker} 1184*890232f2SAndroid Build Coastguard Worker 1185*890232f2SAndroid Build Coastguard Worker/// Reader of unmodifiable binary data (a list of unsigned 8-bit integers). 1186*890232f2SAndroid Build Coastguard Workerclass Uint8ListReader extends Reader<List<int>> { 1187*890232f2SAndroid Build Coastguard Worker /// Enables lazy reading of the list 1188*890232f2SAndroid Build Coastguard Worker /// 1189*890232f2SAndroid Build Coastguard Worker /// If true, the returned unmodifiable list lazily reads bytes on access. 1190*890232f2SAndroid Build Coastguard Worker /// Therefore, the underlying buffer must not change while accessing the list. 1191*890232f2SAndroid Build Coastguard Worker /// 1192*890232f2SAndroid Build Coastguard Worker /// If false, reads the whole list immediately as an Uint8List. 1193*890232f2SAndroid Build Coastguard Worker final bool lazy; 1194*890232f2SAndroid Build Coastguard Worker 1195*890232f2SAndroid Build Coastguard Worker const Uint8ListReader({this.lazy = true}); 1196*890232f2SAndroid Build Coastguard Worker 1197*890232f2SAndroid Build Coastguard Worker @override 1198*890232f2SAndroid Build Coastguard Worker @pragma('vm:prefer-inline') 1199*890232f2SAndroid Build Coastguard Worker int get size => _sizeofUint32; 1200*890232f2SAndroid Build Coastguard Worker 1201*890232f2SAndroid Build Coastguard Worker @override 1202*890232f2SAndroid Build Coastguard Worker @pragma('vm:prefer-inline') 1203*890232f2SAndroid Build Coastguard Worker List<int> read(BufferContext bc, int offset) { 1204*890232f2SAndroid Build Coastguard Worker final listOffset = bc.derefObject(offset); 1205*890232f2SAndroid Build Coastguard Worker if (lazy) return _FbUint8List(bc, listOffset); 1206*890232f2SAndroid Build Coastguard Worker 1207*890232f2SAndroid Build Coastguard Worker final length = bc._getUint32(listOffset); 1208*890232f2SAndroid Build Coastguard Worker final result = Uint8List(length); 1209*890232f2SAndroid Build Coastguard Worker var pos = listOffset + _sizeofUint32; 1210*890232f2SAndroid Build Coastguard Worker for (var i = 0; i < length; i++, pos++) { 1211*890232f2SAndroid Build Coastguard Worker result[i] = bc._getUint8(pos); 1212*890232f2SAndroid Build Coastguard Worker } 1213*890232f2SAndroid Build Coastguard Worker return result; 1214*890232f2SAndroid Build Coastguard Worker } 1215*890232f2SAndroid Build Coastguard Worker} 1216*890232f2SAndroid Build Coastguard Worker 1217*890232f2SAndroid Build Coastguard Worker/// The reader of unsigned 8-bit integers. 1218*890232f2SAndroid Build Coastguard Workerclass Uint8Reader extends Reader<int> { 1219*890232f2SAndroid Build Coastguard Worker const Uint8Reader() : super(); 1220*890232f2SAndroid Build Coastguard Worker 1221*890232f2SAndroid Build Coastguard Worker @override 1222*890232f2SAndroid Build Coastguard Worker @pragma('vm:prefer-inline') 1223*890232f2SAndroid Build Coastguard Worker int get size => _sizeofUint8; 1224*890232f2SAndroid Build Coastguard Worker 1225*890232f2SAndroid Build Coastguard Worker @override 1226*890232f2SAndroid Build Coastguard Worker @pragma('vm:prefer-inline') 1227*890232f2SAndroid Build Coastguard Worker int read(BufferContext bc, int offset) => bc._getUint8(offset); 1228*890232f2SAndroid Build Coastguard Worker} 1229*890232f2SAndroid Build Coastguard Worker 1230*890232f2SAndroid Build Coastguard Worker/// Reader of unmodifiable binary data (a list of signed 8-bit integers). 1231*890232f2SAndroid Build Coastguard Workerclass Int8ListReader extends Reader<List<int>> { 1232*890232f2SAndroid Build Coastguard Worker /// Enables lazy reading of the list 1233*890232f2SAndroid Build Coastguard Worker /// 1234*890232f2SAndroid Build Coastguard Worker /// If true, the returned unmodifiable list lazily reads bytes on access. 1235*890232f2SAndroid Build Coastguard Worker /// Therefore, the underlying buffer must not change while accessing the list. 1236*890232f2SAndroid Build Coastguard Worker /// 1237*890232f2SAndroid Build Coastguard Worker /// If false, reads the whole list immediately as an Uint8List. 1238*890232f2SAndroid Build Coastguard Worker final bool lazy; 1239*890232f2SAndroid Build Coastguard Worker 1240*890232f2SAndroid Build Coastguard Worker const Int8ListReader({this.lazy = true}); 1241*890232f2SAndroid Build Coastguard Worker 1242*890232f2SAndroid Build Coastguard Worker @override 1243*890232f2SAndroid Build Coastguard Worker @pragma('vm:prefer-inline') 1244*890232f2SAndroid Build Coastguard Worker int get size => _sizeofUint32; 1245*890232f2SAndroid Build Coastguard Worker 1246*890232f2SAndroid Build Coastguard Worker @override 1247*890232f2SAndroid Build Coastguard Worker @pragma('vm:prefer-inline') 1248*890232f2SAndroid Build Coastguard Worker List<int> read(BufferContext bc, int offset) { 1249*890232f2SAndroid Build Coastguard Worker final listOffset = bc.derefObject(offset); 1250*890232f2SAndroid Build Coastguard Worker if (lazy) return _FbUint8List(bc, listOffset); 1251*890232f2SAndroid Build Coastguard Worker 1252*890232f2SAndroid Build Coastguard Worker final length = bc._getUint32(listOffset); 1253*890232f2SAndroid Build Coastguard Worker final result = Int8List(length); 1254*890232f2SAndroid Build Coastguard Worker var pos = listOffset + _sizeofUint32; 1255*890232f2SAndroid Build Coastguard Worker for (var i = 0; i < length; i++, pos++) { 1256*890232f2SAndroid Build Coastguard Worker result[i] = bc._getInt8(pos); 1257*890232f2SAndroid Build Coastguard Worker } 1258*890232f2SAndroid Build Coastguard Worker return result; 1259*890232f2SAndroid Build Coastguard Worker } 1260*890232f2SAndroid Build Coastguard Worker} 1261*890232f2SAndroid Build Coastguard Worker 1262*890232f2SAndroid Build Coastguard Worker/// The list backed by 64-bit values - Uint64 length and Float64. 1263*890232f2SAndroid Build Coastguard Workerclass _FbFloat64List extends _FbList<double> { 1264*890232f2SAndroid Build Coastguard Worker _FbFloat64List(BufferContext bc, int offset) : super(bc, offset); 1265*890232f2SAndroid Build Coastguard Worker 1266*890232f2SAndroid Build Coastguard Worker @override 1267*890232f2SAndroid Build Coastguard Worker @pragma('vm:prefer-inline') 1268*890232f2SAndroid Build Coastguard Worker double operator [](int i) => bc._getFloat64(offset + 4 + 8 * i); 1269*890232f2SAndroid Build Coastguard Worker} 1270*890232f2SAndroid Build Coastguard Worker 1271*890232f2SAndroid Build Coastguard Worker/// The list backed by 32-bit values - Float32. 1272*890232f2SAndroid Build Coastguard Workerclass _FbFloat32List extends _FbList<double> { 1273*890232f2SAndroid Build Coastguard Worker _FbFloat32List(BufferContext bc, int offset) : super(bc, offset); 1274*890232f2SAndroid Build Coastguard Worker 1275*890232f2SAndroid Build Coastguard Worker @override 1276*890232f2SAndroid Build Coastguard Worker @pragma('vm:prefer-inline') 1277*890232f2SAndroid Build Coastguard Worker double operator [](int i) => bc._getFloat32(offset + 4 + 4 * i); 1278*890232f2SAndroid Build Coastguard Worker} 1279*890232f2SAndroid Build Coastguard Worker 1280*890232f2SAndroid Build Coastguard Worker/// List backed by a generic object which may have any size. 1281*890232f2SAndroid Build Coastguard Workerclass _FbGenericList<E> extends _FbList<E> { 1282*890232f2SAndroid Build Coastguard Worker final Reader<E> elementReader; 1283*890232f2SAndroid Build Coastguard Worker 1284*890232f2SAndroid Build Coastguard Worker List<E?>? _items; 1285*890232f2SAndroid Build Coastguard Worker 1286*890232f2SAndroid Build Coastguard Worker _FbGenericList(this.elementReader, BufferContext bp, int offset) 1287*890232f2SAndroid Build Coastguard Worker : super(bp, offset); 1288*890232f2SAndroid Build Coastguard Worker 1289*890232f2SAndroid Build Coastguard Worker @override 1290*890232f2SAndroid Build Coastguard Worker @pragma('vm:prefer-inline') 1291*890232f2SAndroid Build Coastguard Worker E operator [](int i) { 1292*890232f2SAndroid Build Coastguard Worker _items ??= List<E?>.filled(length, null); 1293*890232f2SAndroid Build Coastguard Worker var item = _items![i]; 1294*890232f2SAndroid Build Coastguard Worker if (item == null) { 1295*890232f2SAndroid Build Coastguard Worker item = elementReader.read(bc, offset + 4 + elementReader.size * i); 1296*890232f2SAndroid Build Coastguard Worker _items![i] = item; 1297*890232f2SAndroid Build Coastguard Worker } 1298*890232f2SAndroid Build Coastguard Worker return item!; 1299*890232f2SAndroid Build Coastguard Worker } 1300*890232f2SAndroid Build Coastguard Worker} 1301*890232f2SAndroid Build Coastguard Worker 1302*890232f2SAndroid Build Coastguard Worker/// The base class for immutable lists read from flat buffers. 1303*890232f2SAndroid Build Coastguard Workerabstract class _FbList<E> extends Object with ListMixin<E> implements List<E> { 1304*890232f2SAndroid Build Coastguard Worker final BufferContext bc; 1305*890232f2SAndroid Build Coastguard Worker final int offset; 1306*890232f2SAndroid Build Coastguard Worker int? _length; 1307*890232f2SAndroid Build Coastguard Worker 1308*890232f2SAndroid Build Coastguard Worker _FbList(this.bc, this.offset); 1309*890232f2SAndroid Build Coastguard Worker 1310*890232f2SAndroid Build Coastguard Worker @override 1311*890232f2SAndroid Build Coastguard Worker @pragma('vm:prefer-inline') 1312*890232f2SAndroid Build Coastguard Worker int get length => _length ??= bc._getUint32(offset); 1313*890232f2SAndroid Build Coastguard Worker 1314*890232f2SAndroid Build Coastguard Worker @override 1315*890232f2SAndroid Build Coastguard Worker set length(int i) => throw StateError('Attempt to modify immutable list'); 1316*890232f2SAndroid Build Coastguard Worker 1317*890232f2SAndroid Build Coastguard Worker @override 1318*890232f2SAndroid Build Coastguard Worker void operator []=(int i, E e) => 1319*890232f2SAndroid Build Coastguard Worker throw StateError('Attempt to modify immutable list'); 1320*890232f2SAndroid Build Coastguard Worker} 1321*890232f2SAndroid Build Coastguard Worker 1322*890232f2SAndroid Build Coastguard Worker/// List backed by 32-bit unsigned integers. 1323*890232f2SAndroid Build Coastguard Workerclass _FbUint32List extends _FbList<int> { 1324*890232f2SAndroid Build Coastguard Worker _FbUint32List(BufferContext bc, int offset) : super(bc, offset); 1325*890232f2SAndroid Build Coastguard Worker 1326*890232f2SAndroid Build Coastguard Worker @override 1327*890232f2SAndroid Build Coastguard Worker @pragma('vm:prefer-inline') 1328*890232f2SAndroid Build Coastguard Worker int operator [](int i) => bc._getUint32(offset + 4 + 4 * i); 1329*890232f2SAndroid Build Coastguard Worker} 1330*890232f2SAndroid Build Coastguard Worker 1331*890232f2SAndroid Build Coastguard Worker/// List backed by 16-bit unsigned integers. 1332*890232f2SAndroid Build Coastguard Workerclass _FbUint16List extends _FbList<int> { 1333*890232f2SAndroid Build Coastguard Worker _FbUint16List(BufferContext bc, int offset) : super(bc, offset); 1334*890232f2SAndroid Build Coastguard Worker 1335*890232f2SAndroid Build Coastguard Worker @override 1336*890232f2SAndroid Build Coastguard Worker @pragma('vm:prefer-inline') 1337*890232f2SAndroid Build Coastguard Worker int operator [](int i) => bc._getUint16(offset + 4 + 2 * i); 1338*890232f2SAndroid Build Coastguard Worker} 1339*890232f2SAndroid Build Coastguard Worker 1340*890232f2SAndroid Build Coastguard Worker/// List backed by 8-bit unsigned integers. 1341*890232f2SAndroid Build Coastguard Workerclass _FbUint8List extends _FbList<int> { 1342*890232f2SAndroid Build Coastguard Worker _FbUint8List(BufferContext bc, int offset) : super(bc, offset); 1343*890232f2SAndroid Build Coastguard Worker 1344*890232f2SAndroid Build Coastguard Worker @override 1345*890232f2SAndroid Build Coastguard Worker @pragma('vm:prefer-inline') 1346*890232f2SAndroid Build Coastguard Worker int operator [](int i) => bc._getUint8(offset + 4 + i); 1347*890232f2SAndroid Build Coastguard Worker} 1348*890232f2SAndroid Build Coastguard Worker 1349*890232f2SAndroid Build Coastguard Worker/// List backed by 8-bit signed integers. 1350*890232f2SAndroid Build Coastguard Workerclass _FbInt8List extends _FbList<int> { 1351*890232f2SAndroid Build Coastguard Worker _FbInt8List(BufferContext bc, int offset) : super(bc, offset); 1352*890232f2SAndroid Build Coastguard Worker 1353*890232f2SAndroid Build Coastguard Worker @override 1354*890232f2SAndroid Build Coastguard Worker @pragma('vm:prefer-inline') 1355*890232f2SAndroid Build Coastguard Worker int operator [](int i) => bc._getInt8(offset + 4 + i); 1356*890232f2SAndroid Build Coastguard Worker} 1357*890232f2SAndroid Build Coastguard Worker 1358*890232f2SAndroid Build Coastguard Worker/// List backed by 8-bit unsigned integers. 1359*890232f2SAndroid Build Coastguard Workerclass _FbBoolList extends _FbList<bool> { 1360*890232f2SAndroid Build Coastguard Worker _FbBoolList(BufferContext bc, int offset) : super(bc, offset); 1361*890232f2SAndroid Build Coastguard Worker 1362*890232f2SAndroid Build Coastguard Worker @override 1363*890232f2SAndroid Build Coastguard Worker @pragma('vm:prefer-inline') 1364*890232f2SAndroid Build Coastguard Worker bool operator [](int i) => bc._getUint8(offset + 4 + i) == 1 ? true : false; 1365*890232f2SAndroid Build Coastguard Worker} 1366*890232f2SAndroid Build Coastguard Worker 1367*890232f2SAndroid Build Coastguard Worker/// Class that describes the structure of a table. 1368*890232f2SAndroid Build Coastguard Workerclass _VTable { 1369*890232f2SAndroid Build Coastguard Worker static const int _metadataLength = 4; 1370*890232f2SAndroid Build Coastguard Worker 1371*890232f2SAndroid Build Coastguard Worker final int numFields; 1372*890232f2SAndroid Build Coastguard Worker 1373*890232f2SAndroid Build Coastguard Worker // Note: fieldOffsets start as "tail offsets" and are then transformed by 1374*890232f2SAndroid Build Coastguard Worker // [computeFieldOffsets()] to actual offsets when a table is finished. 1375*890232f2SAndroid Build Coastguard Worker final Uint32List fieldOffsets; 1376*890232f2SAndroid Build Coastguard Worker bool offsetsComputed = false; 1377*890232f2SAndroid Build Coastguard Worker 1378*890232f2SAndroid Build Coastguard Worker _VTable(this.numFields) : fieldOffsets = Uint32List(numFields); 1379*890232f2SAndroid Build Coastguard Worker 1380*890232f2SAndroid Build Coastguard Worker /// The size of the table that uses this VTable. 1381*890232f2SAndroid Build Coastguard Worker int tableSize = 0; 1382*890232f2SAndroid Build Coastguard Worker 1383*890232f2SAndroid Build Coastguard Worker /// The tail of this VTable. It is used to share the same VTable between 1384*890232f2SAndroid Build Coastguard Worker /// multiple tables of identical structure. 1385*890232f2SAndroid Build Coastguard Worker int tail = 0; 1386*890232f2SAndroid Build Coastguard Worker 1387*890232f2SAndroid Build Coastguard Worker int get _vTableSize => numOfUint16 * _sizeofUint16; 1388*890232f2SAndroid Build Coastguard Worker 1389*890232f2SAndroid Build Coastguard Worker int get numOfUint16 => 1 + 1 + numFields; 1390*890232f2SAndroid Build Coastguard Worker 1391*890232f2SAndroid Build Coastguard Worker @pragma('vm:prefer-inline') 1392*890232f2SAndroid Build Coastguard Worker void addField(int field, int offset) { 1393*890232f2SAndroid Build Coastguard Worker assert(!offsetsComputed); 1394*890232f2SAndroid Build Coastguard Worker assert(offset > 0); // it's impossible for field to start at the buffer end 1395*890232f2SAndroid Build Coastguard Worker assert(offset <= 4294967295); // uint32 max 1396*890232f2SAndroid Build Coastguard Worker fieldOffsets[field] = offset; 1397*890232f2SAndroid Build Coastguard Worker } 1398*890232f2SAndroid Build Coastguard Worker 1399*890232f2SAndroid Build Coastguard Worker @pragma('vm:prefer-inline') 1400*890232f2SAndroid Build Coastguard Worker bool _offsetsMatch(int vt2Start, ByteData buf) { 1401*890232f2SAndroid Build Coastguard Worker assert(offsetsComputed); 1402*890232f2SAndroid Build Coastguard Worker for (var i = 0; i < numFields; i++) { 1403*890232f2SAndroid Build Coastguard Worker if (fieldOffsets[i] != 1404*890232f2SAndroid Build Coastguard Worker buf.getUint16(vt2Start + _metadataLength + (2 * i), Endian.little)) { 1405*890232f2SAndroid Build Coastguard Worker return false; 1406*890232f2SAndroid Build Coastguard Worker } 1407*890232f2SAndroid Build Coastguard Worker } 1408*890232f2SAndroid Build Coastguard Worker return true; 1409*890232f2SAndroid Build Coastguard Worker } 1410*890232f2SAndroid Build Coastguard Worker 1411*890232f2SAndroid Build Coastguard Worker /// Fill the [fieldOffsets] field. 1412*890232f2SAndroid Build Coastguard Worker @pragma('vm:prefer-inline') 1413*890232f2SAndroid Build Coastguard Worker void computeFieldOffsets(int tableTail) { 1414*890232f2SAndroid Build Coastguard Worker assert(!offsetsComputed); 1415*890232f2SAndroid Build Coastguard Worker offsetsComputed = true; 1416*890232f2SAndroid Build Coastguard Worker for (var i = 0; i < numFields; i++) { 1417*890232f2SAndroid Build Coastguard Worker if (fieldOffsets[i] != 0) { 1418*890232f2SAndroid Build Coastguard Worker fieldOffsets[i] = tableTail - fieldOffsets[i]; 1419*890232f2SAndroid Build Coastguard Worker } 1420*890232f2SAndroid Build Coastguard Worker } 1421*890232f2SAndroid Build Coastguard Worker } 1422*890232f2SAndroid Build Coastguard Worker 1423*890232f2SAndroid Build Coastguard Worker /// Outputs this VTable to [buf], which is is expected to be aligned to 16-bit 1424*890232f2SAndroid Build Coastguard Worker /// and have at least [numOfUint16] 16-bit words available. 1425*890232f2SAndroid Build Coastguard Worker @pragma('vm:prefer-inline') 1426*890232f2SAndroid Build Coastguard Worker void output(ByteData buf, int bufOffset) { 1427*890232f2SAndroid Build Coastguard Worker assert(offsetsComputed); 1428*890232f2SAndroid Build Coastguard Worker // VTable size. 1429*890232f2SAndroid Build Coastguard Worker buf.setUint16(bufOffset, numOfUint16 * 2, Endian.little); 1430*890232f2SAndroid Build Coastguard Worker bufOffset += 2; 1431*890232f2SAndroid Build Coastguard Worker // Table size. 1432*890232f2SAndroid Build Coastguard Worker buf.setUint16(bufOffset, tableSize, Endian.little); 1433*890232f2SAndroid Build Coastguard Worker bufOffset += 2; 1434*890232f2SAndroid Build Coastguard Worker // Field offsets. 1435*890232f2SAndroid Build Coastguard Worker for (var i = 0; i < numFields; i++) { 1436*890232f2SAndroid Build Coastguard Worker buf.setUint16(bufOffset, fieldOffsets[i], Endian.little); 1437*890232f2SAndroid Build Coastguard Worker bufOffset += 2; 1438*890232f2SAndroid Build Coastguard Worker } 1439*890232f2SAndroid Build Coastguard Worker } 1440*890232f2SAndroid Build Coastguard Worker} 1441*890232f2SAndroid Build Coastguard Worker 1442*890232f2SAndroid Build Coastguard Worker/// The interface that [Builder] uses to allocate buffers for encoding. 1443*890232f2SAndroid Build Coastguard Workerabstract class Allocator { 1444*890232f2SAndroid Build Coastguard Worker const Allocator(); 1445*890232f2SAndroid Build Coastguard Worker 1446*890232f2SAndroid Build Coastguard Worker /// Allocate a [ByteData] buffer of a given size. 1447*890232f2SAndroid Build Coastguard Worker ByteData allocate(int size); 1448*890232f2SAndroid Build Coastguard Worker 1449*890232f2SAndroid Build Coastguard Worker /// Free the given [ByteData] buffer previously allocated by [allocate]. 1450*890232f2SAndroid Build Coastguard Worker void deallocate(ByteData data); 1451*890232f2SAndroid Build Coastguard Worker 1452*890232f2SAndroid Build Coastguard Worker /// Reallocate [newSize] bytes of memory, replacing the old [oldData]. This 1453*890232f2SAndroid Build Coastguard Worker /// grows downwards, and is intended specifically for use with [Builder]. 1454*890232f2SAndroid Build Coastguard Worker /// Params [inUseBack] and [inUseFront] indicate how much of [oldData] is 1455*890232f2SAndroid Build Coastguard Worker /// actually in use at each end, and needs to be copied. 1456*890232f2SAndroid Build Coastguard Worker ByteData resize( 1457*890232f2SAndroid Build Coastguard Worker ByteData oldData, int newSize, int inUseBack, int inUseFront) { 1458*890232f2SAndroid Build Coastguard Worker final newData = allocate(newSize); 1459*890232f2SAndroid Build Coastguard Worker _copyDownward(oldData, newData, inUseBack, inUseFront); 1460*890232f2SAndroid Build Coastguard Worker deallocate(oldData); 1461*890232f2SAndroid Build Coastguard Worker return newData; 1462*890232f2SAndroid Build Coastguard Worker } 1463*890232f2SAndroid Build Coastguard Worker 1464*890232f2SAndroid Build Coastguard Worker /// Called by [resize] to copy memory from [oldData] to [newData]. Only 1465*890232f2SAndroid Build Coastguard Worker /// memory of size [inUseFront] and [inUseBack] will be copied from the front 1466*890232f2SAndroid Build Coastguard Worker /// and back of the old memory allocation. 1467*890232f2SAndroid Build Coastguard Worker void _copyDownward( 1468*890232f2SAndroid Build Coastguard Worker ByteData oldData, ByteData newData, int inUseBack, int inUseFront) { 1469*890232f2SAndroid Build Coastguard Worker if (inUseBack != 0) { 1470*890232f2SAndroid Build Coastguard Worker newData.buffer.asUint8List().setAll( 1471*890232f2SAndroid Build Coastguard Worker newData.lengthInBytes - inUseBack, 1472*890232f2SAndroid Build Coastguard Worker oldData.buffer.asUint8List().getRange( 1473*890232f2SAndroid Build Coastguard Worker oldData.lengthInBytes - inUseBack, oldData.lengthInBytes)); 1474*890232f2SAndroid Build Coastguard Worker } 1475*890232f2SAndroid Build Coastguard Worker if (inUseFront != 0) { 1476*890232f2SAndroid Build Coastguard Worker newData.buffer 1477*890232f2SAndroid Build Coastguard Worker .asUint8List() 1478*890232f2SAndroid Build Coastguard Worker .setAll(0, oldData.buffer.asUint8List().getRange(0, inUseFront)); 1479*890232f2SAndroid Build Coastguard Worker } 1480*890232f2SAndroid Build Coastguard Worker } 1481*890232f2SAndroid Build Coastguard Worker} 1482*890232f2SAndroid Build Coastguard Worker 1483*890232f2SAndroid Build Coastguard Workerclass DefaultAllocator extends Allocator { 1484*890232f2SAndroid Build Coastguard Worker const DefaultAllocator(); 1485*890232f2SAndroid Build Coastguard Worker 1486*890232f2SAndroid Build Coastguard Worker @override 1487*890232f2SAndroid Build Coastguard Worker ByteData allocate(int size) => ByteData(size); 1488*890232f2SAndroid Build Coastguard Worker 1489*890232f2SAndroid Build Coastguard Worker @override 1490*890232f2SAndroid Build Coastguard Worker void deallocate(ByteData data) { 1491*890232f2SAndroid Build Coastguard Worker // nothing to do, it's garbage-collected 1492*890232f2SAndroid Build Coastguard Worker } 1493*890232f2SAndroid Build Coastguard Worker} 1494