@shockpkg/dir-projector
Version:
Package for creating Shockwave Director projectors
377 lines (295 loc) • 8.13 kB
JavaScript
;
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.defaultValue = defaultValue;
exports.defaultNull = defaultNull;
exports.defaultFalse = defaultFalse;
exports.defaultTrue = defaultTrue;
exports.entryIsEmptyResourceFork = entryIsEmptyResourceFork;
exports.pathRelativeBase = pathRelativeBase;
exports.pathRelativeBaseMatch = pathRelativeBaseMatch;
exports.trimExtension = trimExtension;
exports.xmlEntitiesEncode = xmlEntitiesEncode;
exports.xmlEntitiesDecode = xmlEntitiesDecode;
exports.plistStringTagEncode = plistStringTagEncode;
exports.plistStringTagDecode = plistStringTagDecode;
exports.infoPlistReplace = infoPlistReplace;
exports.infoPlistRead = infoPlistRead;
exports.rcedit = rcedit;
var _archiveFiles = require("@shockpkg/archive-files");
var entities = _interopRequireWildcard(require("entities"));
var _rcedit2 = _interopRequireDefault(require("rcedit"));
var _sax = _interopRequireDefault(require("sax"));
// @ts-ignore
// Handle module loader differences between CJS and ESM.
const decodeXML = entities.decodeXML || entities.default.decodeXML;
const encodeXML = entities.encodeXML || entities.default.encodeXML;
/**
* Default value if value is undefined.
*
* @param value Value.
* @param defaultValue Default value.
* @returns Value or the default value if undefined.
*/
function defaultValue(value, defaultValue) {
// eslint-disable-next-line no-undefined
return value === undefined ? defaultValue : value;
}
/**
* Default null if value is undefined.
*
* @param value Value.
* @returns Value or null if undefined.
*/
function defaultNull(value) {
return defaultValue(value, null);
}
/**
* Default false if value is undefined.
*
* @param value Value.
* @returns Value or false if undefined.
*/
function defaultFalse(value) {
return defaultValue(value, false);
}
/**
* Default true if value is undefined.
*
* @param value Value.
* @returns Value or true if undefined.
*/
function defaultTrue(value) {
return defaultValue(value, true);
}
/**
* Check if Archive Entry is empty resource fork.
*
* @param entry Archive Entry.
* @returns Is empty resource fork.
*/
function entryIsEmptyResourceFork(entry) {
return entry.type === _archiveFiles.PathType.RESOURCE_FORK && !entry.size;
}
/**
* Find path relative from base, if base matches.
*
* @param path Path to match against.
* @param start Search start.
* @param nocase Match case-insensitive.
* @returns Returns path, or null.
*/
function pathRelativeBase(path, start, nocase = false) {
const p = nocase ? path.toLowerCase() : path;
const s = nocase ? start.toLowerCase() : start;
if (p === s) {
return '';
}
if (p.startsWith(`${s}/`)) {
return path.substr(s.length + 1);
}
return null;
}
/**
* Same as pathRelativeBase, but retuns true on a match, else false.
*
* @param path Path to match against.
* @param start Search start.
* @param nocase Match case-insensitive.
* @returns Returns true on match, else false.
*/
function pathRelativeBaseMatch(path, start, nocase = false) {
const p = nocase ? path.toLowerCase() : path;
const s = nocase ? start.toLowerCase() : start;
if (p === s) {
return true;
}
if (p.startsWith(`${s}/`)) {
return true;
}
return false;
}
/**
* Trim a file extenion.
*
* @param path File path.
* @param ext File extension.
* @param nocase Match case-insensitive.
* @returns Path without file extension.
*/
function trimExtension(path, ext, nocase = false) {
const p = nocase ? path.toLowerCase() : path;
const e = nocase ? ext.toLowerCase() : ext;
return p.endsWith(e) ? path.substr(0, p.length - e.length) : path;
}
/**
* Encode string for XML.
*
* @param value String value.
* @returns Escaped string.
*/
function xmlEntitiesEncode(value) {
return encodeXML(value);
}
/**
* Decode string for XML.
*
* @param value Encoded value.
* @returns Decoded string.
*/
function xmlEntitiesDecode(value) {
return decodeXML(value);
}
/**
* Encode string into plist string tag.
*
* @param value String value.
* @returns Plist string.
*/
function plistStringTagEncode(value) {
return `<string>${xmlEntitiesEncode(value)}</string>`;
}
/**
* Decode string from plist string tag.
*
* @param xml XML tag.
* @returns Plain string, or null.
*/
function plistStringTagDecode(xml) {
const start = '<string>';
const end = '</string>';
if (!xml.startsWith(start) || !xml.endsWith(end)) {
return null;
}
const contents = xml.substring(start.length, xml.length - end.length);
return xmlEntitiesDecode(contents);
}
/**
* A small helper function for finding Info.plist values.
*
* @param xml XML string.
* @param key Plist dict key.
* @returns Found indexes or null.
*/
function infoPlistFind(xml, key) {
let replaceTagStart = -1;
let replaceTagEnd = -1;
const parser = _sax.default.parser(true, {}); // Get the tag path in a consistent way.
const tagPath = () => {
const tags = [...parser.tags];
const {
tag
} = parser;
if (tag && tags[tags.length - 1] !== tag) {
tags.push(tag);
}
return tags.map(o => o.name);
};
const dictTag = () => {
const path = tagPath();
if (path.length !== 3 || path[0] !== 'plist' || path[1] !== 'dict') {
return null;
}
return path[2];
};
let keyTag = false;
let nextTag = false; // eslint-disable-next-line @typescript-eslint/unbound-method
parser.onerror = err => {
throw err;
}; // eslint-disable-next-line @typescript-eslint/unbound-method
parser.ontext = text => {
if (keyTag && text === key) {
nextTag = true;
}
}; // eslint-disable-next-line @typescript-eslint/unbound-method
parser.onopentag = node => {
const tag = dictTag();
if (!tag) {
return;
}
if (tag === 'key') {
keyTag = true;
return;
}
if (!nextTag) {
return;
}
if (replaceTagStart < 0) {
replaceTagStart = parser.startTagPosition - 1;
}
}; // eslint-disable-next-line @typescript-eslint/unbound-method
parser.onclosetag = node => {
const tag = dictTag();
if (!tag) {
return;
}
if (tag === 'key') {
keyTag = false;
return;
}
if (!nextTag) {
return;
}
nextTag = false;
if (replaceTagEnd < 0) {
replaceTagEnd = parser.position;
}
};
parser.write(xml).close();
return replaceTagStart < 0 || replaceTagEnd < 0 ? null : [replaceTagStart, replaceTagEnd];
}
/**
* A small utility function for replacing Info.plist values.
*
* @param xml XML string.
* @param key Plist dict key.
* @param value Plist dict value, XML tag.
* @returns Updated document.
*/
function infoPlistReplace(xml, key, value) {
const found = infoPlistFind(xml, key);
if (!found) {
return xml;
} // Splice in new value.
const before = xml.substr(0, found[0]);
const after = xml.substr(found[1]);
return `${before}${value}${after}`;
}
/**
* A small utility function for reading Info.plist values.
*
* @param xml XML string.
* @param key Plist dict key.
* @returns XML tag.
*/
function infoPlistRead(xml, key) {
const found = infoPlistFind(xml, key);
return found ? xml.substring(found[0], found[1]) : null;
}
/**
* Uses rcedit to edit the resources of a Windows EXE.
* Requires either Windows or wine in the path.
*
* @param path File path.
* @param options Options object.
*/
async function rcedit(path, options) {
const opts = {};
if (options.iconPath) {
opts.icon = options.iconPath;
}
if (typeof options.fileVersion === 'string') {
opts['file-version'] = options.fileVersion;
}
if (typeof options.productVersion === 'string') {
opts['product-version'] = options.productVersion;
}
if (options.versionStrings) {
opts['version-string'] = options.versionStrings;
}
await (0, _rcedit2.default)(path, opts);
}
//# sourceMappingURL=util.js.map