var tar = tar || {}; tar.Archive = class { static open(data) { const stream = data instanceof Uint8Array ? new tar.BinaryReader(data) : data; if (stream.length > 512) { const buffer = stream.peek(512); const sum = buffer.map((value, index) => (index >= 148 && index < 156) ? 32 : value).reduce((a, b) => a + b, 0); let checksum = ''; for (let i = 148; i < 156 && buffer[i] !== 0x00; i++) { checksum += String.fromCharCode(buffer[i]); } checksum = parseInt(checksum, 8); if (!isNaN(checksum) && sum === checksum) { return new tar.Archive(stream); } } return null; } constructor(stream) { this._entries = new Map(); const position = stream.position; while (stream.position < stream.length) { const entry = new tar.Entry(stream); if (entry.type === '0' || entry.type === '1' || entry.type === '2') { this._entries.set(entry.name, entry.stream); } if (stream.position + 512 > stream.length || stream.peek(512).every((value) => value === 0x00)) { break; } } stream.seek(position); } get entries() { return this._entries; } }; tar.Entry = class { constructor(stream) { const buffer = stream.read(512); const reader = new tar.BinaryReader(buffer); const sum = buffer.map((value, index) => (index >= 148 && index < 156) ? 32 : value).reduce((a, b) => a + b, 0); let checksum = ''; for (let i = 148; i < 156 && buffer[i] !== 0x00; i++) { checksum += String.fromCharCode(buffer[i]); } checksum = parseInt(checksum, 8); if (isNaN(checksum) || sum !== checksum) { throw new tar.Error('Invalid tar archive.'); } this._name = reader.string(100); reader.string(8); // file mode reader.string(8); // owner reader.string(8); // group const size = parseInt(reader.string(12).trim(), 8); reader.string(12); // timestamp reader.string(8); // checksum this._type = reader.string(1); reader.string(100); // name of linked file if (reader.string(6) === 'ustar') { reader.string(2); // ustar version reader.string(32); // owner user name reader.string(32); // owner group name reader.string(8); // device major number reader.string(8); // device number number this._name = reader.string(155) + this._name; } this._stream = stream.stream(size); stream.read(((size % 512) != 0) ? (512 - (size % 512)) : 0); } get type() { return this._type; } get name() { return this._name; } get stream() { return this._stream; } }; tar.BinaryReader = class { constructor(buffer) { this._buffer = buffer; this._length = buffer.length; this._position = 0; this._view = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength); } get position() { return this._position; } get length() { return this._length; } create(buffer) { return new tar.BinaryReader(buffer); } stream(length) { return this.create(this.read(length)); } seek(position) { this._position = position >= 0 ? position : this._length + position; } skip(offset) { this._position += offset; } peek(length) { if (this._position === 0 && length === undefined) { return this._buffer; } const position = this._position; this.skip(length !== undefined ? length : this._length - this._position); const end = this._position; this.seek(position); return this._buffer.subarray(position, end); } read(length) { if (this._position === 0 && length === undefined) { this._position = this._length; return this._buffer; } const position = this._position; this.skip(length !== undefined ? length : this._length - this._position); return this._buffer.subarray(position, this._position); } string(length) { const buffer = this.read(length); let position = 0; let content = ''; for (let i = 0; i < length; i++) { const c = buffer[position++]; if (c === 0) { break; } content += String.fromCharCode(c); } return content; } }; tar.Error = class extends Error { constructor(message) { super(message); this.name = 'tar Error'; } }; if (typeof module !== 'undefined' && typeof module.exports === 'object') { module.exports.Archive = tar.Archive; }