From 1b29e09e6708a6e660174b6241a541158e79fe7f Mon Sep 17 00:00:00 2001 From: TheBrokenRail Date: Thu, 15 Feb 2024 03:16:34 -0500 Subject: [PATCH] This Is So Cursed, I Hate It --- src/common.ts | 5 +-- src/cpp.ts | 110 ++++++++++++++++++++++++++++++++++++++++++++++++ src/index.ts | 53 ++++++++++------------- src/loader.ts | 5 --- src/map.ts | 17 -------- src/property.ts | 6 +++ src/vtable.ts | 2 +- 7 files changed, 141 insertions(+), 57 deletions(-) create mode 100644 src/cpp.ts diff --git a/src/common.ts b/src/common.ts index 5f70dbd..cb63d1e 100644 --- a/src/common.ts +++ b/src/common.ts @@ -1,5 +1,4 @@ import * as fs from 'node:fs'; -import { isCppAllowed } from './map'; export const INDENT = ' '; export const POINTER_SIZE = 4; @@ -67,7 +66,7 @@ export function toHex(x: number) { return '0x' + x.toString(16); } export function getAssertFunction() { - return isCppAllowed() ? 'static_assert' : '_Static_assert'; + return 'static_assert'; } export function assertSize(name: string, size: number, isDefined: boolean) { let out = ''; @@ -75,7 +74,7 @@ export function assertSize(name: string, size: number, isDefined: boolean) { const macro = toUpperSnakeCase(name) + '_SIZE'; out += `#define ${macro} ${toHex(size)}\n`; // Check Size - out += `${getAssertFunction()}(sizeof (${name}) == ${macro}, "Invalid Size");\n`; + out += `${getAssertFunction()}(sizeof(${name}) == ${macro}, "Invalid Size");\n`; // Hide Structure Size If The Real Size Is Unknown if (!isDefined) { out += `#undef ${macro}\n`; diff --git a/src/cpp.ts b/src/cpp.ts new file mode 100644 index 0000000..3937be7 --- /dev/null +++ b/src/cpp.ts @@ -0,0 +1,110 @@ +import { INDENT } from './common'; +import { SimpleProperty } from './property'; + +// List Of Supported C++ Types +const CPP_TYPES = [ + 'std::string', + 'std::vector<', + 'std::map<' +]; +const CPP_HEADERS = [ + 'string', + 'vector', + 'map' +]; + +// Get Fake Type Name +function isGeneric(type: string) { + return type.endsWith('<'); +} +function removeGeneric(type: string) { + if (isGeneric(type)) { + // Remove Generic Parameters + type = type.substring(0, type.length - 1); + } + return type; +} +function getFakeName(type: string) { + return removeGeneric(type).replaceAll('std::', '__std_'); +} + +// Generate C Type Definition +function generateStruct(type: string) { + // Get Information + const property = new SimpleProperty(0, type, 'fake'); + const size = property.propertySize(); + const alignment = property.propertyAlignment(); + // Generate + let struct = ''; + struct += `typedef struct __attribute__((aligned(${alignment}))) __attribute__((packed)) {\n`; + struct += `${INDENT}uchar data[${size}];\n`; + struct += `} ${getFakeName(type)};\n`; + return struct; +} + +// Turn A C++ Header Into A C/C++ Headeer +export function fixupCpp(data: string) { + // Replace Types + for (const type of CPP_TYPES) { + // Check If Type Is Generic + if (isGeneric(type)) { + // Generic + while (data.includes(type)) { + // Find Type + let index = data.indexOf(type); + // Replace Type + data = data.substring(0, index) + getFakeName(type) + '(' + data.substring(index + type.length); + // Replace > With ( + index = data.indexOf('>', index); + if (index !== -1) { + data = data.substring(0, index) + ')' + data.substring(index + 1); + } + } + } else { + // Normal + data = data.replaceAll(type, getFakeName(type)); + } + } + + // Setup Macros + let header = ''; + header += '// C++ Types\n'; + + // C++ Support + header += '#ifdef __cplusplus\n'; + for (const headerFile of CPP_HEADERS) { + header += `#include <${headerFile}>\n`; + } + for (const type of CPP_TYPES) { + const fakeName = getFakeName(type); + if (isGeneric(type)) { + header += `#define ${fakeName}(...) ${type}__VA_ARGS__>\n`; + } else { + header += `#define ${fakeName} ${type}\n`; + } + } + + // C Support + header += '#else\n'; + for (let type of CPP_TYPES) { + const fakeName = getFakeName(type); + header += generateStruct(type); + // Strip Generic Information + if (isGeneric(type)) { + type = removeGeneric(type); + header += `#define ${fakeName}(...) ${fakeName}\n`; + } + } + header += '#endif\n'; + + // Cleanup Macros + let footer = ''; + footer += '// Cleanup C++ Types\n'; + for (const type of CPP_TYPES) { + const fakeName = getFakeName(type); + footer += `#undef ${fakeName}\n`; + } + + // Return + return header + '\n' + data + '\n' + footer; +} \ No newline at end of file diff --git a/src/index.ts b/src/index.ts index 5ef2ec9..ba7e56c 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,7 +1,8 @@ import * as fs from 'node:fs'; import { STRUCTURE_FILES, EXTENSION, INDENT } from './common'; -import { getStructure, setCppAllowed } from './map'; +import { getStructure } from './map'; import { Struct } from './struct'; +import { fixupCpp } from './cpp'; // Arguments if (process.argv.length < 5) { @@ -103,10 +104,7 @@ function dependencySort(structureObjects: Struct[]) { } // Generate Part Of Header -function makeHeaderPart(allowCpp: boolean) { - // Set Mode - setCppAllowed(allowCpp); - +function makeHeaderPart() { // Load Symbols const structureObjects = loadSymbols(); @@ -148,10 +146,6 @@ function makeMainHeader(output: string) { result += '#ifndef __arm__\n'; result += '#error "Symbols Are ARM-Only"\n'; result += '#endif\n'; - result += '\n// Suppress Warnings\n'; - result += '#pragma GCC diagnostic push\n'; - result += '#pragma GCC diagnostic ignored "-Wunused-variable"\n'; - result += '#pragma GCC diagnostic ignored "-Wunused-function"\n'; result += '\n// Shortcuts\n'; result += 'typedef unsigned char uchar;\n'; result += 'typedef unsigned short ushort;\n'; @@ -164,34 +158,31 @@ function makeMainHeader(output: string) { for (const file of extraHeaders) { result += fs.readFileSync(file, {encoding: 'utf8'}); } - result += '\n// Switch Mode\n'; - result += '#ifndef __cplusplus\n'; - result += '\n// C Mode\n'; - result += '#include \n'; - result += 'typedef uchar bool;\n\n'; - result += makeHeaderPart(false); - result += '\n// End C Mode\n'; - result += '#else\n'; - result += '\n// C++ Mode\n'; - result += '#include \n'; - result += '#include \n'; - result += '#include \n'; - result += '#include \n'; - result += 'extern "C" {\n\n'; - result += makeHeaderPart(true); - result += '\n// End C++ Mode\n'; - result += '}\n'; - result += '#endif\n'; - result += '\n// Stop Suppressing Warnings\n'; - result += '#pragma GCC diagnostic pop\n'; + let core = ''; + core += '// C/C++ Support\n'; + core += '#ifndef __cplusplus\n'; + core += '#include \n'; + core += '#include \n'; + core += 'typedef uchar bool;\n'; + core += '#else\n'; + core += '#include \n'; + core += 'extern "C" {\n'; + core += '#pragma GCC diagnostic push\n'; + core += '#pragma GCC diagnostic ignored "-Winvalid-offsetof"\n'; + core += '#endif\n\n'; + core += makeHeaderPart(); + core += '\n// Cleanup C++ Support\n'; + core += '#ifdef __cplusplus\n'; + core += '#pragma GCC diagnostic pop\n'; + core += '}\n'; + core += '#endif\n'; + result += '\n' + fixupCpp(core); fs.writeFileSync(output, result); } makeMainHeader(headerOutput); // Generate Compiled Code function makeCompiledCode(output: string) { - // Set Mode - setCppAllowed(true); // Load Symbols const structureObjects = loadSymbols(); diff --git a/src/loader.ts b/src/loader.ts index f865463..de0697f 100644 --- a/src/loader.ts +++ b/src/loader.ts @@ -1,5 +1,4 @@ import { COMMENT, EXTENSION, getSelfArg, parseTypeAndName, readDefinition, safeParseInt, syntaxError } from './common'; -import { isCppAllowed } from './map'; import { Method } from './method'; import { SimpleProperty, StaticProperty } from './property'; import { Struct } from './struct'; @@ -93,10 +92,6 @@ export function load(target: Struct, name: string, isExtended: boolean) { if (piece.length === 0) { continue; } - // Skip C++ Types If Applicable - if (!isCppAllowed() && piece.includes('std::')) { - continue; - } // Handle Commands let firstSpace = piece.indexOf(' '); diff --git a/src/map.ts b/src/map.ts index cfba07f..b588a6e 100644 --- a/src/map.ts +++ b/src/map.ts @@ -1,16 +1,6 @@ import { Struct } from './struct'; import { ErrorOnLine, load } from './loader'; -// Track Mode -let allowCpp = false; -export function isCppAllowed() { - return allowCpp; -} -export function setCppAllowed(newMode: boolean) { - clearStructures(); - allowCpp = newMode; -} - // Store Loaded Structures const structures: {[id: string]: Struct} = {}; @@ -40,11 +30,4 @@ export function getStructure(name: string) { process.exit(1); } } -} - -// Clear Loaded Structures -function clearStructures() { - for (const name in structures) { - delete structures[name]; - } } \ No newline at end of file diff --git a/src/property.ts b/src/property.ts index cc35c85..01b75ab 100644 --- a/src/property.ts +++ b/src/property.ts @@ -60,6 +60,9 @@ export class SimpleProperty implements Property { } else if (this.#type.startsWith('std::vector<')) { // C++ Vector return 12; + } else if (this.#type.startsWith('std::map<')) { + // C++ Map + return 24; } else { // Structure const structure = getStructure(this.#type); @@ -96,6 +99,9 @@ export class SimpleProperty implements Property { } else if (this.#type.startsWith('std::vector<')) { // C++ Vector return 4; + } else if (this.#type.startsWith('std::map<')) { + // C++ Map + return 4; } else { // Structure const structure = getStructure(this.#type); diff --git a/src/vtable.ts b/src/vtable.ts index 1c51458..2018a5e 100644 --- a/src/vtable.ts +++ b/src/vtable.ts @@ -174,7 +174,7 @@ export class VTable implements Property { declarations += `${INDENT}if (obj == NULL) {\n`; declarations += `${INDENT}${INDENT}return NULL;\n`; declarations += `${INDENT}}\n`; - declarations += `${INDENT}memcpy((void *) obj, (void *) vtable, sizeof (${this.#getName()}));\n`; + declarations += `${INDENT}memcpy((void *) obj, (void *) vtable, sizeof(${this.#getName()}));\n`; declarations += `${INDENT}return obj;\n`; declarations += '}\n'; }