textractor-wrapper
Version:
Textractor wrapper for Node.js. Extracts text from video games and visual novels.
165 lines (164 loc) • 5.96 kB
JavaScript
"use strict";
var __extends = (this && this.__extends) || (function () {
var extendStatics = function (d, b) {
extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
return extendStatics(d, b);
};
return function (d, b) {
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
var child_process_1 = require("child_process");
var events_1 = require("events");
var path_1 = require("path");
var scanf_1 = require("scanf");
var Split = require("split");
var Textractor = /** @class */ (function (_super) {
__extends(Textractor, _super);
/**
* Textractor wrapper for Node.js
*
* @param path Path to TextractorCLI.exe
*/
function Textractor(path) {
var _this = _super.call(this) || this;
_this.path = path_1.resolve(__dirname, "..", path);
_this.splitStream = Split();
_this.splitStream.on("data", function (line) {
_this.onData(line);
});
_this.attachedPids = [];
_this.textOutputObject = {
handle: -1,
pid: -1,
addr: -1,
ctx: -1,
ctx2: -1,
name: "",
code: "",
text: ""
};
return _this;
}
/**
* Start Textractor process.
*/
Textractor.prototype.start = function () {
if (this.process)
return;
this.process = child_process_1.spawn(this.path, {
stdio: ["pipe", "pipe", "ignore"]
});
this.process.stdout.setEncoding("utf16le");
this.process.stdout.pipe(this.splitStream);
this.process.on("error", function (code) {
console.log("error: " + code);
});
};
/**
* Attach text hooker to a specific process.
*
* @param pid Process ID
*
* @throws _RangeError_ if pid is invalid
* @throws _ReferenceError_ if Textractor process is not started
*/
Textractor.prototype.attach = function (pid) {
if (!this.process)
throw new ReferenceError("Textractor not started");
this.ensurePidValid(pid);
if (this.attachedPids.indexOf(pid) !== -1)
return;
this.exec("attach -P" + pid);
this.attachedPids.push(pid);
};
/**
* Detach text hooker to a specific process.
*
* @param pid Process ID
*
* @throws _ReferenceError_ if the process has not been attached
*/
Textractor.prototype.detach = function (pid) {
this.ensureProcessAttached(pid);
this.exec("detach -P" + pid);
};
/**
* Inject a hook into a specific process.
* Supports __/H__ hook code and __/R__ read code.
*
* @param pid Process ID
* @param code __/H__ hook code or __/R__ read code
*
* @throws _ReferenceError_ if Textractor process is not started
* @throws _ReferenceError_ if the process has not been attached
* @throws _SyntaxError_ if code is invalid
*/
Textractor.prototype.hook = function (pid, code) {
if (!this.process)
throw new ReferenceError("Textractor not started");
this.ensureProcessAttached(pid);
if (code.indexOf("/H") === -1 && code.indexOf("/R") === -1)
throw new SyntaxError("invalid code");
this.exec(code + " -P" + pid);
};
/**
* Execute a command manually.
*
* @param command The command to execute
*
* @throws _ReferenceError_ if Textractor process is not started
*/
Textractor.prototype.exec = function (command) {
if (!this.process)
throw new ReferenceError("Textractor not started");
this.process.stdin.write(Buffer.from(command + "\n", "utf16le"));
};
/**
* Stop Textractor process.
*/
Textractor.prototype.stop = function () {
if (!this.process)
return;
this.process.kill();
delete this.process;
};
Textractor.prototype.ensurePidValid = function (pid) {
if (pid < 0 || pid > 65535)
throw new RangeError("invalid process ID");
};
Textractor.prototype.ensureProcessAttached = function (pid) {
if (this.attachedPids.indexOf(pid) === -1)
throw new ReferenceError("process has not been attached");
};
Textractor.prototype.onData = function (line) {
if (line.indexOf("Usage") === 0)
return;
// Handle multiple lines
if (line.indexOf("[") === 0) {
this.textOutputObject = (scanf_1.sscanf(line, "[%x:%x:%x:%x:%x:%s:%s] %S", "handle", "pid", "addr", "ctx", "ctx2", "name", "code", "text"));
// In case of hook code doesn't exist
if (this.textOutputObject.name.lastIndexOf(']') === this.textOutputObject.name.length - 1) {
this.textOutputObject.name =
this.textOutputObject.name.substring(0, this.textOutputObject.name.length - 1);
this.textOutputObject.text = this.textOutputObject.code;
this.textOutputObject.code = "";
}
}
else {
var text = scanf_1.sscanf(line, "%S");
this.textOutputObject.text += text;
}
if (this.textOutputObject.text === null) {
this.textOutputObject.text = "";
}
this.emit("output", this.textOutputObject);
};
return Textractor;
}(events_1.EventEmitter));
exports.Textractor = Textractor;