@shockpkg/dir-projector
Version:
Package for creating Shockwave Director projectors
348 lines (276 loc) • 7.53 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.ProjectorWindows = void 0;
var _path = require("path");
var _archiveFiles = require("@shockpkg/archive-files");
var _patcher = require("../patcher");
var _projector = require("../projector");
var _util = require("../util");
/**
* ProjectorWindows constructor.
*
* @param options Options object.
*/
class ProjectorWindows extends _projector.Projector {
/**
* Patch the Shockave 3D Xtra to have a larger buffer to avoid a crash.
* The buffer for resolving InstalledDisplayDrivers to a path is small.
* Changes to the values stored in InstalledDisplayDrivers cause issues.
* The value is now supposed to hold full paths on modern Windows.
* In particular, Nvidia drivers which do this need this patch.
*
* @default false
*/
/**
* Icon file, requires Windows or Wine.
*
* @default null
*/
/**
* Version strings, requires Windows or Wine.
*
* @default null
*/
/**
* Product version, requires Windows or Wine.
*
* @default null
*/
/**
* Version strings, requires Windows or Wine.
*
* @default null
*/
constructor(options) {
super(options);
this.patchShockwave3dInstalledDisplayDriversSize = void 0;
this.iconFile = void 0;
this.fileVersion = void 0;
this.productVersion = void 0;
this.versionStrings = void 0;
this.iconFile = (0, _util.defaultNull)(options.iconFile);
this.fileVersion = (0, _util.defaultNull)(options.fileVersion);
this.productVersion = (0, _util.defaultNull)(options.productVersion);
this.versionStrings = (0, _util.defaultNull)(options.versionStrings);
this.patchShockwave3dInstalledDisplayDriversSize = (0, _util.defaultFalse)(options.patchShockwave3dInstalledDisplayDriversSize);
}
/**
* Projector file extension.
*
* @returns File extension.
*/
get projectorExtension() {
return '.exe';
}
/**
* Config file newline characters.
*
* @returns Newline characters.
*/
get configNewline() {
return '\r\n';
}
/**
* Config file newline characters.
*
* @returns Newline characters.
*/
get lingoNewline() {
return '\r\n';
}
/**
* Newline characters.
*
* @returns Newline characters.
*/
get newline() {
return '\r\n';
}
/**
* Splash image file extension.
*
* @returns File extension.
*/
get splashImageExtension() {
return '.BMP';
}
/**
* Get the SKL name.
*
* @returns File name.
*/
get sklName() {
return 'Projec32.skl';
}
/**
* Write out the projector.
*
* @param path Save path.
* @param name Save name.
*/
async write(path, name) {
await super.write(path, name);
await this._patch(path, name);
await this._updateResources(path, name);
}
/**
* Write the projector skeleton from archive.
*
* @param path Save path.
* @param name Save name.
*/
async _writeSkeleton(path, name) {
const {
shockwave,
sklName,
xtrasDirectoryName
} = this;
const xtrasPath = this.getXtrasPath(name);
const xtrasMappings = this.getIncludeXtrasMappings();
let foundProjectorSkl = 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 projectorSklHandler = async entry => {
const entryPath = entry.volumePath; // Should not be in sub directory.
if (entryPath.includes('/')) {
return false;
} // Check if skl path.
if (!(0, _util.pathRelativeBaseMatch)(entryPath, sklName, true)) {
return false;
}
foundProjectorSkl = true;
await entry.extract((0, _path.join)(path, name));
return true;
};
const projectorDllHandler = async entry => {
const entryPath = entry.volumePath; // Should not be in sub directory.
if (entryPath.includes('/')) {
return false;
} // Check if dll path.
if (!/\.dll$/i.test(entryPath)) {
return false;
} // Exclude if shockwave projector.
if (shockwave) {
return true;
}
await entry.extract((0, _path.join)(path, entryPath));
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 projectorSklHandler(entry)) {
return;
}
if (await projectorDllHandler(entry)) {
return;
}
});
if (!foundProjectorSkl) {
throw new Error(`Failed to locate: ${sklName}`);
}
if (!foundXtras) {
throw new Error(`Failed to locate: ${xtrasDirectoryName}`);
}
}
/**
* Patch projector.
*
* @param path Save path.
* @param name Save name.
*/
async _patch(path, name) {
await this._patchShockwave3dInstalledDisplayDriversSize(path, name);
}
/**
* Patch projector, Shockwave 3D InstalledDisplayDrivers size.
*
* @param path Save path.
* @param name Save name.
*/
async _patchShockwave3dInstalledDisplayDriversSize(path, name) {
if (!this.patchShockwave3dInstalledDisplayDriversSize) {
return;
}
const xtrasDir = (0, _path.join)(path, this.getXtrasPath(name));
const search = 'Shockwave 3D Asset.x32';
const searchLower = search.toLowerCase();
let found = false;
await (0, _archiveFiles.fsWalk)(xtrasDir, async (path, stat) => {
if (!stat.isFile()) {
return;
}
const fn = (0, _path.basename)(path);
if (fn.toLowerCase() !== searchLower) {
return;
}
found = true;
await (0, _patcher.patchWindowsS3dInstalledDisplayDriversSize)((0, _path.join)(xtrasDir, path));
}, {
ignoreUnreadableDirectories: true
});
if (!found) {
throw new Error(`Failed to locate for patching: ${search}`);
}
}
/**
* Update projector Windows resources.
*
* @param path Save path.
* @param name Save name.
*/
async _updateResources(path, name) {
const {
iconFile,
fileVersion,
productVersion,
versionStrings
} = this;
const options = {};
let optionsSet = false;
if (iconFile) {
options.iconPath = iconFile;
optionsSet = true;
}
if (fileVersion !== null) {
options.fileVersion = fileVersion;
optionsSet = true;
}
if (productVersion !== null) {
options.productVersion = productVersion;
optionsSet = true;
}
if (versionStrings !== null) {
options.versionStrings = versionStrings;
optionsSet = true;
} // Do not update if no changes are specified.
if (!optionsSet) {
return;
}
const file = (0, _path.join)(path, name);
await (0, _util.rcedit)(file, options);
}
}
exports.ProjectorWindows = ProjectorWindows;
//# sourceMappingURL=windows.js.map