UNPKG

ltcode

Version:

Luby Transform Code implementation.

93 lines (92 loc) 3.52 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.Decoder = void 0; const utils_1 = require("./utils"); const blockgraph_1 = require("./blockgraph"); const prng_1 = require("./prng"); class Decoder { constructor() { this.initialized = false; this.file_size = null; this.block_size = null; this.num_blocks = null; this.block_graph = new blockgraph_1.BlockGraph(0); this.prng = null; } decode(data) { if (!this.isBlockValid(data)) return false; const next_block = this.readBlocks(data).next().value; return this.consume_block(next_block); } getProgress() { if (!this.initialized || this.num_blocks == null) { return 0; } const eliminated = this.block_graph.eliminated.size; return Math.round(eliminated / this.num_blocks * 100); } result() { const bytes = this.resultBytes(); return bytes.reduce((acc, byte) => acc + String.fromCharCode(byte), ''); } resultBytes() { if (!this.initialized || !this.num_blocks || !this.file_size || !this.block_size) { throw new Error("Decoder not initialized"); } const sorted_blocks = Array.from(this.block_graph.eliminated.entries()).sort((a, b) => a[0] - b[0]); let out_stream = []; for (let i = 0; i < this.num_blocks; i++) { const sorted_block = sorted_blocks[i]; const block_data = (0, utils_1.intToBytes)(sorted_block[1], this.block_size, 'big'); if (i < this.num_blocks - 1 || this.file_size % this.block_size === 0) { out_stream.push(block_data); } else { const x = block_data.subarray(0, this.file_size % this.block_size); out_stream.push(x); } } return (0, utils_1.concatUint8Arrays)(out_stream); } consume_block(lt_block) { const { size, length, blockseed, block_data } = lt_block; if (!this.initialized) this._initialize(length, size, blockseed); const [_, source_blocks] = this.prng.sample_source_blocks(blockseed); return this.block_graph.add_block(source_blocks, block_data); } _initialize(file_size, block_size, block_seed) { this.file_size = file_size; this.block_size = block_size; this.num_blocks = Math.ceil(file_size / block_size); this.block_graph = new blockgraph_1.BlockGraph(this.num_blocks); this.prng = new prng_1.PRNG(this.num_blocks, block_seed); this.initialized = true; } *readBlocks(data) { const { size, length, seed, data: block_data } = JSON.parse(data); const block_data_int = BigInt(block_data); const bytes = (0, utils_1.intToBytes)(block_data_int, Number(size), "little"); const block_data_ = (0, utils_1.intFromBytes)(bytes, "big"); return { size: Number(size), length: Number(length), blockseed: Number(seed), block_data: block_data_ }; } isBlockValid(block) { try { const { length, size, seed, data } = JSON.parse(block); return typeof length === 'number' && typeof size === 'number' && typeof seed === 'number' && typeof data === 'string'; } catch (e) { return false; } } } exports.Decoder = Decoder;