diff --git a/src/index.ts b/src/index.ts index dd8568b..e62055d 100644 --- a/src/index.ts +++ b/src/index.ts @@ -30,6 +30,9 @@ while (process.argv.length > 0) { let name = parts[parts.length - 1]!; name = name.substring(0, name.length - EXTENSION.length); // Store + if (name in STRUCTURE_FILES) { + throw new Error(`Multiple Definition Files Provided: ${name}${EXTENSION}`); + } STRUCTURE_FILES[name] = file; } else if (file.endsWith('.h')) { // Extra Headers diff --git a/src/struct.ts b/src/struct.ts index d01d2ab..0abf1df 100644 --- a/src/struct.ts +++ b/src/struct.ts @@ -49,6 +49,9 @@ export class Struct { return Math.ceil(size / alignment) * alignment; } getSize(round: boolean) { + if (this.#isUndefined()) { + return 0; + } let size; if (this.#size !== null) { size = this.#size; @@ -116,6 +119,11 @@ export class Struct { this.#vtable!.setAddress(address); } + // Check If Structure Is Undefined + #isUndefined() { + return this.#properties.length === 0 && this.#size === null; + } + // Check #check() { // Sort Properties @@ -140,6 +148,43 @@ export class Struct { } } + // Compute Padding Between Properties + #computePadding(a: Property | null, b: Property | null) { + // Null A = Start Of Structure + // Null B = End Of Structure + let neededPadding = 0; + if (a === null) { + // Start Of Structure Padding + if (b !== null) { + neededPadding = b.propertyOffset(); + } else { + // Both A And B Are Null + if (this.#size !== null) { + neededPadding = this.#size; + } else { + neededPadding = MIN_SIZE; + } + } + } else if (b === null) { + // End Of Structure Padding + if (this.#size !== null) { + const realSize = a.propertyOffset() + a.propertySize(); + const realRoundedSize = this.#roundSize(realSize); + if (realRoundedSize !== this.#size) { + neededPadding = this.#size - realSize; + } + } + } else { + // Inner Structure Padding + const realSizeSoFar = a.propertyOffset() + a.propertySize(); + neededPadding = b.propertyOffset() - realSizeSoFar; + } + if (neededPadding < 0) { + throw new Error('Overlapping properties detected!'); + } + return neededPadding; + } + // Generate Header generate() { let out = ''; @@ -160,7 +205,7 @@ export class Struct { } // Early Exit For Undefined Structures - if (this.#properties.length === 0 && this.#size === null) { + if (this.#isUndefined()) { return out; } @@ -172,46 +217,17 @@ export class Struct { // Structure out += `struct ${this.#name} {\n`; for (let i = 0; i <= this.#properties.length; i++) { - const property = this.#properties[i]; + const property = i < this.#properties.length ? this.#properties[i]! : null; // Padding - const lastProperty = this.#properties[i - 1]; - let neededPadding = 0; - if (i === 0) { - // Start Of Structure Padding - if (property) { - neededPadding = property.propertyOffset(); - } else if (this.#properties.length === 0) { - if (this.#size !== null) { - neededPadding = this.#size; - } else { - neededPadding = MIN_SIZE; - } - } - } else if (i === this.#properties.length) { - // End Of Structure Padding - if (this.#size !== null && lastProperty) { - const realSize = lastProperty.propertyOffset() + lastProperty.propertySize(); - const realRoundedSize = this.#roundSize(realSize); - if (realRoundedSize !== this.#size) { - neededPadding = this.#size - realSize; - } - } - } else { - // Inner Structure Padding - if (property && lastProperty) { - const realSize = lastProperty.propertyOffset() + lastProperty.propertySize(); - neededPadding = property.propertyOffset() - realSize; - } - } + const lastProperty = (i >= 1 && (i - 1) < this.#properties.length) ? this.#properties[i - 1]! : null; + const neededPadding = this.#computePadding(lastProperty, property); if (neededPadding > 0) { out += `${INDENT}uchar padding${i}[${neededPadding}];\n`; - } else if (neededPadding < 0) { - throw new Error('Overlapping properties detected!'); } // Property - if (property) { + if (property !== null) { // Check Offset const offset = property.propertyOffset(); const alignment = property.propertyAlignment();