splice static method
executable with sections carried inside it.
Throws FormatException for bytes that do not end the way a compiled Dart executable does: splicing into anything else writes a file that does not start, and says nothing until somebody runs it.
Implementation
static Uint8List splice(
Uint8List executable,
Map<String, List<int>> sections,
) {
if (executable.length < 32) {
throw const FormatException('too short to be a compiled executable');
}
final ByteData bytes = ByteData.sublistView(executable);
if (bytes.getUint64(executable.length - 8, Endian.little) !=
_snapshotMagic) {
if (_isPortableExecutable(executable) || _isMachO(executable)) {
return _append(executable, sections);
}
throw const FormatException(
'not a compiled Dart executable: it does not end with the snapshot '
'trailer `dart compile exe` writes, and it is not a Windows or macOS '
'executable image',
);
}
final int snapshot = bytes.getUint64(executable.length - 16, Endian.little);
if (snapshot > executable.length - 16) {
throw const FormatException('the snapshot trailer points past the file');
}
final Uint8List block = _block(sections);
final int start = snapshot;
final int end = start + block.length;
final int moved = ((end + 16 + _alignment - 1) ~/ _alignment) * _alignment;
final BytesBuilder out = BytesBuilder(copy: false)
..add(Uint8List.sublistView(executable, 0, snapshot))
..add(block)
..add(Uint8List(moved - 16 - end));
final ByteData locator = ByteData(16)
..setUint64(0, start, Endian.little);
final Uint8List locatorBytes = locator.buffer.asUint8List();
locatorBytes.setRange(8, 16, ascii.encode(_locatorMagic));
out
..add(locatorBytes)
..add(Uint8List.sublistView(executable, snapshot, executable.length - 16));
final ByteData trailer = ByteData(16)
..setUint64(0, moved, Endian.little)
..setUint64(8, _snapshotMagic, Endian.little);
out.add(trailer.buffer.asUint8List());
return out.takeBytes();
}