UNPKG

@gmod/cram

Version:

read CRAM files with pure Javascript

323 lines 11.3 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 }); /* * 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 index_ts_1 = require("../seek-bzip/index.js"); const arith_sh_ts_1 = __importDefault(require("./arith_sh.js")); const byte_model_ts_1 = __importDefault(require("./byte_model.js")); const iostream_ts_1 = __importDefault(require("./iostream.js")); const ARITH_ORDER = 1; const ARITH_EXT = 4; const ARITH_STRIPE = 8; const ARITH_NOSIZE = 16; const ARITH_CAT = 32; const ARITH_RLE = 64; const ARITH_PACK = 128; class RangeCoderGen { decode(src) { this.stream = new iostream_ts_1.default(src); return this.decodeStream(this.stream); } decodeStream(stream, n_out = 0) { const flags = this.stream.ReadByte(); if (!(flags & ARITH_NOSIZE)) { n_out = this.stream.ReadUint7(); } let e_len = n_out; const order = flags & ARITH_ORDER; // 4-way recursion if (flags & ARITH_STRIPE) { return this.decodeStripe(this.stream, n_out); } // Meta data if (flags & ARITH_PACK) { var P; [P, e_len] = this.decodePackMeta(this.stream); } // NOP, useful for tiny blocks if (flags & ARITH_CAT) { var data = this.decodeCat(this.stream, e_len); } // Entropy decode else if (flags & ARITH_EXT) { var data = this.decodeExt(this.stream, e_len); } else if (flags & ARITH_RLE) { var data = order ? this.decodeRLE1(this.stream, e_len) : this.decodeRLE0(this.stream, e_len); } else { var data = order ? this.decode1(this.stream, e_len) : this.decode0(this.stream, e_len); } // Transforms if (flags & ARITH_PACK) { data = this.decodePack(data, P, n_out); } return data; } // ---------------------------------------------------------------------- // Order-0 codec decode0(stream, n_out) { const output = new Uint8Array(n_out); let max_sym = stream.ReadByte(); if (max_sym == 0) { max_sym = 256; } const byte_model = new byte_model_ts_1.default(max_sym); const rc = new arith_sh_ts_1.default(stream); rc.RangeStartDecode(stream); for (let i = 0; i < n_out; i++) { output[i] = byte_model.ModelDecode(stream, rc); } return output; } // ---------------------------------------------------------------------- // Order-1 codec decode1(stream, n_out) { const output = new Uint8Array(n_out); let max_sym = stream.ReadByte(); if (max_sym == 0) { max_sym = 256; } const byte_model = new Array(max_sym); for (var i = 0; i < max_sym; i++) { byte_model[i] = new byte_model_ts_1.default(max_sym); } const rc = new arith_sh_ts_1.default(stream); rc.RangeStartDecode(stream); let last = 0; for (var i = 0; i < n_out; i++) { output[i] = byte_model[last].ModelDecode(stream, rc); last = output[i]; } return output; } // ---------------------------------------------------------------------- // External codec decodeExt(stream, n_out) { return (0, index_ts_1.decode)(stream.buf.slice(stream.pos)); } // ---------------------------------------------------------------------- // Order-0 RLE codec decodeRLE0(stream, n_out) { const output = new Uint8Array(n_out); let max_sym = stream.ReadByte(); if (max_sym == 0) { max_sym = 256; } const model_lit = new byte_model_ts_1.default(max_sym); const model_run = new Array(258); for (var i = 0; i <= 257; i++) { model_run[i] = new byte_model_ts_1.default(4); } const rc = new arith_sh_ts_1.default(stream); rc.RangeStartDecode(stream); var i = 0; while (i < n_out) { output[i] = model_lit.ModelDecode(stream, rc); let part = model_run[output[i]].ModelDecode(stream, rc); let run = part; let rctx = 256; while (part == 3) { part = model_run[rctx].ModelDecode(stream, rc); rctx = 257; run += part; } for (let j = 1; j <= run; j++) { output[i + j] = output[i]; } i += run + 1; } return output; } // ---------------------------------------------------------------------- // Order-1 RLE codec decodeRLE1(stream, n_out) { const output = new Uint8Array(n_out); let max_sym = stream.ReadByte(); if (max_sym == 0) { max_sym = 256; } const model_lit = new Array(max_sym); for (var i = 0; i < max_sym; i++) { model_lit[i] = new byte_model_ts_1.default(max_sym); } const model_run = new Array(258); for (var i = 0; i <= 257; i++) { model_run[i] = new byte_model_ts_1.default(4); } const rc = new arith_sh_ts_1.default(stream); rc.RangeStartDecode(stream); let last = 0; var i = 0; while (i < n_out) { output[i] = model_lit[last].ModelDecode(stream, rc); last = output[i]; let part = model_run[output[i]].ModelDecode(stream, rc); let run = part; let rctx = 256; while (part == 3) { part = model_run[rctx].ModelDecode(stream, rc); rctx = 257; run += part; } for (let j = 1; j <= run; j++) { output[i + j] = output[i]; } i += run + 1; } return output; } // ---------------------------------------------------------------------- // Pack method decodePackMeta(stream) { this.nsym = stream.ReadByte(); const M = new Array(this.nsym); for (let i = 0; i < this.nsym; i++) { M[i] = stream.ReadByte(); } const e_len = stream.ReadUint7(); // Could be derived data from nsym and n_out return [M, e_len]; } decodePack(data, M, len) { const out = new Uint8Array(len); if (this.nsym <= 1) { // Constant value for (var i = 0; i < len; i++) { out[i] = M[0]; } } else if (this.nsym <= 2) { // 1 bit per value for (var i = 0, j = 0; i < len; i++) { if (i % 8 == 0) { var v = data[j++]; } out[i] = M[v & 1]; v >>= 1; } } else if (this.nsym <= 4) { // 2 bits per value for (var i = 0, j = 0; i < len; i++) { if (i % 4 == 0) { var v = data[j++]; } out[i] = M[v & 3]; v >>= 2; } } else if (this.nsym <= 16) { // 4 bits per value for (var i = 0, j = 0; i < len; i++) { if (i % 2 == 0) { var v = data[j++]; } out[i] = M[v & 15]; v >>= 4; } } else { // 8 bits per value: NOP return data; } return out; } // Compute M array and return meta-data stream packMeta(src) { const stream = new iostream_ts_1.default('', 0, 1024); // Count symbols const M = new Array(256); for (var i = 0; i < src.length; i++) { M[src[i]] = 1; } // Write Map for (var nsym = 0, i = 0; i < 256; i++) { if (M[i]) { M[i] = ++nsym; } } // map to 1..N stream.WriteByte(nsym); // FIXME: add check for nsym > 16? // Or just accept it as an inefficient waste of time. for (var i = 0; i < 256; i++) { if (M[i]) { stream.WriteByte(i); // adjust to 0..N-1 M[i]--; } } return [stream, M, nsym]; } decodeStripe(stream, len) { const N = stream.ReadByte(); // Retrieve lengths const clen = new Array(N); const ulen = new Array(N); for (var j = 0; j < N; j++) { clen[j] = stream.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] = this.decodeStream(stream, 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; } // ---------------------------------------------------------------------- // Cat method decodeCat(stream, len) { const out = new Uint8Array(len); for (let i = 0; i < len; i++) { out[i] = stream.ReadByte(); } return out; } } exports.default = RangeCoderGen; //# sourceMappingURL=arith_gen.js.map