UNPKG

@obsidize/tar-browserify

Version:

Browser-based tar utility for packing and unpacking tar files (stream-capable)

238 lines (237 loc) 8.55 kB
import { Constants } from '../../common/constants'; import { TarUtility } from '../../common/tar-utility'; import { UstarHeaderFieldTransformType } from './ustar-header-field-transform'; import { UstarHeaderFieldType } from './ustar-header-field-type'; /** * Definitions taken from here: * https://en.wikipedia.org/wiki/Tar_(computing) */ export class UstarHeaderField { constructor(config) { this.name = config.name; this.offset = config.offset; this.size = config.size; this.type = config.type; this.constantValue = config.constantValue || undefined; this.transform = UstarHeaderFieldTransformType.from(this.type); } static frozen(config) { return Object.freeze(new UstarHeaderField(config)); } static all() { return [ UstarHeaderField.fileName, UstarHeaderField.fileMode, UstarHeaderField.ownerUserId, UstarHeaderField.groupUserId, UstarHeaderField.fileSize, UstarHeaderField.lastModified, UstarHeaderField.headerChecksum, UstarHeaderField.typeFlag, UstarHeaderField.linkedFileName, UstarHeaderField.ustarIndicator, UstarHeaderField.ustarVersion, UstarHeaderField.ownerUserName, UstarHeaderField.ownerGroupName, UstarHeaderField.deviceMajorNumber, UstarHeaderField.deviceMinorNumber, UstarHeaderField.fileNamePrefix, ]; } static checksumSet() { return UstarHeaderField.all().filter((v) => v !== UstarHeaderField.headerChecksum); } // ===================================================================== // Instance Methods // ===================================================================== /** * Shorthand for padding the output of `slice` into `decodeString`. */ sliceString(input, offset) { return TarUtility.decodeString(this.slice(input, offset)); } /** * @param input - a buffer of one or more complete tar sectors * @param offset - the offset to slice from (must be a multiple of `SECTOR_SIZE`) * @returns the slice of the given input Uint8Array that this field resides in. */ slice(input, offset = 0) { if (!TarUtility.isUint8Array(input)) { return new Uint8Array(0); } const start = offset + this.offset; const end = start + this.size; return input.slice(start, end); } /** * @param input - a buffer of one or more complete tar sectors * @returns The value parsed from the input based on this field's transform type, * or `undefined` on error. */ deserialize(input, offset = 0) { if (TarUtility.isUint8Array(input)) { return this.transform.deserialize(input, this.size, offset); } return undefined; } /** * @param input - the value to be serialized, based on this field's transform type. * @returns the serialized value as a Uint8Array */ serialize(input) { const result = new Uint8Array(this.size); const value = this.transform.serialize(input, this.size); result.set(value, 0); return result; } /** * Runs `deserialize()` while also taking this field's offset into account. */ readFrom(input, offset) { return this.deserialize(input, offset + this.offset); } /** * Serialize the given value and set the output bytes in the given output buffer. * @param output - the output buffer to be written to * @param headerOffset - the offset of the header in the output buffer to insert the update. * Note that this field's offset will be added to the header offset when inserting. * @param value - the value to be serialized * @returns true if the buffer was updated */ writeTo(output, headerOffset, value) { headerOffset = Math.max(headerOffset, 0); const valueBytes = this.serialize(value); const valueByteLength = valueBytes.byteLength; const absoluteOffset = headerOffset + this.offset; if (valueByteLength > 0 && TarUtility.isUint8Array(output) && output.byteLength >= absoluteOffset + valueByteLength) { output.set(valueBytes, absoluteOffset); return true; } return false; } /** * Calculates the checksum value for this field in the given input buffer, at the given offset. * All field checksum values are aggregated together to form the main header checksum entry. * @param input - the input buffer to extract a field checksum from * @param offset - the offset of the header in the buffer (will be combined with this field's offset) * @returns the checksum value for this specific field */ calculateChecksum(input, offset = 0) { let checksum = 0; if (!TarUtility.isUint8Array(input)) { return checksum; } const start = offset + this.offset; const end = start + this.size; for (let i = start; i < end; i++) { checksum += input[i]; } return checksum; } } // ===================================================================== // Legacy Fields // ===================================================================== UstarHeaderField.fileName = UstarHeaderField.frozen({ name: 'fileName', offset: 0, size: 100, type: UstarHeaderFieldType.ASCII_PADDED_END, }); UstarHeaderField.fileMode = UstarHeaderField.frozen({ name: 'fileMode', offset: 100, size: 8, type: UstarHeaderFieldType.INTEGER_OCTAL, }); UstarHeaderField.ownerUserId = UstarHeaderField.frozen({ name: 'ownerUserId', offset: 108, size: 8, type: UstarHeaderFieldType.INTEGER_OCTAL, }); UstarHeaderField.groupUserId = UstarHeaderField.frozen({ name: 'groupUserId', offset: 116, size: 8, type: UstarHeaderFieldType.INTEGER_OCTAL, }); UstarHeaderField.fileSize = UstarHeaderField.frozen({ name: 'fileSize', offset: 124, size: 12, type: UstarHeaderFieldType.INTEGER_OCTAL, }); UstarHeaderField.lastModified = UstarHeaderField.frozen({ name: 'lastModified', offset: 136, size: 12, type: UstarHeaderFieldType.INTEGER_OCTAL_TIMESTAMP, }); UstarHeaderField.headerChecksum = UstarHeaderField.frozen({ name: 'headerChecksum', offset: 148, size: 8, type: UstarHeaderFieldType.INTEGER_OCTAL, }); UstarHeaderField.typeFlag = UstarHeaderField.frozen({ name: 'typeFlag', offset: 156, size: 1, type: UstarHeaderFieldType.ASCII, }); UstarHeaderField.linkedFileName = UstarHeaderField.frozen({ name: 'linkedFileName', offset: 157, size: 100, type: UstarHeaderFieldType.ASCII_PADDED_END, }); // ===================================================================== // USTAR Fields // ===================================================================== UstarHeaderField.ustarIndicator = UstarHeaderField.frozen({ name: 'ustarIndicator', offset: 257, size: 6, type: UstarHeaderFieldType.ASCII, constantValue: Constants.USTAR_INDICATOR_VALUE, }); UstarHeaderField.ustarVersion = UstarHeaderField.frozen({ name: 'ustarVersion', offset: 263, size: 2, type: UstarHeaderFieldType.ASCII, constantValue: Constants.USTAR_VERSION_VALUE, }); UstarHeaderField.ownerUserName = UstarHeaderField.frozen({ name: 'ownerUserName', offset: 265, size: 32, type: UstarHeaderFieldType.ASCII_PADDED_END, }); UstarHeaderField.ownerGroupName = UstarHeaderField.frozen({ name: 'ownerGroupName', offset: 297, size: 32, type: UstarHeaderFieldType.ASCII_PADDED_END, }); UstarHeaderField.deviceMajorNumber = UstarHeaderField.frozen({ name: 'deviceMajorNumber', offset: 329, size: 8, type: UstarHeaderFieldType.ASCII_PADDED_END, }); UstarHeaderField.deviceMinorNumber = UstarHeaderField.frozen({ name: 'deviceMinorNumber', offset: 337, size: 8, type: UstarHeaderFieldType.ASCII_PADDED_END, }); UstarHeaderField.fileNamePrefix = UstarHeaderField.frozen({ name: 'fileNamePrefix', offset: 345, size: 155, type: UstarHeaderFieldType.ASCII_PADDED_END, });