UNPKG

@gmod/cram

Version:

read CRAM files with pure Javascript

445 lines 13.6 kB
"use strict"; /* eslint-disable no-var */ // @ts-nocheck var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.decode = decode; /* * Copyright (c) 2019,2020 Genome Research Ltd. * Author(s): James Bonfield * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials provided * with the distribution. * * 3. Neither the names Genome Research Ltd and Wellcome Trust Sanger * Institute nor the names of its contributors may be used to endorse * or promote products derived from this software without specific * prior written permission. * * THIS SOFTWARE IS PROVIDED BY GENOME RESEARCH LTD AND CONTRIBUTORS "AS * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GENOME RESEARCH * LTD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ const iostream_ts_1 = __importDefault(require("./iostream.js")); // ---------------------------------------------------------------------- // rANS primitives itself // // RansGet* is decoder side function RansGetCumulativeFreq(R, bits) { return R & ((1 << bits) - 1); } function RansGetSymbolFromFreq(C, f) { // NOTE: Inefficient. // In practice we would implement this via a precomputed // lookup table C2S[f]; see RansBuildC2S below. let s = 0; while (f >= C[s + 1]) { s++; } // console.error(f, C, s) return s; } function RansBuildC2S(C, bits) { const max = 1 << bits; const C2S = new Array(max); let s = 0; for (let f = 0; f < max; f++) { while (f >= C[s + 1]) { s++; } C2S[f] = s; } return C2S; } function RansAdvanceStep(R, c, f, bits) { return f * (R >> bits) + (R & ((1 << bits) - 1)) - c; } function RansRenorm(src, R) { if (R < 1 << 15) { R = (R << 16) + src.ReadUint16(); } return R; } function DecodeRLEMeta(src, N) { const u_meta_len = src.ReadUint7(); const rle_len = src.ReadUint7(); // Decode RLE lengths if (u_meta_len & 1) { var rle_meta = src.ReadData((u_meta_len - 1) / 2); } else { const comp_meta_len = src.ReadUint7(); var rle_meta = src.ReadData(comp_meta_len); rle_meta = RansDecode0(new iostream_ts_1.default(rle_meta), u_meta_len / 2, N); } // Decode list of symbols for which RLE lengths are applied var rle_meta = new iostream_ts_1.default(rle_meta); const L = new Array(256); let n = rle_meta.ReadByte(); if (n == 0) { n = 256; } for (let i = 0; i < n; i++) { L[rle_meta.ReadByte()] = 1; } return [L, rle_meta, rle_len]; } function DecodeRLE(buf, L, rle_meta, len) { const src = new iostream_ts_1.default(buf); const out = new Uint8Array(len); // Expand up buf+meta to out; i = buf index, j = out index let j = 0; for (let i = 0; j < len; i++) { const sym = buf[i]; if (L[sym]) { const run = rle_meta.ReadUint7(); for (let r = 0; r <= run; r++) { out[j++] = sym; } } else { out[j++] = sym; } } return out; } // Pack meta data is the number and value of distinct symbols plus // the length of the packed byte stream. function DecodePackMeta(src) { const nsym = src.ReadByte(); const P = new Array(nsym); for (let i = 0; i < nsym; i++) { P[i] = src.ReadByte(); } const len = src.ReadUint7(); return [P, nsym, len]; } // Extract bits from src producing output of length len. // Nsym is number of distinct symbols used. function DecodePack(data, P, nsym, len) { const out = new Uint8Array(len); let j = 0; // Constant value if (nsym <= 1) { for (var i = 0; i < len; i++) { out[i] = P[0]; } } // 1 bit per value else if (nsym <= 2) { for (i = 0; i < len; i++) { if (i % 8 == 0) { var v = data[j++]; } out[i] = P[v & 1]; v >>= 1; } } // 2 bits per value else if (nsym <= 4) { for (i = 0; i < len; i++) { if (i % 4 == 0) { var v = data[j++]; } out[i] = P[v & 3]; v >>= 2; } } // 4 bits per value else if (nsym <= 16) { for (i = 0; i < len; i++) { if (i % 2 == 0) { var v = data[j++]; } out[i] = P[v & 15]; v >>= 4; } } return out; } function RansDecodeStripe(src, len) { const N = src.ReadByte(); // Retrieve lengths const clen = new Array(N); const ulen = new Array(N); for (var j = 0; j < N; j++) { clen[j] = src.ReadUint7(); } // Decode streams const T = new Array(N); for (var j = 0; j < N; j++) { ulen[j] = Math.floor(len / N) + (len % N > j); T[j] = RansDecodeStream(src, ulen[j]); } // Transpose const out = new Uint8Array(len); for (var j = 0; j < N; j++) { for (let i = 0; i < ulen[j]; i++) { out[i * N + j] = T[j][i]; } } return out; } // ---------------------------------------------------------------------- // Main rANS entry function: decodes a compressed src and // returns the uncompressed buffer. function decode(src) { const stream = new iostream_ts_1.default(src); return RansDecodeStream(stream, 0); } function RansDecodeStream(stream, n_out) { const format = stream.ReadByte(); const order = format & 1; const x32 = format & 4; const stripe = format & 8; const nosz = format & 16; const cat = format & 32; const rle = format & 64; const pack = format & 128; const Nway = x32 ? 32 : 4; if (!nosz) { n_out = stream.ReadUint7(); } // N-way interleaving if (stripe) { return RansDecodeStripe(stream, n_out); } // Bit packing if (pack) { var pack_len = n_out; var [P, nsym, n_out] = DecodePackMeta(stream); } // Run length encoding if (rle) { var rle_len = n_out; var [L, rle_meta, n_out] = DecodeRLEMeta(stream, Nway); } // Uncompress data (all, packed or run literals) if (cat) { var buf = stream.ReadData(n_out); } else if (order == 0) { var buf = RansDecode0(stream, n_out, Nway); } else { var buf = RansDecode1(stream, n_out, Nway); } // Apply expansion transforms if (rle) { buf = DecodeRLE(buf, L, rle_meta, rle_len); } if (pack) { buf = DecodePack(buf, P, nsym, pack_len); } return buf; } // ---------------------------------------------------------------------- // Order-0 decoder function ReadAlphabet(src) { const A = new Array(256); for (let i = 0; i < 256; i++) { A[i] = 0; } let rle = 0; let sym = src.ReadByte(); let last_sym = sym; do { A[sym] = 1; if (rle > 0) { rle--; sym++; } else { sym = src.ReadByte(); if (sym == last_sym + 1) { rle = src.ReadByte(); } } last_sym = sym; } while (sym != 0); return A; } // Decode a single table of order-0 frequences, // filling out the F and C arrays. function ReadFrequencies0(src, F, C) { // Initialise; not in the specification - implicit? for (var i = 0; i < 256; i++) { F[i] = 0; } // Fetch alphabet const A = ReadAlphabet(src); // Fetch frequencies for the symbols listed in our alphabet for (var i = 0; i < 256; i++) { if (A[i] > 0) { F[i] = src.ReadUint7(); } } NormaliseFrequencies0_Shift(F, 12); // Compute C[] from F[] C[0] = 0; for (var i = 0; i <= 255; i++) { C[i + 1] = C[i] + F[i]; } } function RansDecode0(src, nbytes, N) { // Decode frequencies const F = new Array(256); const C = new Array(256); ReadFrequencies0(src, F, C); // Fast lookup to avoid slow RansGetSymbolFromFreq const C2S = RansBuildC2S(C, 12); // Initialise rANS state const R = new Array(N); for (var i = 0; i < N; i++) { R[i] = src.ReadUint32(); } // Main decode loop const output = new Uint8Array(nbytes); for (var i = 0; i < nbytes; i++) { const ix = i & (N - 1); // equiv to i%N as N is power of 2 const f = RansGetCumulativeFreq(R[ix], 12); const s = C2S[f]; // Equiv to RansGetSymbolFromFreq(C, f); output[i] = s; R[ix] = RansAdvanceStep(R[ix], C[s], F[s], 12); R[ix] = RansRenorm(src, R[ix]); } // Main decode loop return output; } function NormaliseFrequencies0_Shift(F, bits) { // Compute total and number of bits to shift by let tot = 0; for (var i = 0; i < 256; i++) { tot += F[i]; } if (tot == 0 || tot == 1 << bits) { return; } let shift = 0; while (tot < 1 << bits) { tot *= 2; shift++; } // Scale total of frequencies to (1<<bits) for (var i = 0; i < 256; i++) { F[i] <<= shift; } } // ---------------------------------------------------------------------- // Order-1 decoder // Decode a table of order-1 frequences, // filling out the F and C arrays. function ReadFrequencies1(src, F, C, shift) { // Initialise; not in the specification - implicit? for (var i = 0; i < 256; i++) { F[i] = new Array(256); C[i] = new Array(256); for (var j = 0; j < 256; j++) { F[i][j] = 0; } } // Fetch alphabet const A = ReadAlphabet(src); // Read F[] for (var i = 0; i < 256; i++) { if (!A[i]) { continue; } let run = 0; for (var j = 0; j < 256; j++) { if (!A[j]) { continue; } if (run > 0) { run--; } else { F[i][j] = src.ReadUint7(); if (F[i][j] == 0) { run = src.ReadByte(); } } } NormaliseFrequencies0_Shift(F[i], shift); // Compute C[] from F[] C[i][0] = 0; for (var j = 0; j < 256; j++) { C[i][j + 1] = C[i][j] + F[i][j]; } } } function RansDecode1(src, nbytes, N) { // FIXME: this bit is missing from the RansDecode0 pseudocode. var comp = src.ReadByte(); const shift = comp >> 4; var freq_src = src; if (comp & 1) { const ulen = src.ReadUint7(); const clen = src.ReadUint7(); var comp = new iostream_ts_1.default(src.ReadData(clen)); var freq_src = new iostream_ts_1.default(RansDecode0(comp, ulen, 4)); } // Decode frequencies const F = new Array(256); const C = new Array(256); ReadFrequencies1(freq_src, F, C, shift); // Fast lookup to avoid slow RansGetSymbolFromFreq const C2S = new Array(256); for (var i = 0; i < 256; i++ // Could do only for symbols in alphabet? ) { C2S[i] = RansBuildC2S(C[i], shift); } // Initialise rANS state const R = new Array(N); const L = new Array(N); for (var j = 0; j < N; j++) { R[j] = src.ReadUint32(); L[j] = 0; } // Main decode loop const output = new Uint8Array(nbytes); const nbytesx = Math.floor(nbytes / N); for (var i = 0; i < nbytesx; i++) { for (var j = 0; j < N; j++) { var f = RansGetCumulativeFreq(R[j], shift); // var s = RansGetSymbolFromFreq(C[L[j]], f); var s = C2S[L[j]][f]; // Precomputed version of above output[i + j * nbytesx] = s; R[j] = RansAdvanceStep(R[j], C[L[j]][s], F[L[j]][s], shift); R[j] = RansRenorm(src, R[j]); L[j] = s; } } // Now deal with the remainder if buffer size is not a multiple of N, // using the last rANS state exclusively. (It'd have been nice to have // designed this to just act as if we kept going with a bail out.) i = N * i; while (i < nbytes) { var f = RansGetCumulativeFreq(R[N - 1], shift); var s = RansGetSymbolFromFreq(C[L[N - 1]], f); output[i++] = s; R[N - 1] = RansAdvanceStep(R[N - 1], C[L[N - 1]][s], F[L[N - 1]][s], shift); R[N - 1] = RansRenorm(src, R[N - 1]); L[N - 1] = s; } return output; } //# sourceMappingURL=rans4x16.js.map