@shockpkg/ria-packager
Version:
Package for creating Adobe AIR packages
213 lines (190 loc) • 4.91 kB
JavaScript
import { createWriteStream } from 'node:fs';
import { mkdir, open } from 'node:fs/promises';
import { dirname } from 'node:path';
import { Zipper } from "../zipper.mjs";
import { Packager } from "../packager.mjs";
/**
* PackagerAir object.
*/
export class PackagerAir extends Packager {
/**
* Zipper instance.
*/
_zipper = null;
/**
* Zipper hash entry to be updated.
*/
_zipperEntryHash = null;
/**
* PackagerAir constructor.
*
* @param path Output path.
*/
constructor(path) {
super(path);
}
/**
* ZIP file Ux metadata user ID.
*
* @returns User ID.
*/
get _zipUxUid() {
return 203;
}
/**
* ZIP file Ux metadata group ID.
*
* @returns Group ID.
*/
get _zipUxGid() {
return 0;
}
/**
* ZIP file metadata create version number.
*
* @returns Version number.
*/
get _zipCreateVersion() {
return 0x17;
}
/**
* ZIP file metadata create host OS.
*
* @returns OS ID.
*/
get _zipCreateHostOS() {
return 3;
}
/**
* ZIP file internal attributes.
*
* @returns Internal attributes.
*/
get _zipInternalAttributes() {
return 1;
}
/**
* ZIP file external attributes.
*
* @param executable Is the entry executable.
* @returns External attributes.
*/
_zipGetExternalAttributes(executable) {
return executable ? 0x81ed0000 : 0x81a40000;
}
/**
* Create a Zipper instance.
*
* @param writable Writable stream.
* @returns Zipper instance.
*/
_createZipper(writable) {
return new Zipper(writable);
}
/**
* Get the active Zipper.
*
* @returns Zipper instance.
*/
_activeZipper() {
const r = this._zipper;
if (!r) {
throw new Error('Internal error');
}
return r;
}
/**
* Check if resource is compressable file.
*
* @param destination Resource destination.
* @returns Returne true if not a match for the excluded files.
*/
_isResourceCompressible(destination) {
// Do not compress the following resources.
return destination !== this._metaResourceMimetypePath && destination !== this._metaResourceHashPath;
}
/**
* Check if resource is hash file.
*
* @param destination Resource destination.
* @returns Returns true if match.
*/
_isResourceHash(destination) {
return destination === this._metaResourceHashPath;
}
/**
* Open implementation.
*/
async _open() {
const {
path
} = this;
await mkdir(dirname(path), {
recursive: true
});
this._zipper = this._createZipper(createWriteStream(path));
}
/**
* Close implementation.
*/
async _close() {
const zipper = this._activeZipper();
await zipper.close();
this._zipper = null;
// Update the hash in the hash meta resource, if present.
const hashEntry = this._zipperEntryHash;
if (!hashEntry) {
return;
}
this._zipperEntryHash = null;
// First get the digest.
const hashDigest = this._hasher.digest();
// Get the offset of the local file header.
const {
headerOffsetLocal
} = hashEntry;
// Init entry with the hash data, no compression.
await hashEntry.initData(hashDigest, false);
// Encode the local file header.
const local = hashEntry.encodeLocal();
// Merge both the header and digest together, write all at once.
const data = new Uint8Array(local.length + hashDigest.length);
data.set(local);
data.set(hashDigest, local.length);
// Write that buffer at the offset.
const f = await open(this.path, 'r+');
try {
await f.write(data, 0, data.length, headerOffsetLocal);
} finally {
await f.close();
}
}
/**
* Write resource with data implementation.
*
* @param destination Packaged file relative destination.
* @param data Resource data.
* @param options Resource options.
*/
async _writeResource(destination, data, options) {
const zipper = this._activeZipper();
const compressible = this._isResourceCompressible(destination);
const hash = this._isResourceHash(destination);
const mtime = options.mtime || new Date();
const entry = zipper.createEntry();
entry.path = new TextEncoder().encode(destination);
entry.createVersion = this._zipCreateVersion;
entry.createHostOS = this._zipCreateHostOS;
entry.internalAttributes = this._zipInternalAttributes;
entry.externalAttributes = this._zipGetExternalAttributes(options.executable === true);
entry.setDate(mtime);
entry.addExtraFieldsExtendedTimestamp(mtime, mtime, null);
entry.addExtraFieldsInfoZipUnix2(this._zipUxUid, this._zipUxGid);
const entryData = await entry.initData(data, compressible ? null : false);
await zipper.addEntry(entry, entryData);
if (hash) {
this._zipperEntryHash = entry;
}
}
}
//# sourceMappingURL=air.mjs.map