/* jshint esversion: 6 */ /* global pako */ var gzip = gzip || {}; gzip.Archive = class { constructor(buffer) { this._entries = []; if (buffer.length < 18 || buffer[0] != 0x1f || buffer[1] != 0x8b) { throw new gzip.Error('Invalid GZIP archive.'); } const reader = new gzip.Reader(buffer, 0, buffer.length); this._entries.push(new gzip.Entry(reader)); } get entries() { return this._entries; } }; gzip.Entry = class { constructor(reader) { if (!reader.match([ 0x1f, 0x8b ])) { throw new gzip.Error('Invalid GZIP signature.'); } const compressionMethod = reader.byte(); if (compressionMethod != 8) { throw new gzip.Error("Invalid compression method '" + compressionMethod.toString() + "'."); } const flags = reader.byte(); reader.uint32(); // MTIME reader.byte(); reader.byte(); // OS if ((flags & 4) != 0) { const xlen = reader.uint16(); reader.skip(xlen); } if ((flags & 8) != 0) { this._name = reader.string(); } if ((flags & 16) != 0) { // FLG.FCOMMENT reader.string(); } if ((flags & 1) != 0) { reader.uint16(); // CRC16 } const compressedData = reader.bytes(); if (typeof process === 'object' && typeof process.versions == 'object' && typeof process.versions.node !== 'undefined') { this._data = require('zlib').inflateRawSync(compressedData); } else if (typeof pako !== 'undefined') { this._data = pako.inflateRaw(compressedData); } else { this._data = new require('./zip').Inflater().inflateRaw(compressedData); } reader.position = -8; reader.uint32(); // CRC32 const size = reader.uint32(); if (size != this._data.length) { throw new gzip.Error('Invalid size.'); } } get name() { return this._name; } get data() { return this._data; } }; gzip.Reader = class { constructor(buffer, start, end) { this._buffer = buffer; this._position = start; this._end = end; } match(signature) { if (this._position + signature.length <= this._end) { for (let i = 0; i < signature.length; i++) { if (this._buffer[this._position + i] != signature[i]) { return false; } } } this._position += signature.length; return true; } get position() { return this._position; } set position(value) { this._position = value >= 0 ? value : this._end + value; } skip(size) { if (this._position + size > this._end) { throw new gzip.Error('Data not available.'); } this._position += size; } bytes(size) { if (this._position + size > this._end) { throw new gzip.Error('Data not available.'); } size = size === undefined ? this._end : size; const data = this._buffer.subarray(this._position, this._position + size); this._position += size; return data; } byte() { if (this._position + 1 > this._end) { throw new gzip.Error('Data not available.'); } const value = this._buffer[this._position]; this._position++; return value; } uint16() { if (this._position + 2 > this._end) { throw new gzip.Error('Data not available.'); } const value = this._buffer[this._position] | (this._buffer[this._position + 1] << 8); this._position += 2; return value; } uint32() { return this.uint16() | (this.uint16() << 16); } string() { let result = ''; const end = this._buffer.indexOf(0x00, this._position); if (end < 0) { throw new gzip.Error('End of string not found.'); } while (this._position < end) { result += String.fromCharCode(this._buffer[this._position++]); } this._position++; return result; } }; gzip.Error = class extends Error { constructor(message) { super(message); this.name = 'gzip Error'; } }; if (typeof module !== 'undefined' && typeof module.exports === 'object') { module.exports.Archive = gzip.Archive; }