UNPKG

@shockpkg/ria-packager

Version:

Package for creating Adobe AIR packages

702 lines (562 loc) 14.6 kB
import _defineProperty from "@babel/runtime/helpers/defineProperty"; /* eslint-disable max-classes-per-file */ import { deflateRaw } from 'zlib'; import bufferCrc32 from 'buffer-crc32'; /** * Convert Date object or timestamp to DOS date and time values. * * @param date Data object or timestamp. * @returns Date and time values. */ function dateToDosTime(date) { const d = typeof date === 'number' ? new Date(date * 1000) : date; return { date: // eslint-disable-next-line no-bitwise d.getDate() & 0x1F | (d.getMonth() + 1 & 0xF) << 5 | (d.getFullYear() - 1980 & 0x7F) << 9, time: // eslint-disable-next-line no-bitwise Math.floor(d.getSeconds() / 2) | (d.getMinutes() & 0x3F) << 5 | (d.getHours() & 0x1F) << 11 }; } /** * Zipper Entry Extra Field. */ export class ZipperEntryExtraField extends Object { /** * Type ID. */ /** * Data for the type. */ constructor() { super(); _defineProperty(this, "type", 0); _defineProperty(this, "data", null); } /** * Encode type and data as buffer. * * @returns Buffer data. */ toBuffer() { const { data } = this; const b = Buffer.alloc(4); b.writeUInt16LE(this.type, 0); if (data) { b.writeUInt16LE(data.length, 2); } return data ? Buffer.concat([b, data]) : b; } /** * Init Info-ZIP UNIX type 2 data, local header. * * @param uid User ID. * @param gid Group ID. */ initInfoZipUnix2Local(uid = 0, gid = 0) { this._initInfoZipUnix2(true, uid, gid); } /** * Init Info-ZIP UNIX type 2 data, central header. * * @param uid User ID. * @param gid Group ID. */ initInfoZipUnix2Central(uid = 0, gid = 0) { this._initInfoZipUnix2(false, uid, gid); } /** * Init Extended Timestamp data, local header. * * @param mtime Modification time. * @param atime Access time. * @param ctime Creation time. */ initExtendedTimestampLocal(mtime = null, atime = null, ctime = null) { this._initExtendedTimestamp(true, mtime, atime, ctime); } /** * Init Extended Timestamp data, central header. * * @param mtime Modification time. * @param atime Access time. * @param ctime Creation time. */ initExtendedTimestampCentral(mtime = null, atime = null, ctime = null) { this._initExtendedTimestamp(false, mtime, atime, ctime); } /** * Init Info-ZIP UNIX type 2 data. * * @param local Local header or central. * @param uid User ID. * @param gid Group ID. */ _initInfoZipUnix2(local, uid, gid) { const d = local ? Buffer.alloc(4) : null; if (d) { d.writeUInt16LE(uid, 0); d.writeUInt16LE(gid, 2); } // Type: 'Ux' this.type = 0x7855; this.data = d; } /** * Init Extended Timestamp data. * * @param local Local header or central. * @param mtime Modification time. * @param atime Access time. * @param ctime Creation time. */ _initExtendedTimestamp(local, mtime, atime, ctime) { let flags = 0; const flagsB = Buffer.alloc(1); const buffers = [flagsB]; [mtime, atime, ctime].forEach((v, i) => { if (v === null) { return; } // eslint-disable-next-line no-bitwise flags |= 1 << i; if (!local && !i) { return; } const time = typeof v === 'number' ? v : Math.round(v.getTime() / 1000); const b = Buffer.alloc(4); b.writeUInt32LE(time, 0); buffers.push(b); }); flagsB.writeUInt8(flags, 0); // Type: 'UT' this.type = 0x5455; this.data = Buffer.concat(buffers); } } /** * Zipper Entry. */ export class ZipperEntry extends Object { /** * Tag signature, local header. */ /** * Tag signature, central header. */ /** * Extract version. */ /** * Extract host OS. */ /** * Create version. */ /** * Create host OS. */ /** * Extract flags. */ /** * Compression type. */ /** * DOS time. */ /** * DOS date. */ /** * Data CRC32. */ /** * Size compressed. */ /** * Size uncompressed. */ /** * Disk number start. */ /** * Internal attributes. */ /** * External attributes. */ /** * Header offset, local header. */ /** * Entry path. */ /** * Entry comment. */ /** * Extra fields, local header. */ /** * Extra fields, central header. */ constructor() { super(); _defineProperty(this, "signatureLocal", 0x4034B50); _defineProperty(this, "signatureCentral", 0x2014B50); _defineProperty(this, "extractVersion", 0x14); _defineProperty(this, "extractHostOS", 0); _defineProperty(this, "createVersion", 0x14); _defineProperty(this, "createHostOS", 0); _defineProperty(this, "flags", 0); _defineProperty(this, "compression", 0); _defineProperty(this, "time", 0); _defineProperty(this, "date", 0); _defineProperty(this, "crc32", 0); _defineProperty(this, "sizeCompressed", 0); _defineProperty(this, "sizeUncompressed", 0); _defineProperty(this, "diskNumberStart", 0); _defineProperty(this, "internalAttributes", 0); _defineProperty(this, "externalAttributes", 0); _defineProperty(this, "headerOffsetLocal", 0); _defineProperty(this, "path", ''); _defineProperty(this, "comment", ''); _defineProperty(this, "extraFieldsLocal", []); _defineProperty(this, "extraFieldsCentral", []); } /** * Create new ZipperEntryExtraField object. * * @returns ZipperEntryExtraField object. */ createExtraField() { return new ZipperEntryExtraField(); } /** * Set date from a date object or timestamp. * * @param date Date object or timestamp. */ setDate(date) { const dosTime = this._dateToDosTime(date); this.date = dosTime.date; this.time = dosTime.time; } /** * Get path as data. * * @returns Path as data buffer. */ getPathBuffer() { return Buffer.from(this.path, 'utf8'); } /** * Get comment as data. * * @returns Comment as data buffer. */ getCommentBuffer() { return Buffer.from(this.comment, 'utf8'); } /** * Get the file record extra fields as data. * * @returns Extra fields as data. */ getExtraFieldsLocalBuffer() { return Buffer.concat(this.extraFieldsLocal.map(e => e.toBuffer())); } /** * Get the director entry extra fields as data. * * @returns Extra fields as data. */ getExtraFieldsCentralBuffer() { return Buffer.concat(this.extraFieldsCentral.map(e => e.toBuffer())); } /** * Get file record data. * * @returns File record data. */ getLocalBuffer() { const pathBuffer = this.getPathBuffer(); const extraFieldsBuffer = this.getExtraFieldsLocalBuffer(); const head = Buffer.alloc(30); head.writeUInt32LE(this.signatureLocal, 0); head.writeUInt8(this.extractVersion, 4); head.writeUInt8(this.extractHostOS, 5); head.writeUInt16LE(this.flags, 6); head.writeUInt16LE(this.compression, 8); head.writeUInt16LE(this.time, 10); head.writeUInt16LE(this.date, 12); head.writeUInt32LE(this.crc32, 14); head.writeUInt32LE(this.sizeCompressed, 18); head.writeUInt32LE(this.sizeUncompressed, 22); head.writeUInt16LE(pathBuffer.length, 26); head.writeUInt16LE(extraFieldsBuffer.length, 28); return Buffer.concat([head, pathBuffer, extraFieldsBuffer]); } /** * Get directory entry data. * * @returns Directory entry data. */ getCentralBuffer() { const pathBuffer = this.getPathBuffer(); const extraFieldsBuffer = this.getExtraFieldsCentralBuffer(); const commentBuffer = this.getCommentBuffer(); const head = Buffer.alloc(46); head.writeUInt32LE(this.signatureCentral, 0); head.writeUInt8(this.createVersion, 4); head.writeUInt8(this.createHostOS, 5); head.writeUInt8(this.extractVersion, 6); head.writeUInt8(this.extractHostOS, 7); head.writeUInt16LE(this.flags, 8); head.writeUInt16LE(this.compression, 10); head.writeUInt16LE(this.time, 12); head.writeUInt16LE(this.date, 14); head.writeUInt32LE(this.crc32, 16); head.writeUInt32LE(this.sizeCompressed, 20); head.writeUInt32LE(this.sizeUncompressed, 24); head.writeUInt16LE(pathBuffer.length, 28); head.writeUInt16LE(extraFieldsBuffer.length, 30); head.writeUInt16LE(commentBuffer.length, 32); head.writeUInt16LE(this.diskNumberStart, 34); head.writeUInt16LE(this.internalAttributes, 36); head.writeUInt32LE(this.externalAttributes, 38); head.writeUInt32LE(this.headerOffsetLocal, 42); return Buffer.concat([head, pathBuffer, extraFieldsBuffer, commentBuffer]); } /** * Setup data for entry. * * @param data Data for the entry. * @param compress Compress option, true to force, false to disable. * @returns Resulting data, or null if no data passed. */ async initData(data, compress = null) { this.compression = 0; this.crc32 = 0; this.sizeCompressed = 0; this.sizeUncompressed = 0; if (!data) { return null; } const crc32 = this._bufferCrc32(data); if (compress === false) { this.crc32 = crc32; this.sizeCompressed = this.sizeUncompressed = data.length; this.compression = 0; return data; } if (compress === true) { const comp = await this._zlibDeflateRaw(data); this.crc32 = crc32; this.sizeUncompressed = data.length; this.sizeCompressed = comp.length; this.compression = 8; return comp; } const comp = await this._zlibDeflateRaw(data); const r = comp.length < data.length ? comp : data; this.crc32 = crc32; this.sizeUncompressed = data.length; this.sizeCompressed = r.length; this.compression = r === data ? 0 : 8; return r; } /** * Add extra fields for Extended Timestamp. * * @param mtime Modification time. * @param atime Access time. * @param ctime Creation time. */ addExtraFieldsExtendedTimestamp(mtime = null, atime = null, ctime = null) { const efl = this.createExtraField(); efl.initExtendedTimestampLocal(mtime, atime, ctime); this.extraFieldsLocal.push(efl); const efc = this.createExtraField(); efc.initExtendedTimestampCentral(mtime, atime, ctime); this.extraFieldsCentral.push(efc); } /** * Add extra fields for Info-ZIP UNIX type 2. * * @param uid User ID. * @param gid Group ID. */ addExtraFieldsInfoZipUnix2(uid = 0, gid = 0) { const efl = this.createExtraField(); efl.initInfoZipUnix2Local(uid, gid); this.extraFieldsLocal.push(efl); const efc = this.createExtraField(); efc.initInfoZipUnix2Central(uid, gid); this.extraFieldsCentral.push(efc); } /** * Convert date from a date object or timestamp. * * @param date Date object or timestamp. * @returns DOS time. */ _dateToDosTime(date) { return dateToDosTime(date); } /** * Calculate the CRC32 hash for data. * * @param data Data to be hashed. * @returns CRC32 hash. */ _bufferCrc32(data) { return bufferCrc32.unsigned(data); } /** * Zlib deflate raw data. * * @param data Data to be compressed. * @returns Compressed data. */ async _zlibDeflateRaw(data) { return new Promise((resolve, reject) => { deflateRaw(data, (err, comp) => { if (err) { reject(err); return; } resolve(comp); }); }); } } /** * Zipper, a low-level ZIP file writter. * * @param output Writable stream. */ export class Zipper extends Object { /** * Tag signature. */ /** * Archive comment. */ /** * Added entries. */ /** * Current offset. */ /** * Output stream. */ constructor(output) { super(); _defineProperty(this, "signature", 0x6054B50); _defineProperty(this, "comment", ''); _defineProperty(this, "entries", []); _defineProperty(this, "_offset", 0); _defineProperty(this, "_output", void 0); this._output = output; } /** * Create new ZipperEntry object. * * @returns ZipperEntry object. */ createEntry() { return new ZipperEntry(); } /** * Get comment as data. * * @returns Comment data. */ getCommentBuffer() { return Buffer.from(this.comment, 'utf8'); } /** * Get directory buffer data. * * @returns Directory data. */ getDirectoryBuffer() { const { _offset, entries } = this; const directoryData = Buffer.concat(entries.map(e => e.getCentralBuffer())); const commentBuffer = this.getCommentBuffer(); const end = Buffer.alloc(22); end.writeUInt32LE(this.signature, 0); end.writeUInt16LE(0, 4); end.writeUInt16LE(0, 6); end.writeUInt16LE(entries.length, 8); end.writeUInt16LE(entries.length, 10); end.writeUInt32LE(directoryData.length, 12); end.writeUInt32LE(_offset, 16); end.writeUInt16LE(commentBuffer.length, 20); return Buffer.concat([directoryData, end, commentBuffer]); } /** * Add Entry and any associated data. * * @param entry Entry object. * @param data Data from the entry initData method. */ async addEntry(entry, data = null) { const { _offset } = this; const { sizeCompressed } = entry; if (data) { if (data.length !== sizeCompressed) { throw new Error('Data length and compressed size must match'); } } else if (sizeCompressed) { throw new Error('Data required when compressed size not zero'); } entry.headerOffsetLocal = _offset; this.entries.push(entry); await this._writeOutput(entry.getLocalBuffer()); if (data) { await this._writeOutput(data); } } /** * Close stream. */ async close() { await this._writeOutput(this.getDirectoryBuffer()); await new Promise((resolve, reject) => { this._output.end(err => { if (err) { reject(err); return; } resolve(); }); }); } /** * Write data buffer to output stream. * * @param data Data buffer. */ async _writeOutput(data) { await new Promise((resolve, reject) => { this._output.write(data, err => { if (err) { reject(err); return; } resolve(); }); }); this._offset += data.length; } } //# sourceMappingURL=zipper.mjs.map