Press n or j to go to the next uncovered block, b, p or k for the previous block.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 | 1x 1x 1x 1x 1x 1x 112x 112x 112x 1x 116x 1x 1x 2x 1x 173x 1x 2x 2x 2x 112x 84x 2x 2x 1x 114x 2x 112x 112x 112x 112x 112x 112x 80x 112x 112x 8x 112x 112x 1x 112x 112x 112x 112x 1x | import * as path from "./path" import { Reader } from "./reader" enum Type { Dir, File, } export interface TarHeader { readonly size: number readonly name: string readonly type: Type } export class TarFile { public constructor( public readonly header: TarHeader, private readonly offset: number, private readonly reader: Reader ) {} public read(): Uint8Array public read(encoding: "utf8"): string public read(encoding?: "utf8"): Uint8Array | string { return this.reader.jump(this.offset).read(this.header.size, encoding as any) // eslint-disable-line @typescript-eslint/no-explicit-any } } export class Tar { private readonly files = new Map<string, TarFile>() public getFile(filePath: string): TarFile | undefined { return this.files.get(filePath) } public static fromUint8Array(array: Uint8Array): Tar { const reader = new Reader(array) const tar = new Tar() let file: TarFile | undefined while ((file = Tar.getNextFile(reader))) { if (file.header.type === Type.File) { tar.files.set(path.normalize(file.header.name), file) } } reader.unclamp() return tar } private static getNextFile(reader: Reader): TarFile | undefined { if (reader.eof()) { return undefined } const header = Tar.parseHeader(reader) reader.jump(512) const offset = reader.offset reader.skip(header.size) // Blocks are 512 in size and the remaining will be padding so we need to // skip past however much padding there is for the last block. const overflow = header.size & 511 if (overflow > 0) { reader.skip(512 - overflow) } // There can also be empty padding block(s) after a file. try { while (reader.peek(1)[0] === 0x00) { reader.skip(512) } } catch (error) { // EOF } reader.clamp() return new TarFile(header, offset, reader) } // See https://www.gnu.org/software/tar/manual/html_node/Standard.html private static parseHeader(reader: Reader): TarHeader { // Tar uses base256 encoding for very large numbers. 0xff is a negative // number and 0x80 is a positive number. const sign = reader.jump(124).peek(1)[0] Iif (sign === 0xff || sign === 0x80) { throw new Error("base256 encoding not supported") } const prefix = reader.jump(345).read(155, "utf8") return { name: (prefix ? prefix + "/" : "") + reader.jump(0).read(100, "utf8"), size: parseInt(reader.jump(124).read(12, "utf8"), 8), type: reader.jump(156).read(1)[0] === 53 ? Type.Dir : Type.File, } } } |