Trace.decode constructor

Trace.decode(
  1. Uint8List bytes
)

Reads a trace written by encode.

Throws a TraceFormatException for bytes that are not a trace, a version newer than formatVersion, or an event or a value this build does not know.

Implementation

factory Trace.decode(Uint8List bytes) {
  final data = ByteData.sublistView(bytes);
  for (var i = 0; i < _magic.length; i++) {
    if (bytes.length <= i || bytes[i] != _magic[i]) {
      throw const TraceFormatException(
        'not a flutter3d trace: no F3DTRACE magic',
      );
    }
  }
  // Every format up to this build's, lifted through [_migrations]; only a
  // trace from the future is refused (decision 8 of
  // `tasks/1.0-stability.md`). Mutation: put back `!=` and bump the
  // constant, and `test/fixtures/v1/frame.f3dtrace` stops opening.
  final version = data.getUint32(8, Endian.little);
  if (version < 1 || version > formatVersion) {
    throw TraceFormatException(
      'a trace of format $version; this build reads up to $formatVersion. '
      'Update flutter3d to replay it',
    );
  }
  final headerLength = data.getUint32(12, Endian.little);
  if (bytes.length < 16 + headerLength) {
    throw TraceFormatException(
      'a trace whose header says $headerLength bytes, in a file of '
      '${bytes.length}',
    );
  }
  try {
    final header = _migrations
        .skip(version - 1)
        .fold(
          asMap(
            jsonDecode(utf8.decode(bytes.sublist(16, 16 + headerLength))),
          ),
          (Map<String, Object?> json, _TraceMigration lift) => lift(json),
        );
    final blob = TraceBlobReader(bytes.sublist(16 + headerLength));
    return Trace(<TraceEvent>[
      for (final e in (header['events']! as List<Object?>).map(asMap))
        TraceEvent.fromJson(e, blob),
    ], metadata: asMap(header['metadata'] ?? <String, Object?>{}));
  } on FormatException catch (error) {
    // JSON or UTF-8 that does not parse: the file, not this build.
    throw TraceFormatException(
      'a trace header that does not read',
      cause: error,
    );
  }
}