Socket
Socket
Sign inDemoInstall

@camoto/gamecode

Package Overview
Dependencies
10
Maintainers
1
Versions
11
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 0.0.2 to 1.0.0

formats/index.js

35

cli/index.js

@@ -1,5 +0,5 @@

/**
* @file Command line interface to the library.
/*
* Command line interface to the library.
*
* Copyright (C) 2018-2019 Adam Nielsen <malvineous@shikadi.net>
* Copyright (C) 2010-2021 Adam Nielsen <malvineous@shikadi.net>
*

@@ -22,4 +22,7 @@ * This program is free software: you can redistribute it and/or modify

import commandLineArgs from 'command-line-args';
import GameCode from '../index.js';
import GameCodeDecompress from '../util/decompress.js';
import {
all as gamecodeFormats,
decompressEXE,
findHandler as gamecodeFindHandler,
} from '../index.js';
import Debug from '../util/debug.js';

@@ -43,5 +46,5 @@ const debug = Debug.extend('cli');

const content = {
main: GameCodeDecompress(fs.readFileSync(params.target)),
main: decompressEXE(fs.readFileSync(params.target)),
};
let handlers = GameCode.findHandler(content.main);
let handlers = gamecodeFindHandler(content.main, params.target);

@@ -83,3 +86,9 @@ console.log(handlers.length + ' format handler(s) matched');

list() {
for (const a of this.code.attributes) {
if (!this.code) {
throw new OperationsError('list: must open a file first.');
}
const ids = Object.keys(this.code.attributes).sort();
for (const id of ids) {
const a = this.code.attributes[id];
console.log(`${a.id}: "${a.value}" ${a.desc ? `// ${a.desc}` : ''}`);

@@ -92,3 +101,3 @@ }

if (params.format) {
handler = GameCode.getHandler(params.format);
handler = gamecodeFormats.find(h => h.metadata().id === params.format);
if (!handler) {

@@ -103,6 +112,6 @@ throw new OperationsError('Invalid format code: ' + params.format);

let content = {
main: GameCodeDecompress(fs.readFileSync(params.target)),
main: decompressEXE(fs.readFileSync(params.target)),
};
if (!handler) {
let handlers = GameCode.findHandler(content.main);
let handlers = gamecodeFindHandler(content.main, params.target);
if (handlers.length === 0) {

@@ -202,3 +211,3 @@ throw new OperationsError('Unable to identify this executable format.');

{
GameCode.listHandlers().forEach(handler => {
for (const handler of gamecodeFormats) {
const md = handler.metadata();

@@ -209,3 +218,3 @@ console.log(`${md.id}: ${md.title}`);

});
});
}
}

@@ -212,0 +221,0 @@

@@ -1,5 +0,5 @@

/**
* @file Executable handler for Cosmo's Cosmic Adventures.
/*
* Executable handler for Cosmo's Cosmic Adventures.
*
* Copyright (C) 2010-2020 Adam Nielsen <malvineous@shikadi.net>
* Copyright (C) 2010-2021 Adam Nielsen <malvineous@shikadi.net>
*

@@ -25,4 +25,3 @@ * This program is free software: you can redistribute it and/or modify

import pkgRecordIOBuffer from '@malvineous/record-io-buffer';
const { RecordBuffer, RecordType } = pkgRecordIOBuffer;
import { RecordBuffer, RecordType } from '@camoto/record-io-buffer';
import CodeHandler_Simple from '../interface/CodeHandler_Simple.js';

@@ -246,3 +245,3 @@

{ id: 'msg.key.rshift', type: 'stringz', len: 6 },
{ id: 'msg.key.printscreen', type: 'stringz', len: 6, desc: 'Matches keypad *.' },
{ id: 'msg.key.pad.star', type: 'stringz', len: 6 },
{ id: 'msg.key.alt', type: 'stringz', len: 6 },

@@ -249,0 +248,0 @@ { id: 'msg.key.space', type: 'stringz', len: 6 },

@@ -20,87 +20,72 @@ /*

export * from './formats/index.js';
import * as formats from './formats/index.js';
export { default as decompressEXE } from './util/decompress.js';
import Debug from './util/debug.js';
const debug = Debug.extend('index');
import exe_cosmo1 from './formats/exe-cosmo1.js';
const fileTypes = [
exe_cosmo1,
/**
* Get a list of all the available handlers.
*
* This is preferable to `import *` because most libraries also export utility
* functions like the autodetection routine which would be included even though
* they are not format handlers.
*/
export const all = [
...Object.values(formats),
];
/**
* Main library interface.
* Get a handler by examining the file content.
*
* Ensure the content has been decompressed first if necessary, e.g. by passing
* it through `decompressEXE()` first.
*
* @param {Uint8Array} content
* Executable file content.
*
* @param {string} filename
* Filename where `content` was read from. This is required to identify
* formats where the filename extension is significant. This can be
* omitted for less accurate autodetection.
*
* @return {Array<CodeHandler>} from formats/*.js that can handle the
* format, or an empty array if the format could not be identified.
*
* @example
* import { findHandler as gameCodeFindHandler, decompressEXE } from '@camoto/gamecode';
* const content = decompressEXE(fs.readFileSync('cosmo1.exe'));
* const handler = gameCodeFindHandler(content, 'cosmo1.exe');
* if (handler.length === 0) {
* console.log('Unable to identify file format.');
* } else {
* const md = handler[0].metadata();
* console.log('File is in ' + md.id + ' format');
* }
*/
export default class GameCode
{
/**
* Get a handler by ID directly.
*
* @param {string} type
* Identifier of desired file format.
*
* @return {CodeHandler} from formats/*.js matching requested code, or null
* if the code is invalid.
*
* @example const handler = GameCode.getHandler('exe-cosmo1');
*/
static getHandler(type)
{
return fileTypes.find(x => type === x.metadata().id);
export function findHandler(content, filename) {
if (content.length === undefined) {
throw new Error('content parameter must be Uint8Array');
}
/**
* Get a handler by examining the file content.
*
* Ensure the content has been passed through `decompress()` first.
*
* @param {Uint8Array} content
* Executable file content.
*
* @return {Array} of {CodeHandler} from formats/*.js that can handle the
* format, or an empty array if the format could not be identified.
*
* @example
* const content = fs.readFileSync('cosmo1.exe');
* const handler = GameCode.findHandler(content);
* if (!handler) {
* console.log('Unable to identify file format.');
* } else {
* const md = handler.metadata();
* console.log('File is in ' + md.id + ' format');
* }
*/
static findHandler(content)
{
if (content.length === undefined) {
throw new Error('content parameter must be Uint8Array');
let handlers = [];
for (const x of all) {
const metadata = x.metadata();
debug(`Trying format handler ${metadata.id} (${metadata.title})`);
const confidence = x.identify(content, filename);
if (confidence.valid === true) {
debug(`Matched ${metadata.id}: ${confidence.reason}`);
handlers = [x];
break;
} else if (confidence.valid === undefined) {
debug(`Possible match for ${metadata.id}: ${confidence.reason}`);
handlers.push(x);
// keep going to look for a better match
} else {
debug(`Not ${metadata.id}: ${confidence.reason}`);
}
let handlers = [];
fileTypes.some(x => {
const metadata = x.metadata();
debug(`Trying format handler ${metadata.id} (${metadata.title})`);
const confidence = x.identify(content);
if (confidence.valid === true) {
handlers = [x];
return true; // exit loop early
}
if (confidence.valid === undefined) {
handlers.push(x);
// keep going to look for a better match
}
debug(` - Handler reported: ${confidence.reason}`);
});
return handlers;
}
/**
* Get a list of all the available handlers.
*
* This is probably only useful when testing the library.
*
* @return {Array} of file format handlers, with each element being just like
* the return value of getHandler().
*/
static listHandlers() {
return fileTypes;
}
return handlers;
};

@@ -1,5 +0,5 @@

/**
* @file Simple list of offsets and property types for executable handlers.
/*
* Simple list of offsets and property types for executable handlers.
*
* Copyright (C) 2010-2020 Adam Nielsen <malvineous@shikadi.net>
* Copyright (C) 2010-2021 Adam Nielsen <malvineous@shikadi.net>
*

@@ -23,4 +23,3 @@ * This program is free software: you can redistribute it and/or modify

import pkgRecordIOBuffer from '@malvineous/record-io-buffer';
const { RecordBuffer, RecordType } = pkgRecordIOBuffer;
import { RecordBuffer, RecordType } from '@camoto/record-io-buffer';
import CodeHandler from './CodeHandler.js';

@@ -105,2 +104,2 @@

}
};
}

@@ -1,5 +0,5 @@

/**
* @file Base class and defaults for executable format handlers.
/*
* Base class and defaults for executable format handlers.
*
* Copyright (C) 2020-2021 Adam Nielsen <malvineous@shikadi.net>
* Copyright (C) 2010-2021 Adam Nielsen <malvineous@shikadi.net>
*

@@ -90,11 +90,21 @@ * This program is free software: you can redistribute it and/or modify

*
* @return {Boolean} true if the data is definitely in this format, false if
* it is definitely not in this format, and undefined if the data could not
* be positively identified but it's possible it is in this format.
* @param {string} filename
* The executable's filename in case it is relevant, for those formats where
* the filename is significant.
*
* @return {object} with a `.valid` property, set to `true` if the data is
* definitely in this format, `false` if it is definitely not in this
* format, and `undefined` if it's possible the data is in this format but
* there is not enough information to know for certain one way or the other.
* The returned object also has a `.reason` property containing a technical
* although user-friendly explanation as to why the data was decreed to be
* or not be in this format. This is most useful when uncertain or
* rejecting content, as the user can then be informed why.
*/
// eslint-disable-next-line no-unused-vars
static identify(content) {
static identify(content, filename) {
return {
valid: false,
reason: 'identify() is unimplemented for this format.',
reason: 'The identify() function has not been implemented by the format '
+ 'handler, so autodetecting this format is not possible.',
};

@@ -134,2 +144,2 @@ }

}
};
}
{
"name": "@camoto/gamecode",
"version": "0.0.2",
"version": "1.0.0",
"description": "Modify executable files used by DOS games",

@@ -31,10 +31,10 @@ "bin": {

"dependencies": {
"@camoto/gamecomp": "^1.1.3",
"@camoto/record-io-buffer": "^2.4.1",
"@camoto/gamecomp": "^2.0.2",
"@camoto/record-io-buffer": "^3.0.0",
"command-line-args": "^5.1.1",
"debug": "^4.3.1"
},
"devDependencies": {
"command-line-args": "^5.1.1",
"eslint": "^7.10.0",
"mocha": "^8.1.3",
"eslint": "^7.17.0",
"mocha": "^8.2.1",
"mocha-eslint": "^6.0.0"

@@ -41,0 +41,0 @@ },

# gamecode.js
Copyright 2010-2020 Adam Nielsen <<malvineous@shikadi.net>>
Copyright 2010-2021 Adam Nielsen <<malvineous@shikadi.net>>

@@ -33,2 +33,4 @@ This is a Javascript library that can modify executable files for a number of

For Arch Linux users the AUR package `gamecodejs` is also available.
### Command line interface

@@ -64,13 +66,15 @@

import GameCode from '@camoto/gamecode';
import GameCodeDecompress from '@camoto/gamecode/util/decompress.js';
import {
all as gamecodeFormats,
decompressEXE,
exe_cosmo1 as formatHandler,
} from '@camoto/gamecode';
// Read an executable's attributes into memory.
const handler = GameCode.getHandler('exe-cosmo');
const content = {
// Load the file and UNLZEXE it if needed.
main: GameCodeDecompress(fs.readFileSync('cosmo1.exe')),
main: decompressEXE(fs.readFileSync('cosmo1.exe')),
// Some formats need additional files here, see handler.supps()
};
let exe = handler.extract(content);
let exe = formatHandler.extract(content);

@@ -84,3 +88,3 @@ // List the attributes.

// Write the .exe back to disk with the modifications.
const outBuffer = handler.patch(content, exe);
const outBuffer = formatHandler.patch(content, exe);
fs.writeFileSync('cosmo1a.exe', outBuffer.main);

@@ -106,24 +110,10 @@

2. Edit the main `index.js` and add a `require()` statement for your new file.
3. Make a folder in `test/` for your new format and populate it with
files similar to the other formats. The tests work by creating
a standard archive file with some preset files in it, and
comparing the result to what is inside this folder.
You can either create these archives by hand, with another utility, or if
you are confident that your code is correct, from the code itself. This is
done by setting an environment variable when running the tests, which will
cause the archive file produced by your code to be saved to a temporary
file in the current directory:
SAVE_FAILED_TEST=1 npm test
mv error1.bin test/exe-myformat/default.bin
2. Edit `formats/index.js` and add a line for your new file.
If your archive format has any sort of compression or encryption,
these algorithms should go into the `gamecomp` project instead. This
is to make it easier to reuse the algorithms, as many of them
(particularly the compression ones) are used amongst many unrelated
archive formats. All the `gamecomp` algorithms are available to be
used by any archive format in this library.
If your file format has any sort of compression or encryption, these algorithms
should go into the [gamecompjs](https://github.com/Malvineous/gamecompjs)
project instead. This is to make it easier to reuse the algorithms, as many of
them (particularly the compression ones) are used amongst many unrelated file
formats. All the gamecompjs algorithms are available to be used by any format
in this library.

@@ -133,6 +123,6 @@ During development you can test your code like this:

# Read a sample song and list its details, with debug messages on
$ DEBUG='gamecode:*' ./bin/gamemus open -f mus-myformat example.dat list
$ DEBUG='gamecode:*' ./bin/gamecode open -f exe-myformat example.exe list
# Make sure the format is identified correctly or if not why not
$ DEBUG='gamecode:*' ./bin/gamemus identify example.dat
$ DEBUG='gamecode:*' ./bin/gamecode identify example.exe

@@ -139,0 +129,0 @@ If you use `debug()` rather than `console.log()` in your code then these

@@ -20,3 +20,3 @@ /*

import cmp_lzexe from '@malvineous/gamecomp/compress/cmp-lzexe.js';
import cmp_lzexe from '@camoto/gamecomp/compress/cmp-lzexe.js';

@@ -23,0 +23,0 @@ /**

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc