Skip to content

Commit

Permalink
Reduced Windows patch IO
Browse files Browse the repository at this point in the history
  • Loading branch information
JrMasterModelBuilder committed Oct 15, 2023
1 parent 34ea453 commit 33c8f19
Show file tree
Hide file tree
Showing 2 changed files with 145 additions and 54 deletions.
26 changes: 26 additions & 0 deletions src/projector/otto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,32 @@ export interface IIncludeXtras {
[key: string]: string | null;
}

/**
* File patch.
*/
export interface IFilePatch {
/**
* Check if skeleton file path matches.
*
* @param file File path.
* @returns If matched.
*/
match: (file: string) => boolean;

/**
* Modify data, possibly inplace.
*
* @param data The data to modify.
* @returns Modified data.
*/
modify: (data: Uint8Array) => Uint8Array;

/**
* Run after all patches.
*/
after: () => void;
}

/**
* ProjectorOtto object.
*/
Expand Down
173 changes: 119 additions & 54 deletions src/projector/otto/windows.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,18 @@
import {readFile, writeFile} from 'node:fs/promises';
import {join as pathJoin, dirname, basename} from 'node:path';
import {mkdir, readFile, writeFile} from 'node:fs/promises';
import {join as pathJoin, dirname} from 'node:path';

import {
Entry,
PathType,
createArchiveByFileStatOrThrow,
fsWalk
createArchiveByFileStatOrThrow
} from '@shockpkg/archive-files';

import {pathRelativeBase, pathRelativeBaseMatch} from '../../util';
import {
peResourceReplace,
windowsPatch3dDisplayDriversSize
} from '../../util/windows';
import {ProjectorOtto} from '../otto';
import {IFilePatch, ProjectorOtto} from '../otto';

/**
* ProjectorOttoWindows object.
Expand Down Expand Up @@ -121,6 +120,39 @@ export class ProjectorOttoWindows extends ProjectorOtto {
let foundProjectorSkl = false;
let foundXtras = false;

const patches = await this._getPatches();

/**
* Extract entry, and also apply patches if any.
*
* @param entry Archive entry.
* @param dest Output path.
*/
const extract = async (entry: Entry, dest: string) => {
let data: Uint8Array | null = null;
for (const patch of patches) {
if (
entry.type === PathType.FILE &&
patch.match(entry.volumePath)
) {
// eslint-disable-next-line no-await-in-loop
data = data || (await entry.read());
if (!data) {
throw new Error(`Failed to read: ${entry.volumePath}`);
}
data = patch.modify(data);
}
}

if (data) {
await mkdir(dirname(dest), {recursive: true});
await writeFile(dest, data);
return;
}

await entry.extract(dest);
};

/**
* Xtras handler.
*
Expand All @@ -145,7 +177,7 @@ export class ProjectorOttoWindows extends ProjectorOtto {
return true;
}

await entry.extract(pathJoin(xtrasPath, dest));
await extract(entry, pathJoin(xtrasPath, dest));
return true;
};

Expand All @@ -169,7 +201,7 @@ export class ProjectorOttoWindows extends ProjectorOtto {
}
foundProjectorSkl = true;

await entry.extract(path);
await extract(entry, path);
return true;
};

Expand Down Expand Up @@ -197,7 +229,7 @@ export class ProjectorOttoWindows extends ProjectorOtto {
return true;
}

await entry.extract(pathJoin(dirname(path), entryPath));
await extract(entry, pathJoin(dirname(path), entryPath));
return true;
};

Expand Down Expand Up @@ -234,65 +266,98 @@ export class ProjectorOttoWindows extends ProjectorOtto {
}

/**
* @inheritdoc
* Get patches to apply.
*
* @returns Patches list.
*/
protected async _getPatches() {
const patches: IFilePatch[] = [];
let p = this._getPatch3dDisplayDriversSize();
if (p) {
patches.push(p);
}
p = await this._getPatchResources();
if (p) {
patches.push(p);
}
return patches;
}

/**
* Get patch for main file resources.
*
* @returns Patch spec.
*/
protected async _modifySkeleton() {
const {path} = this;
protected async _getPatchResources() {
const iconData = await this.getIconData();
const {versionStrings} = this;
const {versionStrings, sklName} = this;
if (!(iconData || versionStrings)) {
return;
return null;
}

await writeFile(
path,
peResourceReplace(await readFile(path), {
iconData,
versionStrings
})
);

await this._patch3dDisplayDriversSize();
const skl = sklName;
const search = skl.toLowerCase();
let count = 0;

const patch: IFilePatch = {
// eslint-disable-next-line jsdoc/require-jsdoc
match: (file: string) =>
search === file.split('/').pop()!.toLowerCase(),
// eslint-disable-next-line jsdoc/require-jsdoc
modify: (data: Uint8Array) => {
const d = peResourceReplace(data, {
iconData,
versionStrings
});
count++;
return d;
},
// eslint-disable-next-line jsdoc/require-jsdoc
after: () => {
if (!count) {
throw new Error(`Failed to locate for patching: ${skl}`);
}
}
};
return patch;
}

/**
* Patch projector, Shockwave 3D InstalledDisplayDrivers size.
* Get patch for Shockwave 3D InstalledDisplayDrivers size.
*
* @returns Patch spec.
*/
protected async _patch3dDisplayDriversSize() {
protected _getPatch3dDisplayDriversSize() {
if (!this.patch3dDisplayDriversSize) {
return;
return null;
}

const xtrasDir = this.xtrasPath;
const search = 'Shockwave 3D Asset.x32';
const searchLower = search.toLowerCase();

let found = false;
await fsWalk(
xtrasDir,
async (path, stat) => {
if (!stat.isFile()) {
return;
}

const fn = basename(path);
if (fn.toLowerCase() !== searchLower) {
return;
}

found = true;
const f = pathJoin(xtrasDir, path);
const d = await readFile(f);
windowsPatch3dDisplayDriversSize(d);
await writeFile(f, d);
const x32 = 'Shockwave 3D Asset.x32';
const search = x32.toLowerCase();
let count = 0;

const patch: IFilePatch = {
// eslint-disable-next-line jsdoc/require-jsdoc
match: (file: string) =>
search === file.split('/').pop()!.toLowerCase(),
// eslint-disable-next-line jsdoc/require-jsdoc
modify: (data: Uint8Array) => {
windowsPatch3dDisplayDriversSize(data);
count++;
return data;
},
{
ignoreUnreadableDirectories: true
// eslint-disable-next-line jsdoc/require-jsdoc
after: () => {
if (!count) {
throw new Error(`Failed to locate for patching: ${x32}`);
}
}
);

if (!found) {
throw new Error(`Failed to locate for patching: ${search}`);
}
};
return patch;
}

/**
* @inheritdoc
*/
protected async _modifySkeleton() {}
}

0 comments on commit 33c8f19

Please sign in to comment.