@shockpkg/dir-projector
Version:
Package for creating Shockwave Director projectors
768 lines (614 loc) • 15.7 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.ProjectorMacApp = void 0;
var _path = require("path");
var _projector = require("../projector");
var _util = require("../util");
/**
* ProjectorMacApp constructor.
*
* @param options Options object.
*/
class ProjectorMacApp extends _projector.Projector {
/**
* Binary name.
*
* @default null
*/
/**
* Intel binary package, not universal binary.
*
* @default false
*/
/**
* Icon file.
*
* @default null
*/
/**
* Icon data.
*
* @default null
*/
/**
* Info.plist file.
*
* @default null
*/
/**
* Info.plist data.
*
* @default null
*/
/**
* PkgInfo file.
*
* @default null
*/
/**
* PkgInfo data.
*
* @default null
*/
/**
* Nest Xtras at *.app/Contents/xtras.
*
* @default false
*/
constructor(options = {}) {
super(options);
this.binaryName = void 0;
this.intel = void 0;
this.iconFile = void 0;
this.iconData = void 0;
this.infoPlistFile = void 0;
this.infoPlistData = void 0;
this.pkgInfoFile = void 0;
this.pkgInfoData = void 0;
this.nestXtrasContents = void 0;
this.binaryName = (0, _util.defaultNull)(options.binaryName);
this.intel = (0, _util.defaultFalse)(options.intel);
this.iconFile = (0, _util.defaultNull)(options.iconFile);
this.iconData = (0, _util.defaultNull)(options.iconData);
this.infoPlistFile = (0, _util.defaultNull)(options.infoPlistFile);
this.infoPlistData = (0, _util.defaultNull)(options.infoPlistData);
this.pkgInfoFile = (0, _util.defaultNull)(options.pkgInfoFile);
this.pkgInfoData = (0, _util.defaultNull)(options.pkgInfoData);
this.nestXtrasContents = (0, _util.defaultFalse)(options.nestXtrasContents);
}
/**
* Projector file extension.
*
* @returns File extension.
*/
get projectorExtension() {
return '.app';
}
/**
* Config file newline characters.
*
* @returns Newline characters.
*/
get configNewline() {
return '\n';
}
/**
* Config file newline characters.
*
* @returns Newline characters.
*/
get lingoNewline() {
return '\n';
}
/**
* Splash image file extension.
*
* @returns File extension.
*/
get splashImageExtension() {
return '.pict';
}
/**
* If icon is specified.
*
* @returns Has icon.
*/
get hasIcon() {
return !!(this.iconData || this.iconFile);
}
/**
* If Info.plist is specified.
*
* @returns Has Info.plist.
*/
get hasInfoPlist() {
return !!(this.infoPlistData || this.infoPlistFile);
}
/**
* If PkgInfo is specified.
*
* @returns Has PkgInfo.
*/
get hasPkgInfo() {
return !!(this.pkgInfoData || this.pkgInfoFile);
}
/**
* Get the Projector Resources directory name.
*
* @returns Directory name.
*/
get projectorResourcesDirectoryName() {
return this.intel ? 'Projector Intel Resources' : 'Projector Resources';
}
/**
* Get app binary name.
*
* @returns File name.
*/
get appBinaryName() {
return this.appBinaryNameCustom || this.appBinaryNameDefault;
}
/**
* Get app binary name, default.
*
* @returns File name.
*/
get appBinaryNameDefault() {
return 'Projector';
}
/**
* Get app binary name, custom.
*
* @returns File name.
*/
get appBinaryNameCustom() {
return this.binaryName;
}
/**
* Get app icon name.
*
* @returns File name.
*/
get appIconName() {
return this.appIconNameCustom || this.appIconNameDefault;
}
/**
* Get app icon name, default.
*
* @returns File name.
*/
get appIconNameDefault() {
return 'projector.icns';
}
/**
* Get app icon name, custom.
*
* @returns File name.
*/
get appIconNameCustom() {
const n = this.binaryName;
return n ? `${n}.icns` : null;
}
/**
* Get app rsrc name.
*
* @returns File name.
*/
get appRsrcName() {
return this.appRsrcNameCustom || this.appRsrcNameDefault;
}
/**
* Get app rsrc name, default.
*
* @returns File name.
*/
get appRsrcNameDefault() {
return 'Projector.rsrc';
}
/**
* Get app rsrc name, custom.
*
* @returns File name.
*/
get appRsrcNameCustom() {
const n = this.binaryName;
return n ? `${n}.rsrc` : null;
}
/**
* Get app Info.plist path.
*
* @returns File path.
*/
get appPathInfoPlist() {
return 'Contents/Info.plist';
}
/**
* Get app PkgInfo path.
*
* @returns File path.
*/
get appPathPkgInfo() {
return 'Contents/PkgInfo';
}
/**
* Get app Frameworks path.
*
* @returns File path.
*/
get appPathFrameworks() {
return 'Contents/Frameworks';
}
/**
* Get app Xtras path.
*
* @returns Directory path.
*/
get appPathXtras() {
return `Contents/${this.xtrasDirectoryName}`;
}
/**
* Get app binary path.
*
* @returns File path.
*/
get appPathBinary() {
return this.appPathBinaryCustom || this.appPathBinaryDefault;
}
/**
* Get app binary path, default.
*
* @returns File path.
*/
get appPathBinaryDefault() {
return `Contents/MacOS/${this.appBinaryNameDefault}`;
}
/**
* Get app binary path, custom.
*
* @returns File path.
*/
get appPathBinaryCustom() {
const n = this.appBinaryNameCustom;
return n ? `Contents/MacOS/${n}` : null;
}
/**
* Get app icon path.
*
* @returns File path.
*/
get appPathIcon() {
return this.appPathIconCustom || this.appPathIconDefault;
}
/**
* Get app icon path, default.
*
* @returns File path.
*/
get appPathIconDefault() {
return `Contents/Resources/${this.appIconNameDefault}`;
}
/**
* Get app icon path, custom.
*
* @returns File path.
*/
get appPathIconCustom() {
const n = this.appIconNameCustom;
return n ? `Contents/Resources/${n}` : null;
}
/**
* Get app rsrc path.
*
* @returns File path.
*/
get appPathRsrc() {
return this.appPathRsrcCustom || this.appPathRsrcDefault;
}
/**
* Get app rsrc path, default.
*
* @returns File path.
*/
get appPathRsrcDefault() {
return `Contents/Resources/${this.appRsrcNameDefault}`;
}
/**
* Get app rsrc path, custom.
*
* @returns File path.
*/
get appPathRsrcCustom() {
const n = this.appRsrcNameCustom;
return n ? `Contents/Resources/${n}` : null;
}
/**
* Get icon data if any specified, from data or file.
*
* @returns Icon data or null.
*/
async getIconData() {
return this._dataFromBufferOrFile(this.iconData, this.iconFile);
}
/**
* Get Info.plist data if any specified, from data or file.
*
* @returns Info.plist data or null.
*/
async getInfoPlistData() {
return this._dataFromValueOrFile(this.infoPlistData, this.infoPlistFile, '\n', 'utf8');
}
/**
* Get PkgInfo data if any specified, from data or file.
*
* @returns PkgInfo data or null.
*/
async getPkgInfoData() {
return this._dataFromValueOrFile(this.pkgInfoData, this.pkgInfoFile, null, 'ascii');
}
/**
* Get the Xtras path.
*
* @param name Save name.
* @returns Xtras path.
*/
getXtrasPath(name) {
if (this.nestXtrasContents) {
return `${name}/${this.appPathXtras}`;
}
return super.getXtrasPath(name);
}
/**
* Get the icon path.
*
* @param name Save name.
* @returns Icon path.
*/
getIconPath(name) {
return `${name}/${this.appPathIcon}`;
}
/**
* Get the Info.plist path.
*
* @param name Save name.
* @returns Icon path.
*/
getInfoPlistPath(name) {
return `${name}/${this.appPathInfoPlist}`;
}
/**
* Get the PkgInfo path.
*
* @param name Save name.
* @returns Icon path.
*/
getPkgInfoPath(name) {
return `${name}/${this.appPathPkgInfo}`;
}
/**
* Update XML code with customized variables.
*
* @param xml Plist code.
* @param name Application name.
* @returns Updated XML.
*/
updateInfoPlistCode(xml, name) {
const {
appBinaryNameCustom,
appIconNameCustom
} = this;
if (appBinaryNameCustom) {
xml = (0, _util.infoPlistReplace)(xml, 'CFBundleExecutable', (0, _util.plistStringTagEncode)(appBinaryNameCustom));
}
if (appIconNameCustom) {
xml = (0, _util.infoPlistReplace)(xml, 'CFBundleIconFile', (0, _util.plistStringTagEncode)(appIconNameCustom));
}
xml = (0, _util.infoPlistReplace)(xml, 'CFBundleName', (0, _util.plistStringTagEncode)(this.getProjectorNameNoExtension(name)));
return xml;
}
/**
* Write out the projector.
*
* @param path Save path.
* @param name Save name.
*/
async write(path, name) {
await super.write(path, name);
await this._writeIcon(path, name);
await this._writePkgInfo(path, name);
await this._writeInfoPlist(path, name);
await this._updateInfoPlist(path, name);
}
/**
* Write the projector skeleton from archive.
*
* @param path Save path.
* @param name Save name.
*/
async _writeSkeleton(path, name) {
const {
hasIcon,
hasInfoPlist,
hasPkgInfo,
shockwave,
appPathInfoPlist,
appPathPkgInfo,
appPathFrameworks,
appPathBinaryDefault,
appPathBinaryCustom,
appPathIconDefault,
appPathIconCustom,
appPathRsrcDefault,
appPathRsrcCustom,
xtrasDirectoryName,
projectorResourcesDirectoryName
} = this;
const xtrasPath = this.getXtrasPath(name);
const xtrasMappings = this.getIncludeXtrasMappings();
let foundProjectorResourcesDirectory = false;
let foundFrameworks = false;
let foundBinary = false;
let foundInfoPlist = false;
let foundPkgInfo = false;
let foundIcon = false;
let foundRsrc = false;
let foundXtras = false;
const xtrasHandler = async entry => {
// Check if Xtras path.
const xtrasRel = (0, _util.pathRelativeBase)(entry.volumePath, xtrasDirectoryName, true);
if (xtrasRel === null) {
return false;
}
foundXtras = true; // Find output path if being included, else skip.
const dest = this.includeXtrasMappingsDest(xtrasMappings, xtrasRel);
if (!dest) {
return true;
}
await entry.extract((0, _path.join)(path, xtrasPath, dest));
return true;
};
const projectorResourcesHandler = async entry => {
// Check if projector path.
const projectorRel = (0, _util.pathRelativeBase)(entry.volumePath, projectorResourcesDirectoryName, true);
if (projectorRel === null) {
return false;
}
foundProjectorResourcesDirectory = true;
if ((0, _util.pathRelativeBaseMatch)(projectorRel, appPathFrameworks, true)) {
foundFrameworks = true; // Exclude Frameworks directory for Shockwave projectors.
if (shockwave) {
return true;
}
} // Exclude Info.plist if using custom one.
if ((0, _util.pathRelativeBaseMatch)(projectorRel, appPathInfoPlist, true)) {
foundInfoPlist = true;
if (hasInfoPlist) {
return true;
}
} // Exclude PkgInfo if using custom one.
if ((0, _util.pathRelativeBaseMatch)(projectorRel, appPathPkgInfo, true)) {
foundPkgInfo = true;
if (hasPkgInfo) {
return true;
}
}
let dest = projectorRel; // Possibly rename the binary.
if ((0, _util.pathRelativeBaseMatch)(projectorRel, appPathBinaryDefault, true)) {
foundBinary = true;
if (appPathBinaryCustom) {
dest = appPathBinaryCustom;
}
} // Special case for icon.
if ((0, _util.pathRelativeBaseMatch)(projectorRel, appPathIconDefault, true)) {
foundIcon = true; // Skip extracting icon if custom one.
if (hasIcon) {
return true;
} // Possible rename the icon.
if (appPathIconCustom) {
dest = appPathIconCustom;
}
} // Special case for rsrc.
if ((0, _util.pathRelativeBaseMatch)(projectorRel, appPathRsrcDefault, true)) {
foundRsrc = true;
if (appPathRsrcCustom) {
dest = appPathRsrcCustom;
}
}
await entry.extract((0, _path.join)(path, name, dest));
return true;
};
const archive = await this.getSkeletonArchive();
await archive.read(async entry => {
// Skip empty resource forks (every file in DMG).
if ((0, _util.entryIsEmptyResourceFork)(entry)) {
return;
}
if (await xtrasHandler(entry)) {
return;
}
if (await projectorResourcesHandler(entry)) {
return;
}
});
if (!foundProjectorResourcesDirectory) {
throw new Error(`Failed to locate: ${projectorResourcesDirectoryName}`);
}
if (!foundFrameworks) {
const d = projectorResourcesDirectoryName;
throw new Error(`Failed to locate: ${d}/${appPathFrameworks}`);
}
if (!foundBinary) {
const d = projectorResourcesDirectoryName;
throw new Error(`Failed to locate: ${d}/${appPathBinaryDefault}`);
}
if (!foundInfoPlist) {
const d = projectorResourcesDirectoryName;
throw new Error(`Failed to locate: ${d}/${appPathInfoPlist}`);
}
if (!foundPkgInfo) {// Some projector skeletons lack this file.
// const d = projectorResourcesDirectoryName;
// throw new Error(`Failed to locate: ${d}/${appPathPkgInfo}`);
}
if (!foundIcon) {
const d = projectorResourcesDirectoryName;
throw new Error(`Failed to locate: ${d}/${appPathIconDefault}`);
}
if (!foundRsrc) {
const d = projectorResourcesDirectoryName;
throw new Error(`Failed to locate: ${d}/${appPathRsrcDefault}`);
}
if (!foundXtras) {
throw new Error(`Failed to locate: ${xtrasDirectoryName}`);
}
}
/**
* Write out the projector icon file.
*
* @param path Save path.
* @param name Save name.
*/
async _writeIcon(path, name) {
await this._maybeWriteFile((await this.getIconData()), (0, _path.join)(path, this.getIconPath(name)));
}
/**
* Write out the projector PkgInfo file.
*
* @param path Save path.
* @param name Save name.
*/
async _writePkgInfo(path, name) {
await this._maybeWriteFile((await this.getPkgInfoData()), (0, _path.join)(path, this.getPkgInfoPath(name)));
}
/**
* Write out the projector Info.plist file.
*
* @param path Save path.
* @param name Save name.
*/
async _writeInfoPlist(path, name) {
await this._maybeWriteFile((await this.getInfoPlistData()), (0, _path.join)(path, this.getInfoPlistPath(name)));
}
/**
* Update the projector Info.plist file fields.
*
* @param path Save path.
* @param name Save name.
*/
async _updateInfoPlist(path, name) {
const file = (0, _path.join)(path, this.getInfoPlistPath(name));
let data = await this._dataFromBufferOrFile(null, file);
if (!data) {
throw new Error('Failed to read Info.plist or updating');
} // Decode buffer, and update.
const xmlOriginal = data.toString('utf8');
const xml = this.updateInfoPlistCode(xmlOriginal, name); // If unchanged, all done.
if (xml === xmlOriginal) {
return;
} // Encode data and write.
data = Buffer.from(xml, 'utf8');
await this._maybeWriteFile(data, (0, _path.join)(path, this.getInfoPlistPath(name)));
}
}
exports.ProjectorMacApp = ProjectorMacApp;
//# sourceMappingURL=macapp.js.map