UNPKG

@obsidize/tar-browserify

Version:

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

107 lines (106 loc) 3.81 kB
import { TarUtility } from '../../common/tar-utility'; const ASCII_SPACE = 0x20; const KEY_VALUE_SEPARATOR = '='; /** * Single segment in a PAX header block, represented by a text line with the format: * ```LENGTH KEY=VALUE\n``` */ export class PaxTarHeaderSegment { constructor(mKey = '', mValue = '', mBytes = null) { this.mKey = mKey; this.mValue = mValue; this.mBytes = mBytes; } static serialize(key, value) { if (!key || !value) { return new Uint8Array(0); } const segmentSuffix = ` ${key}=${value}\n`; const preCalculatedLength = segmentSuffix.length.toString().length; let segmentLength = segmentSuffix.length + preCalculatedLength; // Calculation caused decimal rollover, increase combined length by 1 // (e.g. including the length part caused combined length to go from something like '99' to '101') if (segmentLength < (segmentLength.toString().length + segmentSuffix.length)) { segmentLength += 1; } const segment = segmentLength.toString() + segmentSuffix; return TarUtility.encodeString(segment); } static tryParse(bytes, offset = 0) { if (!TarUtility.isUint8Array(bytes)) { return null; } const lengthEndIndex = PaxTarHeaderSegment.findNextLengthEndIndex(bytes, offset); if (lengthEndIndex < 0) { return null; } const segmentLengthStr = TarUtility.decodeString(bytes.slice(offset, lengthEndIndex)); const segmentLength = parseInt(segmentLengthStr, 10); if (isNaN(segmentLength)) { return null; } const kvpStart = lengthEndIndex + 1; const kvpEnd = offset + segmentLength; const kvpData = TarUtility.decodeString(bytes.slice(kvpStart, kvpEnd)); const equalsDelimiterIndex = kvpData.indexOf(KEY_VALUE_SEPARATOR); const key = kvpData.substring(0, equalsDelimiterIndex); const value = kvpData.substring(equalsDelimiterIndex + 1).replace(/\n$/, ''); const segmentBytes = TarUtility.cloneUint8Array(bytes, offset, offset + segmentLength); return new PaxTarHeaderSegment(key, value, segmentBytes); } static findNextLengthEndIndex(bytes, offset) { const NONE = -1; let lengthEnd = offset + 1; let found = false; while (lengthEnd < bytes.byteLength && !found) { if (bytes[lengthEnd] === ASCII_SPACE) { found = true; } else { lengthEnd += 1; } } if (!found) { return NONE; } return lengthEnd; } get key() { return this.mKey; } get value() { return this.mValue; } get bytes() { return this.toUint8Array(); } /** * the value parsed as an integer, or undefined if the parse operation fails */ get intValue() { const parsed = parseInt(this.value); return isNaN(parsed) ? undefined : parsed; } /** * the value parsed as a float, or undefined if the parse operation fails */ get floatValue() { const parsed = parseFloat(this.value); return isNaN(parsed) ? undefined : parsed; } toUint8Array() { if (!TarUtility.isUint8Array(this.mBytes)) { this.mBytes = PaxTarHeaderSegment.serialize(this.key, this.value); } return this.mBytes; } toJSON() { const { key, value, bytes } = this; const content = TarUtility.getDebugHexString(bytes); return { key, value, content }; } }