| // Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file |
| // for details. All rights reserved. Use of this source code is governed by a |
| // BSD-style license that can be found in the LICENSE file. |
| |
| // Example of using package:wasm to run a wasm build of the Brotli compression |
| // library. Usage: |
| // dart brotli.dart input.txt |
| |
| import 'dart:io'; |
| import 'dart:typed_data'; |
| |
| import 'package:wasm/wasm.dart'; |
| |
| // Brotli compression parameters. |
| const int kDefaultQuality = 11; |
| const int kDefaultWindow = 22; |
| const int kDefaultMode = 0; |
| |
| void main(List<String> args) { |
| var brotliPath = Platform.script.resolve('libbrotli.wasm'); |
| var moduleData = File(brotliPath.path).readAsBytesSync(); |
| var module = WasmModule(moduleData); |
| print(module.describe()); |
| |
| var instance = module.instantiate().enableWasi().build(); |
| var memory = instance.memory; |
| var compress = instance.lookupFunction('BrotliEncoderCompress'); |
| var decompress = instance.lookupFunction('BrotliDecoderDecompress'); |
| |
| print('Loading ${args[0]}'); |
| var inputData = File(args[0]).readAsBytesSync(); |
| print('Input size: ${inputData.length} bytes'); |
| |
| // Grow the module's memory to get unused space to put our data. |
| // [initial memory][input data][output data][size][decoded data][size] |
| var inputPtr = memory.lengthInBytes; |
| memory.grow((3 * inputData.length / WasmMemory.kPageSizeInBytes).ceil()); |
| var memoryView = memory.view; |
| var outputPtr = inputPtr + inputData.length; |
| var outSizePtr = outputPtr + inputData.length; |
| var decodedPtr = outSizePtr + 4; |
| var decSizePtr = decodedPtr + inputData.length; |
| |
| memoryView.setRange(inputPtr, inputPtr + inputData.length, inputData); |
| |
| var sizeBytes = ByteData(4)..setUint32(0, inputData.length, Endian.host); |
| memoryView.setRange( |
| outSizePtr, |
| outSizePtr + 4, |
| sizeBytes.buffer.asUint8List(), |
| ); |
| |
| print('\nCompressing...'); |
| var status = compress( |
| kDefaultQuality, |
| kDefaultWindow, |
| kDefaultMode, |
| inputData.length, |
| inputPtr, |
| outSizePtr, |
| outputPtr, |
| ); |
| print('Compression status: $status'); |
| |
| var compressedSize = |
| ByteData.sublistView(memoryView, outSizePtr, outSizePtr + 4) |
| .getUint32(0, Endian.host); |
| print('Compressed size: $compressedSize bytes'); |
| var spaceSaving = 100 * (1 - compressedSize / inputData.length); |
| print('Space saving: ${spaceSaving.toStringAsFixed(2)}%'); |
| |
| var decSizeBytes = ByteData(4)..setUint32(0, inputData.length, Endian.host); |
| memoryView.setRange( |
| decSizePtr, |
| decSizePtr + 4, |
| decSizeBytes.buffer.asUint8List(), |
| ); |
| |
| print('\nDecompressing...'); |
| status = decompress(compressedSize, outputPtr, decSizePtr, decodedPtr); |
| print('Decompression status: $status'); |
| |
| var decompressedSize = |
| ByteData.sublistView(memoryView, decSizePtr, decSizePtr + 4) |
| .getUint32(0, Endian.host); |
| print('Decompressed size: $decompressedSize bytes'); |
| |
| print('\nVerifying decompression...'); |
| assert(inputData.length == decompressedSize); |
| for (var i = 0; i < inputData.length; ++i) { |
| assert(inputData[i] == memoryView[decodedPtr + i]); |
| } |
| print('Decompression succeeded :)'); |
| } |