@gaialabs/core 0.2.9 → 0.2.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +2721 -2737
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -11
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +2 -11
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +2722 -2737
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":["isNode","RebuildProcessor","snesAddressingModes","snesVectors","snesHeaders"],"sources":["../snes/addressingModes.json","../snes/vectors.json","../snes/headers.json","../src/rom/state.ts","../src/rom/extraction/processor.ts","../src/rom/extraction/reader.ts","../src/types/constants.ts","../src/types/addressing.ts","../src/types/members.ts","../src/types/processor.ts","../src/types/resources.ts","../src/types/transforms.ts","../src/database/opcode.ts","../src/types/assembly.ts","../src/types/bitstream.ts","../src/types/compression-registry.ts","../src/types/files.ts","../src/types/location.ts","../src/types/strings.ts","../src/types/tables.ts","../src/types/operands.ts","../src/rom/extraction/references.ts","../src/rom/extraction/stack.ts","../src/rom/extraction/cop.ts","../src/rom/extraction/addressing.ts","../src/rom/extraction/transforms.ts","../src/database/blocks.ts","../src/database/files.ts","../src/database/structs.ts","../src/database/addressingMode.ts","../src/database/strings.ts","../src/database/cop.ts","../src/utils/file.ts","../src/utils/crc.ts","../src/utils/base64.ts","../src/utils/index.ts","../src/database/parts.ts","../src/database/transforms.ts","../src/database/scenes.ts","../src/database/groups.ts","../src/compression/QuintetLZ.ts","../src/compression/index.ts","../src/rom/extraction/postprocessor.ts","../src/rom/extraction/writer.ts","../src/assembly/Stack.ts","../src/assembly/Registers.ts","../src/rom/extraction/asm.ts","../src/rom/extraction/parser.ts","../src/rom/extraction/blocks.ts","../src/rom/rebuild/layout.ts","../src/rom/rebuild/processor.ts","../src/rom/rebuild/writer.ts","../src/database/header.ts","../src/database/root.ts","../src/database/overrides.ts","../src/database/paths.ts","../src/rom/extraction/strings.ts","../src/rom/rebuild/string-processor.ts","../src/rom/rebuild/sorted-map.ts","../src/rom/rebuild/assembler-state.ts","../src/rom/rebuild/assembler.ts","../src/supabase/client.ts","../src/supabase/utils.ts","../src/supabase/types.ts","../src/supabase/rom-loader.ts","../src/rom/generator.ts","../src/sprites/SpriteFrame.ts","../src/sprites/SpritePart.ts","../src/sprites/SpriteGroup.ts","../src/sprites/SpriteMap.ts","../src/index.ts"],"sourcesContent":["","","","/**\n * Lightweight ROM state placeholder used during early development.\n * This stub will be expanded as the ROM extraction pipeline matures.\n */\nexport class RomState {\n // Basic memory buffers\n public readonly cgram = new Uint8Array(0x200); // Color palette RAM\n public readonly vram = new Uint8Array(0x10000); // Video RAM\n\n /**\n * Create ROM state from scene metadata.\n * Parameters are currently unused but kept for future implementation.\n */\n public static async fromScene(\n _baseDir: string,\n _root: unknown,\n _metaFile: string,\n _id: number\n ): Promise<RomState> {\n return new RomState();\n }\n}\n\n/**\n * Utility helpers for working with RomState.\n */\nexport class RomStateUtils {\n /** Create an empty ROM state */\n public static createEmpty(): RomState {\n return new RomState();\n }\n\n /** Clear all data in the given ROM state */\n public static clear(state: RomState): void {\n state.cgram.fill(0);\n state.vram.fill(0);\n }\n}\n","import { Registers } from '../../assembly';\n\nexport class MapExt<K, V> extends Map<K, V> {\n\n constructor() {\n super();\n }\n\n public tryAdd(key: K, value: V): boolean {\n if (this.has(key)) {\n return false;\n }\n this.set(key, value);\n return true;\n }\n\n public setFlag(key: K, flag: number, value: boolean = true): void {\n if (!value) this.clearFlag(key, flag);\n else this.set(key, (((this.get(key) as number) ?? 0) | flag) as V);\n }\n\n public clearFlag(key: K, flag: number): void {\n this.set(key, (((this.get(key) as number) ?? 0) & ~flag) as V);\n }\n}\n\n/**\n * Manages CPU processor state during ROM analysis\n * Converted from GaiaLib/Rom/Extraction/ProcessorStateManager.cs\n */\nexport class ProcessorStateManager {\n // public readonly accumulatorFlags = new MapExt<number, boolean | null>();\n // public readonly indexFlags = new MapExt<number, boolean | null>();\n // public readonly bankNotes = new MapExt<number, number | null>();\n public readonly stackPositions = new MapExt<number, number>();\n\n private readonly _buckets: Record<string, MapExt<number, number>> = {};\n\n public get(key: string): MapExt<number, number> {\n return this._buckets[key] ?? (this._buckets[key] = new MapExt<number, number>());\n }\n\n /**\n * Hydrate processor registers with stored state\n * Uses Registers from gaia-core/assembly for processor state management\n */\n public hydrateRegisters(position: number, reg: Registers): void {\n\n for (const [key, value] of Object.entries(this._buckets)) {\n const val = value.get(position);\n if (val !== undefined) {\n reg.value[key] = val;\n }\n }\n\n // const acc = this.accumulatorFlags.get(position);\n // if (acc !== undefined) {\n // reg.accumulatorFlag = acc ?? undefined;\n // }\n\n // const ind = this.indexFlags.get(position);\n // if (ind !== undefined) {\n // reg.indexFlag = ind ?? undefined;\n // }\n\n // const bnk = this.bankNotes.get(position);\n // if (bnk !== undefined) {\n // reg.dataBank = bnk ?? undefined;\n // }\n\n const stack = this.stackPositions.get(position);\n if (stack !== undefined) {\n reg.stack.location = stack;\n }\n }\n\n // // Accumulator flag methods\n // public getAccumulatorFlag(location: number): boolean | null | undefined {\n // return this.accumulatorFlags.get(location);\n // }\n\n // public setAccumulatorFlag(location: number, value: boolean | null): void {\n // this.accumulatorFlags.set(location, value);\n // }\n\n // public tryAddAccumulatorFlag(location: number, value: boolean | null): boolean {\n // if (this.accumulatorFlags.has(location)) {\n // return false;\n // }\n // this.accumulatorFlags.set(location, value);\n // return true;\n // }\n\n // // Index flag methods\n // public getIndexFlag(location: number): boolean | null | undefined {\n // return this.indexFlags.get(location);\n // }\n\n // public setIndexFlag(location: number, value: boolean | null): void {\n // this.indexFlags.set(location, value);\n // }\n\n // public tryAddIndexFlag(location: number, value: boolean | null): boolean {\n // if (this.indexFlags.has(location)) {\n // return false;\n // }\n // this.indexFlags.set(location, value);\n // return true;\n // }\n\n // // Bank note methods\n // public getBankNote(location: number): number | null | undefined {\n // return this.bankNotes.get(location);\n // }\n\n // public setBankNote(location: number, value: number | null): void {\n // this.bankNotes.set(location, value);\n // }\n\n // Stack position methods\n public getStackPosition(location: number): number | undefined {\n return this.stackPositions.get(location);\n }\n\n public setStackPosition(location: number, value: number): void {\n this.stackPositions.set(location, value);\n }\n\n public tryAddStackPosition(location: number, value: number): boolean {\n if (this.stackPositions.has(location)) {\n return false;\n }\n this.stackPositions.set(location, value);\n return true;\n }\n} ","/**\r\n * Provides low-level ROM data reading functionality\r\n * Converted from GaiaLib/Rom/Extraction/RomDataReader.cs\r\n */\r\nexport class RomDataReader {\r\n public readonly romData: Uint8Array;\r\n public position: number;\r\n\r\n constructor(romData: Uint8Array) {\r\n if (!romData) {\r\n throw new Error('romData cannot be null');\r\n }\r\n this.romData = romData;\r\n this.position = 0;\r\n }\r\n\r\n public readByte(): number {\r\n return this.romData[this.position++];\r\n }\r\n\r\n public readSByte(): number {\r\n const value = this.readByte();\r\n return value > 127 ? value - 256 : value;\r\n }\r\n\r\n public readUShort(): number {\r\n return this.readByte() | (this.readByte() << 8);\r\n }\r\n\r\n public readShort(): number {\r\n const value = this.readUShort();\r\n return value > 32767 ? value - 65536 : value;\r\n }\r\n\r\n public readAddress(): number {\r\n return this.readByte() | (this.readByte() << 8) | (this.readByte() << 16);\r\n }\r\n\r\n public readInt(): number {\r\n return this.readByte() | (this.readByte() << 8) | (this.readByte() << 16) | (this.readByte() << 24);\r\n }\r\n\r\n public peekByte(): number {\r\n return this.romData[this.position];\r\n }\r\n\r\n public peekShort(): number {\r\n return this.romData[this.position] | (this.romData[this.position + 1] << 8);\r\n }\r\n\r\n public peekAddress(): number {\r\n return this.romData[this.position]\r\n | (this.romData[this.position + 1] << 8)\r\n | (this.romData[this.position + 2] << 16);\r\n }\r\n} ","/**\r\n * ROM processing constants\r\n * Converted from GaiaLib/Types/RomProcessingConstants.cs\r\n */\r\nexport class RomProcessingConstants {\r\n // Core constants\r\n public static readonly PAGE_SIZE = 0x8000;\r\n public static readonly SNES_HEADER_SIZE = 0x50;\r\n\r\n // Dictionary constants\r\n public static readonly DICTIONARIES = [\"dictionary_01EBA8\", \"dictionary_01F54D\"];\r\n public static readonly DICT_COMMANDS = [0xD6, 0xD7];\r\n public static readonly END_CHARS = [0xC0, 0xCA, 0xD1];\r\n\r\n // Character arrays for parsing\r\n public static readonly WHITESPACE = [' ', '\\t'];\r\n public static readonly OPERATORS = ['-', '+'];\r\n public static readonly COMMA_SPACE = [',', ' ', '\\t'];\r\n public static readonly ADDRESS_SPACE = ['@', '&', '^', '#', '$', '%', '*'];\r\n public static readonly SYMBOL_SPACE = [',', ' ', '\\t', '<', '>', '(', ')', ':', '[', ']', '{', '}', '`', '~', '|'];\r\n public static readonly LABEL_SPACE = ['[', '{', '#', '`', '~', '|', ':'];\r\n public static readonly OBJECT_SPACE = ['<', '['];\r\n public static readonly COP_SPLIT_CHARS = [' ', '\\t', ',', '(', ')', '[', ']', '$', '#'];\r\n\r\n // Pre-compiled regular expressions for parsing\r\n public static readonly WHITESPACE_REGEX = /[ \\t]/;\r\n public static readonly COMMA_SPACE_REGEX = /[, \\t]/;\r\n public static readonly SYMBOL_SPACE_REGEX = /[, \\t<>()\\:\\[\\]{}`~|]/;\r\n public static readonly LABEL_SPACE_REGEX = /[\\[{#`~|:]/;\r\n public static readonly OBJECT_SPACE_REGEX = /[<\\[]/;\r\n public static readonly ADDRESS_SPACE_REGEX = /[@&^#$%*]/;\r\n public static readonly COP_SPLIT_REGEX = /[ \\t,()[\\]$#]/;\r\n \r\n // Trim patterns (for start/end of string)\r\n public static readonly COMMA_SPACE_TRIM_REGEX = /^[, \\t]+|[, \\t]+$/g;\r\n\r\n /**\r\n * Gets the size of an object for processing purposes\r\n * @param obj The object to get the size for\r\n * @returns Size in bytes\r\n * @throws Error when unable to determine size\r\n */\r\n public static getSize(obj: unknown): number {\r\n if(obj === undefined || obj === null) return 0;\r\n switch(typeof obj) {\r\n case 'object':\r\n if(Array.isArray(obj)) {\r\n return obj.reduce((acc, x) => acc + RomProcessingConstants.getSize(x), 0);\r\n }\r\n if ('size' in obj) return obj.size as number;\r\n if ('length' in obj) return obj.length as number;\r\n if ('_tag' in obj) {\r\n switch ((obj as { _tag: string })._tag) {\r\n case 'Byte':\r\n return 1;\r\n case 'Word':\r\n return 2;\r\n }\r\n }\r\n break;\r\n\r\n case 'number':\r\n // Determine size based on value range\r\n if (obj <= 0xFF) return 1;\r\n if (obj <= 0xFFFF) return 2;\r\n if (obj <= 0xFFFFFF) return 3;\r\n return 4;\r\n\r\n case 'string':\r\n if(!obj.length) return 0;\r\n\r\n switch (obj[0]) {\r\n case '@':\r\n case '%':\r\n return 3;\r\n case '*':\r\n case '&':\r\n return 2;\r\n case '^':\r\n return 1;\r\n }\r\n\r\n switch (obj) {\r\n case \"Byte\":\r\n return 1;\r\n case \"Word\":\r\n return 2;\r\n case \"Offset\":\r\n return 2;\r\n case \"Address\":\r\n return 3;\r\n }\r\n \r\n return obj.length;\r\n }\r\n\r\n return 0;\r\n }\r\n}\r\n\r\n/**\r\n * BlockReader specific constants\r\n */\r\nexport class BlockReaderConstants {\r\n public static readonly REF_SEARCH_MAX_RANGE = 0x1A0;\r\n public static readonly BANK_MASK_CHECK = 0x40;\r\n public static readonly BYTE_DELIMITER_THRESHOLD = 0x100;\r\n public static readonly BANK_HIGH_MEMORY_1 = 0x7E;\r\n public static readonly BANK_HIGH_MEMORY_2 = 0x7F;\r\n public static readonly POINTER_CHARACTERS = ['&', '@'];\r\n public static readonly WIDE_STRING_TYPE = \"WideString\";\r\n public static readonly BINARY_TYPE = \"Binary\";\r\n public static readonly CODE_TYPE = \"Code\";\r\n \r\n // Format strings\r\n public static readonly LOCATION_FORMAT = \"loc_{0:X6}\";\r\n public static readonly TYPE_NAME_FORMAT = \"{0}_{1:X6}\";\r\n public static readonly OFFSET_FORMAT = \"+{0:X}\";\r\n public static readonly MARKER_FORMAT = \"+M\";\r\n public static readonly NEGATIVE_OFFSET_FORMAT = \"-{0:X}\";\r\n public static readonly NEGATIVE_MARKER_FORMAT = \"-M\";\r\n} ","import { RomProcessingConstants } from './constants';\r\n\r\n\r\n/**\r\n * Address type classifications\r\n * Converted from GaiaLib/Enum/AddressType.cs\r\n */\r\nexport enum AddressType {\r\n Unknown = 'Unknown',\r\n Bank = 'Bank',\r\n Offset = 'Offset',\r\n Address = 'Address',\r\n WBank = 'WBank',\r\n Relative = 'Relative',\r\n WRelative = 'WRelative',\r\n Location = 'Location'\r\n}\r\n\r\n/**\r\n * Address space types\r\n * Converted from GaiaLib/Types/Address.cs\r\n */\r\nexport enum AddressSpace {\r\n None = 'None',\r\n ROM = 'ROM',\r\n WRAM = 'WRAM',\r\n SRAM = 'SRAM',\r\n System = 'System'\r\n}\r\n\r\nexport enum MemoryMapMode {\r\n Lo = 'Lo',\r\n Hi = 'Hi',\r\n ExHi = 'ExHi'\r\n}\r\n\r\nexport enum CpuMode {\r\n Slow = 'Slow',\r\n Fast = 'Fast'\r\n}\r\n\r\n/**\r\n * SNES address structure\r\n * Converted from GaiaLib/Types/Address.cs\r\n */\r\nexport class Address {\r\n public offset: number;\r\n public bank: number;\r\n public mode: MemoryMapMode;\r\n \r\n public static readonly UPPER_BANK = 0x8000;\r\n public static readonly DATA_BANK_FLAG = 0x40;\r\n public static readonly FAST_BANK_FLAG = 0x80;\r\n\r\n constructor(bank: number, offset: number, mode: MemoryMapMode) {\r\n this.bank = bank & 0xFF;\r\n this.offset = offset & 0xFFFF;\r\n this.mode = mode;\r\n }\r\n\r\n public get isROM(): boolean {\r\n if(this.bank === 0x7E || this.bank === 0x7F) return false;\r\n if(this.offset >= Address.UPPER_BANK) return true;\r\n if(!this.isCodeBank) {\r\n if(this.mode === MemoryMapMode.Lo && this.bank >= 0x70 && this.bank <= 0x7D) return false;\r\n return true;\r\n }\r\n return false;\r\n }\r\n\r\n public get isCodeBank(): boolean {\r\n return (this.bank & Address.DATA_BANK_FLAG) === 0;\r\n }\r\n\r\n // public get space(): AddressSpace {\r\n \r\n // if (this.bank === 0x7E || this.bank === 0x7F) return AddressSpace.WRAM;\r\n // if (this.offset >= RomProcessingConstants.PAGE_SIZE) return AddressSpace.ROM;\r\n\r\n // // Check if bank is in lower half (bank & 0x40 == 0)\r\n // if (this.isCodeBank) {\r\n // // Memory map for lower banks\r\n // if (this.offset >= 0x6000 && (this.bank & 0x20) !== 0) {\r\n // return AddressSpace.SRAM;\r\n // }\r\n // if (this.offset < 0x2000) {\r\n // return AddressSpace.WRAM;\r\n // } else if (this.offset < 0x2100) {\r\n // return AddressSpace.None;\r\n // } else if (this.offset < 0x2200) {\r\n // return AddressSpace.System;\r\n // } else if (this.offset < 0x3000) {\r\n // return AddressSpace.None;\r\n // } else if (this.offset < 0x4100) {\r\n // return AddressSpace.System;\r\n // } else if (this.offset < 0x4200) {\r\n // return AddressSpace.None;\r\n // } else if (this.offset < 0x4500) {\r\n // return AddressSpace.System;\r\n // } else {\r\n // return AddressSpace.None;\r\n // }\r\n // }\r\n\r\n\r\n // return AddressSpace.ROM;\r\n // }\r\n\r\n public toLocation(): number {\r\n if(this.mode === MemoryMapMode.Lo) return ((this.bank & 0x3F) << 15) | (this.offset & 0x7FFF);\r\n if(this.mode === MemoryMapMode.Hi || (this.bank & Address.FAST_BANK_FLAG)) return ((this.bank & 0x3F) << 16) | (this.offset & 0xFFFF);\r\n return (this.bank === 0x3E) ? (this.offset + 0x13D0000) : (this.bank === 0x3F) ? (this.offset + 0x13E0000) \r\n : ((((this.bank & 0x3F) << 16) | (this.offset & 0xFFFF)) + 0x1000000);\r\n }\r\n\r\n public static fromLocation(value: number, mode: MemoryMapMode, cpuMode: CpuMode): Address {\r\n let bankFlag = cpuMode === CpuMode.Fast ? Address.FAST_BANK_FLAG : 0;\r\n if(mode === MemoryMapMode.Lo) {\r\n return new Address((value >> 15) & 0x7F | bankFlag, (value & 0x7FFF) | 0x8000, mode);\r\n }\r\n if(mode === MemoryMapMode.Hi) {\r\n if((value & RomProcessingConstants.PAGE_SIZE) === 0) bankFlag = 0xC0\r\n return new Address((value >> 16) & 0x7F | bankFlag, value & 0xFFFF, mode);\r\n }\r\n ///TODO: Handle ExHi mode\r\n if(value & Address.FAST_BANK_FLAG) return new Address((value >> 16) & 0xFF, value & 0xFFFF, mode);\r\n if(value >= 0x13D0000 && value < 0x13E0000) return new Address(0x3E, value - 0x13D0000, mode);\r\n if(value >= 0x13E0000 && value < 0x13F0000) return new Address(0x3F, value - 0x13E0000, mode);\r\n return new Address((value >> 16) & 0x7F, value & 0xFFFF, mode);\r\n }\r\n\r\n public static resolveBank(value: number, mode: MemoryMapMode): number {\r\n if(mode === MemoryMapMode.Lo) return (value >> 15) & 0xFF;\r\n if(mode === MemoryMapMode.Hi || (value & Address.FAST_BANK_FLAG)) return (value >> 16) & 0xFF;\r\n if(value >= 0x13D0000 && value < 0x13E0000) return 0x3E;\r\n if(value >= 0x13E0000 && value < 0x13F0000) return 0x3F;\r\n return (value >> 16) & 0x7F; \r\n }\r\n\r\n public toInt(): number {\r\n return (this.bank << 16) | this.offset;\r\n }\r\n\r\n public toString(): string {\r\n return this.toInt().toString(16).toUpperCase().padStart(6, '0');\r\n }\r\n\r\n public static typeFromCode(code: string): AddressType {\r\n switch (code) {\r\n case '^':\r\n return AddressType.Bank;\r\n case '&':\r\n return AddressType.Offset;\r\n case '@':\r\n return AddressType.Address;\r\n case '*':\r\n return AddressType.WBank;\r\n case '%':\r\n return AddressType.Location;\r\n default:\r\n return AddressType.Unknown;\r\n }\r\n }\r\n\r\n public static codeFromType(type: AddressType): string | null {\r\n switch (type) {\r\n case AddressType.Bank:\r\n return '^';\r\n case AddressType.Offset:\r\n return '&';\r\n case AddressType.Address:\r\n return '@';\r\n case AddressType.WBank:\r\n return '*';\r\n case AddressType.Location:\r\n return '%';\r\n default:\r\n return null;\r\n }\r\n }\r\n} ","/**\r\n * Member type definitions for data structures\r\n * Converted from GaiaLib/Enum/MemberType.cs\r\n */\r\nexport enum MemberType {\r\n Byte = 'Byte',\r\n Word = 'Word',\r\n Offset = 'Offset',\r\n Address = 'Address',\r\n Binary = 'Binary',\r\n Code = 'Code',\r\n Location = 'Location'\r\n} ","/**\r\n * Processor register type definitions\r\n * Converted from GaiaLib/Enum/RegisterType.cs\r\n */\r\nexport enum RegisterType {\r\n M = 'M',\r\n X = 'X',\r\n B = 'B'\r\n}\r\n\r\n/**\r\n * Status flags for 65816 processor\r\n * Converted from GaiaLib/Enum/StatusFlags.cs\r\n * \r\n * Bit pattern: [ n v m x d i z c ]\r\n * n = Negative\r\n * v = Overflow\r\n * m = Accumulator Mode\r\n * x = Index Mode\r\n * d = Decimal Mode\r\n * i = IRQ Disable\r\n * z = Zero\r\n * c = Carry\r\n */\r\nexport enum StatusFlags {\r\n /**\r\n * Clear before starting addition or subtraction.\r\n * Arithmetic overflow:\r\n * [addition - carry out of high bit:]\r\n * 0 = no carry\r\n * 1 = carry\r\n * [subtraction - borrow required to subtract:]\r\n * 0 = borrow required\r\n * 1 = no borrow required\r\n * [Logic:]\r\n * receives bit shifted or rotated out;\r\n * source of bit rotated in\r\n */\r\n Carry = 0x01,\r\n /**\r\n * Indicates zero or non-zero result:\r\n * 0 = non-zero result\r\n * 1 = zero result\r\n */\r\n Zero = 0x02,\r\n /**\r\n * Enables or disables processor's IRQ interrupt line:\r\n * Set to disable interrupts by masking the IRQ line\r\n * Clear to enable IRQ interrupts\r\n */\r\n IrqDisable = 0x04,\r\n /**\r\n * Determines mode for add/subtract (not increment/decrement, though):\r\n * Set to force decimal operation (BCD)\r\n * Clear to return to binary operation\r\n */\r\n DecimalMode = 0x08,\r\n IndexMode = 0x10,\r\n AccumulatorMode = 0x20,\r\n /**\r\n * Clear to reverse \"set-overflow\" hardware input.\r\n * Indicates invalid carry into high bit of arithmetic\r\n * result (two's-complement overflow):\r\n * 0 = two's-complement result ok\r\n * 1 = error if two's-complement arithmetic\r\n */\r\n Overflow = 0x40,\r\n /**\r\n * Reflects most significant bit of result\r\n * (the sign of a two's-complement binary number):\r\n * 0 = high bit clear (positive result)\r\n * 1 = high bit set (negative result)\r\n */\r\n Negative = 0x80\r\n} ","/**\r\n * Binary resource type definitions\r\n * Converted from GaiaLib/Enum/BinType.cs\r\n */\r\nexport enum BinType {\r\n Bitmap = 'Bitmap',\r\n Tilemap = 'Tilemap',\r\n Tileset = 'Tileset',\r\n Palette = 'Palette',\r\n Sound = 'Sound',\r\n Music = 'Music',\r\n //Unknown = 'Unknown',\r\n Meta17 = 'Meta17',\r\n Spritemap = 'Spritemap',\r\n Assembly = 'Assembly',\r\n Patch = 'Patch',\r\n Transform = 'Transform',\r\n Binary = 'Binary'\r\n} ","/**\r\n * Transform type definitions\r\n * Converted from GaiaLib/Enum/XformType.cs\r\n */\r\nexport enum XformType {\r\n Lookup = 'Lookup',\r\n Replace = 'Replace'\r\n}\r\n\r\n/**\r\n * Transform definition\r\n * Converted from GaiaLib/Types/XformDef.cs\r\n */\r\nexport interface XformDef {\r\n type: XformType;\r\n key?: string;\r\n value?: string;\r\n keyIx?: number;\r\n valueIx?: number;\r\n} ","\r\nexport class OpCode {\r\n public code: number;\r\n public mnem: string;\r\n public mode: string;\r\n\r\n constructor(code: number, mnem: string, mode: string) {\r\n this.code = code;\r\n this.mnem = mnem;\r\n this.mode = mode;\r\n }\r\n}\r\n","import { ChunkFile } from \"./files\";\nimport { CopDef } from \"../database/cop\";\nimport { OpCode } from \"../database/opcode\";\n\n\n/**\n * Represents a single assembly operation/instruction\n */\nexport class Op extends OpCode {\n public location: number;\n public operands: unknown[];\n public size: number;\n public copDef?: CopDef;\n\n constructor(\n code: OpCode,\n location: number = 0,\n operands: unknown[] = [],\n size: number = 1\n ) {\n super(code.code, code.mnem, code.mode);\n this.code = code.code;\n this.location = location;\n this.operands = operands;\n this.size = size;\n }\n}\n\n/**\n * Represents a block of assembly code or data\n */\nexport class AsmBlock {\n public label?: string;\n public location: number;\n public size: number;\n public isString: boolean;\n public objList: any[];\n public structName?: string;\n public bank?: number;\n public includes?: Set<{block: ChunkFile, part: AsmBlock}>;\n\n constructor(\n location: number = 0,\n size: number = 0,\n isString: boolean = false,\n label?: string,\n structName?: string,\n bank?: number\n ) {\n this.label = label;\n this.location = location;\n this.size = size;\n this.isString = isString;\n this.objList = [];\n this.structName = structName;\n this.bank = bank;\n this.includes = new Set();\n }\n} \n\n/**\n * Database part utilities\n */\nexport class AsmBlockUtils {\n /**\n * Check if a location is inside this part\n */\n static isInside(part: AsmBlock, location: number): boolean {\n return location >= part.location && location < (part.location + part.size);\n }\n\n /**\n * Check if a location is outside this part\n */\n static isOutside(part: AsmBlock, location: number): boolean {\n return location < part.location || location >= (part.location + part.size);\n }\n} ","/**\n * Bit stream for reading/writing binary data at bit level\n * Converted from GaiaLib/Types/BitStream.cs\n */\nexport class BitStream {\n private static readonly NIBBLE_MASK = 0xF;\n private static readonly NIBBLE_PERFECT_POSITION = 0x08;\n\n private data: Uint8Array;\n private position: number;\n private bitFlag: number = 0x80;\n private writeSample: number = 0;\n\n constructor(data: Uint8Array, position: number = 0) {\n this.data = data;\n this.position = position;\n }\n\n public get dataArray(): Uint8Array {\n return this.data;\n }\n\n public get currentPosition(): number {\n return this.position;\n }\n\n public set currentPosition(value: number) {\n this.position = value;\n }\n\n /**\n * Read a byte from the stream\n * @returns The byte read, or -1 if the end of the data has been reached\n */\n public readByte(): number {\n // If we've reached the end of the data, return -1\n if (this.position >= this.data.length) {\n return -1;\n }\n\n // Read the current byte, and advance the position\n let sample = this.data[this.position++];\n\n // If the bit flag is not the most significant bit, we need to include the next byte\n if (this.bitFlag !== 0x80) {\n // Include the next byte in the sample\n sample = (sample << 8) | this.data[this.position];\n\n // Shift the (temporary) bit flag to the right until it is 0\n for (let x = this.bitFlag; x > 0; x >>= 1) {\n // Shift sample for each iteration so it will line up with the byte boundary\n sample >>= 1;\n }\n }\n\n // Return the sample\n return sample & 0xFF;\n }\n\n /**\n * Read a ushort from the stream (ignores the current bit flag)\n * @returns The short read, or -1 if the end of the data has been reached\n */\n public readShort(): number {\n // If end of stream (position would overlap data.length), return -1\n if (this.position + 1 >= this.data.length) {\n return -1;\n }\n\n // Read sample using two bytes to form a ushort. Advance position by 2\n const value = this.data[this.position++] | (this.data[this.position++] << 8);\n\n // Return the value\n return value;\n }\n\n /**\n * Read a bit from the stream\n * @returns True if the current bit at bitFlag is set, false otherwise\n */\n public readBit(): boolean {\n // If we've reached the end of the data, return false\n if (this.position >= this.data.length) {\n return false;\n }\n\n // Read the current bit and test it against current bit flag\n const sample = this.data[this.position] & this.bitFlag;\n\n // Shift the bit flag to the right\n this.bitFlag >>= 1;\n\n // If the bit flag is 0, we need to move to the next byte\n if (this.bitFlag === 0) {\n // Reset the bit flag to the most significant bit\n this.bitFlag = 0x80;\n // Advance the position to the next byte\n this.position++;\n }\n\n // Return true if the bit is set, false otherwise\n return sample !== 0;\n }\n\n /**\n * Read a nibble from the stream\n * @returns The nibble read, or -1 if the end of the data has been reached\n */\n public readNibble(): number {\n // If we've reached the end of the data, return -1\n if (this.position >= this.data.length) {\n return -1;\n }\n\n // Read the current (unshifted) byte sample\n let sample = this.data[this.position];\n\n if (this.bitFlag === BitStream.NIBBLE_PERFECT_POSITION) {\n // Reset the bit flag to the most significant bit\n this.bitFlag = 0x80;\n // Advance the position to the next byte\n this.position++;\n } else {\n // Initialize the bit position to -4 (will be incremented as we shift the bit flag to the right)\n let bitPos = -4;\n\n // Shift the bit flag to the right until it is 0\n while (this.bitFlag !== 0) {\n // Shift the bit flag to the right\n this.bitFlag >>= 1;\n // Increment the bit position\n bitPos++;\n }\n\n // If the bit position is less than 0, we need to include the next byte\n if (bitPos < 0) {\n // Include the next byte in the sample, and advance the position\n sample = (sample << 8) | this.data[++this.position];\n\n // Advance the bit position by 8 (will no longer be less than 0)\n bitPos += 8;\n }\n\n // Shift the sample to the right by the bit position\n sample >>= bitPos;\n\n // Set the bit flag to the new bit position\n this.bitFlag = 1 << (bitPos - 1);\n }\n\n // Return the nibble\n return sample & BitStream.NIBBLE_MASK;\n }\n\n /**\n * Write a bit to the stream\n * @param set True if the current bit should be set, false otherwise\n */\n public writeBit(set: boolean): void {\n // If the bit should be set, set the bit in the write sample\n if (set) {\n this.writeSample |= this.bitFlag;\n }\n\n // Shift the bit flag to the right\n this.bitFlag >>= 1;\n\n // If the bit flag is 0, we need to move to the next byte\n if (this.bitFlag === 0) {\n // Reset the bit flag to the most significant bit\n this.bitFlag = 0x80;\n // Write the sample to the data stream\n this.data[this.position++] = this.writeSample;\n // Reset the write sample\n this.writeSample = 0;\n }\n }\n\n /**\n * Write a byte to the stream\n * @param value The byte to write\n */\n public writeByte(value: number): void {\n // If the bit flag is the most significant bit, we can write the byte directly\n if (this.bitFlag === 0x80) {\n this.data[this.position++] = value;\n } else {\n // Shift the value to the left until it is aligned with the bit flag\n for (let x = 1; x <= this.bitFlag; x <<= 1) {\n value <<= 1;\n }\n\n // Write the value to the data stream\n this.data[this.position++] = (this.writeSample | (value >> 8)) & 0xFF;\n\n // Update the write sample\n this.writeSample = value & 0xFF;\n }\n }\n\n /**\n * Write a nibble to the stream\n * @param value The nibble to write\n */\n public writeNibble(value: number): void {\n value &= BitStream.NIBBLE_MASK;\n\n if (this.bitFlag >= 0x10) {\n let shift = 0;\n switch (this.bitFlag) {\n case 0x80: shift = 4; break;\n case 0x40: shift = 3; break;\n case 0x20: shift = 2; break;\n case 0x10: shift = 1; break;\n }\n this.writeSample |= (value << shift);\n this.bitFlag >>= 4;\n } else {\n let shift = 0;\n switch (this.bitFlag) {\n case 0x8: shift = 0; break;\n case 0x4: shift = 1; break;\n case 0x2: shift = 2; break;\n case 0x1: shift = 3; break;\n }\n this.data[this.position++] = (this.writeSample | (value >> shift));\n this.writeSample = (value << (8 - shift));\n this.bitFlag <<= 4;\n }\n }\n\n public flush(): void {\n if (this.bitFlag !== 0x80) {\n this.data[this.position++] = this.writeSample;\n }\n }\n} ","import type { ICompressionProvider } from './compression';\r\n\r\n/**\r\n * Registry for compression providers\r\n * Allows registration of compression implementations by string ID\r\n */\r\nexport class CompressionRegistry {\r\n private static providers = new Map<string, () => ICompressionProvider>();\r\n\r\n /**\r\n * Register a compression provider\r\n * @param id String identifier for the compression type\r\n * @param factory Factory function that creates the compression provider\r\n */\r\n public static register(id: string, factory: () => ICompressionProvider): void {\r\n this.providers.set(id, factory);\r\n }\r\n\r\n /**\r\n * Get a compression provider by ID\r\n * @param id String identifier for the compression type\r\n * @returns Compression provider instance\r\n */\r\n public static get(id: string): ICompressionProvider {\r\n const factory = this.providers.get(id);\r\n if (!factory) {\r\n throw new Error(`No compression provider registered for type: ${id}`);\r\n }\r\n return factory();\r\n }\r\n\r\n /**\r\n * Check if a compression provider is registered\r\n * @param id String identifier for the compression type\r\n * @returns True if provider is registered\r\n */\r\n public static has(id: string): boolean {\r\n return this.providers.has(id);\r\n }\r\n\r\n /**\r\n * Get list of registered provider IDs\r\n * @returns Array of registered provider IDs\r\n */\r\n public static getRegisteredIds(): string[] {\r\n return Array.from(this.providers.keys());\r\n }\r\n\r\n /**\r\n * Clear all registered providers (mainly for testing)\r\n */\r\n public static clear(): void {\r\n this.providers.clear();\r\n }\r\n}\r\n","import { BinType } from './resources';\r\nimport { AsmBlock, AsmBlockUtils } from './assembly';\r\nimport { DbFile, DbFileType } from '../database/files';\r\nimport { DbBlock } from '../database/blocks';\r\nimport { ICompressionProvider } from './compression';\r\nimport { MemoryMapMode } from './addressing';\r\n\r\n/**\r\n * Chunk file for ROM processing\r\n * Converted from GaiaLib/Types/ChunkFile.cs\r\n */\r\nexport class ChunkFile {\r\n //id?: string;\r\n name: string;\r\n size: number;\r\n location: number;\r\n type: DbFileType;\r\n parts?: AsmBlock[];\r\n includes?: Set<string>;\r\n includeLookup?: Map<string, AsmBlock>;\r\n bank?: number;\r\n compressed?: boolean;\r\n upper?: boolean;\r\n rawData?: Uint8Array | null;\r\n textData?: string;\r\n transforms?: { key: string; value: string }[];\r\n postProcess?: string;\r\n mnemonics: Record<number, string>;\r\n group?: string;\r\n scene?: string;\r\n\r\n constructor(name: string, size: number, location: number, type: DbFileType) {\r\n this.name = name;\r\n this.size = size;\r\n this.location = location;\r\n this.mnemonics = {};\r\n this.compressed = type.compressed;\r\n this.type = type;\r\n }\r\n\r\n // public getExtension() : string {\r\n // switch(this.type) {\r\n // case BinType.Assembly:\r\n // case BinType.Patch:\r\n // return 'asm';\r\n // case BinType.Music:\r\n // return 'bgm';\r\n // case BinType.Sound:\r\n // return 'sfx';\r\n // case BinType.Bitmap:\r\n // return 'bin';\r\n // case BinType.Tilemap:\r\n // return 'map';\r\n // case BinType.Tileset:\r\n // return 'set';\r\n // case BinType.Spritemap:\r\n // return 'spm';\r\n // case BinType.Palette:\r\n // return 'pal';\r\n // case BinType.Meta17:\r\n // return 'dmp';\r\n // }\r\n // }\r\n}\r\n\r\n// /**\r\n// * Creates a new ChunkFile\r\n// */\r\n// export function createChunkFile(name: string, size: number, location: number, type: BinType): ChunkFile {\r\n// return {\r\n// name,\r\n// size,\r\n// location,\r\n// type,\r\n// mnemonics: {}\r\n// };\r\n// }\r\n\r\nexport function createChunkFileFromDbFile(rom: Uint8Array, compression: ICompressionProvider | undefined, dbFile: DbFile, fileType: DbFileType): ChunkFile {\r\n // Create ChunkFile with the DbFile's type\r\n const chunkFile = new ChunkFile(dbFile.name, dbFile.end - dbFile.start, dbFile.start, fileType);\r\n //chunkFile.id = dbFile.id;\r\n chunkFile.compressed = dbFile.compressed;\r\n chunkFile.upper = dbFile.upper;\r\n chunkFile.group = dbFile.group;\r\n chunkFile.scene = dbFile.scene;\r\n\r\n \r\n // Enrich with raw binary data\r\n enrichWithRawDataFromDbFile(rom, chunkFile, compression, dbFile, fileType);\r\n\r\n return chunkFile;\r\n}\r\n\r\nexport function createChunkFileFromDbBlock(block: DbBlock, fileType: DbFileType, memoryMode: MemoryMapMode): ChunkFile {\r\n // Create assembly ChunkFile\r\n const chunkFile = new ChunkFile(block.name, 0, 0, fileType);\r\n //chunkFile.id = block.id;\r\n chunkFile.group = block.group;\r\n chunkFile.scene = block.scene;\r\n \r\n // Enrich with AsmBlock parts\r\n enrichWithPartsFromDbBlock(chunkFile, block, memoryMode);\r\n \r\n return chunkFile;\r\n}\r\n\r\n\r\nfunction combineHeader(\r\n data: Uint8Array,\r\n position: number,\r\n length: number,\r\n header: Uint8Array | null,\r\n type: BinType\r\n): Uint8Array {\r\n let totalLength = length + (header ? header.length : 0);\r\n if (type === BinType.Palette && length < 0x200) {\r\n totalLength += (0x200 - length);\r\n }\r\n const result = new Uint8Array(totalLength);\r\n let offset = 0;\r\n if (header) { result.set(header, offset); offset += header.length; }\r\n result.set(data.slice(position, position + length), offset);\r\n offset += length;\r\n if (type === BinType.Palette && length < 0x200) {\r\n result.fill(0, offset, offset + (0x200 - length));\r\n }\r\n return result;\r\n}\r\n\r\n/**\r\n * Enriches ChunkFile with raw binary data from DbFile\r\n */\r\nfunction enrichWithRawDataFromDbFile(rom: Uint8Array, chunkFile: ChunkFile, compression: ICompressionProvider | undefined, dbFile: DbFile, fileType: DbFileType): void {\r\n \r\n // Extract raw data (uncompressed) with headers for specific types\r\n let start = dbFile.start;\r\n let header: Uint8Array | null = null;\r\n if(fileType.header) {\r\n header = new Uint8Array(rom.slice(start, start + fileType.header));\r\n start += fileType.header;\r\n }\r\n let length = dbFile.end - start;\r\n let fileData: Uint8Array;\r\n if (dbFile.compressed === true && compression) {\r\n const expanded = compression.expand(rom, start, length);\r\n fileData = combineHeader(expanded, 0, expanded.length, header, fileType.type as BinType);\r\n } else {\r\n if (dbFile.compressed !== undefined) {\r\n start += 2; length -= 2; // skip zero-compression header\r\n }\r\n fileData = combineHeader(rom, start, length, header, fileType.type as BinType);\r\n }\r\n \r\n //const hasSizePrefix = chunkFile.compressed !== undefined || dbFile.type === BinType.Sound;\r\n\r\n // Binary files get rawData\r\n chunkFile.rawData = fileData;\r\n chunkFile.size = fileData.length;// + (hasSizePrefix ? 2 : 0);\r\n\r\n}\r\n\r\n/**\r\n * Enriches ChunkFile with AsmBlock parts from DbBlock\r\n */\r\nfunction enrichWithPartsFromDbBlock(chunkFile: ChunkFile, block: DbBlock, memoryMode: MemoryMapMode): void {\r\n chunkFile.parts = [];\r\n chunkFile.size = 0;\r\n if(!block.parts?.length) {\r\n throw new Error(`Block ${block.name} has no parts`);\r\n }\r\n chunkFile.location = block.parts[0].start;\r\n chunkFile.bank = block.movable ? undefined : (memoryMode === MemoryMapMode.Lo ? chunkFile.location >> 15 : chunkFile.location >> 16);\r\n chunkFile.transforms = block.transforms;\r\n chunkFile.postProcess = block.postProcess;\r\n \r\n for (const part of block.parts) {\r\n const asmBlock = new AsmBlock(\r\n part.start,\r\n part.end - part.start,\r\n false, // isString will be determined during processing\r\n part.name,\r\n part.type || undefined,\r\n part.bank\r\n );\r\n chunkFile.size += asmBlock.size;\r\n chunkFile.parts.push(asmBlock);\r\n }\r\n}\r\n\r\n/**\r\n * Chunk file utilities\r\n */\r\nexport class ChunkFileUtils {\r\n /**\r\n * Rebase blocks to a new location\r\n */\r\n static rebase(chunkFile: ChunkFile, newLocation?: number): void {\r\n if (newLocation !== undefined) {\r\n chunkFile.location = newLocation;\r\n }\r\n\r\n if (!chunkFile.parts) {\r\n return;\r\n }\r\n\r\n let loc = chunkFile.location;\r\n for (let x = 0; x < chunkFile.parts.length; x++) {\r\n const block = chunkFile.parts[x];\r\n if (x > 0 && !block.label) {\r\n break;\r\n }\r\n block.location = loc;\r\n loc += block.size || 0;\r\n }\r\n }\r\n\r\n /**\r\n * Calculate the total size of all blocks\r\n */\r\n static calculateSize(chunkFile: ChunkFile): number {\r\n if (!chunkFile.parts) {\r\n let size = chunkFile.rawData?.length ?? chunkFile.size;\r\n if (chunkFile.type.header === -2 || chunkFile.compressed === false){\r\n size += 2;\r\n chunkFile.size = size;\r\n }\r\n return size;\r\n }\r\n\r\n let size = 0;\r\n for (let x = 0; x < chunkFile.parts.length; x++) {\r\n const block = chunkFile.parts[x];\r\n if (x > 0 && !block.label) {\r\n break;\r\n }\r\n size += block.size || 0;\r\n }\r\n \r\n chunkFile.size = size;\r\n return size;\r\n }\r\n\r\n /**\r\n * Check if a location is outside this block and return the part (matches C# IsOutside)\r\n * Returns [isOutside, part] where part is the part containing the location\r\n */\r\n static isOutsideWithPart(root: ChunkFile[], block: ChunkFile, location: number): [boolean, ChunkFile | null, AsmBlock | null] {\r\n const [isInside, part] = this.isInsideWithPart(block, location);\r\n if (isInside) {\r\n return [false, block, part];\r\n }\r\n\r\n // Find chunk this reference belongs to\r\n for (const otherBlock of root) {\r\n if (otherBlock !== block) {\r\n const [otherIsInside, otherPart] = this.isInsideWithPart(otherBlock, location);\r\n if (otherIsInside) {\r\n return [true, otherBlock, otherPart];\r\n }\r\n }\r\n }\r\n\r\n return [true, null, null];\r\n }\r\n\r\n /**\r\n * Check if a location is inside this block and return the part (matches C# IsInside)\r\n * Returns [isInside, part] where part is the part containing the location\r\n */\r\n static isInsideWithPart(block: ChunkFile, location: number): [boolean, AsmBlock | null] {\r\n for (const part of block?.parts || []) {\r\n if (AsmBlockUtils.isInside(part, location)) {\r\n return [true, part];\r\n }\r\n }\r\n return [false, null];\r\n }\r\n\r\n /**\r\n * Check if a location is outside this block (shorthand version)\r\n */\r\n static isOutside(block: ChunkFile, location: number): boolean {\r\n return !this.isInside(block, location);\r\n }\r\n\r\n /**\r\n * Check if a location is inside this block (shorthand version)\r\n */\r\n static isInside(block: ChunkFile, location: number): boolean {\r\n for (const part of block?.parts || []) {\r\n if (AsmBlockUtils.isInside(part, location)) {\r\n return true;\r\n }\r\n }\r\n return false;\r\n }\r\n\r\n /**\r\n * Get all included blocks\r\n */\r\n static getIncludes(chunkFile: ChunkFile): ChunkFile[] {\r\n if(!chunkFile.parts) return [];\r\n const includes: ChunkFile[] = [];\r\n const seen = new Set<ChunkFile>();\r\n\r\n for (const part of chunkFile.parts) {\r\n if (part?.includes) {\r\n for (const includedPart of part.includes) {\r\n if (!seen.has(includedPart.block)) {\r\n includes.push(includedPart.block);\r\n seen.add(includedPart.block);\r\n }\r\n }\r\n }\r\n }\r\n\r\n return includes;\r\n }\r\n} ","import { AddressType } from './addressing';\r\n\r\n/**\r\n * Location wrapper for additional metadata\r\n * Converted from GaiaLib/Types/LocationWrapper.cs\r\n */\r\nexport class LocationWrapper {\r\n public location: number;\r\n public type: AddressType;\r\n\r\n constructor(location: number, type: AddressType) {\r\n this.location = location;\r\n this.type = type;\r\n }\r\n} ","import type { DbStringType } from '../database/strings';\r\nimport { AsmBlock } from './assembly';\r\n\r\n/**\r\n * String marker for positioning\r\n * Converted from GaiaLib/Types/StringMarker.cs\r\n */\r\nexport interface StringMarker {\r\n offset: number;\r\n}\r\n\r\n/**\r\n * String wrapper with type and location information\r\n * Converted from GaiaLib/Types/StringWrapper.cs\r\n */\r\nexport interface StringWrapper {\r\n string: string;\r\n type: DbStringType;\r\n marker: number;\r\n location: number;\r\n fixedSize: number;\r\n}\r\n\r\n/**\r\n * String entry (commented out in original C# code)\r\n * Converted from GaiaLib/Types/StringEntry.cs\r\n */\r\nexport interface StringEntry {\r\n block: AsmBlock;\r\n index: number;\r\n size: number;\r\n data: Uint8Array;\r\n}\r\n\r\n/**\r\n * String size comparer utility\r\n * Converted from GaiaLib/Types/StringSizeComparer.cs\r\n */\r\nexport class StringSizeComparer {\r\n /**\r\n * Compare two strings by length\r\n */\r\n static compare(a: string, b: string): number {\r\n if (a.length < b.length) return -1;\r\n if (a.length > b.length) return 1;\r\n return a.localeCompare(b);\r\n }\r\n \r\n /**\r\n * Compare two StringWrapper objects by string length\r\n */\r\n static compareWrappers(a: StringWrapper, b: StringWrapper): number {\r\n return this.compare(a.string, b.string);\r\n }\r\n} ","\r\nexport class TableEntry {\r\n location: number;\r\n object: unknown;\r\n\r\n constructor(location: number) {\r\n if(typeof location !== 'number') throw new Error('Location is required');\r\n this.location = location;\r\n }\r\n}\r\n","export class TypedNumber {\r\n value: number;\r\n size: number;\r\n\r\n constructor(value: number, size: number) {\r\n this.value = value;\r\n this.size = size;\r\n }\r\n}\r\n\r\nexport class Byte extends TypedNumber {\r\n constructor(value: number) {\r\n super(value & 0xFF, 1);\r\n }\r\n}\r\n\r\nexport class Word extends TypedNumber {\r\n constructor(value: number) {\r\n super(value & 0xFFFF, 2);\r\n }\r\n}\r\n\r\nexport class Long extends TypedNumber {\r\n constructor(value: number) {\r\n super(value & 0xFFFFFF, 3);\r\n }\r\n}","import { AddressType, Address } from '../../types';\r\nimport { BlockReaderConstants } from '../../types/constants';\r\nimport type { DbRoot } from '../../database';\r\n\r\n/**\r\n * Manages references, chunks, and markers during ROM analysis\r\n * Converted from GaiaLib/Rom/Extraction/ReferenceManager.cs\r\n */\r\nexport class ReferenceManager {\r\n public readonly structTable = new Map<number, string>();\r\n public readonly markerTable = new Map<number, number>();\r\n public readonly nameTable = new Map<number, string>();\r\n private readonly root: DbRoot;\r\n\r\n constructor(root: DbRoot) {\r\n if (!root) {\r\n throw new Error('root cannot be null');\r\n }\r\n this.root = root;\r\n }\r\n\r\n // Struct management\r\n public tryGetStruct(location: number): { found: boolean; chunkType?: string } {\r\n const chunkType = this.structTable.get(location);\r\n return { found: chunkType !== undefined, chunkType };\r\n }\r\n\r\n public tryAddStruct(location: number, chunkType: string): boolean {\r\n if (this.structTable.has(location)) {\r\n return false;\r\n }\r\n this.structTable.set(location, chunkType);\r\n return true;\r\n }\r\n\r\n public containsStruct(location: number): boolean {\r\n return this.structTable.has(location);\r\n }\r\n\r\n // Name management\r\n public tryGetName(location: number): { found: boolean; referenceName?: string } {\r\n const referenceName = this.nameTable.get(location);\r\n return { found: referenceName !== undefined, referenceName };\r\n }\r\n\r\n public tryAddName(location: number, referenceName: string): boolean {\r\n if (this.nameTable.has(location)) {\r\n return false;\r\n }\r\n this.nameTable.set(location, referenceName);\r\n return true;\r\n }\r\n\r\n // Marker management\r\n public tryGetMarker(location: number): { found: boolean; offset?: number } {\r\n const offset = this.markerTable.get(location);\r\n return { found: offset !== undefined, offset };\r\n }\r\n\r\n public setMarker(location: number, offset: number): void {\r\n this.markerTable.set(location, offset);\r\n }\r\n\r\n // Label creation\r\n public createBranchLabel(location: number): string {\r\n // const adrs = Address.fromInt(location, this.root.config.memoryMode);\r\n // const name = `loc_${adrs.toString()}`;\r\n const name = `loc_${location.toString(16).toUpperCase().padStart(6, '0')}`;\r\n this.nameTable.set(location, name);\r\n return name;\r\n }\r\n\r\n public createTypeName(type: string, location: number): string {\r\n let name = type.toLowerCase();\r\n \r\n // Handle pointer characters\r\n while (name.length > 0 && BlockReaderConstants.POINTER_CHARACTERS.includes(name[0])) {\r\n name = name.substring(1) + '_list';\r\n }\r\n\r\n //const adrs = Address.fromInt(location, this.root.config.memoryMode);\r\n //return `${name}_${adrs.toString()}`;\r\n return `${name}_${location.toString(16).toUpperCase().padStart(6, '0')}`;\r\n }\r\n\r\n public createFallbackName(location: number): string {\r\n const fileMatch = this.root.files.find(x =>\r\n x.start <= location && x.end > location\r\n );\r\n\r\n if (fileMatch) {\r\n const offset = location - fileMatch.start;\r\n return fileMatch.name + (offset !== 0 ? `+${offset.toString(16).toUpperCase()}` : '');\r\n }\r\n\r\n // const adrs = Address.fromInt(location, this.root.config.memoryMode);\r\n // return adrs.toString(); \r\n return location.toString(16).toUpperCase().padStart(6, '0');\r\n }\r\n\r\n /**\r\n * Finds a reference location by its assigned name.\r\n */\r\n public findLocationByName(name: string): number | undefined {\r\n for (const [loc, refName] of this.nameTable) {\r\n if (refName === name) {\r\n return loc;\r\n }\r\n }\r\n return undefined;\r\n }\r\n\r\n public resolveName(location: number, type: AddressType, isBranch: boolean): string {\r\n const prefix = Address.codeFromType(type);\r\n let name: string;\r\n let label: string | null = null;\r\n let resolvedLocation = location;\r\n\r\n // Handle rewrites first\r\n const rewrite = this.root.rewrites[location];\r\n if (rewrite !== undefined) {\r\n const result = this.processRewrite(location, rewrite);\r\n resolvedLocation = result.location;\r\n label = result.label;\r\n }\r\n\r\n // Try to get existing reference\r\n const existingName = this.nameTable.get(resolvedLocation);\r\n if (existingName) {\r\n name = existingName;\r\n } else {\r\n name = isBranch ? \r\n this.createBranchLabel(resolvedLocation) : \r\n this.findClosestReference(resolvedLocation) || this.createFallbackName(resolvedLocation);\r\n }\r\n\r\n return `${prefix || ''}${name}${label || ''}`;\r\n }\r\n\r\n public findClosestReference(location: number): string | null {\r\n let closestDistance = BlockReaderConstants.REF_SEARCH_MAX_RANGE;\r\n let closestName: string | null = null;\r\n let closestLocation: number | null = null;\r\n\r\n for (const [entryKey, entryValue] of this.nameTable) {\r\n if (entryKey > location) {\r\n continue;\r\n }\r\n\r\n const distance = location - entryKey;\r\n if (distance >= closestDistance) {\r\n continue;\r\n }\r\n\r\n closestDistance = distance;\r\n closestName = entryValue;\r\n closestLocation = entryKey;\r\n\r\n if (closestDistance === 1) {\r\n break;\r\n }\r\n }\r\n\r\n return this.processClosestMatch(location, closestName, closestLocation, closestDistance);\r\n }\r\n\r\n private processRewrite(location: number, rewrite: number): { location: number; label: string | null } {\r\n const offset = location - rewrite;\r\n const cmd = offset < 0 ? '-' : '+';\r\n const absOffset = Math.abs(offset);\r\n\r\n let label: string | null = null;\r\n const structType = this.structTable.get(rewrite);\r\n \r\n if (structType === BlockReaderConstants.WIDE_STRING_TYPE) {\r\n this.markerTable.set(rewrite, absOffset);\r\n this.markerTable.set(location, absOffset);\r\n label = cmd === '-' ? BlockReaderConstants.NEGATIVE_MARKER_FORMAT : BlockReaderConstants.MARKER_FORMAT;\r\n } else {\r\n const formatString = cmd === '-' ? BlockReaderConstants.NEGATIVE_OFFSET_FORMAT : BlockReaderConstants.OFFSET_FORMAT;\r\n label = formatString.replace('{0:X}', absOffset.toString(16).toUpperCase());\r\n }\r\n\r\n return { location: rewrite, label };\r\n }\r\n\r\n private processClosestMatch(\r\n location: number, \r\n closestName: string | null, \r\n closestLocation: number | null, \r\n closestDistance: number\r\n ): string | null {\r\n if (!closestName || closestLocation === null) {\r\n return null;\r\n }\r\n\r\n let result = closestName;\r\n const structType = this.structTable.get(closestLocation);\r\n\r\n if (structType === BlockReaderConstants.WIDE_STRING_TYPE) {\r\n this.markerTable.set(closestLocation, closestDistance);\r\n this.markerTable.set(location, closestDistance);\r\n result += BlockReaderConstants.MARKER_FORMAT;\r\n } else {\r\n result += `+${closestDistance.toString(16).toUpperCase()}`;\r\n }\r\n\r\n return result;\r\n }\r\n} ","import { Registers } from '../../assembly';\nimport { StatusFlags } from '../../types';\nimport type { BlockReader } from './blocks';\n\n/**\n * Handles stack operations for various stack-related instructions\n * Converted from GaiaLib/Rom/Extraction/StackOperations.cs\n */\nexport class StackOperations {\n private readonly _registers: Registers;\n private readonly _blockReader: BlockReader;\n\n constructor(registers: Registers, blockReader: BlockReader) {\n this._registers = registers;\n this._blockReader = blockReader;\n }\n\n public handleStackOperation(mnemonic: string): void {\n switch (mnemonic) {\n case 'PHD':\n this._registers.stack.push(this._registers.value['direct'] ?? 0);\n break;\n \n case 'PLD':\n this._registers.value['direct'] = this._registers.stack.popUInt16();\n break;\n \n case 'PHK':\n this._registers.stack.push((this._blockReader._romDataReader.position >> 16) | 0x80);\n break;\n \n case 'PHB':\n this._registers.stack.push(this._registers.value['dataBank'] ?? 0x81);\n break;\n \n case 'PLB':\n this._registers.value['dataBank'] = this._registers.stack.popByte();\n break;\n \n case 'PHP':\n this._registers.stack.push(this._registers.value['statusFlags'] ?? 0);\n break;\n \n case 'PLP':\n this._registers.value['statusFlags'] = this._registers.stack.popByte();\n break;\n\n case 'PHA':\n this.handleAccumulatorPush();\n break;\n\n case 'PLA':\n this.handleAccumulatorPull();\n break;\n\n case 'PHX':\n this.handleXIndexPush();\n break;\n\n case 'PLX':\n this.handleXIndexPull();\n break;\n\n case 'PHY':\n this.handleYIndexPush();\n break;\n\n case 'PLY':\n this.handleYIndexPull();\n break;\n\n case 'XBA':\n this.handleExchangeBytes();\n break;\n }\n }\n\n private handleAccumulatorPush(): void {\n if (this._registers.value['statusFlags'] & StatusFlags.AccumulatorMode) {\n this._registers.stack.push(this._registers.value['accumulator'] ?? 0);\n } else {\n this._registers.stack.pushUInt16(this._registers.value['accumulator'] ?? 0);\n }\n }\n\n private handleAccumulatorPull(): void {\n if (this._registers.value['statusFlags'] & StatusFlags.AccumulatorMode) {\n this._registers.value['accumulator'] = ((this._registers.value['accumulator'] ?? 0) & 0xFF00) | this._registers.stack.popByte();\n } else {\n this._registers.value['accumulator'] = this._registers.stack.popUInt16();\n }\n }\n\n private handleXIndexPush(): void {\n if (this._registers.value['statusFlags'] & StatusFlags.IndexMode) {\n this._registers.stack.push((this._registers.value['xIndex'] ?? 0) & 0xFF);\n } else {\n this._registers.stack.pushUInt16(this._registers.value['xIndex'] ?? 0);\n }\n }\n\n private handleXIndexPull(): void {\n if (this._registers.value['statusFlags'] & StatusFlags.IndexMode) {\n this._registers.value['xIndex'] = ((this._registers.value['xIndex'] ?? 0) & 0xFF00) | this._registers.stack.popByte();\n } else {\n this._registers.value['xIndex'] = this._registers.stack.popUInt16();\n }\n }\n\n private handleYIndexPush(): void {\n if (this._registers.value['statusFlags'] & StatusFlags.IndexMode) {\n this._registers.stack.push((this._registers.value['yIndex'] ?? 0) & 0xFF);\n } else {\n this._registers.stack.pushUInt16(this._registers.value['yIndex'] ?? 0);\n }\n }\n\n private handleYIndexPull(): void {\n if (this._registers.value['statusFlags'] & StatusFlags.IndexMode) {\n this._registers.value['yIndex'] = ((this._registers.value['yIndex'] ?? 0) & 0xFF00) | this._registers.stack.popByte();\n } else {\n this._registers.value['yIndex'] = this._registers.stack.popUInt16();\n }\n }\n\n private handleExchangeBytes(): void {\n const acc = this._registers.value['accumulator'] ?? 0;\n this._registers.value['accumulator'] = ((acc >> 8) | (acc << 8)) & 0xFFFF;\n }\n} ","import { RomDataReader } from './reader';\r\nimport {\r\n Address,\r\n AddressType,\r\n AddressSpace,\r\n LocationWrapper,\r\n MemberType,\r\n Byte,\r\n Word,\r\n} from '../../types';\r\nimport type { CopDef } from '../../database';\r\nimport type { BlockReader } from './blocks';\r\n\r\n/**\r\n * Handles COP (Coprocessor) command processing\r\n * Converted from GaiaLib/Rom/Extraction/CopCommandProcessor.cs\r\n */\r\nexport class CopCommandProcessor {\r\n private readonly _blockReader: BlockReader;\r\n private readonly _romDataReader: RomDataReader;\r\n\r\n constructor(blockReader: BlockReader) {\r\n this._blockReader = blockReader;\r\n this._romDataReader = blockReader._romDataReader;\r\n }\r\n\r\n /**\r\n * Parses a COP command based on its definition\r\n */\r\n public parseCopCommand(copDef: CopDef, operands: unknown[]): void {\r\n for (let partStr of copDef.parts) {\r\n let bank : number | null = null;\r\n\r\n //Trim the end for bank hints\r\n const bankHintIx = partStr.indexOf('$')\r\n if(bankHintIx > 0) {\r\n bank = parseInt(partStr.substring(bankHintIx + 1), 16);\r\n partStr = partStr.substring(0, bankHintIx);\r\n }\r\n\r\n // Use the first character to determine the address type (for pointers)\r\n const addrType = Address.typeFromCode(partStr[0]);\r\n const isPtr = addrType !== AddressType.Unknown;\r\n \r\n // Reference type is the target of a pointer from partStr, or the struct type if not a pointer\r\n const referenceType = isPtr ? partStr.substring(1) : this._blockReader._currentAsmBlock!.structName ?? 'Binary';\r\n \r\n // Member type resolves to the underlying pointer type, or partStr\r\n const memberTypeName = isPtr ? addrType.toString() : partStr;\r\n\r\n // Resolve member type name to a MemberType enum\r\n const memberType = this.tryParseMemberType(memberTypeName);\r\n if (memberType === null) {\r\n throw new Error('Cannot use structs in cop def'); // Only basic types are allowed in COP definitions\r\n }\r\n\r\n // If there is a label, ignore reading and use the label instead\r\n const label = this._blockReader._root.labels[this._romDataReader.position];\r\n if (label) {\r\n this._romDataReader.position += this.getMemberTypeSize(memberType);\r\n operands.push(label);\r\n } else {\r\n operands.push(this.readMemberTypeValue(memberType, partStr, isPtr, referenceType, addrType, bank));\r\n }\r\n\r\n }\r\n }\r\n\r\n private tryParseMemberType(memberTypeName: string): MemberType | null {\r\n // Check if the string matches any MemberType enum value (case-insensitive)\r\n const upperName = memberTypeName.toUpperCase();\r\n for (const [key, value] of Object.entries(MemberType)) {\r\n if (key.toUpperCase() === upperName) {\r\n return value;\r\n }\r\n }\r\n return null;\r\n }\r\n\r\n private getMemberTypeSize(memberType: MemberType): number {\r\n switch (memberType) {\r\n case MemberType.Byte:\r\n return 1;\r\n case MemberType.Word:\r\n case MemberType.Offset:\r\n return 2;\r\n case MemberType.Address:\r\n return 3;\r\n default:\r\n throw new Error('Unsupported COP member type');\r\n }\r\n }\r\n\r\n private readMemberTypeValue(\r\n memberType: MemberType,\r\n partStr: string,\r\n isPtr: boolean,\r\n referenceType: string,\r\n addrType: AddressType,\r\n bank: number | null\r\n ): unknown {\r\n switch (memberType) {\r\n case MemberType.Byte:\r\n return new Byte(this._romDataReader.readByte());\r\n case MemberType.Word:\r\n return new Word(this._romDataReader.readUShort());\r\n case MemberType.Offset:\r\n return this.createCopLocation(this._romDataReader.readUShort(), bank, partStr, isPtr, referenceType, addrType);\r\n case MemberType.Address:\r\n return this.createCopLocation(this._romDataReader.readUShort(), this._romDataReader.readByte(), partStr, isPtr, referenceType, addrType);\r\n default:\r\n throw new Error('Unsupported COP member type');\r\n }\r\n }\r\n\r\n private createCopLocation(\r\n offset: number, \r\n bank: number | null, \r\n partStr: string, \r\n isPtr: boolean, \r\n otherStr: string, \r\n type: AddressType\r\n ): unknown {\r\n if (bank === null && offset === 0) {\r\n return new Word(offset);\r\n }\r\n\r\n const resolvedBank = bank ?? Address.resolveBank(this._romDataReader.position, this._blockReader._root.config.memoryMode);\r\n\r\n const addr = new Address(resolvedBank, offset, this._blockReader._root.config.memoryMode);\r\n if (addr.isROM) {\r\n const location = addr.toLocation();\r\n if (partStr !== 'Address' && isPtr && !this._blockReader._root.rewrites[location]) {\r\n this._blockReader.noteType(location, otherStr, true);\r\n }\r\n\r\n // When address is unknown, try to use the part string (for Offset or Address)\r\n if (type === AddressType.Unknown) {\r\n type = this.tryParseAddressType(partStr) ?? AddressType.Unknown;\r\n }\r\n\r\n return new LocationWrapper(location, type);\r\n }\r\n return addr;\r\n }\r\n\r\n private tryParseAddressType(addressTypeName: string): AddressType | null {\r\n // Check if the string matches any AddressType enum value (case-insensitive)\r\n const upperName = addressTypeName.toUpperCase();\r\n for (const [key, value] of Object.entries(AddressType)) {\r\n if (key.toUpperCase() === upperName) {\r\n return value;\r\n }\r\n }\r\n return null;\r\n }\r\n} ","import { Registers } from '../../assembly';\r\nimport {\r\n AddressType,\r\n AddressSpace,\r\n Address,\r\n LocationWrapper,\r\n StatusFlags,\r\n Byte,\r\n Word,\r\n} from '../../types';\r\nimport { RomDataReader } from './reader';\r\nimport { StackOperations } from './stack';\r\nimport { TransformProcessor } from './transforms';\r\nimport { CopCommandProcessor } from './cop';\r\nimport type { DbRoot, CopDef, OpCode } from '../../database';\r\nimport type { BlockReader } from './blocks';\r\n\r\n/**\r\n * Context information for an operation being processed\r\n * Converted from GaiaLib/Rom/Extraction/AsmReader.cs OperationContext\r\n */\r\nexport class OperationContext {\r\n public size: number = 0;\r\n public nextAddress: number = 0;\r\n public xForm1: string | null = null;\r\n public xForm2: string | null = null;\r\n public copDef: CopDef | null = null;\r\n}\r\n\r\n/**\r\n * Handles different addressing modes for assembly instructions\r\n * Converted from GaiaLib/Rom/Extraction/AddressingModeHandler.cs\r\n */\r\nexport class AddressingModeHandler {\r\n private readonly _blockReader: BlockReader;\r\n private readonly _transformProcessor: TransformProcessor;\r\n private readonly _copProcessor: CopCommandProcessor;\r\n private readonly _dataReader: RomDataReader;\r\n\r\n constructor(blockReader: BlockReader, transformProcessor: TransformProcessor) {\r\n this._blockReader = blockReader;\r\n this._transformProcessor = transformProcessor;\r\n this._copProcessor = new CopCommandProcessor(blockReader);\r\n this._dataReader = blockReader._romDataReader;\r\n }\r\n\r\n public processAddressingMode(code: OpCode, context: OperationContext, reg: Registers): unknown[] {\r\n const operands: unknown[] = [];\r\n\r\n switch (code.mode) {\r\n case 'Stack':\r\n case 'Implied':\r\n case 'Accumulator':\r\n this.handleStackOrImpliedMode(code.mnem, reg);\r\n break;\r\n\r\n case 'Immediate':\r\n this.handleImmediateMode(code.mnem, context.size, operands, reg);\r\n break;\r\n\r\n case 'AbsoluteIndexedIndirect':\r\n this.handleAbsoluteMode(code.mnem, undefined, context.nextAddress, reg.value['dataBank'], operands, reg, true);\r\n break;\r\n\r\n case 'AbsoluteIndirect':\r\n case 'AbsoluteIndirectLong':\r\n case 'Absolute':\r\n case 'AbsoluteIndexedX':\r\n case 'AbsoluteIndexedY':\r\n this.handleAbsoluteMode(code.mnem, undefined, context.nextAddress, reg.value['dataBank'], operands, reg);\r\n break;\r\n\r\n case 'AbsoluteLong':\r\n case 'AbsoluteLongIndexedX':\r\n this.handleAbsoluteLongMode(code.mnem, operands, reg);\r\n break;\r\n\r\n case 'BlockMove':\r\n this.handleBlockMoveMode(operands, context);\r\n break;\r\n\r\n case 'DirectPage':\r\n case 'DirectPageIndexedIndirectX':\r\n case 'DirectPageIndexedX':\r\n case 'DirectPageIndexedY':\r\n case 'DirectPageIndirect':\r\n case 'DirectPageIndirectIndexedY':\r\n case 'DirectPageIndirectLong':\r\n case 'DirectPageIndirectLongIndexedY':\r\n this.handleDirectPageMode(operands);\r\n break;\r\n\r\n case 'PCRelative':\r\n this.handlePCRelativeMode(operands, context.nextAddress, reg, false);\r\n break;\r\n\r\n case 'PCRelativeLong':\r\n this.handlePCRelativeMode(operands, context.nextAddress, reg, true);\r\n break;\r\n\r\n case 'StackRelative':\r\n case 'StackRelativeIndirectIndexedY':\r\n this.handleStackRelativeMode(operands);\r\n break;\r\n\r\n case 'StackInterrupt':\r\n this.handleStackInterruptMode(code.mnem, operands, context);\r\n break;\r\n\r\n default:\r\n throw new Error(`Unknown addressing mode: ${code}`);\r\n }\r\n\r\n return operands;\r\n }\r\n\r\n private handleImmediateMode(mnemonic: string, size: number, operands: unknown[], reg: Registers): void {\r\n const operand = this.readImmediateOperand(size);\r\n operands.push(operand);\r\n this.updateRegisterForImmediateInstruction(mnemonic, operand, reg);\r\n }\r\n\r\n private readImmediateOperand(size: number) {\r\n return size === 3\r\n ? new Word(this._dataReader.readUShort())\r\n : new Byte(this._dataReader.readByte());\r\n }\r\n\r\n private updateRegisterForImmediateInstruction(\r\n mnemonic: string,\r\n operand: number | { value: number },\r\n reg: Registers\r\n ): void {\r\n const value = typeof operand === 'number' ? operand : operand.value;\r\n switch (mnemonic) {\r\n case 'LDA':\r\n reg.value['accumulator'] = this.calculateRegisterValue(reg.value['accumulator'], (reg.value['statusFlags'] & StatusFlags.AccumulatorMode) === StatusFlags.AccumulatorMode, value);\r\n break;\r\n\r\n case 'LDX':\r\n reg.value['xIndex'] = this.calculateRegisterValue(reg.value['xIndex'], (reg.value['statusFlags'] & StatusFlags.IndexMode) === StatusFlags.IndexMode, value);\r\n break;\r\n\r\n case 'LDY':\r\n reg.value['yIndex'] = this.calculateRegisterValue(reg.value['yIndex'], (reg.value['statusFlags'] & StatusFlags.IndexMode) === StatusFlags.IndexMode, value);\r\n break;\r\n\r\n case 'SEP':\r\n case 'REP':\r\n let statusFlags = reg.value['statusFlags'] ?? 0;\r\n if (mnemonic === 'SEP') {\r\n statusFlags |= value;\r\n } else {\r\n statusFlags &= ~value;\r\n }\r\n reg.value['statusFlags'] = statusFlags;\r\n break;\r\n }\r\n }\r\n\r\n private calculateRegisterValue(currentValue: number | undefined, flag: boolean, operand: number): number {\r\n if (flag) {\r\n // 16-bit mode: use full operand value\r\n return operand;\r\n } else {\r\n // 8-bit mode: preserve high byte\r\n return ((currentValue ?? 0) & 0xFF00) | (operand & 0xFF);\r\n }\r\n }\r\n\r\n private handleAbsoluteLongMode(mnemonic: string, operands: unknown[], reg: Registers): void {\r\n const refLoc = this._dataReader.readUShort();\r\n const bank = this._dataReader.readByte();\r\n const address = new Address(bank, refLoc, reg.mode);\r\n\r\n if (address.isROM) {\r\n const wrapper = new LocationWrapper(address.toLocation(), AddressType.Address);\r\n if (this.isJumpInstruction(mnemonic)) {\r\n this._blockReader.noteType(wrapper.location, 'Code', false, reg);\r\n }\r\n operands.push(wrapper);\r\n } else {\r\n operands.push(address);\r\n }\r\n }\r\n\r\n private handleBlockMoveMode(operands: unknown[], context: OperationContext): void {\r\n operands.push(new Byte(this._dataReader.readByte()));\r\n context.xForm2 = this._transformProcessor.getTransform();\r\n operands.push(new Byte(this._dataReader.readByte()));\r\n }\r\n\r\n private handleDirectPageMode(operands: unknown[]): void {\r\n operands.push(new Byte(this._dataReader.readByte()));\r\n }\r\n\r\n private handlePCRelativeMode(operands: unknown[], nextAddress: number, reg: Registers, isLong: boolean): void {\r\n const relative = isLong\r\n ? nextAddress + this._dataReader.readShort()\r\n : nextAddress + this._dataReader.readSByte();\r\n\r\n //this._blockReader.noteType(relative, 'Code', false, reg);\r\n this._blockReader.updateRegisterState(relative, reg);\r\n operands.push(new LocationWrapper(relative, isLong ? AddressType.WRelative : AddressType.Relative));\r\n }\r\n\r\n private handleStackRelativeMode(operands: unknown[]): void {\r\n operands.push(new Byte(this._dataReader.readByte()));\r\n }\r\n\r\n private handleStackInterruptMode(mnemonic: string, operands: unknown[], context: OperationContext): void {\r\n const cmd = this._dataReader.readByte();\r\n operands.push(new Byte(cmd));\r\n\r\n if (mnemonic === 'COP') {\r\n const copDef = this._blockReader._root.copDef[cmd];\r\n if (!copDef) {\r\n //throw new Error('Unknown COP command');\r\n return;\r\n }\r\n\r\n context.copDef = copDef;\r\n this._copProcessor.parseCopCommand(copDef, operands);\r\n }\r\n }\r\n\r\n private handleStackOrImpliedMode(mnemonic: string, reg: Registers): void {\r\n const stackOperations = new StackOperations(reg, this._blockReader);\r\n stackOperations.handleStackOperation(mnemonic);\r\n }\r\n\r\n private handleAbsoluteMode(\r\n mnemonic: string,\r\n xBank1: number | undefined,\r\n next: number,\r\n dataBank: number | undefined,\r\n operands: unknown[],\r\n registers: Registers,\r\n isIndexedIndirect: boolean = false\r\n ): void {\r\n let refLoc = this._dataReader.readUShort();\r\n\r\n const isPush = this.isPushInstruction(mnemonic);\r\n if (isPush) {\r\n refLoc++;\r\n }\r\n\r\n const isJump = isPush || isIndexedIndirect || this.isJumpInstruction(mnemonic);\r\n const resolvedBank = xBank1 ?? (isJump ? Address.resolveBank(this._dataReader.position, registers.mode) : dataBank) ?? 0x81;\r\n\r\n const addr = new Address(resolvedBank, refLoc, registers.mode);\r\n if (addr.isROM) {\r\n const wrapper = new LocationWrapper(addr.toLocation(), AddressType.Offset);\r\n if (isJump) {\r\n const type = isIndexedIndirect ? '&Code' : 'Code';\r\n const name = this._blockReader.noteType(wrapper.location, type, isPush, registers);\r\n\r\n if (isPush) {\r\n operands.push(`&${name}-1`);\r\n return;\r\n }\r\n }\r\n operands.push(wrapper);\r\n } else {\r\n operands.push(addr);\r\n }\r\n }\r\n\r\n private isJumpInstruction(mnemonic: string): boolean {\r\n return mnemonic[0] === 'J';\r\n }\r\n\r\n private isPushInstruction(mnemonic: string): boolean {\r\n return mnemonic[0] === 'P';\r\n }\r\n} ","import { RomDataReader } from './reader';\r\nimport { ReferenceManager } from './references';\r\nimport { RomProcessingConstants } from '../../types/constants';\r\nimport type { BlockReader } from './blocks';\r\nimport { Address, AddressType } from '../../types/addressing';\r\nimport { LocationWrapper } from '../..';\r\n\r\n/**\r\n * Handles transform processing for assembly instructions\r\n * Converted from GaiaLib/Rom/Extraction/TransformProcessor.cs\r\n */\r\nexport class TransformProcessor {\r\n private readonly _blockReader: BlockReader;\r\n private readonly _romDataReader: RomDataReader;\r\n private readonly _referenceManager: ReferenceManager;\r\n private readonly _labelLookup: Record<number, string>;\r\n\r\n // Location regex pattern: _([A-Fa-f0-9]{6})\r\n private static readonly LOCATION_REGEX = /_([A-Fa-f0-9]{6})/;\r\n\r\n constructor(romReader: BlockReader) {\r\n this._blockReader = romReader;\r\n this._romDataReader = romReader._romDataReader;\r\n this._referenceManager = romReader._referenceManager;\r\n this._labelLookup = romReader._root.labels;\r\n }\r\n\r\n /**\r\n * Retrieves transform information for the current ROM position\r\n */\r\n public getTransform(): string | null {\r\n const transform = this._labelLookup[this._romDataReader.position];\r\n if (transform === '') {\r\n return transform;\r\n } else if (!transform) {\r\n return null;\r\n }\r\n\r\n const transformName = this.cleanTransformName(transform);\r\n const referenceLocation = this.resolveTransformReference(transformName);\r\n \r\n if (referenceLocation !== null) {\r\n this._blockReader.resolveInclude(referenceLocation, false);\r\n }\r\n\r\n return transform;\r\n }\r\n\r\n /**\r\n * Applies transforms to operands\r\n */\r\n public applyTransforms(op1Label: string | null, op2Label: string | null, operands: unknown[]): void {\r\n this.applyTransform(op1Label, 0, operands);\r\n this.applyTransform(op2Label, 1, operands);\r\n }\r\n\r\n private applyTransform(transform: string | null, operandIndex: number, operands: unknown[]): void {\r\n if (transform === null || transform === undefined || operandIndex >= operands.length) {\r\n return;\r\n }\r\n\r\n // There is special logic for empty labels\r\n const hasBank = transform.startsWith('$');\r\n if (transform === '' || hasBank) {\r\n this.applyDefaultTransform(operandIndex, operands, hasBank ? parseInt(transform.substring(1), 16) : undefined);\r\n } else {\r\n operands[operandIndex] = transform; // Otherwise it is a direct replacement\r\n }\r\n }\r\n\r\n private applyDefaultTransform(operandIndex: number, operands: unknown[], bank?: number): void {\r\n const opnd = operands[operandIndex] as any;\r\n const resolvedBank = bank ?? Address.resolveBank(this._romDataReader.position, this._blockReader._root.config.memoryMode);\r\n const offset = opnd && 'value' in opnd ? opnd['value'] : opnd as number;\r\n const adrs = new Address(resolvedBank, offset, this._blockReader._root.config.memoryMode);\r\n const loc = adrs.toLocation();\r\n\r\n operands[operandIndex] = new LocationWrapper(loc, AddressType.Offset);\r\n return;\r\n\r\n // const nameResult = this._referenceManager.tryGetName(loc);\r\n // let referenceName: string;\r\n \r\n // if (!nameResult.found) {\r\n // referenceName = `loc_${loc.toString(16).toUpperCase().padStart(6, '0')}`;\r\n // this._referenceManager.tryAddName(loc, referenceName);\r\n // } else {\r\n // referenceName = nameResult.referenceName!;\r\n // }\r\n \r\n // this._blockReader.resolveInclude(loc, false);\r\n // operands[operandIndex] = `&${referenceName}`;\r\n }\r\n\r\n private cleanTransformName(transform: string): string {\r\n let name = transform;\r\n \r\n // Remove address space characters from the start\r\n while (name.length > 0 && RomProcessingConstants.ADDRESS_SPACE.includes(name[0])) {\r\n name = name.substring(1);\r\n }\r\n \r\n // Find math operators and truncate at that point\r\n let mathIndex = -1;\r\n for (let i = 0; i < name.length; i++) {\r\n if (RomProcessingConstants.OPERATORS.includes(name[i])) {\r\n mathIndex = i;\r\n break;\r\n }\r\n }\r\n \r\n if (mathIndex > 0) {\r\n name = name.substring(0, mathIndex);\r\n }\r\n \r\n return name;\r\n }\r\n\r\n private resolveTransformReference(transformName: string): number | null {\r\n // Directly resolve by name in the reference table\r\n const location = this._referenceManager.findLocationByName(transformName);\r\n if (location !== undefined) {\r\n return location;\r\n }\r\n\r\n // Fallback to parsing the location pattern\r\n const match = TransformProcessor.LOCATION_REGEX.exec(transformName);\r\n return match ? parseInt(match[1], 16) : null;\r\n }\r\n}","import type { DbPart } from './parts';\r\nimport { DbTransform } from './transforms';\r\n\r\n/**\r\n * Database block definition\r\n * Converted from GaiaLib/Database/DbBlock.cs\r\n */\r\nexport class DbBlock {\r\n public name: string;\r\n public movable: boolean;\r\n public group?: string;\r\n public scene?: string;\r\n public parts: DbPart[];\r\n public transforms?: DbTransform[];\r\n public postProcess?: string;\r\n public order?: number;\r\n //public id?: string;\r\n\r\n constructor(data: Partial<DbBlock>) {\r\n this.name = data.name ?? '';\r\n this.movable = data.movable ?? false;\r\n this.group = data.group ?? undefined;\r\n this.scene = data.scene ?? undefined;\r\n this.parts = (data.parts ?? []).sort((a, b) => {\r\n const orderA = a.order ?? 0;\r\n const orderB = b.order ?? 0;\r\n if (orderA !== orderB) {\r\n return orderA - orderB;\r\n }\r\n return a.start - b.start;\r\n });\r\n this.transforms = data.transforms ?? [];\r\n this.postProcess = data.postProcess ?? undefined;\r\n this.order = data.order ?? undefined;\r\n //this.id = data.id ?? undefined;\r\n\r\n\r\n if(!this.name) throw new Error('Name is required');\r\n }\r\n}\r\n","import { BinType } from '../types/resources';\r\n\r\nexport class DbFile {\r\n //public id?: string;\r\n public name: string;\r\n public type: string;\r\n public start: number;\r\n public end: number;\r\n public compressed?: boolean;\r\n public upper?: boolean;\r\n public group?: string;\r\n public scene?: string;\r\n\r\n constructor(data: Partial<DbFile>) {\r\n if(!data.name) throw new Error('Name is required');\r\n if(!data.type) throw new Error('Type is required');\r\n if(typeof data.start !== 'number') throw new Error('Start is required');\r\n if(typeof data.end !== 'number') throw new Error('End is required');\r\n\r\n this.name = data.name;\r\n this.type = data.type;\r\n this.start = data.start;\r\n this.end = data.end;\r\n this.compressed = data.compressed ?? undefined;\r\n this.upper = data.upper ?? undefined;\r\n this.group = data.group || undefined;\r\n this.scene = data.scene || undefined;\r\n }\r\n} \r\n\r\nexport class DbFileType {\r\n public name: string;\r\n public extension: string;\r\n public type: string;\r\n public isPatch: boolean;\r\n public isBlock: boolean;\r\n public header: number;\r\n public compressed?: boolean;\r\n\r\n constructor(data: Partial<DbFileType>) {\r\n this.name = data.name ?? '';\r\n this.extension = data.extension ?? '';\r\n this.type = data.type ?? '';\r\n this.isPatch = data.isPatch ?? false;\r\n this.isBlock = data.isBlock ?? false;\r\n this.header = data.header ?? 0;\r\n this.compressed = data.compressed ?? undefined;\r\n \r\n if(!this.name) throw new Error('Name is required');\r\n if(!this.extension) throw new Error('Extension is required');\r\n if(!this.type) throw new Error('Type is required');\r\n }\r\n}","/**\r\n * Database structure definition\r\n * Converted from GaiaLib/Database/DbStruct.cs\r\n */\r\nexport class DbStruct {\r\n public name: string;\r\n public types?: string[];\r\n public parent?: string;\r\n public delimiter?: number;\r\n public discriminator?: number;\r\n\r\n constructor(data: Partial<DbStruct>) {\r\n this.name = data.name ?? '';\r\n this.types = data.types ?? undefined;\r\n this.parent = data.parent ?? undefined;\r\n this.delimiter = data.delimiter ?? undefined;\r\n this.discriminator = data.discriminator ?? undefined;\r\n\r\n if(!this.name) throw new Error('Name is required');\r\n }\r\n} ","\r\nexport class DbAddressingMode {\r\n public name: string;\r\n public shorthand: string;\r\n public operands: string[];\r\n public size: number;\r\n public formatString?: string;\r\n public parseRegex?: string;\r\n public instructions: Record<string, number>;\r\n\r\n constructor(data: Partial<DbAddressingMode>) {\r\n if(!data.name) throw new Error('Addressing mode name is required');\r\n if(!data.shorthand) throw new Error('Addressing mode shorthand is required');\r\n if(!data.instructions) throw new Error('Addressing mode instructions are required');\r\n if(!data.size) throw new Error('Addressing mode size is required');\r\n\r\n this.name = data.name;\r\n this.shorthand = data.shorthand;\r\n this.operands = data.operands ?? [];\r\n this.size = data.size ?? 1;\r\n this.formatString = data.formatString ?? undefined;\r\n this.parseRegex = data.parseRegex ?? undefined;\r\n this.instructions = data.instructions;\r\n }\r\n}\r\n","import { MemberType } from '../types/members';\r\n\r\n/**\r\n * Database string command definition\r\n * Converted from GaiaLib/Database/DbStringCommand.cs\r\n */\r\nexport class DbStringCommand {\r\n public id: number;\r\n public name: string;\r\n public types: string[];\r\n public delimiter?: number;\r\n public halt: boolean;\r\n public dictionary?: DbStringDictionary;\r\n\r\n constructor(data: Partial<DbStringCommand>) {\r\n if(typeof data.id !== 'number') throw new Error('Id is required');\r\n if(!data.name) throw new Error('Name is required');\r\n\r\n this.id = data.id;\r\n this.name = data.name;\r\n this.types = data.types ?? [];\r\n this.delimiter = data.delimiter ?? undefined;\r\n this.halt = data.halt ?? false;\r\n this.dictionary = data.dictionary ?? undefined;\r\n }\r\n}\r\n\r\n/**\r\n * Database string layer definition\r\n * Converted from GaiaLib/Database/DbStringLayer.cs\r\n */\r\nexport interface DbStringLayer {\r\n base?: number;\r\n range?: number;\r\n on?: number;\r\n shift?: string;\r\n map: string[];\r\n}\r\n\r\nexport class DbStringDictionary {\r\n public base?: number;\r\n public range: number;\r\n public command?: number;\r\n public name: string;\r\n //public suffix: string;\r\n public entries: string[];\r\n\r\n constructor(data: Partial<DbStringDictionary>) {\r\n if(typeof data.base !== 'number' && typeof data.command !== 'number') throw new Error('Base or command is required');\r\n if(!data.name) throw new Error('Name is required');\r\n if(!data.entries || data.entries.length === 0) throw new Error('Entries is required');\r\n\r\n this.base = data.base ?? undefined;\r\n this.range = data.range ?? 0;\r\n this.command = data.command ?? undefined;\r\n this.name = data.name;\r\n this.entries = data.entries;\r\n //this.suffix = data.suffix ?? '';\r\n\r\n if(this.base !== undefined) this.range = this.base + this.entries.length;\r\n }\r\n}\r\n\r\n/**\r\n * Database string type definition\r\n * Converted from GaiaLib/Database/DbStringType.cs\r\n */\r\nexport class DbStringType {\r\n public name: string;\r\n public delimiter: string;\r\n public terminator: number;\r\n public commands: Record<string, DbStringCommand>;\r\n public commandLookup: Record<number, DbStringCommand>;\r\n public layers: DbStringLayer[];\r\n public greedyTerminator: boolean;\r\n public dictionaries: Record<string, DbStringDictionary>;\r\n public dictionaryLookup: { text: string, id: number }[];\r\n\r\n constructor(data: Partial<DbStringType>) {\r\n if(!data.name) throw new Error('Name is required');\r\n if(!data.delimiter) throw new Error('Delimiter is required');\r\n if(typeof data.terminator !== 'number') throw new Error('Terminator is required');\r\n if(!data.layers || !data.layers.length) throw new Error('Layers are required');\r\n\r\n this.name = data.name;\r\n this.delimiter = data.delimiter;\r\n this.terminator = data.terminator;\r\n this.commands = data.commands ?? {};\r\n this.layers = data.layers;\r\n this.greedyTerminator = data.greedyTerminator ?? false;\r\n this.dictionaries = data.dictionaries ?? {};\r\n this.commandLookup = Object.values(this.commands).reduce((acc, x) => {\r\n acc[x.id] = x;\r\n return acc;\r\n }, {} as Record<number, DbStringCommand>);\r\n this.dictionaryLookup = Object.values(this.dictionaries)\r\n .flatMap((y) => y.entries.map((z, ix) => ({ text: z, id: ((y.command ?? 0) << 8) | (y.base ?? 0 + ix) })))\r\n //.map((y, z) => ({ text: y.entries[z], id: (y.command << 8) | (y.base + z) }))\r\n .sort((a, b) => b.text.length - a.text.length);\r\n }\r\n}\r\n\r\n/**\r\n * String type utilities\r\n */\r\nexport class DbStringTypeUtils {\r\n // Shift functions (simplified versions of C# implementation)\r\n private static readonly shiftDownFunctions: Record<string, (x: number) => number> = {\r\n '': (x) => x,\r\n 'h2': (x) => (((x & 0xE0) >> 1) | (x & 0x0F)),\r\n 'wh2': (x) => (((x & 0x70) >> 1) | (x & 0x07))\r\n };\r\n\r\n private static readonly shiftUpFunctions: Record<string, (x: number) => number> = {\r\n '': (x) => x,\r\n 'h2': (x) => (((x & 0x70) << 1) | (x & 0x0F)),\r\n 'wh2': (x) => (((x & 0x38) << 1) | (x & 0x07))\r\n };\r\n\r\n public static getShiftDown(shiftType?: string): (x: number) => number {\r\n return this.shiftDownFunctions[shiftType || ''] || this.shiftDownFunctions[''];\r\n }\r\n\r\n public static getShiftUp(shiftType?: string): (x: number) => number {\r\n return this.shiftUpFunctions[shiftType || ''] || this.shiftUpFunctions[''];\r\n }\r\n} ","\r\n/**\r\n * COP instruction definition\r\n * Converted from GaiaLib/Database/CopDef.cs\r\n */\r\nexport class CopDef {\r\n public id: number;\r\n public name: string;\r\n public size: number;\r\n public parts: string[];\r\n public halt: boolean;\r\n\r\n constructor(data: Partial<CopDef>) {\r\n if(!data.name) throw new Error('Name is required');\r\n if(typeof data.id !== 'number') throw new Error('ID is required');\r\n\r\n this.name = data.name;\r\n this.id = data.id;\r\n this.parts = data.parts ?? [];\r\n this.halt = data.halt ?? false;\r\n this.size = data.size ?? 0;\r\n }\r\n}\r\n","/**\r\n * Universal file reading utilities\r\n * Works in both Node.js and browser environments\r\n */\r\n\r\n// Platform detection\r\nconst isNode = typeof process !== 'undefined' && process.versions?.node;\r\n// const isBrowser = typeof globalThis !== 'undefined' && 'window' in globalThis;\r\n\r\nexport interface FileReadOptions {\r\n encoding?: 'utf8' | 'binary';\r\n}\r\n\r\n/**\r\n * Read a file as text\r\n * @param path File path or URL\r\n * @param options Read options\r\n * @returns Promise<string>\r\n */\r\nexport async function readFileAsText(path: string, options: FileReadOptions = {}): Promise<string> {\r\n const { encoding = 'utf8' } = options;\r\n \r\n if (isNode) {\r\n // Node.js environment\r\n const { readFile } = await import('fs/promises');\r\n const pathModule = await import('path');\r\n \r\n const fullPath = pathModule.resolve(path);\r\n \r\n try {\r\n let text = await readFile(fullPath, { encoding });\r\n \r\n // Strip UTF-8 BOM if present\r\n if (text.charCodeAt(0) === 0xFEFF) {\r\n text = text.slice(1);\r\n }\r\n \r\n return text;\r\n } catch (error: any) {\r\n if (error.code === 'ENOENT') {\r\n throw new Error(`File not found: ${fullPath}`);\r\n }\r\n throw error;\r\n }\r\n } else {\r\n // Browser environment\r\n const response = await fetch(path);\r\n if (!response.ok) {\r\n throw new Error(`Failed to fetch file: ${path} (${response.status})`);\r\n }\r\n \r\n let text = await response.text();\r\n \r\n // Strip UTF-8 BOM if present\r\n if (text.charCodeAt(0) === 0xFEFF) {\r\n text = text.slice(1);\r\n }\r\n \r\n return text;\r\n }\r\n}\r\n\r\n/**\r\n * Read a file as binary data (Uint8Array)\r\n * @param path File path or URL\r\n * @returns Promise<Uint8Array>\r\n */\r\nexport async function readFileAsBinary(path: string): Promise<Uint8Array> {\r\n if (isNode) {\r\n // Node.js environment\r\n const { readFile } = await import('fs/promises');\r\n const pathModule = await import('path');\r\n \r\n const fullPath = pathModule.resolve(path);\r\n\r\n try {\r\n const buffer = await readFile(fullPath);\r\n return new Uint8Array(buffer);\r\n } catch (error: any) {\r\n if (error.code === 'ENOENT') {\r\n throw new Error(`File not found: ${fullPath}`);\r\n }\r\n throw error;\r\n }\r\n } else {\r\n // Browser environment\r\n const response = await fetch(path);\r\n if (!response.ok) {\r\n throw new Error(`Failed to fetch file: ${path} (${response.status})`);\r\n }\r\n \r\n const arrayBuffer = await response.arrayBuffer();\r\n return new Uint8Array(arrayBuffer);\r\n }\r\n}\r\n\r\n/**\r\n * Read a JSON file and parse it\r\n * @param path File path or URL\r\n * @returns Promise<any>\r\n */\r\nexport async function readJsonFile<T = any>(path: string): Promise<T> {\r\n const text = await readFileAsText(path);\r\n return JSON.parse(text) as T;\r\n}\r\n\r\n/**\r\n * Check if a file exists\r\n * @param path File path\r\n * @returns Promise<boolean>\r\n */\r\nexport async function fileExists(path: string): Promise<boolean> {\r\n if (isNode) {\r\n // Node.js environment\r\n const { access } = await import('fs/promises');\r\n const pathModule = await import('path');\r\n \r\n const fullPath = pathModule.resolve(path);\r\n try {\r\n await access(fullPath);\r\n return true;\r\n } catch {\r\n return false;\r\n }\r\n } else {\r\n // Browser environment - try to fetch and check if successful\r\n try {\r\n const response = await fetch(path, { method: 'HEAD' });\r\n return response.ok;\r\n } catch {\r\n return false;\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Get the directory path containing a file\r\n * @param filePath File path\r\n * @returns string\r\n */\r\nexport async function getDirectory(filePath: string): Promise<string> {\r\n if (isNode) {\r\n // Node.js environment\r\n const path = await import('path');\r\n return path.dirname(path.resolve(filePath));\r\n } else {\r\n // Browser environment\r\n const url = new URL(filePath, (globalThis as any).location.href);\r\n return url.pathname.split('/').slice(0, -1).join('/') || './';\r\n }\r\n}\r\n\r\n/**\r\n * Create a temporary directory.\r\n * This is a Node.js-specific operation.\r\n * @param prefix Prefix for the temporary directory name.\r\n * @returns Promise<string> Path to the created temporary directory.\r\n */\r\nexport async function createTempDirectory(prefix: string): Promise<string> {\r\n if (isNode) {\r\n const { mkdtemp } = await import('fs/promises');\r\n const { tmpdir } = await import('os');\r\n const { join } = await import('path');\r\n return mkdtemp(join(tmpdir(), prefix));\r\n } else {\r\n throw new Error('createTempDirectory is not supported in the browser environment.');\r\n }\r\n}\r\n\r\n/**\r\n * Remove a directory recursively.\r\n * This is a Node.js-specific operation.\r\n * @param dirPath Path to the directory to remove.\r\n * @returns Promise<void>\r\n */\r\nexport async function removeDirectory(dirPath: string): Promise<void> {\r\n if (isNode) {\r\n const { rm } = await import('fs/promises');\r\n return rm(dirPath, { recursive: true, force: true });\r\n } else {\r\n throw new Error('removeDirectory is not supported in the browser environment.');\r\n }\r\n}\r\n\r\nexport interface DirectoryEntry {\r\n name: string;\r\n path: string;\r\n extension: string | null;\r\n isDirectory: boolean;\r\n isFile: boolean;\r\n}\r\n\r\n/**\r\n * List directory contents\r\n * This is a Node.js-specific operation.\r\n * @param dirPath Path to the directory to list\r\n * @param options Options for filtering and recursion\r\n * @returns Promise<DirectoryEntry[]>\r\n */\r\nexport async function listDirectory(\r\n dirPath: string,\r\n options: {\r\n recursive?: boolean;\r\n filter?: (entry: DirectoryEntry) => boolean;\r\n extension?: string;\r\n } = {}\r\n): Promise<DirectoryEntry[]> {\r\n if (isNode) {\r\n const { readdir, stat } = await import('fs/promises');\r\n const pathModule = await import('path');\r\n\r\n const { recursive = false, filter, extension } = options;\r\n const fullPath = pathModule.resolve(dirPath);\r\n\r\n try {\r\n const entries: DirectoryEntry[] = [];\r\n const items = await readdir(fullPath);\r\n\r\n for (const item of items) {\r\n const itemPath = pathModule.join(fullPath, item);\r\n const stats = await stat(itemPath);\r\n const isFile = stats.isFile();\r\n const extIx = isFile ? item.indexOf('.') : -1;\r\n const ext = extIx > 0 ? item.substring(extIx + 1) : null;\r\n const name = extIx > 0 ? item.substring(0, extIx) : item;\r\n\r\n const entry: DirectoryEntry = {\r\n name: name,\r\n path: itemPath,\r\n extension: ext,\r\n isFile: isFile,\r\n isDirectory: stats.isDirectory()\r\n };\r\n\r\n // Apply extension filter\r\n if (extension && ext !== extension) {\r\n continue;\r\n }\r\n\r\n // Apply custom filter\r\n if (filter && !filter(entry)) {\r\n continue;\r\n }\r\n\r\n entries.push(entry);\r\n\r\n // Recurse into subdirectories if requested\r\n if (recursive && entry.isDirectory) {\r\n const subEntries = await listDirectory(itemPath, options);\r\n entries.push(...subEntries);\r\n }\r\n }\r\n\r\n return entries;\r\n } catch (error: any) {\r\n if (error.code === 'ENOENT') {\r\n throw new Error(`Directory not found: ${fullPath}`);\r\n }\r\n throw error;\r\n }\r\n } else {\r\n throw new Error('listDirectory is not supported in the browser environment.');\r\n }\r\n}\r\n\r\n/**\r\n * Save text content to a file\r\n * This is a Node.js-specific operation.\r\n * @param path File path where to save the content\r\n * @param text Text content to save\r\n * @returns Promise<void>\r\n */\r\nexport async function saveFileAsText(path: string, text: string): Promise<void> {\r\n if (isNode) {\r\n const { writeFile, mkdir } = await import('fs/promises');\r\n const pathModule = await import('path');\r\n\r\n const fullPath = pathModule.resolve(path);\r\n const dirPath = pathModule.dirname(fullPath);\r\n\r\n try {\r\n // Ensure parent directories exist\r\n await mkdir(dirPath, { recursive: true });\r\n\r\n // Write the file with UTF-8 encoding\r\n await writeFile(fullPath, text, { encoding: 'utf8' });\r\n } catch (error: any) {\r\n throw new Error(`Failed to save file: ${fullPath} - ${error.message}`);\r\n }\r\n } else {\r\n throw new Error('saveFileAsText is not supported in the browser environment.');\r\n }\r\n}\r\n\r\n/**\r\n * Save binary data to a file\r\n * This is a Node.js-specific operation.\r\n * @param path File path where to save the data\r\n * @param data Binary data as Uint8Array to save\r\n * @returns Promise<void>\r\n */\r\nexport async function saveFileAsBinary(path: string, data: Uint8Array): Promise<void> {\r\n if (isNode) {\r\n const { writeFile, mkdir } = await import('fs/promises');\r\n const pathModule = await import('path');\r\n\r\n const fullPath = pathModule.resolve(path);\r\n const dirPath = pathModule.dirname(fullPath);\r\n\r\n try {\r\n // Ensure parent directories exist\r\n await mkdir(dirPath, { recursive: true });\r\n\r\n // Write the binary data directly\r\n await writeFile(fullPath, data);\r\n } catch (error: any) {\r\n throw new Error(`Failed to save file: ${fullPath} - ${error.message}`);\r\n }\r\n } else {\r\n throw new Error('saveFileAsBinary is not supported in the browser environment.');\r\n }\r\n}","\r\nconst polynomial = 0x04C11DB7;\r\n\r\nfunction crc32_reverse(polynomial: number) {\r\n var reversedPolynomial = 0\r\n\r\n for (let i = 0; i < 32; i++) {\r\n reversedPolynomial = reversedPolynomial << 1\r\n reversedPolynomial = reversedPolynomial | ((polynomial >>> i) & 1)\r\n }\r\n\r\n return reversedPolynomial\r\n}\r\n\r\nconst reversedPolynomial = crc32_reverse(polynomial);\r\n\r\nfunction crc32_generate() {\r\n var table = new Array()\r\n var i, j, n\r\n\r\n for (i = 0; i < 256; i++) {\r\n n = i\r\n for (j = 8; j > 0; j--) {\r\n if ((n & 1) == 1) {\r\n n = (n >>> 1) ^ reversedPolynomial\r\n } else {\r\n n = n >>> 1\r\n }\r\n }\r\n table[i] = n\r\n }\r\n\r\n return table\r\n}\r\n\r\nfunction crc32_initial() {\r\n return 0xFFFFFFFF\r\n}\r\n\r\nfunction crc32_add_byte(table: number[], crc: number, byte: number) {\r\n crc = (crc >>> 8) ^ table[(byte) ^ (crc & 0x000000FF)]\r\n return crc\r\n}\r\n\r\nfunction crc32_final(crc: number) {\r\n crc = ~crc\r\n crc = (crc < 0) ? (0xFFFFFFFF + crc + 1) : crc\r\n return crc & 0xFFFFFFFF;\r\n}\r\n\r\n// Deprecated\r\n// export function crc32_string(str: string) {\r\n// var table = crc32_generate()\r\n// var crc = crc32_initial()\r\n\r\n// for (let i = 0; i < str.length; i++)\r\n// crc = crc32_add_byte(table, crc, str.charCodeAt(i))\r\n\r\n// crc = crc32_final(crc)\r\n// return crc\r\n// }\r\n\r\nexport function crc32_buffer(data: Uint8Array) {\r\n var table = crc32_generate()\r\n var crc = crc32_initial()\r\n\r\n for (let i = 0; i < data.length; i++)\r\n crc = crc32_add_byte(table, crc, data[i])\r\n\r\n crc = crc32_final(crc)\r\n return crc\r\n}\r\n\r\nexport function crc32_text_utf8(text: string): number {\r\n const utf8Bytes = new TextEncoder().encode(text);\r\n return crc32_buffer(utf8Bytes);\r\n}\r\n\r\nexport function crc32_text_utf16(text: string): number {\r\n const utf16Bytes = new Uint8Array(text.length * 2);\r\n for (let i = 0; i < text.length; i++) {\r\n const code = text.charCodeAt(i);\r\n utf16Bytes[i * 2] = code & 0xFF;\r\n utf16Bytes[i * 2 + 1] = (code >> 8) & 0xFF;\r\n }\r\n return crc32_buffer(utf16Bytes);\r\n}\r\n","/**\n * Base64 encoding and decoding utilities for Uint8Arrays\n * Works in both Node.js and browser environments\n */\n\n// Platform detection\nconst isNode = typeof process !== 'undefined' && process.versions?.node;\n\n// Base64 character set\nconst BASE64_CHARS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';\n\n// Create lookup table for decoding\nconst BASE64_LOOKUP: { [key: string]: number } = {};\nfor (let i = 0; i < BASE64_CHARS.length; i++) {\n BASE64_LOOKUP[BASE64_CHARS[i]] = i;\n}\n\n/**\n * Custom base64 encoding implementation that handles large data without call stack overflow\n * @param data The binary data to encode\n * @returns Base64 encoded string\n */\nfunction customBase64Encode(data: Uint8Array): string {\n let result = '';\n let i = 0;\n\n // Process 3 bytes at a time\n while (i < data.length) {\n const byte1 = data[i++];\n const byte2 = i < data.length ? data[i++] : 0;\n const byte3 = i < data.length ? data[i++] : 0;\n\n // Convert 3 bytes to 4 base64 characters\n const bitmap = (byte1 << 16) | (byte2 << 8) | byte3;\n\n result += BASE64_CHARS[(bitmap >> 18) & 63];\n result += BASE64_CHARS[(bitmap >> 12) & 63];\n result += BASE64_CHARS[(bitmap >> 6) & 63];\n result += BASE64_CHARS[bitmap & 63];\n }\n\n // Add padding if necessary\n const padding = data.length % 3;\n if (padding === 1) {\n result = result.slice(0, -2) + '==';\n } else if (padding === 2) {\n result = result.slice(0, -1) + '=';\n }\n\n return result;\n}\n\n/**\n * Custom base64 decoding implementation that handles large data without call stack overflow\n * @param base64String The base64 string to decode\n * @returns Decoded binary data as Uint8Array\n * @throws {Error} If the input contains invalid base64 characters\n */\nfunction customBase64Decode(base64String: string): Uint8Array {\n // Remove padding for calculation\n const cleanString = base64String.replace(/=/g, '');\n const outputLength = Math.floor((cleanString.length * 3) / 4);\n const result = new Uint8Array(outputLength);\n\n let resultIndex = 0;\n let i = 0;\n\n // Process 4 characters at a time\n while (i < cleanString.length) {\n const char1 = cleanString[i++];\n const char2 = i < cleanString.length ? cleanString[i++] : 'A';\n const char3 = i < cleanString.length ? cleanString[i++] : 'A';\n const char4 = i < cleanString.length ? cleanString[i++] : 'A';\n\n // Validate characters\n if (!(char1 in BASE64_LOOKUP) || !(char2 in BASE64_LOOKUP) ||\n !(char3 in BASE64_LOOKUP) || !(char4 in BASE64_LOOKUP)) {\n throw new Error('Invalid base64 character encountered');\n }\n\n // Convert 4 base64 characters to 3 bytes\n const bitmap = (BASE64_LOOKUP[char1] << 18) |\n (BASE64_LOOKUP[char2] << 12) |\n (BASE64_LOOKUP[char3] << 6) |\n BASE64_LOOKUP[char4];\n\n if (resultIndex < result.length) {\n result[resultIndex++] = (bitmap >> 16) & 255;\n }\n if (resultIndex < result.length) {\n result[resultIndex++] = (bitmap >> 8) & 255;\n }\n if (resultIndex < result.length) {\n result[resultIndex++] = bitmap & 255;\n }\n }\n\n return result;\n}\n\n/**\n * Encode a Uint8Array to a base64 string\n * @param data The binary data to encode\n * @returns Base64 encoded string\n */\nexport function encodeBase64(data: Uint8Array): string {\n if (!data || data.length === 0) {\n return '';\n }\n\n if (isNode) {\n // Node.js environment - use Buffer\n return Buffer.from(data).toString('base64');\n } else {\n // Browser environment - custom base64 encoding implementation\n return customBase64Encode(data);\n }\n}\n\n/**\n * Decode a base64 string to a Uint8Array\n * @param base64String The base64 string to decode\n * @returns Decoded binary data as Uint8Array\n * @throws {Error} If the input is not a valid base64 string\n */\nexport function decodeBase64(base64String: string): Uint8Array {\n if (!base64String || base64String.length === 0) {\n return new Uint8Array(0);\n }\n\n // Validate base64 format\n if (!/^[A-Za-z0-9+/]*={0,2}$/.test(base64String)) {\n throw new Error('Invalid base64 string format');\n }\n\n if (isNode) {\n // Node.js environment - use Buffer\n try {\n const buffer = Buffer.from(base64String, 'base64');\n return new Uint8Array(buffer);\n } catch (error) {\n throw new Error(`Failed to decode base64 string: ${error instanceof Error ? error.message : 'Unknown error'}`);\n }\n } else {\n // Browser environment - custom base64 decoding implementation\n try {\n return customBase64Decode(base64String);\n } catch (error) {\n throw new Error(`Failed to decode base64 string: ${error instanceof Error ? error.message : 'Unknown error'}`);\n }\n }\n}\n\n/**\n * Check if a string is valid base64\n * @param str The string to validate\n * @returns True if the string is valid base64, false otherwise\n */\nexport function isValidBase64(str: string): boolean {\n if (typeof str !== 'string') {\n return false;\n }\n\n // Empty string is valid base64\n if (str === '') {\n return true;\n }\n\n // Check format with regex\n if (!/^[A-Za-z0-9+/]*={0,2}$/.test(str)) {\n return false;\n }\n\n // Check length (must be multiple of 4)\n if (str.length % 4 !== 0) {\n return false;\n }\n\n try {\n // Try to decode to verify it's actually valid\n decodeBase64(str);\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Encode a string to base64 (convenience function)\n * @param text The text string to encode\n * @returns Base64 encoded string\n */\nexport function encodeBase64String(text: string): string {\n const encoder = new TextEncoder();\n const data = encoder.encode(text);\n return encodeBase64(data);\n}\n\n/**\n * Decode a base64 string to text (convenience function)\n * @param base64String The base64 string to decode\n * @returns Decoded text string\n * @throws {Error} If the input is not a valid base64 string or doesn't contain valid UTF-8\n */\nexport function decodeBase64String(base64String: string): string {\n const data = decodeBase64(base64String);\n const decoder = new TextDecoder('utf-8', { fatal: true });\n \n try {\n return decoder.decode(data);\n } catch (error) {\n throw new Error(`Failed to decode base64 string as UTF-8 text: ${error instanceof Error ? error.message : 'Unknown error'}`);\n }\n}\n","// Utility functions and helpers\r\n\r\n// File utilities\r\nexport * from './file';\r\nexport * from './crc';\r\nexport * from './base64';\r\n\r\n/**\r\n * Convert bytes to hex string\r\n */\r\nexport function bytesToHex(bytes: Uint8Array): string {\r\n return Array.from(bytes, byte => byte.toString(16).padStart(2, '0')).join('');\r\n}\r\n\r\n/**\r\n * Convert hex string to bytes\r\n */\r\nexport function hexToBytes(hex: string): Uint8Array {\r\n const bytes = new Uint8Array(hex.length / 2);\r\n for (let i = 0; i < hex.length; i += 2) {\r\n bytes[i / 2] = parseInt(hex.substring(i, i + 2), 16);\r\n }\r\n return bytes;\r\n}\r\n\r\n/**\r\n * Clamp a value between min and max\r\n */\r\nexport function clamp(value: number, min: number, max: number): number {\r\n return Math.min(Math.max(value, min), max);\r\n}\r\n\r\n/**\r\n * Convert binary data (Uint8Array) to UTF-8 string representation\r\n *\r\n * This function properly decodes UTF-8 encoded binary data to avoid corruption\r\n * of special characters and multi-byte sequences.\r\n *\r\n * @param binaryData - The binary data as Uint8Array containing UTF-8 encoded text\r\n * @returns The decoded UTF-8 string\r\n * @throws {Error} If the binary data contains invalid UTF-8 sequences\r\n *\r\n * @example\r\n * ```typescript\r\n * const binaryData = new Uint8Array([72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100]);\r\n * const text = binaryToUtf8String(binaryData);\r\n * console.log(text); // \"Hello World\"\r\n *\r\n * // Handle UTF-8 multi-byte characters\r\n * const utf8Data = new Uint8Array([240, 159, 152, 128]); // 😀 emoji\r\n * const emoji = binaryToUtf8String(utf8Data);\r\n * console.log(emoji); // \"😀\"\r\n * ```\r\n */\r\nexport function binaryToUtf8String(binaryData: Uint8Array): string {\r\n if (!binaryData || binaryData.length === 0) {\r\n return '';\r\n }\r\n\r\n try {\r\n // Use TextDecoder for proper UTF-8 decoding with error handling\r\n if (typeof TextDecoder !== 'undefined') {\r\n const decoder = new TextDecoder('utf-8', { fatal: true });\r\n return decoder.decode(binaryData);\r\n }\r\n\r\n // Node.js fallback using Buffer\r\n if (typeof Buffer !== 'undefined') {\r\n return Buffer.from(binaryData).toString('utf8');\r\n }\r\n\r\n // Manual UTF-8 decoding fallback (less robust but works in all environments)\r\n let result = '';\r\n let i = 0;\r\n\r\n while (i < binaryData.length) {\r\n let byte1 = binaryData[i++];\r\n\r\n // Single-byte character (ASCII)\r\n if (byte1 < 0x80) {\r\n result += String.fromCharCode(byte1);\r\n }\r\n // Two-byte character\r\n else if ((byte1 & 0xE0) === 0xC0) {\r\n if (i >= binaryData.length) {\r\n throw new Error(`Invalid UTF-8 sequence: incomplete two-byte character at position ${i - 1}`);\r\n }\r\n const byte2 = binaryData[i++];\r\n if ((byte2 & 0xC0) !== 0x80) {\r\n throw new Error(`Invalid UTF-8 sequence: invalid continuation byte at position ${i - 1}`);\r\n }\r\n const codePoint = ((byte1 & 0x1F) << 6) | (byte2 & 0x3F);\r\n result += String.fromCharCode(codePoint);\r\n }\r\n // Three-byte character\r\n else if ((byte1 & 0xF0) === 0xE0) {\r\n if (i + 1 >= binaryData.length) {\r\n throw new Error(`Invalid UTF-8 sequence: incomplete three-byte character at position ${i - 1}`);\r\n }\r\n const byte2 = binaryData[i++];\r\n const byte3 = binaryData[i++];\r\n if ((byte2 & 0xC0) !== 0x80 || (byte3 & 0xC0) !== 0x80) {\r\n throw new Error(`Invalid UTF-8 sequence: invalid continuation bytes at position ${i - 2}`);\r\n }\r\n const codePoint = ((byte1 & 0x0F) << 12) | ((byte2 & 0x3F) << 6) | (byte3 & 0x3F);\r\n result += String.fromCharCode(codePoint);\r\n }\r\n // Four-byte character\r\n else if ((byte1 & 0xF8) === 0xF0) {\r\n if (i + 2 >= binaryData.length) {\r\n throw new Error(`Invalid UTF-8 sequence: incomplete four-byte character at position ${i - 1}`);\r\n }\r\n const byte2 = binaryData[i++];\r\n const byte3 = binaryData[i++];\r\n const byte4 = binaryData[i++];\r\n if ((byte2 & 0xC0) !== 0x80 || (byte3 & 0xC0) !== 0x80 || (byte4 & 0xC0) !== 0x80) {\r\n throw new Error(`Invalid UTF-8 sequence: invalid continuation bytes at position ${i - 3}`);\r\n }\r\n const codePoint = ((byte1 & 0x07) << 18) | ((byte2 & 0x3F) << 12) | ((byte3 & 0x3F) << 6) | (byte4 & 0x3F);\r\n // Use surrogate pairs for code points > 0xFFFF\r\n if (codePoint > 0xFFFF) {\r\n const surrogate1 = 0xD800 + ((codePoint - 0x10000) >> 10);\r\n const surrogate2 = 0xDC00 + ((codePoint - 0x10000) & 0x3FF);\r\n result += String.fromCharCode(surrogate1, surrogate2);\r\n } else {\r\n result += String.fromCharCode(codePoint);\r\n }\r\n }\r\n // Invalid UTF-8 start byte\r\n else {\r\n throw new Error(`Invalid UTF-8 sequence: invalid start byte 0x${byte1.toString(16)} at position ${i - 1}`);\r\n }\r\n }\r\n\r\n return result;\r\n } catch (error) {\r\n throw new Error(`Failed to decode UTF-8 binary data: ${error instanceof Error ? error.message : 'Unknown error'}`);\r\n }\r\n}\r\n\r\n/**\r\n * Safely get nested object property\r\n */\r\nexport function getNestedProperty(obj: any, path: string): any {\r\n return path.split('.').reduce((current, key) => current?.[key], obj);\r\n}\r\n\r\n\r\nexport function indexOfAny(str: string, chars: string[], startIndex = 0): number {\r\n for (let i = startIndex; i < str.length; i++) {\r\n if (chars.includes(str[i])) {\r\n return i;\r\n }\r\n }\r\n return -1;\r\n}\r\n\r\n","\r\n/**\r\n * Database part definition\r\n * Converted from GaiaLib/Database/DbPart.cs\r\n */\r\nexport class DbPart {\r\n public name: string;\r\n public start: number;\r\n public end: number;\r\n public type: string;\r\n public bank?: number;\r\n public order?: number;\r\n\r\n constructor(data: Partial<DbPart>) {\r\n if(typeof data.start !== 'number') throw new Error('Start is required');\r\n if(!data.name) throw new Error('Name is required');\r\n if(!data.end) throw new Error('End is required');\r\n if(!data.type) throw new Error('Struct is required');\r\n\r\n this.name = data.name;\r\n this.start = data.start;\r\n this.end = data.end;\r\n this.type = data.type;\r\n this.bank = data.bank ?? undefined;\r\n this.order = data.order ?? undefined;\r\n\r\n }\r\n}\r\n","\r\nexport class DbTransform {\r\n key: string; \r\n value: string;\r\n\r\n constructor(data: Partial<DbTransform>) {\r\n this.key = data.key ?? '';\r\n this.value = data.value ?? '';\r\n\r\n if(!this.key) throw new Error('Key is required');\r\n }\r\n} ","import { DbAsset } from \"./assets\";\r\n\r\nexport class DbScene {\r\n public name: string;\r\n public id: number;\r\n public description?: string;\r\n public assets: DbAsset[];\r\n \r\n constructor(data: Partial<DbScene>) {\r\n this.name = data.name ?? '';\r\n this.id = data.id ?? 0;\r\n this.description = data.description ?? '';\r\n this.assets = data.assets ?? [];\r\n\r\n if(!this.name) throw new Error('Scene name is required');\r\n if(!this.id) throw new Error('Scene id is required');\r\n }\r\n}","import { DbScene } from \"./scenes\";\r\n\r\nexport class DbGroup {\r\n public name: string;\r\n public prefix: string;\r\n public description?: string;\r\n public scenes: Record<string, DbScene>;\r\n\r\n constructor(data: Partial<DbGroup>) {\r\n this.name = data.name ?? '';\r\n this.prefix = data.prefix ?? '';\r\n this.description = data.description ?? '';\r\n this.scenes = data.scenes ?? {};\r\n }\r\n}","import { BitStream } from '../types/bitstream';\nimport { type ICompressionProvider } from '../types/compression';\n\n/**\n * QuintetLZ compression algorithm implementation\n * Dictionary-based compression used in Quintet games\n */\nexport class QuintetLZ implements ICompressionProvider {\n public static readonly DICTIONARY_SIZE = 0x100;\n public static readonly DICTIONARY_INIT = 0x20;\n public static readonly DICTIONARY_OFFSET = 0xEF;\n private static readonly DEFAULT_PAGE_SIZE = 0x8000;\n\n /**\n * Expand (decompress) data using QuintetLZ algorithm\n * @param srcData Source data buffer\n * @param srcPosition Starting position in source data\n * @param srcLen Length of source data to process\n * @returns Expanded data\n */\n public expand(srcData: Uint8Array, srcPosition: number = 0, srcLen: number = QuintetLZ.DEFAULT_PAGE_SIZE): Uint8Array {\n const bitStream = new BitStream(srcData, srcPosition);\n const srcStop = srcPosition + srcLen;\n\n // Initialize dictionary with spaces (0x20)\n const dictionary = new Uint8Array(QuintetLZ.DICTIONARY_SIZE);\n dictionary.fill(QuintetLZ.DICTIONARY_INIT);\n\n // Initialize positions\n let dictPosition = QuintetLZ.DICTIONARY_OFFSET;\n let outPosition = 0;\n\n // First two bytes is decompressed size\n let dstLen = bitStream.readShort();\n\n if(dstLen === 0){\n return srcData.slice(srcPosition + 2, srcStop);\n } else if(dstLen & 0x8000) {\n dstLen = 0x10000 - dstLen;\n }\n\n // Create output buffer with the expected size\n const outBuffer = new Uint8Array(dstLen);\n\n while (bitStream.currentPosition < srcStop && outPosition < dstLen) {\n // If current bit is set, read byte and add to output buffer and dictionary\n if (bitStream.readBit()) {\n // Read byte from bitstream\n const sample = bitStream.readByte();\n\n // Add byte to output buffer and increment\n if (outPosition < dstLen) {\n outBuffer[outPosition++] = sample;\n }\n\n // Add byte to dictionary\n dictionary[dictPosition] = sample;\n\n // Wrap dictionary index\n dictPosition = (dictPosition + 1) & 0xFF;\n }\n // If current bit is not set, read sequence from dictionary\n else {\n // Read wordIndex and wordLength from bitstream\n let wordIndex = bitStream.readByte();\n let wordLength = bitStream.readNibble() + 2;\n\n // Continue while there are remaining bytes to copy\n while (wordLength-- > 0) {\n // Read byte at wordIndex\n const sample = dictionary[wordIndex];\n\n // Wrap dictionary index\n wordIndex = (wordIndex + 1) & 0xFF;\n\n // Copy byte to output buffer and increment, but only if there is space\n if (outPosition < dstLen) {\n outBuffer[outPosition++] = sample;\n }\n\n // Add byte to dictionary and increment\n dictionary[dictPosition] = sample;\n\n // Wrap dictionary index\n dictPosition = (dictPosition + 1) & 0xFF;\n }\n }\n }\n\n // Return only the used portion of the buffer\n if (outPosition < dstLen) {\n return outBuffer.slice(0, outPosition);\n }\n\n return outBuffer;\n }\n\n /**\n * Compact (compress) data using QuintetLZ algorithm\n * @param srcData Source data to compress\n * @returns Compressed data\n */\n public compact(srcData: Uint8Array, srcPosition?: number, srcLen?: number): Uint8Array {\n // Initialize dictionary with spaces\n const dictionary = new Uint8Array(QuintetLZ.DICTIONARY_SIZE);\n dictionary.fill(QuintetLZ.DICTIONARY_INIT);\n\n let offset = QuintetLZ.DICTIONARY_OFFSET;\n let srcIx = srcPosition ?? 0;\n let dstIx = 0;\n if(!srcLen) srcLen = srcData.length - srcIx;\n let endIx = srcIx + srcLen;\n\n\n //const srcLen = srcData.length;\n const outputBuffer = new Uint8Array(srcLen * 2); // Allocate extra space for safety\n\n // Write header (16-bit length in little-endian)\n outputBuffer[dstIx++] = srcLen & 0xFF;\n outputBuffer[dstIx++] = (srcLen >> 8) & 0xFF;\n\n const bitStream = new BitStream(outputBuffer, 2); // Start after header\n\n /**\n * Find the best match in the dictionary\n * @returns Tuple of [startByte, length]\n */\n const getCommand = (): [number, number] => {\n const maxLen = Math.min(endIx - srcIx, 17);\n if (maxLen < 2) {\n return [0, 0];\n }\n\n let startByte = 0;\n let bestLen = 0;\n let baseIndex = offset;\n\n for (let i = 0; i < 0x100; i++, baseIndex = (baseIndex + 1) & 0xFF) {\n let size = 0;\n let currentIndex = baseIndex;\n let sourceIndex = srcIx;\n let isEnd = false;\n\n while (size < maxLen) {\n if(isEnd) { if(srcData[sourceIndex++] !== srcData[srcIx + size]) break; } \n else if(dictionary[currentIndex] !== srcData[sourceIndex++]) break; \n else {\n currentIndex = (currentIndex + 1) & 0xFF;\n if (currentIndex === offset) {\n sourceIndex = srcIx;\n isEnd = true;\n }\n }\n \n size++;\n }\n\n if (size > bestLen) {\n startByte = baseIndex;\n bestLen = size;\n\n if (bestLen >= maxLen) {\n break;\n }\n }\n }\n\n return [startByte, bestLen];\n };\n\n while (srcIx < endIx) {\n const [cmdStart, cmdLen] = getCommand();\n\n if (cmdLen >= 2) {\n // Write dictionary reference\n bitStream.writeBit(false);\n bitStream.writeByte(cmdStart);\n bitStream.writeNibble(cmdLen - 2);\n\n // Copy bytes to dictionary\n for (let i = 0; i < cmdLen; i++) {\n dictionary[offset] = srcData[srcIx++];\n offset = (offset + 1) & 0xFF;\n }\n } else {\n // Write literal byte\n bitStream.writeBit(true);\n const val = srcData[srcIx++];\n bitStream.writeByte(val);\n dictionary[offset] = val;\n offset = (offset + 1) & 0xFF;\n }\n }\n bitStream.flush();\n\n // Get the final size including the bit stream data\n const finalSize = Math.max(dstIx, bitStream.currentPosition);\n return outputBuffer.slice(0, finalSize);\n }\n} ","import { ICompressionProvider } from '../types/compression';\nimport { QuintetLZ } from './QuintetLZ';\n\nexport * from './QuintetLZ';\n\nexport const CompressionAlgorithms = {\n 'QuintetLZ': () => new QuintetLZ(),\n} as Record<string, () => ICompressionProvider>;\n","import { ChunkFile } from '../../types/files';\nimport { TableEntry } from '../../types';\nimport { StructDef, Word } from '../../types';\nimport { BlockReader } from './blocks';\nimport { ReferenceManager } from './references';\n\n/**\n * Handles post processing of extracted blocks.\n * Mirrors functionality of GaiaLib.Rom.Extraction.PostProcessor.\n */\nexport class PostProcessor {\n private readonly _referenceManager: ReferenceManager;\n\n constructor(reader: BlockReader) {\n this._referenceManager = reader._referenceManager;\n }\n\n /**\n * Execute post process directive on a block if present.\n */\n public process(block: ChunkFile): void {\n if (!block.postProcess || block.postProcess.trim() === '') {\n return;\n }\n\n let signature = block.postProcess;\n const parts: string[] = [];\n\n const index = signature.indexOf('(');\n if (index > 0) {\n const endIx = signature.indexOf(')', index);\n const params = signature.substring(\n index + 1,\n endIx >= 0 ? endIx : signature.length\n );\n if (params.length > 0) {\n for (const p of params.split(',')) {\n parts.push(p.trim());\n }\n }\n signature = signature.substring(0, index);\n }\n\n const fn = (this as any)[signature];\n if (typeof fn !== 'function') {\n throw new Error(`Unable to locate postprocess function ${signature}`);\n }\n fn.apply(this, [block, ...parts]);\n }\n\n /**\n * Builds a lookup table from struct entries.\n * Equivalent to PostProcessor.Lookup in C# implementation.\n */\n public Lookup(block: ChunkFile, keyIx: string, valueIx: string): void {\n const kix = parseInt(keyIx.trim());\n const vix = parseInt(valueIx.trim());\n\n if(!block.parts || block.parts.length === 0) {\n throw new Error('Invalid block structure for Lookup post process');\n }\n\n const table = block.parts[0]?.objList;\n const tableEntry = table && table[0];\n const entries = tableEntry?.object as unknown[] | undefined;\n\n if (!tableEntry || !entries) {\n throw new Error('Invalid table structure for Lookup post process');\n }\n\n const newParts: TableEntry[] = [];\n const newList: any[] = [];\n\n newParts.push({ location: tableEntry.location, object: newList });\n\n let eIx = 1;\n for (const entry of entries as StructDef[]) {\n if (!entry || !Array.isArray((entry as any).parts)) {\n continue;\n }\n const struct = entry as StructDef;\n let cIx = 0;\n let key: number | null = null;\n let value: unknown = null;\n\n for (const obj of struct.parts) {\n if (cIx === kix) {\n if(obj && typeof obj === 'object' && 'value' in obj) {\n key = obj.value as number;\n } else {\n key = obj as number;\n }\n } else if (cIx === vix) {\n value = obj;\n }\n cIx++;\n }\n\n if (key === null || value === null) {\n throw new Error('Could not locate key or value for transform');\n }\n\n const name = `entry_${key.toString(16).toUpperCase().padStart(2, '0')}`;\n const loc = tableEntry.location + eIx;\n\n newParts.push({ location: loc, object: value });\n\n // Force labels to match the new name\n this._referenceManager.nameTable.set(loc, name);\n\n while (newList.length <= key) {\n newList.push(new Word(0));\n }\n\n newList[key] = `&${name}`;\n eIx++;\n }\n\n block.parts[0].objList = newParts;\n }\n}\n\nexport default PostProcessor;\n\n","import { Op } from '../../types/assembly';\r\nimport { AsmBlock, ChunkFile, ChunkFileUtils, TypedNumber } from '../../types';\r\nimport { \r\n AddressType, \r\n MemberType,\r\n AddressSpace,\r\n TableEntry,\r\n StructDef,\r\n StringWrapper,\r\n LocationWrapper,\r\n Address\r\n} from '../../types';\r\nimport { DbRoot } from '../../database';\r\nimport { BlockReader } from './blocks';\r\nimport { ReferenceManager } from './references';\r\nimport { PostProcessor } from './postprocessor';\r\n\r\n// Platform detection that works in both Node.js and web environments\r\nconst isWindows = (() => {\r\n // Check if we're in Node.js environment\r\n if (typeof process !== 'undefined' && process.platform) {\r\n return process.platform === 'win32';\r\n }\r\n // In web environment, check user agent as fallback\r\n // if (typeof navigator !== 'undefined' && navigator.userAgent) {\r\n // return navigator.userAgent.includes('Windows');\r\n // }\r\n // Default to Unix-style line endings if we can't determine\r\n return false;\r\n})();\r\n\r\nconst NEWLINE = isWindows ? '\\r\\n' : '\\n';\r\n\r\n// Type tags for better object identification\r\nexport enum ObjectType {\r\n TableEntryArray = 'TableEntryArray',\r\n StructDef = 'StructDef',\r\n OpArray = 'OpArray',\r\n LocationWrapper = 'LocationWrapper',\r\n Address = 'Address',\r\n StringWrapper = 'StringWrapper',\r\n ByteArray = 'ByteArray',\r\n Array = 'Array',\r\n String = 'String',\r\n Number = 'Number',\r\n TypedNumber = 'TypedNumber'\r\n}\r\n\r\nexport class BlockWriter {\r\n private _root: DbRoot;\r\n private _blockReader: BlockReader;\r\n private _referenceManager: ReferenceManager;\r\n private _postProcessor: PostProcessor;\r\n private _isInline: boolean = false;\r\n private _currentPart: AsmBlock | null = null;\r\n\r\n constructor(reader: BlockReader) {\r\n this._blockReader = reader;\r\n this._root = reader._root;\r\n this._referenceManager = reader._referenceManager;\r\n this._postProcessor = new PostProcessor(reader);\r\n }\r\n\r\n // async writeBlocks(outPath: string): Promise<void> {\r\n // const res = DbRootUtils.getPath(this._root, BinType.Assembly);\r\n\r\n // const folderPath = join(outPath, res.folder);\r\n\r\n // for (const block of this._root.blocks) {\r\n // const groupedFolderPath = block.group \r\n // ? join(folderPath, block.group)\r\n // : folderPath;\r\n \r\n // await fs.mkdir(groupedFolderPath, { recursive: true });\r\n\r\n // const outFile = join(groupedFolderPath, `${block.name}.${res.extension}`);\r\n \r\n // // Check if file exists, skip if it does\r\n // try {\r\n // await fs.access(outFile);\r\n // continue;\r\n // } catch {\r\n // // File doesn't exist, continue with creation\r\n // }\r\n\r\n // const content = this.generateAsm(block);\r\n \r\n // await fs.writeFile(outFile, content);\r\n // }\r\n // }\r\n\r\n generateAllAsm(chunkFiles: ChunkFile[]): any[] {\r\n const lines: any[] = [];\r\n for (const block of chunkFiles) {\r\n lines.push({\r\n name: block.name,\r\n group: block.group,\r\n text: this.generateAsm(block)\r\n });\r\n }\r\n return lines;\r\n }\r\n\r\n generateAsm(block: ChunkFile): string{\r\n if(!block.parts) {\r\n throw new Error('Invalid block structure for generateAsm');\r\n }\r\n\r\n const lines: string[] = [];\r\n\r\n // Write bank information if not movable\r\n if (block.bank !== undefined) {\r\n lines.push(`?BANK ${block.bank.toString(16).toUpperCase().padStart(2, '0')}`);\r\n }\r\n\r\n // Write includes - these should be from the block's include list\r\n const includes = ChunkFileUtils.getIncludes(block);\r\n if (includes && includes.length > 0) {\r\n lines.push('');\r\n for (const inc of includes) {\r\n lines.push(`?INCLUDE '${inc.name}'`);\r\n }\r\n }\r\n\r\n // Write mnemonics - these should be from the root mnemonics that are referenced in this block\r\n const mnemonics = this.getMnemonicsForBlock(block);\r\n if (mnemonics && mnemonics.length > 0) {\r\n lines.push('');\r\n for (const [name, address] of mnemonics) {\r\n const paddedName = name.padEnd(30, ' ');\r\n lines.push(`!${paddedName} ${address.toString(16).toUpperCase().padStart(4, '0')}`);\r\n }\r\n }\r\n\r\n // Apply any post processing defined for the block\r\n this._postProcessor.process(block);\r\n\r\n // Process each part\r\n for (const part of block.parts || []) {\r\n this._currentPart = part;\r\n this._isInline = true;\r\n\r\n lines.push('');\r\n lines.push('---------------------------------------------');\r\n\r\n const objectLines = this.writeObject(part.objList, -1);\r\n lines.push(...objectLines);\r\n }\r\n\r\n let content = lines.join(NEWLINE);\r\n\r\n // Apply replace transforms\r\n if (block.transforms) {\r\n for (const x of block.transforms) {\r\n if (x.key && x.value) {\r\n const regex = new RegExp(x.key, 'g');\r\n content = content.replace(regex, x.value);\r\n }\r\n }\r\n }\r\n\r\n if(!isWindows){\r\n content = content.replace(/\\r/g, '');\r\n }\r\n\r\n return content;\r\n };\r\n\r\n private getMnemonicsForBlock(block: ChunkFile): [string, number][] {\r\n if (!block.mnemonics) {\r\n return [];\r\n }\r\n\r\n return Object.entries(block.mnemonics)\r\n .map(([k, v]) => [v, parseInt(k, 10)] as [string, number])\r\n .sort((a, b) => a[1] - b[1]);\r\n }\r\n\r\n private resolveOperand(op: Op, obj: any, isBranch: boolean = false): any {\r\n\r\n if(obj instanceof TypedNumber) {\r\n const len = obj.size * 2;\r\n return obj.value.toString(16).toUpperCase().padStart(len, '0');\r\n }\r\n\r\n if (typeof obj === 'number') {\r\n if (op.mode === 'Immediate') {\r\n return obj;\r\n }\r\n return this._blockReader.resolveName(obj, AddressType.Address, isBranch);\r\n }\r\n \r\n if (this.getObjectType(obj) === ObjectType.LocationWrapper) {\r\n const lw = obj as LocationWrapper;\r\n return this._blockReader.resolveName(lw.location, lw.type, isBranch);\r\n }\r\n if (this.getObjectType(obj) === ObjectType.Address) {\r\n const addr = obj as Address;\r\n\r\n if (op.size === 4) {\r\n return addr;\r\n }\r\n\r\n if (addr.isCodeBank && addr.offset < Address.UPPER_BANK) {\r\n const label = this._root.mnemonics[addr.offset];\r\n if (label) return label;\r\n }\r\n\r\n return addr.offset;\r\n }\r\n\r\n // Preserve tag information on typed numbers without resolving names\r\n if (obj && obj instanceof TypedNumber) {\r\n // const typed = obj as { _tag: string; value: any };\r\n\r\n // // Byte/Word objects should remain untouched\r\n // if (typed._tag === 'Byte' || typed._tag === 'Word' || typed._tag === 'TypedNumber') {\r\n // return obj;\r\n // }\r\n\r\n // if (typeof typed.value === 'number' && op.mode !== 'Immediate') {\r\n // const resolved = this._blockReader.resolveName(typed.value, AddressType.Address, isBranch);\r\n // return { ...typed, value: resolved };\r\n // }\r\n return obj;\r\n }\r\n return obj;\r\n }\r\n\r\n private getObjectType(obj: any): ObjectType {\r\n if (obj === null || obj === undefined) {\r\n return ObjectType.String;\r\n }\r\n\r\n // Check for explicit type tags first\r\n if (obj._tag) {\r\n return obj._tag as ObjectType;\r\n }\r\n\r\n if (obj instanceof TypedNumber) {\r\n return ObjectType.TypedNumber;\r\n }\r\n\r\n // Duck typing fallbacks\r\n if (Array.isArray(obj)) {\r\n if (obj.length > 0) {\r\n if (obj[0] && typeof obj[0] === 'object' && 'location' in obj[0] && 'object' in obj[0]) {\r\n return ObjectType.TableEntryArray;\r\n }\r\n if (obj[0] instanceof Op) {\r\n return ObjectType.OpArray;\r\n }\r\n }\r\n return ObjectType.Array;\r\n }\r\n\r\n if (obj instanceof Op) {\r\n return ObjectType.OpArray;\r\n }\r\n\r\n if (obj instanceof LocationWrapper) {\r\n return ObjectType.LocationWrapper;\r\n }\r\n\r\n if (obj instanceof Address) {\r\n return ObjectType.Address;\r\n }\r\n\r\n if (obj instanceof Uint8Array) {\r\n return ObjectType.ByteArray;\r\n }\r\n\r\n if (obj && typeof obj === 'object') {\r\n if ('string' in obj && 'type' in obj && 'marker' in obj && 'location' in obj) {\r\n return ObjectType.StringWrapper;\r\n }\r\n if ('name' in obj && 'parts' in obj) {\r\n return ObjectType.StructDef;\r\n }\r\n }\r\n\r\n if (typeof obj === 'string') {\r\n return ObjectType.String;\r\n }\r\n\r\n if (typeof obj === 'number') {\r\n return ObjectType.Number;\r\n }\r\n\r\n return ObjectType.String;\r\n }\r\n\r\n private writeObject(obj: any, depth: number, isBranch: boolean = false, isArray: boolean = false): string[] {\r\n const lines: string[] = [];\r\n\r\n const objType = this.getObjectType(obj);\r\n let objLines: string[];\r\n\r\n switch (objType) {\r\n case ObjectType.TableEntryArray:\r\n objLines = this.writeTableEntryArray(obj as TableEntry[], depth);\r\n break;\r\n\r\n case ObjectType.StructDef:\r\n objLines = this.writeStructDef(obj as StructDef, depth);\r\n break;\r\n\r\n case ObjectType.OpArray:\r\n objLines = this.writeOpArray(obj as Op[], depth);\r\n break;\r\n\r\n case ObjectType.LocationWrapper:\r\n objLines = [\r\n this._blockReader.resolveName(\r\n (obj as LocationWrapper).location,\r\n (obj as LocationWrapper).type,\r\n isBranch\r\n ),\r\n ];\r\n break;\r\n\r\n case ObjectType.Address:\r\n objLines = isArray \r\n ? [`$#${(obj as Address).offset.toString(16).toUpperCase().padStart(4, '0')}`] \r\n : [`$${(obj as Address).toString()}`];\r\n break;\r\n\r\n case ObjectType.ByteArray:\r\n objLines = [\r\n `#${Array.from(obj as Uint8Array)\r\n .map(b => b.toString(16).toUpperCase().padStart(2, '0'))\r\n .join('')}`,\r\n ];\r\n break;\r\n\r\n case ObjectType.StringWrapper:\r\n objLines = this.writeStringWrapper(obj as StringWrapper);\r\n break;\r\n\r\n case ObjectType.Array:\r\n objLines = this.writeArray(obj as any[], depth);\r\n break;\r\n\r\n case ObjectType.Number:\r\n objLines = this.writeNumber(obj as number);\r\n break;\r\n\r\n case ObjectType.TypedNumber:\r\n objLines = this.writeTypedNumber(obj as any);\r\n break;\r\n\r\n case ObjectType.String:\r\n objLines = [String(obj)];\r\n break;\r\n\r\n default:\r\n objLines = [String(obj)];\r\n break;\r\n }\r\n\r\n lines.push(...objLines);\r\n\r\n return lines;\r\n }\r\n\r\n private writeTableEntryArray(tGroup: TableEntry[], depth: number): string[] {\r\n const lines: string[] = [];\r\n const isInline = this._isInline;\r\n //this._isInline = true;\r\n\r\n for (const t of tGroup) {\r\n const nameResult = this._referenceManager.tryGetName(t.location);\r\n //const adrs = Address.fromInt(t.location, this._blockReader._root.config.memoryMode);\r\n //const name = nameResult.found ? nameResult.referenceName! : `loc_${adrs.toString()}`;\r\n const name = nameResult.found ? nameResult.referenceName! : `loc_${t.location.toString(16).toUpperCase().padStart(6, '0')}`;\r\n \r\n const objectLines = this.writeObject(t.object, depth + 1);\r\n lines.push('');\r\n lines.push(`${name} ${objectLines[0]}`);\r\n if (objectLines.length > 1) {\r\n lines.push(...objectLines.slice(1));\r\n }\r\n }\r\n \r\n this._isInline = isInline;\r\n return lines;\r\n }\r\n\r\n private writeStructDef(structObj: StructDef, depth: number): string[] {\r\n const parts: string[] = [];\r\n const isInline = this._isInline;\r\n this._isInline = true;\r\n for (const part of structObj.parts) {\r\n const partLines = this.writeObject(part, depth);\r\n parts.push(partLines.join(NEWLINE));\r\n }\r\n const line = `${structObj.name} < ${parts.join(', ')} >`;\r\n this._isInline = isInline; // match C# spacing behaviour\r\n return [line];\r\n }\r\n\r\n private writeOpArray(opList: Op[], depth: number): string[] {\r\n const lines: string[] = [];\r\n lines.push('{');\r\n const isInline = this._isInline;\r\n this._isInline = true; // instructions follow immediately\r\n \r\n let first = true;\r\n for (const op of opList) {\r\n if (first) {\r\n first = false;\r\n } else {\r\n // Check for labels on subsequent instructions\r\n const labelResult = this._referenceManager.tryGetName(op.location);\r\n if (labelResult.found) {\r\n lines.push('');\r\n lines.push(` ${labelResult.referenceName}:`);\r\n }\r\n }\r\n\r\n let opLine = ` ${op.mnem} `;\r\n\r\n if (op.copDef) {\r\n // Handle COP instructions specially\r\n opLine += `[${op.copDef.name}]`;\r\n if (op.operands && op.operands.length > 1) {\r\n const operandStrings: string[] = [];\r\n for (let i = 1; i < op.operands.length; i++) {\r\n const operandLines = this.writeObject(op.operands[i], depth + 1, false);\r\n operandStrings.push(operandLines[0]);\r\n }\r\n opLine += ` ( ${operandStrings.join(', ')} )`;\r\n }\r\n } else if (op.operands && op.operands.length > 0) {\r\n const isBr = op.mnem[0] === 'J' || \r\n op.mode === 'PCRelative' ||\r\n op.mode === 'PCRelativeLong';\r\n\r\n // Regular instruction formatting\r\n const resolvedOperand = this.resolveOperand(op, op.operands[0], isBr);\r\n const format = this._root.addrLookup[op.mode]?.formatString; // || this._root.config.asmFormats?.[op.code.mode];\r\n \r\n if (format) {\r\n let actualFormat = format;\r\n if (op.mode === 'Immediate' && op.size === 3) {\r\n actualFormat = format.replace('X2', 'X4');\r\n }\r\n const resolvedSecondOperand = op.operands.length > 1 ? this.resolveOperand(op, op.operands[1], isBr) : undefined;\r\n opLine += this.formatOperand(actualFormat, [resolvedOperand, resolvedSecondOperand]);\r\n } else {\r\n // Default formatting based on operand type\r\n opLine += this.formatDefaultOperand(resolvedOperand, op.size);\r\n }\r\n }\r\n \r\n lines.push(opLine);\r\n }\r\n \r\n lines.push('}');\r\n this._isInline = isInline; // ensure following object is separated by blank line\r\n return lines;\r\n }\r\n\r\n private formatDefaultOperand(operand: any, size: number): string {\r\n if (typeof operand === 'string') {\r\n return operand; // Already formatted\r\n }\r\n\r\n if (operand && operand instanceof TypedNumber) {\r\n return this.formatTypedNumber(operand);\r\n }\r\n\r\n if (typeof operand === 'number') {\r\n const hexSize = (size - 1) * 2;\r\n const hex = operand.toString(16).toUpperCase().padStart(hexSize, '0');\r\n return `$${hex}`;\r\n }\r\n \r\n return String(operand);\r\n }\r\n\r\n private writeStringWrapper(stringObj: StringWrapper): string[] {\r\n let str = stringObj.string;\r\n \r\n // Process string references\r\n const stringReferenceChars = ['~', '^'];\r\n for (const char of stringReferenceChars) {\r\n let ix = str.indexOf(char);\r\n while (ix >= 0) {\r\n const hexStr = str.substring(ix + 1, ix + 7);\r\n const rawAddr = parseInt(hexStr, 16);\r\n const adrs = new Address((rawAddr >> 16) & 0xFF, rawAddr & 0xFFFF, this._blockReader._root.config.memoryMode);\r\n const addressType = char === '^' ? AddressType.Offset : AddressType.Address;\r\n let name = '';\r\n \r\n if (adrs.isROM) {\r\n name = this._blockReader.resolveName(adrs.toLocation(), addressType, false);\r\n } else if(addressType === AddressType.Offset) {\r\n name = adrs.offset.toString(16).toUpperCase().padStart(4, '0');\r\n } else {\r\n name = adrs.toString();\r\n }\r\n \r\n str = str.replace(str.substring(ix, ix + 7), name);\r\n ix = str.indexOf(char);\r\n }\r\n }\r\n\r\n const refChar = stringObj.type.delimiter;\r\n let marker = stringObj.marker;\r\n \r\n if (marker <= 0) {\r\n const markerResult = this._referenceManager.tryGetMarker(stringObj.location);\r\n marker = markerResult.found ? markerResult.offset || 0 : 0;\r\n }\r\n\r\n if (marker > 0) {\r\n let six = 0;\r\n let mix = 0;\r\n \r\n while (mix < marker) {\r\n if (str[six] === '[') {\r\n const eix = str.indexOf(']', ++six);\r\n const parts = str.substring(six, eix).split(/[,: ]/);\r\n \r\n const cmd = stringObj.type.commands[parts[0]];\r\n if (cmd && (cmd as any).types) {\r\n for (const t of (cmd as any).types) {\r\n switch (t) {\r\n case MemberType.Byte:\r\n mix += 1;\r\n break;\r\n case MemberType.Word:\r\n case MemberType.Offset:\r\n mix += 2;\r\n break;\r\n case MemberType.Address:\r\n case MemberType.Location:\r\n mix += 3;\r\n break;\r\n case MemberType.Binary:\r\n mix += parts.length - 1;\r\n break;\r\n default:\r\n throw new Error('Unsupported member type');\r\n }\r\n }\r\n }\r\n six = eix + 1;\r\n mix++;\r\n } else {\r\n six++;\r\n mix++;\r\n }\r\n }\r\n \r\n str = str.substring(0, six) + '[::]' + str.substring(six);\r\n }\r\n\r\n const sizeParam = stringObj.fixedSize ? `(${stringObj.fixedSize})` : '';\r\n\r\n return [`${refChar}${str}${refChar}${sizeParam}`];\r\n }\r\n\r\n private writeArray(arr: any[], depth: number): string[] {\r\n const lines: string[] = [];\r\n const indent = ' '.repeat(Math.max(0, depth));\r\n const isInline = this._isInline;\r\n lines.push('[');\r\n this._isInline = false; // start elements on their own lines\r\n\r\n for (let i = 0; i < arr.length; i++) {\r\n const objLines = this.writeObject(arr[i], depth + 1, false, true);\r\n for(const line of objLines) {\r\n lines.push(indent + ' ' + line);\r\n }\r\n lines[lines.length - 1] += ` ;${i.toString(16).toUpperCase().padStart(2, '0')}`;\r\n }\r\n\r\n lines.push(indent + ']');\r\n this._isInline = isInline;\r\n return lines;\r\n }\r\n\r\n private writeNumber(num: number): string[] {\r\n // Format numbers based on value and size\r\n if (num <= 0xff) {\r\n // Mirror C# BlockWriter: bytes omit the '$' prefix\r\n return [`#${num.toString(16).toUpperCase().padStart(2, '0')}`];\r\n }\r\n\r\n if (num <= 0xffff) {\r\n return [`#$${num.toString(16).toUpperCase().padStart(4, '0')}`];\r\n }\r\n\r\n return [`#$${num.toString(16).toUpperCase().padStart(6, '0')}`];\r\n }\r\n\r\n private formatTypedNumber(num: TypedNumber): string {\r\n if (typeof num.value === 'number') {\r\n const width = num.size * 2;\r\n const hex = num.value.toString(16).toUpperCase().padStart(width, '0');\r\n return num.size === 1 ? `#${hex}` : `#$${hex}`;\r\n }\r\n\r\n return `#${num.value}`;\r\n }\r\n\r\n private writeTypedNumber(num: TypedNumber): string[] {\r\n return [this.formatTypedNumber(num)];\r\n }\r\n\r\n private formatOperand(format: string, operands: any[]): string {\r\n return format.replace(/\\{(\\d+)(?::([^}]+))?\\}/g, (match, index, formatSpec) => {\r\n const operand = operands[parseInt(index)];\r\n if (operand && typeof operand === 'object' && operand._tag && 'value' in operand) {\r\n const value = operand.value;\r\n if (formatSpec && typeof value === 'number' && formatSpec.startsWith('X')) {\r\n const width = parseInt(formatSpec.substring(1)) || 2;\r\n return value.toString(16).toUpperCase().padStart(width, '0');\r\n }\r\n return String(value);\r\n }\r\n\r\n if (formatSpec && typeof operand === 'number') {\r\n if (formatSpec.startsWith('X')) {\r\n const width = parseInt(formatSpec.substring(1)) || 2;\r\n return operand.toString(16).toUpperCase().padStart(width, '0');\r\n }\r\n }\r\n return String(operand);\r\n });\r\n }\r\n} ","/**\r\n * Represents the stack for the 65816 processor\r\n */\r\nexport class Stack {\r\n public bytes: Uint8Array;\r\n public location: number;\r\n\r\n constructor() {\r\n this.bytes = new Uint8Array(70);\r\n this.location = 10;\r\n }\r\n\r\n /**\r\n * Push a byte onto the stack\r\n */\r\n public push(value: number): void {\r\n this.bytes[this.location++] = value & 0xFF;\r\n }\r\n\r\n /**\r\n * Push a 16-bit value onto the stack (little-endian)\r\n */\r\n public pushUInt16(value: number): void {\r\n this.bytes[this.location++] = value & 0xFF;\r\n this.bytes[this.location++] = (value >> 8) & 0xFF;\r\n }\r\n\r\n /**\r\n * Pop a byte from the stack\r\n */\r\n public popByte(): number {\r\n return this.bytes[--this.location];\r\n }\r\n\r\n /**\r\n * Pop a 16-bit value from the stack (little-endian)\r\n */\r\n public popUInt16(): number {\r\n const high = this.bytes[--this.location];\r\n const low = this.bytes[--this.location];\r\n return (high << 8) | low;\r\n }\r\n\r\n /**\r\n * Reset the stack to initial state\r\n */\r\n public reset(): void {\r\n this.bytes.fill(0);\r\n this.location = 10;\r\n }\r\n} ","import { StatusFlags } from '../types';\r\nimport { Stack } from './Stack';\r\nimport { MemoryMapMode } from '../types';\r\n\r\n/**\r\n * Manages the 65816 processor registers and status flags\r\n */\r\nexport class Registers {\r\n // public accumulatorFlag?: boolean;\r\n // public indexFlag?: boolean;\r\n // public direct?: number;\r\n // public dataBank?: number;\r\n // public accumulator?: number;\r\n // public xIndex?: number;\r\n // public yIndex?: number;\r\n public value: Record<string, number>;\r\n public stack: Stack;\r\n public mode: MemoryMapMode;\r\n\r\n constructor(mode: MemoryMapMode) {\r\n this.value = {};\r\n this.stack = new Stack();\r\n this.mode = mode;\r\n }\r\n\r\n /**\r\n * Get the current status flags\r\n */\r\n // public get statusFlags(): StatusFlags {\r\n // let flags = 0;\r\n // if (this.accumulatorFlag ?? false) {\r\n // flags |= StatusFlags.AccumulatorMode;\r\n // }\r\n // if (this.indexFlag ?? false) {\r\n // flags |= StatusFlags.IndexMode;\r\n // }\r\n // return flags;\r\n // }\r\n\r\n // /**\r\n // * Set the status flags\r\n // */\r\n // public set statusFlags(value: StatusFlags) {\r\n // this.accumulatorFlag = (value & StatusFlags.AccumulatorMode) !== 0;\r\n // this.indexFlag = (value & StatusFlags.IndexMode) !== 0;\r\n // }\r\n\r\n /**\r\n * Reset all registers to initial state\r\n */\r\n // public reset(): void {\r\n // this.accumulatorFlag = undefined;\r\n // this.indexFlag = undefined;\r\n // this.direct = undefined;\r\n // this.dataBank = undefined;\r\n // this.accumulator = undefined;\r\n // this.xIndex = undefined;\r\n // this.yIndex = undefined;\r\n // this.stack.reset();\r\n // }\r\n} ","import { OpCode } from '../../database';\r\nimport { Op } from '../../types/assembly';\r\n\r\nimport { Registers } from '../../assembly';\r\nimport { RomDataReader } from './reader';\r\nimport { TransformProcessor } from './transforms';\r\nimport { AddressingModeHandler, OperationContext } from './addressing';\r\nimport type { BlockReader } from './blocks';\r\nimport { StatusFlags } from '../../types/processor';\r\n\r\n/**\r\n * Parses assembly instructions from ROM data, handling different addressing modes\r\n * and maintaining CPU register state during analysis.\r\n * Converted from GaiaLib/Rom/Extraction/AsmReader.cs\r\n */\r\nexport class AsmReader {\r\n // Constants\r\n private static readonly STATUS_OP_MASK = 0xDF;\r\n private static readonly STATUS_OP_VALUE = 0xC2;\r\n private static readonly ACCUMULATOR_OP_MASK = 0xF;\r\n private static readonly ACCUMULATOR_OP_VALUE = 0x9;\r\n public static readonly VARIABLE_SIZE_INDICATOR = -2;\r\n // private static readonly TWO_BYTES_SIZE = 2;\r\n // private static readonly THREE_BYTES_SIZE = 3;\r\n\r\n private readonly _blockReader: BlockReader;\r\n private readonly _transformProcessor: TransformProcessor;\r\n private readonly _addressingModeHandler: AddressingModeHandler;\r\n private readonly _romDataReader: RomDataReader;\r\n\r\n constructor(blockReader: BlockReader) {\r\n this._blockReader = blockReader;\r\n this._transformProcessor = new TransformProcessor(blockReader);\r\n this._addressingModeHandler = new AddressingModeHandler(blockReader, this._transformProcessor);\r\n this._romDataReader = blockReader._romDataReader;\r\n }\r\n\r\n public parseAsm(reg: Registers): Op {\r\n const opStart = this._romDataReader.position;\r\n const opCode = this._romDataReader.readByte();\r\n \r\n // Find matching OpCode in the database\r\n const code = this._blockReader._root.opCodes[opCode];\r\n if (!code) {\r\n throw new Error('Unknown OpCode');\r\n }\r\n\r\n // Initialize operation context\r\n const operationContext = this.initializeOperation(code, reg, opStart);\r\n\r\n // Process operands based on the addressing mode\r\n const operands = this._addressingModeHandler.processAddressingMode(code, operationContext, reg);\r\n \r\n // Apply label transforms to operands after processing. This ensures that the ROM state is processed and valid.\r\n this._transformProcessor.applyTransforms(operationContext.xForm1, operationContext.xForm2, operands);\r\n\r\n const op = new Op(\r\n code,\r\n opStart,\r\n operands,\r\n this._romDataReader.position - opStart\r\n );\r\n\r\n if (operationContext.copDef) {\r\n op.copDef = operationContext.copDef;\r\n }\r\n\r\n return op;\r\n }\r\n\r\n public clearDestinationRegister(code: OpCode, reg: Registers): void {\r\n switch (code.mnem) {\r\n case 'LDA':\r\n delete reg.value['accumulator'];\r\n break;\r\n case 'LDX':\r\n delete reg.value['xIndex'];\r\n break;\r\n case 'LDY':\r\n delete reg.value['yIndex'];\r\n break;\r\n }\r\n }\r\n\r\n private initializeOperation(code: OpCode, reg: Registers, loc: number): OperationContext {\r\n // Calculate instruction size (some are variable)\r\n const size = this.calculateInstructionSize(code, reg);\r\n\r\n // Calculate next address (for branching)\r\n const next = loc + size;\r\n\r\n // Clear destination register for load operations. This resets the register state\r\n this.clearDestinationRegister(code, reg);\r\n\r\n const context = new OperationContext();\r\n context.size = size;\r\n context.nextAddress = next;\r\n context.xForm1 = this._transformProcessor.getTransform();\r\n context.xForm2 = null;\r\n context.copDef = null;\r\n\r\n return context;\r\n }\r\n\r\n private calculateInstructionSize(code: OpCode, reg: Registers): number {\r\n const addrMode = this._blockReader._root.addrLookup[code.mode];\r\n let size = addrMode.size;\r\n \r\n if (size === AsmReader.VARIABLE_SIZE_INDICATOR || code.mode === 'Immediate') {\r\n if((code.code & AsmReader.STATUS_OP_MASK) === AsmReader.STATUS_OP_VALUE){\r\n size = 2; //SEP REP are 2 bytes\r\n } else if ((code.code & AsmReader.ACCUMULATOR_OP_MASK) === AsmReader.ACCUMULATOR_OP_VALUE) {\r\n size = ((reg.value['statusFlags'] & StatusFlags.AccumulatorMode) === StatusFlags.AccumulatorMode) ? 2 : 3;\r\n } else {\r\n size = ((reg.value['statusFlags'] & StatusFlags.IndexMode) === StatusFlags.IndexMode) ? 2 : 3;\r\n }\r\n }\r\n \r\n return size;\r\n }\r\n} ","import { Op } from '../../types/assembly';\r\nimport { Registers } from '../../assembly';\r\nimport { RomDataReader } from './reader';\r\nimport { StringReader } from './strings';\r\nimport { ReferenceManager } from './references';\r\nimport {\r\n Address,\r\n AddressSpace,\r\n AddressType,\r\n ChunkFileUtils,\r\n LocationWrapper,\r\n MemberType,\r\n StructDef,\r\n Byte,\r\n Word,\r\n} from '../../types';\r\nimport type { DbRoot, DbBlock, DbPart } from '../../database';\r\nimport type { DbStruct } from '../../database';\r\nimport type { DbStringType } from '../../database';\r\nimport { AsmReader } from './asm';\r\nimport type { BlockReader } from './blocks';\r\n\r\n/**\r\n * Handles parsing of different data types from ROM\r\n * Converted from GaiaLib/Rom/Extraction/TypeParser.cs\r\n */\r\nexport class TypeParser {\r\n private readonly _blockReader: BlockReader;\r\n private readonly _romDataReader: RomDataReader;\r\n private readonly _stringReader: StringReader;\r\n private readonly _stringTypes: Record<string, DbStringType>;\r\n private readonly _referenceManager: ReferenceManager;\r\n\r\n constructor(blockReader: BlockReader) {\r\n this._blockReader = blockReader;\r\n this._referenceManager = blockReader._referenceManager;\r\n this._romDataReader = blockReader._romDataReader;\r\n this._stringReader = blockReader._stringReader;\r\n this._stringTypes = blockReader._root.stringTypes;\r\n }\r\n\r\n public parseType(typeName: string, reg: Registers | null, depth: number, bank?: number): unknown {\r\n \r\n\r\n // Shortcut for symbolic Offsets\r\n if (typeName[0] === '&') {\r\n return this.parseLocation(this._romDataReader.readUShort(), bank, typeName.substring(1), AddressType.Offset);\r\n }\r\n\r\n // Shortcut for symbolic Addresses\r\n if (typeName[0] === '@') {\r\n return this.parseLocation(this._romDataReader.readUShort(), this._romDataReader.readByte(), typeName.substring(1), AddressType.Address);\r\n }\r\n \r\n // Shortcut for symbolic Locations\r\n if (typeName[0] === '%') {\r\n return this.parseLocation(this._romDataReader.readUShort(), this._romDataReader.readByte(), typeName.substring(1), AddressType.Location);\r\n }\r\n \r\n const isFixed = typeName[typeName.length - 1] === ')';\r\n let fixedTypeName = typeName;\r\n let fixedSize = 0;\r\n\r\n if(isFixed) {\r\n const startIx = typeName.indexOf('(');\r\n fixedTypeName = typeName.substring(0, startIx);\r\n fixedSize = parseInt(typeName.substring(startIx + 1, typeName.length - 1), 10);\r\n }\r\n\r\n // Check string types\r\n const stringType = this._stringTypes[fixedTypeName];\r\n if (stringType) {\r\n return this._stringReader.parseString(stringType, fixedSize);\r\n }\r\n\r\n // Parse raw values\r\n const mType = this.tryParseMemberType(fixedTypeName);\r\n if (mType !== null) {\r\n switch (mType) {\r\n case MemberType.Byte:\r\n return new Byte(this._romDataReader.readByte());\r\n case MemberType.Word:\r\n return new Word(this.parseWordSafe());\r\n case MemberType.Offset:\r\n return this.parseLocation(this._romDataReader.readUShort(), bank, null, AddressType.Offset);\r\n case MemberType.Address:\r\n return this.parseLocation(this._romDataReader.readUShort(), this._romDataReader.readByte(), null, AddressType.Address);\r\n case MemberType.Location:\r\n return this.parseLocation(this._romDataReader.readUShort(), this._romDataReader.readByte(), null, AddressType.Location);\r\n case MemberType.Binary:\r\n return this.parseBinary(fixedSize);\r\n case MemberType.Code:\r\n return this.parseCode(reg!);\r\n default:\r\n throw new Error('Invalid member type');\r\n }\r\n }\r\n\r\n const parentType = this._blockReader._root.structs[fixedTypeName];\r\n if (!parentType) {\r\n throw new Error(`Unknown type: ${fixedTypeName}`);\r\n }\r\n\r\n const delimiter = parentType.delimiter;\r\n const discOffset = parentType.discriminator;\r\n const objects: unknown[] = [];\r\n\r\n // Continue to iterate until end or delimiter is reached\r\n let delReached: boolean;\r\n while (!(delReached = this._blockReader.delimiterReached(delimiter))) {\r\n const startPosition = this._romDataReader.position;\r\n let targetType = parentType;\r\n\r\n // If a discriminator offset is present, use it to identify the type\r\n if (discOffset !== undefined) {\r\n // Get discriminator position in ROM\r\n const discPosition = this._romDataReader.position + discOffset;\r\n\r\n // Get discriminator value\r\n const desc = this._romDataReader.romData[discPosition];\r\n\r\n // Advance position (hide value) if discriminator is first\r\n if (discOffset === 0) {\r\n this._romDataReader.position++;\r\n }\r\n\r\n // Match discriminator to type\r\n const matchedStruct = Object.values(this._blockReader._root.structs).find(\r\n x => x.parent === fixedTypeName && x.discriminator === desc\r\n );\r\n targetType = matchedStruct || parentType; // Default to parent if no match is found\r\n }\r\n\r\n const types = targetType.types;\r\n if (types && types.length > 0) {\r\n const memberCount = types.length;\r\n const prevPosition = this._romDataReader.position;\r\n const parts = new Array(memberCount); // Create new member collection\r\n const def: StructDef = { name: targetType.name, parts };\r\n\r\n // Parse each member of the struct\r\n for (let i = 0; i < memberCount; i++) {\r\n parts[i] = this.parseType(types[i], reg, depth + 1, bank);\r\n }\r\n\r\n // Advance (hide) discriminator if it is the last member\r\n if (discOffset !== undefined && discOffset === this._romDataReader.position - prevPosition) {\r\n this._romDataReader.position++;\r\n }\r\n\r\n objects.push(def);\r\n }\r\n\r\n // Roll back work if struct overflows a chunk boundary\r\n // SHOULD only happen for the inventory sprite map\r\n let checkPosition = startPosition;\r\n while (++checkPosition < this._romDataReader.position) {\r\n const struct = this._referenceManager.tryGetStruct(checkPosition)\r\n if (struct.found && struct.chunkType !== 'Code') {\r\n this._romDataReader.position = checkPosition;\r\n break;\r\n }\r\n }\r\n\r\n // Stop if the reader should not continue\r\n if (!this._blockReader.partCanContinue()) {\r\n break;\r\n }\r\n }\r\n\r\n // If we have reached delimiter and at depth 0, note the struct\r\n if (delReached && depth === 0) {\r\n this._referenceManager.tryAddStruct(this._romDataReader.position, typeName);\r\n }\r\n\r\n return objects;\r\n }\r\n\r\n private tryParseMemberType(memberTypeName: string): MemberType | null {\r\n // Check if the string matches any MemberType enum value (case-insensitive)\r\n const upperName = memberTypeName.toUpperCase();\r\n for (const [key, value] of Object.entries(MemberType)) {\r\n if (key.toUpperCase() === upperName) {\r\n return value;\r\n }\r\n }\r\n return null;\r\n }\r\n\r\n private parseWordSafe(): number {\r\n return this._referenceManager.containsStruct(this._romDataReader.position + 1)\r\n ? this._romDataReader.readByte()\r\n : this._romDataReader.readUShort();\r\n }\r\n\r\n private parseBinary(size: number): Uint8Array {\r\n // Store old position for length calculation\r\n const startPosition = this._romDataReader.position;\r\n\r\n //Calculate length if it is not provided\r\n let len = 0;\r\n\r\n // Advance the reader until we reach the end of the section\r\n do {\r\n this._romDataReader.position++;\r\n len++;\r\n } while (len !== size && this._blockReader.partCanContinue());\r\n\r\n // Create buffer for the raw bytes\r\n const outBuffer = new Uint8Array(len);\r\n\r\n // Copy raw bytes from ROM to buffer\r\n for (let i = 0; i < len; i++) {\r\n outBuffer[i] = this._romDataReader.romData[startPosition + i];\r\n }\r\n\r\n return outBuffer;\r\n }\r\n\r\n private parseLocation(offset: number, bank: number | undefined, typeName: string | null, addrType: AddressType): unknown {\r\n // If bank is not provided and offset is 0, it should resolve to #$0000\r\n if ((bank === undefined || bank === null) && offset === 0) {\r\n return new Word(offset);\r\n }\r\n\r\n let adrs: Address;\r\n let loc: number;\r\n if(addrType === AddressType.Location) {\r\n loc = offset | (bank! << 16);\r\n //adrs = Address.fromInt(loc, this._blockReader._root.config.memoryMode);\r\n } else {\r\n // Bank cannot be null, instead use bank from current position\r\n const resolvedBank = bank ?? Address.resolveBank(this._romDataReader.position, this._blockReader._root.config.memoryMode);\r\n \r\n // Create the address with resolved bank\r\n adrs = new Address(resolvedBank, offset, this._blockReader._root.config.memoryMode);\r\n \r\n // If we have a system address, keep it as is\r\n if (!adrs.isROM) return adrs;\r\n \r\n // Convert address to ROM location\r\n loc = adrs.toLocation();\r\n }\r\n\r\n\r\n // If the location is inside the current block and there is no rewrite for it...\r\n if (\r\n //this._blockReader._currentChunk &&\r\n //ChunkFileUtils.isInside(this._blockReader._currentChunk, loc) &&\r\n typeName &&\r\n !this._blockReader._root.rewrites[loc]\r\n ) {\r\n // Normalize the type name to default to current part definition\r\n //const resolvedTypeName = typeName ?? this._blockReader._currentAsmBlock!.structName ?? 'Binary';\r\n\r\n // Add the struct type to our chunk table if it is not already present\r\n this._referenceManager.tryAddStruct(loc, typeName);\r\n\r\n // If the location is not already in the reference table, add it\r\n //const referenceName = `${resolvedTypeName.toLowerCase()}_${adrs.toString()}`;\r\n const referenceName = `${typeName.toLowerCase()}_${loc.toString(16).toUpperCase().padStart(6, '0')}`;\r\n this._referenceManager.tryAddName(loc, referenceName);\r\n }\r\n\r\n return new LocationWrapper(loc, addrType);\r\n }\r\n\r\n private parseCode(reg: Registers): Op[] {\r\n // Output list\r\n const opList: Op[] = [];\r\n\r\n let first = true;\r\n while (this._romDataReader.position < this._blockReader._partEnd) {\r\n // Check the chunk table for a new type block, but not on the first iteration\r\n if (first) {\r\n first = false;\r\n } else if (this._referenceManager.containsStruct(this._romDataReader.position)) {\r\n break;\r\n }\r\n\r\n // Process register adjustments before parse\r\n if (reg) {\r\n this._blockReader.hydrateRegisters(reg);\r\n }\r\n\r\n // Parse instruction\r\n const op = this._blockReader._asmReader.parseAsm(reg);\r\n\r\n // Add instruction to list\r\n opList.push(op);\r\n }\r\n\r\n return opList;\r\n }\r\n} ","import { Registers } from '../../assembly';\r\nimport { Op } from '../../types/assembly';\r\nimport { RomDataReader } from './reader';\r\nimport { ProcessorStateManager } from './processor';\r\nimport { ReferenceManager } from './references';\r\nimport { StringReader } from './strings';\r\nimport { AsmReader } from './asm';\r\nimport { TypeParser } from './parser';\r\nimport { \r\n Address, \r\n AddressType, \r\n LocationWrapper, \r\n StructDef, \r\n RegisterType,\r\n BlockReaderConstants,\r\n RomProcessingConstants,\r\n TableEntry,\r\n BinType,\r\n AsmBlock,\r\n createChunkFileFromDbFile,\r\n createChunkFileFromDbBlock,\r\n StatusFlags,\r\n} from '../../types';\r\nimport type { StringWrapper } from '../../types';\r\nimport type { DbRoot, DbFile } from '../../database';\r\nimport type { DbBlock } from '../../database';\r\nimport type { DbPart } from '../../database';\r\nimport { ChunkFile, ChunkFileUtils } from '../../types/files';\r\nimport { indexOfAny, saveFileAsBinary, saveFileAsText } from '../../utils';\r\nimport { BlockWriter } from './writer';\r\n\r\n/**\r\n * Central class for reading and analyzing ROM blocks\r\n * Converted from GaiaLib/Rom/Extraction/BlockReader.cs\r\n */\r\nexport class BlockReader {\r\n // Constants\r\n private static readonly REF_SEARCH_MAX_RANGE = 0x1A0;\r\n private static readonly BANK_MASK_CHECK = 0x40;\r\n private static readonly BYTE_DELIMITER_THRESHOLD = 0x100;\r\n private static readonly BANK_HIGH_MEMORY_1 = 0x7E;\r\n private static readonly BANK_HIGH_MEMORY_2 = 0x7F;\r\n private static readonly POINTER_CHARACTERS = ['&', '@'];\r\n\r\n // Location regex pattern: _([A-Fa-f0-9]{6})\r\n private static readonly LOCATION_REGEX = /_([A-Fa-f0-9]{6})/;\r\n\r\n // Core Dependencies\r\n public readonly _root: DbRoot;\r\n public readonly _stringReader: StringReader;\r\n public readonly _asmReader: AsmReader;\r\n public readonly _typeParser: TypeParser;\r\n public readonly _romDataReader: RomDataReader;\r\n public readonly _stateManager: ProcessorStateManager;\r\n public readonly _referenceManager: ReferenceManager;\r\n\r\n // Current Processing State (Database)\r\n //public _currentBlock!: DbBlock;\r\n //public _currentPart: DbPart | null = null;\r\n public _partEnd: number = 0;\r\n \r\n // ChunkFile Processing State\r\n public _currentChunk: ChunkFile | null = null;\r\n public _currentAsmBlock: AsmBlock | null = null;\r\n public _enrichedChunks: ChunkFile[] = [];\r\n\r\n constructor(romData: Uint8Array, root: DbRoot) {\r\n this._romDataReader = new RomDataReader(romData);\r\n this._stateManager = new ProcessorStateManager();\r\n this._referenceManager = new ReferenceManager(root);\r\n this._root = root;\r\n\r\n this._stringReader = new StringReader(this as any);\r\n this._asmReader = new AsmReader(this as any);\r\n this._typeParser = new TypeParser(this as any);\r\n\r\n this.initializeOverrides();\r\n this.initializeFileReferences();\r\n }\r\n\r\n /**\r\n * Processes predefined overrides for registers and bank notes\r\n */\r\n private initializeOverrides(): void {\r\n if(!this._root.overrides) return;\r\n for (const [location, overrides] of Object.entries(this._root.overrides)) {\r\n for (const [register, value] of Object.entries(overrides)) {\r\n switch (register) {\r\n case 'M':\r\n this._stateManager.get('statusFlags').setFlag(parseInt(location), StatusFlags.AccumulatorMode, value === 1);\r\n break;\r\n case 'X':\r\n this._stateManager.get('statusFlags').setFlag(parseInt(location), StatusFlags.IndexMode, value === 1);\r\n break;\r\n case 'B':\r\n this._stateManager.get('dataBank').set(parseInt(location), value);\r\n break;\r\n case 'type':\r\n this._referenceManager.tryAddStruct(parseInt(location), value);\r\n break;\r\n case 'name':\r\n this._referenceManager.tryAddName(parseInt(location), value);\r\n break;\r\n }\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * Processes predefined file references\r\n */\r\n private initializeFileReferences(): void {\r\n for (const file of this._root.files) {\r\n this._referenceManager.tryAddName(file.start, file.name);\r\n }\r\n }\r\n\r\n /**\r\n * Resolves mnemonic for a given address\r\n */\r\n public resolveMnemonic(addr: Address): void {\r\n // If the address is in high memory (ROM only), skip processing\r\n if ((addr.bank & Address.DATA_BANK_FLAG) !== 0) {\r\n return;\r\n }\r\n\r\n let offset = addr.offset;\r\n \r\n const label = this._root.mnemonics[offset];\r\n if (!label) {\r\n return;\r\n }\r\n\r\n const ix = indexOfAny(label, RomProcessingConstants.OPERATORS);\r\n if (ix >= 0) {\r\n let opnd = parseInt(label.substring(ix + 1), 16);\r\n const op = label[ix];\r\n if(op === '-')\r\n opnd = -opnd;\r\n \r\n offset -= opnd;\r\n }\r\n\r\n // Add to current block's mnemonics\r\n this._currentChunk!.mnemonics[offset] = label.substring(0, ix >= 0 ? ix : label.length);\r\n }\r\n\r\n /**\r\n * Resolves name for a location (delegated to ReferenceManager)\r\n */\r\n public resolveName(location: number, type: AddressType, isBranch: boolean): string {\r\n return this._referenceManager.resolveName(location, type, isBranch);\r\n }\r\n\r\n /**\r\n * Resolves include for a location\r\n */\r\n public resolveInclude(loc: number, isBranch: boolean): void {\r\n const [outside, foundBlock, foundPart] = ChunkFileUtils.isOutsideWithPart(this._enrichedChunks, this._currentChunk!, loc);\r\n if (outside && foundBlock && foundPart) {\r\n this._currentAsmBlock!.includes!.add({block: foundBlock, part: foundPart});\r\n } else if (isBranch && !this._referenceManager.tryGetName(loc).found) {\r\n // const adrs = Address.fromInt(loc, this._root.config.memoryMode);\r\n // const name = `loc_${adrs.toString()}`;\r\n const name = `loc_${loc.toString(16).toUpperCase().padStart(6, '0')}`;\r\n this._referenceManager.tryAddName(loc, name);\r\n }\r\n }\r\n\r\n /**\r\n * Notes a type at a location and manages chunk references\r\n */\r\n public noteType(loc: number, type: string, silent: boolean = false, reg?: Registers): string {\r\n this._referenceManager.tryAddStruct(loc, type);\r\n\r\n const nameResult = this._referenceManager.tryGetName(loc);\r\n let name: string;\r\n \r\n if (!nameResult.found) {\r\n name = this._referenceManager.createTypeName(type, loc);\r\n this._referenceManager.tryAddName(loc, name);\r\n } else {\r\n name = nameResult.referenceName!;\r\n }\r\n\r\n if (!silent && type === BlockReaderConstants.CODE_TYPE && reg) {\r\n this.updateRegisterState(loc, reg);\r\n }\r\n\r\n return name;\r\n }\r\n\r\n public updateRegisterState(loc: number, reg: Registers): void {\r\n for (const [key, value] of Object.entries(reg.value)) {\r\n if (value === undefined || value === null) continue;\r\n this._stateManager.get(key).tryAdd(loc, value);\r\n }\r\n // if (reg.accumulatorFlag !== undefined) {\r\n // this._stateManager.tryAddAccumulatorFlag(loc, reg.accumulatorFlag);\r\n // }\r\n // if (reg.indexFlag !== undefined) {\r\n // this._stateManager.tryAddIndexFlag(loc, reg.indexFlag);\r\n // }\r\n if (reg.stack.location > 0) {\r\n this._stateManager.tryAddStackPosition(loc, reg.stack.location);\r\n }\r\n }\r\n\r\n /**\r\n * Checks if a delimiter has been reached\r\n */\r\n public delimiterReached(delimiter?: number): boolean {\r\n if (delimiter === undefined) {\r\n return false;\r\n }\r\n\r\n if (delimiter >= BlockReaderConstants.BYTE_DELIMITER_THRESHOLD) {\r\n if (this._romDataReader.peekShort() === delimiter) {\r\n this._romDataReader.position += 2;\r\n return true;\r\n }\r\n } else if (this._romDataReader.peekByte() === delimiter) {\r\n this._romDataReader.position++;\r\n return true;\r\n }\r\n\r\n return false;\r\n }\r\n\r\n /**\r\n * Checks if processing of the current part can continue\r\n */\r\n public partCanContinue(): boolean {\r\n return this._romDataReader.position < this._partEnd && \r\n !this._referenceManager.containsStruct(this._romDataReader.position);\r\n }\r\n\r\n public analyzeAndResolve(): ChunkFile[] {\r\n this.createChunkFilesFromDatabase();\r\n this.initializeBlocksAndParts();\r\n this.analyzeChunkFiles();\r\n this.resolveReferences();\r\n \r\n return this._enrichedChunks;\r\n }\r\n\r\n /**\r\n * Analyzes all blocks in the ROM\r\n */\r\n // private analyzeBlocks(): void {\r\n // this.initializeBlocksAndParts();\r\n\r\n // for (const chunk of this._enrichedChunks) {\r\n // this._currentChunk = chunk;\r\n // for (const part of chunk.parts || []) {\r\n // this.processPart(part);\r\n // }\r\n // }\r\n // }\r\n\r\n /**\r\n * Initializes blocks and parts with base references\r\n */\r\n private initializeBlocksAndParts(): void {\r\n for (const block of this._enrichedChunks) {\r\n for (const part of block.parts || []) {\r\n if(part.structName) {\r\n this._referenceManager.tryAddStruct(part.location, part.structName);\r\n }\r\n if(part.label) {\r\n this._referenceManager.tryAddName(part.location, part.label);\r\n }\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * Processes a single part\r\n */\r\n private processPart(part: AsmBlock): void {\r\n this._currentAsmBlock = part;\r\n this._romDataReader.position = part.location;\r\n this._partEnd = part.location + part.size;\r\n\r\n let current = part.structName || BlockReaderConstants.BINARY_TYPE;\r\n const chunks: TableEntry[] = [];\r\n const reg = new Registers(this._root.config.memoryMode); //platform.createRegisters()\r\n const bank = part.bank;\r\n let last: TableEntry | null = null;\r\n\r\n while (this._romDataReader.position < this._partEnd) {\r\n const structResult = this._referenceManager.tryGetStruct(this._romDataReader.position);\r\n if (structResult.found) {\r\n current = structResult.chunkType!;\r\n } else if (last !== null && !this._root.stringTypes[current]) {\r\n this.processContinuousEntry(current, reg, bank, last);\r\n continue;\r\n }\r\n\r\n if(!this._referenceManager.nameTable.has(this._romDataReader.position)) {\r\n const name = this._referenceManager.createTypeName(current, this._romDataReader.position);\r\n this._referenceManager.nameTable.set(this._romDataReader.position, name);\r\n }\r\n last = new TableEntry(this._romDataReader.position);\r\n chunks.push(last);\r\n this.processNewEntry(current, reg, bank, last);\r\n }\r\n\r\n part.objList = chunks;\r\n }\r\n\r\n /**\r\n * Processes a continuous entry (same type as previous)\r\n */\r\n private processContinuousEntry(current: string, reg: Registers, bank: number | undefined, last: TableEntry): void {\r\n const obj = this._typeParser.parseType(current, reg, 0, bank);\r\n if (!Array.isArray(last.object)) {\r\n last.object = [last.object];\r\n }\r\n (last.object as unknown[]).push(obj);\r\n }\r\n\r\n /**\r\n * Processes a new entry\r\n */\r\n private processNewEntry(current: string, reg: Registers, bank: number | undefined, last: TableEntry): void {\r\n let res = this._typeParser.parseType(current, reg, 0, bank);\r\n if (BlockReaderConstants.POINTER_CHARACTERS.includes(current[0]) && !Array.isArray(res)) {\r\n res = [res];\r\n }\r\n last.object = res;\r\n }\r\n\r\n /**\r\n * Creates ChunkFile objects from database structure\r\n */\r\n private createChunkFilesFromDatabase(): void {\r\n // Clear any previous results\r\n this._enrichedChunks = [];\r\n this.createChunkFilesFromSfx();\r\n // Convert DbFiles to binary ChunkFiles with rawData\r\n this.createChunkFilesFromDbFiles();\r\n // Convert DbBlocks to assembly ChunkFiles with parts\r\n this.createChunkFilesFromDbBlocks();\r\n }\r\n\r\n /**\r\n * Creates binary ChunkFiles from DbFiles (enriched with rawData)\r\n */\r\n private createChunkFilesFromSfx(): void {\r\n let pos = this._root.config.sfxLocation;\r\n let offset = 0;\r\n const count = this._root.config.sfxCount;\r\n const romData = this._romDataReader.romData;\r\n const fileType = Object.values(this._root.fileTypes).find(x => x.type === BinType.Sound)!;\r\n\r\n const getByte = this._root.config.sfxType === 'Striped' ? () => {\r\n const byte = romData[pos + offset++];\r\n if(offset & RomProcessingConstants.PAGE_SIZE) offset += RomProcessingConstants.PAGE_SIZE;\r\n return byte;\r\n } : () => romData[pos + offset++];\r\n\r\n const getSize = () => getByte() | (getByte() << 8);\r\n\r\n const getBytes = this._root.config.sfxType === 'Striped' ? (size: number) => {\r\n let end = offset + size;\r\n let data: Uint8Array;\r\n if (end & RomProcessingConstants.PAGE_SIZE) {\r\n const endLen = end & 0x7FFF;\r\n size -= endLen;\r\n data = romData.slice(pos + offset, pos + offset + size);\r\n offset += size + RomProcessingConstants.PAGE_SIZE;\r\n end = offset + endLen;\r\n const data2 = romData.slice(pos + offset, pos + end);\r\n data = new Uint8Array([...data, ...data2]);\r\n } else {\r\n data = romData.slice(pos + offset, pos + end);\r\n }\r\n offset = end;\r\n return data;\r\n } : (size: number) => {\r\n const end = offset + size;\r\n const data = romData.slice(pos + offset, pos + end);\r\n offset = end;\r\n return data;\r\n }\r\n\r\n for (let i = 0; i < count; i++) {\r\n const size = getSize();\r\n const startPos = pos + offset;\r\n const data = getBytes(size);\r\n\r\n const chunk = new ChunkFile(`sfx${i.toString(16).toUpperCase().padStart(2, '0')}`, size, startPos, fileType);\r\n chunk.rawData = data;\r\n chunk.group = 'sfx';\r\n this._enrichedChunks.push(chunk);\r\n }\r\n }\r\n\r\n /**\r\n * Creates binary ChunkFiles from DbFiles (enriched with rawData)\r\n */\r\n private createChunkFilesFromDbFiles(): void {\r\n for (const dbFile of this._root.files) {\r\n const chunkFile = createChunkFileFromDbFile(this._romDataReader.romData, this._root.compression, dbFile, this._root.fileTypes[dbFile.type]);\r\n this._enrichedChunks.push(chunkFile);\r\n }\r\n }\r\n\r\n /**\r\n * Creates assembly ChunkFiles from DbBlocks (enriched with parts)\r\n */\r\n private createChunkFilesFromDbBlocks(): void {\r\n const fileType = Object.values(this._root.fileTypes).find(x => x.isBlock)!;\r\n for (const block of this._root.blocks) {\r\n const chunkFile = createChunkFileFromDbBlock(block, fileType, this._root.config.memoryMode);\r\n this._enrichedChunks.push(chunkFile);\r\n }\r\n }\r\n /**\r\n * Analyzes only assembly ChunkFiles (those with parts from DbBlocks)\r\n */\r\n private analyzeChunkFiles(): void {\r\n // Only process assembly ChunkFiles, skip binary ones\r\n const assemblyChunks = this._enrichedChunks.filter(chunk => chunk.type.type === 'Assembly');\r\n \r\n for (const chunkFile of assemblyChunks) {\r\n this._currentChunk = chunkFile;\r\n for (const asmBlock of chunkFile.parts || []) {\r\n this._currentAsmBlock = asmBlock;\r\n this.processPart(asmBlock);\r\n }\r\n }\r\n }\r\n\r\n // /**\r\n // * Processes a single AsmBlock (similar to processPart)\r\n // */\r\n // private processAsmBlock(asmBlock: AsmBlock): void {\r\n // this._romDataReader.position = asmBlock.location;\r\n // this._partEnd = asmBlock.location + asmBlock.size;\r\n\r\n // let current = asmBlock.structName || BlockReaderConstants.BINARY_TYPE;\r\n // const chunks: TableEntry[] = [];\r\n // const reg = new Registers();\r\n // const bank = this._currentAsmBlock?.bank;\r\n // let last: TableEntry | null = null;\r\n\r\n // while (this._romDataReader.position < this._partEnd) {\r\n // const structResult = this._referenceManager.tryGetStruct(this._romDataReader.position);\r\n // if (structResult.found) {\r\n // current = structResult.chunkType!;\r\n // } else if (last !== null) {\r\n // this.processContinuousEntry(current, reg, bank, last);\r\n // continue;\r\n // }\r\n\r\n // last = createTableEntry(this._romDataReader.position);\r\n // chunks.push(last);\r\n // this.processNewEntry(current, reg, bank, last);\r\n // }\r\n\r\n // asmBlock.objList = chunks;\r\n // }\r\n\r\n /**\r\n * Resolves references in assembly ChunkFiles only\r\n */\r\n private resolveReferences(): void {\r\n for (const chunkFile of this._enrichedChunks) {\r\n this._currentChunk = chunkFile;\r\n \r\n for (const asmBlock of chunkFile.parts || []) {\r\n this._currentAsmBlock = asmBlock;\r\n this.resolveObject(asmBlock.objList, false);\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * Resolves a single object and its references\r\n */\r\n private resolveObject(obj: unknown, isBranch: boolean): void {\r\n if(obj === undefined || obj === null) return;\r\n\r\n if (typeof obj === 'string') {\r\n // String objects don't need resolution\r\n return;\r\n }\r\n\r\n if (Array.isArray(obj)) {\r\n for (const o of obj) {\r\n this.resolveObject(o, isBranch);\r\n }\r\n return;\r\n }\r\n\r\n if (obj instanceof Address) {\r\n this.resolveMnemonic(obj);\r\n return;\r\n }\r\n\r\n if (typeof obj === 'number') {\r\n this.resolveInclude(obj, isBranch);\r\n return;\r\n }\r\n\r\n if (obj instanceof LocationWrapper) {\r\n this.resolveInclude(obj.location, isBranch);\r\n return;\r\n }\r\n\r\n if (obj instanceof TableEntry) {\r\n this.resolveObject(obj.object, isBranch);\r\n return;\r\n }\r\n\r\n if (obj instanceof Op) {\r\n this.resolveOperationObject(obj);\r\n return;\r\n }\r\n\r\n if (typeof obj === 'object') {\r\n if ('string' in obj && 'type' in obj) {\r\n // StringWrapper\r\n this._stringReader.resolveString(obj as StringWrapper, isBranch);\r\n return;\r\n }\r\n\r\n if ('name' in obj && 'parts' in obj) {\r\n // StructDef\r\n this.resolveObject((obj as StructDef).parts, isBranch);\r\n return;\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * Resolves references in an operation object\r\n */\r\n private resolveOperationObject(op: Op): void {\r\n const branch = this.isBranchOperation(op);\r\n for (const opnd of op.operands) {\r\n this.resolveObject(opnd, branch);\r\n }\r\n }\r\n\r\n /**\r\n * Checks if an operation is a branch operation\r\n */\r\n private isBranchOperation(op: Op): boolean {\r\n return op.mode === 'PCRelative' ||\r\n op.mode === 'PCRelativeLong' ||\r\n op.mnem[0] === 'J';\r\n }\r\n\r\n /**\r\n * Hydrates registers with stored state\r\n */\r\n public hydrateRegisters(reg: Registers): void {\r\n this._stateManager.hydrateRegisters(this._romDataReader.position, reg);\r\n }\r\n\r\n}","import { RomProcessingConstants } from '../../types/constants';\r\nimport { ChunkFile } from '../../types/files';\r\nimport { MemoryMapMode } from '../../types/addressing';\r\nimport type { DbConfig } from '../../database/config';\r\nimport type { DbRoot } from '../../database/root';\r\nimport { BinType } from '../../types/resources';\r\n\r\n/**\r\n * ROM layout planner\r\n * Converted from ext/GaiaLib/Rom/Rebuild/RomLayout.cs\r\n */\r\nexport class RomLayout {\r\n private static readonly MIN_ACCEPTED_REMAINING = 0x20;\r\n\r\n public readonly unmatchedFiles: ChunkFile[];\r\n private readonly bestResult: number[] = new Array(0x200).fill(0);\r\n private readonly bestSample: number[] = new Array(0x200).fill(0);\r\n\r\n private currentBank = 0;\r\n private currentUpper = false;\r\n private bestDepth = 0;\r\n private bestOffset = 0;\r\n private bestRemain = 0;\r\n private root: DbRoot;\r\n private config: DbConfig;\r\n private sfxPackType: string;\r\n public readonly sfxFiles: ChunkFile[] = [];\r\n\r\n constructor(files: ChunkFile[], root: DbRoot) {\r\n this.root = root;\r\n this.config = root.config;\r\n this.sfxPackType = root.config.sfxPack ?? root.config.sfxType;\r\n this.sfxFiles = this.sfxPackType !== 'Individual' ? files.filter(x => x.type.type === 'Sound')\r\n .sort((a, b) => {\r\n const aId = parseInt(a.name.substring(a.name.length - 2, a.name.length), 16);\r\n const bId = parseInt(b.name.substring(b.name.length - 2, b.name.length), 16);\r\n return aId - bId;\r\n }) : [];\r\n \r\n // Filter out zero-size files and order: assembly first, then by size desc\r\n this.unmatchedFiles = files.filter(x => (x.size || 0) > 0)\r\n .filter(x => this.sfxPackType === 'Individual' || x.type.type !== 'Sound')\r\n .sort((a, b) => {\r\n const aAsm = a.parts ? 0 : 1;\r\n const bAsm = b.parts ? 0 : 1;\r\n if (aAsm !== bAsm) return aAsm - bAsm;\r\n if (b.size !== a.size) return b.size - a.size;\r\n if (a.location !== b.location) return a.location - b.location;\r\n return a.name.localeCompare(b.name);\r\n });\r\n }\r\n\r\n public organize(): number {\r\n let stripeSfx = false;\r\n let page: number;\r\n const maxPages = this.config.memoryMode === MemoryMapMode.Hi ? 0x80 \r\n : this.config.memoryMode === MemoryMapMode.ExHi ? 0x100\r\n : 0x40;\r\n for (page = 0; page < maxPages; page++) {\r\n if (this.unmatchedFiles.length === 0) break;\r\n let start = page << 15; // 0x8000 per page\r\n let remain = RomProcessingConstants.PAGE_SIZE;\r\n \r\n if(start <= this.config.sfxLocation && start + remain > this.config.sfxLocation) {\r\n const gap = this.config.sfxLocation - start;\r\n //if(gap) do something\r\n\r\n if(this.sfxPackType === 'Sequential') {\r\n let offset = 0;\r\n for(const file of this.sfxFiles) {\r\n file.location = start + offset;\r\n console.log(` ${file.location.toString(16).toUpperCase().padStart(6, '0')}: ${file.name}`);\r\n offset += file.size;\r\n if(offset & RomProcessingConstants.PAGE_SIZE) {\r\n offset &= 0x7FFF;\r\n console.log(`Page ${start.toString(16).toUpperCase().padStart(6, '0')} matched with SFX files 0 remaining`);\r\n start += RomProcessingConstants.PAGE_SIZE;\r\n page++;\r\n }\r\n }\r\n console.log(`Page ${start.toString(16).toUpperCase().padStart(6, '0')} matched with SFX files ${remain} remaining`);\r\n start += offset;\r\n remain = RomProcessingConstants.PAGE_SIZE - offset;\r\n } else if(this.sfxPackType === 'Striped') {\r\n stripeSfx = true;\r\n }\r\n }\r\n\r\n if ((page === 0 && this.config.memoryMode === MemoryMapMode.Lo) ||\r\n (page === 1 && this.config.memoryMode === MemoryMapMode.Hi)) {\r\n remain -= RomProcessingConstants.SNES_HEADER_SIZE;\r\n }\r\n\r\n if(stripeSfx) {\r\n let offset = 0;\r\n while(remain > 0 && this.sfxFiles.length) {\r\n const file = this.sfxFiles.shift();\r\n if(!file) continue;\r\n file.location = start + offset;\r\n console.log(` ${file.location.toString(16).toUpperCase().padStart(6, '0')}: ${file.name}`);\r\n offset += file.size;\r\n if(offset & RomProcessingConstants.PAGE_SIZE) {\r\n offset &= 0x7FFF;\r\n console.log(`Page ${start.toString(16).toUpperCase().padStart(6, '0')} matched with SFX files 0 remaining`);\r\n start += RomProcessingConstants.PAGE_SIZE;\r\n page++;\r\n\r\n if(offset) {\r\n const newFile = new ChunkFile(file.name + \"_2\", file.size, file.location, Object.values(this.root.fileTypes).find(x => x.type === BinType.Binary)!);\r\n const end = file.rawData!.length - offset;\r\n newFile.rawData = file.rawData!.slice(end);\r\n newFile.size = newFile.rawData.length;\r\n this.sfxFiles.unshift(newFile);\r\n file.rawData = file.rawData!.slice(0, end);\r\n file.size -= offset;\r\n offset = 0;\r\n }\r\n remain = RomProcessingConstants.PAGE_SIZE;\r\n break;\r\n } else {\r\n remain -= file.size;\r\n }\r\n }\r\n start += offset;\r\n if(!this.sfxFiles.length) {\r\n stripeSfx = false;\r\n }\r\n\r\n }\r\n \r\n this.currentUpper = this.config.memoryMode === MemoryMapMode.Lo || (page & 1) !== 0;\r\n this.currentBank = this.config.memoryMode === MemoryMapMode.Lo ? page : (page >> 1);\r\n this.bestDepth = 0;\r\n this.bestRemain = remain;\r\n this.bestOffset = 0;\r\n\r\n // Pass 1: assembly preferred in upper banks\r\n this.testDepth(0, 0, remain, this.currentUpper);\r\n\r\n // Pass 2: if upper, also try binary-only fill\r\n if (this.currentUpper) {\r\n this.bestOffset = this.bestDepth;\r\n this.testDepth(0, this.bestDepth, this.bestRemain, false);\r\n }\r\n\r\n // Assign positions for best selection\r\n let position = start;\r\n for (let i = 0; i < this.bestDepth;) {\r\n const file = this.unmatchedFiles[this.bestResult[i++]];\r\n file.location = position;\r\n console.log(` ${position.toString(16).toUpperCase().padStart(6, '0')}: ${file.name}`);\r\n position += file.size;\r\n }\r\n\r\n console.log(`Page ${start.toString(16).toUpperCase().padStart(6, '0')} matched with ${this.bestDepth} files ${this.bestRemain} remaining`);\r\n // Commit: remove placed files from queue\r\n this.commitPage();\r\n }\r\n\r\n if (this.unmatchedFiles.length > 0) {\r\n const names = this.unmatchedFiles.map(x => x.name).join('\\r\\n');\r\n throw new Error(`Unable to match ${this.unmatchedFiles.length} files\\r\\n${names}`);\r\n }\r\n\r\n return page;\r\n }\r\n\r\n private testDepth(startIndex: number, depth: number, remain: number, asmMode: boolean): boolean {\r\n for (let fileIndex = startIndex; fileIndex < this.unmatchedFiles.length; fileIndex++) {\r\n const file = this.unmatchedFiles[fileIndex];\r\n\r\n const fileSize = file.size || 0;\r\n if (fileSize > remain) continue;\r\n\r\n // Assembly preference and constraints\r\n if (file.parts) {\r\n if (!asmMode) {\r\n if (!this.currentUpper || ((file.bank ?? -1) >= 0)) continue;\r\n } else if (file.bank !== this.currentBank) {\r\n continue;\r\n }\r\n } else if (asmMode) {\r\n continue;\r\n } else if (file.upper && !this.currentUpper) {\r\n continue;\r\n }\r\n\r\n // Skip if already selected in first pass window\r\n let inList = false;\r\n for (let y = this.bestOffset; --y >= 0;) {\r\n if (this.bestResult[y] === fileIndex) {\r\n inList = true;\r\n break;\r\n }\r\n }\r\n if (inList) continue;\r\n\r\n // Try this file at current depth\r\n this.bestSample[depth] = fileIndex;\r\n const newRemain = remain - fileSize;\r\n\r\n if (newRemain < this.bestRemain) {\r\n this.bestRemain = newRemain;\r\n this.bestDepth = depth + 1;\r\n for (let i = this.bestOffset; i < this.bestDepth; i++) {\r\n this.bestResult[i] = this.bestSample[i];\r\n }\r\n }\r\n\r\n if (newRemain < RomLayout.MIN_ACCEPTED_REMAINING) return true;\r\n\r\n if (this.testDepth(fileIndex + 1, depth + 1, newRemain, asmMode)) return true;\r\n }\r\n return true;\r\n }\r\n\r\n private commitPage(): void {\r\n if (this.bestOffset > 0) {\r\n for (let i = this.bestDepth; --i >= 0;) {\r\n let lastY = 0;\r\n let lastX = 0;\r\n let y = 0;\r\n for (let x = this.bestDepth; --x >= 0;) {\r\n y = this.bestResult[x];\r\n if (y > lastY) {\r\n lastY = y;\r\n lastX = x;\r\n }\r\n }\r\n this.bestResult[lastX] = 0;\r\n this.unmatchedFiles.splice(lastY, 1);\r\n }\r\n } else {\r\n for (let i = this.bestDepth; --i >= 0;) {\r\n this.unmatchedFiles.splice(this.bestResult[i], 1);\r\n }\r\n }\r\n }\r\n}\r\n\r\n\r\n\r\n","import { BinType } from '../../types/resources';\r\nimport { ChunkFileUtils, type ChunkFile } from '../../types/files';\r\nimport { RomLayout } from './layout';\r\nimport { RomWriter } from './writer';\r\nimport { Assembler } from '../..';\r\nimport { DbRoot } from '../../database';\r\nimport { AsmBlock } from '../../types/assembly';\r\n\r\n/**\r\n * ROM rebuild processor\r\n * Converted from ext/GaiaLib/Rom/Rebuild/RomProcessor.cs\r\n */\r\nexport class RomProcessor {\r\n private readonly writer: RomWriter;\r\n\r\n constructor(writer: RomWriter) {\r\n this.writer = writer;\r\n }\r\n\r\n public async repack(allFiles: ChunkFile[]): Promise<Map<string, number>> {\r\n // Discover files\r\n //const allFiles = await this.discoverFiles(this.writer._projectRoot.baseDir);\r\n\r\n const patches : ChunkFile[] = [];\r\n const asmFiles : ChunkFile[] = [];\r\n const compression = this.writer.root.compression;\r\n const canCompress = !!compression;\r\n const conditionFiles : string[] = [];\r\n\r\n for (const file of allFiles) {\r\n if (file.type.type === \"Patch\") {\r\n patches.push(file);\r\n } else if (file.type.type !== \"Assembly\") {\r\n if(file.compressed === true && canCompress) {\r\n if(this.writer.root.config.uncompress){\r\n file.compressed = false;\r\n } else {\r\n let newData = compression!.compact(file.rawData!, file.type.header);\r\n if(file.type.header) newData = new Uint8Array([...file.rawData!.slice(0, file.type.header), ...newData]);\r\n file.rawData = newData;\r\n file.size = newData.length;\r\n }\r\n }\r\n continue;\r\n }\r\n \r\n asmFiles.push(file);\r\n conditionFiles.push(file.name);\r\n }\r\n\r\n for(const file of asmFiles) {\r\n const assembler = new Assembler(this.writer.root, file.textData!, conditionFiles);\r\n const { blocks, includes, reqBank } = assembler.parseAssembly();\r\n file.parts = blocks;\r\n file.includes = includes;\r\n file.bank = reqBank ?? void 0;\r\n }\r\n\r\n // const patches = allFiles.filter(x => x.type.type === 'Patch');\r\n // const asmFiles = allFiles.filter(x => !!x.parts);\r\n\r\n // //Assemble code that hasn't been assembled yet\r\n // for(const asm of asmFiles) {\r\n // if(!asm.parts) {\r\n // const assembler = new Assembler(this.writer.root, asm.textData!);\r\n // const { blocks, includes, reqBank } = assembler.parseAssembly();\r\n // asm.parts = blocks;\r\n // asm.includes = includes;\r\n // asm.bank = reqBank ?? undefined;\r\n // }\r\n // }\r\n\r\n // Assembly processing now happens in project.ts via ChunkBlockReader.analyzeAndResolveChunks()\r\n // This provides comprehensive cross-referencing and object graph generation\r\n\r\n // Apply patches to asm blocks\r\n RomProcessor.applyPatches(asmFiles, patches);\r\n\r\n // Calculate ASM sizes\r\n for (const file of allFiles) {\r\n ChunkFileUtils.calculateSize(file);\r\n }\r\n\r\n // Assign locations\r\n const layout = new RomLayout(allFiles, this.writer.root);\r\n const pages = layout.organize();\r\n\r\n // Rebase assemblies\r\n for (const file of asmFiles) {\r\n ChunkFileUtils.rebase(file);\r\n }\r\n\r\n const masterLookup = new Map<string, number>();\r\n\r\n // Build include lookup map per asm file\r\n for (const f of asmFiles) {\r\n const includeBlocks = asmFiles\r\n .filter(x => f.includes?.has(x.name.toUpperCase()))\r\n .flatMap(x => x.parts!)\r\n .filter(b => !!b.label);\r\n\r\n f.includeLookup = new Map<string, AsmBlock>();\r\n\r\n //Add labels from include blocks\r\n for (const b of includeBlocks) {\r\n if (b.label) f.includeLookup.set(b.label.toUpperCase(), b);\r\n }\r\n\r\n //Add labels from current file\r\n for (const b of f.parts!) {\r\n if(b.label) {\r\n const nameUpper = b.label.toUpperCase();\r\n masterLookup.set(nameUpper, b.location);\r\n f.includeLookup.set(nameUpper, b);\r\n }\r\n }\r\n }\r\n\r\n // Create block lookup for resolving labels to locations\r\n const fileLookup = new Map<string, number>();\r\n for (const f of allFiles) fileLookup.set(f.name.toUpperCase(), f.location);\r\n \r\n //Allocate memory for the ROM\r\n this.writer.allocate(pages);\r\n\r\n // Write all files\r\n for (const file of allFiles) {\r\n await this.writer.writeFile(file, fileLookup);\r\n }\r\n\r\n return masterLookup;\r\n }\r\n\r\n public static applyPatches(asmFiles: ChunkFile[], patches: ChunkFile[]): void {\r\n for (const patch of patches.filter(x => x.includes && x.includes.size > 0)) {\r\n let file: ChunkFile | null = null;\r\n let dstIx = -1;\r\n const inc = asmFiles.filter(x => patch.includes!.has(x.name.toUpperCase()));\r\n for (let ix = 0; patch.parts && ix < patch.parts.length;) {\r\n const block = patch.parts[ix];\r\n let match: any = null;\r\n if (block.label) { \r\n for (const i of inc) {\r\n if (!i.parts) continue;\r\n for (let y = 0; y < i.parts.length; y++) {\r\n const check = i.parts[y];\r\n if (check.label === block.label) {\r\n file = i; \r\n dstIx = y; \r\n match = check;\r\n break;\r\n }\r\n }\r\n }\r\n }\r\n if (match) {\r\n file!.parts![dstIx++] = block;\r\n } else if (dstIx >= 0) {\r\n file!.parts!.splice(dstIx++, 0, block);\r\n } else { ix++; continue; }\r\n file!.includes = file!.includes || new Set();\r\n file!.includes.add(patch.name.toUpperCase());\r\n patch.parts!.splice(ix, 1);\r\n }\r\n }\r\n }\r\n}\r\n\r\n\r\n","import { \r\n BinType, \r\n AddressType, \r\n Address, \r\n RomProcessingConstants,\r\n ChunkFile, \r\n AsmBlock, \r\n StringMarker,\r\n TableEntry,\r\n Byte,\r\n Word,\r\n Long,\r\n TypedNumber\r\n} from '../../types';\r\nimport { DbEntryPoint, DbHeader, DbRoot } from '../../database';\r\nimport { RomProcessor as RebuildProcessor } from './processor';\r\nimport { Op } from '../../types/assembly';\r\nimport { CpuMode, MemoryMapMode } from '../../types/addressing';\r\n//import { ConditionBlock } from './assembler';\r\n/**\r\n * ROM writer (binary)\r\n * Converted from ext/GaiaLib/Rom/Rebuild/RomWriter.cs (subset: binary write only)\r\n */\r\nexport class RomWriter {\r\n public bpsPath?: string;\r\n public outBuffer?: Uint8Array;\r\n private romSize? : number;\r\n public readonly root: DbRoot;\r\n\r\n constructor(root: DbRoot) {\r\n this.root = root;\r\n }\r\n\r\n public async repack(files: ChunkFile[]): Promise<Uint8Array> {\r\n const processor = new RebuildProcessor(this);\r\n const masterLookup = await processor.repack(files);\r\n\r\n this.writeHeaders(masterLookup);\r\n\r\n //await this.generatePatch();\r\n return this.outBuffer!;\r\n }\r\n\r\n public allocate(pages: number): void {\r\n const size = pages * RomProcessingConstants.PAGE_SIZE;\r\n let bits = 0;\r\n let target = 1 << 10; // 1KB\r\n\r\n while(target < size) {\r\n target <<= 1;\r\n bits++;\r\n }\r\n\r\n this.romSize = bits;\r\n this.outBuffer = new Uint8Array(target);\r\n }\r\n\r\n public writeHeaders(masterLookup: Map<string, number>): void {\r\n const values = this.prepareHeaderValues();\r\n for (const header of this.root.headers) {\r\n if(header.condition && !eval(header.condition)) continue;\r\n this.writeHeader(header, values, masterLookup);\r\n }\r\n this.writeChecksum(values);\r\n }\r\n\r\n public prepareHeaderValues(): any {\r\n const values = { ...this.root.config } as any;\r\n values.romSize = this.romSize;\r\n values.checksum = 0;\r\n values.compliment = 0xFFFF;\r\n values.mapMode = 0x20 \r\n | (values.cpuMode === CpuMode.Fast ? 0x10 : 0x00)\r\n | (values.memoryMode === MemoryMapMode.Hi ? 1 : values.memoryMode === MemoryMapMode.ExHi ? 5 : 0);\r\n return values;\r\n }\r\n\r\n\r\n public writeHeader(header: DbHeader, values: any, masterLookup: Map<string, number>): void {\r\n const buf = this.outBuffer!;\r\n \r\n let pos = new Address(header.bank, header.address, this.root.config.memoryMode).toLocation();\r\n\r\n for (const part of header.parts) {\r\n let type = part.type;\r\n let value = part.value ?? values[part.name] ?? (type === 'string' ? '' : 0);\r\n let size = part.size;\r\n\r\n if(!size) {\r\n if(!type) {\r\n //Try to infer the type/size from the value\r\n if(typeof value === 'string') throw new Error(`String size for ${part.name} is not specified`);\r\n if(typeof value === 'number') {\r\n if(value <= 0xFF) {\r\n size = 1;\r\n type = 'byte';\r\n }\r\n else {\r\n size = 2;\r\n type = 'word';\r\n }\r\n }\r\n } else {\r\n switch(type) {\r\n case 'byte': size = 1; break;\r\n case 'word': case 'entry': size = 2; break;\r\n case 'string': throw new Error(`String size for ${part.name} is not specified`); break;\r\n default: throw new Error(`Invalid type ${type} for ${part.name}`);\r\n }\r\n }\r\n }\r\n\r\n switch(part.type) {\r\n case 'string':\r\n value = value.toString();\r\n value = value.length > size ? value.substring(0, size) : value.padEnd(size, ' ');\r\n this.writeAscii(value, pos);\r\n break;\r\n\r\n case 'byte':\r\n buf[pos] = value & 0xFF;\r\n break;\r\n\r\n case 'entry':\r\n let location = 0;\r\n if(typeof value === 'string') {\r\n location = value === '' ? 0 : masterLookup.get(value.toUpperCase()) ?? 0;\r\n } else if(typeof value === 'number') {\r\n location = value;\r\n }\r\n value = location;\r\n\r\n case 'word':\r\n buf[pos] = value & 0xFF;\r\n buf[pos + 1] = (value >> 8) & 0xFF;\r\n break;\r\n\r\n }\r\n\r\n part.value = value;\r\n part.size = size;\r\n part.type = type;\r\n\r\n pos += size;\r\n }\r\n\r\n // //let pos = this.root.config.memoryMode === MemoryMapMode.Lo ? 0x7FB0 : 0xFFB0;\r\n // this.writeAscii(this.makerCode.padEnd(6, ' '), pos); \r\n // pos += 6;\r\n // for (let i = 0; i < 10; i++) buf[pos++] = 0;\r\n // this.writeAscii(this.cartName.toUpperCase().padEnd(21, ' '), pos); \r\n // pos += 21;\r\n // buf[pos++] = 0x20 // map mode\r\n // | (this.root.config.cpuMode === CpuMode.Fast ? 0x10 : 0x00)\r\n // | (this.root.config.memoryMode === MemoryMapMode.Hi ? 1 : this.root.config.memoryMode === MemoryMapMode.ExHi ? 5 : 0);\r\n // buf[pos++] = this.root.config.chipset; // chipset\r\n // buf[pos++] = this.romSize!; // ROM size\r\n // buf[pos++] = this.root.config.ramSize; // RAM size\r\n // buf[pos++] = 0x01; // country\r\n // buf[pos++] = 0x33; // dev id\r\n // buf[pos++] = 0x00; // version\r\n }\r\n\r\n public writeChecksum(values: any): void {\r\n const buf = this.outBuffer!;\r\n\r\n let sum = 0;\r\n for (let i = 0; i < buf.length; i++) sum += buf[i];\r\n\r\n const comp = ~sum;\r\n\r\n for(const header of this.root.headers) {\r\n if(header.condition && !eval(header.condition)) continue;\r\n let pos = new Address(header.bank, header.address, this.root.config.memoryMode).toLocation();\r\n for(const part of header.parts) {\r\n if(part.name === 'checksum') {\r\n buf[pos] = sum & 0xFF;\r\n buf[pos + 1] = (sum >> 8) & 0xFF;\r\n } else if(part.name === 'compliment') {\r\n buf[pos] = comp & 0xFF;\r\n buf[pos + 1] = (comp >> 8) & 0xFF;\r\n }\r\n pos += part.size;\r\n }\r\n }\r\n \r\n // const buf = this.outBuffer!;\r\n // let pos = new Address(0, 0xFFDC, this.root.config.memoryMode).toLocation();\r\n \r\n // //Zero out the checksum location\r\n // buf[pos] = 0xFF;\r\n // buf[pos + 1] = 0xFF;\r\n // buf[pos + 2] = 0;\r\n // buf[pos + 3] = 0;\r\n\r\n // // checksum\r\n // let sum = 0;\r\n // for (let i = 0; i < buf.length; i++) sum += buf[i];\r\n\r\n // // complement at 0xFFDC\r\n // const comp = ~sum;\r\n // buf[pos] = comp & 0xFF;\r\n // buf[pos + 1] = (comp >> 8) & 0xFF;\r\n\r\n // // checksum at 0xFFDE\r\n // buf[pos + 2] = sum & 0xFF;\r\n // buf[pos + 3] = (sum >> 8) & 0xFF;\r\n }\r\n\r\n // private async generatePatch(): Promise<void> {\r\n // const flips = this._projectRoot.flipsPath;\r\n // if (!flips) return;\r\n // if (typeof process === 'undefined' || !process.versions?.node) return;\r\n // const { spawn } = await import('child_process');\r\n // const { resolve } = await import('path');\r\n // this.bpsPath = `${this._projectRoot.baseDir}/${this._projectRoot.name}.bps`;\r\n // await new Promise<void>((resolvePromise) => {\r\n // const p = spawn(flips, ['--create', '--bps', `${this._projectRoot.romPath}`, `${this.romPath}`, `${this.bpsPath}`], {\r\n // stdio: ['ignore', 'pipe', 'pipe']\r\n // });\r\n // p.on('close', () => resolvePromise());\r\n // });\r\n // }\r\n\r\n public writeEntryPoints(asmFiles: ChunkFile[]): void {\r\n const buf = this.outBuffer!;\r\n \r\n // Entry point fixups\r\n const entryBlocks = (asmFiles\r\n .filter(x => (x.bank ?? -1) === 0)\r\n .flatMap(x => x.parts || [])\r\n .filter(b => !!b.label)) as { label?: string; location: number }[];\r\n\r\n for (const ep of this.root.config.entryPoints) {\r\n const match = entryBlocks.find(b => b.label === ep.name);\r\n if (match) {\r\n let location = match.location;\r\n if(this.root.config.memoryMode === MemoryMapMode.Lo) location += RomProcessingConstants.PAGE_SIZE;\r\n buf[ep.location] = location & 0xFF;\r\n buf[ep.location + 1] = (location >> 8) & 0xFF;\r\n }\r\n }\r\n }\r\n\r\n // public writeTransform(location: number, value: number, size?: number): void {\r\n // const buf = this.outBuffer!;\r\n\r\n // // Determine size based on value range if not explicitly provided\r\n // if (size === undefined) {\r\n // if (value <= 0xFF) {\r\n // size = 1; // byte\r\n // } else if (value <= 0xFFFF) {\r\n // size = 2; // ushort \r\n // } else if (value <= 0xFFFFFF) {\r\n // size = 3; // uint (3 bytes)\r\n // } else {\r\n // size = 4; // full uint (4 bytes, though C# version only uses 3)\r\n // }\r\n // }\r\n\r\n // // Write bytes based on size\r\n // switch (size) {\r\n // case 1: // byte\r\n // buf[location] = value & 0xFF;\r\n // break;\r\n // case 2: // ushort\r\n // buf[location] = value & 0xFF;\r\n // buf[location + 1] = (value >> 8) & 0xFF;\r\n // break;\r\n // case 3: // uint (3 bytes as per C# version)\r\n // buf[location] = value & 0xFF;\r\n // buf[location + 1] = (value >> 8) & 0xFF;\r\n // buf[location + 2] = (value >> 16) & 0xFF;\r\n // break;\r\n // case 4: // full uint\r\n // buf[location] = value & 0xFF;\r\n // buf[location + 1] = (value >> 8) & 0xFF;\r\n // buf[location + 2] = (value >> 16) & 0xFF;\r\n // buf[location + 3] = (value >> 24) & 0xFF;\r\n // break;\r\n // default:\r\n // throw new Error(`Invalid size ${size} for writeTransform`);\r\n // }\r\n // }\r\n\r\n public async writeFile(file: ChunkFile, fileLookup: Map<string, number>): Promise<number> {\r\n const start = file.location;\r\n let pos = start;\r\n const buf = this.outBuffer!;\r\n\r\n if (file.rawData) {\r\n // Write type-specific headers\r\n const data = file.rawData;\r\n let remain = file.size;\r\n let srcPos = 0;\r\n\r\n if (file.compressed !== true) {\r\n if (file.type.header === -2) {\r\n remain -= 2;\r\n buf[pos++] = remain & 0xFF;\r\n buf[pos++] = (remain >> 8) & 0xFF;\r\n } else if (file.type.header > 0) {\r\n remain -= file.type.header;\r\n for (let i = 0; i < file.type.header; i++) buf[pos++] = data[srcPos++];\r\n }\r\n }\r\n\r\n //Write null compression header\r\n if (file.compressed === false) {\r\n remain -= 2;\r\n const size = (0 - remain) & 0xFFFF;\r\n buf[pos++] = size & 0xFF;\r\n buf[pos++] = (size >> 8) & 0xFF;\r\n }\r\n\r\n // Copy the rest\r\n while (remain > 0) {\r\n buf[pos++] = data[srcPos++];\r\n remain--;\r\n }\r\n } else {\r\n // Handle assembly parts\r\n if (file.parts && file.parts.length > 0) {\r\n // For safety, ensure first block location matches file location when present\r\n if (file.parts[0].location !== file.location && (file.location || 0) !== 0) {\r\n throw new Error('Assembly was not based properly');\r\n }\r\n \r\n // Parse assembly parts\r\n this.parseAssembly(file.parts, fileLookup, file.includeLookup!);\r\n }\r\n }\r\n\r\n return pos - start;\r\n }\r\n\r\n // No address mapping required: layout assigns absolute file offsets\r\n\r\n private writeAscii(text: string, pos: number): void {\r\n const buf = this.outBuffer!;\r\n for (let i = 0; i < text.length; i++) buf[pos + i] = text.charCodeAt(i) & 0xFF;\r\n }\r\n\r\n /**\r\n * Parse assembly blocks and write binary data to output buffer\r\n * Converted from ext/GaiaLib/Rom/Rebuild/RomWriter.cs ParseAssembly method\r\n */\r\n private parseAssembly(blocks: AsmBlock[], fileLookup: Map<string, number>, includeLookup: Map<string, AsmBlock>): void {\r\n if (!blocks) {\r\n throw new Error('Assembly has not been parsed');\r\n }\r\n\r\n const buf = this.outBuffer!;\r\n\r\n let bix = 0;\r\n // let inCondition = false;\r\n // let exitCondition = false;\r\n\r\n for (const block of blocks) {\r\n\r\n // if(inCondition) {\r\n // if(block instanceof ConditionBlock) {\r\n // if(exitCondition) continue;\r\n // if(block.condition) {\r\n // if(!fileLookup.has(block.condition) && !includeLookup.has(block.condition)) continue;\r\n // exitCondition = true; //If condition passes, set exit flag\r\n // } else inCondition = false;\r\n // } else {\r\n // inCondition = false;\r\n // exitCondition = false;\r\n // }\r\n // } else if(block instanceof ConditionBlock) {\r\n // inCondition = true;\r\n // exitCondition = false;\r\n // if(!fileLookup.has(block.condition) && !includeLookup.has(block.condition)) continue;\r\n // exitCondition = true;\r\n // }\r\n\r\n let oldPos: number | null = null;\r\n let position = block.location; // Always start at block's absolute location\r\n \r\n // Note: C# version had position management logic, but we always use block.location\r\n\r\n const objList = block.objList;\r\n let oix = 0;\r\n let opos = 0;\r\n\r\n // Process each object in the block's object list\r\n const processObject = (obj: unknown, parentOp?: Op): void => {\r\n let currentObj = obj;\r\n\r\n while (true) { // Top: label equivalent\r\n if (Array.isArray(currentObj)) {\r\n for (const obj of currentObj) {\r\n processObject(obj, parentOp);\r\n }\r\n break;\r\n } else if (currentObj instanceof TableEntry) {\r\n currentObj = currentObj.object;\r\n continue;\r\n } else if (currentObj instanceof Op) {\r\n const op = currentObj as Op;\r\n buf[position++] = op.code & 0xFF;\r\n opos += op.size;\r\n\r\n for (const operand of op.operands) {\r\n processObject(operand, op);\r\n }\r\n break;\r\n } else if (currentObj instanceof Uint8Array) {\r\n const arr = currentObj as Uint8Array;\r\n for (let i = 0; i < arr.length; i++) {\r\n buf[position + i] = arr[i];\r\n }\r\n position += arr.length;\r\n opos += arr.length;\r\n break;\r\n } else if (typeof currentObj === 'string') {\r\n const str = currentObj as string;\r\n let label = str;\r\n\r\n let ix = 0;\r\n while (ix < label.length && RomProcessingConstants.ADDRESS_SPACE.includes(label[ix])) {\r\n ix++;\r\n }\r\n\r\n if (ix > 0) {\r\n label = label.substring(ix);\r\n }\r\n\r\n let loc: number;\r\n const isRelative = parentOp && \r\n (parentOp.mode === 'PCRelative' || \r\n parentOp.mode === 'PCRelativeLong');\r\n\r\n const operatorIdx = this.indexOfAny(label, RomProcessingConstants.OPERATORS);\r\n let offset: number | null = null;\r\n let useMarker = false;\r\n\r\n if (operatorIdx > 0) {\r\n if (label[operatorIdx + 1] === 'M') {\r\n useMarker = true;\r\n } else {\r\n offset = parseInt(label.substring(operatorIdx + 1), 16);\r\n if (label[operatorIdx] === '-') {\r\n offset = -offset;\r\n }\r\n }\r\n label = label.substring(0, operatorIdx);\r\n }\r\n\r\n // Search local labels first\r\n const labelUpper = label.toUpperCase();\r\n let target: AsmBlock | null = null;\r\n\r\n if(includeLookup.has(labelUpper)) {\r\n target = includeLookup.get(labelUpper)!;\r\n loc = target.location;\r\n } else if(fileLookup.has(labelUpper)) {\r\n loc = fileLookup.get(labelUpper)!;\r\n } else {\r\n // Handle direct hex values\r\n if (label.startsWith('#')) {\r\n label = label.substring(1);\r\n }\r\n if (label.startsWith('$')) {\r\n label = label.substring(1);\r\n }\r\n\r\n if (isRelative && label.length > 4) {\r\n throw new Error(`Invalid relative operand '${label}'`);\r\n //const off = parseInt(label, 16) - (block.location + opos);\r\n //currentObj = parentOp?.size === 2 ? (off & 0xFF) : (off & 0xFFFF);\r\n //continue; // goto Top\r\n } else {\r\n let num: number;\r\n switch (label.length) {\r\n case 1:\r\n case 2:\r\n currentObj = new Byte(parseInt(label, 16));\r\n continue;\r\n case 3:\r\n case 4:\r\n currentObj = new Word(parseInt(label, 16));\r\n continue;\r\n case 5:\r\n case 6:\r\n currentObj = new Long(parseInt(label, 16));\r\n continue;\r\n default:\r\n throw new Error(`Invalid operand '${label}'`);\r\n }\r\n }\r\n }\r\n\r\n let type = isRelative ? (parentOp?.size === 3 ? AddressType.WRelative : AddressType.Relative) : Address.typeFromCode(str[0]);\r\n if (type === AddressType.Unknown) {\r\n type = parentOp?.size === 4 ? AddressType.Address\r\n : parentOp?.size === 2 ? AddressType.Unknown : AddressType.Offset;\r\n }\r\n\r\n if (isRelative) {\r\n loc -= block.location + opos;\r\n if (type === AddressType.Unknown && !(loc < 0x80 || loc >= 0x3FFF80)) {\r\n throw new Error('Relative out of range');\r\n }\r\n }\r\n\r\n if (offset !== null) {\r\n loc += offset;\r\n } else if (useMarker && target instanceof AsmBlock) {\r\n let markerOffset = 0;\r\n for (const part of target.objList) {\r\n if (this.isStringMarker(part)) {\r\n loc += markerOffset;\r\n break;\r\n } else {\r\n markerOffset += RomProcessingConstants.getSize(part);\r\n }\r\n }\r\n }\r\n\r\n if(!isRelative && type !== AddressType.Location) {\r\n const address = Address.fromLocation(loc, this.root.config.memoryMode, this.root.config.cpuMode);\r\n loc = address.toInt();\r\n }\r\n\r\n switch (type) {\r\n case AddressType.Offset:\r\n case AddressType.WRelative:\r\n currentObj = new Word(loc);\r\n continue;\r\n case AddressType.Bank:\r\n currentObj = new Byte(loc >> 16);\r\n continue;\r\n case AddressType.WBank:\r\n currentObj = new Word(loc >> 16);\r\n continue;\r\n case AddressType.Address:\r\n case AddressType.Location:\r\n currentObj = new Long(loc);\r\n continue;\r\n case AddressType.Unknown:\r\n case AddressType.Relative:\r\n default:\r\n currentObj = new Byte(loc);\r\n continue;\r\n }\r\n \r\n } else if (currentObj instanceof TypedNumber) {\r\n let value = currentObj.value;\r\n for (let i = 0; i < currentObj.size; i++) {\r\n buf[position++] = value & 0xFF;\r\n value >>= 8;\r\n }\r\n break;\r\n } else if (typeof currentObj === 'number') {\r\n const num = currentObj as number;\r\n const size = parentOp?.size ?? 0;\r\n \r\n if (num <= 0xFF && size <= 2) {\r\n // byte\r\n buf[position] = num & 0xFF;\r\n position++;\r\n } else if (num <= 0xFFFF && size <= 3) {\r\n // ushort\r\n buf[position] = num & 0xFF;\r\n buf[position + 1] = (num >> 8) & 0xFF;\r\n position += 2;\r\n } else if (num <= 0xFFFFFF && size <= 4) {\r\n // 3-byte\r\n buf[position] = num & 0xFF;\r\n buf[position + 1] = (num >> 8) & 0xFF;\r\n buf[position + 2] = (num >> 16) & 0xFF;\r\n position += 3;\r\n } else {\r\n // 4-byte\r\n buf[position] = num & 0xFF;\r\n buf[position + 1] = (num >> 8) & 0xFF;\r\n buf[position + 2] = (num >> 16) & 0xFF;\r\n buf[position + 3] = (num >> 24) & 0xFF;\r\n position += 4;\r\n }\r\n break;\r\n } else if (this.isStringMarker(currentObj)) {\r\n // StringMarker - no operation needed\r\n break;\r\n } else {\r\n throw new Error(`Unable to process '${currentObj}'`);\r\n }\r\n }\r\n };\r\n\r\n for (const obj of objList) {\r\n oix++;\r\n processObject(obj);\r\n }\r\n\r\n // Position management no longer needed since we use absolute locations\r\n\r\n bix++;\r\n }\r\n }\r\n\r\n /**\r\n * Helper method to find index of any character from an array in a string\r\n */\r\n private indexOfAny(str: string, chars: string[]): number {\r\n for (let i = 0; i < str.length; i++) {\r\n if (chars.includes(str[i])) {\r\n return i;\r\n }\r\n }\r\n return -1;\r\n }\r\n\r\n /**\r\n * Helper method to check if an object is a StringMarker\r\n */\r\n private isStringMarker(obj: unknown): obj is StringMarker {\r\n return typeof obj === 'object' && obj !== null && 'offset' in obj;\r\n }\r\n\r\n private isTableEntry(obj: unknown): obj is TableEntry {\r\n return typeof obj === 'object' && obj !== null && 'location' in obj && 'object' in obj;\r\n }\r\n}\r\n\r\n\r\n","\r\nexport class DbHeader {\r\n public bank: number;\r\n public address: number;\r\n public condition?: string;\r\n public parts: DbHeaderPart[];\r\n\r\n constructor(data: Partial<DbHeader>) {\r\n if(typeof data.address !== 'number') throw new Error('Address is required');\r\n if(!data.parts || !data.parts.length) throw new Error('Parts are required');\r\n\r\n this.bank = data.bank ?? 0;\r\n this.address = data.address;\r\n this.condition = data.condition ?? undefined;\r\n this.parts = data.parts.map(p => new DbHeaderPart(p));\r\n }\r\n}\r\n\r\nexport class DbHeaderPart {\r\n public name: string;\r\n public size: number;\r\n public type: string;\r\n public value?: any;\r\n\r\n constructor(data: Partial<DbHeaderPart>) {\r\n if(!data.name) throw new Error('Name is required');\r\n\r\n this.name = data.name;\r\n this.size = data.size ?? 0;\r\n this.type = data.type ?? '';\r\n this.value = data.value ?? undefined;\r\n }\r\n}","import { BinType } from '../types/resources';\r\nimport type { ICompressionProvider } from '../types/compression';\r\nimport { DbBlock } from './blocks';\r\nimport type { DbConfig } from './config';\r\nimport type { DbEntryPoint } from './entrypoints';\r\nimport { DbFile, DbFileType } from './files';\r\nimport { DbOverride } from './overrides';\r\nimport { DbStruct } from './structs';\r\nimport { DbAddressingMode } from './addressingMode';\r\nimport { DbStringType, DbStringCommand, DbStringLayer, DbStringDictionary } from './strings';\r\nimport { CopDef } from './cop';\r\nimport { listDirectory, readFileAsBinary, readJsonFile, saveFileAsText, saveFileAsBinary, readFileAsText } from '../utils';\r\nimport type { DbMnemonic } from './mnemonics';\r\nimport type { DbRewrite } from './rewrites';\r\nimport { DbPart } from './parts';\r\nimport type { DbLabel } from './labels';\r\nimport { DbTransform } from './transforms';\r\nimport type { BaseRomFileData, ProjectFileData, ProjectPayload } from '../supabase/types';\r\nimport { OpCode } from './opcode';\r\nimport { fromSupabaseByProject, fromSupabaseByGameRom } from '../supabase/rom-loader';\r\nimport { RomProcessingConstants } from '../types/constants';\r\nimport { ChunkFile } from '../types/files';\r\nimport { DbScene } from './scenes';\r\nimport { DbGroup } from './groups';\r\nimport { DbAsset } from './assets';\r\nimport { CompressionAlgorithms } from '../compression';\r\nimport { DbBaseRomModule, DbGameRomModule, DbProjectModule } from './modules';\r\nimport { BlockWriter } from '../rom/extraction/writer';\r\nimport { BlockReader } from '../rom/extraction/blocks';\r\nimport { RomWriter } from '../rom/rebuild/writer';\r\nimport { DbHeader } from './header';\r\n\r\n/**\r\n * Main database root class\r\n * Converted from GaiaLib/Database/DbRoot.cs\r\n */\r\nexport interface DbRoot {\r\n copDef: Record<number, CopDef>;\r\n copLookup: Record<string, CopDef>;\r\n mnemonics: Record<number, string>;\r\n //paths: Record<BinType, DbPath>;\r\n structs: Record<string, DbStruct>;\r\n stringTypes: Record<string, DbStringType>;\r\n stringDelimiters: string[];\r\n stringDelimiterLookup: Record<string, DbStringType>;\r\n //stringCharLookup: Record<string, DbStringType>;\r\n headers: DbHeader[];\r\n files: DbFile[];\r\n config: DbConfig;\r\n blocks: DbBlock[];\r\n overrides: Record<number, Record<string, any>>;\r\n labels: Record<number, string>;\r\n rewrites: Record<number, number>;\r\n entryPoints: DbEntryPoint[];\r\n opCodes: Record<number, OpCode>;\r\n opLookup: Record<string, OpCode[]>;\r\n addrLookup: Record<string, DbAddressingMode>;\r\n compression?: ICompressionProvider;\r\n baseRomFiles?: ChunkFile[];\r\n projectFiles?: ChunkFile[];\r\n groups: Record<string, DbGroup>;\r\n scenes: Record<number, DbScene>;\r\n fileTypes: Record<string, DbFileType>;\r\n fileExtLookup: Record<string, DbFileType>;\r\n}\r\n\r\n/**\r\n * Database root utilities\r\n */\r\nexport class DbRootUtils {\r\n /**\r\n * JSON serialization options\r\n */\r\n // public static readonly JSON_OPTIONS = {\r\n // propertyNamingPolicy: 'camelCase',\r\n // readCommentHandling: 'skip',\r\n // writeIndented: true\r\n // };\r\n\r\n // /**\r\n // * Load database from a single file\r\n // */\r\n // // public static async fromFile(dbFilePath: string): Promise<DbRoot> {\r\n // // return await readJsonFile<DbRoot>(dbFilePath);\r\n // // }\r\n\r\n // public static async fromFolder(folderPath: string, systemPath: string) : Promise<DbRoot> {\r\n // return this.fromGameModule(await this.gameModuleFromFolder(folderPath, systemPath));\r\n // }\r\n\r\n // /**\r\n // * Load database from folder structure\r\n // */\r\n // public static async gameModuleFromFolder(folderPath: string, systemPath: string): Promise<DbGameRomModule> {\r\n // return {\r\n // mnemonics: await readJsonFile<Record<number, string>>(`${folderPath}/mnemonics.json`),\r\n // overrides: await readJsonFile<Record<number, Record<string, any>>>(`${folderPath}/overrides.json`),\r\n // rewrites: await readJsonFile<Record<string, number>>(`${folderPath}/rewrites.json`),\r\n // blocks: await readJsonFile<Record<string, Record<string, Partial<DbBlock>>>>(`${folderPath}/blocks.json`),\r\n // files: await readJsonFile<Record<string, Record<string, Record<string, Partial<DbFile>>>>>(`${folderPath}/files.json`),\r\n // config: await readJsonFile<DbConfig>(`${folderPath}/config.json`),\r\n // labels: await readJsonFile<DbLabel[]>(`${folderPath}/labels.json`),\r\n // structs: await readJsonFile<Record<string, DbStruct>>(`${folderPath}/structs.json`),\r\n // copdef: await readJsonFile<Record<string, Partial<CopDef>>>(`${folderPath}/copdef.json`),\r\n // addrModes: await readJsonFile<Record<string, Partial<DbAddressingMode>>>(`${systemPath}/addressingModes.json`),\r\n // strings: await readJsonFile<Record<string, Partial<DbStringType>>>(`${folderPath}/stringTypes.json`),\r\n // transforms: await readJsonFile<Record<string, Partial<DbTransform>[]>>(`${folderPath}/transforms.json`),\r\n // groups: await readJsonFile<Record<string, Partial<DbGroup>>>(`${folderPath}/groups.json`),\r\n // fileTypes: await readJsonFile<Record<string, Partial<DbFileType>>>(`${folderPath}/fileTypes.json`),\r\n // }\r\n // }\r\n\r\n public static fromGameModule(module: DbGameRomModule): DbRoot {\r\n // Build lookup tables\r\n\r\n const opCodes = {} as Record<number, OpCode>;\r\n const opLookup = {} as Record<string, OpCode[]>;\r\n const addrLookup = Object.entries(module.addrModes).reduce((acc, x) => {\r\n const modeData = x[1];\r\n const modeName = x[0];\r\n for(const [mnem, code] of Object.entries(modeData.instructions ?? [])) {\r\n const opCode = new OpCode(code, mnem, modeName);\r\n opCodes[code] = opCode;\r\n if (!opLookup[mnem]) opLookup[mnem] = [];\r\n opLookup[mnem].push(opCode);\r\n }\r\n acc[modeName] = new DbAddressingMode({...modeData, name: modeName});\r\n return acc;\r\n }, {} as Record<string, DbAddressingMode>);\r\n\r\n const blocksArray: DbBlock[] = [];\r\n for (const [groupName, groupData] of Object.entries(module.blocks)) {\r\n for(const [blockName, blockData] of Object.entries(groupData)) {\r\n\r\n const partsData = blockData.parts as unknown as Record<string, Partial<DbPart>> ?? {};\r\n const parts = Object.entries(partsData).map((p) => {\r\n return new DbPart({...p[1], name: p[0]});\r\n });\r\n\r\n const transformList = (module.transforms[blockName] ?? []).map((t) => {\r\n return new DbTransform(t);\r\n });\r\n\r\n const block = new DbBlock({\r\n ...blockData, \r\n name: blockName, \r\n group: groupName,\r\n parts: parts,\r\n transforms: transformList\r\n });\r\n\r\n blocksArray.push(block);\r\n }\r\n }\r\n\r\n const sceneLookup = {} as Record<number, DbScene>;\r\n const groupLookup = Object.entries(module.groups).reduce((acc, x) => {\r\n const groupData = x[1];\r\n const groupName = x[0];\r\n\r\n const scenes = Object.entries(groupData.scenes ?? {}).reduce((acc, y) => {\r\n const sceneData = y[1];\r\n const sceneName = y[0];\r\n const scene = new DbScene({...sceneData, name: sceneName });\r\n sceneLookup[scene.id] = scene;\r\n acc[sceneName] = scene;\r\n return acc;\r\n }, {} as Record<string, DbScene>);\r\n \r\n acc[groupName] = new DbGroup({...groupData, name: groupName, scenes: scenes });\r\n return acc;\r\n }, {} as Record<string, DbGroup>);\r\n\r\n const fileList: DbFile[] = [];\r\n for(const [groupName, groupData] of Object.entries(module.files)) {\r\n for(const [sceneName, sceneData] of Object.entries(groupData)) {\r\n for(const [fileName, fileData] of Object.entries(sceneData)) {\r\n fileList.push(new DbFile({...fileData, name: fileName, group: groupName, scene: sceneName }));\r\n }\r\n }\r\n }\r\n\r\n const stringDelimiterLookup = {} as Record<string, DbStringType>;\r\n const stringDelimiterList: string[] = [];\r\n const stringLookup = Object.entries(module.strings).reduce((acc, x) => {\r\n const stringType = x[1];\r\n const name = x[0];\r\n const commands = Object.entries(stringType.commands ?? {}).reduce((acc, y) => {\r\n acc[y[0]] = new DbStringCommand({...y[1], name: y[0]});\r\n return acc;\r\n }, {} as Record<string, DbStringCommand>);\r\n const dictionaries = Object.entries(stringType.dictionaries ?? {}).reduce((acc, y) => {\r\n const dictionary = new DbStringDictionary({...y[1], name: y[0]});\r\n acc[y[0]] = dictionary;\r\n if(dictionary.command !== undefined) {\r\n commands[dictionary.command] = new DbStringCommand({id: dictionary.command, name: dictionary.name, dictionary: dictionary});\r\n }\r\n return acc;\r\n }, {} as Record<string, DbStringDictionary>);\r\n const st = new DbStringType({...stringType, name, commands, dictionaries});\r\n acc[name] = st;\r\n stringDelimiterLookup[st.delimiter] = st;\r\n stringDelimiterList.push(st.delimiter);\r\n return acc;\r\n }, {} as Record<string, DbStringType>);\r\n\r\n const structLookup = Object.entries(module.structs).reduce((acc, x) => {\r\n acc[x[0]] = new DbStruct({...x[1], name: x[0]});\r\n return acc;\r\n }, {} as Record<string, DbStruct>);\r\n\r\n\r\n const copCodes = {} as Record<number, CopDef>;\r\n const copLookup = Object.entries(module.copdef).reduce((acc, x) => {\r\n const copDef = x[1];\r\n const name = x[0];\r\n const def = new CopDef({...copDef, name});\r\n copCodes[def.id] = def;\r\n acc[name] = def;\r\n return acc;\r\n }, {} as Record<string, CopDef>);\r\n\r\n const extLookup = {} as Record<string, DbFileType>;\r\n const fileTypeLookup = {} as Record<string, DbFileType>;\r\n const fileTypes = Object.entries(module.fileTypes).reduce((acc, x) => {\r\n const fileType = x[1];\r\n const name = x[0];\r\n const type = new DbFileType({...fileType, name});\r\n extLookup[type.extension] = type;\r\n fileTypeLookup[type.type] = type;\r\n acc[name] = type;\r\n return acc;\r\n }, {} as Record<string, DbFileType>);\r\n\r\n const cfg = module.config;\r\n\r\n const compression = cfg.compression ? CompressionAlgorithms[cfg.compression]() : undefined;\r\n\r\n \r\n const baseRomChunks = (module as DbBaseRomModule).baseRomFiles ?? module.supaBaseRomFiles?.map((file: BaseRomFileData) => {\r\n const chunkFile = new ChunkFile(file.name, 0, 0, fileTypeLookup[file.type]);\r\n if(file.isText) {\r\n chunkFile.textData = file.text ?? undefined;\r\n chunkFile.size = file.text?.length ?? 0;\r\n } else {\r\n chunkFile.rawData = file.data;\r\n chunkFile.size = file.data?.length ?? 0;\r\n }\r\n return chunkFile;\r\n });\r\n \r\n const projectChunks = (module as DbProjectModule).projectFiles ?? module.supaProjectFiles?.map((file: ProjectFileData) => {\r\n const chunkFile = new ChunkFile(file.name, 0, 0, fileTypeLookup[file.type]);\r\n chunkFile.group = file.module ?? undefined;\r\n if(file.isText) {\r\n chunkFile.textData = file.text ?? undefined;\r\n chunkFile.size = file.text?.length ?? 0;\r\n } else {\r\n chunkFile.rawData = file.data;\r\n chunkFile.size = file.data?.length ?? 0;\r\n }\r\n return chunkFile;\r\n });\r\n\r\n // Build the database root\r\n const root: DbRoot = {\r\n headers: module.headers.map((h) => new DbHeader(h)),\r\n mnemonics: module.mnemonics,\r\n overrides: module.overrides,\r\n rewrites: module.rewrites,\r\n labels: module.labels,\r\n structs: structLookup,\r\n blocks: blocksArray.sort((a, b) => {\r\n const orderA = a.order ?? 0;\r\n const orderB = b.order ?? 0;\r\n if (orderA !== orderB) return orderA - orderB;\r\n return a.parts[0].start - b.parts[0].start;\r\n }),\r\n files: fileList,\r\n fileTypes,\r\n fileExtLookup: extLookup,\r\n copDef: copCodes,\r\n copLookup,\r\n config: cfg,\r\n opCodes,\r\n opLookup,\r\n addrLookup,\r\n entryPoints: cfg.entryPoints,\r\n stringTypes: stringLookup,\r\n stringDelimiters: stringDelimiterList,\r\n stringDelimiterLookup,\r\n compression,\r\n groups: groupLookup,\r\n scenes: sceneLookup,\r\n baseRomFiles: baseRomChunks,\r\n projectFiles: projectChunks\r\n };\r\n\r\n return root;\r\n }\r\n\r\n public static async applyFolder(root: DbRoot, folderPath: string, sourceFiles: ChunkFile[] = []) : Promise<ChunkFile[]> {\r\n const chunkFiles = sourceFiles;\r\n const folderEntries = await listDirectory(folderPath, { recursive: true });\r\n for(const entry of folderEntries) {\r\n if(!entry.isFile || !entry.extension) continue; //await this.applyFolder(root, entry.path, chunkFiles);\r\n \r\n const type = root.fileExtLookup[entry.extension];\r\n if(!type) continue;\r\n\r\n const existing = chunkFiles.find(x => x.name === entry.name && x.type.type === type.type);\r\n const chunkFile = existing ?? new ChunkFile(entry.name, 0, 0, type);\r\n\r\n if(chunkFile.type.type === 'Assembly' || chunkFile.type.type === 'Patch') {\r\n const chunkData = await readFileAsText(entry.path);\r\n chunkFile.textData = chunkData;\r\n chunkFile.size = chunkData.length;\r\n } else {\r\n const chunkData = await readFileAsBinary(entry.path);\r\n chunkFile.rawData = chunkData;\r\n chunkFile.size = chunkData.length;\r\n }\r\n if(!existing){\r\n const sourceFile = root.files.find(x => x.name === entry.name && x.type === type.type);\r\n if (sourceFile) {\r\n chunkFile.location = sourceFile.start;\r\n chunkFile.upper = sourceFile.upper;\r\n chunkFile.compressed = sourceFile.compressed;\r\n }\r\n \r\n chunkFiles.push(chunkFile);\r\n }\r\n }\r\n return chunkFiles;\r\n }\r\n\r\n \r\n public static async extractAllContent(root: DbRoot, romPath: string, outPath: string) : Promise<void> {\r\n const romData = await readFileAsBinary(romPath);\r\n const reader = new BlockReader(romData, root);\r\n const chunkFiles = reader.analyzeAndResolve();\r\n const writer = new BlockWriter(reader);\r\n\r\n for(const block of chunkFiles) {\r\n const ext = block.type.extension;\r\n const filePath = `${outPath}/${block.group ? (block.group + '/') : ''}${block.scene ? (block.scene + '/') : ''}${block.name}${ext ? '.' + ext : ''}`;\r\n if(block.parts?.length) {\r\n if(!block.textData) block.textData = writer.generateAsm(block);\r\n await saveFileAsText(filePath, block.textData);\r\n } else {\r\n if (!block.rawData) continue;\r\n await saveFileAsBinary(filePath, block.rawData);\r\n }\r\n }\r\n }\r\n\r\n public static async rebuildAllContent(root: DbRoot, inPath: string[], outPath: string) : Promise<ChunkFile[]> {\r\n var sourceFiles: ChunkFile[] = [];\r\n for(const path of inPath) {\r\n sourceFiles = await this.applyFolder(root, path, sourceFiles);\r\n }\r\n\r\n const romWriter = new RomWriter(root);\r\n const outData = await romWriter.repack(sourceFiles);\r\n await saveFileAsBinary(outPath, outData);\r\n\r\n return sourceFiles;\r\n }\r\n\r\n\r\n // /**\r\n // * Get path configuration for a resource type\r\n // */\r\n // public static getPath(root: DbRoot, type: BinType): DbPath {\r\n // return root.paths[type] || root.paths[BinType.Unknown];\r\n // }\r\n\r\n // /**\r\n // * Get resource path for a file\r\n // */\r\n // public static getResource(root: DbRoot, baseDir: string, name: string, type: BinType): string {\r\n // const res = this.getPath(root, type);\r\n // return `${baseDir}/${res.folder}/${name}.${res.extension}`;\r\n // }\r\n\r\n /**\r\n * Load database from Supabase using BaseRomBranch ID\r\n * @param baseRomBranchId - The ID of the BaseRomBranch to load\r\n * @returns Promise<DbRoot> containing the complete database root\r\n * @throws {Error} If the branch is not found or loading fails\r\n * \r\n * @example\r\n * ```typescript\r\n * const dbRoot = await DbRootUtils.fromSupabaseById('clm1234567890');\r\n * console.log(dbRoot.files.length);\r\n * ```\r\n */\r\n // public static async fromSupabaseById(baseRomBranchId: string): Promise<DbRoot> {\r\n // const payload = await fromSupabaseById(baseRomBranchId);\r\n // return this.fromSupabasePayload(payload);\r\n // }\r\n\r\n /**\r\n * Load database from Supabase using name-based lookup\r\n * @param options - Options for name-based lookup (optional)\r\n * @returns Promise<DbRoot> containing the complete database root\r\n * @throws {Error} If the branch is not found or loading fails\r\n * \r\n * @example\r\n * ```typescript\r\n * // Load default ROM (GaiaLabs BaseROM, main branch)\r\n * const dbRoot1 = await DbRootUtils.fromSupabase({});\r\n * \r\n * // Load specific ROM and branch\r\n * const dbRoot2 = await DbRootUtils.fromSupabase({\r\n * baseRomName: 'My Custom ROM',\r\n * branchName: 'development',\r\n * branchVersion: null\r\n * });\r\n * ```\r\n */\r\n // public static async fromSupabase(options?: FromSupabaseByNameOptions): Promise<DbRoot> {\r\n // const payload = await fromSupabaseByName(options);\r\n // return this.fromSupabasePayload(payload);\r\n // }\r\n\r\n // public static async fromSupabaseProject(projectName?: string, branchId?: string): Promise<DbRoot> {\r\n // const payload = await fromSupabaseByProject(projectName, branchId);\r\n // return this.fromSupabasePayload(payload);\r\n // }\r\n\r\n /**\r\n * Load database from GameRomBranch data (for ROM-only processing)\r\n * @param gameRomBranchData - Direct GameRomBranch data from Supabase API\r\n * @returns Promise<DbRoot> containing the complete database root\r\n */\r\n // public static async fromSupabaseGameRom(gameRomName?: string, branchId?: string): Promise<DbRoot> {\r\n // const payload = await fromSupabaseByGameRom(gameRomName, branchId);\r\n // return this.fromSupabasePayload(payload);\r\n // }\r\n\r\n /**\r\n * Convert Supabase payload to DbRoot structure\r\n * @private\r\n * @param payload - The ROM payload from Supabase\r\n * @returns DbRoot containing the processed database structure\r\n */\r\n // private static async fromSupabasePayload(payload: ProjectPayload): Promise<DbRoot> {\r\n \r\n // // Extract data from the Supabase payload\r\n // const gameRomBranch = payload.baseRomBranch.gameRomBranch;\r\n \r\n // const config = gameRomBranch.config;\r\n // const copDef = gameRomBranch.coplib;\r\n // const romFiles = gameRomBranch.files;\r\n // const romBlocks = gameRomBranch.blocks;\r\n // const romStrings = gameRomBranch.strings;\r\n // const romStructs = gameRomBranch.structs;\r\n // const romFixups = gameRomBranch.fixups;\r\n // const romScenes = gameRomBranch.scenes;\r\n\r\n // const platformBranch = gameRomBranch.platformBranch;\r\n // const instructionSet = platformBranch.instructionSet;\r\n // const addressingModes = platformBranch.addressingModes;\r\n // //const vectors = platformBranch.vectors;\r\n\r\n // const transforms = romFixups.transforms || [];\r\n\r\n // // Build configuration from available data\r\n // const compression = config.compression ? CompressionAlgorithms[config.compression]() : null;\r\n \r\n // const files: DbFile[] = Object.entries(romFiles).map((x: any) => {\r\n // const file = x[1];\r\n // file.start = file.location;\r\n // file.end = file.location + file.size;\r\n // //file.type = BinType[file.type as keyof typeof BinType] || BinType.Unknown;\r\n // file.name = x[0];\r\n // return file;\r\n // });\r\n \r\n // const blocks: DbBlock[] = Object.entries(romBlocks).map((x: any) => {\r\n // const block = x[1];\r\n // block.name = x[0];\r\n\r\n // const transform = transforms[block.name];\r\n // block.transforms = transform ? Object.entries(transform).map((t: any) => { return { key: t[0], value: t[1] } }) : [];\r\n \r\n // block.parts = Object.entries(block.parts)\r\n // .sort((a: any, b: any) => {\r\n // const orderA = a[1].order ?? 0;\r\n // const orderB = b[1].order ?? 0;\r\n // if (orderA !== orderB) {\r\n // return orderA - orderB;\r\n // }\r\n // return a[1].location - b[1].location;\r\n // })\r\n // .map((p: any) => {\r\n // const part = p[1];\r\n // part.name = p[0];\r\n // part.start = part.location;\r\n // part.end = part.location + part.size;\r\n // part.struct = part.type;\r\n // return part;\r\n // });\r\n\r\n // return block;\r\n // }).sort((a: any, b: any) => a.parts[0].location - b.parts[0].location);\r\n \r\n // const baseRomFiles : ChunkFile[] = payload.baseRomFiles && payload.baseRomFiles.map((file: BaseRomFileData) => {\r\n // const chunkFile = new ChunkFile(file.name, 0, 0, file.type as BinType);\r\n // if(file.isText) {\r\n // chunkFile.textData = file.text ?? undefined;\r\n // chunkFile.size = file.text?.length ?? 0;\r\n // } else {\r\n // chunkFile.rawData = file.data;\r\n // chunkFile.size = file.data?.length ?? 0;\r\n // }\r\n // return chunkFile;\r\n // });\r\n \r\n // const projectFiles : ChunkFile[] = payload.projectFiles && payload.projectFiles.map((file: ProjectFileData) => {\r\n // const chunkFile = new ChunkFile(file.name, 0, 0, file.type as BinType);\r\n // chunkFile.group = file.module ?? undefined;\r\n // if(file.isText) {\r\n // chunkFile.textData = file.text ?? undefined;\r\n // chunkFile.size = file.text?.length ?? 0;\r\n // } else {\r\n // chunkFile.rawData = file.data;\r\n // chunkFile.size = file.data?.length ?? 0;\r\n // }\r\n // return chunkFile;\r\n // });\r\n\r\n // // Extract other data from the JSON structures\r\n // const mnemonics = romFixups.mnemonics || {};\r\n // const opCodes = this.extractOpCodesFromInstructionSet(instructionSet);\r\n // const overrides = romFixups.overrides || {};\r\n // const rewrites = romFixups.rewrites || {};\r\n // const labels = romFixups.labels || {};\r\n // const structs = romStructs || {};\r\n // //const parts: DbPart[] = Array.isArray(typesJson.parts) ? typesJson.parts : [];\r\n // //const transforms: DbTransform[] = Array.isArray(typesJson.transforms) ? typesJson.transforms : [];\r\n // //const stringTypes = romTypes.strings || {};\r\n // //const stringCommands = romTypes.stringCommands || {};\r\n // //const stringLayers = Array.isArray(romTypes.stringLayers) ? romTypes.stringLayers : [];\r\n // //const copDef = Array.isArray(romTypes.copDef) ? romTypes.copDef : [];\r\n // const entryPoints = Array.isArray(config.entryPoints) ? config.entryPoints : [];\r\n \r\n\r\n // const stringTypes = Object.entries(romStrings).reduce((acc: any, x: any) => {\r\n // const strType = x[1];\r\n // strType.name = x[0];\r\n\r\n // const commands = Object.entries(strType.commands).reduce((acc: any, x: any) => {\r\n // const cmd = x[1];\r\n // acc[cmd.code] = {\r\n // key: cmd.code,\r\n // value: x[0],\r\n // types: cmd.types,\r\n // delimiter: cmd.delimiter,\r\n // halt: cmd.halt\r\n // };\r\n // return acc;\r\n // }, {} as Record<number, any>);\r\n // strType.commands = commands;\r\n\r\n // acc[strType.name] = strType;\r\n // return acc;\r\n // }, {} as Record<string, DbStringType>);\r\n \r\n // // Build lookup tables\r\n // const copLookup = Object.entries(copDef).reduce((acc: any, x: any) => {\r\n // const def = x[1];\r\n // def.mnem = x[0];\r\n // def.size = RomProcessingConstants.getSize(def.parts);\r\n // acc[x[0]] = def;\r\n // return acc;\r\n // }, {} as Record<string, CopDef>);\r\n \r\n // const copDefLookup = Object.values(copDef).reduce((acc: any, x: any) => {\r\n // acc[x.code] = x;\r\n // return acc;\r\n // }, {} as Record<number, CopDef>);\r\n \r\n \r\n // const opLookup = Object.entries(instructionSet).reduce((acc: any, x: any) => {\r\n // acc[x[0]] = Object.entries(x[1]).map((y: any) => new OpCode(y[1], x[0], y[0]));\r\n // return acc;\r\n // }, {});\r\n\r\n // const stringDelimiters = Object.values(stringTypes).map((x: any) => x?.delimiter).filter(Boolean);\r\n // const stringCharLookup = Object.values(stringTypes).reduce((acc: any, x: any) => {\r\n // if (x?.delimiter) {\r\n // acc[x.delimiter] = x;\r\n // }\r\n // return acc;\r\n // }, {});\r\n \r\n\r\n // const scenes = {} as Record<number, DbScene>;\r\n // const sceneGroups = Object.entries(romScenes ?? {}).reduce((acc: any, x: any) => {\r\n // const group = x[1];\r\n // const groupName = x[0];\r\n // const newGroup = {\r\n // name: groupName,\r\n // scenes: Object.entries(group).reduce((accy: any, y: any) => {\r\n // const scene = y[1];\r\n // const sceneName = y[0];\r\n // const newScene = {\r\n // name: sceneName,\r\n // id: scene.id,\r\n // group: groupName,\r\n // assets: scene.assets.map((asset: any, index: number) : DbAsset => {\r\n // const meta = { ...asset };\r\n // delete meta.type;\r\n // delete meta.data;\r\n // return { \r\n // index,\r\n // type: asset.type,\r\n // file: asset.data,\r\n // scene: sceneName,\r\n // meta\r\n // };\r\n // }),\r\n // };\r\n // if(scene.id) {\r\n // scenes[scene.id] = newScene;\r\n // }\r\n // accy[sceneName] = newScene;\r\n // return accy;\r\n // }, {} as Record<string, DbScene>)\r\n // }\r\n\r\n // acc[groupName] = newGroup;\r\n // return acc;\r\n // }, {} as Record<string, DbGroup>);\r\n \r\n \r\n // // Build the complete DbRoot structure\r\n // const root: DbRoot = {\r\n // mnemonics: Object.entries(mnemonics).reduce((acc: any, x: any) => {\r\n // acc[x[1]] = x[0];\r\n // return acc;\r\n // }, {} as Record<number, string>),\r\n // overrides: Array.isArray(overrides) ? overrides.reduce((acc: any, x: any) => {\r\n // acc[x.location] = x;\r\n // return acc;\r\n // }, {}) : overrides,\r\n // rewrites: Array.isArray(rewrites) ? rewrites.reduce((acc: any, x: any) => {\r\n // acc[x.location] = x.value;\r\n // return acc;\r\n // }, {}) : rewrites,\r\n // labels: Array.isArray(labels) ? labels.reduce((acc: any, x: any) => {\r\n // acc[x.location] = x.label;\r\n // return acc;\r\n // }, {}) : labels,\r\n // structs: Object.entries(structs).reduce((acc: any, x: any) => {\r\n // const struct = x[1];\r\n // struct.name = x[0];\r\n // acc[x[0]] = struct;\r\n // return acc;\r\n // }, {} as Record<string, DbStruct>),\r\n // blocks,\r\n // files,\r\n // copDef: copDefLookup as Record<number, CopDef>,\r\n // copLookup,\r\n // baseRomFiles,\r\n // projectFiles,\r\n // config,\r\n // opCodes,\r\n // opLookup,\r\n // addrLookup: addressingModes,\r\n // entryPoints,\r\n // //paths: config.paths,\r\n // stringTypes: stringTypes,\r\n // stringDelimiters,\r\n // //stringCharLookup: stringCharLookup as Record<string, DbStringType>,\r\n // compression,\r\n // groups: sceneGroups,\r\n // scenes\r\n // };\r\n\r\n // console.log('✅ Successfully transformed Supabase payload to DbRoot');\r\n // console.log(`📁 Files: ${files.length}, 🧱 Blocks: ${blocks.length}`);\r\n // console.log(`🎯 ROM: ${payload.baseRomBranch.baseRom.name} (${payload.baseRomBranch.name || 'main'})`);\r\n // console.log(`💾 BaseRom files: ${root?.baseRomFiles?.length} files, ${root.baseRomFiles?.reduce((sum, f) => sum + f.size, 0)} bytes total`);\r\n // console.log(`💾 Project files: ${root?.projectFiles?.length} files, ${root.projectFiles?.reduce((sum, f) => sum + f.size, 0)} bytes total`);\r\n \r\n // return root;\r\n // }\r\n\r\n /**\r\n * Extract and flatten OpCodes from the instruction set schema\r\n * @private\r\n * @param instructionSet - The instruction set object from the schema\r\n * @returns Array of OpCode objects with code, mnem, mode, and size properties\r\n */\r\n // private static extractOpCodesFromInstructionSet(instructionSet: any): OpCode[] {\r\n // const opCodes: OpCode[] = [];\r\n \r\n // for (const mnem in instructionSet) {\r\n // for (const mode in instructionSet[mnem]) {\r\n // const op = instructionSet[mnem][mode];\r\n // opCodes[op] = new OpCode(op, mnem, mode);\r\n // }\r\n // }\r\n \r\n // return opCodes;\r\n // }\r\n\r\n // /**\r\n // * Convert GameRomBranch data directly to DbRoot structure\r\n // * @private\r\n // * @param gameRomBranchData - Direct GameRomBranch data from Supabase API\r\n // * @returns DbRoot containing the processed database structure\r\n // */\r\n // private static async fromGameRomBranchData(gameRomBranchData: any): Promise<DbRoot> {\r\n \r\n // // Extract data from the GameRomBranch data\r\n // const config = gameRomBranchData.config;\r\n // const copDef = gameRomBranchData.coplib;\r\n // const romFiles = gameRomBranchData.files;\r\n // const romBlocks = gameRomBranchData.blocks;\r\n // const romTypes = gameRomBranchData.types;\r\n // const romFixups = gameRomBranchData.fixups;\r\n // const structs = gameRomBranchData.structs;\r\n\r\n // // Note: For direct GameRomBranch processing, we won't have platformBranch data\r\n // // So we'll use defaults or extract from what's available\r\n // const instructionSet = {}; // Will be empty for now\r\n // const addressingModes = {}; // Will be empty for now\r\n \r\n // const transforms = romFixups?.transforms || [];\r\n\r\n // // Build configuration from available data\r\n // const compression = CompressionRegistry.get(config?.compression || 'QuintetLZ');\r\n \r\n // const files: DbFile[] = romFiles ? Object.entries(romFiles).map((x: any) => {\r\n // const file = x[1];\r\n // file.start = file.location;\r\n // file.end = file.location + file.size;\r\n // file.name = x[0];\r\n // return file;\r\n // }) : [];\r\n \r\n // const blocks: DbBlock[] = romBlocks ? Object.entries(romBlocks).map((x: any) => {\r\n // const block = x[1];\r\n // block.name = x[0];\r\n\r\n // const transform = transforms[block.name];\r\n // block.transforms = transform ? Object.entries(transform).map((t: any) => { return { key: t[0], value: t[1] } }) : [];\r\n \r\n // block.parts = Object.entries(block.parts || {})\r\n // .sort((a: any, b: any) => {\r\n // const orderA = a[1].order ?? 0;\r\n // const orderB = b[1].order ?? 0;\r\n // if (orderA !== orderB) {\r\n // return orderA - orderB;\r\n // }\r\n // return a[1].location - b[1].location;\r\n // })\r\n // .map((p: any) => {\r\n // const part = p[1];\r\n // part.name = p[0];\r\n // part.start = part.location;\r\n // part.end = part.location + part.size;\r\n // part.struct = part.type;\r\n // return part;\r\n // });\r\n\r\n // return block;\r\n // }).sort((a: any, b: any) => a.parts[0]?.location || 0 - b.parts[0]?.location || 0) : [];\r\n \r\n // // For GameRomBranch direct processing, we don't have baseRomFiles or projectFiles\r\n // const baseRomFiles: ChunkFile[] = [];\r\n // const projectFiles: ChunkFile[] = [];\r\n \r\n // const entryPoints: DbEntryPoint[] = [];\r\n \r\n // // Extract overrides from configs (if available)\r\n // const overrides: Record<number, DbOverride> = {};\r\n \r\n // // Build OpCode array from instruction set\r\n // const opCodes = this.extractOpCodesFromInstructionSet(instructionSet);\r\n \r\n // // Build lookup tables\r\n // const copDefLookup = Object.values(copDef || {}).reduce((acc: any, x: any) => {\r\n // acc[x.code] = x;\r\n // return acc;\r\n // }, {} as Record<number, CopDef>);\r\n \r\n // const opLookup = Object.entries(instructionSet).reduce((acc: any, x: any) => {\r\n // acc[x[0]] = Object.entries(x[1]).map((y: any) => new OpCode(y[1], x[0], y[0]));\r\n // return acc;\r\n // }, {});\r\n\r\n // const stringDelimiters = Object.values(romTypes || {}).map((x: any) => x?.delimiter).filter(Boolean);\r\n // const stringCharLookup = Object.values(romTypes || {}).reduce((acc: any, x: any) => {\r\n // if (x?.delimiter) {\r\n // acc[x.delimiter] = x;\r\n // }\r\n // return acc;\r\n // }, {});\r\n \r\n // // Create the root object\r\n // const dbRoot: DbRoot = {\r\n // copDef: copDefLookup as Record<number, CopDef>,\r\n // copLookup: copDef || {},\r\n // stringTypes: romTypes || {},\r\n // stringDelimiters,\r\n // stringCharLookup: stringCharLookup as Record<string, DbStringType>,\r\n // structs: structs || {},\r\n // files,\r\n // blocks,\r\n // entryPoints,\r\n // overrides,\r\n // labels: {},\r\n // rewrites: {},\r\n // compression,\r\n // opCodes,\r\n // opLookup,\r\n // addrLookup: addressingModes,\r\n // mnemonics: {},\r\n // baseRomFiles,\r\n // projectFiles,\r\n // config: config || {}\r\n // };\r\n \r\n // return dbRoot;\r\n // }\r\n} ","\r\nexport class DbOverride {\r\n location: number;\r\n register: string;\r\n value: number;\r\n\r\n constructor(values: Partial<DbOverride>) {\r\n if(typeof values.value !== 'number') throw new Error('Value is required');\r\n if(typeof values.location !== 'number') throw new Error('Location is required');\r\n if(!values.register) throw new Error('Register is required');\r\n\r\n this.location = values.location;\r\n this.register = values.register;\r\n this.value = values.value;\r\n\r\n }\r\n} ","/**\r\n * Database path configuration\r\n * Converted from GaiaLib/Database/DbPath.cs\r\n */\r\nexport interface DbPath {\r\n folder: string;\r\n extension: string;\r\n}\r\n\r\n/**\r\n * Creates a default DbPath\r\n */\r\nexport function createDbPath(folder: string = 'misc', extension: string = 'bin'): DbPath {\r\n return {\r\n folder,\r\n extension\r\n };\r\n} ","import { RomDataReader } from './reader';\r\nimport { \r\n Address, \r\n AddressSpace, \r\n AddressType, \r\n MemberType, \r\n RomProcessingConstants,\r\n ChunkFileUtils, \r\n TableEntry \r\n} from '../../types';\r\nimport type { DbStringType, DbStringCommand, DbStringLayer } from '../../database';\r\nimport { DbStringTypeUtils } from '../../database';\r\nimport type { StringWrapper } from '../../types';\r\nimport type { BlockReader } from './blocks';\r\nimport { indexOfAny } from '../../utils';\r\n\r\n/**\r\n * Reads and processes strings from ROM data\r\n * Converted from GaiaLib/Rom/Extraction/StringReader.cs\r\n */\r\nexport class StringReader {\r\n public static readonly STRING_REFERENCE_CHARACTERS = ['~', '^'];\r\n\r\n private readonly _blockReader: BlockReader;\r\n private readonly _romDataReader: RomDataReader;\r\n\r\n constructor(blockReader: BlockReader) {\r\n this._blockReader = blockReader;\r\n this._romDataReader = blockReader._romDataReader;\r\n }\r\n\r\n private resolveCommand(cmd: DbStringCommand, builder: string[]): void {\r\n if(cmd.dictionary) {\r\n builder.push(cmd.dictionary.entries[this._romDataReader.readByte() - (cmd.dictionary.base ?? 0)]);\r\n } else if (cmd.types && cmd.types.length > 0) {\r\n builder.push(`[${cmd.name}`);\r\n\r\n let first = true;\r\n for (const t of cmd.types) {\r\n if (first) {\r\n builder.push(':');\r\n first = false;\r\n } else {\r\n builder.push(',');\r\n }\r\n\r\n switch (t) {\r\n case MemberType.Byte:\r\n builder.push(this._romDataReader.readByte().toString(16).toUpperCase());\r\n break;\r\n case MemberType.Word:\r\n builder.push(this._romDataReader.readUShort().toString(16).toUpperCase());\r\n break;\r\n case MemberType.Offset:\r\n const loc = this._romDataReader.readUShort() | \r\n (Address.resolveBank(this._romDataReader.position, this._blockReader._root.config.memoryMode) << 16);\r\n builder.push(`^${loc.toString(16).toUpperCase().padStart(6, '0')}`);\r\n break;\r\n case MemberType.Address:\r\n builder.push(`~${this._romDataReader.readAddress().toString(16).toUpperCase().padStart(6, '0')}`);\r\n break;\r\n case MemberType.Binary:\r\n let sfirst = true;\r\n do {\r\n const r = this._romDataReader.readByte();\r\n if (cmd.delimiter !== undefined && r === cmd.delimiter) {\r\n break;\r\n }\r\n if (sfirst) {\r\n sfirst = false;\r\n } else {\r\n builder.push(',');\r\n }\r\n builder.push(r.toString(16).toUpperCase());\r\n } while (this._blockReader.partCanContinue());\r\n break;\r\n default:\r\n throw new Error('Unsupported member type');\r\n }\r\n }\r\n builder.push(']');\r\n } else {\r\n builder.push(`[${cmd.name}]`);\r\n }\r\n }\r\n\r\n public parseString(stringType: DbStringType, fixedSize: number): StringWrapper {\r\n const commands = stringType.commandLookup;\r\n const dictionaries = stringType.dictionaries;\r\n const builder: string[] = [];\r\n const strLoc = this._romDataReader.position;\r\n const terminator = stringType.terminator;\r\n let currentLayer = stringType.layers[0];\r\n\r\n do {\r\n const c = this._romDataReader.readByte();\r\n if (c === terminator) {\r\n if (stringType.greedyTerminator) {\r\n while (this._romDataReader.peekByte() === terminator && this._blockReader.partCanContinue()) {\r\n this._romDataReader.position++;\r\n }\r\n }\r\n break;\r\n }\r\n\r\n const cmd = commands[c];\r\n if (cmd) {\r\n this.resolveCommand(cmd, builder);\r\n if (cmd.halt) {\r\n break;\r\n }\r\n } else {\r\n let found = false;\r\n for(const dictionary of Object.values(dictionaries)) {\r\n if(dictionary.base !== undefined && c >= dictionary.base && c <= dictionary.range) {\r\n builder.push(dictionary.entries[c - dictionary.base]);\r\n found = true;\r\n break;\r\n }\r\n }\r\n if(!found) {\r\n for(const layer of stringType.layers) {\r\n if(layer.on !== undefined) {\r\n if(c === layer.on) {\r\n currentLayer = layer;\r\n found = true;\r\n break;\r\n }\r\n } else if(c >= (layer.base ?? 0) && c <= (layer.range ?? 255)){\r\n let index = c - (layer.base ?? 0);\r\n if(index >= 0 && index < layer.map.length) {\r\n if(layer.shift) index = DbStringTypeUtils.getShiftDown(layer.shift)(index);\r\n builder.push(layer.map[index]);\r\n found = true;\r\n break;\r\n }\r\n }\r\n }\r\n }\r\n if(!found) {\r\n const index = currentLayer.shift ? DbStringTypeUtils.getShiftDown(currentLayer.shift)(c) : c - (currentLayer.base ?? 0);\r\n if (index >= 0 && index < currentLayer.map.length) {\r\n builder.push(currentLayer.map[index]);\r\n } else {\r\n // Fallback for unknown characters\r\n builder.push(`[${c.toString(16).toUpperCase()}]`);\r\n }\r\n }\r\n }\r\n\r\n if(fixedSize && this._romDataReader.position >= strLoc + fixedSize) break;\r\n \r\n } while (this._blockReader.partCanContinue());\r\n\r\n if(fixedSize && this._romDataReader.position < strLoc + fixedSize) this._romDataReader.position = strLoc + fixedSize;\r\n\r\n return {\r\n string: builder.join(''),\r\n type: stringType,\r\n marker: 0,\r\n location: strLoc,\r\n fixedSize\r\n };\r\n }\r\n\r\n public resolveString(sw: StringWrapper, isBranch: boolean): void {\r\n let str = sw.string;\r\n let ix = indexOfAny(str, StringReader.STRING_REFERENCE_CHARACTERS);\r\n \r\n while (ix >= 0) {\r\n if (ix + 6 < str.length) {\r\n const hexStr = str.substring(ix + 1, ix + 7);\r\n const sloc = parseInt(hexStr, 16);\r\n \r\n if (!isNaN(sloc)) {\r\n const addrs = new Address((sloc >> 16) & 0xFF, sloc & 0xFFFF, this._blockReader._root.config.memoryMode);\r\n if (addrs.isROM) {\r\n this._blockReader.resolveInclude(sloc, false);\r\n const name = this._blockReader.resolveName(sloc, AddressType.Unknown, false);\r\n const opix = indexOfAny(name, RomProcessingConstants.OPERATORS);\r\n \r\n if (opix > 0) {\r\n const offsetStr = name.substring(opix + 1);\r\n let offset: number;\r\n \r\n if (offsetStr === 'M') {\r\n offset = this._blockReader._referenceManager.markerTable.get(sloc) || 0;\r\n } else {\r\n offset = parseInt(offsetStr, 16) || 0;\r\n }\r\n\r\n if (name[opix] === '-') {\r\n offset = -offset;\r\n }\r\n\r\n const targetName = name.substring(0, opix);\r\n const target = sloc - offset;\r\n \r\n // Try to find the target using IsOutside pattern\r\n const [isOutside, block, part] = ChunkFileUtils.isOutsideWithPart(this._blockReader._enrichedChunks, this._blockReader._currentChunk!, sloc);\r\n if (part != null) {\r\n const entry = part.objList?.find((x): x is TableEntry => \r\n typeof x === 'object' && x !== null && 'location' in x && 'object' in x && (x as TableEntry).location === target) as TableEntry | undefined;\r\n if (entry && entry.object) {\r\n (entry.object as StringWrapper).marker = offset;\r\n }\r\n }\r\n }\r\n }\r\n }\r\n }\r\n \r\n ix = indexOfAny(str, StringReader.STRING_REFERENCE_CHARACTERS, ix + 7);\r\n }\r\n }\r\n\r\n}","import { DbRoot, DbStringCommand, DbStringLayer, DbStringType, DbStringTypeUtils } from '../../database';\r\nimport { MemberType, StringMarker } from '../../types';\r\nimport type { Assembler } from './assembler';\r\n\r\n/**\r\n * String processor for assembly parsing\r\n * Converted from GaiaLib/Rom/Rebuild/StringProcessor.cs\r\n */\r\nexport class StringProcessor {\r\n private memBuffer: number[] = [];\r\n private totalSize: number = 0;\r\n private fixedStr: number = 0;\r\n private readonly context: Assembler;\r\n private readonly root: DbRoot;\r\n private readonly stringCharLookup: Record<string, DbStringType>;\r\n private readonly testRegex: RegExp;\r\n private inShift: boolean = false;\r\n\r\n constructor(context: Assembler) {\r\n this.context = context;\r\n this.root = context.root;\r\n this.stringCharLookup = context.root.stringDelimiterLookup;\r\n this.testRegex = new RegExp(/^[0-9A-F]+$/i);\r\n }\r\n\r\n public consumeString(typeChar: string): void {\r\n let str: string | null = null;\r\n let fixedStr: number = 0;\r\n\r\n // Get character code of string type\r\n //const typeChar = this.context.lineBuffer[0];\r\n\r\n // Find last index of character code\r\n const endIx = this.context.lineBuffer.indexOf(typeChar, 1);\r\n if (endIx >= 0) {\r\n // Take the line up until the type code\r\n str = this.context.lineBuffer.substring(1, endIx);\r\n // Line takes content after and code\r\n this.context.lineBuffer = this.context.lineBuffer.substring(endIx + 1)\r\n .replace(/^[\\s,\\t]+/, '');\r\n if(this.context.lineBuffer.startsWith('(')) {\r\n const endIx = this.context.lineBuffer.indexOf(')');\r\n if(endIx >= 0) {\r\n fixedStr = parseInt(this.context.lineBuffer.substring(1, endIx), 10);\r\n this.context.lineBuffer = this.context.lineBuffer.substring(endIx + 1)\r\n .replace(/^[\\s,\\t]+/, '');\r\n }\r\n }\r\n } else {\r\n // Take the remaining line\r\n str = this.context.lineBuffer.substring(1);\r\n this.context.lineBuffer = '';\r\n }\r\n\r\n // Reset memory buffer for new string\r\n this.memBuffer.length = 0;\r\n this.totalSize = 0;\r\n this.fixedStr = fixedStr;\r\n\r\n this.processString(str!, typeChar);\r\n }\r\n\r\n private flushBuffer(stringType: DbStringType, wrap: boolean = false): void {\r\n const size = this.memBuffer.length;\r\n if (size > 0) {\r\n const newSize = this.totalSize + size;\r\n if(this.fixedStr && newSize > this.fixedStr) {\r\n const buffer = new Uint8Array(this.memBuffer.slice(0, this.fixedStr - this.totalSize));\r\n this.context.currentBlock!.objList.push(buffer);\r\n this.context.currentBlock!.size += buffer.length;\r\n this.totalSize = this.fixedStr;\r\n } else {\r\n const buffer = new Uint8Array(this.memBuffer);\r\n this.context.currentBlock!.objList.push(buffer);\r\n this.context.currentBlock!.size += size;\r\n this.totalSize += size;\r\n }\r\n this.memBuffer.length = 0;\r\n }\r\n }\r\n\r\n private processString(str: string, typeChar: string): void {\r\n const stringType = this.stringCharLookup[typeChar];\r\n const dictionary = stringType.dictionaryLookup;\r\n const cmdLookup = stringType.commands;\r\n let currentLayer = stringType.layers[0];\r\n\r\n //const charMap = stringType.characterMap;\r\n //const shift = this.getShiftUp(stringType.shiftType);\r\n let lastCmd: DbStringCommand | null = null;\r\n\r\n let fullMatch = false;\r\n for(const entry of dictionary) {\r\n let index : number;\r\n while((index = str.indexOf(entry.text)) >= 0) {\r\n if(index === 0 && str.length === entry.text.length) {\r\n fullMatch = true;\r\n break;\r\n }\r\n str = str.substring(0, index) + `[${(entry.id).toString(16).toUpperCase()}]` + str.substring(index + entry.text.length);\r\n }\r\n if(fullMatch) break;\r\n }\r\n\r\n\r\n for (let x = 0; x < str.length; x++) {\r\n const c = str[x];\r\n if (c === '[') {\r\n const endIx = str.indexOf(']', x + 1);\r\n const splitChars = [':', ',', ' '];\r\n\r\n const parts = str.substring(x + 1, endIx)\r\n .split(new RegExp(`[${splitChars.join('')}]`))\r\n .filter(p => p.length > 0);\r\n\r\n x = endIx;\r\n\r\n // Marker\r\n if (parts.length === 0) {\r\n this.flushBuffer(stringType, true);\r\n this.context.currentBlock!.objList.push({\r\n offset: this.context.currentBlock!.size\r\n } as StringMarker);\r\n continue;\r\n }\r\n\r\n const cmd = cmdLookup[parts[0]];\r\n if (cmd) {\r\n lastCmd = cmd;\r\n this.memBuffer.push(cmd.id);\r\n this.processStringCommand(cmd, stringType, parts);\r\n continue;\r\n }\r\n\r\n //Direct values for dictionary commands etc\r\n if(parts.length === 1 && this.testRegex.test(parts[0])) {\r\n const value = parseInt(parts[0], 16);\r\n if(value < 0x100) this.memBuffer.push(value);\r\n else this.memBuffer.push((value >> 8) & 0xFF, value & 0xFF);\r\n continue;\r\n }\r\n }\r\n\r\n lastCmd = null;\r\n\r\n // Process string layers\r\n let found = false;\r\n for (const layer of stringType.layers) {\r\n for (let i = 0, len = layer.map.length; i < len; i++) {\r\n const v = layer.map[i];\r\n if (c === v) {\r\n //Toggle layers if they are not active\r\n if(layer.on !== undefined && currentLayer !== layer) {\r\n this.memBuffer.push(layer.on);\r\n currentLayer = layer;\r\n }\r\n\r\n let value = i + (layer.base ?? 0);\r\n if(layer.shift) value = DbStringTypeUtils.getShiftUp(layer.shift)(value);\r\n this.memBuffer.push(value);\r\n found = true; \r\n break;\r\n }\r\n }\r\n if(found) break;\r\n }\r\n }\r\n\r\n if(this.fixedStr) {\r\n let count = this.fixedStr - this.totalSize;\r\n while(count--) this.memBuffer.push(stringType.terminator);\r\n } else if (lastCmd === null || !lastCmd.halt) {\r\n this.memBuffer.push(stringType.terminator);\r\n }\r\n\r\n this.flushBuffer(stringType, true);\r\n }\r\n\r\n private processStringCommand(cmd: DbStringCommand, stringType: DbStringType, parts: string[]): void {\r\n const hasPointer = cmd.types.includes(MemberType.Address) || cmd.types.includes(MemberType.Offset);\r\n if (hasPointer) {\r\n this.flushBuffer(stringType, true);\r\n }\r\n\r\n for (let y = 0, pix = 1; y < cmd.types.length; y++, pix++) {\r\n switch (cmd.types[y]) {\r\n case MemberType.Byte:\r\n this.memBuffer.push(parseInt(parts[pix], 16));\r\n break;\r\n\r\n case MemberType.Word:\r\n const us = parseInt(parts[pix], 16);\r\n this.memBuffer.push(us & 0xFF);\r\n this.memBuffer.push((us >> 8) & 0xFF);\r\n break;\r\n\r\n case MemberType.Binary:\r\n while (pix < parts.length) {\r\n const ch = parseInt(parts[pix], 16);\r\n this.memBuffer.push(ch);\r\n pix++;\r\n }\r\n if (cmd.delimiter !== undefined) {\r\n this.memBuffer.push(cmd.delimiter);\r\n }\r\n break;\r\n\r\n case MemberType.Offset:\r\n case MemberType.Address:\r\n // Have to keep these for later since we don't have lookups yet\r\n this.flushBuffer(stringType, false);\r\n this.context.currentBlock!.objList.push(parts[pix]);\r\n this.context.currentBlock!.size += cmd.types[y] === MemberType.Offset ? 2 : 3;\r\n break;\r\n }\r\n }\r\n\r\n if (hasPointer) {\r\n this.flushBuffer(stringType, false);\r\n }\r\n }\r\n}\r\n","/**\r\n * A map that sorts keys by length in descending order, then alphabetically\r\n * This is used for tag replacement where longer tags should be replaced first\r\n * to avoid conflicts (e.g., \"ABCD\" should be replaced before \"ABC\")\r\n */\r\nexport class SortedMap<V> {\r\n private map = new Map<string, V>();\r\n private _keys: string[] = [];\r\n\r\n public get size(): number {\r\n return this.map.size;\r\n }\r\n\r\n public set(key: string, value: V): this {\r\n if (!this.map.has(key)) {\r\n this._keys.push(key);\r\n this.sortKeys();\r\n }\r\n this.map.set(key, value);\r\n return this;\r\n }\r\n\r\n public get(key: string): V | undefined {\r\n return this.map.get(key);\r\n }\r\n\r\n public has(key: string): boolean {\r\n return this.map.has(key);\r\n }\r\n\r\n public delete(key: string): boolean {\r\n const result = this.map.delete(key);\r\n if (result) {\r\n const index = this._keys.indexOf(key);\r\n if (index >= 0) {\r\n this._keys.splice(index, 1);\r\n }\r\n }\r\n return result;\r\n }\r\n\r\n public clear(): void {\r\n this.map.clear();\r\n this._keys.length = 0;\r\n }\r\n\r\n public keys(): string[] {\r\n return [...this._keys];\r\n }\r\n\r\n public values(): V[] {\r\n return this._keys.map(key => this.map.get(key)!);\r\n }\r\n\r\n public entries(): [string, V][] {\r\n return this._keys.map(key => [key, this.map.get(key)!]);\r\n }\r\n\r\n public *[Symbol.iterator](): Generator<[string, V], void, unknown> {\r\n for (const key of this._keys) {\r\n yield [key, this.map.get(key)!];\r\n }\r\n }\r\n\r\n private sortKeys(): void {\r\n this._keys.sort((a, b) => {\r\n // Sort by length descending first\r\n if (a.length !== b.length) {\r\n return b.length - a.length;\r\n }\r\n // Then alphabetically\r\n return a.localeCompare(b);\r\n });\r\n }\r\n}\r\n","import { Byte, RomProcessingConstants, AsmBlock, Op } from '../../types';\r\nimport { DbRoot, DbStruct, OpCode } from '../../database';\r\nimport type { Assembler } from './assembler';\r\nimport { AsmReader } from '../extraction/asm';\r\n\r\n/**\r\n * Assembler state machine for processing assembly text\r\n * Converted from GaiaLib/Rom/Rebuild/AssemblerState.cs\r\n */\r\nexport class AssemblerState {\r\n private readonly dbStruct: DbStruct | null;\r\n private readonly parentStruct: DbStruct | null;\r\n private readonly root: DbRoot;\r\n private readonly discriminator: number | null;\r\n private delimiter: number | null;\r\n private memberOffset: number;\r\n private dataOffset: number;\r\n private readonly memberTypes: string[] | null;\r\n private currentType: string | null;\r\n private readonly context: Assembler;\r\n\r\n constructor(context: Assembler, structType: string | null = null, saveDelimiter: boolean = false) {\r\n this.context = context;\r\n this.root = context.root;\r\n\r\n this.dbStruct = structType === null ? null\r\n : Object.values(this.root.structs).find(x =>\r\n x.name.toLowerCase() === structType.toLowerCase()\r\n ) || null;\r\n\r\n this.parentStruct = !this.dbStruct || !this.dbStruct.parent ? null\r\n : Object.values(this.root.structs).find(x =>\r\n x.name.toLowerCase() === this.dbStruct!.parent!.toLowerCase()\r\n ) || null;\r\n\r\n this.discriminator = this.parentStruct?.discriminator ?? null;\r\n this.delimiter = this.dbStruct?.delimiter ?? null;\r\n this.memberOffset = 0;\r\n this.dataOffset = 0;\r\n this.memberTypes = this.dbStruct?.types || null;\r\n this.currentType = this.memberTypes?.[this.memberOffset] || null;\r\n\r\n if (saveDelimiter) {\r\n this.context.lastDelimiter = this.dbStruct?.delimiter ?? this.parentStruct?.delimiter ?? null;\r\n }\r\n }\r\n\r\n private checkDisc(): void {\r\n if (this.discriminator === this.dataOffset) {\r\n // Discriminator is always 1 byte\r\n this.context.currentBlock!.objList.push(this.dbStruct!.discriminator!);\r\n this.context.currentBlock!.size += 1;\r\n this.dataOffset += 1;\r\n }\r\n }\r\n\r\n private advancePart(): void {\r\n if (this.currentType != null && this.discriminator != null) {\r\n this.dataOffset += RomProcessingConstants.getSize(this.currentType);\r\n }\r\n\r\n if (this.memberTypes != null && this.memberOffset + 1 < this.memberTypes.length) {\r\n this.currentType = this.memberTypes[++this.memberOffset];\r\n }\r\n }\r\n\r\n private processOrigin(): void {\r\n this.context.lineBuffer = this.context.lineBuffer.substring(3).replace(/^[\\s,\\t]+/, '');\r\n if (this.context.lineBuffer.startsWith('$')) {\r\n this.context.lineBuffer = this.context.lineBuffer.substring(1);\r\n }\r\n\r\n let hex: string;\r\n const endIx = this.context.lineBuffer.search(/[\\s,\\t]/);\r\n if (endIx >= 0) {\r\n hex = this.context.lineBuffer.substring(0, endIx);\r\n this.context.lineBuffer = this.context.lineBuffer.substring(endIx + 1).replace(/^[\\s,\\t]+/, '');\r\n } else {\r\n hex = this.context.lineBuffer;\r\n this.context.lineBuffer = '';\r\n }\r\n\r\n const location = parseInt(hex, 16);\r\n\r\n this.context.blocks.push(this.context.currentBlock = new AsmBlock(location));\r\n //this.context.blockIndex++;\r\n }\r\n\r\n private static doMath(operand: string): string {\r\n const ix = operand.search(/[-+]/);\r\n if (ix >= 0) {\r\n const op = operand[ix];\r\n\r\n const vix = operand.lastIndexOf('$', ix) + 1;\r\n\r\n const valueStr = operand.substring(vix, ix);\r\n if (valueStr.match(/^[a-fA-F0-9]+$/)) {\r\n const value = parseInt(valueStr, 16);\r\n \r\n let endIx = operand.substring(ix + 1).search(RomProcessingConstants.SYMBOL_SPACE_REGEX);\r\n if(endIx < 0) {\r\n endIx = operand.length;\r\n }\r\n \r\n const number = parseInt(operand.substring(ix + 1, endIx), 16);\r\n\r\n let result: number;\r\n if (op === '-') {\r\n result = value - number;\r\n } else {\r\n result = value + number;\r\n }\r\n\r\n const len = (ix - vix) <= 2 ? 2 : (ix - vix) <= 4 ? 4 : 6;\r\n\r\n operand = operand.substring(0, vix) + result.toString(16).toUpperCase().padStart(len, '0') + operand.substring(endIx);\r\n }\r\n }\r\n return operand;\r\n }\r\n\r\n private tryCreateLabel(mnemonic: string, operand?: string): boolean {\r\n // Check that the operand has content\r\n if (!operand || operand.length === 0) {\r\n return false;\r\n }\r\n\r\n const labelChar = operand[0];\r\n\r\n // If our operand starts with a label space character, create a label\r\n if (!RomProcessingConstants.LABEL_SPACE.includes(labelChar)) {\r\n return false;\r\n }\r\n\r\n // Create new block for this label\r\n const newBlock = new AsmBlock(\r\n this.context.currentBlock!.location + this.context.currentBlock!.size,\r\n 0,\r\n this.root.stringDelimiters.includes(operand[0]),\r\n mnemonic\r\n );\r\n\r\n // const conditionBlock = this.context.conditionBlock;\r\n // if(conditionBlock) {\r\n // conditionBlock.objList.push(newBlock);\r\n // } else {\r\n this.context.blocks.push(newBlock);\r\n //}\r\n\r\n // Set as current\r\n this.context.currentBlock = newBlock;\r\n\r\n // Increment current block index\r\n //this.context.blockIndex++;\r\n\r\n // Remove label marker\r\n if (labelChar === ':') {\r\n this.context.lineBuffer = this.context.lineBuffer.substring(1);\r\n } else if (labelChar === '[' || labelChar === '{') {\r\n this.context.lineBuffer = operand.substring(1).replace(/^[\\s,\\t]+/, '');\r\n\r\n // Process the next \r\n const state = new AssemblerState(this.context, this.currentType);\r\n state.processText(labelChar);\r\n\r\n // Advance to next part\r\n this.advancePart();\r\n }\r\n\r\n return true;\r\n }\r\n\r\n public processText(openTag?: string): void {\r\n this.checkDisc();\r\n\r\n while (!this.context.eof) {\r\n if (!this.context.getLine()) {\r\n return;\r\n }\r\n\r\n // if (this.context.lineBuffer.startsWith('DB')) {\r\n // const hex = this.context.lineBuffer.substring(2).replace(HEX_REGEX, '');\r\n // const data = this.hexStringToBytes(hex);\r\n // this.context.currentBlock!.objList.push(data);\r\n // this.context.currentBlock!.size += data.length;\r\n // this.context.lineBuffer = '';\r\n // continue;\r\n // }\r\n\r\n let mnemonic: string | null = null;\r\n let operand: string | null = null;\r\n let operand2: string | null = null;\r\n\r\n while (this.context.lineBuffer.length > 0) {\r\n const lineSymbol = this.context.lineBuffer[0];\r\n\r\n // Process strings\r\n if (this.root.stringDelimiters.includes(lineSymbol)) {\r\n this.context.stringProcessor.consumeString(lineSymbol);\r\n this.advancePart();\r\n continue;\r\n }\r\n\r\n // Process raw data\r\n if (RomProcessingConstants.ADDRESS_SPACE.includes(lineSymbol)) {\r\n this.context.processRawData();\r\n\r\n if (openTag === '[') {\r\n this.context.lastDelimiter = null;\r\n }\r\n\r\n this.advancePart();\r\n continue;\r\n }\r\n\r\n if (lineSymbol === '>') {\r\n if (openTag === '<') {\r\n this.context.lineBuffer = this.context.lineBuffer.substring(1).replace(/^[\\s,\\t]+/, '');\r\n this.checkDisc();\r\n }\r\n return;\r\n }\r\n\r\n // Array Close\r\n if (lineSymbol === ']') {\r\n this.context.lineBuffer = this.context.lineBuffer.substring(1).replace(/^[\\s,\\t]+/, '');\r\n\r\n this.delimiter = this.delimiter ?? this.context.lastDelimiter;\r\n\r\n // Apply delimiter if set\r\n if (this.delimiter != null) {\r\n if (this.delimiter >= 0x100) {\r\n // When over the word boundary use two bytes\r\n this.context.currentBlock!.objList.push(this.delimiter);\r\n this.context.currentBlock!.size += 2;\r\n } else {\r\n // Otherwise default to single byte\r\n this.context.currentBlock!.objList.push(this.delimiter);\r\n this.context.currentBlock!.size += 1;\r\n }\r\n }\r\n\r\n return;\r\n }\r\n\r\n // Block close\r\n if (lineSymbol === '}') {\r\n if (openTag === '{') {\r\n this.context.lineBuffer = this.context.lineBuffer.substring(1).replace(/^[\\s,\\t]+/, '');\r\n }\r\n return;\r\n }\r\n\r\n // Array Open\r\n if (lineSymbol === '[') {\r\n this.context.lineBuffer = this.context.lineBuffer.substring(1).replace(/^[\\s,\\t]+/, '');\r\n const state = new AssemblerState(this.context, this.currentType);\r\n state.processText('[');\r\n this.advancePart();\r\n continue;\r\n }\r\n\r\n // Process origin tags\r\n if (this.context.lineBuffer.startsWith('ORG')) {\r\n this.processOrigin();\r\n continue;\r\n }\r\n\r\n // Separate instructions into mnemonic and operand parts\r\n const symbolIndex = this.context.lineBuffer.search(RomProcessingConstants.SYMBOL_SPACE_REGEX);\r\n if (symbolIndex > 0) {\r\n mnemonic = this.context.lineBuffer.substring(0, symbolIndex);\r\n operand = this.context.lineBuffer.substring(symbolIndex).replace(/^[, \\t]+/, '');\r\n\r\n // Process object tags\r\n if (operand && operand.startsWith('<')) {\r\n this.context.lineBuffer = operand.substring(1).replace(/^[, \\t]+/, '');\r\n const state = new AssemblerState(this.context, mnemonic, openTag === '[' && this.currentType == null);\r\n state.processText('<');\r\n mnemonic = null;\r\n continue;\r\n }\r\n \r\n this.context.lineBuffer = operand;\r\n } else {\r\n mnemonic = this.context.lineBuffer;\r\n this.context.lineBuffer = '';\r\n }\r\n\r\n break;\r\n }\r\n\r\n if (mnemonic && mnemonic.length > 0) {\r\n // Get list of opcodes from mnemonic\r\n const codes = this.root.opLookup[mnemonic.toUpperCase()];\r\n\r\n // If no codes were found, try to create a label\r\n if (!codes || codes.length === 0) {\r\n if (this.tryCreateLabel(mnemonic, operand || undefined)) {\r\n continue;\r\n }\r\n\r\n // If label creation fails, throw exception\r\n throw new Error(`Unknown instruction line ${this.context.lineCount}: '${mnemonic}'`);\r\n }\r\n\r\n // Reset current assembler line\r\n this.context.lineBuffer = '';\r\n\r\n // No operand instructions\r\n if (!operand) {\r\n const opCode = codes.find(x => this.root.addrLookup[x.mode].size === 1);\r\n this.context.currentBlock!.objList.push(new Op (opCode!, 0, [], 1));\r\n this.context.currentBlock!.size++;\r\n continue;\r\n }\r\n\r\n // Do maths before regex processing\r\n operand = AssemblerState.doMath(operand);\r\n\r\n // COP processing\r\n let opCode: OpCode | null = codes[0];\r\n if (opCode?.mnem === 'COP') {\r\n const parts = operand.split(/[\\s\\t,()[\\]$#]/).filter(p => p.length > 0);\r\n const cmd = parts[0];\r\n\r\n const cop = this.root.copLookup[cmd];\r\n if (!cop) {\r\n throw new Error(`Unknown COP command ${cmd}`);\r\n }\r\n\r\n this.context.currentBlock!.objList.push(new Op(opCode, 0, [new Byte(cop.id), ...parts.slice(1)], cop.size + 2));\r\n\r\n this.context.currentBlock!.size += cop.size + 2;\r\n\r\n continue;\r\n }\r\n\r\n opCode = null;\r\n for (const code of codes) {\r\n // Keep branch operands until all blocks are processed (for labels)\r\n if (code.mode === 'PCRelative' || code.mode === 'PCRelativeLong') {\r\n opCode = code;\r\n break;\r\n }\r\n\r\n // Regex parse operand based on addressing mode\r\n const addrMode = this.root.addrLookup[code.mode]; \r\n const regex = addrMode.parseRegex;\r\n if (regex) {\r\n const match = new RegExp(regex).exec(operand);\r\n if (match) {\r\n // Keep the current code\r\n opCode = code;\r\n\r\n // Operand is the \"first\" matched group\r\n operand = match[1];\r\n\r\n // Support for second operand (MVN/MVP)\r\n if (match.length > 2) {\r\n operand2 = match[2];\r\n }\r\n\r\n break;\r\n }\r\n }\r\n }\r\n\r\n if (operand!.startsWith('#')) {\r\n operand = operand!.substring(1);\r\n }\r\n\r\n if (operand!.startsWith('$')) {\r\n operand = operand!.substring(1);\r\n }\r\n\r\n if (opCode == null) {\r\n const addrIx = operand!.search(RomProcessingConstants.ADDRESS_SPACE_REGEX);\r\n if (addrIx && addrIx >= 0) {\r\n const eix = operand!.search(/[\\s\\t,\\])]/);\r\n if (eix && eix >= 0) {\r\n operand = operand!.substring(addrIx, eix);\r\n }\r\n }\r\n\r\n opCode = codes.find(x => x.mode === 'Immediate')\r\n ?? codes.find(x => x.mode === 'AbsoluteLong')\r\n ?? codes.find(x => x.mode === 'Absolute')\r\n ?? null;\r\n\r\n if (opCode == null) {\r\n throw new Error(`Unable to determine mode/code line ${this.context.lineCount}: '${this.context.lineBuffer}'`);\r\n }\r\n }\r\n\r\n const opnd1 = this.context.parseOperand(operand!);\r\n\r\n const addrMode = this.root.addrLookup[opCode.mode];\r\n let size = addrMode.size;\r\n if (size === AsmReader.VARIABLE_SIZE_INDICATOR || opCode.mode === 'Immediate') {\r\n size = operand?.startsWith('^') || operand?.length === 2 ? 2 : 3;\r\n }\r\n\r\n const operands: unknown[] = operand2 != null ? [opnd1, this.context.parseOperand(operand2)] : [opnd1];\r\n\r\n this.context.currentBlock!.objList.push(new Op(opCode, 0, operands, size));\r\n\r\n this.context.currentBlock!.size += size;\r\n }\r\n }\r\n }\r\n\r\n private hexStringToBytes(hex: string): Uint8Array {\r\n const result = new Uint8Array(hex.length / 2);\r\n for (let i = 0; i < hex.length; i += 2) {\r\n result[i / 2] = parseInt(hex.substring(i, i + 2), 16);\r\n }\r\n return result;\r\n }\r\n}\r\n","import { RomProcessingConstants, Word, Byte, Long } from '../../types';\r\nimport { DbRoot } from '../../database';\r\nimport { AsmBlock } from '../../types/assembly';\r\nimport { StringProcessor } from './string-processor';\r\nimport { SortedMap } from './sorted-map';\r\nimport { AssemblerState } from './assembler-state';\r\n\r\n// export class ConditionBlock extends AsmBlock {\r\n// public condition: string;\r\n// //public next: ConditionBlock | null = null;\r\n\r\n// constructor(location: number = 0, condition: string) {\r\n// super(location, 0, false, undefined, undefined, undefined);\r\n// this.condition = condition;\r\n// }\r\n// }\r\n\r\n/**\r\n * Main assembler class for parsing assembly files\r\n * Converted from GaiaLib/Rom/Rebuild/Assembler.cs\r\n */\r\nexport class Assembler {\r\n public readonly root: DbRoot;\r\n private readonly lines: string[];\r\n private currentLineIndex: number = 0;\r\n public readonly stringProcessor: StringProcessor;\r\n\r\n public lineBuffer: string = '';\r\n public includes = new Set<string>();\r\n public blocks: AsmBlock[] = [];\r\n public tags = new SortedMap<string | null>();\r\n public currentBlock: AsmBlock | null = null;\r\n public lineCount: number = 0;\r\n //public blockIndex: number = 0;\r\n public lastDelimiter: number | null = null;\r\n public reqBank: number | null = null;\r\n public eof: boolean = false;\r\n public strDelimRegex: RegExp;\r\n public conditionFiles: string[];\r\n private inCondition: boolean = false;\r\n private exitCondition: boolean = false;\r\n private failCondition: boolean = false;\r\n\r\n constructor(dbRoot: DbRoot, textData: string, conditionFiles: string[]) {\r\n this.root = dbRoot;\r\n // Handle both Windows (\\r\\n) and Unix (\\n) line endings\r\n this.lines = textData.split(/\\r?\\n/);\r\n this.stringProcessor = new StringProcessor(this);\r\n this.strDelimRegex = new RegExp(`[${this.root.stringDelimiters.map(c => c.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')).join('')}]`);\r\n this.conditionFiles = conditionFiles;\r\n }\r\n\r\n public parseAssembly(): { blocks: AsmBlock[], includes: Set<string>, reqBank: number | null } {\r\n // Initialize root block (no label, location 0) and set as current\r\n this.blocks.push(this.currentBlock = new AsmBlock());\r\n\r\n // Initialize state machine and process text\r\n const state = new AssemblerState(this);\r\n state.processText();\r\n\r\n return { \r\n blocks: this.blocks, \r\n includes: this.includes, \r\n reqBank: this.reqBank \r\n };\r\n }\r\n\r\n public getLine(): boolean {\r\n // This can happen\r\n if (this.eof) {\r\n return false;\r\n }\r\n\r\n // Keep processing what we already have\r\n if (this.lineBuffer.length > 0) {\r\n return true;\r\n }\r\n\r\n let rawLine: string | null = null;\r\n \r\n while (true) {\r\n // Read next line\r\n if (this.currentLineIndex >= this.lines.length) {\r\n if (this.lineBuffer.length === 0) {\r\n this.eof = true;\r\n return false;\r\n } else {\r\n rawLine = '';\r\n }\r\n } else {\r\n rawLine = this.lines[this.currentLineIndex++];\r\n this.lineBuffer += rawLine;\r\n }\r\n\r\n this.lineCount++;\r\n\r\n // Ignore comments\r\n this.trimComments('--');\r\n this.trimComments(';');\r\n this.trimComments('//');\r\n\r\n // Trim\r\n this.lineBuffer = this.lineBuffer.replace(RomProcessingConstants.COMMA_SPACE_TRIM_REGEX, '');\r\n\r\n // This can happen\r\n if (this.lineBuffer.length === 0) {\r\n continue;\r\n }\r\n\r\n // Process hard line continuations\r\n if (this.lineBuffer.endsWith('\\\\')) {\r\n this.lineBuffer = this.lineBuffer.slice(0, -1);\r\n continue;\r\n }\r\n\r\n // Process directives\r\n if (this.lineBuffer[0] === '?') {\r\n this.processDirectives();\r\n this.lineBuffer = '';\r\n continue;\r\n }\r\n\r\n if(this.failCondition) {\r\n this.lineBuffer = '';\r\n continue;\r\n }\r\n\r\n // Process tags\r\n if (this.lineBuffer[0] === '!') {\r\n this.processTags();\r\n this.lineBuffer = '';\r\n continue;\r\n }\r\n\r\n this.resolveTags();\r\n\r\n return true;\r\n }\r\n }\r\n\r\n private trimComments(sequence: string): void {\r\n // Look for the first instance of the comment sequence\r\n const index = this.lineBuffer.indexOf(sequence);\r\n if (index >= 0) {\r\n // Make sure it's not inside a string\r\n const strIndex = this.lineBuffer.search(this.strDelimRegex);\r\n \r\n // This works with line continuations because the string ending will not be on this line yet\r\n // If no string, string starts after comment, or last delimiter is before comment, trim it\r\n if (strIndex < 0 || \r\n strIndex > index || \r\n this.lineBuffer.lastIndexOf(this.lineBuffer[strIndex] || '') < index) {\r\n this.lineBuffer = this.lineBuffer.substring(0, index);\r\n }\r\n }\r\n }\r\n\r\n private processDirectives(): void {\r\n // Find end of directive\r\n let endIx = this.lineBuffer.search(RomProcessingConstants.COMMA_SPACE_REGEX);\r\n\r\n // Default to line length if no end characters\r\n if (endIx < 0) {\r\n endIx = this.lineBuffer.length;\r\n }\r\n\r\n let value = this.lineBuffer.substring(endIx).replace(/^[\\s,\\t]+/, '');\r\n\r\n switch (this.lineBuffer.substring(1, endIx).toUpperCase()) {\r\n // This is taken care of by the loader\r\n case 'BANK':\r\n this.reqBank = parseInt(value, 16);\r\n break;\r\n\r\n case 'INCLUDE':\r\n if (value.length > 0) {\r\n this.includes.add(value.toUpperCase().replace(/'/g, ''));\r\n }\r\n break;\r\n\r\n case 'IF':\r\n if(this.inCondition) throw new Error('IF without ENDIF');\r\n value = value.replace(/'/g, '');\r\n if(!value) throw new Error('IF without condition');\r\n this.inCondition = true;\r\n if(!this.conditionFiles.includes(value)) { this.failCondition = true; this.exitCondition = false; }\r\n else { this.failCondition = false; this.exitCondition = true; }\r\n break;\r\n \r\n case 'ELSEIF':\r\n if(!this.inCondition) throw new Error('ELSEIF without IF');\r\n value = value.replace(/'/g, '');\r\n if(!value) throw new Error('ELSEIF without condition');\r\n if(this.exitCondition || !this.conditionFiles.includes(value)) this.failCondition = true;\r\n else { this.exitCondition = true; this.failCondition = false; }\r\n break;\r\n \r\n case 'ELSE':\r\n if(!this.inCondition) throw new Error('ELSE without IF');\r\n if(value) throw new Error('ELSE with condition');\r\n\r\n if(this.exitCondition) this.failCondition = true;\r\n else { this.failCondition = false; this.exitCondition = true; }\r\n break;\r\n\r\n case 'ENDIF':\r\n if(!this.inCondition) throw new Error('ENDIF without IF');\r\n if(value) throw new Error('ENDIF with condition');\r\n this.failCondition = false;\r\n this.exitCondition = false;\r\n this.inCondition = false;\r\n break;\r\n }\r\n }\r\n\r\n private processTags(): void {\r\n // Remove the '!' prefix and trim leading spaces\r\n this.lineBuffer = this.lineBuffer.substring(1).replace(/^[\\s,\\t]+/, '');\r\n\r\n // Process as many pairs as we can\r\n while (this.lineBuffer.length > 0) {\r\n // Default name and value\r\n let name = this.lineBuffer;\r\n let value: string | null = null;\r\n\r\n // Find first index of comma/space/tab\r\n let endIx = this.lineBuffer.search(/[\\s,\\t]/);\r\n\r\n if (endIx >= 0) {\r\n // Split into name and value\r\n name = this.lineBuffer.substring(0, endIx);\r\n value = this.lineBuffer.substring(endIx + 1).replace(/^[\\s,\\t]+/, '');\r\n\r\n // Find next index of comma/space/tab inside value\r\n const nextIx = value.search(/[\\s,\\t]/);\r\n if (nextIx >= 0) {\r\n // Line buffer then take the remainder\r\n this.lineBuffer = value.substring(nextIx + 1).replace(/^[\\s,\\t]+/, '');\r\n // Value takes up to next index\r\n value = value.substring(0, nextIx);\r\n } else {\r\n this.lineBuffer = ''; // No more pairs, clear buffer\r\n }\r\n } else {\r\n this.lineBuffer = ''; // Take all as name, clear buffer\r\n }\r\n\r\n // Assign name/value pair to tags\r\n this.tags.set(name, value);\r\n }\r\n }\r\n\r\n private resolveTags(): void {\r\n // Tags are sorted by length descending so longer tags are replaced first (avoids minor conflicts)\r\n for (const [key, value] of this.tags) {\r\n let ix: number;\r\n while ((ix = this.lineBuffer.toLowerCase().indexOf(key.toLowerCase())) >= 0) {\r\n this.lineBuffer = this.lineBuffer.substring(0, ix) + (value || '') + \r\n this.lineBuffer.substring(ix + key.length);\r\n }\r\n }\r\n }\r\n\r\n public parseOperand(opnd: string): unknown {\r\n if (!opnd) return null;\r\n\r\n if(opnd.match(/^[a-fA-F0-9]{2,6}$/)){\r\n switch(opnd.length){\r\n case 2:\r\n return new Byte(parseInt(opnd, 16));\r\n case 4:\r\n return new Word(parseInt(opnd, 16));\r\n case 6:\r\n return new Long(parseInt(opnd, 16));\r\n }\r\n }\r\n\r\n return opnd;\r\n }\r\n\r\n public processRawData(): void {\r\n let reverse = false;\r\n\r\n // Immediate binary marker\r\n if (this.lineBuffer[0] === '#') {\r\n this.lineBuffer = this.lineBuffer.substring(1);\r\n }\r\n\r\n // Reverse binary marker\r\n if (this.lineBuffer[0] === '$') {\r\n reverse = true;\r\n this.lineBuffer = this.lineBuffer.substring(1);\r\n }\r\n\r\n let hex: string;\r\n const symbolIx = this.lineBuffer.search(RomProcessingConstants.SYMBOL_SPACE_REGEX);\r\n if (symbolIx >= 0) {\r\n hex = this.lineBuffer.substring(0, symbolIx);\r\n this.lineBuffer = this.lineBuffer.substring(symbolIx).replace(/^[, \\t]+/, '');\r\n } else {\r\n hex = this.lineBuffer;\r\n this.lineBuffer = '';\r\n }\r\n\r\n if (hex.length > 0) {\r\n // Keep string values of address markers so they can be resolved later\r\n if (RomProcessingConstants.ADDRESS_SPACE.includes(hex[0])) {\r\n this.currentBlock!.objList.push(hex);\r\n this.currentBlock!.size += RomProcessingConstants.getSize(hex);\r\n } else {\r\n const data = this.hexStringToBytes(hex);\r\n if (data.length === 1) {\r\n this.currentBlock!.objList.push(new Byte(data[0]));\r\n this.currentBlock!.size++;\r\n } else {\r\n if (reverse) {\r\n data.reverse();\r\n }\r\n\r\n // Explicitly change two-byte data into number for easier processing later\r\n if (data.length === 2) {\r\n this.currentBlock!.objList.push(new Word(data[0] | (data[1] << 8)));\r\n this.currentBlock!.size += 2;\r\n } else {\r\n this.currentBlock!.objList.push(data);\r\n this.currentBlock!.size += data.length;\r\n }\r\n }\r\n }\r\n }\r\n }\r\n\r\n private hexStringToBytes(hex: string): Uint8Array {\r\n const result = new Uint8Array(hex.length / 2);\r\n for (let i = 0; i < hex.length; i += 2) {\r\n result[i / 2] = parseInt(hex.substring(i, i + 2), 16);\r\n }\r\n return result;\r\n }\r\n}\r\n","/**\r\n * Supabase client configuration and initialization\r\n */\r\n\r\nimport { createClient, SupabaseClient } from '@supabase/supabase-js';\r\n\r\n/**\r\n * Database interface definitions based on Prisma schema\r\n * These types represent the structure of data returned from Supabase queries\r\n */\r\nexport interface Database {\r\n public: {\r\n Tables: {\r\n BaseRom: {\r\n Row: {\r\n id: string;\r\n name: string;\r\n gameId: string;\r\n gameRomId: string;\r\n createdAt: string;\r\n updatedAt: string;\r\n };\r\n };\r\n BaseRomBranch: {\r\n Row: {\r\n id: string;\r\n name: string | null;\r\n version: number | null;\r\n isPublic: boolean;\r\n baseRomId: string;\r\n gameRomBranchId: string;\r\n fileCrcs: number[];\r\n createdAt: string;\r\n updatedAt: string;\r\n };\r\n };\r\n GameRomBranch: {\r\n Row: {\r\n id: string;\r\n name: string | null;\r\n version: number | null;\r\n isPublic: boolean;\r\n gameRomId: string;\r\n platformBranchId: string;\r\n coplib: any | null;\r\n config: any | null;\r\n files: any | null;\r\n blocks: any | null;\r\n fixups: any | null;\r\n strings: any | null;\r\n structs: any | null;\r\n scenes: any | null;\r\n createdAt: string;\r\n updatedAt: string;\r\n };\r\n };\r\n GameRomBranchAsset: {\r\n Row: {\r\n id: string;\r\n name: string;\r\n type: string;\r\n gameRomBranchId: string;\r\n text: string | null;\r\n data: string | null;\r\n createdAt: string;\r\n updatedAt: string;\r\n };\r\n };\r\n PlatformBranch: {\r\n Row: {\r\n id: string;\r\n name: string | null;\r\n version: number | null;\r\n isPublic: boolean;\r\n platformId: string;\r\n addressingModes: any | null;\r\n instructionSet: any | null;\r\n vectors: any | null;\r\n createdAt: string;\r\n updatedAt: string;\r\n };\r\n };\r\n BaseRomFile: {\r\n Row: {\r\n id: string;\r\n name: string;\r\n type: string;\r\n version: number | null;\r\n crc: number | null;\r\n meta: any | null;\r\n baseRomId: string;\r\n data: string; // Base64 encoded binary data\r\n createdAt: string;\r\n updatedAt: string;\r\n };\r\n };\r\n };\r\n };\r\n}\r\n\r\n/**\r\n * Singleton Supabase client instance\r\n */\r\nlet supabaseClient: SupabaseClient<Database> | null = null;\r\n\r\n/**\r\n * Create and configure a Supabase client instance\r\n * @returns Configured Supabase client\r\n */\r\nexport function createSupabaseClient(): SupabaseClient<Database> {\r\n // Validate required environment variables\r\n //validateEnvironmentVariables(['SUPABASE_URL', 'SUPABASE_ANON_KEY']);\r\n \r\n const supabaseUrl = 'https://adwobxutnpmjbmhdxrzx.supabase.co';\r\n const supabaseAnonKey = 'sb_publishable_uBZdKmgGql5sDNGpj1DVMQ_opZ2V4kV';\r\n \r\n return createClient<Database>(supabaseUrl, supabaseAnonKey, {\r\n auth: {\r\n // Disable auth for public data access\r\n persistSession: false,\r\n autoRefreshToken: false,\r\n },\r\n db: {\r\n // Configure database connection\r\n schema: 'public',\r\n },\r\n });\r\n}\r\n\r\n/**\r\n * Get the singleton Supabase client instance\r\n * Creates the instance if it doesn't exist\r\n * @returns Supabase client instance\r\n */\r\nexport function getSupabaseClient(): SupabaseClient<Database> {\r\n if (!supabaseClient) {\r\n supabaseClient = createSupabaseClient();\r\n }\r\n return supabaseClient;\r\n}\r\n\r\n/**\r\n * Reset the singleton client instance (useful for testing)\r\n */\r\nexport function resetSupabaseClient(): void {\r\n supabaseClient = null;\r\n}\r\n\r\n// /**\r\n// * Test the Supabase connection by performing a simple query\r\n// * @returns Promise that resolves to true if connection is successful\r\n// * @throws Error if connection fails\r\n// */\r\n// export async function testSupabaseConnection(): Promise<boolean> {\r\n// try {\r\n// const client = getSupabaseClient();\r\n \r\n// // Perform a simple query to test the connection\r\n// const { data, error } = await client\r\n// .from('BaseRom')\r\n// .select('id')\r\n// .limit(1);\r\n \r\n// if (error) {\r\n// throw new Error(`Supabase connection test failed: ${error.message}`);\r\n// }\r\n \r\n// return true;\r\n// } catch (error) {\r\n// throw new Error(`Failed to connect to Supabase: ${error instanceof Error ? error.message : 'Unknown error'}`);\r\n// }\r\n// }\r\n","/**\r\n * Utility functions for Supabase integration\r\n */\r\n\r\n/**\r\n * Get environment variable value that works in both browser and Node.js contexts\r\n * @param key - The environment variable key to retrieve\r\n * @throws {Error} If the environment variable is not set\r\n * @returns The environment variable value\r\n */\r\nexport function getEnvVar(key: string): string {\r\n let value = '';\r\n\r\n // Try different environment variable sources in order of preference\r\n try {\r\n // Browser with Vite (import.meta.env) - check if we're in a browser environment\r\n if (typeof globalThis !== 'undefined' &&\r\n typeof (globalThis as any).window !== 'undefined' &&\r\n typeof import.meta !== 'undefined' &&\r\n (import.meta as any).env) {\r\n const env = (import.meta as any).env;\r\n // Try the exact key first\r\n value = env[key] ||\r\n // Try with VITE_ prefix if not already prefixed\r\n (key.startsWith('VITE_') ? '' : env[`VITE_${key}`]) ||\r\n '';\r\n }\r\n } catch (error) {\r\n // import.meta might not be available in all contexts, continue to Node.js fallback\r\n }\r\n\r\n // Node.js (process.env) - fallback or primary for server-side\r\n if (!value && typeof process !== 'undefined' && process.env) {\r\n value = process.env[key] ||\r\n // Try with VITE_ prefix if not already prefixed (for Node.js build tools)\r\n (key.startsWith('VITE_') ? '' : process.env[`VITE_${key}`]) ||\r\n '';\r\n }\r\n\r\n if (!value) {\r\n throw new Error(`Required environment variable ${key} is not set`);\r\n }\r\n\r\n return value;\r\n}\r\n\r\n/**\r\n * Convert base64 string to Uint8Array for binary data processing\r\n * @param base64 - Base64 encoded string\r\n * @returns Uint8Array containing the binary data\r\n */\r\nexport function base64ToUint8Array(base64: string): Uint8Array {\r\n // Handle data URLs by extracting just the base64 part\r\n const base64Data = base64.includes(',') ? base64.split(',')[1] : base64;\r\n \r\n try {\r\n // Use browser's built-in atob if available\r\n if (typeof atob !== 'undefined') {\r\n const binaryString = atob(base64Data);\r\n const bytes = new Uint8Array(binaryString.length);\r\n for (let i = 0; i < binaryString.length; i++) {\r\n bytes[i] = binaryString.charCodeAt(i);\r\n }\r\n return bytes;\r\n }\r\n \r\n // Node.js fallback\r\n if (typeof Buffer !== 'undefined') {\r\n return new Uint8Array(Buffer.from(base64Data, 'base64'));\r\n }\r\n \r\n throw new Error('No base64 decoding method available');\r\n } catch (error) {\r\n throw new Error(`Failed to decode base64 data: ${error instanceof Error ? error.message : 'Unknown error'}`);\r\n }\r\n}\r\n\r\n/**\r\n * Convert hex-encoded string to Uint8Array\r\n * @param hexString - Hex encoded string (with or without \\x prefix)\r\n * @returns Uint8Array containing the binary data\r\n */\r\nexport function hexToUint8Array(hexString: string): Uint8Array {\r\n try {\r\n // Remove \\x prefixes and any whitespace\r\n let cleanHex = hexString.replace(/\\\\x/g, '').replace(/\\s/g, '');\r\n\r\n // Ensure even length\r\n if (cleanHex.length % 2 !== 0) {\r\n throw new Error('Hex string must have even length');\r\n }\r\n\r\n const bytes = new Uint8Array(cleanHex.length / 2);\r\n for (let i = 0; i < cleanHex.length; i += 2) {\r\n const hexByte = cleanHex.substring(i, i + 2);\r\n const byte = parseInt(hexByte, 16);\r\n if (isNaN(byte)) {\r\n throw new Error(`Invalid hex character at position ${i}: ${hexByte}`);\r\n }\r\n bytes[i / 2] = byte;\r\n }\r\n\r\n return bytes;\r\n } catch (error) {\r\n throw new Error(`Failed to decode hex data: ${error instanceof Error ? error.message : 'Unknown error'}`);\r\n }\r\n}\r\n\r\n/**\r\n * Convert binary data to appropriate format based on the input string\r\n * Automatically detects if the input is hex-encoded or base64\r\n * @param dataString - Either hex-encoded string (starting with \\x) or base64 string\r\n * @returns Uint8Array containing the binary data\r\n */\r\nexport function decodeDataString(dataString: string): Uint8Array {\r\n // Check if it's hex-encoded (starts with \\x)\r\n if (dataString.startsWith('\\\\x')) {\r\n return hexToUint8Array(dataString);\r\n }\r\n\r\n // Otherwise assume it's base64\r\n return base64ToUint8Array(dataString);\r\n}\r\n\r\n/**\r\n * Convert Uint8Array to base64 string\r\n * @param uint8Array - Binary data as Uint8Array\r\n * @returns Base64 encoded string\r\n */\r\nexport function uint8ArrayToBase64(uint8Array: Uint8Array): string {\r\n try {\r\n // Use browser's built-in btoa if available\r\n if (typeof btoa !== 'undefined') {\r\n const binaryString = Array.from(uint8Array)\r\n .map(byte => String.fromCharCode(byte))\r\n .join('');\r\n return btoa(binaryString);\r\n }\r\n \r\n // Node.js fallback\r\n if (typeof Buffer !== 'undefined') {\r\n return Buffer.from(uint8Array).toString('base64');\r\n }\r\n \r\n throw new Error('No base64 encoding method available');\r\n } catch (error) {\r\n throw new Error(`Failed to encode base64 data: ${error instanceof Error ? error.message : 'Unknown error'}`);\r\n }\r\n}\r\n\r\n/**\r\n * Validate that required environment variables are set\r\n * @param requiredVars - Array of environment variable names that must be set\r\n * @throws {Error} If any required environment variable is missing\r\n */\r\nexport function validateEnvironmentVariables(requiredVars: string[]): void {\r\n const missingVars: string[] = [];\r\n \r\n for (const varName of requiredVars) {\r\n try {\r\n getEnvVar(varName);\r\n } catch {\r\n missingVars.push(varName);\r\n }\r\n }\r\n \r\n if (missingVars.length > 0) {\r\n throw new Error(\r\n `Missing required environment variables: ${missingVars.join(', ')}\\n` +\r\n 'For web/Vite environments, use VITE_ prefixed variables (e.g., VITE_SUPABASE_URL, VITE_SUPABASE_ANON_KEY)\\n' +\r\n 'For Node.js environments, use the variable names directly (e.g., SUPABASE_URL, SUPABASE_ANON_KEY)'\r\n );\r\n }\r\n}\r\n","/**\n * TypeScript interfaces for Supabase API responses\n * These types represent the structured data returned from ROM database queries\n */\n\nexport interface PlatformData {\n id: string;\n name: string;\n meta: any | null;\n createdAt: string;\n updatedAt: string;\n}\n\nexport interface BranchBaseData {\n id: string;\n name: string | null;\n version: number | null;\n isActive?: boolean | null;\n notes?: string[] | null;\n createdAt: string;\n updatedAt: string;\n}\n\nexport interface FileBaseData {\n id: string;\n name: string;\n type: string;\n version: number | null;\n crc: number | null;\n meta: any | null;\n isText: boolean;\n text: string | null;\n data: Uint8Array | null;\n createdAt: string;\n updatedAt: string;\n}\n\nexport interface FileBaseRaw extends Omit<FileBaseData, 'data'> {\n data: string | null;\n}\n\n/**\n * Platform branch information containing instruction set and addressing modes\n */\nexport interface PlatformBranchData extends BranchBaseData {\n platformId: string;\n addressingModes: any | null; // JSON field\n headers: any | null; // JSON field\n vectors: any | null; // JSON field\n types: any | null; // JSON field\n platform: PlatformData;\n}\n\n/**\n * Game ROM branch information with platform reference\n */\nexport interface GameRomBranchData extends BranchBaseData {\n gameRomId: string;\n platformBranchId: string;\n coplib: any | null; // JSON field\n config: any | null; // JSON field\n files: any | null; // JSON field\n blocks: any | null; // JSON field\n rewrites: any | null; // JSON field\n transforms: any | null; // JSON field\n overrides: any | null; // JSON field\n labels: any | null; // JSON field\n mnemonics: any | null; // JSON field\n fileTypes: any | null; // JSON field\n groups: any | null; // JSON field\n strings: any | null; // JSON field\n structs: any | null; // JSON field\n gameRom: GameRomData;\n platformBranch: PlatformBranchData;\n}\n\nexport interface GameRomArtifactData extends FileBaseData {\n gameRomId: string;\n}\n\nexport interface GameRomArtifactRaw extends FileBaseRaw {\n gameRomId: string;\n}\n\nexport interface GameRomBranchArtifactRaw {\n id: string;\n branchId: string;\n artifactId: string;\n artifact: GameRomArtifactRaw;\n}\n\n/**\n * Base ROM information\n */\nexport interface BaseRomData {\n id: string;\n name: string;\n gameId: string;\n gameRomId: string;\n createdAt: string;\n updatedAt: string;\n}\n\nexport interface GameData {\n id: string;\n name: string;\n createdAt: string;\n updatedAt: string;\n}\n\nexport interface DeveloperData {\n id: string;\n name: string;\n meta: any | null;\n createdAt: string;\n updatedAt: string;\n}\n\nexport interface GameDeveloperData {\n id: string;\n gameId: string;\n developerId: string;\n createdAt: string;\n updatedAt: string;\n game: GameData;\n developer: DeveloperData;\n}\n\nexport interface RegionData {\n id: string;\n name: string;\n meta: any | null;\n createdAt: string;\n updatedAt: string;\n}\n\nexport interface GameRomData {\n id: string;\n crc: number;\n meta: any | null;\n gameId: string;\n regionId: string;\n createdAt: string;\n updatedAt: string;\n game: GameData;\n region: RegionData;\n}\n\n\n/**\n * Base ROM branch with complete relationship chain\n */\nexport interface BaseRomBranchData extends BranchBaseData {\n baseRomId: string;\n gameRomBranchId: string;\n gameRomBranch: GameRomBranchData;\n baseRom: BaseRomData;\n}\n\n/**\n * Base ROM file containing binary data\n */\nexport interface BaseRomFileData extends FileBaseData {\n baseRomId: string;\n}\n\nexport interface BaseRomBranchFileRaw {\n id: string;\n branchId: string;\n fileId: string;\n file: BaseRomFileRaw;\n}\n\n/**\n * Raw BaseRomFile data as returned from Supabase (before conversion)\n */\nexport interface BaseRomFileRaw extends FileBaseRaw {\n baseRomId: string;\n}\n\n/**\n * Complete ROM payload containing branch data and files\n */\nexport interface BaseRomPayload {\n baseRomBranch: BaseRomBranchData;\n files: BaseRomFileData[];\n}\n\n/**\n * Options for loading ROM data by name\n */\nexport interface FromSupabaseByNameOptions {\n /**\n * Name of the game to load\n * @default 'Illusion of Gaia'\n */\n gameName: string;\n\n /**\n * Name of the base ROM to load\n * @default 'GaiaLabs BaseROM'\n */\n baseRomName: string;\n \n /**\n * Name of the branch to load\n * Set to null to load the main/develop branch\n * Set to undefined to not filter by branch name\n */\n branchName?: string | null;\n \n /**\n * Version of the branch to load\n * Set to null to load the latest/main version\n * Set to undefined to not filter by version\n */\n branchVersion?: number | null;\n}\n\n/**\n * Error codes for Supabase operations\n */\nexport enum SupabaseErrorCode {\n BRANCH_NOT_FOUND = 'BRANCH_NOT_FOUND',\n ROM_NOT_FOUND = 'ROM_NOT_FOUND',\n FILES_NOT_FOUND = 'FILES_NOT_FOUND',\n NETWORK_ERROR = 'NETWORK_ERROR',\n INVALID_DATA = 'INVALID_DATA',\n ENVIRONMENT_ERROR = 'ENVIRONMENT_ERROR',\n PERMISSION_ERROR = 'PERMISSION_ERROR',\n}\n\n/**\n * Custom error class for Supabase operations\n */\nexport class SupabaseFromError extends Error {\n constructor(\n message: string, \n public readonly code: SupabaseErrorCode,\n public readonly details?: any\n ) {\n super(message);\n this.name = 'SupabaseFromError';\n }\n}\n\n/**\n * Result type for async operations that may fail\n */\nexport type SupabaseResult<T> = {\n data: T;\n error: null;\n} | {\n data: null;\n error: SupabaseFromError;\n};\n\n/**\n * Project information\n */\nexport interface ProjectData {\n id: string;\n name: string;\n meta: any | null; // JSON field\n gameId: string;\n baseRomId: string;\n createdAt: string;\n updatedAt: string;\n}\n\n/**\n * Project branch with complete relationship chain\n */\nexport interface ProjectBranchData extends BranchBaseData {\n projectId: string;\n baseRomBranchId: string;\n modules: any[]; // JSON array\n project: ProjectData;\n baseRomBranch: BaseRomBranchData;\n}\n\n/**\n * Project file containing binary data\n */\nexport interface ProjectFileData extends FileBaseData {\n module: string | null;\n projectId: string;\n}\n\nexport interface ProjectBranchFileRaw {\n id: string;\n branchId: string;\n fileId: string;\n file: ProjectFileRaw;\n}\n\n/**\n * Raw ProjectFile data as returned from Supabase (before conversion)\n */\nexport interface ProjectFileRaw extends FileBaseRaw {\n module: string | null;\n projectId: string;\n}\n\n/**\n * Complete Project payload containing branch data and files\n */\nexport interface ProjectPayload {\n projectBranch: ProjectBranchData;\n projectFiles: ProjectFileData[];\n baseRomBranch: BaseRomBranchData;\n baseRomFiles: BaseRomFileData[];\n}\n\n/**\n * Options for loading Project data by name\n */\nexport interface FromSupabaseByProjectOptions {\n projectName: string;\n /**\n * Name of the branch to load\n * Set to null to load the main/develop branch\n * Set to undefined to not filter by branch name\n */\n branchName?: string | null;\n \n /**\n * Version of the branch to load\n * Set to null to load the latest/main version\n * Set to undefined to not filter by version\n */\n branchVersion?: number | null;\n}\n\n/**\n * Query statistics for performance monitoring\n */\nexport interface QueryStats {\n branchQueryTime: number;\n fileQueryTime: number;\n totalTime: number;\n fileCount: number;\n}\n","/**\n * ROM data loading functions for Supabase integration\n * \n * This module provides functions to load ROM branch data and files from Supabase,\n * enabling cloud-based ROM database functionality for the GaiaLabs platform.\n */\n\nimport { getSupabaseClient } from './client';\nimport { decodeDataString } from './utils';\nimport {\n BaseRomPayload,\n BaseRomBranchData,\n BaseRomFileData,\n FromSupabaseByNameOptions,\n ProjectPayload,\n ProjectBranchData,\n ProjectFileData,\n SupabaseFromError,\n SupabaseErrorCode,\n QueryStats,\n GameRomBranchData,\n ProjectData,\n FileBaseRaw,\n FileBaseData,\n ProjectBranchFileRaw,\n BaseRomBranchFileRaw\n} from './types';\nimport { DbGameRomModule } from '../database';\n\n/**\n * Load ROM data from Supabase using a BaseRomBranch ID\n * \n * @param baseRomBranchId - The ID of the BaseRomBranch to load\n * @returns Promise<BaseRomPayload> containing the branch data and files\n * @throws {SupabaseFromError} If the branch is not found or other errors occur\n * \n * @example\n * ```typescript\n * const payload = await fromSupabaseById('clm1234567890');\n * console.log(payload.baseRomBranch.name);\n * console.log(`Loaded ${payload.files.length} files`);\n * ```\n */\nexport async function fromSupabaseById(baseRomBranchId: string): Promise<BaseRomPayload> {\n const startTime = performance.now();\n let branchQueryTime = 0;\n let fileQueryTime = 0;\n \n try {\n const client = getSupabaseClient();\n \n // Step 1: Get the BaseRomBranch with all related data using joins\n const branchStart = performance.now();\n \n const { data: branchData, error: branchError } = await client\n .from('BaseRomBranch')\n .select(`\n id,\n name,\n version,\n isActive,\n notes,\n baseRomId,\n gameRomBranchId,\n createdAt,\n updatedAt,\n gameRomBranch:GameRomBranch!inner(\n id,\n name,\n version,\n isActive,\n notes,\n gameRomId,\n platformBranchId,\n config,\n files,\n blocks,\n rewrites,\n transforms,\n overrides,\n labels,\n mnemonics,\n fileTypes,\n groups,\n strings,\n structs,\n createdAt,\n updatedAt,\n platformBranch:PlatformBranch!inner(\n id,\n name,\n version,\n isActive,\n notes,\n platformId,\n addressingModes,\n vectors,\n types,\n createdAt,\n updatedAt\n )\n ),\n baseRom:BaseRom!inner(\n id,\n name,\n gameId,\n gameRomId,\n createdAt,\n updatedAt\n )\n `)\n .eq('id', baseRomBranchId)\n .single();\n \n branchQueryTime = performance.now() - branchStart;\n \n if (branchError || !branchData) {\n throw new SupabaseFromError(\n `BaseRomBranch not found with ID: ${baseRomBranchId}`,\n SupabaseErrorCode.BRANCH_NOT_FOUND,\n { baseRomBranchId, error: branchError }\n );\n }\n \n // Step 2: Load all the BaseRomFile data using the fileCrcs array\n const files = await loadBaseRomFiles(baseRomBranchId);\n \n fileQueryTime = performance.now() - branchStart - branchQueryTime;\n \n const payload: BaseRomPayload = {\n baseRomBranch: branchData as unknown as BaseRomBranchData,\n files,\n };\n \n // Log performance statistics\n const totalTime = performance.now() - startTime;\n const stats: QueryStats = {\n branchQueryTime,\n fileQueryTime,\n totalTime,\n fileCount: files.length,\n };\n \n console.log('ROM load stats:', stats);\n \n return payload;\n \n } catch (error) {\n if (error instanceof SupabaseFromError) {\n throw error;\n }\n \n throw new SupabaseFromError(\n `Failed to load ROM data: ${error instanceof Error ? error.message : 'Unknown error'}`,\n SupabaseErrorCode.NETWORK_ERROR,\n { baseRomBranchId, error }\n );\n }\n}\n\n/**\n * Load ROM data from Supabase using name-based lookup\n * \n * @param options - Options for name-based lookup\n * @returns Promise<BaseRomPayload> containing the branch data and files\n * @throws {SupabaseFromError} If the branch is not found or other errors occur\n * \n * @example\n * ```typescript\n * // Load default ROM (GaiaLabs BaseROM, main branch)\n * const payload1 = await fromSupabaseByName({});\n * \n * // Load specific ROM and branch\n * const payload2 = await fromSupabaseByName({\n * baseRomName: 'My Custom ROM',\n * branchName: 'development',\n * branchVersion: null // latest version\n * });\n * \n * // Load main branch explicitly\n * const payload3 = await fromSupabaseByName({\n * baseRomName: 'GaiaLabs BaseROM',\n * branchName: null, // main branch\n * branchVersion: null // latest version\n * });\n * ```\n */\nexport async function fromSupabaseByName(\n options: FromSupabaseByNameOptions\n): Promise<BaseRomPayload> {\n const {\n gameName,\n baseRomName,\n branchName,\n branchVersion,\n } = options;\n \n const startTime = performance.now();\n let branchQueryTime = 0;\n let fileQueryTime = 0;\n \n try {\n const client = getSupabaseClient();\n \n // Step 1: Build query with filters\n const branchStart = performance.now();\n \n let query = client\n .from('BaseRomBranch')\n .select(`\n id,\n name,\n version,\n isActive,\n notes,\n baseRomId,\n gameRomBranchId,\n createdAt,\n updatedAt,\n gameRomBranch:GameRomBranch!inner(\n id,\n name,\n version,\n isActive,\n notes,\n gameRomId,\n platformBranchId,\n config,\n coplib,\n files,\n blocks,\n rewrites,\n transforms,\n overrides,\n labels,\n mnemonics,\n fileTypes,\n strings,\n structs,\n groups,\n createdAt,\n updatedAt,\n platformBranch:PlatformBranch!inner(\n id,\n name,\n version,\n isActive,\n notes,\n platformId,\n addressingModes,\n vectors,\n headers,\n types,\n createdAt,\n updatedAt\n )\n ),\n baseRom:BaseRom!inner(\n id,\n name,\n gameId,\n gameRomId,\n createdAt,\n updatedAt,\n game:Game!inner(\n id,\n name,\n createdAt,\n updatedAt\n )\n )\n `);\n \n // Filter by Game name\n query = query.eq('baseRom.game.name', gameName);\n \n // Filter by BaseRom name\n query = query.eq('baseRom.name', baseRomName);\n \n // Filter by branch name if specified\n if (branchName !== undefined) {\n if (branchName === null) {\n query = query.is('name', null);\n } else {\n query = query.eq('name', branchName);\n }\n }\n \n // Filter by branch version if specified\n if (branchVersion !== undefined) {\n if (branchVersion === null) {\n query = query.is('version', null);\n } else {\n query = query.eq('version', branchVersion);\n }\n }\n \n // Execute query - get single result\n const { data: branchData, error: branchError } = await query.single<BaseRomBranchData>();\n \n branchQueryTime = performance.now() - branchStart;\n \n if (branchError || !branchData) {\n throw new SupabaseFromError(\n `BaseRomBranch not found for criteria: gameName=\"${gameName}\", baseRomName=\"${baseRomName}\", branchName=${branchName}, branchVersion=${branchVersion}`,\n SupabaseErrorCode.BRANCH_NOT_FOUND,\n { options, error: branchError }\n );\n }\n \n // Step 2: Load all the BaseRomFile data using the fileCrcs array\n const files = await loadBaseRomFiles(branchData.id);\n \n fileQueryTime = performance.now() - branchStart - branchQueryTime;\n \n const payload: BaseRomPayload = {\n baseRomBranch: branchData as unknown as BaseRomBranchData,\n files,\n };\n \n // Log performance statistics\n const totalTime = performance.now() - startTime;\n const stats: QueryStats = {\n branchQueryTime,\n fileQueryTime,\n totalTime,\n fileCount: files.length,\n };\n \n console.log('ROM load stats:', stats);\n \n return payload;\n \n } catch (error) {\n if (error instanceof SupabaseFromError) {\n throw error;\n }\n \n throw new SupabaseFromError(\n `Failed to load ROM data: ${error instanceof Error ? error.message : 'Unknown error'}`,\n SupabaseErrorCode.NETWORK_ERROR,\n { options, error }\n );\n }\n}\n\n/**\n * Load BaseRomFile data using CRCs with parallel requests\n * \n * @param baseRomId - The BaseRom ID to filter files\n * @param fileCrcs - Array of CRC values to fetch\n * @returns Promise<BaseRomFileData[]> Array of file data with converted binary content\n * @throws {SupabaseFromError} If files are not found or conversion fails\n */\nasync function loadBaseRomFiles(\n baseRomBranchId: string\n): Promise<BaseRomFileData[]> {\n\n try {\n const client = getSupabaseClient();\n \n // Query all files with matching CRCs in one request\n const { data: filesData, error: filesError } = await client\n .from('BaseRomBranchFile')\n .select<string, BaseRomBranchFileRaw>('*,file:BaseRomFile!inner(*)')\n .eq('branchId', baseRomBranchId);\n \n if (filesError) {\n throw new SupabaseFromError(\n `Failed to load BaseRomFiles: ${filesError.message}`,\n SupabaseErrorCode.FILES_NOT_FOUND,\n { baseRomBranchId, error: filesError }\n );\n }\n \n if (!filesData || filesData.length === 0) {\n throw new SupabaseFromError(\n `No BaseRomFiles found for baseRomBranchId: ${baseRomBranchId}`,\n SupabaseErrorCode.FILES_NOT_FOUND,\n { baseRomBranchId }\n );\n }\n \n // Convert data to Uint8Array for each file (handles both hex and base64 formats)\n const convertedFiles: BaseRomFileData[] = await convertRawData<BaseRomFileData>(filesData.map(f => f.file));\n \n return convertedFiles;\n \n } catch (error) {\n if (error instanceof SupabaseFromError) {\n throw error;\n }\n \n throw new SupabaseFromError(\n `Failed to load and convert BaseRomFiles: ${error instanceof Error ? error.message : 'Unknown error'}`,\n SupabaseErrorCode.NETWORK_ERROR,\n { baseRomBranchId, error }\n );\n }\n}\n\nasync function convertRawData<T extends FileBaseData>(files: FileBaseRaw[]): Promise<T[]> {\n return files.map((file: FileBaseRaw) => {\n try {\n return {\n ...file,\n data: file.data ? decodeDataString(file.data) : undefined,\n } as T;\n } catch (error) {\n throw new SupabaseFromError(\n `Failed to convert data for file ${file.name}: ${error instanceof Error ? error.message : 'Unknown error'}`,\n SupabaseErrorCode.INVALID_DATA,\n { file, error }\n );\n }\n });\n}\n\n/**\n * Load ProjectFile data using CRCs with parallel requests\n * \n * @param projectId - The Project ID to filter files\n * @param fileCrcs - Array of CRC values to fetch\n * @returns Promise<ProjectFileData[]> Array of file data with converted binary content\n * @throws {SupabaseFromError} If files are not found or conversion fails\n */\nasync function loadProjectFiles(\n projectBranchId: string\n): Promise<ProjectFileData[]> {\n try {\n const client = getSupabaseClient();\n \n // Query all files with matching CRCs in one request\n const { data: filesData, error: filesError } = await client\n .from('ProjectBranchFile')\n .select<string, ProjectBranchFileRaw>('*,file:ProjectFile!inner(*)')\n .eq('branchId', projectBranchId);\n \n if (filesError) {\n throw new SupabaseFromError(\n `Failed to load ProjectFiles: ${filesError.message}`,\n SupabaseErrorCode.FILES_NOT_FOUND,\n { projectBranchId, error: filesError }\n );\n }\n \n if (!filesData || filesData.length === 0) {\n throw new SupabaseFromError(\n `No ProjectFiles found for projectBranchId: ${projectBranchId}`,\n SupabaseErrorCode.FILES_NOT_FOUND,\n { projectBranchId }\n );\n }\n \n // Convert data to Uint8Array for each file (handles both hex and base64 formats)\n const convertedFiles: ProjectFileData[] = await convertRawData<ProjectFileData>(filesData.map(f => f.file));\n \n return convertedFiles;\n \n } catch (error) {\n if (error instanceof SupabaseFromError) {\n throw error;\n }\n \n throw new SupabaseFromError(\n `Failed to load and convert ProjectFiles: ${error instanceof Error ? error.message : 'Unknown error'}`,\n SupabaseErrorCode.NETWORK_ERROR,\n { projectBranchId, error }\n );\n }\n}\n\n/**\n * Load Project data from Supabase using project name-based lookup\n * \n * @param projectName - The name of the project to load\n * @param options - Options for branch filtering\n * @returns Promise<ProjectPayload> containing the project branch data and files\n * @throws {SupabaseFromError} If the project branch is not found or other errors occur\n * \n * @example\n * ```typescript\n * // Load default project branch (main/latest)\n * const payload1 = await fromSupabaseByProject('My Game Project');\n * \n * // Load specific branch\n * const payload2 = await fromSupabaseByProject('My Game Project', {\n * branchName: 'development',\n * branchVersion: null // latest version\n * });\n * \n * // Load main branch explicitly\n * const payload3 = await fromSupabaseByProject('My Game Project', {\n * branchName: null, // main branch\n * branchVersion: null // latest version\n * });\n * ```\n */\nexport async function fromSupabaseByProject(projectName?: string, branchId?: string): Promise<DbGameRomModule> {\n const startTime = performance.now();\n let branchQueryTime = 0;\n let fileQueryTime = 0;\n \n //Use default project name if not provided\n if(!projectName && !branchId){\n throw new Error('Project name or branch ID are required');\n }\n\n try {\n const client = getSupabaseClient();\n \n // Step 1: Build query with filters\n const branchStart = performance.now();\n \n let query = client\n .from('ProjectBranch')\n .select(`\n id,\n name,\n version,\n isActive,\n notes,\n projectId,\n baseRomBranchId,\n modules,\n createdAt,\n updatedAt,\n project:Project!inner(\n id,\n name,\n meta,\n gameId,\n baseRomId,\n createdAt,\n updatedAt\n ),\n baseRomBranch:BaseRomBranch!inner(\n id,\n name,\n version,\n isActive,\n notes,\n baseRomId,\n gameRomBranchId,\n createdAt,\n updatedAt,\n baseRom:BaseRom!inner(\n id,\n name,\n gameId,\n gameRomId,\n createdAt,\n updatedAt\n ),\n gameRomBranch:GameRomBranch!inner(\n id,\n name,\n version,\n isActive,\n notes,\n gameRomId,\n platformBranchId,\n config,\n coplib,\n files,\n blocks,\n rewrites,\n transforms,\n overrides,\n labels,\n mnemonics,\n fileTypes,\n groups,\n strings,\n structs,\n createdAt,\n updatedAt,\n gameRom:GameRom!inner(\n id,\n crc,\n gameId,\n regionId,\n createdAt,\n updatedAt,\n game:Game!inner(\n id,\n name,\n createdAt,\n updatedAt\n ),\n region:Region!inner(\n id,\n name,\n meta,\n createdAt,\n updatedAt\n )\n ),\n platformBranch:PlatformBranch!inner(\n id,\n name,\n version,\n isActive,\n notes,\n platformId,\n addressingModes,\n vectors,\n headers,\n types,\n createdAt,\n updatedAt,\n platform:Platform!inner(\n id,\n name,\n meta,\n createdAt,\n updatedAt\n )\n )\n )\n )\n `);\n \n\n // Filter by Project name\n if(projectName) query = query.eq('project.name', projectName);\n\n // Make sure we use the selected or current active branch\n if(branchId) query = query.eq('id', branchId);\n else query = query.eq('isActive', true);\n \n // Execute query - get single result\n const { data: branchData, error: branchError } = await query.single<ProjectBranchData>();\n \n branchQueryTime = performance.now() - branchStart;\n \n if (branchError || !branchData) {\n throw new SupabaseFromError(\n `ProjectBranch not found for criteria: projectName=\"${projectName}\"`,\n SupabaseErrorCode.BRANCH_NOT_FOUND,\n { projectName, error: branchError }\n );\n }\n\n const baseRomBranch = branchData.baseRomBranch;\n \n // Step 2: Load all the ProjectFile data using the fileCrcs array\n const projectFiles = await loadProjectFiles(branchData.id);\n \n const baseRomFiles = await loadBaseRomFiles(baseRomBranch.id);\n\n fileQueryTime = performance.now() - branchStart - branchQueryTime;\n \n const payload: ProjectPayload = {\n projectBranch: branchData as unknown as ProjectBranchData,\n projectFiles,\n baseRomBranch,\n baseRomFiles\n };\n \n // Log performance statistics\n const totalTime = performance.now() - startTime;\n const stats: QueryStats = {\n branchQueryTime,\n fileQueryTime,\n totalTime,\n fileCount: projectFiles.length,\n };\n \n console.log('Project ROM load stats:', stats);\n \n const module : DbGameRomModule = {\n supaProjectFiles: projectFiles,\n supaBaseRomFiles: baseRomFiles,\n mnemonics: baseRomBranch.gameRomBranch.mnemonics,\n overrides: baseRomBranch.gameRomBranch.overrides,\n rewrites: baseRomBranch.gameRomBranch.rewrites,\n blocks: baseRomBranch.gameRomBranch.blocks,\n files: baseRomBranch.gameRomBranch.files,\n config: baseRomBranch.gameRomBranch.config,\n labels: baseRomBranch.gameRomBranch.labels,\n structs: baseRomBranch.gameRomBranch.structs,\n copdef: baseRomBranch.gameRomBranch.coplib,\n strings: baseRomBranch.gameRomBranch.strings,\n transforms: baseRomBranch.gameRomBranch.transforms,\n groups: baseRomBranch.gameRomBranch.groups,\n fileTypes: baseRomBranch.gameRomBranch.fileTypes,\n addrModes: baseRomBranch.gameRomBranch.platformBranch.addressingModes,\n headers: baseRomBranch.gameRomBranch.platformBranch.headers,\n };\n\n return module;\n \n } catch (error) {\n if (error instanceof SupabaseFromError) {\n throw error;\n }\n \n throw new SupabaseFromError(\n `Failed to load Project data: ${error instanceof Error ? error.message : 'Unknown error'}`,\n SupabaseErrorCode.NETWORK_ERROR,\n { projectName, error }\n );\n }\n}\n\nexport async function fromSupabaseByGameRom(gameName?: string, regionName?: string, platformName?: string, branchId?: string): Promise<ProjectPayload> {\n const startTime = performance.now();\n let branchQueryTime = 0;\n let fileQueryTime = 0;\n \n //Use default project name if not provided\n if(!branchId && !gameName && !regionName && !platformName) { \n throw new Error('Game name, region name, and platform name are required');\n }\n\n try {\n const client = getSupabaseClient();\n \n // Step 1: Build query with filters\n const branchStart = performance.now();\n \n let query = client\n .from('GameRomBranch')\n .select(`\n id,\n name,\n version,\n isActive,\n notes,\n gameRomId,\n platformBranchId,\n coplib,\n config,\n files,\n blocks,\n rewrites,\n transforms,\n overrides,\n labels,\n mnemonics,\n fileTypes,\n groups,\n strings,\n structs,\n createdAt,\n updatedAt,\n gameRom:GameRom!inner(\n id,\n crc,\n meta,\n gameId,\n regionId,\n createdAt,\n updatedAt,\n game:Game!inner(\n id,\n name,\n createdAt,\n updatedAt\n ),\n region:Region!inner(\n id,\n name,\n meta,\n createdAt,\n updatedAt\n )\n ),\n platformBranch:PlatformBranch!inner(\n id,\n name,\n version,\n isActive,\n platformId,\n addressingModes,\n headers,\n vectors,\n types,\n createdAt,\n updatedAt,\n platform:Platform!inner(\n id,\n name,\n meta,\n createdAt,\n updatedAt\n )\n )\n `);\n \n\n // Filter by Project name\n if(gameName) query = query.eq('gameRom.game.name', gameName);\n if(regionName) query = query.eq('gameRom.region.name', regionName);\n if(platformName) query = query.eq('platformBranch.platform.name', platformName);\n\n // Make sure we use the selected or current active branch\n if(branchId) query = query.eq('id', branchId);\n else query = query.eq('isActive', true);\n \n // Execute query - get single result\n const { data: branchData, error: branchError } = await query.single<GameRomBranchData>();\n \n branchQueryTime = performance.now() - branchStart;\n \n if (branchError || !branchData) {\n throw new SupabaseFromError(\n `GameRomBranch not found for criteria: gameName=\"${gameName}\", regionName=\"${regionName}\", platformName=\"${platformName}\"`,\n SupabaseErrorCode.BRANCH_NOT_FOUND,\n { gameName, regionName, platformName, error: branchError }\n );\n }\n\n // Construct a minimal BaseRomBranch wrapper so downstream code can consume a unified ProjectPayload\n const baseRomBranch: BaseRomBranchData = {\n id: '',\n name: null,\n version: null,\n baseRomId: '',\n gameRomBranchId: branchData.id,\n gameRomBranch: branchData,\n baseRom: {\n id: '',\n name: '',\n gameId: '',\n gameRomId: '',\n createdAt: '',\n updatedAt: ''\n },\n createdAt: '',\n updatedAt: ''\n };\n\n const project: ProjectData = {\n id: '',\n name: '',\n meta: null,\n gameId: '',\n baseRomId: '',\n createdAt: '',\n updatedAt: '',\n };\n\n const projectBranch: ProjectBranchData = {\n id: '',\n name: null,\n version: null,\n projectId: '',\n baseRomBranchId: '',\n modules: [],\n project,\n baseRomBranch,\n createdAt: '',\n updatedAt: ''\n };\n\n const payload: ProjectPayload = {\n projectBranch,\n projectFiles: [],\n baseRomBranch,\n baseRomFiles: []\n };\n\n fileQueryTime = performance.now() - branchStart - branchQueryTime;\n\n // Log performance statistics\n const totalTime = performance.now() - startTime;\n const stats: QueryStats = {\n branchQueryTime,\n fileQueryTime,\n totalTime,\n fileCount: 0,\n };\n\n console.log('Game ROM load stats:', stats);\n\n return payload;\n \n } catch (error) {\n if (error instanceof SupabaseFromError) {\n throw error;\n }\n \n throw new SupabaseFromError(\n `Failed to load GameRomBranch data: ${error instanceof Error ? error.message : 'Unknown error'}`,\n SupabaseErrorCode.NETWORK_ERROR,\n { gameName, regionName, platformName, error }\n );\n }\n}\n\nexport async function summaryFromSupabaseByProject(projectName?: string): Promise<ProjectBranchData> {\n const startTime = performance.now();\n let branchQueryTime = 0;\n let fileQueryTime = 0;\n \n //Use default project name if not provided\n if(!projectName){\n throw new Error('Project name or branch ID are required');\n }\n\n try {\n const client = getSupabaseClient();\n\n // Step 1: Build query with filters\n const branchStart = performance.now();\n \n let query = client\n .from('ProjectBranch')\n .select(`\n id,\n name,\n version,\n isActive,\n notes,\n projectId,\n baseRomBranchId,\n modules,\n createdAt,\n updatedAt,\n project:Project!inner(\n id,\n name,\n meta,\n gameId,\n baseRomId,\n createdAt,\n updatedAt\n ),\n baseRomBranch:BaseRomBranch!inner(\n id,\n name,\n version,\n isActive,\n notes,\n baseRomId,\n gameRomBranchId,\n createdAt,\n updatedAt,\n baseRom:BaseRom!inner(\n id,\n name,\n gameId,\n gameRomId,\n createdAt,\n updatedAt\n ),\n gameRomBranch:GameRomBranch!inner(\n id,\n name,\n version,\n isActive,\n notes,\n gameRomId,\n platformBranchId,\n createdAt,\n updatedAt,\n gameRom:GameRom!inner(\n id,\n crc,\n gameId,\n regionId,\n createdAt,\n updatedAt,\n game:Game!inner(\n id,\n name,\n createdAt,\n updatedAt\n ),\n region:Region!inner(\n id,\n name,\n meta,\n createdAt,\n updatedAt\n )\n ),\n platformBranch:PlatformBranch!inner(\n id,\n name,\n version,\n isActive,\n notes,\n platformId,\n createdAt,\n updatedAt,\n platform:Platform!inner(\n id,\n name,\n meta,\n createdAt,\n updatedAt\n )\n )\n )\n )\n `);\n \n // Filter by Project name\n query = query.eq('project.name', projectName);\n \n // Make sure we use the current active branch\n query = query.eq('isActive', true);\n \n // Execute query - get single result\n const { data: branchData, error: branchError } = await query.single();\n \n branchQueryTime = performance.now() - branchStart;\n \n if (branchError || !branchData) {\n throw new SupabaseFromError(\n `ProjectBranch not found for criteria: projectName=\"${projectName}\"`,\n SupabaseErrorCode.BRANCH_NOT_FOUND,\n { projectName, error: branchError }\n );\n }\n\n const projectBranch = branchData as unknown as ProjectBranchData;\n \n\n fileQueryTime = performance.now() - branchStart - branchQueryTime;\n \n const payload = projectBranch;\n \n // Log performance statistics\n const totalTime = performance.now() - startTime;\n const stats: QueryStats = {\n branchQueryTime,\n fileQueryTime,\n totalTime,\n fileCount: 0,\n };\n \n console.log('Project ROM load stats:', stats);\n \n return payload;\n \n } catch (error) {\n if (error instanceof SupabaseFromError) {\n throw error;\n }\n \n throw new SupabaseFromError(\n `Failed to load Project data: ${error instanceof Error ? error.message : 'Unknown error'}`,\n SupabaseErrorCode.NETWORK_ERROR,\n { projectName, error }\n );\n }\n}\n","import { crc32_buffer } from '../utils';\r\nimport { DbRoot, DbRootUtils } from '../database';\r\nimport { ChunkFile } from '../types/files';\r\nimport { summaryFromSupabaseByProject } from '../supabase/rom-loader';\r\nimport { BlockReader, BlockWriter } from './extraction';\r\nimport { RomWriter } from './rebuild';\r\nimport { fromSupabaseByProject } from '../supabase/rom-loader';\r\n\r\nexport class RomGenerator {\r\n //private readonly patchFiles: ChunkFile[] = [];\r\n public readonly projectName: string;\r\n public readonly crc: number;\r\n //public branchId: string;\r\n //private chunkFiles: ChunkFile[] = [];\r\n //private asmFiles: ChunkFile[] = [];\r\n public dbRoot: DbRoot = {} as DbRoot;\r\n private sourceData: Uint8Array = new Uint8Array();\r\n\r\n constructor(projectName: string, crc: number) {\r\n this.projectName = projectName;\r\n this.crc = crc;\r\n }\r\n\r\n // public async initialize(){\r\n // var projectData = await summaryFromSupabaseByProject(this.projectName);\r\n // this.crc = projectData.baseRomBranch.gameRomBranch.gameRom.crc;\r\n // this.branchId = projectData.id;\r\n // }\r\n\r\n public async validateAndDownload(sourceData: Uint8Array): Promise<boolean> {\r\n const calc = crc32_buffer(sourceData);\r\n if(this.crc !== calc) return false;\r\n\r\n const moduleData = await fromSupabaseByProject(this.projectName);\r\n this.dbRoot = DbRootUtils.fromGameModule(moduleData);\r\n this.sourceData = sourceData;\r\n return true;\r\n }\r\n\r\n public async generateProject(modules: string[], manualFiles?: ChunkFile[], unshiftManualFiles: boolean = false): Promise<Uint8Array> {\r\n if(!this.dbRoot) throw new Error('Database not initialized');\r\n if(!this.sourceData) throw new Error('Source data not initialized');\r\n\r\n //Initialize chunks\r\n const reader = new BlockReader(this.sourceData, this.dbRoot);\r\n const chunkFiles = reader.analyzeAndResolve();\r\n const asmFiles = chunkFiles.filter(b => b.type.type === 'Assembly');\r\n const patchFiles: ChunkFile[] = [];\r\n\r\n //Convert asm blocks to text\r\n const writer = new BlockWriter(reader);\r\n for(const block of asmFiles) block.textData = writer.generateAsm(block);\r\n \r\n //Apply baserom files\r\n for (const chunkFile of this.dbRoot.baseRomFiles!) this.applyPatchFile(chunkFile, chunkFiles, asmFiles, patchFiles);\r\n\r\n //Apply base project files and collect module files\r\n const moduleLookup = this.applyProjectInit(chunkFiles, asmFiles, patchFiles);\r\n\r\n //Apply manual files (before modules)\r\n if(unshiftManualFiles) {\r\n for(const file of manualFiles ?? []) this.applyPatchFile(file, chunkFiles, asmFiles, patchFiles);\r\n }\r\n\r\n //Apply selected modules\r\n for(const module of modules) {\r\n for(const file of moduleLookup.get(module)!) this.applyPatchFile(file, chunkFiles, asmFiles, patchFiles);\r\n }\r\n\r\n //Apply manual files\r\n if(!unshiftManualFiles) {\r\n for(const file of manualFiles ?? []) this.applyPatchFile(file, chunkFiles, asmFiles, patchFiles);\r\n }\r\n\r\n const romWriter = new RomWriter(this.dbRoot);\r\n const outRom = await romWriter.repack(chunkFiles);\r\n \r\n // this.assembleCodeFromText(asmFiles);\r\n\r\n // //Apply code patches\r\n // RomProcessor.applyPatches(asmFiles, patchFiles);\r\n\r\n // //Calculate sizes\r\n // for (const asm of chunkFiles) ChunkFileUtils.calculateSize(asm);\r\n\r\n // //Assign locations\r\n // const layout = new RomLayout(chunkFiles, this.dbRoot);\r\n // const pages = layout.organize();\r\n\r\n // //Rebase assemblies\r\n // for (const file of asmFiles) ChunkFileUtils.rebase(file);\r\n\r\n // this.generateAsmIncludeLookups(asmFiles);\r\n\r\n // //Generate block lookup\r\n // const blockLookup = new Map<string, number>();\r\n // for (const f of chunkFiles) blockLookup.set(f.name.toUpperCase(), f.location);\r\n\r\n // const outRom = await this.writeRom(blockLookup, chunkFiles, asmFiles, pages);\r\n\r\n\r\n return outRom;\r\n }\r\n\r\n private applyProjectInit(chunkFiles: ChunkFile[], asmFiles: ChunkFile[], patchFiles: ChunkFile[]){\r\n const moduleLookup: Map<string, ChunkFile[]> = new Map();\r\n\r\n //Run a single pass to collect all the module files, and apply base files\r\n for (const chunkFile of this.dbRoot.projectFiles!) {\r\n // Parse the patch file with the assembler\r\n console.log(`Processing patch: ${chunkFile.name}`);\r\n\r\n //ChunkFile.group is the module name\r\n if(chunkFile.group){\r\n let modArray = moduleLookup.get(chunkFile.group);\r\n if(!modArray) moduleLookup.set(chunkFile.group, modArray = []);\r\n modArray.push(chunkFile);\r\n } else this.applyPatchFile(chunkFile, chunkFiles, asmFiles, patchFiles); //If chunk file is not part of a group, apply it now\r\n }\r\n\r\n return moduleLookup;\r\n }\r\n\r\n // //Assemble code from script text\r\n // private assembleCodeFromText(asmFiles: ChunkFile[]){\r\n // for(const block of asmFiles) {\r\n // const assembler = new Assembler(this.dbRoot, block.textData!);\r\n // const { blocks, includes, reqBank } = assembler.parseAssembly();\r\n // block.parts = blocks;\r\n // block.includes = includes;\r\n // block.bank = reqBank ?? undefined;\r\n // }\r\n // }\r\n\r\n // // Build include lookup map per asm file\r\n // private generateAsmIncludeLookups(asmFiles: ChunkFile[]){\r\n // for (const f of asmFiles) {\r\n // const includeBlocks = asmFiles\r\n // .filter(x => f.includes?.has(x.name.toUpperCase()))\r\n // .flatMap(x => x.parts!)\r\n // .filter(b => !!b.label);\r\n\r\n // f.includeLookup = new Map<string, AsmBlock>();\r\n\r\n // for (const b of includeBlocks) {\r\n // if (b.label) f.includeLookup.set(b.label.toUpperCase(), b);\r\n // }\r\n\r\n // for (const b of f.parts) {\r\n // if (b.label) f.includeLookup.set(b.label.toUpperCase(), b);\r\n // }\r\n // }\r\n // }\r\n\r\n public applyPatchFile(chunkFile: ChunkFile, chunkFiles: ChunkFile[], asmFiles: ChunkFile[], patchFiles: ChunkFile[]): void {\r\n console.log(`Processing patch: ${chunkFile.name}`);\r\n const existing = chunkFiles.find(x => x.name === chunkFile.name);\r\n\r\n if(chunkFile.textData) {\r\n if(existing){\r\n existing.textData = chunkFile.textData;\r\n } else {\r\n if(chunkFile.type.type === 'Patch') {\r\n patchFiles.push(chunkFile);\r\n }\r\n asmFiles.push(chunkFile);\r\n chunkFiles.push(chunkFile);\r\n }\r\n } else {\r\n if(existing){\r\n existing.rawData = chunkFile.rawData;\r\n existing.size = chunkFile.size;\r\n } else {\r\n chunkFiles.push(chunkFile);\r\n }\r\n }\r\n }\r\n\r\n // private async writeRom(blockLookup: Map<string, number>, chunkFiles: ChunkFile[], asmFiles: ChunkFile[], pages: number){\r\n // //Create rom writer\r\n // const romWriter = new RomWriter(this.dbRoot);\r\n\r\n // romWriter.allocate(pages);\r\n\r\n // // Write all files\r\n // for (const file of chunkFiles) await romWriter.writeFile(file, blockLookup);\r\n\r\n // //Write header\r\n // romWriter.writeHeaders();\r\n\r\n // //Write entry points\r\n // //romWriter.writeEntryPoints(asmFiles);\r\n\r\n // //Write checksum\r\n // romWriter.writeChecksum();\r\n\r\n // return romWriter.outBuffer;\r\n // }\r\n}","/**\r\n * Represents a single frame in a sprite animation sequence\r\n */\r\nexport class SpriteFrame {\r\n public duration: number;\r\n public groupIndex: number;\r\n \r\n /**\r\n * Internal offset to the group data (not serialized)\r\n */\r\n public groupOffset: number;\r\n\r\n constructor(duration: number = 0, groupIndex: number = 0, groupOffset: number = 0) {\r\n this.duration = duration;\r\n this.groupIndex = groupIndex;\r\n this.groupOffset = groupOffset;\r\n }\r\n} ","/**\r\n * Represents a single part/piece of a sprite\r\n */\r\nexport class SpritePart {\r\n public isLarge: boolean;\r\n public xOffset: number;\r\n public xOffsetMirror: number;\r\n public yOffset: number;\r\n public yOffsetMirror: number;\r\n public vMirror: boolean;\r\n public hMirror: boolean;\r\n public someOffset: number;\r\n public paletteIndex: number;\r\n public tileIndex: number;\r\n\r\n constructor() {\r\n this.isLarge = false;\r\n this.xOffset = 0;\r\n this.xOffsetMirror = 0;\r\n this.yOffset = 0;\r\n this.yOffsetMirror = 0;\r\n this.vMirror = false;\r\n this.hMirror = false;\r\n this.someOffset = 0;\r\n this.paletteIndex = 0;\r\n this.tileIndex = 0;\r\n }\r\n} ","import { SpritePart } from './SpritePart';\r\n\r\n/**\r\n * Represents a group of sprite parts that form a complete sprite frame\r\n */\r\nexport class SpriteGroup {\r\n public xOffset: number;\r\n public xOffsetMirror: number;\r\n public yOffset: number;\r\n public yOffsetMirror: number;\r\n public xRecoilHitboxOffset: number;\r\n public yRecoilHitboxOffset: number;\r\n public xRecoilHitboxTilesize: number;\r\n public yRecoilHitboxTilesize: number;\r\n public xHostileHitboxOffset: number;\r\n public xHostileHitboxSize: number;\r\n public yHostileHitboxOffset: number;\r\n public yHostileHitboxSize: number;\r\n public parts: SpritePart[];\r\n\r\n constructor() {\r\n this.xOffset = 0;\r\n this.xOffsetMirror = 0;\r\n this.yOffset = 0;\r\n this.yOffsetMirror = 0;\r\n this.xRecoilHitboxOffset = 0;\r\n this.yRecoilHitboxOffset = 0;\r\n this.xRecoilHitboxTilesize = 0;\r\n this.yRecoilHitboxTilesize = 0;\r\n this.xHostileHitboxOffset = 0;\r\n this.xHostileHitboxSize = 0;\r\n this.yHostileHitboxOffset = 0;\r\n this.yHostileHitboxSize = 0;\r\n this.parts = [];\r\n }\r\n} ","import { SpriteFrame } from './SpriteFrame';\r\nimport { SpriteGroup } from './SpriteGroup';\r\nimport { SpritePart } from './SpritePart';\r\n\r\n/**\r\n * Represents a complete sprite map with frame sets and groups\r\n */\r\nexport class SpriteMap {\r\n public frameSets: SpriteFrame[][];\r\n public groups: SpriteGroup[];\r\n\r\n constructor() {\r\n this.frameSets = [];\r\n this.groups = [];\r\n }\r\n\r\n /**\r\n * Create a SpriteMap from binary data\r\n * @param data Binary data buffer\r\n * @returns SpriteMap instance\r\n */\r\n public static fromBytes(data: Uint8Array): SpriteMap {\r\n let position = 0;\r\n\r\n const getByte = (): number => {\r\n if (position >= data.length) return 0;\r\n return data[position++];\r\n };\r\n\r\n const getUshort = (): number => {\r\n if (position + 1 >= data.length) return 0;\r\n const low = data[position++];\r\n const high = data[position++];\r\n return low | (high << 8);\r\n };\r\n\r\n const spriteMap = new SpriteMap();\r\n const setOffsets = new Set<number>();\r\n const groupOffsets = new Set<number>();\r\n\r\n // Read frame set offsets\r\n position = 0;\r\n while (!setOffsets.has(position)) {\r\n const offset = getUshort() - 0x4000;\r\n setOffsets.add(offset);\r\n }\r\n\r\n // Read frame sets\r\n for (const offStart of setOffsets) {\r\n position = offStart;\r\n const frameList: SpriteFrame[] = [];\r\n\r\n while (true) {\r\n const duration = getUshort();\r\n if (duration === 0xFFFF) {\r\n break;\r\n }\r\n\r\n const groupOffset = getUshort() - 0x4000;\r\n frameList.push(new SpriteFrame(duration, 0, groupOffset));\r\n groupOffsets.add(groupOffset);\r\n }\r\n\r\n spriteMap.frameSets.push(frameList);\r\n }\r\n\r\n // Read groups\r\n let grpIx = 0;\r\n const sortedGroupOffsets = Array.from(groupOffsets).sort((a, b) => a - b);\r\n \r\n for (const offStart of sortedGroupOffsets) {\r\n position = offStart;\r\n\r\n // Update frame group indices\r\n for (const set of spriteMap.frameSets) {\r\n for (const frame of set) {\r\n if (frame.groupOffset === offStart) {\r\n frame.groupIndex = grpIx;\r\n }\r\n }\r\n }\r\n\r\n const grp = new SpriteGroup();\r\n grp.xOffset = getByte();\r\n grp.xOffsetMirror = getByte();\r\n grp.yOffset = getByte();\r\n grp.yOffsetMirror = getByte();\r\n grp.xRecoilHitboxOffset = getByte();\r\n grp.yRecoilHitboxOffset = getByte();\r\n grp.xRecoilHitboxTilesize = getByte();\r\n grp.yRecoilHitboxTilesize = getByte();\r\n grp.xHostileHitboxOffset = getByte();\r\n grp.xHostileHitboxSize = getByte();\r\n grp.yHostileHitboxOffset = getByte();\r\n grp.yHostileHitboxSize = getByte();\r\n\r\n let numParts = getByte();\r\n while (numParts-- > 0) {\r\n const part = new SpritePart();\r\n part.isLarge = getByte() !== 0;\r\n part.xOffset = getByte();\r\n part.xOffsetMirror = getByte();\r\n part.yOffset = getByte();\r\n part.yOffsetMirror = getByte();\r\n\r\n const props = getUshort();\r\n part.vMirror = (props & 0x8000) !== 0;\r\n part.hMirror = (props & 0x4000) !== 0;\r\n part.someOffset = (props >> 12) & 0x3;\r\n part.paletteIndex = (props >> 9) & 0x7;\r\n part.tileIndex = props & 0x1FF;\r\n\r\n grp.parts.push(part);\r\n }\r\n\r\n spriteMap.groups.push(grp);\r\n grpIx++;\r\n }\r\n\r\n return spriteMap;\r\n }\r\n\r\n /**\r\n * Convert this SpriteMap to binary data\r\n * @returns Binary data buffer\r\n */\r\n public toBytes(): Uint8Array {\r\n // Calculate buffer size (estimate)\r\n let size = this.frameSets.length * 2; // Frame set offsets\r\n \r\n for (const set of this.frameSets) {\r\n size += (set.length * 4) + 2; // Frames + terminator\r\n }\r\n \r\n for (const grp of this.groups) {\r\n size += (grp.parts.length * 7) + 13; // Parts + group header\r\n }\r\n\r\n const buffer = new Uint8Array(size);\r\n let position = 0;\r\n\r\n const writeShort = (val: number): void => {\r\n buffer[position++] = val & 0xFF;\r\n buffer[position++] = (val >> 8) & 0xFF;\r\n };\r\n\r\n const writeLoc = (val: number): void => writeShort(val + 0x4000);\r\n\r\n let pos = this.frameSets.length << 1;\r\n const groupPos = new Array<number>(this.groups.length);\r\n\r\n // Write frame set offsets\r\n for (const set of this.frameSets) {\r\n writeLoc(pos);\r\n pos += (set.length << 2) + 2;\r\n }\r\n\r\n // Calculate group positions\r\n for (let i = 0; i < this.groups.length; i++) {\r\n groupPos[i] = pos;\r\n pos += this.groups[i].parts.length * 7 + 13;\r\n }\r\n\r\n // Write frame sets\r\n for (const set of this.frameSets) {\r\n for (const frm of set) {\r\n writeShort(frm.duration);\r\n writeLoc(groupPos[frm.groupIndex]);\r\n }\r\n writeShort(0xFFFF);\r\n }\r\n\r\n // Write groups\r\n for (const grp of this.groups) {\r\n buffer[position++] = grp.xOffset;\r\n buffer[position++] = grp.xOffsetMirror;\r\n buffer[position++] = grp.yOffset;\r\n buffer[position++] = grp.yOffsetMirror;\r\n buffer[position++] = grp.xRecoilHitboxOffset;\r\n buffer[position++] = grp.yRecoilHitboxOffset;\r\n buffer[position++] = grp.xRecoilHitboxTilesize;\r\n buffer[position++] = grp.yRecoilHitboxTilesize;\r\n buffer[position++] = grp.xHostileHitboxOffset;\r\n buffer[position++] = grp.xHostileHitboxSize;\r\n buffer[position++] = grp.yHostileHitboxOffset;\r\n buffer[position++] = grp.yHostileHitboxSize;\r\n buffer[position++] = grp.parts.length;\r\n\r\n for (const prt of grp.parts) {\r\n buffer[position++] = prt.isLarge ? 1 : 0;\r\n buffer[position++] = prt.xOffset;\r\n buffer[position++] = prt.xOffsetMirror;\r\n buffer[position++] = prt.yOffset;\r\n buffer[position++] = prt.yOffsetMirror;\r\n\r\n const accum = (prt.vMirror ? 0x8000 : 0)\r\n | (prt.hMirror ? 0x4000 : 0)\r\n | ((prt.someOffset & 0x3) << 12)\r\n | ((prt.paletteIndex & 0x7) << 9)\r\n | prt.tileIndex;\r\n\r\n writeShort(accum);\r\n }\r\n }\r\n\r\n // Return trimmed buffer\r\n return buffer.slice(0, position);\r\n }\r\n} ","import snesAddressingModes from '../snes/addressingModes.json' with { type: 'json' };\nimport snesVectors from '../snes/vectors.json' with { type: 'json' };\nimport snesHeaders from '../snes/headers.json' with { type: 'json' };\n\nexport const snes = {\n addressingModes: snesAddressingModes,\n vectors: snesVectors,\n headers: snesHeaders\n}\n\n// Core modules\nexport * from './rom';\nexport * from './assembly';\nexport * from './compression';\nexport * from './sprites';\n\n// Core types\nexport * from './types'\nexport * from './project'\nexport * from './collaboration'\n\n// Database\nexport * from './database'\n\n// Supabase integration\nexport * from './supabase'\n\n// Utilities\nexport * from './utils' \n\n// All core modules have been converted and are exported above\n\n\n// Platform detection\n//export const isPlatformBrowser = typeof window !== 'undefined';\nexport const isPlatformNode = typeof process !== 'undefined' && process.versions?.node;\n//export const isPlatformWebWorker = typeof importScripts !== 'undefined'; \n\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.mjs","names":["isNode","RebuildProcessor","snesAddressingModes","snesVectors","snesHeaders"],"sources":["../snes/addressingModes.json","../snes/vectors.json","../snes/headers.json","../src/rom/state.ts","../src/rom/extraction/processor.ts","../src/rom/extraction/reader.ts","../src/types/constants.ts","../src/types/addressing.ts","../src/types/members.ts","../src/types/processor.ts","../src/types/resources.ts","../src/types/transforms.ts","../src/database/opcode.ts","../src/types/assembly.ts","../src/types/bitstream.ts","../src/types/compression-registry.ts","../src/types/files.ts","../src/types/location.ts","../src/types/strings.ts","../src/types/tables.ts","../src/types/operands.ts","../src/rom/extraction/references.ts","../src/rom/extraction/stack.ts","../src/rom/extraction/cop.ts","../src/rom/extraction/addressing.ts","../src/rom/extraction/transforms.ts","../src/utils/file.ts","../src/utils/crc.ts","../src/utils/base64.ts","../src/utils/index.ts","../src/rom/extraction/strings.ts","../src/rom/extraction/parser.ts","../src/rom/extraction/asm.ts","../src/assembly/Stack.ts","../src/assembly/Registers.ts","../src/rom/extraction/blocks.ts","../src/rom/extraction/postprocessor.ts","../src/rom/extraction/writer.ts","../src/rom/rebuild/layout.ts","../src/rom/rebuild/processor.ts","../src/rom/rebuild/writer.ts","../src/rom/rebuild/string-processor.ts","../src/rom/rebuild/sorted-map.ts","../src/rom/rebuild/assembler-state.ts","../src/rom/rebuild/assembler.ts","../src/database/blocks.ts","../src/database/files.ts","../src/database/structs.ts","../src/database/addressingMode.ts","../src/database/strings.ts","../src/database/cop.ts","../src/database/parts.ts","../src/database/transforms.ts","../src/database/scenes.ts","../src/database/groups.ts","../src/compression/QuintetLZ.ts","../src/compression/index.ts","../src/database/header.ts","../src/database/root.ts","../src/database/overrides.ts","../src/database/paths.ts","../src/supabase/client.ts","../src/supabase/utils.ts","../src/supabase/types.ts","../src/supabase/rom-loader.ts","../src/rom/generator.ts","../src/sprites/SpriteFrame.ts","../src/sprites/SpritePart.ts","../src/sprites/SpriteGroup.ts","../src/sprites/SpriteMap.ts","../src/index.ts"],"sourcesContent":["","","","/**\n * Lightweight ROM state placeholder used during early development.\n * This stub will be expanded as the ROM extraction pipeline matures.\n */\nexport class RomState {\n // Basic memory buffers\n public readonly cgram = new Uint8Array(0x200); // Color palette RAM\n public readonly vram = new Uint8Array(0x10000); // Video RAM\n\n /**\n * Create ROM state from scene metadata.\n * Parameters are currently unused but kept for future implementation.\n */\n public static async fromScene(\n _baseDir: string,\n _root: unknown,\n _metaFile: string,\n _id: number\n ): Promise<RomState> {\n return new RomState();\n }\n}\n\n/**\n * Utility helpers for working with RomState.\n */\nexport class RomStateUtils {\n /** Create an empty ROM state */\n public static createEmpty(): RomState {\n return new RomState();\n }\n\n /** Clear all data in the given ROM state */\n public static clear(state: RomState): void {\n state.cgram.fill(0);\n state.vram.fill(0);\n }\n}\n","import { Registers } from '../../assembly';\n\nexport class MapExt<K, V> extends Map<K, V> {\n\n constructor() {\n super();\n }\n\n public tryAdd(key: K, value: V): boolean {\n if (this.has(key)) {\n return false;\n }\n this.set(key, value);\n return true;\n }\n\n public setFlag(key: K, flag: number, value: boolean = true): void {\n if (!value) this.clearFlag(key, flag);\n else this.set(key, (((this.get(key) as number) ?? 0) | flag) as V);\n }\n\n public clearFlag(key: K, flag: number): void {\n this.set(key, (((this.get(key) as number) ?? 0) & ~flag) as V);\n }\n}\n\n/**\n * Manages CPU processor state during ROM analysis\n * Converted from GaiaLib/Rom/Extraction/ProcessorStateManager.cs\n */\nexport class ProcessorStateManager {\n // public readonly accumulatorFlags = new MapExt<number, boolean | null>();\n // public readonly indexFlags = new MapExt<number, boolean | null>();\n // public readonly bankNotes = new MapExt<number, number | null>();\n public readonly stackPositions = new MapExt<number, number>();\n\n private readonly _buckets: Record<string, MapExt<number, number>> = {};\n\n public get(key: string): MapExt<number, number> {\n return this._buckets[key] ?? (this._buckets[key] = new MapExt<number, number>());\n }\n\n /**\n * Hydrate processor registers with stored state\n * Uses Registers from gaia-core/assembly for processor state management\n */\n public hydrateRegisters(position: number, reg: Registers): void {\n\n for (const [key, value] of Object.entries(this._buckets)) {\n const val = value.get(position);\n if (val !== undefined) {\n reg.value[key] = val;\n }\n }\n\n // const acc = this.accumulatorFlags.get(position);\n // if (acc !== undefined) {\n // reg.accumulatorFlag = acc ?? undefined;\n // }\n\n // const ind = this.indexFlags.get(position);\n // if (ind !== undefined) {\n // reg.indexFlag = ind ?? undefined;\n // }\n\n // const bnk = this.bankNotes.get(position);\n // if (bnk !== undefined) {\n // reg.dataBank = bnk ?? undefined;\n // }\n\n const stack = this.stackPositions.get(position);\n if (stack !== undefined) {\n reg.stack.location = stack;\n }\n }\n\n // // Accumulator flag methods\n // public getAccumulatorFlag(location: number): boolean | null | undefined {\n // return this.accumulatorFlags.get(location);\n // }\n\n // public setAccumulatorFlag(location: number, value: boolean | null): void {\n // this.accumulatorFlags.set(location, value);\n // }\n\n // public tryAddAccumulatorFlag(location: number, value: boolean | null): boolean {\n // if (this.accumulatorFlags.has(location)) {\n // return false;\n // }\n // this.accumulatorFlags.set(location, value);\n // return true;\n // }\n\n // // Index flag methods\n // public getIndexFlag(location: number): boolean | null | undefined {\n // return this.indexFlags.get(location);\n // }\n\n // public setIndexFlag(location: number, value: boolean | null): void {\n // this.indexFlags.set(location, value);\n // }\n\n // public tryAddIndexFlag(location: number, value: boolean | null): boolean {\n // if (this.indexFlags.has(location)) {\n // return false;\n // }\n // this.indexFlags.set(location, value);\n // return true;\n // }\n\n // // Bank note methods\n // public getBankNote(location: number): number | null | undefined {\n // return this.bankNotes.get(location);\n // }\n\n // public setBankNote(location: number, value: number | null): void {\n // this.bankNotes.set(location, value);\n // }\n\n // Stack position methods\n public getStackPosition(location: number): number | undefined {\n return this.stackPositions.get(location);\n }\n\n public setStackPosition(location: number, value: number): void {\n this.stackPositions.set(location, value);\n }\n\n public tryAddStackPosition(location: number, value: number): boolean {\n if (this.stackPositions.has(location)) {\n return false;\n }\n this.stackPositions.set(location, value);\n return true;\n }\n} ","/**\r\n * Provides low-level ROM data reading functionality\r\n * Converted from GaiaLib/Rom/Extraction/RomDataReader.cs\r\n */\r\nexport class RomDataReader {\r\n public readonly romData: Uint8Array;\r\n public position: number;\r\n\r\n constructor(romData: Uint8Array) {\r\n if (!romData) {\r\n throw new Error('romData cannot be null');\r\n }\r\n this.romData = romData;\r\n this.position = 0;\r\n }\r\n\r\n public readByte(): number {\r\n return this.romData[this.position++];\r\n }\r\n\r\n public readSByte(): number {\r\n const value = this.readByte();\r\n return value > 127 ? value - 256 : value;\r\n }\r\n\r\n public readUShort(): number {\r\n return this.readByte() | (this.readByte() << 8);\r\n }\r\n\r\n public readShort(): number {\r\n const value = this.readUShort();\r\n return value > 32767 ? value - 65536 : value;\r\n }\r\n\r\n public readAddress(): number {\r\n return this.readByte() | (this.readByte() << 8) | (this.readByte() << 16);\r\n }\r\n\r\n public readInt(): number {\r\n return this.readByte() | (this.readByte() << 8) | (this.readByte() << 16) | (this.readByte() << 24);\r\n }\r\n\r\n public peekByte(): number {\r\n return this.romData[this.position];\r\n }\r\n\r\n public peekShort(): number {\r\n return this.romData[this.position] | (this.romData[this.position + 1] << 8);\r\n }\r\n\r\n public peekAddress(): number {\r\n return this.romData[this.position]\r\n | (this.romData[this.position + 1] << 8)\r\n | (this.romData[this.position + 2] << 16);\r\n }\r\n} ","/**\r\n * ROM processing constants\r\n * Converted from GaiaLib/Types/RomProcessingConstants.cs\r\n */\r\nexport class RomProcessingConstants {\r\n // Core constants\r\n public static readonly PAGE_SIZE = 0x8000;\r\n public static readonly SNES_HEADER_SIZE = 0x50;\r\n\r\n // Dictionary constants\r\n public static readonly DICTIONARIES = [\"dictionary_01EBA8\", \"dictionary_01F54D\"];\r\n public static readonly DICT_COMMANDS = [0xD6, 0xD7];\r\n public static readonly END_CHARS = [0xC0, 0xCA, 0xD1];\r\n\r\n // Character arrays for parsing\r\n public static readonly WHITESPACE = [' ', '\\t'];\r\n public static readonly OPERATORS = ['-', '+'];\r\n public static readonly COMMA_SPACE = [',', ' ', '\\t'];\r\n public static readonly ADDRESS_SPACE = ['@', '&', '^', '#', '$', '%', '*'];\r\n public static readonly SYMBOL_SPACE = [',', ' ', '\\t', '<', '>', '(', ')', ':', '[', ']', '{', '}', '`', '~', '|'];\r\n public static readonly LABEL_SPACE = ['[', '{', '#', '`', '~', '|', ':'];\r\n public static readonly OBJECT_SPACE = ['<', '['];\r\n public static readonly COP_SPLIT_CHARS = [' ', '\\t', ',', '(', ')', '[', ']', '$', '#'];\r\n\r\n // Pre-compiled regular expressions for parsing\r\n public static readonly WHITESPACE_REGEX = /[ \\t]/;\r\n public static readonly COMMA_SPACE_REGEX = /[, \\t]/;\r\n public static readonly SYMBOL_SPACE_REGEX = /[, \\t<>()\\:\\[\\]{}`~|]/;\r\n public static readonly LABEL_SPACE_REGEX = /[\\[{#`~|:]/;\r\n public static readonly OBJECT_SPACE_REGEX = /[<\\[]/;\r\n public static readonly ADDRESS_SPACE_REGEX = /[@&^#$%*]/;\r\n public static readonly COP_SPLIT_REGEX = /[ \\t,()[\\]$#]/;\r\n \r\n // Trim patterns (for start/end of string)\r\n public static readonly COMMA_SPACE_TRIM_REGEX = /^[, \\t]+|[, \\t]+$/g;\r\n\r\n /**\r\n * Gets the size of an object for processing purposes\r\n * @param obj The object to get the size for\r\n * @returns Size in bytes\r\n * @throws Error when unable to determine size\r\n */\r\n public static getSize(obj: unknown): number {\r\n if(obj === undefined || obj === null) return 0;\r\n switch(typeof obj) {\r\n case 'object':\r\n if(Array.isArray(obj)) {\r\n return obj.reduce((acc, x) => acc + RomProcessingConstants.getSize(x), 0);\r\n }\r\n if ('size' in obj) return obj.size as number;\r\n if ('length' in obj) return obj.length as number;\r\n if ('_tag' in obj) {\r\n switch ((obj as { _tag: string })._tag) {\r\n case 'Byte':\r\n return 1;\r\n case 'Word':\r\n return 2;\r\n }\r\n }\r\n break;\r\n\r\n case 'number':\r\n // Determine size based on value range\r\n if (obj <= 0xFF) return 1;\r\n if (obj <= 0xFFFF) return 2;\r\n if (obj <= 0xFFFFFF) return 3;\r\n return 4;\r\n\r\n case 'string':\r\n if(!obj.length) return 0;\r\n\r\n switch (obj[0]) {\r\n case '@':\r\n case '%':\r\n return 3;\r\n case '*':\r\n case '&':\r\n return 2;\r\n case '^':\r\n return 1;\r\n }\r\n\r\n switch (obj) {\r\n case \"Byte\":\r\n return 1;\r\n case \"Word\":\r\n return 2;\r\n case \"Offset\":\r\n return 2;\r\n case \"Address\":\r\n return 3;\r\n }\r\n \r\n return obj.length;\r\n }\r\n\r\n return 0;\r\n }\r\n}\r\n\r\n/**\r\n * BlockReader specific constants\r\n */\r\nexport class BlockReaderConstants {\r\n public static readonly REF_SEARCH_MAX_RANGE = 0x1A0;\r\n public static readonly BANK_MASK_CHECK = 0x40;\r\n public static readonly BYTE_DELIMITER_THRESHOLD = 0x100;\r\n public static readonly BANK_HIGH_MEMORY_1 = 0x7E;\r\n public static readonly BANK_HIGH_MEMORY_2 = 0x7F;\r\n public static readonly POINTER_CHARACTERS = ['&', '@'];\r\n public static readonly WIDE_STRING_TYPE = \"WideString\";\r\n public static readonly BINARY_TYPE = \"Binary\";\r\n public static readonly CODE_TYPE = \"Code\";\r\n \r\n // Format strings\r\n public static readonly LOCATION_FORMAT = \"loc_{0:X6}\";\r\n public static readonly TYPE_NAME_FORMAT = \"{0}_{1:X6}\";\r\n public static readonly OFFSET_FORMAT = \"+{0:X}\";\r\n public static readonly MARKER_FORMAT = \"+M\";\r\n public static readonly NEGATIVE_OFFSET_FORMAT = \"-{0:X}\";\r\n public static readonly NEGATIVE_MARKER_FORMAT = \"-M\";\r\n} ","import { RomProcessingConstants } from './constants';\r\n\r\n\r\n/**\r\n * Address type classifications\r\n * Converted from GaiaLib/Enum/AddressType.cs\r\n */\r\nexport enum AddressType {\r\n Unknown = 'Unknown',\r\n Bank = 'Bank',\r\n Offset = 'Offset',\r\n Address = 'Address',\r\n WBank = 'WBank',\r\n Relative = 'Relative',\r\n WRelative = 'WRelative',\r\n Location = 'Location'\r\n}\r\n\r\n/**\r\n * Address space types\r\n * Converted from GaiaLib/Types/Address.cs\r\n */\r\nexport enum AddressSpace {\r\n None = 'None',\r\n ROM = 'ROM',\r\n WRAM = 'WRAM',\r\n SRAM = 'SRAM',\r\n System = 'System'\r\n}\r\n\r\nexport enum MemoryMapMode {\r\n Lo = 'Lo',\r\n Hi = 'Hi',\r\n ExHi = 'ExHi'\r\n}\r\n\r\nexport enum CpuMode {\r\n Slow = 'Slow',\r\n Fast = 'Fast'\r\n}\r\n\r\n/**\r\n * SNES address structure\r\n * Converted from GaiaLib/Types/Address.cs\r\n */\r\nexport class Address {\r\n public offset: number;\r\n public bank: number;\r\n public mode: MemoryMapMode;\r\n \r\n public static readonly UPPER_BANK = 0x8000;\r\n public static readonly DATA_BANK_FLAG = 0x40;\r\n public static readonly FAST_BANK_FLAG = 0x80;\r\n\r\n constructor(bank: number, offset: number, mode: MemoryMapMode) {\r\n this.bank = bank & 0xFF;\r\n this.offset = offset & 0xFFFF;\r\n this.mode = mode;\r\n }\r\n\r\n public get isROM(): boolean {\r\n if(this.bank === 0x7E || this.bank === 0x7F) return false;\r\n if(this.offset >= Address.UPPER_BANK) return true;\r\n if(!this.isCodeBank) {\r\n if(this.mode === MemoryMapMode.Lo && this.bank >= 0x70 && this.bank <= 0x7D) return false;\r\n return true;\r\n }\r\n return false;\r\n }\r\n\r\n public get isCodeBank(): boolean {\r\n return (this.bank & Address.DATA_BANK_FLAG) === 0;\r\n }\r\n\r\n // public get space(): AddressSpace {\r\n \r\n // if (this.bank === 0x7E || this.bank === 0x7F) return AddressSpace.WRAM;\r\n // if (this.offset >= RomProcessingConstants.PAGE_SIZE) return AddressSpace.ROM;\r\n\r\n // // Check if bank is in lower half (bank & 0x40 == 0)\r\n // if (this.isCodeBank) {\r\n // // Memory map for lower banks\r\n // if (this.offset >= 0x6000 && (this.bank & 0x20) !== 0) {\r\n // return AddressSpace.SRAM;\r\n // }\r\n // if (this.offset < 0x2000) {\r\n // return AddressSpace.WRAM;\r\n // } else if (this.offset < 0x2100) {\r\n // return AddressSpace.None;\r\n // } else if (this.offset < 0x2200) {\r\n // return AddressSpace.System;\r\n // } else if (this.offset < 0x3000) {\r\n // return AddressSpace.None;\r\n // } else if (this.offset < 0x4100) {\r\n // return AddressSpace.System;\r\n // } else if (this.offset < 0x4200) {\r\n // return AddressSpace.None;\r\n // } else if (this.offset < 0x4500) {\r\n // return AddressSpace.System;\r\n // } else {\r\n // return AddressSpace.None;\r\n // }\r\n // }\r\n\r\n\r\n // return AddressSpace.ROM;\r\n // }\r\n\r\n public toLocation(): number {\r\n if(this.mode === MemoryMapMode.Lo) return ((this.bank & 0x3F) << 15) | (this.offset & 0x7FFF);\r\n if(this.mode === MemoryMapMode.Hi || (this.bank & Address.FAST_BANK_FLAG)) return ((this.bank & 0x3F) << 16) | (this.offset & 0xFFFF);\r\n return (this.bank === 0x3E) ? (this.offset + 0x13D0000) : (this.bank === 0x3F) ? (this.offset + 0x13E0000) \r\n : ((((this.bank & 0x3F) << 16) | (this.offset & 0xFFFF)) + 0x1000000);\r\n }\r\n\r\n public static fromLocation(value: number, mode: MemoryMapMode, cpuMode: CpuMode): Address {\r\n let bankFlag = cpuMode === CpuMode.Fast ? Address.FAST_BANK_FLAG : 0;\r\n if(mode === MemoryMapMode.Lo) {\r\n return new Address((value >> 15) & 0x7F | bankFlag, (value & 0x7FFF) | 0x8000, mode);\r\n }\r\n if(mode === MemoryMapMode.Hi) {\r\n if((value & RomProcessingConstants.PAGE_SIZE) === 0) bankFlag = 0xC0\r\n return new Address((value >> 16) & 0x7F | bankFlag, value & 0xFFFF, mode);\r\n }\r\n ///TODO: Handle ExHi mode\r\n if(value & Address.FAST_BANK_FLAG) return new Address((value >> 16) & 0xFF, value & 0xFFFF, mode);\r\n if(value >= 0x13D0000 && value < 0x13E0000) return new Address(0x3E, value - 0x13D0000, mode);\r\n if(value >= 0x13E0000 && value < 0x13F0000) return new Address(0x3F, value - 0x13E0000, mode);\r\n return new Address((value >> 16) & 0x7F, value & 0xFFFF, mode);\r\n }\r\n\r\n public static resolveBank(value: number, mode: MemoryMapMode): number {\r\n if(mode === MemoryMapMode.Lo) return (value >> 15) & 0xFF;\r\n if(mode === MemoryMapMode.Hi || (value & Address.FAST_BANK_FLAG)) return (value >> 16) & 0xFF;\r\n if(value >= 0x13D0000 && value < 0x13E0000) return 0x3E;\r\n if(value >= 0x13E0000 && value < 0x13F0000) return 0x3F;\r\n return (value >> 16) & 0x7F; \r\n }\r\n\r\n public toInt(): number {\r\n return (this.bank << 16) | this.offset;\r\n }\r\n\r\n public toString(): string {\r\n return this.toInt().toString(16).toUpperCase().padStart(6, '0');\r\n }\r\n\r\n public static typeFromCode(code: string): AddressType {\r\n switch (code) {\r\n case '^':\r\n return AddressType.Bank;\r\n case '&':\r\n return AddressType.Offset;\r\n case '@':\r\n return AddressType.Address;\r\n case '*':\r\n return AddressType.WBank;\r\n case '%':\r\n return AddressType.Location;\r\n default:\r\n return AddressType.Unknown;\r\n }\r\n }\r\n\r\n public static codeFromType(type: AddressType): string | null {\r\n switch (type) {\r\n case AddressType.Bank:\r\n return '^';\r\n case AddressType.Offset:\r\n return '&';\r\n case AddressType.Address:\r\n return '@';\r\n case AddressType.WBank:\r\n return '*';\r\n case AddressType.Location:\r\n return '%';\r\n default:\r\n return null;\r\n }\r\n }\r\n} ","/**\r\n * Member type definitions for data structures\r\n * Converted from GaiaLib/Enum/MemberType.cs\r\n */\r\nexport enum MemberType {\r\n Byte = 'Byte',\r\n Word = 'Word',\r\n Offset = 'Offset',\r\n Address = 'Address',\r\n Binary = 'Binary',\r\n Code = 'Code',\r\n Location = 'Location'\r\n} ","/**\r\n * Processor register type definitions\r\n * Converted from GaiaLib/Enum/RegisterType.cs\r\n */\r\nexport enum RegisterType {\r\n M = 'M',\r\n X = 'X',\r\n B = 'B'\r\n}\r\n\r\n/**\r\n * Status flags for 65816 processor\r\n * Converted from GaiaLib/Enum/StatusFlags.cs\r\n * \r\n * Bit pattern: [ n v m x d i z c ]\r\n * n = Negative\r\n * v = Overflow\r\n * m = Accumulator Mode\r\n * x = Index Mode\r\n * d = Decimal Mode\r\n * i = IRQ Disable\r\n * z = Zero\r\n * c = Carry\r\n */\r\nexport enum StatusFlags {\r\n /**\r\n * Clear before starting addition or subtraction.\r\n * Arithmetic overflow:\r\n * [addition - carry out of high bit:]\r\n * 0 = no carry\r\n * 1 = carry\r\n * [subtraction - borrow required to subtract:]\r\n * 0 = borrow required\r\n * 1 = no borrow required\r\n * [Logic:]\r\n * receives bit shifted or rotated out;\r\n * source of bit rotated in\r\n */\r\n Carry = 0x01,\r\n /**\r\n * Indicates zero or non-zero result:\r\n * 0 = non-zero result\r\n * 1 = zero result\r\n */\r\n Zero = 0x02,\r\n /**\r\n * Enables or disables processor's IRQ interrupt line:\r\n * Set to disable interrupts by masking the IRQ line\r\n * Clear to enable IRQ interrupts\r\n */\r\n IrqDisable = 0x04,\r\n /**\r\n * Determines mode for add/subtract (not increment/decrement, though):\r\n * Set to force decimal operation (BCD)\r\n * Clear to return to binary operation\r\n */\r\n DecimalMode = 0x08,\r\n IndexMode = 0x10,\r\n AccumulatorMode = 0x20,\r\n /**\r\n * Clear to reverse \"set-overflow\" hardware input.\r\n * Indicates invalid carry into high bit of arithmetic\r\n * result (two's-complement overflow):\r\n * 0 = two's-complement result ok\r\n * 1 = error if two's-complement arithmetic\r\n */\r\n Overflow = 0x40,\r\n /**\r\n * Reflects most significant bit of result\r\n * (the sign of a two's-complement binary number):\r\n * 0 = high bit clear (positive result)\r\n * 1 = high bit set (negative result)\r\n */\r\n Negative = 0x80\r\n} ","/**\r\n * Binary resource type definitions\r\n * Converted from GaiaLib/Enum/BinType.cs\r\n */\r\nexport enum BinType {\r\n Bitmap = 'Bitmap',\r\n Tilemap = 'Tilemap',\r\n Tileset = 'Tileset',\r\n Palette = 'Palette',\r\n Sound = 'Sound',\r\n Music = 'Music',\r\n //Unknown = 'Unknown',\r\n Meta17 = 'Meta17',\r\n Spritemap = 'Spritemap',\r\n Assembly = 'Assembly',\r\n Patch = 'Patch',\r\n Transform = 'Transform',\r\n Binary = 'Binary'\r\n} ","/**\r\n * Transform type definitions\r\n * Converted from GaiaLib/Enum/XformType.cs\r\n */\r\nexport enum XformType {\r\n Lookup = 'Lookup',\r\n Replace = 'Replace'\r\n}\r\n\r\n/**\r\n * Transform definition\r\n * Converted from GaiaLib/Types/XformDef.cs\r\n */\r\nexport interface XformDef {\r\n type: XformType;\r\n key?: string;\r\n value?: string;\r\n keyIx?: number;\r\n valueIx?: number;\r\n} ","\r\nexport class OpCode {\r\n public code: number;\r\n public mnem: string;\r\n public mode: string;\r\n\r\n constructor(code: number, mnem: string, mode: string) {\r\n this.code = code;\r\n this.mnem = mnem;\r\n this.mode = mode;\r\n }\r\n}\r\n","import { ChunkFile } from \"./files\";\nimport { CopDef } from \"../database/cop\";\nimport { OpCode } from \"../database/opcode\";\n\n\n/**\n * Represents a single assembly operation/instruction\n */\nexport class Op extends OpCode {\n public location: number;\n public operands: unknown[];\n public size: number;\n public copDef?: CopDef;\n\n constructor(\n code: OpCode,\n location: number = 0,\n operands: unknown[] = [],\n size: number = 1\n ) {\n super(code.code, code.mnem, code.mode);\n this.code = code.code;\n this.location = location;\n this.operands = operands;\n this.size = size;\n }\n}\n\n/**\n * Represents a block of assembly code or data\n */\nexport class AsmBlock {\n public label?: string;\n public location: number;\n public size: number;\n public isString: boolean;\n public objList: any[];\n public structName?: string;\n public bank?: number;\n public includes?: Set<{block: ChunkFile, part: AsmBlock}>;\n\n constructor(\n location: number = 0,\n size: number = 0,\n isString: boolean = false,\n label?: string,\n structName?: string,\n bank?: number\n ) {\n this.label = label;\n this.location = location;\n this.size = size;\n this.isString = isString;\n this.objList = [];\n this.structName = structName;\n this.bank = bank;\n this.includes = new Set();\n }\n} \n\n/**\n * Database part utilities\n */\nexport class AsmBlockUtils {\n /**\n * Check if a location is inside this part\n */\n static isInside(part: AsmBlock, location: number): boolean {\n return location >= part.location && location < (part.location + part.size);\n }\n\n /**\n * Check if a location is outside this part\n */\n static isOutside(part: AsmBlock, location: number): boolean {\n return location < part.location || location >= (part.location + part.size);\n }\n} ","/**\n * Bit stream for reading/writing binary data at bit level\n * Converted from GaiaLib/Types/BitStream.cs\n */\nexport class BitStream {\n private static readonly NIBBLE_MASK = 0xF;\n private static readonly NIBBLE_PERFECT_POSITION = 0x08;\n\n private data: Uint8Array;\n private position: number;\n private bitFlag: number = 0x80;\n private writeSample: number = 0;\n\n constructor(data: Uint8Array, position: number = 0) {\n this.data = data;\n this.position = position;\n }\n\n public get dataArray(): Uint8Array {\n return this.data;\n }\n\n public get currentPosition(): number {\n return this.position;\n }\n\n public set currentPosition(value: number) {\n this.position = value;\n }\n\n /**\n * Read a byte from the stream\n * @returns The byte read, or -1 if the end of the data has been reached\n */\n public readByte(): number {\n // If we've reached the end of the data, return -1\n if (this.position >= this.data.length) {\n return -1;\n }\n\n // Read the current byte, and advance the position\n let sample = this.data[this.position++];\n\n // If the bit flag is not the most significant bit, we need to include the next byte\n if (this.bitFlag !== 0x80) {\n // Include the next byte in the sample\n sample = (sample << 8) | this.data[this.position];\n\n // Shift the (temporary) bit flag to the right until it is 0\n for (let x = this.bitFlag; x > 0; x >>= 1) {\n // Shift sample for each iteration so it will line up with the byte boundary\n sample >>= 1;\n }\n }\n\n // Return the sample\n return sample & 0xFF;\n }\n\n /**\n * Read a ushort from the stream (ignores the current bit flag)\n * @returns The short read, or -1 if the end of the data has been reached\n */\n public readShort(): number {\n // If end of stream (position would overlap data.length), return -1\n if (this.position + 1 >= this.data.length) {\n return -1;\n }\n\n // Read sample using two bytes to form a ushort. Advance position by 2\n const value = this.data[this.position++] | (this.data[this.position++] << 8);\n\n // Return the value\n return value;\n }\n\n /**\n * Read a bit from the stream\n * @returns True if the current bit at bitFlag is set, false otherwise\n */\n public readBit(): boolean {\n // If we've reached the end of the data, return false\n if (this.position >= this.data.length) {\n return false;\n }\n\n // Read the current bit and test it against current bit flag\n const sample = this.data[this.position] & this.bitFlag;\n\n // Shift the bit flag to the right\n this.bitFlag >>= 1;\n\n // If the bit flag is 0, we need to move to the next byte\n if (this.bitFlag === 0) {\n // Reset the bit flag to the most significant bit\n this.bitFlag = 0x80;\n // Advance the position to the next byte\n this.position++;\n }\n\n // Return true if the bit is set, false otherwise\n return sample !== 0;\n }\n\n /**\n * Read a nibble from the stream\n * @returns The nibble read, or -1 if the end of the data has been reached\n */\n public readNibble(): number {\n // If we've reached the end of the data, return -1\n if (this.position >= this.data.length) {\n return -1;\n }\n\n // Read the current (unshifted) byte sample\n let sample = this.data[this.position];\n\n if (this.bitFlag === BitStream.NIBBLE_PERFECT_POSITION) {\n // Reset the bit flag to the most significant bit\n this.bitFlag = 0x80;\n // Advance the position to the next byte\n this.position++;\n } else {\n // Initialize the bit position to -4 (will be incremented as we shift the bit flag to the right)\n let bitPos = -4;\n\n // Shift the bit flag to the right until it is 0\n while (this.bitFlag !== 0) {\n // Shift the bit flag to the right\n this.bitFlag >>= 1;\n // Increment the bit position\n bitPos++;\n }\n\n // If the bit position is less than 0, we need to include the next byte\n if (bitPos < 0) {\n // Include the next byte in the sample, and advance the position\n sample = (sample << 8) | this.data[++this.position];\n\n // Advance the bit position by 8 (will no longer be less than 0)\n bitPos += 8;\n }\n\n // Shift the sample to the right by the bit position\n sample >>= bitPos;\n\n // Set the bit flag to the new bit position\n this.bitFlag = 1 << (bitPos - 1);\n }\n\n // Return the nibble\n return sample & BitStream.NIBBLE_MASK;\n }\n\n /**\n * Write a bit to the stream\n * @param set True if the current bit should be set, false otherwise\n */\n public writeBit(set: boolean): void {\n // If the bit should be set, set the bit in the write sample\n if (set) {\n this.writeSample |= this.bitFlag;\n }\n\n // Shift the bit flag to the right\n this.bitFlag >>= 1;\n\n // If the bit flag is 0, we need to move to the next byte\n if (this.bitFlag === 0) {\n // Reset the bit flag to the most significant bit\n this.bitFlag = 0x80;\n // Write the sample to the data stream\n this.data[this.position++] = this.writeSample;\n // Reset the write sample\n this.writeSample = 0;\n }\n }\n\n /**\n * Write a byte to the stream\n * @param value The byte to write\n */\n public writeByte(value: number): void {\n // If the bit flag is the most significant bit, we can write the byte directly\n if (this.bitFlag === 0x80) {\n this.data[this.position++] = value;\n } else {\n // Shift the value to the left until it is aligned with the bit flag\n for (let x = 1; x <= this.bitFlag; x <<= 1) {\n value <<= 1;\n }\n\n // Write the value to the data stream\n this.data[this.position++] = (this.writeSample | (value >> 8)) & 0xFF;\n\n // Update the write sample\n this.writeSample = value & 0xFF;\n }\n }\n\n /**\n * Write a nibble to the stream\n * @param value The nibble to write\n */\n public writeNibble(value: number): void {\n value &= BitStream.NIBBLE_MASK;\n\n if (this.bitFlag >= 0x10) {\n let shift = 0;\n switch (this.bitFlag) {\n case 0x80: shift = 4; break;\n case 0x40: shift = 3; break;\n case 0x20: shift = 2; break;\n case 0x10: shift = 1; break;\n }\n this.writeSample |= (value << shift);\n this.bitFlag >>= 4;\n } else {\n let shift = 0;\n switch (this.bitFlag) {\n case 0x8: shift = 0; break;\n case 0x4: shift = 1; break;\n case 0x2: shift = 2; break;\n case 0x1: shift = 3; break;\n }\n this.data[this.position++] = (this.writeSample | (value >> shift));\n this.writeSample = (value << (8 - shift));\n this.bitFlag <<= 4;\n }\n }\n\n public flush(): void {\n if (this.bitFlag !== 0x80) {\n this.data[this.position++] = this.writeSample;\n }\n }\n} ","import type { ICompressionProvider } from './compression';\r\n\r\n/**\r\n * Registry for compression providers\r\n * Allows registration of compression implementations by string ID\r\n */\r\nexport class CompressionRegistry {\r\n private static providers = new Map<string, () => ICompressionProvider>();\r\n\r\n /**\r\n * Register a compression provider\r\n * @param id String identifier for the compression type\r\n * @param factory Factory function that creates the compression provider\r\n */\r\n public static register(id: string, factory: () => ICompressionProvider): void {\r\n this.providers.set(id, factory);\r\n }\r\n\r\n /**\r\n * Get a compression provider by ID\r\n * @param id String identifier for the compression type\r\n * @returns Compression provider instance\r\n */\r\n public static get(id: string): ICompressionProvider {\r\n const factory = this.providers.get(id);\r\n if (!factory) {\r\n throw new Error(`No compression provider registered for type: ${id}`);\r\n }\r\n return factory();\r\n }\r\n\r\n /**\r\n * Check if a compression provider is registered\r\n * @param id String identifier for the compression type\r\n * @returns True if provider is registered\r\n */\r\n public static has(id: string): boolean {\r\n return this.providers.has(id);\r\n }\r\n\r\n /**\r\n * Get list of registered provider IDs\r\n * @returns Array of registered provider IDs\r\n */\r\n public static getRegisteredIds(): string[] {\r\n return Array.from(this.providers.keys());\r\n }\r\n\r\n /**\r\n * Clear all registered providers (mainly for testing)\r\n */\r\n public static clear(): void {\r\n this.providers.clear();\r\n }\r\n}\r\n","import { BinType } from './resources';\r\nimport { AsmBlock, AsmBlockUtils } from './assembly';\r\nimport { DbFile, DbFileType } from '../database/files';\r\nimport { DbBlock } from '../database/blocks';\r\nimport { ICompressionProvider } from './compression';\r\nimport { MemoryMapMode } from './addressing';\r\n\r\n/**\r\n * Chunk file for ROM processing\r\n * Converted from GaiaLib/Types/ChunkFile.cs\r\n */\r\nexport class ChunkFile {\r\n //id?: string;\r\n name: string;\r\n size: number;\r\n location: number;\r\n type: DbFileType;\r\n parts?: AsmBlock[];\r\n includes?: Set<string>;\r\n includeLookup?: Map<string, AsmBlock>;\r\n bank?: number;\r\n compressed?: boolean;\r\n upper?: boolean;\r\n rawData?: Uint8Array | null;\r\n textData?: string;\r\n transforms?: { key: string; value: string }[];\r\n postProcess?: string;\r\n mnemonics: Record<number, string>;\r\n group?: string;\r\n scene?: string;\r\n\r\n constructor(name: string, size: number, location: number, type: DbFileType) {\r\n this.name = name;\r\n this.size = size;\r\n this.location = location;\r\n this.mnemonics = {};\r\n this.compressed = type.compressed;\r\n this.type = type;\r\n }\r\n\r\n // public getExtension() : string {\r\n // switch(this.type) {\r\n // case BinType.Assembly:\r\n // case BinType.Patch:\r\n // return 'asm';\r\n // case BinType.Music:\r\n // return 'bgm';\r\n // case BinType.Sound:\r\n // return 'sfx';\r\n // case BinType.Bitmap:\r\n // return 'bin';\r\n // case BinType.Tilemap:\r\n // return 'map';\r\n // case BinType.Tileset:\r\n // return 'set';\r\n // case BinType.Spritemap:\r\n // return 'spm';\r\n // case BinType.Palette:\r\n // return 'pal';\r\n // case BinType.Meta17:\r\n // return 'dmp';\r\n // }\r\n // }\r\n}\r\n\r\n// /**\r\n// * Creates a new ChunkFile\r\n// */\r\n// export function createChunkFile(name: string, size: number, location: number, type: BinType): ChunkFile {\r\n// return {\r\n// name,\r\n// size,\r\n// location,\r\n// type,\r\n// mnemonics: {}\r\n// };\r\n// }\r\n\r\nexport function createChunkFileFromDbFile(rom: Uint8Array, compression: ICompressionProvider | undefined, dbFile: DbFile, fileType: DbFileType): ChunkFile {\r\n // Create ChunkFile with the DbFile's type\r\n const chunkFile = new ChunkFile(dbFile.name, dbFile.end - dbFile.start, dbFile.start, fileType);\r\n //chunkFile.id = dbFile.id;\r\n chunkFile.compressed = dbFile.compressed;\r\n chunkFile.upper = dbFile.upper;\r\n chunkFile.group = dbFile.group;\r\n chunkFile.scene = dbFile.scene;\r\n\r\n \r\n // Enrich with raw binary data\r\n enrichWithRawDataFromDbFile(rom, chunkFile, compression, dbFile, fileType);\r\n\r\n return chunkFile;\r\n}\r\n\r\nexport function createChunkFileFromDbBlock(block: DbBlock, fileType: DbFileType, memoryMode: MemoryMapMode): ChunkFile {\r\n // Create assembly ChunkFile\r\n const chunkFile = new ChunkFile(block.name, 0, 0, fileType);\r\n //chunkFile.id = block.id;\r\n chunkFile.group = block.group;\r\n chunkFile.scene = block.scene;\r\n \r\n // Enrich with AsmBlock parts\r\n enrichWithPartsFromDbBlock(chunkFile, block, memoryMode);\r\n \r\n return chunkFile;\r\n}\r\n\r\n\r\nfunction combineHeader(\r\n data: Uint8Array,\r\n position: number,\r\n length: number,\r\n header: Uint8Array | null,\r\n type: BinType\r\n): Uint8Array {\r\n let totalLength = length + (header ? header.length : 0);\r\n if (type === BinType.Palette && length < 0x200) {\r\n totalLength += (0x200 - length);\r\n }\r\n const result = new Uint8Array(totalLength);\r\n let offset = 0;\r\n if (header) { result.set(header, offset); offset += header.length; }\r\n result.set(data.slice(position, position + length), offset);\r\n offset += length;\r\n if (type === BinType.Palette && length < 0x200) {\r\n result.fill(0, offset, offset + (0x200 - length));\r\n }\r\n return result;\r\n}\r\n\r\n/**\r\n * Enriches ChunkFile with raw binary data from DbFile\r\n */\r\nfunction enrichWithRawDataFromDbFile(rom: Uint8Array, chunkFile: ChunkFile, compression: ICompressionProvider | undefined, dbFile: DbFile, fileType: DbFileType): void {\r\n \r\n // Extract raw data (uncompressed) with headers for specific types\r\n let start = dbFile.start;\r\n let header: Uint8Array | null = null;\r\n if(fileType.header) {\r\n header = new Uint8Array(rom.slice(start, start + fileType.header));\r\n start += fileType.header;\r\n }\r\n let length = dbFile.end - start;\r\n let fileData: Uint8Array;\r\n if (dbFile.compressed === true && compression) {\r\n const expanded = compression.expand(rom, start, length);\r\n fileData = combineHeader(expanded, 0, expanded.length, header, fileType.type as BinType);\r\n } else {\r\n if (dbFile.compressed !== undefined) {\r\n start += 2; length -= 2; // skip zero-compression header\r\n }\r\n fileData = combineHeader(rom, start, length, header, fileType.type as BinType);\r\n }\r\n \r\n //const hasSizePrefix = chunkFile.compressed !== undefined || dbFile.type === BinType.Sound;\r\n\r\n // Binary files get rawData\r\n chunkFile.rawData = fileData;\r\n chunkFile.size = fileData.length;// + (hasSizePrefix ? 2 : 0);\r\n\r\n}\r\n\r\n/**\r\n * Enriches ChunkFile with AsmBlock parts from DbBlock\r\n */\r\nfunction enrichWithPartsFromDbBlock(chunkFile: ChunkFile, block: DbBlock, memoryMode: MemoryMapMode): void {\r\n chunkFile.parts = [];\r\n chunkFile.size = 0;\r\n if(!block.parts?.length) {\r\n throw new Error(`Block ${block.name} has no parts`);\r\n }\r\n chunkFile.location = block.parts[0].start;\r\n chunkFile.bank = block.movable ? undefined : (memoryMode === MemoryMapMode.Lo ? chunkFile.location >> 15 : chunkFile.location >> 16);\r\n chunkFile.transforms = block.transforms;\r\n chunkFile.postProcess = block.postProcess;\r\n \r\n for (const part of block.parts) {\r\n const asmBlock = new AsmBlock(\r\n part.start,\r\n part.end - part.start,\r\n false, // isString will be determined during processing\r\n part.name,\r\n part.type || undefined,\r\n part.bank\r\n );\r\n chunkFile.size += asmBlock.size;\r\n chunkFile.parts.push(asmBlock);\r\n }\r\n}\r\n\r\n/**\r\n * Chunk file utilities\r\n */\r\nexport class ChunkFileUtils {\r\n /**\r\n * Rebase blocks to a new location\r\n */\r\n static rebase(chunkFile: ChunkFile, newLocation?: number): void {\r\n if (newLocation !== undefined) {\r\n chunkFile.location = newLocation;\r\n }\r\n\r\n if (!chunkFile.parts) {\r\n return;\r\n }\r\n\r\n let loc = chunkFile.location;\r\n for (let x = 0; x < chunkFile.parts.length; x++) {\r\n const block = chunkFile.parts[x];\r\n if (x > 0 && !block.label) {\r\n break;\r\n }\r\n block.location = loc;\r\n loc += block.size || 0;\r\n }\r\n }\r\n\r\n /**\r\n * Calculate the total size of all blocks\r\n */\r\n static calculateSize(chunkFile: ChunkFile): number {\r\n if (!chunkFile.parts) {\r\n let size = chunkFile.rawData?.length ?? chunkFile.size;\r\n if (chunkFile.type.header === -2 || chunkFile.compressed === false){\r\n size += 2;\r\n chunkFile.size = size;\r\n }\r\n return size;\r\n }\r\n\r\n let size = 0;\r\n for (let x = 0; x < chunkFile.parts.length; x++) {\r\n const block = chunkFile.parts[x];\r\n if (x > 0 && !block.label) {\r\n break;\r\n }\r\n size += block.size || 0;\r\n }\r\n \r\n chunkFile.size = size;\r\n return size;\r\n }\r\n\r\n /**\r\n * Check if a location is outside this block and return the part (matches C# IsOutside)\r\n * Returns [isOutside, part] where part is the part containing the location\r\n */\r\n static isOutsideWithPart(root: ChunkFile[], block: ChunkFile, location: number): [boolean, ChunkFile | null, AsmBlock | null] {\r\n const [isInside, part] = this.isInsideWithPart(block, location);\r\n if (isInside) {\r\n return [false, block, part];\r\n }\r\n\r\n // Find chunk this reference belongs to\r\n for (const otherBlock of root) {\r\n if (otherBlock !== block) {\r\n const [otherIsInside, otherPart] = this.isInsideWithPart(otherBlock, location);\r\n if (otherIsInside) {\r\n return [true, otherBlock, otherPart];\r\n }\r\n }\r\n }\r\n\r\n return [true, null, null];\r\n }\r\n\r\n /**\r\n * Check if a location is inside this block and return the part (matches C# IsInside)\r\n * Returns [isInside, part] where part is the part containing the location\r\n */\r\n static isInsideWithPart(block: ChunkFile, location: number): [boolean, AsmBlock | null] {\r\n for (const part of block?.parts || []) {\r\n if (AsmBlockUtils.isInside(part, location)) {\r\n return [true, part];\r\n }\r\n }\r\n return [false, null];\r\n }\r\n\r\n /**\r\n * Check if a location is outside this block (shorthand version)\r\n */\r\n static isOutside(block: ChunkFile, location: number): boolean {\r\n return !this.isInside(block, location);\r\n }\r\n\r\n /**\r\n * Check if a location is inside this block (shorthand version)\r\n */\r\n static isInside(block: ChunkFile, location: number): boolean {\r\n for (const part of block?.parts || []) {\r\n if (AsmBlockUtils.isInside(part, location)) {\r\n return true;\r\n }\r\n }\r\n return false;\r\n }\r\n\r\n /**\r\n * Get all included blocks\r\n */\r\n static getIncludes(chunkFile: ChunkFile): ChunkFile[] {\r\n if(!chunkFile.parts) return [];\r\n const includes: ChunkFile[] = [];\r\n const seen = new Set<ChunkFile>();\r\n\r\n for (const part of chunkFile.parts) {\r\n if (part?.includes) {\r\n for (const includedPart of part.includes) {\r\n if (!seen.has(includedPart.block)) {\r\n includes.push(includedPart.block);\r\n seen.add(includedPart.block);\r\n }\r\n }\r\n }\r\n }\r\n\r\n return includes;\r\n }\r\n} ","import { AddressType } from './addressing';\r\n\r\n/**\r\n * Location wrapper for additional metadata\r\n * Converted from GaiaLib/Types/LocationWrapper.cs\r\n */\r\nexport class LocationWrapper {\r\n public location: number;\r\n public type: AddressType;\r\n\r\n constructor(location: number, type: AddressType) {\r\n this.location = location;\r\n this.type = type;\r\n }\r\n} ","import type { DbStringType } from '../database/strings';\r\nimport { AsmBlock } from './assembly';\r\n\r\n/**\r\n * String marker for positioning\r\n * Converted from GaiaLib/Types/StringMarker.cs\r\n */\r\nexport interface StringMarker {\r\n offset: number;\r\n}\r\n\r\n/**\r\n * String wrapper with type and location information\r\n * Converted from GaiaLib/Types/StringWrapper.cs\r\n */\r\nexport interface StringWrapper {\r\n string: string;\r\n type: DbStringType;\r\n marker: number;\r\n location: number;\r\n fixedSize: number;\r\n}\r\n\r\n/**\r\n * String entry (commented out in original C# code)\r\n * Converted from GaiaLib/Types/StringEntry.cs\r\n */\r\nexport interface StringEntry {\r\n block: AsmBlock;\r\n index: number;\r\n size: number;\r\n data: Uint8Array;\r\n}\r\n\r\n/**\r\n * String size comparer utility\r\n * Converted from GaiaLib/Types/StringSizeComparer.cs\r\n */\r\nexport class StringSizeComparer {\r\n /**\r\n * Compare two strings by length\r\n */\r\n static compare(a: string, b: string): number {\r\n if (a.length < b.length) return -1;\r\n if (a.length > b.length) return 1;\r\n return a.localeCompare(b);\r\n }\r\n \r\n /**\r\n * Compare two StringWrapper objects by string length\r\n */\r\n static compareWrappers(a: StringWrapper, b: StringWrapper): number {\r\n return this.compare(a.string, b.string);\r\n }\r\n} ","\r\nexport class TableEntry {\r\n location: number;\r\n object: unknown;\r\n\r\n constructor(location: number) {\r\n if(typeof location !== 'number') throw new Error('Location is required');\r\n this.location = location;\r\n }\r\n}\r\n","export class TypedNumber {\r\n value: number;\r\n size: number;\r\n\r\n constructor(value: number, size: number) {\r\n this.value = value;\r\n this.size = size;\r\n }\r\n}\r\n\r\nexport class Byte extends TypedNumber {\r\n constructor(value: number) {\r\n super(value & 0xFF, 1);\r\n }\r\n}\r\n\r\nexport class Word extends TypedNumber {\r\n constructor(value: number) {\r\n super(value & 0xFFFF, 2);\r\n }\r\n}\r\n\r\nexport class Long extends TypedNumber {\r\n constructor(value: number) {\r\n super(value & 0xFFFFFF, 3);\r\n }\r\n}","import { AddressType, Address } from '../../types';\r\nimport { BlockReaderConstants } from '../../types/constants';\r\nimport type { DbRoot } from '../../database';\r\n\r\n/**\r\n * Manages references, chunks, and markers during ROM analysis\r\n * Converted from GaiaLib/Rom/Extraction/ReferenceManager.cs\r\n */\r\nexport class ReferenceManager {\r\n public readonly structTable = new Map<number, string>();\r\n public readonly markerTable = new Map<number, number>();\r\n public readonly nameTable = new Map<number, string>();\r\n private readonly root: DbRoot;\r\n\r\n constructor(root: DbRoot) {\r\n if (!root) {\r\n throw new Error('root cannot be null');\r\n }\r\n this.root = root;\r\n }\r\n\r\n // Struct management\r\n public tryGetStruct(location: number): { found: boolean; chunkType?: string } {\r\n const chunkType = this.structTable.get(location);\r\n return { found: chunkType !== undefined, chunkType };\r\n }\r\n\r\n public tryAddStruct(location: number, chunkType: string): boolean {\r\n if (this.structTable.has(location)) {\r\n return false;\r\n }\r\n this.structTable.set(location, chunkType);\r\n return true;\r\n }\r\n\r\n public containsStruct(location: number): boolean {\r\n return this.structTable.has(location);\r\n }\r\n\r\n // Name management\r\n public tryGetName(location: number): { found: boolean; referenceName?: string } {\r\n const referenceName = this.nameTable.get(location);\r\n return { found: referenceName !== undefined, referenceName };\r\n }\r\n\r\n public tryAddName(location: number, referenceName: string): boolean {\r\n if (this.nameTable.has(location)) {\r\n return false;\r\n }\r\n this.nameTable.set(location, referenceName);\r\n return true;\r\n }\r\n\r\n // Marker management\r\n public tryGetMarker(location: number): { found: boolean; offset?: number } {\r\n const offset = this.markerTable.get(location);\r\n return { found: offset !== undefined, offset };\r\n }\r\n\r\n public setMarker(location: number, offset: number): void {\r\n this.markerTable.set(location, offset);\r\n }\r\n\r\n // Label creation\r\n public createBranchLabel(location: number): string {\r\n // const adrs = Address.fromInt(location, this.root.config.memoryMode);\r\n // const name = `loc_${adrs.toString()}`;\r\n const name = `loc_${location.toString(16).toUpperCase().padStart(6, '0')}`;\r\n this.nameTable.set(location, name);\r\n return name;\r\n }\r\n\r\n public createTypeName(type: string, location: number): string {\r\n let name = type.toLowerCase();\r\n \r\n // Handle pointer characters\r\n while (name.length > 0 && BlockReaderConstants.POINTER_CHARACTERS.includes(name[0])) {\r\n name = name.substring(1) + '_list';\r\n }\r\n\r\n //const adrs = Address.fromInt(location, this.root.config.memoryMode);\r\n //return `${name}_${adrs.toString()}`;\r\n return `${name}_${location.toString(16).toUpperCase().padStart(6, '0')}`;\r\n }\r\n\r\n public createFallbackName(location: number): string {\r\n const fileMatch = this.root.files.find(x =>\r\n x.start <= location && x.end > location\r\n );\r\n\r\n if (fileMatch) {\r\n const offset = location - fileMatch.start;\r\n return fileMatch.name + (offset !== 0 ? `+${offset.toString(16).toUpperCase()}` : '');\r\n }\r\n\r\n // const adrs = Address.fromInt(location, this.root.config.memoryMode);\r\n // return adrs.toString(); \r\n return location.toString(16).toUpperCase().padStart(6, '0');\r\n }\r\n\r\n /**\r\n * Finds a reference location by its assigned name.\r\n */\r\n public findLocationByName(name: string): number | undefined {\r\n for (const [loc, refName] of this.nameTable) {\r\n if (refName === name) {\r\n return loc;\r\n }\r\n }\r\n return undefined;\r\n }\r\n\r\n public resolveName(location: number, type: AddressType, isBranch: boolean): string {\r\n const prefix = Address.codeFromType(type);\r\n let name: string;\r\n let label: string | null = null;\r\n let resolvedLocation = location;\r\n\r\n // Handle rewrites first\r\n const rewrite = this.root.rewrites[location];\r\n if (rewrite !== undefined) {\r\n const result = this.processRewrite(location, rewrite);\r\n resolvedLocation = result.location;\r\n label = result.label;\r\n }\r\n\r\n // Try to get existing reference\r\n const existingName = this.nameTable.get(resolvedLocation);\r\n if (existingName) {\r\n name = existingName;\r\n } else {\r\n name = isBranch ? \r\n this.createBranchLabel(resolvedLocation) : \r\n this.findClosestReference(resolvedLocation) || this.createFallbackName(resolvedLocation);\r\n }\r\n\r\n return `${prefix || ''}${name}${label || ''}`;\r\n }\r\n\r\n public findClosestReference(location: number): string | null {\r\n let closestDistance = BlockReaderConstants.REF_SEARCH_MAX_RANGE;\r\n let closestName: string | null = null;\r\n let closestLocation: number | null = null;\r\n\r\n for (const [entryKey, entryValue] of this.nameTable) {\r\n if (entryKey > location) {\r\n continue;\r\n }\r\n\r\n const distance = location - entryKey;\r\n if (distance >= closestDistance) {\r\n continue;\r\n }\r\n\r\n closestDistance = distance;\r\n closestName = entryValue;\r\n closestLocation = entryKey;\r\n\r\n if (closestDistance === 1) {\r\n break;\r\n }\r\n }\r\n\r\n return this.processClosestMatch(location, closestName, closestLocation, closestDistance);\r\n }\r\n\r\n private processRewrite(location: number, rewrite: number): { location: number; label: string | null } {\r\n const offset = location - rewrite;\r\n const cmd = offset < 0 ? '-' : '+';\r\n const absOffset = Math.abs(offset);\r\n\r\n let label: string | null = null;\r\n const structType = this.structTable.get(rewrite);\r\n \r\n if (structType === BlockReaderConstants.WIDE_STRING_TYPE) {\r\n this.markerTable.set(rewrite, absOffset);\r\n this.markerTable.set(location, absOffset);\r\n label = cmd === '-' ? BlockReaderConstants.NEGATIVE_MARKER_FORMAT : BlockReaderConstants.MARKER_FORMAT;\r\n } else {\r\n const formatString = cmd === '-' ? BlockReaderConstants.NEGATIVE_OFFSET_FORMAT : BlockReaderConstants.OFFSET_FORMAT;\r\n label = formatString.replace('{0:X}', absOffset.toString(16).toUpperCase());\r\n }\r\n\r\n return { location: rewrite, label };\r\n }\r\n\r\n private processClosestMatch(\r\n location: number, \r\n closestName: string | null, \r\n closestLocation: number | null, \r\n closestDistance: number\r\n ): string | null {\r\n if (!closestName || closestLocation === null) {\r\n return null;\r\n }\r\n\r\n let result = closestName;\r\n const structType = this.structTable.get(closestLocation);\r\n\r\n if (structType === BlockReaderConstants.WIDE_STRING_TYPE) {\r\n this.markerTable.set(closestLocation, closestDistance);\r\n this.markerTable.set(location, closestDistance);\r\n result += BlockReaderConstants.MARKER_FORMAT;\r\n } else {\r\n result += `+${closestDistance.toString(16).toUpperCase()}`;\r\n }\r\n\r\n return result;\r\n }\r\n} ","import { Registers } from '../../assembly';\nimport { StatusFlags } from '../../types';\nimport type { BlockReader } from './blocks';\n\n/**\n * Handles stack operations for various stack-related instructions\n * Converted from GaiaLib/Rom/Extraction/StackOperations.cs\n */\nexport class StackOperations {\n private readonly _registers: Registers;\n private readonly _blockReader: BlockReader;\n\n constructor(registers: Registers, blockReader: BlockReader) {\n this._registers = registers;\n this._blockReader = blockReader;\n }\n\n public handleStackOperation(mnemonic: string): void {\n switch (mnemonic) {\n case 'PHD':\n this._registers.stack.push(this._registers.value['direct'] ?? 0);\n break;\n \n case 'PLD':\n this._registers.value['direct'] = this._registers.stack.popUInt16();\n break;\n \n case 'PHK':\n this._registers.stack.push((this._blockReader._romDataReader.position >> 16) | 0x80);\n break;\n \n case 'PHB':\n this._registers.stack.push(this._registers.value['dataBank'] ?? 0x81);\n break;\n \n case 'PLB':\n this._registers.value['dataBank'] = this._registers.stack.popByte();\n break;\n \n case 'PHP':\n this._registers.stack.push(this._registers.value['statusFlags'] ?? 0);\n break;\n \n case 'PLP':\n this._registers.value['statusFlags'] = this._registers.stack.popByte();\n break;\n\n case 'PHA':\n this.handleAccumulatorPush();\n break;\n\n case 'PLA':\n this.handleAccumulatorPull();\n break;\n\n case 'PHX':\n this.handleXIndexPush();\n break;\n\n case 'PLX':\n this.handleXIndexPull();\n break;\n\n case 'PHY':\n this.handleYIndexPush();\n break;\n\n case 'PLY':\n this.handleYIndexPull();\n break;\n\n case 'XBA':\n this.handleExchangeBytes();\n break;\n }\n }\n\n private handleAccumulatorPush(): void {\n if (this._registers.value['statusFlags'] & StatusFlags.AccumulatorMode) {\n this._registers.stack.push(this._registers.value['accumulator'] ?? 0);\n } else {\n this._registers.stack.pushUInt16(this._registers.value['accumulator'] ?? 0);\n }\n }\n\n private handleAccumulatorPull(): void {\n if (this._registers.value['statusFlags'] & StatusFlags.AccumulatorMode) {\n this._registers.value['accumulator'] = ((this._registers.value['accumulator'] ?? 0) & 0xFF00) | this._registers.stack.popByte();\n } else {\n this._registers.value['accumulator'] = this._registers.stack.popUInt16();\n }\n }\n\n private handleXIndexPush(): void {\n if (this._registers.value['statusFlags'] & StatusFlags.IndexMode) {\n this._registers.stack.push((this._registers.value['xIndex'] ?? 0) & 0xFF);\n } else {\n this._registers.stack.pushUInt16(this._registers.value['xIndex'] ?? 0);\n }\n }\n\n private handleXIndexPull(): void {\n if (this._registers.value['statusFlags'] & StatusFlags.IndexMode) {\n this._registers.value['xIndex'] = ((this._registers.value['xIndex'] ?? 0) & 0xFF00) | this._registers.stack.popByte();\n } else {\n this._registers.value['xIndex'] = this._registers.stack.popUInt16();\n }\n }\n\n private handleYIndexPush(): void {\n if (this._registers.value['statusFlags'] & StatusFlags.IndexMode) {\n this._registers.stack.push((this._registers.value['yIndex'] ?? 0) & 0xFF);\n } else {\n this._registers.stack.pushUInt16(this._registers.value['yIndex'] ?? 0);\n }\n }\n\n private handleYIndexPull(): void {\n if (this._registers.value['statusFlags'] & StatusFlags.IndexMode) {\n this._registers.value['yIndex'] = ((this._registers.value['yIndex'] ?? 0) & 0xFF00) | this._registers.stack.popByte();\n } else {\n this._registers.value['yIndex'] = this._registers.stack.popUInt16();\n }\n }\n\n private handleExchangeBytes(): void {\n const acc = this._registers.value['accumulator'] ?? 0;\n this._registers.value['accumulator'] = ((acc >> 8) | (acc << 8)) & 0xFFFF;\n }\n} ","import { RomDataReader } from './reader';\r\nimport {\r\n Address,\r\n AddressType,\r\n AddressSpace,\r\n LocationWrapper,\r\n MemberType,\r\n Byte,\r\n Word,\r\n} from '../../types';\r\nimport type { CopDef } from '../../database';\r\nimport type { BlockReader } from './blocks';\r\n\r\n/**\r\n * Handles COP (Coprocessor) command processing\r\n * Converted from GaiaLib/Rom/Extraction/CopCommandProcessor.cs\r\n */\r\nexport class CopCommandProcessor {\r\n private readonly _blockReader: BlockReader;\r\n private readonly _romDataReader: RomDataReader;\r\n\r\n constructor(blockReader: BlockReader) {\r\n this._blockReader = blockReader;\r\n this._romDataReader = blockReader._romDataReader;\r\n }\r\n\r\n /**\r\n * Parses a COP command based on its definition\r\n */\r\n public parseCopCommand(copDef: CopDef, operands: unknown[]): void {\r\n for (let partStr of copDef.parts) {\r\n let bank : number | null = null;\r\n\r\n //Trim the end for bank hints\r\n const bankHintIx = partStr.indexOf('$')\r\n if(bankHintIx > 0) {\r\n bank = parseInt(partStr.substring(bankHintIx + 1), 16);\r\n partStr = partStr.substring(0, bankHintIx);\r\n }\r\n\r\n // Use the first character to determine the address type (for pointers)\r\n const addrType = Address.typeFromCode(partStr[0]);\r\n const isPtr = addrType !== AddressType.Unknown;\r\n \r\n // Reference type is the target of a pointer from partStr, or the struct type if not a pointer\r\n const referenceType = isPtr ? partStr.substring(1) : this._blockReader._currentAsmBlock!.structName ?? 'Binary';\r\n \r\n // Member type resolves to the underlying pointer type, or partStr\r\n const memberTypeName = isPtr ? addrType.toString() : partStr;\r\n\r\n // Resolve member type name to a MemberType enum\r\n const memberType = this.tryParseMemberType(memberTypeName);\r\n if (memberType === null) {\r\n throw new Error('Cannot use structs in cop def'); // Only basic types are allowed in COP definitions\r\n }\r\n\r\n // If there is a label, ignore reading and use the label instead\r\n const label = this._blockReader._root.labels[this._romDataReader.position];\r\n if (label) {\r\n this._romDataReader.position += this.getMemberTypeSize(memberType);\r\n operands.push(label);\r\n } else {\r\n operands.push(this.readMemberTypeValue(memberType, partStr, isPtr, referenceType, addrType, bank));\r\n }\r\n\r\n }\r\n }\r\n\r\n private tryParseMemberType(memberTypeName: string): MemberType | null {\r\n // Check if the string matches any MemberType enum value (case-insensitive)\r\n const upperName = memberTypeName.toUpperCase();\r\n for (const [key, value] of Object.entries(MemberType)) {\r\n if (key.toUpperCase() === upperName) {\r\n return value;\r\n }\r\n }\r\n return null;\r\n }\r\n\r\n private getMemberTypeSize(memberType: MemberType): number {\r\n switch (memberType) {\r\n case MemberType.Byte:\r\n return 1;\r\n case MemberType.Word:\r\n case MemberType.Offset:\r\n return 2;\r\n case MemberType.Address:\r\n return 3;\r\n default:\r\n throw new Error('Unsupported COP member type');\r\n }\r\n }\r\n\r\n private readMemberTypeValue(\r\n memberType: MemberType,\r\n partStr: string,\r\n isPtr: boolean,\r\n referenceType: string,\r\n addrType: AddressType,\r\n bank: number | null\r\n ): unknown {\r\n switch (memberType) {\r\n case MemberType.Byte:\r\n return new Byte(this._romDataReader.readByte());\r\n case MemberType.Word:\r\n return new Word(this._romDataReader.readUShort());\r\n case MemberType.Offset:\r\n return this.createCopLocation(this._romDataReader.readUShort(), bank, partStr, isPtr, referenceType, addrType);\r\n case MemberType.Address:\r\n return this.createCopLocation(this._romDataReader.readUShort(), this._romDataReader.readByte(), partStr, isPtr, referenceType, addrType);\r\n default:\r\n throw new Error('Unsupported COP member type');\r\n }\r\n }\r\n\r\n private createCopLocation(\r\n offset: number, \r\n bank: number | null, \r\n partStr: string, \r\n isPtr: boolean, \r\n otherStr: string, \r\n type: AddressType\r\n ): unknown {\r\n if (bank === null && offset === 0) {\r\n return new Word(offset);\r\n }\r\n\r\n const resolvedBank = bank ?? Address.resolveBank(this._romDataReader.position, this._blockReader._root.config.memoryMode);\r\n\r\n const addr = new Address(resolvedBank, offset, this._blockReader._root.config.memoryMode);\r\n if (addr.isROM) {\r\n const location = addr.toLocation();\r\n if (partStr !== 'Address' && isPtr && !this._blockReader._root.rewrites[location]) {\r\n this._blockReader.noteType(location, otherStr, true);\r\n }\r\n\r\n // When address is unknown, try to use the part string (for Offset or Address)\r\n if (type === AddressType.Unknown) {\r\n type = this.tryParseAddressType(partStr) ?? AddressType.Unknown;\r\n }\r\n\r\n return new LocationWrapper(location, type);\r\n }\r\n return addr;\r\n }\r\n\r\n private tryParseAddressType(addressTypeName: string): AddressType | null {\r\n // Check if the string matches any AddressType enum value (case-insensitive)\r\n const upperName = addressTypeName.toUpperCase();\r\n for (const [key, value] of Object.entries(AddressType)) {\r\n if (key.toUpperCase() === upperName) {\r\n return value;\r\n }\r\n }\r\n return null;\r\n }\r\n} ","import { Registers } from '../../assembly';\r\nimport {\r\n AddressType,\r\n AddressSpace,\r\n Address,\r\n LocationWrapper,\r\n StatusFlags,\r\n Byte,\r\n Word,\r\n} from '../../types';\r\nimport { RomDataReader } from './reader';\r\nimport { StackOperations } from './stack';\r\nimport { TransformProcessor } from './transforms';\r\nimport { CopCommandProcessor } from './cop';\r\nimport type { DbRoot, CopDef, OpCode } from '../../database';\r\nimport type { BlockReader } from './blocks';\r\n\r\n/**\r\n * Context information for an operation being processed\r\n * Converted from GaiaLib/Rom/Extraction/AsmReader.cs OperationContext\r\n */\r\nexport class OperationContext {\r\n public size: number = 0;\r\n public nextAddress: number = 0;\r\n public xForm1: string | null = null;\r\n public xForm2: string | null = null;\r\n public copDef: CopDef | null = null;\r\n}\r\n\r\n/**\r\n * Handles different addressing modes for assembly instructions\r\n * Converted from GaiaLib/Rom/Extraction/AddressingModeHandler.cs\r\n */\r\nexport class AddressingModeHandler {\r\n private readonly _blockReader: BlockReader;\r\n private readonly _transformProcessor: TransformProcessor;\r\n private readonly _copProcessor: CopCommandProcessor;\r\n private readonly _dataReader: RomDataReader;\r\n\r\n constructor(blockReader: BlockReader, transformProcessor: TransformProcessor) {\r\n this._blockReader = blockReader;\r\n this._transformProcessor = transformProcessor;\r\n this._copProcessor = new CopCommandProcessor(blockReader);\r\n this._dataReader = blockReader._romDataReader;\r\n }\r\n\r\n public processAddressingMode(code: OpCode, context: OperationContext, reg: Registers): unknown[] {\r\n const operands: unknown[] = [];\r\n\r\n switch (code.mode) {\r\n case 'Stack':\r\n case 'Implied':\r\n case 'Accumulator':\r\n this.handleStackOrImpliedMode(code.mnem, reg);\r\n break;\r\n\r\n case 'Immediate':\r\n this.handleImmediateMode(code.mnem, context.size, operands, reg);\r\n break;\r\n\r\n case 'AbsoluteIndexedIndirect':\r\n this.handleAbsoluteMode(code.mnem, undefined, context.nextAddress, reg.value['dataBank'], operands, reg, true);\r\n break;\r\n\r\n case 'AbsoluteIndirect':\r\n case 'AbsoluteIndirectLong':\r\n case 'Absolute':\r\n case 'AbsoluteIndexedX':\r\n case 'AbsoluteIndexedY':\r\n this.handleAbsoluteMode(code.mnem, undefined, context.nextAddress, reg.value['dataBank'], operands, reg);\r\n break;\r\n\r\n case 'AbsoluteLong':\r\n case 'AbsoluteLongIndexedX':\r\n this.handleAbsoluteLongMode(code.mnem, operands, reg);\r\n break;\r\n\r\n case 'BlockMove':\r\n this.handleBlockMoveMode(operands, context);\r\n break;\r\n\r\n case 'DirectPage':\r\n case 'DirectPageIndexedIndirectX':\r\n case 'DirectPageIndexedX':\r\n case 'DirectPageIndexedY':\r\n case 'DirectPageIndirect':\r\n case 'DirectPageIndirectIndexedY':\r\n case 'DirectPageIndirectLong':\r\n case 'DirectPageIndirectLongIndexedY':\r\n this.handleDirectPageMode(operands);\r\n break;\r\n\r\n case 'PCRelative':\r\n this.handlePCRelativeMode(operands, context.nextAddress, reg, false);\r\n break;\r\n\r\n case 'PCRelativeLong':\r\n this.handlePCRelativeMode(operands, context.nextAddress, reg, true);\r\n break;\r\n\r\n case 'StackRelative':\r\n case 'StackRelativeIndirectIndexedY':\r\n this.handleStackRelativeMode(operands);\r\n break;\r\n\r\n case 'StackInterrupt':\r\n this.handleStackInterruptMode(code.mnem, operands, context);\r\n break;\r\n\r\n default:\r\n throw new Error(`Unknown addressing mode: ${code}`);\r\n }\r\n\r\n return operands;\r\n }\r\n\r\n private handleImmediateMode(mnemonic: string, size: number, operands: unknown[], reg: Registers): void {\r\n const operand = this.readImmediateOperand(size);\r\n operands.push(operand);\r\n this.updateRegisterForImmediateInstruction(mnemonic, operand, reg);\r\n }\r\n\r\n private readImmediateOperand(size: number) {\r\n return size === 3\r\n ? new Word(this._dataReader.readUShort())\r\n : new Byte(this._dataReader.readByte());\r\n }\r\n\r\n private updateRegisterForImmediateInstruction(\r\n mnemonic: string,\r\n operand: number | { value: number },\r\n reg: Registers\r\n ): void {\r\n const value = typeof operand === 'number' ? operand : operand.value;\r\n switch (mnemonic) {\r\n case 'LDA':\r\n reg.value['accumulator'] = this.calculateRegisterValue(reg.value['accumulator'], (reg.value['statusFlags'] & StatusFlags.AccumulatorMode) === StatusFlags.AccumulatorMode, value);\r\n break;\r\n\r\n case 'LDX':\r\n reg.value['xIndex'] = this.calculateRegisterValue(reg.value['xIndex'], (reg.value['statusFlags'] & StatusFlags.IndexMode) === StatusFlags.IndexMode, value);\r\n break;\r\n\r\n case 'LDY':\r\n reg.value['yIndex'] = this.calculateRegisterValue(reg.value['yIndex'], (reg.value['statusFlags'] & StatusFlags.IndexMode) === StatusFlags.IndexMode, value);\r\n break;\r\n\r\n case 'SEP':\r\n case 'REP':\r\n let statusFlags = reg.value['statusFlags'] ?? 0;\r\n if (mnemonic === 'SEP') {\r\n statusFlags |= value;\r\n } else {\r\n statusFlags &= ~value;\r\n }\r\n reg.value['statusFlags'] = statusFlags;\r\n break;\r\n }\r\n }\r\n\r\n private calculateRegisterValue(currentValue: number | undefined, flag: boolean, operand: number): number {\r\n if (flag) {\r\n // 16-bit mode: use full operand value\r\n return operand;\r\n } else {\r\n // 8-bit mode: preserve high byte\r\n return ((currentValue ?? 0) & 0xFF00) | (operand & 0xFF);\r\n }\r\n }\r\n\r\n private handleAbsoluteLongMode(mnemonic: string, operands: unknown[], reg: Registers): void {\r\n const refLoc = this._dataReader.readUShort();\r\n const bank = this._dataReader.readByte();\r\n const address = new Address(bank, refLoc, reg.mode);\r\n\r\n if (address.isROM) {\r\n const wrapper = new LocationWrapper(address.toLocation(), AddressType.Address);\r\n if (this.isJumpInstruction(mnemonic)) {\r\n this._blockReader.noteType(wrapper.location, 'Code', false, reg);\r\n }\r\n operands.push(wrapper);\r\n } else {\r\n operands.push(address);\r\n }\r\n }\r\n\r\n private handleBlockMoveMode(operands: unknown[], context: OperationContext): void {\r\n operands.push(new Byte(this._dataReader.readByte()));\r\n context.xForm2 = this._transformProcessor.getTransform();\r\n operands.push(new Byte(this._dataReader.readByte()));\r\n }\r\n\r\n private handleDirectPageMode(operands: unknown[]): void {\r\n operands.push(new Byte(this._dataReader.readByte()));\r\n }\r\n\r\n private handlePCRelativeMode(operands: unknown[], nextAddress: number, reg: Registers, isLong: boolean): void {\r\n const relative = isLong\r\n ? nextAddress + this._dataReader.readShort()\r\n : nextAddress + this._dataReader.readSByte();\r\n\r\n //this._blockReader.noteType(relative, 'Code', false, reg);\r\n this._blockReader.updateRegisterState(relative, reg);\r\n operands.push(new LocationWrapper(relative, isLong ? AddressType.WRelative : AddressType.Relative));\r\n }\r\n\r\n private handleStackRelativeMode(operands: unknown[]): void {\r\n operands.push(new Byte(this._dataReader.readByte()));\r\n }\r\n\r\n private handleStackInterruptMode(mnemonic: string, operands: unknown[], context: OperationContext): void {\r\n const cmd = this._dataReader.readByte();\r\n operands.push(new Byte(cmd));\r\n\r\n if (mnemonic === 'COP') {\r\n const copDef = this._blockReader._root.copDef[cmd];\r\n if (!copDef) {\r\n //throw new Error('Unknown COP command');\r\n return;\r\n }\r\n\r\n context.copDef = copDef;\r\n this._copProcessor.parseCopCommand(copDef, operands);\r\n }\r\n }\r\n\r\n private handleStackOrImpliedMode(mnemonic: string, reg: Registers): void {\r\n const stackOperations = new StackOperations(reg, this._blockReader);\r\n stackOperations.handleStackOperation(mnemonic);\r\n }\r\n\r\n private handleAbsoluteMode(\r\n mnemonic: string,\r\n xBank1: number | undefined,\r\n next: number,\r\n dataBank: number | undefined,\r\n operands: unknown[],\r\n registers: Registers,\r\n isIndexedIndirect: boolean = false\r\n ): void {\r\n let refLoc = this._dataReader.readUShort();\r\n\r\n const isPush = this.isPushInstruction(mnemonic);\r\n if (isPush) {\r\n refLoc++;\r\n }\r\n\r\n const isJump = isPush || isIndexedIndirect || this.isJumpInstruction(mnemonic);\r\n const resolvedBank = xBank1 ?? (isJump ? Address.resolveBank(this._dataReader.position, registers.mode) : dataBank) ?? 0x81;\r\n\r\n const addr = new Address(resolvedBank, refLoc, registers.mode);\r\n if (addr.isROM) {\r\n const wrapper = new LocationWrapper(addr.toLocation(), AddressType.Offset);\r\n if (isJump) {\r\n const type = isIndexedIndirect ? '&Code' : 'Code';\r\n const name = this._blockReader.noteType(wrapper.location, type, isPush, registers);\r\n\r\n if (isPush) {\r\n operands.push(`&${name}-1`);\r\n return;\r\n }\r\n }\r\n operands.push(wrapper);\r\n } else {\r\n operands.push(addr);\r\n }\r\n }\r\n\r\n private isJumpInstruction(mnemonic: string): boolean {\r\n return mnemonic[0] === 'J';\r\n }\r\n\r\n private isPushInstruction(mnemonic: string): boolean {\r\n return mnemonic[0] === 'P';\r\n }\r\n} ","import { RomDataReader } from './reader';\r\nimport { ReferenceManager } from './references';\r\nimport { RomProcessingConstants } from '../../types/constants';\r\nimport type { BlockReader } from './blocks';\r\nimport { Address, AddressType } from '../../types/addressing';\r\nimport { LocationWrapper } from '../..';\r\n\r\n/**\r\n * Handles transform processing for assembly instructions\r\n * Converted from GaiaLib/Rom/Extraction/TransformProcessor.cs\r\n */\r\nexport class TransformProcessor {\r\n private readonly _blockReader: BlockReader;\r\n private readonly _romDataReader: RomDataReader;\r\n private readonly _referenceManager: ReferenceManager;\r\n private readonly _labelLookup: Record<number, string>;\r\n\r\n // Location regex pattern: _([A-Fa-f0-9]{6})\r\n private static readonly LOCATION_REGEX = /_([A-Fa-f0-9]{6})/;\r\n\r\n constructor(romReader: BlockReader) {\r\n this._blockReader = romReader;\r\n this._romDataReader = romReader._romDataReader;\r\n this._referenceManager = romReader._referenceManager;\r\n this._labelLookup = romReader._root.labels;\r\n }\r\n\r\n /**\r\n * Retrieves transform information for the current ROM position\r\n */\r\n public getTransform(): string | null {\r\n const transform = this._labelLookup[this._romDataReader.position];\r\n if (transform === '') {\r\n return transform;\r\n } else if (!transform) {\r\n return null;\r\n }\r\n\r\n const transformName = this.cleanTransformName(transform);\r\n const referenceLocation = this.resolveTransformReference(transformName);\r\n \r\n if (referenceLocation !== null) {\r\n this._blockReader.resolveInclude(referenceLocation, false);\r\n }\r\n\r\n return transform;\r\n }\r\n\r\n /**\r\n * Applies transforms to operands\r\n */\r\n public applyTransforms(op1Label: string | null, op2Label: string | null, operands: unknown[]): void {\r\n this.applyTransform(op1Label, 0, operands);\r\n this.applyTransform(op2Label, 1, operands);\r\n }\r\n\r\n private applyTransform(transform: string | null, operandIndex: number, operands: unknown[]): void {\r\n if (transform === null || transform === undefined || operandIndex >= operands.length) {\r\n return;\r\n }\r\n\r\n // There is special logic for empty labels\r\n const hasBank = transform.startsWith('$');\r\n if (transform === '' || hasBank) {\r\n this.applyDefaultTransform(operandIndex, operands, hasBank ? parseInt(transform.substring(1), 16) : undefined);\r\n } else {\r\n operands[operandIndex] = transform; // Otherwise it is a direct replacement\r\n }\r\n }\r\n\r\n private applyDefaultTransform(operandIndex: number, operands: unknown[], bank?: number): void {\r\n const opnd = operands[operandIndex] as any;\r\n const resolvedBank = bank ?? Address.resolveBank(this._romDataReader.position, this._blockReader._root.config.memoryMode);\r\n const offset = opnd && 'value' in opnd ? opnd['value'] : opnd as number;\r\n const adrs = new Address(resolvedBank, offset, this._blockReader._root.config.memoryMode);\r\n const loc = adrs.toLocation();\r\n\r\n operands[operandIndex] = new LocationWrapper(loc, AddressType.Offset);\r\n return;\r\n\r\n // const nameResult = this._referenceManager.tryGetName(loc);\r\n // let referenceName: string;\r\n \r\n // if (!nameResult.found) {\r\n // referenceName = `loc_${loc.toString(16).toUpperCase().padStart(6, '0')}`;\r\n // this._referenceManager.tryAddName(loc, referenceName);\r\n // } else {\r\n // referenceName = nameResult.referenceName!;\r\n // }\r\n \r\n // this._blockReader.resolveInclude(loc, false);\r\n // operands[operandIndex] = `&${referenceName}`;\r\n }\r\n\r\n private cleanTransformName(transform: string): string {\r\n let name = transform;\r\n \r\n // Remove address space characters from the start\r\n while (name.length > 0 && RomProcessingConstants.ADDRESS_SPACE.includes(name[0])) {\r\n name = name.substring(1);\r\n }\r\n \r\n // Find math operators and truncate at that point\r\n let mathIndex = -1;\r\n for (let i = 0; i < name.length; i++) {\r\n if (RomProcessingConstants.OPERATORS.includes(name[i])) {\r\n mathIndex = i;\r\n break;\r\n }\r\n }\r\n \r\n if (mathIndex > 0) {\r\n name = name.substring(0, mathIndex);\r\n }\r\n \r\n return name;\r\n }\r\n\r\n private resolveTransformReference(transformName: string): number | null {\r\n // Directly resolve by name in the reference table\r\n const location = this._referenceManager.findLocationByName(transformName);\r\n if (location !== undefined) {\r\n return location;\r\n }\r\n\r\n // Fallback to parsing the location pattern\r\n const match = TransformProcessor.LOCATION_REGEX.exec(transformName);\r\n return match ? parseInt(match[1], 16) : null;\r\n }\r\n}","/**\r\n * Universal file reading utilities\r\n * Works in both Node.js and browser environments\r\n */\r\n\r\n// Platform detection\r\nconst isNode = typeof process !== 'undefined' && process.versions?.node;\r\n// const isBrowser = typeof globalThis !== 'undefined' && 'window' in globalThis;\r\n\r\nexport interface FileReadOptions {\r\n encoding?: 'utf8' | 'binary';\r\n}\r\n\r\n/**\r\n * Read a file as text\r\n * @param path File path or URL\r\n * @param options Read options\r\n * @returns Promise<string>\r\n */\r\nexport async function readFileAsText(path: string, options: FileReadOptions = {}): Promise<string> {\r\n const { encoding = 'utf8' } = options;\r\n \r\n if (isNode) {\r\n // Node.js environment\r\n const { readFile } = await import('fs/promises');\r\n const pathModule = await import('path');\r\n \r\n const fullPath = pathModule.resolve(path);\r\n \r\n try {\r\n let text = await readFile(fullPath, { encoding });\r\n \r\n // Strip UTF-8 BOM if present\r\n if (text.charCodeAt(0) === 0xFEFF) {\r\n text = text.slice(1);\r\n }\r\n \r\n return text;\r\n } catch (error: any) {\r\n if (error.code === 'ENOENT') {\r\n throw new Error(`File not found: ${fullPath}`);\r\n }\r\n throw error;\r\n }\r\n } else {\r\n // Browser environment\r\n const response = await fetch(path);\r\n if (!response.ok) {\r\n throw new Error(`Failed to fetch file: ${path} (${response.status})`);\r\n }\r\n \r\n let text = await response.text();\r\n \r\n // Strip UTF-8 BOM if present\r\n if (text.charCodeAt(0) === 0xFEFF) {\r\n text = text.slice(1);\r\n }\r\n \r\n return text;\r\n }\r\n}\r\n\r\n/**\r\n * Read a file as binary data (Uint8Array)\r\n * @param path File path or URL\r\n * @returns Promise<Uint8Array>\r\n */\r\nexport async function readFileAsBinary(path: string): Promise<Uint8Array> {\r\n if (isNode) {\r\n // Node.js environment\r\n const { readFile } = await import('fs/promises');\r\n const pathModule = await import('path');\r\n \r\n const fullPath = pathModule.resolve(path);\r\n\r\n try {\r\n const buffer = await readFile(fullPath);\r\n return new Uint8Array(buffer);\r\n } catch (error: any) {\r\n if (error.code === 'ENOENT') {\r\n throw new Error(`File not found: ${fullPath}`);\r\n }\r\n throw error;\r\n }\r\n } else {\r\n // Browser environment\r\n const response = await fetch(path);\r\n if (!response.ok) {\r\n throw new Error(`Failed to fetch file: ${path} (${response.status})`);\r\n }\r\n \r\n const arrayBuffer = await response.arrayBuffer();\r\n return new Uint8Array(arrayBuffer);\r\n }\r\n}\r\n\r\n/**\r\n * Read a JSON file and parse it\r\n * @param path File path or URL\r\n * @returns Promise<any>\r\n */\r\nexport async function readJsonFile<T = any>(path: string): Promise<T> {\r\n const text = await readFileAsText(path);\r\n return JSON.parse(text) as T;\r\n}\r\n\r\n/**\r\n * Check if a file exists\r\n * @param path File path\r\n * @returns Promise<boolean>\r\n */\r\nexport async function fileExists(path: string): Promise<boolean> {\r\n if (isNode) {\r\n // Node.js environment\r\n const { access } = await import('fs/promises');\r\n const pathModule = await import('path');\r\n \r\n const fullPath = pathModule.resolve(path);\r\n try {\r\n await access(fullPath);\r\n return true;\r\n } catch {\r\n return false;\r\n }\r\n } else {\r\n // Browser environment - try to fetch and check if successful\r\n try {\r\n const response = await fetch(path, { method: 'HEAD' });\r\n return response.ok;\r\n } catch {\r\n return false;\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Get the directory path containing a file\r\n * @param filePath File path\r\n * @returns string\r\n */\r\nexport async function getDirectory(filePath: string): Promise<string> {\r\n if (isNode) {\r\n // Node.js environment\r\n const path = await import('path');\r\n return path.dirname(path.resolve(filePath));\r\n } else {\r\n // Browser environment\r\n const url = new URL(filePath, (globalThis as any).location.href);\r\n return url.pathname.split('/').slice(0, -1).join('/') || './';\r\n }\r\n}\r\n\r\n/**\r\n * Create a temporary directory.\r\n * This is a Node.js-specific operation.\r\n * @param prefix Prefix for the temporary directory name.\r\n * @returns Promise<string> Path to the created temporary directory.\r\n */\r\nexport async function createTempDirectory(prefix: string): Promise<string> {\r\n if (isNode) {\r\n const { mkdtemp } = await import('fs/promises');\r\n const { tmpdir } = await import('os');\r\n const { join } = await import('path');\r\n return mkdtemp(join(tmpdir(), prefix));\r\n } else {\r\n throw new Error('createTempDirectory is not supported in the browser environment.');\r\n }\r\n}\r\n\r\n/**\r\n * Remove a directory recursively.\r\n * This is a Node.js-specific operation.\r\n * @param dirPath Path to the directory to remove.\r\n * @returns Promise<void>\r\n */\r\nexport async function removeDirectory(dirPath: string): Promise<void> {\r\n if (isNode) {\r\n const { rm } = await import('fs/promises');\r\n return rm(dirPath, { recursive: true, force: true });\r\n } else {\r\n throw new Error('removeDirectory is not supported in the browser environment.');\r\n }\r\n}\r\n\r\nexport interface DirectoryEntry {\r\n name: string;\r\n path: string;\r\n extension: string | null;\r\n isDirectory: boolean;\r\n isFile: boolean;\r\n}\r\n\r\n/**\r\n * List directory contents\r\n * This is a Node.js-specific operation.\r\n * @param dirPath Path to the directory to list\r\n * @param options Options for filtering and recursion\r\n * @returns Promise<DirectoryEntry[]>\r\n */\r\nexport async function listDirectory(\r\n dirPath: string,\r\n options: {\r\n recursive?: boolean;\r\n filter?: (entry: DirectoryEntry) => boolean;\r\n extension?: string;\r\n } = {}\r\n): Promise<DirectoryEntry[]> {\r\n if (isNode) {\r\n const { readdir, stat } = await import('fs/promises');\r\n const pathModule = await import('path');\r\n\r\n const { recursive = false, filter, extension } = options;\r\n const fullPath = pathModule.resolve(dirPath);\r\n\r\n try {\r\n const entries: DirectoryEntry[] = [];\r\n const items = await readdir(fullPath);\r\n\r\n for (const item of items) {\r\n const itemPath = pathModule.join(fullPath, item);\r\n const stats = await stat(itemPath);\r\n const isFile = stats.isFile();\r\n const extIx = isFile ? item.indexOf('.') : -1;\r\n const ext = extIx > 0 ? item.substring(extIx + 1) : null;\r\n const name = extIx > 0 ? item.substring(0, extIx) : item;\r\n\r\n const entry: DirectoryEntry = {\r\n name: name,\r\n path: itemPath,\r\n extension: ext,\r\n isFile: isFile,\r\n isDirectory: stats.isDirectory()\r\n };\r\n\r\n // Apply extension filter\r\n if (extension && ext !== extension) {\r\n continue;\r\n }\r\n\r\n // Apply custom filter\r\n if (filter && !filter(entry)) {\r\n continue;\r\n }\r\n\r\n entries.push(entry);\r\n\r\n // Recurse into subdirectories if requested\r\n if (recursive && entry.isDirectory) {\r\n const subEntries = await listDirectory(itemPath, options);\r\n entries.push(...subEntries);\r\n }\r\n }\r\n\r\n return entries;\r\n } catch (error: any) {\r\n if (error.code === 'ENOENT') {\r\n throw new Error(`Directory not found: ${fullPath}`);\r\n }\r\n throw error;\r\n }\r\n } else {\r\n throw new Error('listDirectory is not supported in the browser environment.');\r\n }\r\n}\r\n\r\n/**\r\n * Save text content to a file\r\n * This is a Node.js-specific operation.\r\n * @param path File path where to save the content\r\n * @param text Text content to save\r\n * @returns Promise<void>\r\n */\r\nexport async function saveFileAsText(path: string, text: string): Promise<void> {\r\n if (isNode) {\r\n const { writeFile, mkdir } = await import('fs/promises');\r\n const pathModule = await import('path');\r\n\r\n const fullPath = pathModule.resolve(path);\r\n const dirPath = pathModule.dirname(fullPath);\r\n\r\n try {\r\n // Ensure parent directories exist\r\n await mkdir(dirPath, { recursive: true });\r\n\r\n // Write the file with UTF-8 encoding\r\n await writeFile(fullPath, text, { encoding: 'utf8' });\r\n } catch (error: any) {\r\n throw new Error(`Failed to save file: ${fullPath} - ${error.message}`);\r\n }\r\n } else {\r\n throw new Error('saveFileAsText is not supported in the browser environment.');\r\n }\r\n}\r\n\r\n/**\r\n * Save binary data to a file\r\n * This is a Node.js-specific operation.\r\n * @param path File path where to save the data\r\n * @param data Binary data as Uint8Array to save\r\n * @returns Promise<void>\r\n */\r\nexport async function saveFileAsBinary(path: string, data: Uint8Array): Promise<void> {\r\n if (isNode) {\r\n const { writeFile, mkdir } = await import('fs/promises');\r\n const pathModule = await import('path');\r\n\r\n const fullPath = pathModule.resolve(path);\r\n const dirPath = pathModule.dirname(fullPath);\r\n\r\n try {\r\n // Ensure parent directories exist\r\n await mkdir(dirPath, { recursive: true });\r\n\r\n // Write the binary data directly\r\n await writeFile(fullPath, data);\r\n } catch (error: any) {\r\n throw new Error(`Failed to save file: ${fullPath} - ${error.message}`);\r\n }\r\n } else {\r\n throw new Error('saveFileAsBinary is not supported in the browser environment.');\r\n }\r\n}","\r\nconst polynomial = 0x04C11DB7;\r\n\r\nfunction crc32_reverse(polynomial: number) {\r\n var reversedPolynomial = 0\r\n\r\n for (let i = 0; i < 32; i++) {\r\n reversedPolynomial = reversedPolynomial << 1\r\n reversedPolynomial = reversedPolynomial | ((polynomial >>> i) & 1)\r\n }\r\n\r\n return reversedPolynomial\r\n}\r\n\r\nconst reversedPolynomial = crc32_reverse(polynomial);\r\n\r\nfunction crc32_generate() {\r\n var table = new Array()\r\n var i, j, n\r\n\r\n for (i = 0; i < 256; i++) {\r\n n = i\r\n for (j = 8; j > 0; j--) {\r\n if ((n & 1) == 1) {\r\n n = (n >>> 1) ^ reversedPolynomial\r\n } else {\r\n n = n >>> 1\r\n }\r\n }\r\n table[i] = n\r\n }\r\n\r\n return table\r\n}\r\n\r\nfunction crc32_initial() {\r\n return 0xFFFFFFFF\r\n}\r\n\r\nfunction crc32_add_byte(table: number[], crc: number, byte: number) {\r\n crc = (crc >>> 8) ^ table[(byte) ^ (crc & 0x000000FF)]\r\n return crc\r\n}\r\n\r\nfunction crc32_final(crc: number) {\r\n crc = ~crc\r\n crc = (crc < 0) ? (0xFFFFFFFF + crc + 1) : crc\r\n return crc & 0xFFFFFFFF;\r\n}\r\n\r\n// Deprecated\r\n// export function crc32_string(str: string) {\r\n// var table = crc32_generate()\r\n// var crc = crc32_initial()\r\n\r\n// for (let i = 0; i < str.length; i++)\r\n// crc = crc32_add_byte(table, crc, str.charCodeAt(i))\r\n\r\n// crc = crc32_final(crc)\r\n// return crc\r\n// }\r\n\r\nexport function crc32_buffer(data: Uint8Array) {\r\n var table = crc32_generate()\r\n var crc = crc32_initial()\r\n\r\n for (let i = 0; i < data.length; i++)\r\n crc = crc32_add_byte(table, crc, data[i])\r\n\r\n crc = crc32_final(crc)\r\n return crc\r\n}\r\n\r\nexport function crc32_text_utf8(text: string): number {\r\n const utf8Bytes = new TextEncoder().encode(text);\r\n return crc32_buffer(utf8Bytes);\r\n}\r\n\r\nexport function crc32_text_utf16(text: string): number {\r\n const utf16Bytes = new Uint8Array(text.length * 2);\r\n for (let i = 0; i < text.length; i++) {\r\n const code = text.charCodeAt(i);\r\n utf16Bytes[i * 2] = code & 0xFF;\r\n utf16Bytes[i * 2 + 1] = (code >> 8) & 0xFF;\r\n }\r\n return crc32_buffer(utf16Bytes);\r\n}\r\n","/**\n * Base64 encoding and decoding utilities for Uint8Arrays\n * Works in both Node.js and browser environments\n */\n\n// Platform detection\nconst isNode = typeof process !== 'undefined' && process.versions?.node;\n\n// Base64 character set\nconst BASE64_CHARS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';\n\n// Create lookup table for decoding\nconst BASE64_LOOKUP: { [key: string]: number } = {};\nfor (let i = 0; i < BASE64_CHARS.length; i++) {\n BASE64_LOOKUP[BASE64_CHARS[i]] = i;\n}\n\n/**\n * Custom base64 encoding implementation that handles large data without call stack overflow\n * @param data The binary data to encode\n * @returns Base64 encoded string\n */\nfunction customBase64Encode(data: Uint8Array): string {\n let result = '';\n let i = 0;\n\n // Process 3 bytes at a time\n while (i < data.length) {\n const byte1 = data[i++];\n const byte2 = i < data.length ? data[i++] : 0;\n const byte3 = i < data.length ? data[i++] : 0;\n\n // Convert 3 bytes to 4 base64 characters\n const bitmap = (byte1 << 16) | (byte2 << 8) | byte3;\n\n result += BASE64_CHARS[(bitmap >> 18) & 63];\n result += BASE64_CHARS[(bitmap >> 12) & 63];\n result += BASE64_CHARS[(bitmap >> 6) & 63];\n result += BASE64_CHARS[bitmap & 63];\n }\n\n // Add padding if necessary\n const padding = data.length % 3;\n if (padding === 1) {\n result = result.slice(0, -2) + '==';\n } else if (padding === 2) {\n result = result.slice(0, -1) + '=';\n }\n\n return result;\n}\n\n/**\n * Custom base64 decoding implementation that handles large data without call stack overflow\n * @param base64String The base64 string to decode\n * @returns Decoded binary data as Uint8Array\n * @throws {Error} If the input contains invalid base64 characters\n */\nfunction customBase64Decode(base64String: string): Uint8Array {\n // Remove padding for calculation\n const cleanString = base64String.replace(/=/g, '');\n const outputLength = Math.floor((cleanString.length * 3) / 4);\n const result = new Uint8Array(outputLength);\n\n let resultIndex = 0;\n let i = 0;\n\n // Process 4 characters at a time\n while (i < cleanString.length) {\n const char1 = cleanString[i++];\n const char2 = i < cleanString.length ? cleanString[i++] : 'A';\n const char3 = i < cleanString.length ? cleanString[i++] : 'A';\n const char4 = i < cleanString.length ? cleanString[i++] : 'A';\n\n // Validate characters\n if (!(char1 in BASE64_LOOKUP) || !(char2 in BASE64_LOOKUP) ||\n !(char3 in BASE64_LOOKUP) || !(char4 in BASE64_LOOKUP)) {\n throw new Error('Invalid base64 character encountered');\n }\n\n // Convert 4 base64 characters to 3 bytes\n const bitmap = (BASE64_LOOKUP[char1] << 18) |\n (BASE64_LOOKUP[char2] << 12) |\n (BASE64_LOOKUP[char3] << 6) |\n BASE64_LOOKUP[char4];\n\n if (resultIndex < result.length) {\n result[resultIndex++] = (bitmap >> 16) & 255;\n }\n if (resultIndex < result.length) {\n result[resultIndex++] = (bitmap >> 8) & 255;\n }\n if (resultIndex < result.length) {\n result[resultIndex++] = bitmap & 255;\n }\n }\n\n return result;\n}\n\n/**\n * Encode a Uint8Array to a base64 string\n * @param data The binary data to encode\n * @returns Base64 encoded string\n */\nexport function encodeBase64(data: Uint8Array): string {\n if (!data || data.length === 0) {\n return '';\n }\n\n if (isNode) {\n // Node.js environment - use Buffer\n return Buffer.from(data).toString('base64');\n } else {\n // Browser environment - custom base64 encoding implementation\n return customBase64Encode(data);\n }\n}\n\n/**\n * Decode a base64 string to a Uint8Array\n * @param base64String The base64 string to decode\n * @returns Decoded binary data as Uint8Array\n * @throws {Error} If the input is not a valid base64 string\n */\nexport function decodeBase64(base64String: string): Uint8Array {\n if (!base64String || base64String.length === 0) {\n return new Uint8Array(0);\n }\n\n // Validate base64 format\n if (!/^[A-Za-z0-9+/]*={0,2}$/.test(base64String)) {\n throw new Error('Invalid base64 string format');\n }\n\n if (isNode) {\n // Node.js environment - use Buffer\n try {\n const buffer = Buffer.from(base64String, 'base64');\n return new Uint8Array(buffer);\n } catch (error) {\n throw new Error(`Failed to decode base64 string: ${error instanceof Error ? error.message : 'Unknown error'}`);\n }\n } else {\n // Browser environment - custom base64 decoding implementation\n try {\n return customBase64Decode(base64String);\n } catch (error) {\n throw new Error(`Failed to decode base64 string: ${error instanceof Error ? error.message : 'Unknown error'}`);\n }\n }\n}\n\n/**\n * Check if a string is valid base64\n * @param str The string to validate\n * @returns True if the string is valid base64, false otherwise\n */\nexport function isValidBase64(str: string): boolean {\n if (typeof str !== 'string') {\n return false;\n }\n\n // Empty string is valid base64\n if (str === '') {\n return true;\n }\n\n // Check format with regex\n if (!/^[A-Za-z0-9+/]*={0,2}$/.test(str)) {\n return false;\n }\n\n // Check length (must be multiple of 4)\n if (str.length % 4 !== 0) {\n return false;\n }\n\n try {\n // Try to decode to verify it's actually valid\n decodeBase64(str);\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Encode a string to base64 (convenience function)\n * @param text The text string to encode\n * @returns Base64 encoded string\n */\nexport function encodeBase64String(text: string): string {\n const encoder = new TextEncoder();\n const data = encoder.encode(text);\n return encodeBase64(data);\n}\n\n/**\n * Decode a base64 string to text (convenience function)\n * @param base64String The base64 string to decode\n * @returns Decoded text string\n * @throws {Error} If the input is not a valid base64 string or doesn't contain valid UTF-8\n */\nexport function decodeBase64String(base64String: string): string {\n const data = decodeBase64(base64String);\n const decoder = new TextDecoder('utf-8', { fatal: true });\n \n try {\n return decoder.decode(data);\n } catch (error) {\n throw new Error(`Failed to decode base64 string as UTF-8 text: ${error instanceof Error ? error.message : 'Unknown error'}`);\n }\n}\n","// Utility functions and helpers\r\n\r\n// File utilities\r\nexport * from './file';\r\nexport * from './crc';\r\nexport * from './base64';\r\n\r\n/**\r\n * Convert bytes to hex string\r\n */\r\nexport function bytesToHex(bytes: Uint8Array): string {\r\n return Array.from(bytes, byte => byte.toString(16).padStart(2, '0')).join('');\r\n}\r\n\r\n/**\r\n * Convert hex string to bytes\r\n */\r\nexport function hexToBytes(hex: string): Uint8Array {\r\n const bytes = new Uint8Array(hex.length / 2);\r\n for (let i = 0; i < hex.length; i += 2) {\r\n bytes[i / 2] = parseInt(hex.substring(i, i + 2), 16);\r\n }\r\n return bytes;\r\n}\r\n\r\n/**\r\n * Clamp a value between min and max\r\n */\r\nexport function clamp(value: number, min: number, max: number): number {\r\n return Math.min(Math.max(value, min), max);\r\n}\r\n\r\n/**\r\n * Convert binary data (Uint8Array) to UTF-8 string representation\r\n *\r\n * This function properly decodes UTF-8 encoded binary data to avoid corruption\r\n * of special characters and multi-byte sequences.\r\n *\r\n * @param binaryData - The binary data as Uint8Array containing UTF-8 encoded text\r\n * @returns The decoded UTF-8 string\r\n * @throws {Error} If the binary data contains invalid UTF-8 sequences\r\n *\r\n * @example\r\n * ```typescript\r\n * const binaryData = new Uint8Array([72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100]);\r\n * const text = binaryToUtf8String(binaryData);\r\n * console.log(text); // \"Hello World\"\r\n *\r\n * // Handle UTF-8 multi-byte characters\r\n * const utf8Data = new Uint8Array([240, 159, 152, 128]); // 😀 emoji\r\n * const emoji = binaryToUtf8String(utf8Data);\r\n * console.log(emoji); // \"😀\"\r\n * ```\r\n */\r\nexport function binaryToUtf8String(binaryData: Uint8Array): string {\r\n if (!binaryData || binaryData.length === 0) {\r\n return '';\r\n }\r\n\r\n try {\r\n // Use TextDecoder for proper UTF-8 decoding with error handling\r\n if (typeof TextDecoder !== 'undefined') {\r\n const decoder = new TextDecoder('utf-8', { fatal: true });\r\n return decoder.decode(binaryData);\r\n }\r\n\r\n // Node.js fallback using Buffer\r\n if (typeof Buffer !== 'undefined') {\r\n return Buffer.from(binaryData).toString('utf8');\r\n }\r\n\r\n // Manual UTF-8 decoding fallback (less robust but works in all environments)\r\n let result = '';\r\n let i = 0;\r\n\r\n while (i < binaryData.length) {\r\n let byte1 = binaryData[i++];\r\n\r\n // Single-byte character (ASCII)\r\n if (byte1 < 0x80) {\r\n result += String.fromCharCode(byte1);\r\n }\r\n // Two-byte character\r\n else if ((byte1 & 0xE0) === 0xC0) {\r\n if (i >= binaryData.length) {\r\n throw new Error(`Invalid UTF-8 sequence: incomplete two-byte character at position ${i - 1}`);\r\n }\r\n const byte2 = binaryData[i++];\r\n if ((byte2 & 0xC0) !== 0x80) {\r\n throw new Error(`Invalid UTF-8 sequence: invalid continuation byte at position ${i - 1}`);\r\n }\r\n const codePoint = ((byte1 & 0x1F) << 6) | (byte2 & 0x3F);\r\n result += String.fromCharCode(codePoint);\r\n }\r\n // Three-byte character\r\n else if ((byte1 & 0xF0) === 0xE0) {\r\n if (i + 1 >= binaryData.length) {\r\n throw new Error(`Invalid UTF-8 sequence: incomplete three-byte character at position ${i - 1}`);\r\n }\r\n const byte2 = binaryData[i++];\r\n const byte3 = binaryData[i++];\r\n if ((byte2 & 0xC0) !== 0x80 || (byte3 & 0xC0) !== 0x80) {\r\n throw new Error(`Invalid UTF-8 sequence: invalid continuation bytes at position ${i - 2}`);\r\n }\r\n const codePoint = ((byte1 & 0x0F) << 12) | ((byte2 & 0x3F) << 6) | (byte3 & 0x3F);\r\n result += String.fromCharCode(codePoint);\r\n }\r\n // Four-byte character\r\n else if ((byte1 & 0xF8) === 0xF0) {\r\n if (i + 2 >= binaryData.length) {\r\n throw new Error(`Invalid UTF-8 sequence: incomplete four-byte character at position ${i - 1}`);\r\n }\r\n const byte2 = binaryData[i++];\r\n const byte3 = binaryData[i++];\r\n const byte4 = binaryData[i++];\r\n if ((byte2 & 0xC0) !== 0x80 || (byte3 & 0xC0) !== 0x80 || (byte4 & 0xC0) !== 0x80) {\r\n throw new Error(`Invalid UTF-8 sequence: invalid continuation bytes at position ${i - 3}`);\r\n }\r\n const codePoint = ((byte1 & 0x07) << 18) | ((byte2 & 0x3F) << 12) | ((byte3 & 0x3F) << 6) | (byte4 & 0x3F);\r\n // Use surrogate pairs for code points > 0xFFFF\r\n if (codePoint > 0xFFFF) {\r\n const surrogate1 = 0xD800 + ((codePoint - 0x10000) >> 10);\r\n const surrogate2 = 0xDC00 + ((codePoint - 0x10000) & 0x3FF);\r\n result += String.fromCharCode(surrogate1, surrogate2);\r\n } else {\r\n result += String.fromCharCode(codePoint);\r\n }\r\n }\r\n // Invalid UTF-8 start byte\r\n else {\r\n throw new Error(`Invalid UTF-8 sequence: invalid start byte 0x${byte1.toString(16)} at position ${i - 1}`);\r\n }\r\n }\r\n\r\n return result;\r\n } catch (error) {\r\n throw new Error(`Failed to decode UTF-8 binary data: ${error instanceof Error ? error.message : 'Unknown error'}`);\r\n }\r\n}\r\n\r\n/**\r\n * Safely get nested object property\r\n */\r\nexport function getNestedProperty(obj: any, path: string): any {\r\n return path.split('.').reduce((current, key) => current?.[key], obj);\r\n}\r\n\r\n\r\nexport function indexOfAny(str: string, chars: string[], startIndex = 0): number {\r\n for (let i = startIndex; i < str.length; i++) {\r\n if (chars.includes(str[i])) {\r\n return i;\r\n }\r\n }\r\n return -1;\r\n}\r\n\r\n","import { RomDataReader } from './reader';\r\nimport { \r\n Address, \r\n AddressSpace, \r\n AddressType, \r\n MemberType, \r\n RomProcessingConstants,\r\n ChunkFileUtils, \r\n TableEntry \r\n} from '../../types';\r\nimport type { DbStringType, DbStringCommand, DbStringLayer } from '../../database';\r\nimport type { StringWrapper } from '../../types';\r\nimport type { BlockReader } from './blocks';\r\nimport { indexOfAny } from '../../utils';\r\n\r\n/**\r\n * Reads and processes strings from ROM data\r\n * Converted from GaiaLib/Rom/Extraction/StringReader.cs\r\n */\r\nexport class StringReader {\r\n public static readonly STRING_REFERENCE_CHARACTERS = ['~', '^'];\r\n\r\n private readonly _blockReader: BlockReader;\r\n private readonly _romDataReader: RomDataReader;\r\n\r\n constructor(blockReader: BlockReader) {\r\n this._blockReader = blockReader;\r\n this._romDataReader = blockReader._romDataReader;\r\n }\r\n\r\n private resolveCommand(cmd: DbStringCommand, builder: string[]): void {\r\n if(cmd.dictionary) {\r\n builder.push(cmd.dictionary.entries[this._romDataReader.readByte() - (cmd.dictionary.base ?? 0)]);\r\n } else if (cmd.types && cmd.types.length > 0) {\r\n builder.push(`[${cmd.name}`);\r\n\r\n let first = true;\r\n for (const t of cmd.types) {\r\n if (first) {\r\n builder.push(':');\r\n first = false;\r\n } else {\r\n builder.push(',');\r\n }\r\n\r\n switch (t) {\r\n case MemberType.Byte:\r\n builder.push(this._romDataReader.readByte().toString(16).toUpperCase());\r\n break;\r\n case MemberType.Word:\r\n builder.push(this._romDataReader.readUShort().toString(16).toUpperCase());\r\n break;\r\n case MemberType.Offset:\r\n const loc = this._romDataReader.readUShort() | \r\n (Address.resolveBank(this._romDataReader.position, this._blockReader._root.config.memoryMode) << 16);\r\n builder.push(`^${loc.toString(16).toUpperCase().padStart(6, '0')}`);\r\n break;\r\n case MemberType.Address:\r\n builder.push(`~${this._romDataReader.readAddress().toString(16).toUpperCase().padStart(6, '0')}`);\r\n break;\r\n case MemberType.Binary:\r\n let sfirst = true;\r\n do {\r\n const r = this._romDataReader.readByte();\r\n if (cmd.delimiter !== undefined && r === cmd.delimiter) {\r\n break;\r\n }\r\n if (sfirst) {\r\n sfirst = false;\r\n } else {\r\n builder.push(',');\r\n }\r\n builder.push(r.toString(16).toUpperCase());\r\n } while (this._blockReader.partCanContinue());\r\n break;\r\n default:\r\n throw new Error('Unsupported member type');\r\n }\r\n }\r\n builder.push(']');\r\n } else {\r\n builder.push(`[${cmd.name}]`);\r\n }\r\n }\r\n\r\n public parseString(stringType: DbStringType, fixedSize: number): StringWrapper {\r\n const commands = stringType.commandLookup;\r\n const dictionaries = stringType.dictionaries;\r\n const builder: string[] = [];\r\n const strLoc = this._romDataReader.position;\r\n const terminator = stringType.terminator;\r\n let currentLayer = stringType.layers[0];\r\n\r\n do {\r\n const c = this._romDataReader.readByte();\r\n if (c === terminator) {\r\n if (stringType.greedyTerminator) {\r\n while (this._romDataReader.peekByte() === terminator && this._blockReader.partCanContinue()) {\r\n this._romDataReader.position++;\r\n }\r\n }\r\n break;\r\n }\r\n\r\n const cmd = commands[c];\r\n if (cmd) {\r\n this.resolveCommand(cmd, builder);\r\n if (cmd.halt) {\r\n break;\r\n }\r\n } else {\r\n let found = false;\r\n for(const dictionary of Object.values(dictionaries)) {\r\n if(dictionary.base !== undefined && c >= dictionary.base && c <= dictionary.range) {\r\n builder.push(dictionary.entries[c - dictionary.base]);\r\n found = true;\r\n break;\r\n }\r\n }\r\n if(!found) {\r\n for(const layer of stringType.layers) {\r\n if(layer.on !== undefined) {\r\n if(c === layer.on) {\r\n currentLayer = layer;\r\n found = true;\r\n break;\r\n }\r\n } else if(layer.base && c >= layer.base && c < layer.base + layer.map.length){\r\n builder.push(layer.map[c - layer.base]);\r\n found = true;\r\n break;\r\n }\r\n }\r\n }\r\n if(!found) {\r\n let index = c - (currentLayer.base ?? 0);\r\n if(typeof currentLayer.shiftBit === 'number') {\r\n const shiftBit = 1 << currentLayer.shiftBit;\r\n const lowerFlag = shiftBit - 1;\r\n const upperFlag = ~shiftBit & ~lowerFlag;\r\n index = ((index & upperFlag) >> 1) | (index & lowerFlag);\r\n }\r\n //const index = currentLayer.shift ? DbStringTypeUtils.getShiftDown(currentLayer.shift)(c) : c - (currentLayer.base ?? 0);\r\n if (index >= 0 && index < currentLayer.map.length) {\r\n builder.push(currentLayer.map[index]);\r\n } else {\r\n // Fallback for unknown characters\r\n builder.push(`[${c.toString(16).toUpperCase()}]`);\r\n }\r\n }\r\n }\r\n\r\n if(fixedSize && this._romDataReader.position >= strLoc + fixedSize) break;\r\n \r\n } while (this._blockReader.partCanContinue());\r\n\r\n if(fixedSize && this._romDataReader.position < strLoc + fixedSize) this._romDataReader.position = strLoc + fixedSize;\r\n\r\n return {\r\n string: builder.join(''),\r\n type: stringType,\r\n marker: 0,\r\n location: strLoc,\r\n fixedSize\r\n };\r\n }\r\n\r\n public resolveString(sw: StringWrapper, isBranch: boolean): void {\r\n let str = sw.string;\r\n let ix = indexOfAny(str, StringReader.STRING_REFERENCE_CHARACTERS);\r\n \r\n while (ix >= 0) {\r\n if (ix + 6 < str.length) {\r\n const hexStr = str.substring(ix + 1, ix + 7);\r\n const sloc = parseInt(hexStr, 16);\r\n \r\n if (!isNaN(sloc)) {\r\n const addrs = new Address((sloc >> 16) & 0xFF, sloc & 0xFFFF, this._blockReader._root.config.memoryMode);\r\n if (addrs.isROM) {\r\n this._blockReader.resolveInclude(sloc, false);\r\n const name = this._blockReader.resolveName(sloc, AddressType.Unknown, false);\r\n const opix = indexOfAny(name, RomProcessingConstants.OPERATORS);\r\n \r\n if (opix > 0) {\r\n const offsetStr = name.substring(opix + 1);\r\n let offset: number;\r\n \r\n if (offsetStr === 'M') {\r\n offset = this._blockReader._referenceManager.markerTable.get(sloc) || 0;\r\n } else {\r\n offset = parseInt(offsetStr, 16) || 0;\r\n }\r\n\r\n if (name[opix] === '-') {\r\n offset = -offset;\r\n }\r\n\r\n const targetName = name.substring(0, opix);\r\n const target = sloc - offset;\r\n \r\n // Try to find the target using IsOutside pattern\r\n const [isOutside, block, part] = ChunkFileUtils.isOutsideWithPart(this._blockReader._enrichedChunks, this._blockReader._currentChunk!, sloc);\r\n if (part != null) {\r\n const entry = part.objList?.find((x): x is TableEntry => \r\n typeof x === 'object' && x !== null && 'location' in x && 'object' in x && (x as TableEntry).location === target) as TableEntry | undefined;\r\n if (entry && entry.object) {\r\n (entry.object as StringWrapper).marker = offset;\r\n }\r\n }\r\n }\r\n }\r\n }\r\n }\r\n \r\n ix = indexOfAny(str, StringReader.STRING_REFERENCE_CHARACTERS, ix + 7);\r\n }\r\n }\r\n\r\n}","import { Op } from '../../types/assembly';\r\nimport { Registers } from '../../assembly';\r\nimport { RomDataReader } from './reader';\r\nimport { StringReader } from './strings';\r\nimport { ReferenceManager } from './references';\r\nimport {\r\n Address,\r\n AddressSpace,\r\n AddressType,\r\n ChunkFileUtils,\r\n LocationWrapper,\r\n MemberType,\r\n StructDef,\r\n Byte,\r\n Word,\r\n} from '../../types';\r\nimport type { DbRoot, DbBlock, DbPart } from '../../database';\r\nimport type { DbStruct } from '../../database';\r\nimport type { DbStringType } from '../../database';\r\nimport { AsmReader } from './asm';\r\nimport type { BlockReader } from './blocks';\r\n\r\n/**\r\n * Handles parsing of different data types from ROM\r\n * Converted from GaiaLib/Rom/Extraction/TypeParser.cs\r\n */\r\nexport class TypeParser {\r\n private readonly _blockReader: BlockReader;\r\n private readonly _romDataReader: RomDataReader;\r\n private readonly _stringReader: StringReader;\r\n private readonly _stringTypes: Record<string, DbStringType>;\r\n private readonly _referenceManager: ReferenceManager;\r\n\r\n constructor(blockReader: BlockReader) {\r\n this._blockReader = blockReader;\r\n this._referenceManager = blockReader._referenceManager;\r\n this._romDataReader = blockReader._romDataReader;\r\n this._stringReader = blockReader._stringReader;\r\n this._stringTypes = blockReader._root.stringTypes;\r\n }\r\n\r\n public parseType(typeName: string, reg: Registers | null, depth: number, bank?: number): unknown {\r\n \r\n\r\n // Shortcut for symbolic Offsets\r\n if (typeName[0] === '&') {\r\n return this.parseLocation(this._romDataReader.readUShort(), bank, typeName.substring(1), AddressType.Offset);\r\n }\r\n\r\n // Shortcut for symbolic Addresses\r\n if (typeName[0] === '@') {\r\n return this.parseLocation(this._romDataReader.readUShort(), this._romDataReader.readByte(), typeName.substring(1), AddressType.Address);\r\n }\r\n \r\n // Shortcut for symbolic Locations\r\n if (typeName[0] === '%') {\r\n return this.parseLocation(this._romDataReader.readUShort(), this._romDataReader.readByte(), typeName.substring(1), AddressType.Location);\r\n }\r\n \r\n const isFixed = typeName[typeName.length - 1] === ')';\r\n let fixedTypeName = typeName;\r\n let fixedSize = 0;\r\n\r\n if(isFixed) {\r\n const startIx = typeName.indexOf('(');\r\n fixedTypeName = typeName.substring(0, startIx);\r\n fixedSize = parseInt(typeName.substring(startIx + 1, typeName.length - 1), 10);\r\n }\r\n\r\n // Check string types\r\n const stringType = this._stringTypes[fixedTypeName];\r\n if (stringType) {\r\n return this._stringReader.parseString(stringType, fixedSize);\r\n }\r\n\r\n // Parse raw values\r\n const mType = this.tryParseMemberType(fixedTypeName);\r\n if (mType !== null) {\r\n switch (mType) {\r\n case MemberType.Byte:\r\n return new Byte(this._romDataReader.readByte());\r\n case MemberType.Word:\r\n return new Word(this.parseWordSafe());\r\n case MemberType.Offset:\r\n return this.parseLocation(this._romDataReader.readUShort(), bank, null, AddressType.Offset);\r\n case MemberType.Address:\r\n return this.parseLocation(this._romDataReader.readUShort(), this._romDataReader.readByte(), null, AddressType.Address);\r\n case MemberType.Location:\r\n return this.parseLocation(this._romDataReader.readUShort(), this._romDataReader.readByte(), null, AddressType.Location);\r\n case MemberType.Binary:\r\n return this.parseBinary(fixedSize);\r\n case MemberType.Code:\r\n return this.parseCode(reg!);\r\n default:\r\n throw new Error('Invalid member type');\r\n }\r\n }\r\n\r\n const parentType = this._blockReader._root.structs[fixedTypeName];\r\n if (!parentType) {\r\n throw new Error(`Unknown type: ${fixedTypeName}`);\r\n }\r\n\r\n const delimiter = parentType.delimiter;\r\n const discOffset = parentType.discriminator;\r\n const objects: unknown[] = [];\r\n\r\n // Continue to iterate until end or delimiter is reached\r\n let delReached: boolean;\r\n while (!(delReached = this._blockReader.delimiterReached(delimiter))) {\r\n const startPosition = this._romDataReader.position;\r\n let targetType = parentType;\r\n\r\n // If a discriminator offset is present, use it to identify the type\r\n if (discOffset !== undefined) {\r\n // Get discriminator position in ROM\r\n const discPosition = this._romDataReader.position + discOffset;\r\n\r\n // Get discriminator value\r\n const desc = this._romDataReader.romData[discPosition];\r\n\r\n // Advance position (hide value) if discriminator is first\r\n if (discOffset === 0) {\r\n this._romDataReader.position++;\r\n }\r\n\r\n // Match discriminator to type\r\n const matchedStruct = Object.values(this._blockReader._root.structs).find(\r\n x => x.parent === fixedTypeName && x.discriminator === desc\r\n );\r\n targetType = matchedStruct || parentType; // Default to parent if no match is found\r\n }\r\n\r\n const types = targetType.types;\r\n if (types && types.length > 0) {\r\n const memberCount = types.length;\r\n const prevPosition = this._romDataReader.position;\r\n const parts = new Array(memberCount); // Create new member collection\r\n const def: StructDef = { name: targetType.name, parts };\r\n\r\n // Parse each member of the struct\r\n for (let i = 0; i < memberCount; i++) {\r\n parts[i] = this.parseType(types[i], reg, depth + 1, bank);\r\n }\r\n\r\n // Advance (hide) discriminator if it is the last member\r\n if (discOffset !== undefined && discOffset === this._romDataReader.position - prevPosition) {\r\n this._romDataReader.position++;\r\n }\r\n\r\n objects.push(def);\r\n }\r\n\r\n // Roll back work if struct overflows a chunk boundary\r\n // SHOULD only happen for the inventory sprite map\r\n let checkPosition = startPosition;\r\n while (++checkPosition < this._romDataReader.position) {\r\n const struct = this._referenceManager.tryGetStruct(checkPosition)\r\n if (struct.found && struct.chunkType !== 'Code') {\r\n this._romDataReader.position = checkPosition;\r\n break;\r\n }\r\n }\r\n\r\n // Stop if the reader should not continue\r\n if (!this._blockReader.partCanContinue()) {\r\n break;\r\n }\r\n }\r\n\r\n // If we have reached delimiter and at depth 0, note the struct\r\n if (delReached && depth === 0) {\r\n this._referenceManager.tryAddStruct(this._romDataReader.position, typeName);\r\n }\r\n\r\n return objects;\r\n }\r\n\r\n private tryParseMemberType(memberTypeName: string): MemberType | null {\r\n // Check if the string matches any MemberType enum value (case-insensitive)\r\n const upperName = memberTypeName.toUpperCase();\r\n for (const [key, value] of Object.entries(MemberType)) {\r\n if (key.toUpperCase() === upperName) {\r\n return value;\r\n }\r\n }\r\n return null;\r\n }\r\n\r\n private parseWordSafe(): number {\r\n return this._referenceManager.containsStruct(this._romDataReader.position + 1)\r\n ? this._romDataReader.readByte()\r\n : this._romDataReader.readUShort();\r\n }\r\n\r\n private parseBinary(size: number): Uint8Array {\r\n // Store old position for length calculation\r\n const startPosition = this._romDataReader.position;\r\n\r\n //Calculate length if it is not provided\r\n let len = 0;\r\n\r\n // Advance the reader until we reach the end of the section\r\n do {\r\n this._romDataReader.position++;\r\n len++;\r\n } while (len !== size && this._blockReader.partCanContinue());\r\n\r\n // Create buffer for the raw bytes\r\n const outBuffer = new Uint8Array(len);\r\n\r\n // Copy raw bytes from ROM to buffer\r\n for (let i = 0; i < len; i++) {\r\n outBuffer[i] = this._romDataReader.romData[startPosition + i];\r\n }\r\n\r\n return outBuffer;\r\n }\r\n\r\n private parseLocation(offset: number, bank: number | undefined, typeName: string | null, addrType: AddressType): unknown {\r\n // If bank is not provided and offset is 0, it should resolve to #$0000\r\n if ((bank === undefined || bank === null) && offset === 0) {\r\n return new Word(offset);\r\n }\r\n\r\n let adrs: Address;\r\n let loc: number;\r\n if(addrType === AddressType.Location) {\r\n loc = offset | (bank! << 16);\r\n //adrs = Address.fromInt(loc, this._blockReader._root.config.memoryMode);\r\n } else {\r\n // Bank cannot be null, instead use bank from current position\r\n const resolvedBank = bank ?? Address.resolveBank(this._romDataReader.position, this._blockReader._root.config.memoryMode);\r\n \r\n // Create the address with resolved bank\r\n adrs = new Address(resolvedBank, offset, this._blockReader._root.config.memoryMode);\r\n \r\n // If we have a system address, keep it as is\r\n if (!adrs.isROM) return adrs;\r\n \r\n // Convert address to ROM location\r\n loc = adrs.toLocation();\r\n }\r\n\r\n\r\n // If the location is inside the current block and there is no rewrite for it...\r\n if (\r\n //this._blockReader._currentChunk &&\r\n //ChunkFileUtils.isInside(this._blockReader._currentChunk, loc) &&\r\n typeName &&\r\n !this._blockReader._root.rewrites[loc]\r\n ) {\r\n // Normalize the type name to default to current part definition\r\n //const resolvedTypeName = typeName ?? this._blockReader._currentAsmBlock!.structName ?? 'Binary';\r\n\r\n // Add the struct type to our chunk table if it is not already present\r\n this._referenceManager.tryAddStruct(loc, typeName);\r\n\r\n // If the location is not already in the reference table, add it\r\n //const referenceName = `${resolvedTypeName.toLowerCase()}_${adrs.toString()}`;\r\n const referenceName = `${typeName.toLowerCase()}_${loc.toString(16).toUpperCase().padStart(6, '0')}`;\r\n this._referenceManager.tryAddName(loc, referenceName);\r\n }\r\n\r\n return new LocationWrapper(loc, addrType);\r\n }\r\n\r\n private parseCode(reg: Registers): Op[] {\r\n // Output list\r\n const opList: Op[] = [];\r\n\r\n let first = true;\r\n while (this._romDataReader.position < this._blockReader._partEnd) {\r\n // Check the chunk table for a new type block, but not on the first iteration\r\n if (first) {\r\n first = false;\r\n } else if (this._referenceManager.containsStruct(this._romDataReader.position)) {\r\n break;\r\n }\r\n\r\n // Process register adjustments before parse\r\n if (reg) {\r\n this._blockReader.hydrateRegisters(reg);\r\n }\r\n\r\n // Parse instruction\r\n const op = this._blockReader._asmReader.parseAsm(reg);\r\n\r\n // Add instruction to list\r\n opList.push(op);\r\n }\r\n\r\n return opList;\r\n }\r\n} ","import { OpCode } from '../../database';\r\nimport { Op } from '../../types/assembly';\r\n\r\nimport { Registers } from '../../assembly';\r\nimport { RomDataReader } from './reader';\r\nimport { TransformProcessor } from './transforms';\r\nimport { AddressingModeHandler, OperationContext } from './addressing';\r\nimport type { BlockReader } from './blocks';\r\nimport { StatusFlags } from '../../types/processor';\r\n\r\n/**\r\n * Parses assembly instructions from ROM data, handling different addressing modes\r\n * and maintaining CPU register state during analysis.\r\n * Converted from GaiaLib/Rom/Extraction/AsmReader.cs\r\n */\r\nexport class AsmReader {\r\n // Constants\r\n private static readonly STATUS_OP_MASK = 0xDF;\r\n private static readonly STATUS_OP_VALUE = 0xC2;\r\n private static readonly ACCUMULATOR_OP_MASK = 0xF;\r\n private static readonly ACCUMULATOR_OP_VALUE = 0x9;\r\n public static readonly VARIABLE_SIZE_INDICATOR = -2;\r\n // private static readonly TWO_BYTES_SIZE = 2;\r\n // private static readonly THREE_BYTES_SIZE = 3;\r\n\r\n private readonly _blockReader: BlockReader;\r\n private readonly _transformProcessor: TransformProcessor;\r\n private readonly _addressingModeHandler: AddressingModeHandler;\r\n private readonly _romDataReader: RomDataReader;\r\n\r\n constructor(blockReader: BlockReader) {\r\n this._blockReader = blockReader;\r\n this._transformProcessor = new TransformProcessor(blockReader);\r\n this._addressingModeHandler = new AddressingModeHandler(blockReader, this._transformProcessor);\r\n this._romDataReader = blockReader._romDataReader;\r\n }\r\n\r\n public parseAsm(reg: Registers): Op {\r\n const opStart = this._romDataReader.position;\r\n const opCode = this._romDataReader.readByte();\r\n \r\n // Find matching OpCode in the database\r\n const code = this._blockReader._root.opCodes[opCode];\r\n if (!code) {\r\n throw new Error('Unknown OpCode');\r\n }\r\n\r\n // Initialize operation context\r\n const operationContext = this.initializeOperation(code, reg, opStart);\r\n\r\n // Process operands based on the addressing mode\r\n const operands = this._addressingModeHandler.processAddressingMode(code, operationContext, reg);\r\n \r\n // Apply label transforms to operands after processing. This ensures that the ROM state is processed and valid.\r\n this._transformProcessor.applyTransforms(operationContext.xForm1, operationContext.xForm2, operands);\r\n\r\n const op = new Op(\r\n code,\r\n opStart,\r\n operands,\r\n this._romDataReader.position - opStart\r\n );\r\n\r\n if (operationContext.copDef) {\r\n op.copDef = operationContext.copDef;\r\n }\r\n\r\n return op;\r\n }\r\n\r\n public clearDestinationRegister(code: OpCode, reg: Registers): void {\r\n switch (code.mnem) {\r\n case 'LDA':\r\n delete reg.value['accumulator'];\r\n break;\r\n case 'LDX':\r\n delete reg.value['xIndex'];\r\n break;\r\n case 'LDY':\r\n delete reg.value['yIndex'];\r\n break;\r\n }\r\n }\r\n\r\n private initializeOperation(code: OpCode, reg: Registers, loc: number): OperationContext {\r\n // Calculate instruction size (some are variable)\r\n const size = this.calculateInstructionSize(code, reg);\r\n\r\n // Calculate next address (for branching)\r\n const next = loc + size;\r\n\r\n // Clear destination register for load operations. This resets the register state\r\n this.clearDestinationRegister(code, reg);\r\n\r\n const context = new OperationContext();\r\n context.size = size;\r\n context.nextAddress = next;\r\n context.xForm1 = this._transformProcessor.getTransform();\r\n context.xForm2 = null;\r\n context.copDef = null;\r\n\r\n return context;\r\n }\r\n\r\n private calculateInstructionSize(code: OpCode, reg: Registers): number {\r\n const addrMode = this._blockReader._root.addrLookup[code.mode];\r\n let size = addrMode.size;\r\n \r\n if (size === AsmReader.VARIABLE_SIZE_INDICATOR || code.mode === 'Immediate') {\r\n if((code.code & AsmReader.STATUS_OP_MASK) === AsmReader.STATUS_OP_VALUE){\r\n size = 2; //SEP REP are 2 bytes\r\n } else if ((code.code & AsmReader.ACCUMULATOR_OP_MASK) === AsmReader.ACCUMULATOR_OP_VALUE) {\r\n size = ((reg.value['statusFlags'] & StatusFlags.AccumulatorMode) === StatusFlags.AccumulatorMode) ? 2 : 3;\r\n } else {\r\n size = ((reg.value['statusFlags'] & StatusFlags.IndexMode) === StatusFlags.IndexMode) ? 2 : 3;\r\n }\r\n }\r\n \r\n return size;\r\n }\r\n} ","/**\r\n * Represents the stack for the 65816 processor\r\n */\r\nexport class Stack {\r\n public bytes: Uint8Array;\r\n public location: number;\r\n\r\n constructor() {\r\n this.bytes = new Uint8Array(70);\r\n this.location = 10;\r\n }\r\n\r\n /**\r\n * Push a byte onto the stack\r\n */\r\n public push(value: number): void {\r\n this.bytes[this.location++] = value & 0xFF;\r\n }\r\n\r\n /**\r\n * Push a 16-bit value onto the stack (little-endian)\r\n */\r\n public pushUInt16(value: number): void {\r\n this.bytes[this.location++] = value & 0xFF;\r\n this.bytes[this.location++] = (value >> 8) & 0xFF;\r\n }\r\n\r\n /**\r\n * Pop a byte from the stack\r\n */\r\n public popByte(): number {\r\n return this.bytes[--this.location];\r\n }\r\n\r\n /**\r\n * Pop a 16-bit value from the stack (little-endian)\r\n */\r\n public popUInt16(): number {\r\n const high = this.bytes[--this.location];\r\n const low = this.bytes[--this.location];\r\n return (high << 8) | low;\r\n }\r\n\r\n /**\r\n * Reset the stack to initial state\r\n */\r\n public reset(): void {\r\n this.bytes.fill(0);\r\n this.location = 10;\r\n }\r\n} ","import { StatusFlags } from '../types';\r\nimport { Stack } from './Stack';\r\nimport { MemoryMapMode } from '../types';\r\n\r\n/**\r\n * Manages the 65816 processor registers and status flags\r\n */\r\nexport class Registers {\r\n // public accumulatorFlag?: boolean;\r\n // public indexFlag?: boolean;\r\n // public direct?: number;\r\n // public dataBank?: number;\r\n // public accumulator?: number;\r\n // public xIndex?: number;\r\n // public yIndex?: number;\r\n public value: Record<string, number>;\r\n public stack: Stack;\r\n public mode: MemoryMapMode;\r\n\r\n constructor(mode: MemoryMapMode) {\r\n this.value = {};\r\n this.stack = new Stack();\r\n this.mode = mode;\r\n }\r\n\r\n /**\r\n * Get the current status flags\r\n */\r\n // public get statusFlags(): StatusFlags {\r\n // let flags = 0;\r\n // if (this.accumulatorFlag ?? false) {\r\n // flags |= StatusFlags.AccumulatorMode;\r\n // }\r\n // if (this.indexFlag ?? false) {\r\n // flags |= StatusFlags.IndexMode;\r\n // }\r\n // return flags;\r\n // }\r\n\r\n // /**\r\n // * Set the status flags\r\n // */\r\n // public set statusFlags(value: StatusFlags) {\r\n // this.accumulatorFlag = (value & StatusFlags.AccumulatorMode) !== 0;\r\n // this.indexFlag = (value & StatusFlags.IndexMode) !== 0;\r\n // }\r\n\r\n /**\r\n * Reset all registers to initial state\r\n */\r\n // public reset(): void {\r\n // this.accumulatorFlag = undefined;\r\n // this.indexFlag = undefined;\r\n // this.direct = undefined;\r\n // this.dataBank = undefined;\r\n // this.accumulator = undefined;\r\n // this.xIndex = undefined;\r\n // this.yIndex = undefined;\r\n // this.stack.reset();\r\n // }\r\n} ","import { Registers } from '../../assembly';\r\nimport { Op } from '../../types/assembly';\r\nimport { RomDataReader } from './reader';\r\nimport { ProcessorStateManager } from './processor';\r\nimport { ReferenceManager } from './references';\r\nimport { StringReader } from './strings';\r\nimport { AsmReader } from './asm';\r\nimport { TypeParser } from './parser';\r\nimport { \r\n Address, \r\n AddressType, \r\n LocationWrapper, \r\n StructDef, \r\n RegisterType,\r\n BlockReaderConstants,\r\n RomProcessingConstants,\r\n TableEntry,\r\n BinType,\r\n AsmBlock,\r\n createChunkFileFromDbFile,\r\n createChunkFileFromDbBlock,\r\n StatusFlags,\r\n} from '../../types';\r\nimport type { StringWrapper } from '../../types';\r\nimport type { DbRoot, DbFile } from '../../database';\r\nimport type { DbBlock } from '../../database';\r\nimport type { DbPart } from '../../database';\r\nimport { ChunkFile, ChunkFileUtils } from '../../types/files';\r\nimport { indexOfAny, saveFileAsBinary, saveFileAsText } from '../../utils';\r\nimport { BlockWriter } from './writer';\r\n\r\n/**\r\n * Central class for reading and analyzing ROM blocks\r\n * Converted from GaiaLib/Rom/Extraction/BlockReader.cs\r\n */\r\nexport class BlockReader {\r\n // Constants\r\n private static readonly REF_SEARCH_MAX_RANGE = 0x1A0;\r\n private static readonly BANK_MASK_CHECK = 0x40;\r\n private static readonly BYTE_DELIMITER_THRESHOLD = 0x100;\r\n private static readonly BANK_HIGH_MEMORY_1 = 0x7E;\r\n private static readonly BANK_HIGH_MEMORY_2 = 0x7F;\r\n private static readonly POINTER_CHARACTERS = ['&', '@'];\r\n\r\n // Location regex pattern: _([A-Fa-f0-9]{6})\r\n private static readonly LOCATION_REGEX = /_([A-Fa-f0-9]{6})/;\r\n\r\n // Core Dependencies\r\n public readonly _root: DbRoot;\r\n public readonly _stringReader: StringReader;\r\n public readonly _asmReader: AsmReader;\r\n public readonly _typeParser: TypeParser;\r\n public readonly _romDataReader: RomDataReader;\r\n public readonly _stateManager: ProcessorStateManager;\r\n public readonly _referenceManager: ReferenceManager;\r\n\r\n // Current Processing State (Database)\r\n //public _currentBlock!: DbBlock;\r\n //public _currentPart: DbPart | null = null;\r\n public _partEnd: number = 0;\r\n \r\n // ChunkFile Processing State\r\n public _currentChunk: ChunkFile | null = null;\r\n public _currentAsmBlock: AsmBlock | null = null;\r\n public _enrichedChunks: ChunkFile[] = [];\r\n\r\n constructor(romData: Uint8Array, root: DbRoot) {\r\n this._romDataReader = new RomDataReader(romData);\r\n this._stateManager = new ProcessorStateManager();\r\n this._referenceManager = new ReferenceManager(root);\r\n this._root = root;\r\n\r\n this._stringReader = new StringReader(this as any);\r\n this._asmReader = new AsmReader(this as any);\r\n this._typeParser = new TypeParser(this as any);\r\n\r\n this.initializeOverrides();\r\n this.initializeFileReferences();\r\n }\r\n\r\n /**\r\n * Processes predefined overrides for registers and bank notes\r\n */\r\n private initializeOverrides(): void {\r\n if(!this._root.overrides) return;\r\n for (const [location, overrides] of Object.entries(this._root.overrides)) {\r\n for (const [register, value] of Object.entries(overrides)) {\r\n switch (register) {\r\n case 'M':\r\n this._stateManager.get('statusFlags').setFlag(parseInt(location), StatusFlags.AccumulatorMode, value === 1);\r\n break;\r\n case 'X':\r\n this._stateManager.get('statusFlags').setFlag(parseInt(location), StatusFlags.IndexMode, value === 1);\r\n break;\r\n case 'B':\r\n this._stateManager.get('dataBank').set(parseInt(location), value);\r\n break;\r\n case 'type':\r\n this._referenceManager.tryAddStruct(parseInt(location), value);\r\n break;\r\n case 'name':\r\n this._referenceManager.tryAddName(parseInt(location), value);\r\n break;\r\n }\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * Processes predefined file references\r\n */\r\n private initializeFileReferences(): void {\r\n for (const file of this._root.files) {\r\n this._referenceManager.tryAddName(file.start, file.name);\r\n }\r\n }\r\n\r\n /**\r\n * Resolves mnemonic for a given address\r\n */\r\n public resolveMnemonic(addr: Address): void {\r\n // If the address is in high memory (ROM only), skip processing\r\n if ((addr.bank & Address.DATA_BANK_FLAG) !== 0) {\r\n return;\r\n }\r\n\r\n let offset = addr.offset;\r\n \r\n const label = this._root.mnemonics[offset];\r\n if (!label) {\r\n return;\r\n }\r\n\r\n const ix = indexOfAny(label, RomProcessingConstants.OPERATORS);\r\n if (ix >= 0) {\r\n let opnd = parseInt(label.substring(ix + 1), 16);\r\n const op = label[ix];\r\n if(op === '-')\r\n opnd = -opnd;\r\n \r\n offset -= opnd;\r\n }\r\n\r\n // Add to current block's mnemonics\r\n this._currentChunk!.mnemonics[offset] = label.substring(0, ix >= 0 ? ix : label.length);\r\n }\r\n\r\n /**\r\n * Resolves name for a location (delegated to ReferenceManager)\r\n */\r\n public resolveName(location: number, type: AddressType, isBranch: boolean): string {\r\n return this._referenceManager.resolveName(location, type, isBranch);\r\n }\r\n\r\n /**\r\n * Resolves include for a location\r\n */\r\n public resolveInclude(loc: number, isBranch: boolean): void {\r\n const [outside, foundBlock, foundPart] = ChunkFileUtils.isOutsideWithPart(this._enrichedChunks, this._currentChunk!, loc);\r\n if (outside && foundBlock && foundPart) {\r\n this._currentAsmBlock!.includes!.add({block: foundBlock, part: foundPart});\r\n } else if (isBranch && !this._referenceManager.tryGetName(loc).found) {\r\n // const adrs = Address.fromInt(loc, this._root.config.memoryMode);\r\n // const name = `loc_${adrs.toString()}`;\r\n const name = `loc_${loc.toString(16).toUpperCase().padStart(6, '0')}`;\r\n this._referenceManager.tryAddName(loc, name);\r\n }\r\n }\r\n\r\n /**\r\n * Notes a type at a location and manages chunk references\r\n */\r\n public noteType(loc: number, type: string, silent: boolean = false, reg?: Registers): string {\r\n this._referenceManager.tryAddStruct(loc, type);\r\n\r\n const nameResult = this._referenceManager.tryGetName(loc);\r\n let name: string;\r\n \r\n if (!nameResult.found) {\r\n name = this._referenceManager.createTypeName(type, loc);\r\n this._referenceManager.tryAddName(loc, name);\r\n } else {\r\n name = nameResult.referenceName!;\r\n }\r\n\r\n if (!silent && type === BlockReaderConstants.CODE_TYPE && reg) {\r\n this.updateRegisterState(loc, reg);\r\n }\r\n\r\n return name;\r\n }\r\n\r\n public updateRegisterState(loc: number, reg: Registers): void {\r\n for (const [key, value] of Object.entries(reg.value)) {\r\n if (value === undefined || value === null) continue;\r\n this._stateManager.get(key).tryAdd(loc, value);\r\n }\r\n // if (reg.accumulatorFlag !== undefined) {\r\n // this._stateManager.tryAddAccumulatorFlag(loc, reg.accumulatorFlag);\r\n // }\r\n // if (reg.indexFlag !== undefined) {\r\n // this._stateManager.tryAddIndexFlag(loc, reg.indexFlag);\r\n // }\r\n if (reg.stack.location > 0) {\r\n this._stateManager.tryAddStackPosition(loc, reg.stack.location);\r\n }\r\n }\r\n\r\n /**\r\n * Checks if a delimiter has been reached\r\n */\r\n public delimiterReached(delimiter?: number): boolean {\r\n if (delimiter === undefined) {\r\n return false;\r\n }\r\n\r\n if (delimiter >= BlockReaderConstants.BYTE_DELIMITER_THRESHOLD) {\r\n if (this._romDataReader.peekShort() === delimiter) {\r\n this._romDataReader.position += 2;\r\n return true;\r\n }\r\n } else if (this._romDataReader.peekByte() === delimiter) {\r\n this._romDataReader.position++;\r\n return true;\r\n }\r\n\r\n return false;\r\n }\r\n\r\n /**\r\n * Checks if processing of the current part can continue\r\n */\r\n public partCanContinue(): boolean {\r\n return this._romDataReader.position < this._partEnd && \r\n !this._referenceManager.containsStruct(this._romDataReader.position);\r\n }\r\n\r\n public analyzeAndResolve(): ChunkFile[] {\r\n this.createChunkFilesFromDatabase();\r\n this.initializeBlocksAndParts();\r\n this.analyzeChunkFiles();\r\n this.resolveReferences();\r\n \r\n return this._enrichedChunks;\r\n }\r\n\r\n /**\r\n * Analyzes all blocks in the ROM\r\n */\r\n // private analyzeBlocks(): void {\r\n // this.initializeBlocksAndParts();\r\n\r\n // for (const chunk of this._enrichedChunks) {\r\n // this._currentChunk = chunk;\r\n // for (const part of chunk.parts || []) {\r\n // this.processPart(part);\r\n // }\r\n // }\r\n // }\r\n\r\n /**\r\n * Initializes blocks and parts with base references\r\n */\r\n private initializeBlocksAndParts(): void {\r\n for (const block of this._enrichedChunks) {\r\n for (const part of block.parts || []) {\r\n if(part.structName) {\r\n this._referenceManager.tryAddStruct(part.location, part.structName);\r\n }\r\n if(part.label) {\r\n this._referenceManager.tryAddName(part.location, part.label);\r\n }\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * Processes a single part\r\n */\r\n private processPart(part: AsmBlock): void {\r\n this._currentAsmBlock = part;\r\n this._romDataReader.position = part.location;\r\n this._partEnd = part.location + part.size;\r\n\r\n let current = part.structName || BlockReaderConstants.BINARY_TYPE;\r\n const chunks: TableEntry[] = [];\r\n const reg = new Registers(this._root.config.memoryMode); //platform.createRegisters()\r\n const bank = part.bank;\r\n let last: TableEntry | null = null;\r\n\r\n while (this._romDataReader.position < this._partEnd) {\r\n const structResult = this._referenceManager.tryGetStruct(this._romDataReader.position);\r\n if (structResult.found) {\r\n current = structResult.chunkType!;\r\n } else if (last !== null && !this._root.stringTypes[current]) {\r\n this.processContinuousEntry(current, reg, bank, last);\r\n continue;\r\n }\r\n\r\n if(!this._referenceManager.nameTable.has(this._romDataReader.position)) {\r\n const name = this._referenceManager.createTypeName(current, this._romDataReader.position);\r\n this._referenceManager.nameTable.set(this._romDataReader.position, name);\r\n }\r\n last = new TableEntry(this._romDataReader.position);\r\n chunks.push(last);\r\n this.processNewEntry(current, reg, bank, last);\r\n }\r\n\r\n part.objList = chunks;\r\n }\r\n\r\n /**\r\n * Processes a continuous entry (same type as previous)\r\n */\r\n private processContinuousEntry(current: string, reg: Registers, bank: number | undefined, last: TableEntry): void {\r\n const obj = this._typeParser.parseType(current, reg, 0, bank);\r\n if (!Array.isArray(last.object)) {\r\n last.object = [last.object];\r\n }\r\n (last.object as unknown[]).push(obj);\r\n }\r\n\r\n /**\r\n * Processes a new entry\r\n */\r\n private processNewEntry(current: string, reg: Registers, bank: number | undefined, last: TableEntry): void {\r\n let res = this._typeParser.parseType(current, reg, 0, bank);\r\n if (BlockReaderConstants.POINTER_CHARACTERS.includes(current[0]) && !Array.isArray(res)) {\r\n res = [res];\r\n }\r\n last.object = res;\r\n }\r\n\r\n /**\r\n * Creates ChunkFile objects from database structure\r\n */\r\n private createChunkFilesFromDatabase(): void {\r\n // Clear any previous results\r\n this._enrichedChunks = [];\r\n this.createChunkFilesFromSfx();\r\n // Convert DbFiles to binary ChunkFiles with rawData\r\n this.createChunkFilesFromDbFiles();\r\n // Convert DbBlocks to assembly ChunkFiles with parts\r\n this.createChunkFilesFromDbBlocks();\r\n }\r\n\r\n /**\r\n * Creates binary ChunkFiles from DbFiles (enriched with rawData)\r\n */\r\n private createChunkFilesFromSfx(): void {\r\n let pos = this._root.config.sfxLocation;\r\n let offset = 0;\r\n const count = this._root.config.sfxCount;\r\n const romData = this._romDataReader.romData;\r\n const fileType = Object.values(this._root.fileTypes).find(x => x.type === BinType.Sound)!;\r\n\r\n const getByte = this._root.config.sfxType === 'Striped' ? () => {\r\n const byte = romData[pos + offset++];\r\n if(offset & RomProcessingConstants.PAGE_SIZE) offset += RomProcessingConstants.PAGE_SIZE;\r\n return byte;\r\n } : () => romData[pos + offset++];\r\n\r\n const getSize = () => getByte() | (getByte() << 8);\r\n\r\n const getBytes = this._root.config.sfxType === 'Striped' ? (size: number) => {\r\n let end = offset + size;\r\n let data: Uint8Array;\r\n if (end & RomProcessingConstants.PAGE_SIZE) {\r\n const endLen = end & 0x7FFF;\r\n size -= endLen;\r\n data = romData.slice(pos + offset, pos + offset + size);\r\n offset += size + RomProcessingConstants.PAGE_SIZE;\r\n end = offset + endLen;\r\n const data2 = romData.slice(pos + offset, pos + end);\r\n data = new Uint8Array([...data, ...data2]);\r\n } else {\r\n data = romData.slice(pos + offset, pos + end);\r\n }\r\n offset = end;\r\n return data;\r\n } : (size: number) => {\r\n const end = offset + size;\r\n const data = romData.slice(pos + offset, pos + end);\r\n offset = end;\r\n return data;\r\n }\r\n\r\n for (let i = 0; i < count; i++) {\r\n const size = getSize();\r\n const startPos = pos + offset;\r\n const data = getBytes(size);\r\n\r\n const chunk = new ChunkFile(`sfx${i.toString(16).toUpperCase().padStart(2, '0')}`, size, startPos, fileType);\r\n chunk.rawData = data;\r\n chunk.group = 'sfx';\r\n this._enrichedChunks.push(chunk);\r\n }\r\n }\r\n\r\n /**\r\n * Creates binary ChunkFiles from DbFiles (enriched with rawData)\r\n */\r\n private createChunkFilesFromDbFiles(): void {\r\n for (const dbFile of this._root.files) {\r\n const chunkFile = createChunkFileFromDbFile(this._romDataReader.romData, this._root.compression, dbFile, this._root.fileTypes[dbFile.type]);\r\n this._enrichedChunks.push(chunkFile);\r\n }\r\n }\r\n\r\n /**\r\n * Creates assembly ChunkFiles from DbBlocks (enriched with parts)\r\n */\r\n private createChunkFilesFromDbBlocks(): void {\r\n const fileType = Object.values(this._root.fileTypes).find(x => x.isBlock)!;\r\n for (const block of this._root.blocks) {\r\n const chunkFile = createChunkFileFromDbBlock(block, fileType, this._root.config.memoryMode);\r\n this._enrichedChunks.push(chunkFile);\r\n }\r\n }\r\n /**\r\n * Analyzes only assembly ChunkFiles (those with parts from DbBlocks)\r\n */\r\n private analyzeChunkFiles(): void {\r\n // Only process assembly ChunkFiles, skip binary ones\r\n const assemblyChunks = this._enrichedChunks.filter(chunk => chunk.type.type === 'Assembly');\r\n \r\n for (const chunkFile of assemblyChunks) {\r\n this._currentChunk = chunkFile;\r\n for (const asmBlock of chunkFile.parts || []) {\r\n this._currentAsmBlock = asmBlock;\r\n this.processPart(asmBlock);\r\n }\r\n }\r\n }\r\n\r\n // /**\r\n // * Processes a single AsmBlock (similar to processPart)\r\n // */\r\n // private processAsmBlock(asmBlock: AsmBlock): void {\r\n // this._romDataReader.position = asmBlock.location;\r\n // this._partEnd = asmBlock.location + asmBlock.size;\r\n\r\n // let current = asmBlock.structName || BlockReaderConstants.BINARY_TYPE;\r\n // const chunks: TableEntry[] = [];\r\n // const reg = new Registers();\r\n // const bank = this._currentAsmBlock?.bank;\r\n // let last: TableEntry | null = null;\r\n\r\n // while (this._romDataReader.position < this._partEnd) {\r\n // const structResult = this._referenceManager.tryGetStruct(this._romDataReader.position);\r\n // if (structResult.found) {\r\n // current = structResult.chunkType!;\r\n // } else if (last !== null) {\r\n // this.processContinuousEntry(current, reg, bank, last);\r\n // continue;\r\n // }\r\n\r\n // last = createTableEntry(this._romDataReader.position);\r\n // chunks.push(last);\r\n // this.processNewEntry(current, reg, bank, last);\r\n // }\r\n\r\n // asmBlock.objList = chunks;\r\n // }\r\n\r\n /**\r\n * Resolves references in assembly ChunkFiles only\r\n */\r\n private resolveReferences(): void {\r\n for (const chunkFile of this._enrichedChunks) {\r\n this._currentChunk = chunkFile;\r\n \r\n for (const asmBlock of chunkFile.parts || []) {\r\n this._currentAsmBlock = asmBlock;\r\n this.resolveObject(asmBlock.objList, false);\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * Resolves a single object and its references\r\n */\r\n private resolveObject(obj: unknown, isBranch: boolean): void {\r\n if(obj === undefined || obj === null) return;\r\n\r\n if (typeof obj === 'string') {\r\n // String objects don't need resolution\r\n return;\r\n }\r\n\r\n if (Array.isArray(obj)) {\r\n for (const o of obj) {\r\n this.resolveObject(o, isBranch);\r\n }\r\n return;\r\n }\r\n\r\n if (obj instanceof Address) {\r\n this.resolveMnemonic(obj);\r\n return;\r\n }\r\n\r\n if (typeof obj === 'number') {\r\n this.resolveInclude(obj, isBranch);\r\n return;\r\n }\r\n\r\n if (obj instanceof LocationWrapper) {\r\n this.resolveInclude(obj.location, isBranch);\r\n return;\r\n }\r\n\r\n if (obj instanceof TableEntry) {\r\n this.resolveObject(obj.object, isBranch);\r\n return;\r\n }\r\n\r\n if (obj instanceof Op) {\r\n this.resolveOperationObject(obj);\r\n return;\r\n }\r\n\r\n if (typeof obj === 'object') {\r\n if ('string' in obj && 'type' in obj) {\r\n // StringWrapper\r\n this._stringReader.resolveString(obj as StringWrapper, isBranch);\r\n return;\r\n }\r\n\r\n if ('name' in obj && 'parts' in obj) {\r\n // StructDef\r\n this.resolveObject((obj as StructDef).parts, isBranch);\r\n return;\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * Resolves references in an operation object\r\n */\r\n private resolveOperationObject(op: Op): void {\r\n const branch = this.isBranchOperation(op);\r\n for (const opnd of op.operands) {\r\n this.resolveObject(opnd, branch);\r\n }\r\n }\r\n\r\n /**\r\n * Checks if an operation is a branch operation\r\n */\r\n private isBranchOperation(op: Op): boolean {\r\n return op.mode === 'PCRelative' ||\r\n op.mode === 'PCRelativeLong' ||\r\n op.mnem[0] === 'J';\r\n }\r\n\r\n /**\r\n * Hydrates registers with stored state\r\n */\r\n public hydrateRegisters(reg: Registers): void {\r\n this._stateManager.hydrateRegisters(this._romDataReader.position, reg);\r\n }\r\n\r\n}","import { ChunkFile } from '../../types/files';\nimport { TableEntry } from '../../types';\nimport { StructDef, Word } from '../../types';\nimport { BlockReader } from './blocks';\nimport { ReferenceManager } from './references';\n\n/**\n * Handles post processing of extracted blocks.\n * Mirrors functionality of GaiaLib.Rom.Extraction.PostProcessor.\n */\nexport class PostProcessor {\n private readonly _referenceManager: ReferenceManager;\n\n constructor(reader: BlockReader) {\n this._referenceManager = reader._referenceManager;\n }\n\n /**\n * Execute post process directive on a block if present.\n */\n public process(block: ChunkFile): void {\n if (!block.postProcess || block.postProcess.trim() === '') {\n return;\n }\n\n let signature = block.postProcess;\n const parts: string[] = [];\n\n const index = signature.indexOf('(');\n if (index > 0) {\n const endIx = signature.indexOf(')', index);\n const params = signature.substring(\n index + 1,\n endIx >= 0 ? endIx : signature.length\n );\n if (params.length > 0) {\n for (const p of params.split(',')) {\n parts.push(p.trim());\n }\n }\n signature = signature.substring(0, index);\n }\n\n const fn = (this as any)[signature];\n if (typeof fn !== 'function') {\n throw new Error(`Unable to locate postprocess function ${signature}`);\n }\n fn.apply(this, [block, ...parts]);\n }\n\n /**\n * Builds a lookup table from struct entries.\n * Equivalent to PostProcessor.Lookup in C# implementation.\n */\n public Lookup(block: ChunkFile, keyIx: string, valueIx: string): void {\n const kix = parseInt(keyIx.trim());\n const vix = parseInt(valueIx.trim());\n\n if(!block.parts || block.parts.length === 0) {\n throw new Error('Invalid block structure for Lookup post process');\n }\n\n const table = block.parts[0]?.objList;\n const tableEntry = table && table[0];\n const entries = tableEntry?.object as unknown[] | undefined;\n\n if (!tableEntry || !entries) {\n throw new Error('Invalid table structure for Lookup post process');\n }\n\n const newParts: TableEntry[] = [];\n const newList: any[] = [];\n\n newParts.push({ location: tableEntry.location, object: newList });\n\n let eIx = 1;\n for (const entry of entries as StructDef[]) {\n if (!entry || !Array.isArray((entry as any).parts)) {\n continue;\n }\n const struct = entry as StructDef;\n let cIx = 0;\n let key: number | null = null;\n let value: unknown = null;\n\n for (const obj of struct.parts) {\n if (cIx === kix) {\n if(obj && typeof obj === 'object' && 'value' in obj) {\n key = obj.value as number;\n } else {\n key = obj as number;\n }\n } else if (cIx === vix) {\n value = obj;\n }\n cIx++;\n }\n\n if (key === null || value === null) {\n throw new Error('Could not locate key or value for transform');\n }\n\n const name = `entry_${key.toString(16).toUpperCase().padStart(2, '0')}`;\n const loc = tableEntry.location + eIx;\n\n newParts.push({ location: loc, object: value });\n\n // Force labels to match the new name\n this._referenceManager.nameTable.set(loc, name);\n\n while (newList.length <= key) {\n newList.push(new Word(0));\n }\n\n newList[key] = `&${name}`;\n eIx++;\n }\n\n block.parts[0].objList = newParts;\n }\n}\n\nexport default PostProcessor;\n\n","import { Op } from '../../types/assembly';\r\nimport { AsmBlock, ChunkFile, ChunkFileUtils, TypedNumber } from '../../types';\r\nimport { \r\n AddressType, \r\n MemberType,\r\n AddressSpace,\r\n TableEntry,\r\n StructDef,\r\n StringWrapper,\r\n LocationWrapper,\r\n Address\r\n} from '../../types';\r\nimport { DbRoot } from '../../database';\r\nimport { BlockReader } from './blocks';\r\nimport { ReferenceManager } from './references';\r\nimport { PostProcessor } from './postprocessor';\r\n\r\n// Platform detection that works in both Node.js and web environments\r\nconst isWindows = (() => {\r\n // Check if we're in Node.js environment\r\n if (typeof process !== 'undefined' && process.platform) {\r\n return process.platform === 'win32';\r\n }\r\n // In web environment, check user agent as fallback\r\n // if (typeof navigator !== 'undefined' && navigator.userAgent) {\r\n // return navigator.userAgent.includes('Windows');\r\n // }\r\n // Default to Unix-style line endings if we can't determine\r\n return false;\r\n})();\r\n\r\nconst NEWLINE = isWindows ? '\\r\\n' : '\\n';\r\n\r\n// Type tags for better object identification\r\nexport enum ObjectType {\r\n TableEntryArray = 'TableEntryArray',\r\n StructDef = 'StructDef',\r\n OpArray = 'OpArray',\r\n LocationWrapper = 'LocationWrapper',\r\n Address = 'Address',\r\n StringWrapper = 'StringWrapper',\r\n ByteArray = 'ByteArray',\r\n Array = 'Array',\r\n String = 'String',\r\n Number = 'Number',\r\n TypedNumber = 'TypedNumber'\r\n}\r\n\r\nexport class BlockWriter {\r\n private _root: DbRoot;\r\n private _blockReader: BlockReader;\r\n private _referenceManager: ReferenceManager;\r\n private _postProcessor: PostProcessor;\r\n private _isInline: boolean = false;\r\n private _currentPart: AsmBlock | null = null;\r\n\r\n constructor(reader: BlockReader) {\r\n this._blockReader = reader;\r\n this._root = reader._root;\r\n this._referenceManager = reader._referenceManager;\r\n this._postProcessor = new PostProcessor(reader);\r\n }\r\n\r\n // async writeBlocks(outPath: string): Promise<void> {\r\n // const res = DbRootUtils.getPath(this._root, BinType.Assembly);\r\n\r\n // const folderPath = join(outPath, res.folder);\r\n\r\n // for (const block of this._root.blocks) {\r\n // const groupedFolderPath = block.group \r\n // ? join(folderPath, block.group)\r\n // : folderPath;\r\n \r\n // await fs.mkdir(groupedFolderPath, { recursive: true });\r\n\r\n // const outFile = join(groupedFolderPath, `${block.name}.${res.extension}`);\r\n \r\n // // Check if file exists, skip if it does\r\n // try {\r\n // await fs.access(outFile);\r\n // continue;\r\n // } catch {\r\n // // File doesn't exist, continue with creation\r\n // }\r\n\r\n // const content = this.generateAsm(block);\r\n \r\n // await fs.writeFile(outFile, content);\r\n // }\r\n // }\r\n\r\n generateAllAsm(chunkFiles: ChunkFile[]): any[] {\r\n const lines: any[] = [];\r\n for (const block of chunkFiles) {\r\n lines.push({\r\n name: block.name,\r\n group: block.group,\r\n text: this.generateAsm(block)\r\n });\r\n }\r\n return lines;\r\n }\r\n\r\n generateAsm(block: ChunkFile): string{\r\n if(!block.parts) {\r\n throw new Error('Invalid block structure for generateAsm');\r\n }\r\n\r\n const lines: string[] = [];\r\n\r\n // Write bank information if not movable\r\n if (block.bank !== undefined) {\r\n lines.push(`?BANK ${block.bank.toString(16).toUpperCase().padStart(2, '0')}`);\r\n }\r\n\r\n // Write includes - these should be from the block's include list\r\n const includes = ChunkFileUtils.getIncludes(block);\r\n if (includes && includes.length > 0) {\r\n lines.push('');\r\n for (const inc of includes) {\r\n lines.push(`?INCLUDE '${inc.name}'`);\r\n }\r\n }\r\n\r\n // Write mnemonics - these should be from the root mnemonics that are referenced in this block\r\n const mnemonics = this.getMnemonicsForBlock(block);\r\n if (mnemonics && mnemonics.length > 0) {\r\n lines.push('');\r\n for (const [name, address] of mnemonics) {\r\n const paddedName = name.padEnd(30, ' ');\r\n lines.push(`!${paddedName} ${address.toString(16).toUpperCase().padStart(4, '0')}`);\r\n }\r\n }\r\n\r\n // Apply any post processing defined for the block\r\n this._postProcessor.process(block);\r\n\r\n // Process each part\r\n for (const part of block.parts || []) {\r\n this._currentPart = part;\r\n this._isInline = true;\r\n\r\n lines.push('');\r\n lines.push('---------------------------------------------');\r\n\r\n const objectLines = this.writeObject(part.objList, -1);\r\n lines.push(...objectLines);\r\n }\r\n\r\n let content = lines.join(NEWLINE);\r\n\r\n // Apply replace transforms\r\n if (block.transforms) {\r\n for (const x of block.transforms) {\r\n if (x.key && x.value) {\r\n const regex = new RegExp(x.key, 'g');\r\n content = content.replace(regex, x.value);\r\n }\r\n }\r\n }\r\n\r\n if(!isWindows){\r\n content = content.replace(/\\r/g, '');\r\n }\r\n\r\n return content;\r\n };\r\n\r\n private getMnemonicsForBlock(block: ChunkFile): [string, number][] {\r\n if (!block.mnemonics) {\r\n return [];\r\n }\r\n\r\n return Object.entries(block.mnemonics)\r\n .map(([k, v]) => [v, parseInt(k, 10)] as [string, number])\r\n .sort((a, b) => a[1] - b[1]);\r\n }\r\n\r\n private resolveOperand(op: Op, obj: any, isBranch: boolean = false): any {\r\n\r\n if(obj instanceof TypedNumber) {\r\n const len = obj.size * 2;\r\n return obj.value.toString(16).toUpperCase().padStart(len, '0');\r\n }\r\n\r\n if (typeof obj === 'number') {\r\n if (op.mode === 'Immediate') {\r\n return obj;\r\n }\r\n return this._blockReader.resolveName(obj, AddressType.Address, isBranch);\r\n }\r\n \r\n if (this.getObjectType(obj) === ObjectType.LocationWrapper) {\r\n const lw = obj as LocationWrapper;\r\n return this._blockReader.resolveName(lw.location, lw.type, isBranch);\r\n }\r\n if (this.getObjectType(obj) === ObjectType.Address) {\r\n const addr = obj as Address;\r\n\r\n if (op.size === 4) {\r\n return addr;\r\n }\r\n\r\n if (addr.isCodeBank && addr.offset < Address.UPPER_BANK) {\r\n const label = this._root.mnemonics[addr.offset];\r\n if (label) return label;\r\n }\r\n\r\n return addr.offset;\r\n }\r\n\r\n // Preserve tag information on typed numbers without resolving names\r\n if (obj && obj instanceof TypedNumber) {\r\n // const typed = obj as { _tag: string; value: any };\r\n\r\n // // Byte/Word objects should remain untouched\r\n // if (typed._tag === 'Byte' || typed._tag === 'Word' || typed._tag === 'TypedNumber') {\r\n // return obj;\r\n // }\r\n\r\n // if (typeof typed.value === 'number' && op.mode !== 'Immediate') {\r\n // const resolved = this._blockReader.resolveName(typed.value, AddressType.Address, isBranch);\r\n // return { ...typed, value: resolved };\r\n // }\r\n return obj;\r\n }\r\n return obj;\r\n }\r\n\r\n private getObjectType(obj: any): ObjectType {\r\n if (obj === null || obj === undefined) {\r\n return ObjectType.String;\r\n }\r\n\r\n // Check for explicit type tags first\r\n if (obj._tag) {\r\n return obj._tag as ObjectType;\r\n }\r\n\r\n if (obj instanceof TypedNumber) {\r\n return ObjectType.TypedNumber;\r\n }\r\n\r\n // Duck typing fallbacks\r\n if (Array.isArray(obj)) {\r\n if (obj.length > 0) {\r\n if (obj[0] && typeof obj[0] === 'object' && 'location' in obj[0] && 'object' in obj[0]) {\r\n return ObjectType.TableEntryArray;\r\n }\r\n if (obj[0] instanceof Op) {\r\n return ObjectType.OpArray;\r\n }\r\n }\r\n return ObjectType.Array;\r\n }\r\n\r\n if (obj instanceof Op) {\r\n return ObjectType.OpArray;\r\n }\r\n\r\n if (obj instanceof LocationWrapper) {\r\n return ObjectType.LocationWrapper;\r\n }\r\n\r\n if (obj instanceof Address) {\r\n return ObjectType.Address;\r\n }\r\n\r\n if (obj instanceof Uint8Array) {\r\n return ObjectType.ByteArray;\r\n }\r\n\r\n if (obj && typeof obj === 'object') {\r\n if ('string' in obj && 'type' in obj && 'marker' in obj && 'location' in obj) {\r\n return ObjectType.StringWrapper;\r\n }\r\n if ('name' in obj && 'parts' in obj) {\r\n return ObjectType.StructDef;\r\n }\r\n }\r\n\r\n if (typeof obj === 'string') {\r\n return ObjectType.String;\r\n }\r\n\r\n if (typeof obj === 'number') {\r\n return ObjectType.Number;\r\n }\r\n\r\n return ObjectType.String;\r\n }\r\n\r\n private writeObject(obj: any, depth: number, isBranch: boolean = false, isArray: boolean = false): string[] {\r\n const lines: string[] = [];\r\n\r\n const objType = this.getObjectType(obj);\r\n let objLines: string[];\r\n\r\n switch (objType) {\r\n case ObjectType.TableEntryArray:\r\n objLines = this.writeTableEntryArray(obj as TableEntry[], depth);\r\n break;\r\n\r\n case ObjectType.StructDef:\r\n objLines = this.writeStructDef(obj as StructDef, depth);\r\n break;\r\n\r\n case ObjectType.OpArray:\r\n objLines = this.writeOpArray(obj as Op[], depth);\r\n break;\r\n\r\n case ObjectType.LocationWrapper:\r\n objLines = [\r\n this._blockReader.resolveName(\r\n (obj as LocationWrapper).location,\r\n (obj as LocationWrapper).type,\r\n isBranch\r\n ),\r\n ];\r\n break;\r\n\r\n case ObjectType.Address:\r\n objLines = isArray \r\n ? [`$#${(obj as Address).offset.toString(16).toUpperCase().padStart(4, '0')}`] \r\n : [`$${(obj as Address).toString()}`];\r\n break;\r\n\r\n case ObjectType.ByteArray:\r\n objLines = [\r\n `#${Array.from(obj as Uint8Array)\r\n .map(b => b.toString(16).toUpperCase().padStart(2, '0'))\r\n .join('')}`,\r\n ];\r\n break;\r\n\r\n case ObjectType.StringWrapper:\r\n objLines = this.writeStringWrapper(obj as StringWrapper);\r\n break;\r\n\r\n case ObjectType.Array:\r\n objLines = this.writeArray(obj as any[], depth);\r\n break;\r\n\r\n case ObjectType.Number:\r\n objLines = this.writeNumber(obj as number);\r\n break;\r\n\r\n case ObjectType.TypedNumber:\r\n objLines = this.writeTypedNumber(obj as any);\r\n break;\r\n\r\n case ObjectType.String:\r\n objLines = [String(obj)];\r\n break;\r\n\r\n default:\r\n objLines = [String(obj)];\r\n break;\r\n }\r\n\r\n lines.push(...objLines);\r\n\r\n return lines;\r\n }\r\n\r\n private writeTableEntryArray(tGroup: TableEntry[], depth: number): string[] {\r\n const lines: string[] = [];\r\n const isInline = this._isInline;\r\n //this._isInline = true;\r\n\r\n for (const t of tGroup) {\r\n const nameResult = this._referenceManager.tryGetName(t.location);\r\n //const adrs = Address.fromInt(t.location, this._blockReader._root.config.memoryMode);\r\n //const name = nameResult.found ? nameResult.referenceName! : `loc_${adrs.toString()}`;\r\n const name = nameResult.found ? nameResult.referenceName! : `loc_${t.location.toString(16).toUpperCase().padStart(6, '0')}`;\r\n \r\n const objectLines = this.writeObject(t.object, depth + 1);\r\n lines.push('');\r\n lines.push(`${name} ${objectLines[0]}`);\r\n if (objectLines.length > 1) {\r\n lines.push(...objectLines.slice(1));\r\n }\r\n }\r\n \r\n this._isInline = isInline;\r\n return lines;\r\n }\r\n\r\n private writeStructDef(structObj: StructDef, depth: number): string[] {\r\n const parts: string[] = [];\r\n const isInline = this._isInline;\r\n this._isInline = true;\r\n for (const part of structObj.parts) {\r\n const partLines = this.writeObject(part, depth);\r\n parts.push(partLines.join(NEWLINE));\r\n }\r\n const line = `${structObj.name} < ${parts.join(', ')} >`;\r\n this._isInline = isInline; // match C# spacing behaviour\r\n return [line];\r\n }\r\n\r\n private writeOpArray(opList: Op[], depth: number): string[] {\r\n const lines: string[] = [];\r\n lines.push('{');\r\n const isInline = this._isInline;\r\n this._isInline = true; // instructions follow immediately\r\n \r\n let first = true;\r\n for (const op of opList) {\r\n if (first) {\r\n first = false;\r\n } else {\r\n // Check for labels on subsequent instructions\r\n const labelResult = this._referenceManager.tryGetName(op.location);\r\n if (labelResult.found) {\r\n lines.push('');\r\n lines.push(` ${labelResult.referenceName}:`);\r\n }\r\n }\r\n\r\n let opLine = ` ${op.mnem} `;\r\n\r\n if (op.copDef) {\r\n // Handle COP instructions specially\r\n opLine += `[${op.copDef.name}]`;\r\n if (op.operands && op.operands.length > 1) {\r\n const operandStrings: string[] = [];\r\n for (let i = 1; i < op.operands.length; i++) {\r\n const operandLines = this.writeObject(op.operands[i], depth + 1, false);\r\n operandStrings.push(operandLines[0]);\r\n }\r\n opLine += ` ( ${operandStrings.join(', ')} )`;\r\n }\r\n } else if (op.operands && op.operands.length > 0) {\r\n const isBr = op.mnem[0] === 'J' || \r\n op.mode === 'PCRelative' ||\r\n op.mode === 'PCRelativeLong';\r\n\r\n // Regular instruction formatting\r\n const resolvedOperand = this.resolveOperand(op, op.operands[0], isBr);\r\n const format = this._root.addrLookup[op.mode]?.formatString; // || this._root.config.asmFormats?.[op.code.mode];\r\n \r\n if (format) {\r\n let actualFormat = format;\r\n if (op.mode === 'Immediate' && op.size === 3) {\r\n actualFormat = format.replace('X2', 'X4');\r\n }\r\n const resolvedSecondOperand = op.operands.length > 1 ? this.resolveOperand(op, op.operands[1], isBr) : undefined;\r\n opLine += this.formatOperand(actualFormat, [resolvedOperand, resolvedSecondOperand]);\r\n } else {\r\n // Default formatting based on operand type\r\n opLine += this.formatDefaultOperand(resolvedOperand, op.size);\r\n }\r\n }\r\n \r\n lines.push(opLine);\r\n }\r\n \r\n lines.push('}');\r\n this._isInline = isInline; // ensure following object is separated by blank line\r\n return lines;\r\n }\r\n\r\n private formatDefaultOperand(operand: any, size: number): string {\r\n if (typeof operand === 'string') {\r\n return operand; // Already formatted\r\n }\r\n\r\n if (operand && operand instanceof TypedNumber) {\r\n return this.formatTypedNumber(operand);\r\n }\r\n\r\n if (typeof operand === 'number') {\r\n const hexSize = (size - 1) * 2;\r\n const hex = operand.toString(16).toUpperCase().padStart(hexSize, '0');\r\n return `$${hex}`;\r\n }\r\n \r\n return String(operand);\r\n }\r\n\r\n private writeStringWrapper(stringObj: StringWrapper): string[] {\r\n let str = stringObj.string;\r\n \r\n // Process string references\r\n const stringReferenceChars = ['~', '^'];\r\n for (const char of stringReferenceChars) {\r\n let ix = str.indexOf(char);\r\n while (ix >= 0) {\r\n const hexStr = str.substring(ix + 1, ix + 7);\r\n const rawAddr = parseInt(hexStr, 16);\r\n const adrs = new Address((rawAddr >> 16) & 0xFF, rawAddr & 0xFFFF, this._blockReader._root.config.memoryMode);\r\n const addressType = char === '^' ? AddressType.Offset : AddressType.Address;\r\n let name = '';\r\n \r\n if (adrs.isROM) {\r\n name = this._blockReader.resolveName(adrs.toLocation(), addressType, false);\r\n } else if(addressType === AddressType.Offset) {\r\n name = adrs.offset.toString(16).toUpperCase().padStart(4, '0');\r\n } else {\r\n name = adrs.toString();\r\n }\r\n \r\n str = str.replace(str.substring(ix, ix + 7), name);\r\n ix = str.indexOf(char);\r\n }\r\n }\r\n\r\n const refChar = stringObj.type.delimiter;\r\n let marker = stringObj.marker;\r\n \r\n if (marker <= 0) {\r\n const markerResult = this._referenceManager.tryGetMarker(stringObj.location);\r\n marker = markerResult.found ? markerResult.offset || 0 : 0;\r\n }\r\n\r\n if (marker > 0) {\r\n let six = 0;\r\n let mix = 0;\r\n \r\n while (mix < marker) {\r\n if (str[six] === '[') {\r\n const eix = str.indexOf(']', ++six);\r\n const parts = str.substring(six, eix).split(/[,: ]/);\r\n \r\n const cmd = stringObj.type.commands[parts[0]];\r\n if (cmd && (cmd as any).types) {\r\n for (const t of (cmd as any).types) {\r\n switch (t) {\r\n case MemberType.Byte:\r\n mix += 1;\r\n break;\r\n case MemberType.Word:\r\n case MemberType.Offset:\r\n mix += 2;\r\n break;\r\n case MemberType.Address:\r\n case MemberType.Location:\r\n mix += 3;\r\n break;\r\n case MemberType.Binary:\r\n mix += parts.length - 1;\r\n break;\r\n default:\r\n throw new Error('Unsupported member type');\r\n }\r\n }\r\n }\r\n six = eix + 1;\r\n mix++;\r\n } else {\r\n six++;\r\n mix++;\r\n }\r\n }\r\n \r\n str = str.substring(0, six) + '[::]' + str.substring(six);\r\n }\r\n\r\n const sizeParam = stringObj.fixedSize ? `(${stringObj.fixedSize})` : '';\r\n\r\n return [`${refChar}${str}${refChar}${sizeParam}`];\r\n }\r\n\r\n private writeArray(arr: any[], depth: number): string[] {\r\n const lines: string[] = [];\r\n const indent = ' '.repeat(Math.max(0, depth));\r\n const isInline = this._isInline;\r\n lines.push('[');\r\n this._isInline = false; // start elements on their own lines\r\n\r\n for (let i = 0; i < arr.length; i++) {\r\n const objLines = this.writeObject(arr[i], depth + 1, false, true);\r\n for(const line of objLines) {\r\n lines.push(indent + ' ' + line);\r\n }\r\n lines[lines.length - 1] += ` ;${i.toString(16).toUpperCase().padStart(2, '0')}`;\r\n }\r\n\r\n lines.push(indent + ']');\r\n this._isInline = isInline;\r\n return lines;\r\n }\r\n\r\n private writeNumber(num: number): string[] {\r\n // Format numbers based on value and size\r\n if (num <= 0xff) {\r\n // Mirror C# BlockWriter: bytes omit the '$' prefix\r\n return [`#${num.toString(16).toUpperCase().padStart(2, '0')}`];\r\n }\r\n\r\n if (num <= 0xffff) {\r\n return [`#$${num.toString(16).toUpperCase().padStart(4, '0')}`];\r\n }\r\n\r\n return [`#$${num.toString(16).toUpperCase().padStart(6, '0')}`];\r\n }\r\n\r\n private formatTypedNumber(num: TypedNumber): string {\r\n if (typeof num.value === 'number') {\r\n const width = num.size * 2;\r\n const hex = num.value.toString(16).toUpperCase().padStart(width, '0');\r\n return num.size === 1 ? `#${hex}` : `#$${hex}`;\r\n }\r\n\r\n return `#${num.value}`;\r\n }\r\n\r\n private writeTypedNumber(num: TypedNumber): string[] {\r\n return [this.formatTypedNumber(num)];\r\n }\r\n\r\n private formatOperand(format: string, operands: any[]): string {\r\n return format.replace(/\\{(\\d+)(?::([^}]+))?\\}/g, (match, index, formatSpec) => {\r\n const operand = operands[parseInt(index)];\r\n if (operand && typeof operand === 'object' && operand._tag && 'value' in operand) {\r\n const value = operand.value;\r\n if (formatSpec && typeof value === 'number' && formatSpec.startsWith('X')) {\r\n const width = parseInt(formatSpec.substring(1)) || 2;\r\n return value.toString(16).toUpperCase().padStart(width, '0');\r\n }\r\n return String(value);\r\n }\r\n\r\n if (formatSpec && typeof operand === 'number') {\r\n if (formatSpec.startsWith('X')) {\r\n const width = parseInt(formatSpec.substring(1)) || 2;\r\n return operand.toString(16).toUpperCase().padStart(width, '0');\r\n }\r\n }\r\n return String(operand);\r\n });\r\n }\r\n} ","import { RomProcessingConstants } from '../../types/constants';\r\nimport { ChunkFile } from '../../types/files';\r\nimport { MemoryMapMode } from '../../types/addressing';\r\nimport type { DbConfig } from '../../database/config';\r\nimport type { DbRoot } from '../../database/root';\r\nimport { BinType } from '../../types/resources';\r\n\r\n/**\r\n * ROM layout planner\r\n * Converted from ext/GaiaLib/Rom/Rebuild/RomLayout.cs\r\n */\r\nexport class RomLayout {\r\n private static readonly MIN_ACCEPTED_REMAINING = 0x20;\r\n\r\n public readonly unmatchedFiles: ChunkFile[];\r\n private readonly bestResult: number[] = new Array(0x200).fill(0);\r\n private readonly bestSample: number[] = new Array(0x200).fill(0);\r\n\r\n private currentBank = 0;\r\n private currentUpper = false;\r\n private bestDepth = 0;\r\n private bestOffset = 0;\r\n private bestRemain = 0;\r\n private root: DbRoot;\r\n private config: DbConfig;\r\n private sfxPackType: string;\r\n public readonly sfxFiles: ChunkFile[] = [];\r\n\r\n constructor(files: ChunkFile[], root: DbRoot) {\r\n this.root = root;\r\n this.config = root.config;\r\n this.sfxPackType = root.config.sfxPack ?? root.config.sfxType;\r\n this.sfxFiles = this.sfxPackType !== 'Individual' ? files.filter(x => x.type.type === 'Sound')\r\n .sort((a, b) => {\r\n const aId = parseInt(a.name.substring(a.name.length - 2, a.name.length), 16);\r\n const bId = parseInt(b.name.substring(b.name.length - 2, b.name.length), 16);\r\n return aId - bId;\r\n }) : [];\r\n \r\n // Filter out zero-size files and order: assembly first, then by size desc\r\n this.unmatchedFiles = files.filter(x => (x.size || 0) > 0)\r\n .filter(x => this.sfxPackType === 'Individual' || x.type.type !== 'Sound')\r\n .sort((a, b) => {\r\n const aAsm = a.parts ? 0 : 1;\r\n const bAsm = b.parts ? 0 : 1;\r\n if (aAsm !== bAsm) return aAsm - bAsm;\r\n if (b.size !== a.size) return b.size - a.size;\r\n if (a.location !== b.location) return a.location - b.location;\r\n return a.name.localeCompare(b.name);\r\n });\r\n }\r\n\r\n public organize(): number {\r\n let stripeSfx = false;\r\n let page: number;\r\n const maxPages = this.config.memoryMode === MemoryMapMode.Hi ? 0x80 \r\n : this.config.memoryMode === MemoryMapMode.ExHi ? 0x100\r\n : 0x40;\r\n for (page = 0; page < maxPages; page++) {\r\n if (this.unmatchedFiles.length === 0) break;\r\n let start = page << 15; // 0x8000 per page\r\n let remain = RomProcessingConstants.PAGE_SIZE;\r\n \r\n if(start <= this.config.sfxLocation && start + remain > this.config.sfxLocation) {\r\n const gap = this.config.sfxLocation - start;\r\n //if(gap) do something\r\n\r\n if(this.sfxPackType === 'Sequential') {\r\n let offset = 0;\r\n for(const file of this.sfxFiles) {\r\n file.location = start + offset;\r\n console.log(` ${file.location.toString(16).toUpperCase().padStart(6, '0')}: ${file.name}`);\r\n offset += file.size;\r\n if(offset & RomProcessingConstants.PAGE_SIZE) {\r\n offset &= 0x7FFF;\r\n console.log(`Page ${start.toString(16).toUpperCase().padStart(6, '0')} matched with SFX files 0 remaining`);\r\n start += RomProcessingConstants.PAGE_SIZE;\r\n page++;\r\n }\r\n }\r\n console.log(`Page ${start.toString(16).toUpperCase().padStart(6, '0')} matched with SFX files ${remain} remaining`);\r\n start += offset;\r\n remain = RomProcessingConstants.PAGE_SIZE - offset;\r\n } else if(this.sfxPackType === 'Striped') {\r\n stripeSfx = true;\r\n }\r\n }\r\n\r\n if ((page === 0 && this.config.memoryMode === MemoryMapMode.Lo) ||\r\n (page === 1 && this.config.memoryMode === MemoryMapMode.Hi)) {\r\n remain -= RomProcessingConstants.SNES_HEADER_SIZE;\r\n }\r\n\r\n if(stripeSfx) {\r\n let offset = 0;\r\n while(remain > 0 && this.sfxFiles.length) {\r\n const file = this.sfxFiles.shift();\r\n if(!file) continue;\r\n file.location = start + offset;\r\n console.log(` ${file.location.toString(16).toUpperCase().padStart(6, '0')}: ${file.name}`);\r\n offset += file.size;\r\n if(offset & RomProcessingConstants.PAGE_SIZE) {\r\n offset &= 0x7FFF;\r\n console.log(`Page ${start.toString(16).toUpperCase().padStart(6, '0')} matched with SFX files 0 remaining`);\r\n start += RomProcessingConstants.PAGE_SIZE;\r\n page++;\r\n\r\n if(offset) {\r\n const newFile = new ChunkFile(file.name + \"_2\", file.size, file.location, Object.values(this.root.fileTypes).find(x => x.type === BinType.Binary)!);\r\n const end = file.rawData!.length - offset;\r\n newFile.rawData = file.rawData!.slice(end);\r\n newFile.size = newFile.rawData.length;\r\n this.sfxFiles.unshift(newFile);\r\n file.rawData = file.rawData!.slice(0, end);\r\n file.size -= offset;\r\n offset = 0;\r\n }\r\n remain = RomProcessingConstants.PAGE_SIZE;\r\n break;\r\n } else {\r\n remain -= file.size;\r\n }\r\n }\r\n start += offset;\r\n if(!this.sfxFiles.length) {\r\n stripeSfx = false;\r\n }\r\n\r\n }\r\n \r\n this.currentUpper = this.config.memoryMode === MemoryMapMode.Lo || (page & 1) !== 0;\r\n this.currentBank = this.config.memoryMode === MemoryMapMode.Lo ? page : (page >> 1);\r\n this.bestDepth = 0;\r\n this.bestRemain = remain;\r\n this.bestOffset = 0;\r\n\r\n // Pass 1: assembly preferred in upper banks\r\n this.testDepth(0, 0, remain, this.currentUpper);\r\n\r\n // Pass 2: if upper, also try binary-only fill\r\n if (this.currentUpper) {\r\n this.bestOffset = this.bestDepth;\r\n this.testDepth(0, this.bestDepth, this.bestRemain, false);\r\n }\r\n\r\n // Assign positions for best selection\r\n let position = start;\r\n for (let i = 0; i < this.bestDepth;) {\r\n const file = this.unmatchedFiles[this.bestResult[i++]];\r\n file.location = position;\r\n console.log(` ${position.toString(16).toUpperCase().padStart(6, '0')}: ${file.name}`);\r\n position += file.size;\r\n }\r\n\r\n console.log(`Page ${start.toString(16).toUpperCase().padStart(6, '0')} matched with ${this.bestDepth} files ${this.bestRemain} remaining`);\r\n // Commit: remove placed files from queue\r\n this.commitPage();\r\n }\r\n\r\n if (this.unmatchedFiles.length > 0) {\r\n const names = this.unmatchedFiles.map(x => x.name).join('\\r\\n');\r\n throw new Error(`Unable to match ${this.unmatchedFiles.length} files\\r\\n${names}`);\r\n }\r\n\r\n return page;\r\n }\r\n\r\n private testDepth(startIndex: number, depth: number, remain: number, asmMode: boolean): boolean {\r\n for (let fileIndex = startIndex; fileIndex < this.unmatchedFiles.length; fileIndex++) {\r\n const file = this.unmatchedFiles[fileIndex];\r\n\r\n const fileSize = file.size || 0;\r\n if (fileSize > remain) continue;\r\n\r\n // Assembly preference and constraints\r\n if (file.parts) {\r\n if (!asmMode) {\r\n if (!this.currentUpper || ((file.bank ?? -1) >= 0)) continue;\r\n } else if (file.bank !== this.currentBank) {\r\n continue;\r\n }\r\n } else if (asmMode) {\r\n continue;\r\n } else if (file.upper && !this.currentUpper) {\r\n continue;\r\n }\r\n\r\n // Skip if already selected in first pass window\r\n let inList = false;\r\n for (let y = this.bestOffset; --y >= 0;) {\r\n if (this.bestResult[y] === fileIndex) {\r\n inList = true;\r\n break;\r\n }\r\n }\r\n if (inList) continue;\r\n\r\n // Try this file at current depth\r\n this.bestSample[depth] = fileIndex;\r\n const newRemain = remain - fileSize;\r\n\r\n if (newRemain < this.bestRemain) {\r\n this.bestRemain = newRemain;\r\n this.bestDepth = depth + 1;\r\n for (let i = this.bestOffset; i < this.bestDepth; i++) {\r\n this.bestResult[i] = this.bestSample[i];\r\n }\r\n }\r\n\r\n if (newRemain < RomLayout.MIN_ACCEPTED_REMAINING) return true;\r\n\r\n if (this.testDepth(fileIndex + 1, depth + 1, newRemain, asmMode)) return true;\r\n }\r\n return true;\r\n }\r\n\r\n private commitPage(): void {\r\n if (this.bestOffset > 0) {\r\n for (let i = this.bestDepth; --i >= 0;) {\r\n let lastY = 0;\r\n let lastX = 0;\r\n let y = 0;\r\n for (let x = this.bestDepth; --x >= 0;) {\r\n y = this.bestResult[x];\r\n if (y > lastY) {\r\n lastY = y;\r\n lastX = x;\r\n }\r\n }\r\n this.bestResult[lastX] = 0;\r\n this.unmatchedFiles.splice(lastY, 1);\r\n }\r\n } else {\r\n for (let i = this.bestDepth; --i >= 0;) {\r\n this.unmatchedFiles.splice(this.bestResult[i], 1);\r\n }\r\n }\r\n }\r\n}\r\n\r\n\r\n\r\n","import { BinType } from '../../types/resources';\r\nimport { ChunkFileUtils, type ChunkFile } from '../../types/files';\r\nimport { RomLayout } from './layout';\r\nimport { RomWriter } from './writer';\r\nimport { Assembler } from '../..';\r\nimport { DbRoot } from '../../database';\r\nimport { AsmBlock } from '../../types/assembly';\r\n\r\n/**\r\n * ROM rebuild processor\r\n * Converted from ext/GaiaLib/Rom/Rebuild/RomProcessor.cs\r\n */\r\nexport class RomProcessor {\r\n private readonly writer: RomWriter;\r\n\r\n constructor(writer: RomWriter) {\r\n this.writer = writer;\r\n }\r\n\r\n public async repack(allFiles: ChunkFile[]): Promise<Map<string, number>> {\r\n // Discover files\r\n //const allFiles = await this.discoverFiles(this.writer._projectRoot.baseDir);\r\n\r\n const patches : ChunkFile[] = [];\r\n const asmFiles : ChunkFile[] = [];\r\n const compression = this.writer.root.compression;\r\n const canCompress = !!compression;\r\n const conditionFiles : string[] = [];\r\n\r\n for (const file of allFiles) {\r\n if (file.type.type === \"Patch\") {\r\n patches.push(file);\r\n } else if (file.type.type !== \"Assembly\") {\r\n if(file.compressed === true && canCompress) {\r\n if(this.writer.root.config.uncompress){\r\n file.compressed = false;\r\n } else {\r\n let newData = compression!.compact(file.rawData!, file.type.header);\r\n if(file.type.header) newData = new Uint8Array([...file.rawData!.slice(0, file.type.header), ...newData]);\r\n file.rawData = newData;\r\n file.size = newData.length;\r\n }\r\n }\r\n continue;\r\n }\r\n \r\n asmFiles.push(file);\r\n conditionFiles.push(file.name);\r\n }\r\n\r\n for(const file of asmFiles) {\r\n const assembler = new Assembler(this.writer.root, file.textData!, conditionFiles);\r\n const { blocks, includes, reqBank } = assembler.parseAssembly();\r\n file.parts = blocks;\r\n file.includes = includes;\r\n file.bank = reqBank ?? void 0;\r\n }\r\n\r\n // const patches = allFiles.filter(x => x.type.type === 'Patch');\r\n // const asmFiles = allFiles.filter(x => !!x.parts);\r\n\r\n // //Assemble code that hasn't been assembled yet\r\n // for(const asm of asmFiles) {\r\n // if(!asm.parts) {\r\n // const assembler = new Assembler(this.writer.root, asm.textData!);\r\n // const { blocks, includes, reqBank } = assembler.parseAssembly();\r\n // asm.parts = blocks;\r\n // asm.includes = includes;\r\n // asm.bank = reqBank ?? undefined;\r\n // }\r\n // }\r\n\r\n // Assembly processing now happens in project.ts via ChunkBlockReader.analyzeAndResolveChunks()\r\n // This provides comprehensive cross-referencing and object graph generation\r\n\r\n // Apply patches to asm blocks\r\n RomProcessor.applyPatches(asmFiles, patches);\r\n\r\n // Calculate ASM sizes\r\n for (const file of allFiles) {\r\n ChunkFileUtils.calculateSize(file);\r\n }\r\n\r\n // Assign locations\r\n const layout = new RomLayout(allFiles, this.writer.root);\r\n const pages = layout.organize();\r\n\r\n // Rebase assemblies\r\n for (const file of asmFiles) {\r\n ChunkFileUtils.rebase(file);\r\n }\r\n\r\n const masterLookup = new Map<string, number>();\r\n\r\n // Build include lookup map per asm file\r\n for (const f of asmFiles) {\r\n const includeBlocks = asmFiles\r\n .filter(x => f.includes?.has(x.name.toUpperCase()))\r\n .flatMap(x => x.parts!)\r\n .filter(b => !!b.label);\r\n\r\n f.includeLookup = new Map<string, AsmBlock>();\r\n\r\n //Add labels from include blocks\r\n for (const b of includeBlocks) {\r\n if (b.label) f.includeLookup.set(b.label.toUpperCase(), b);\r\n }\r\n\r\n //Add labels from current file\r\n for (const b of f.parts!) {\r\n if(b.label) {\r\n const nameUpper = b.label.toUpperCase();\r\n masterLookup.set(nameUpper, b.location);\r\n f.includeLookup.set(nameUpper, b);\r\n }\r\n }\r\n }\r\n\r\n // Create block lookup for resolving labels to locations\r\n const fileLookup = new Map<string, number>();\r\n for (const f of allFiles) fileLookup.set(f.name.toUpperCase(), f.location);\r\n \r\n //Allocate memory for the ROM\r\n this.writer.allocate(pages);\r\n\r\n // Write all files\r\n for (const file of allFiles) {\r\n await this.writer.writeFile(file, fileLookup);\r\n }\r\n\r\n return masterLookup;\r\n }\r\n\r\n public static applyPatches(asmFiles: ChunkFile[], patches: ChunkFile[]): void {\r\n for (const patch of patches.filter(x => x.includes && x.includes.size > 0)) {\r\n let file: ChunkFile | null = null;\r\n let dstIx = -1;\r\n const inc = asmFiles.filter(x => patch.includes!.has(x.name.toUpperCase()));\r\n for (let ix = 0; patch.parts && ix < patch.parts.length;) {\r\n const block = patch.parts[ix];\r\n let match: any = null;\r\n if (block.label) { \r\n for (const i of inc) {\r\n if (!i.parts) continue;\r\n for (let y = 0; y < i.parts.length; y++) {\r\n const check = i.parts[y];\r\n if (check.label === block.label) {\r\n file = i; \r\n dstIx = y; \r\n match = check;\r\n break;\r\n }\r\n }\r\n }\r\n }\r\n if (match) {\r\n file!.parts![dstIx++] = block;\r\n } else if (dstIx >= 0) {\r\n file!.parts!.splice(dstIx++, 0, block);\r\n } else { ix++; continue; }\r\n file!.includes = file!.includes || new Set();\r\n file!.includes.add(patch.name.toUpperCase());\r\n patch.parts!.splice(ix, 1);\r\n }\r\n }\r\n }\r\n}\r\n\r\n\r\n","import { \r\n BinType, \r\n AddressType, \r\n Address, \r\n RomProcessingConstants,\r\n ChunkFile, \r\n AsmBlock, \r\n StringMarker,\r\n TableEntry,\r\n Byte,\r\n Word,\r\n Long,\r\n TypedNumber\r\n} from '../../types';\r\nimport { DbEntryPoint, DbHeader, DbRoot } from '../../database';\r\nimport { RomProcessor as RebuildProcessor } from './processor';\r\nimport { Op } from '../../types/assembly';\r\nimport { CpuMode, MemoryMapMode } from '../../types/addressing';\r\n//import { ConditionBlock } from './assembler';\r\n/**\r\n * ROM writer (binary)\r\n * Converted from ext/GaiaLib/Rom/Rebuild/RomWriter.cs (subset: binary write only)\r\n */\r\nexport class RomWriter {\r\n public bpsPath?: string;\r\n public outBuffer?: Uint8Array;\r\n private romSize? : number;\r\n public readonly root: DbRoot;\r\n\r\n constructor(root: DbRoot) {\r\n this.root = root;\r\n }\r\n\r\n public async repack(files: ChunkFile[]): Promise<Uint8Array> {\r\n const processor = new RebuildProcessor(this);\r\n const masterLookup = await processor.repack(files);\r\n\r\n this.writeHeaders(masterLookup);\r\n\r\n //await this.generatePatch();\r\n return this.outBuffer!;\r\n }\r\n\r\n public allocate(pages: number): void {\r\n const size = pages * RomProcessingConstants.PAGE_SIZE;\r\n let bits = 0;\r\n let target = 1 << 10; // 1KB\r\n\r\n while(target < size) {\r\n target <<= 1;\r\n bits++;\r\n }\r\n\r\n this.romSize = bits;\r\n this.outBuffer = new Uint8Array(target);\r\n }\r\n\r\n public writeHeaders(masterLookup: Map<string, number>): void {\r\n const values = this.prepareHeaderValues();\r\n for (const header of this.root.headers) {\r\n if(header.condition && !eval(header.condition)) continue;\r\n this.writeHeader(header, values, masterLookup);\r\n }\r\n this.writeChecksum(values);\r\n }\r\n\r\n public prepareHeaderValues(): any {\r\n const values = { ...this.root.config } as any;\r\n values.romSize = this.romSize;\r\n values.checksum = 0;\r\n values.compliment = 0xFFFF;\r\n values.mapMode = 0x20 \r\n | (values.cpuMode === CpuMode.Fast ? 0x10 : 0x00)\r\n | (values.memoryMode === MemoryMapMode.Hi ? 1 : values.memoryMode === MemoryMapMode.ExHi ? 5 : 0);\r\n return values;\r\n }\r\n\r\n\r\n public writeHeader(header: DbHeader, values: any, masterLookup: Map<string, number>): void {\r\n const buf = this.outBuffer!;\r\n \r\n let pos = new Address(header.bank, header.address, this.root.config.memoryMode).toLocation();\r\n\r\n for (const part of header.parts) {\r\n let type = part.type;\r\n let value = part.value ?? values[part.name] ?? (type === 'string' ? '' : 0);\r\n let size = part.size;\r\n\r\n if(!size) {\r\n if(!type) {\r\n //Try to infer the type/size from the value\r\n if(typeof value === 'string') throw new Error(`String size for ${part.name} is not specified`);\r\n if(typeof value === 'number') {\r\n if(value <= 0xFF) {\r\n size = 1;\r\n type = 'byte';\r\n }\r\n else {\r\n size = 2;\r\n type = 'word';\r\n }\r\n }\r\n } else {\r\n switch(type) {\r\n case 'byte': size = 1; break;\r\n case 'word': case 'entry': size = 2; break;\r\n case 'string': throw new Error(`String size for ${part.name} is not specified`); break;\r\n default: throw new Error(`Invalid type ${type} for ${part.name}`);\r\n }\r\n }\r\n }\r\n\r\n switch(part.type) {\r\n case 'string':\r\n value = value.toString();\r\n value = value.length > size ? value.substring(0, size) : value.padEnd(size, ' ');\r\n this.writeAscii(value, pos);\r\n break;\r\n\r\n case 'byte':\r\n buf[pos] = value & 0xFF;\r\n break;\r\n\r\n case 'entry':\r\n let location = 0;\r\n if(typeof value === 'string') {\r\n location = value === '' ? 0 : masterLookup.get(value.toUpperCase()) ?? 0;\r\n } else if(typeof value === 'number') {\r\n location = value;\r\n }\r\n value = location;\r\n\r\n case 'word':\r\n buf[pos] = value & 0xFF;\r\n buf[pos + 1] = (value >> 8) & 0xFF;\r\n break;\r\n\r\n }\r\n\r\n part.value = value;\r\n part.size = size;\r\n part.type = type;\r\n\r\n pos += size;\r\n }\r\n\r\n // //let pos = this.root.config.memoryMode === MemoryMapMode.Lo ? 0x7FB0 : 0xFFB0;\r\n // this.writeAscii(this.makerCode.padEnd(6, ' '), pos); \r\n // pos += 6;\r\n // for (let i = 0; i < 10; i++) buf[pos++] = 0;\r\n // this.writeAscii(this.cartName.toUpperCase().padEnd(21, ' '), pos); \r\n // pos += 21;\r\n // buf[pos++] = 0x20 // map mode\r\n // | (this.root.config.cpuMode === CpuMode.Fast ? 0x10 : 0x00)\r\n // | (this.root.config.memoryMode === MemoryMapMode.Hi ? 1 : this.root.config.memoryMode === MemoryMapMode.ExHi ? 5 : 0);\r\n // buf[pos++] = this.root.config.chipset; // chipset\r\n // buf[pos++] = this.romSize!; // ROM size\r\n // buf[pos++] = this.root.config.ramSize; // RAM size\r\n // buf[pos++] = 0x01; // country\r\n // buf[pos++] = 0x33; // dev id\r\n // buf[pos++] = 0x00; // version\r\n }\r\n\r\n public writeChecksum(values: any): void {\r\n const buf = this.outBuffer!;\r\n\r\n let sum = 0;\r\n for (let i = 0; i < buf.length; i++) sum += buf[i];\r\n\r\n const comp = ~sum;\r\n\r\n for(const header of this.root.headers) {\r\n if(header.condition && !eval(header.condition)) continue;\r\n let pos = new Address(header.bank, header.address, this.root.config.memoryMode).toLocation();\r\n for(const part of header.parts) {\r\n if(part.name === 'checksum') {\r\n buf[pos] = sum & 0xFF;\r\n buf[pos + 1] = (sum >> 8) & 0xFF;\r\n } else if(part.name === 'compliment') {\r\n buf[pos] = comp & 0xFF;\r\n buf[pos + 1] = (comp >> 8) & 0xFF;\r\n }\r\n pos += part.size;\r\n }\r\n }\r\n \r\n // const buf = this.outBuffer!;\r\n // let pos = new Address(0, 0xFFDC, this.root.config.memoryMode).toLocation();\r\n \r\n // //Zero out the checksum location\r\n // buf[pos] = 0xFF;\r\n // buf[pos + 1] = 0xFF;\r\n // buf[pos + 2] = 0;\r\n // buf[pos + 3] = 0;\r\n\r\n // // checksum\r\n // let sum = 0;\r\n // for (let i = 0; i < buf.length; i++) sum += buf[i];\r\n\r\n // // complement at 0xFFDC\r\n // const comp = ~sum;\r\n // buf[pos] = comp & 0xFF;\r\n // buf[pos + 1] = (comp >> 8) & 0xFF;\r\n\r\n // // checksum at 0xFFDE\r\n // buf[pos + 2] = sum & 0xFF;\r\n // buf[pos + 3] = (sum >> 8) & 0xFF;\r\n }\r\n\r\n // private async generatePatch(): Promise<void> {\r\n // const flips = this._projectRoot.flipsPath;\r\n // if (!flips) return;\r\n // if (typeof process === 'undefined' || !process.versions?.node) return;\r\n // const { spawn } = await import('child_process');\r\n // const { resolve } = await import('path');\r\n // this.bpsPath = `${this._projectRoot.baseDir}/${this._projectRoot.name}.bps`;\r\n // await new Promise<void>((resolvePromise) => {\r\n // const p = spawn(flips, ['--create', '--bps', `${this._projectRoot.romPath}`, `${this.romPath}`, `${this.bpsPath}`], {\r\n // stdio: ['ignore', 'pipe', 'pipe']\r\n // });\r\n // p.on('close', () => resolvePromise());\r\n // });\r\n // }\r\n\r\n public writeEntryPoints(asmFiles: ChunkFile[]): void {\r\n const buf = this.outBuffer!;\r\n \r\n // Entry point fixups\r\n const entryBlocks = (asmFiles\r\n .filter(x => (x.bank ?? -1) === 0)\r\n .flatMap(x => x.parts || [])\r\n .filter(b => !!b.label)) as { label?: string; location: number }[];\r\n\r\n for (const ep of this.root.config.entryPoints) {\r\n const match = entryBlocks.find(b => b.label === ep.name);\r\n if (match) {\r\n let location = match.location;\r\n if(this.root.config.memoryMode === MemoryMapMode.Lo) location += RomProcessingConstants.PAGE_SIZE;\r\n buf[ep.location] = location & 0xFF;\r\n buf[ep.location + 1] = (location >> 8) & 0xFF;\r\n }\r\n }\r\n }\r\n\r\n // public writeTransform(location: number, value: number, size?: number): void {\r\n // const buf = this.outBuffer!;\r\n\r\n // // Determine size based on value range if not explicitly provided\r\n // if (size === undefined) {\r\n // if (value <= 0xFF) {\r\n // size = 1; // byte\r\n // } else if (value <= 0xFFFF) {\r\n // size = 2; // ushort \r\n // } else if (value <= 0xFFFFFF) {\r\n // size = 3; // uint (3 bytes)\r\n // } else {\r\n // size = 4; // full uint (4 bytes, though C# version only uses 3)\r\n // }\r\n // }\r\n\r\n // // Write bytes based on size\r\n // switch (size) {\r\n // case 1: // byte\r\n // buf[location] = value & 0xFF;\r\n // break;\r\n // case 2: // ushort\r\n // buf[location] = value & 0xFF;\r\n // buf[location + 1] = (value >> 8) & 0xFF;\r\n // break;\r\n // case 3: // uint (3 bytes as per C# version)\r\n // buf[location] = value & 0xFF;\r\n // buf[location + 1] = (value >> 8) & 0xFF;\r\n // buf[location + 2] = (value >> 16) & 0xFF;\r\n // break;\r\n // case 4: // full uint\r\n // buf[location] = value & 0xFF;\r\n // buf[location + 1] = (value >> 8) & 0xFF;\r\n // buf[location + 2] = (value >> 16) & 0xFF;\r\n // buf[location + 3] = (value >> 24) & 0xFF;\r\n // break;\r\n // default:\r\n // throw new Error(`Invalid size ${size} for writeTransform`);\r\n // }\r\n // }\r\n\r\n public async writeFile(file: ChunkFile, fileLookup: Map<string, number>): Promise<number> {\r\n const start = file.location;\r\n let pos = start;\r\n const buf = this.outBuffer!;\r\n\r\n if (file.rawData) {\r\n // Write type-specific headers\r\n const data = file.rawData;\r\n let remain = file.size;\r\n let srcPos = 0;\r\n\r\n if (file.compressed !== true) {\r\n if (file.type.header === -2) {\r\n remain -= 2;\r\n buf[pos++] = remain & 0xFF;\r\n buf[pos++] = (remain >> 8) & 0xFF;\r\n } else if (file.type.header > 0) {\r\n remain -= file.type.header;\r\n for (let i = 0; i < file.type.header; i++) buf[pos++] = data[srcPos++];\r\n }\r\n }\r\n\r\n //Write null compression header\r\n if (file.compressed === false) {\r\n remain -= 2;\r\n const size = (0 - remain) & 0xFFFF;\r\n buf[pos++] = size & 0xFF;\r\n buf[pos++] = (size >> 8) & 0xFF;\r\n }\r\n\r\n // Copy the rest\r\n while (remain > 0) {\r\n buf[pos++] = data[srcPos++];\r\n remain--;\r\n }\r\n } else {\r\n // Handle assembly parts\r\n if (file.parts && file.parts.length > 0) {\r\n // For safety, ensure first block location matches file location when present\r\n if (file.parts[0].location !== file.location && (file.location || 0) !== 0) {\r\n throw new Error('Assembly was not based properly');\r\n }\r\n \r\n // Parse assembly parts\r\n this.parseAssembly(file.parts, fileLookup, file.includeLookup!);\r\n }\r\n }\r\n\r\n return pos - start;\r\n }\r\n\r\n // No address mapping required: layout assigns absolute file offsets\r\n\r\n private writeAscii(text: string, pos: number): void {\r\n const buf = this.outBuffer!;\r\n for (let i = 0; i < text.length; i++) buf[pos + i] = text.charCodeAt(i) & 0xFF;\r\n }\r\n\r\n /**\r\n * Parse assembly blocks and write binary data to output buffer\r\n * Converted from ext/GaiaLib/Rom/Rebuild/RomWriter.cs ParseAssembly method\r\n */\r\n private parseAssembly(blocks: AsmBlock[], fileLookup: Map<string, number>, includeLookup: Map<string, AsmBlock>): void {\r\n if (!blocks) {\r\n throw new Error('Assembly has not been parsed');\r\n }\r\n\r\n const buf = this.outBuffer!;\r\n\r\n let bix = 0;\r\n // let inCondition = false;\r\n // let exitCondition = false;\r\n\r\n for (const block of blocks) {\r\n\r\n // if(inCondition) {\r\n // if(block instanceof ConditionBlock) {\r\n // if(exitCondition) continue;\r\n // if(block.condition) {\r\n // if(!fileLookup.has(block.condition) && !includeLookup.has(block.condition)) continue;\r\n // exitCondition = true; //If condition passes, set exit flag\r\n // } else inCondition = false;\r\n // } else {\r\n // inCondition = false;\r\n // exitCondition = false;\r\n // }\r\n // } else if(block instanceof ConditionBlock) {\r\n // inCondition = true;\r\n // exitCondition = false;\r\n // if(!fileLookup.has(block.condition) && !includeLookup.has(block.condition)) continue;\r\n // exitCondition = true;\r\n // }\r\n\r\n let oldPos: number | null = null;\r\n let position = block.location; // Always start at block's absolute location\r\n \r\n // Note: C# version had position management logic, but we always use block.location\r\n\r\n const objList = block.objList;\r\n let oix = 0;\r\n let opos = 0;\r\n\r\n // Process each object in the block's object list\r\n const processObject = (obj: unknown, parentOp?: Op): void => {\r\n let currentObj = obj;\r\n\r\n while (true) { // Top: label equivalent\r\n if (Array.isArray(currentObj)) {\r\n for (const obj of currentObj) {\r\n processObject(obj, parentOp);\r\n }\r\n break;\r\n } else if (currentObj instanceof TableEntry) {\r\n currentObj = currentObj.object;\r\n continue;\r\n } else if (currentObj instanceof Op) {\r\n const op = currentObj as Op;\r\n buf[position++] = op.code & 0xFF;\r\n opos += op.size;\r\n\r\n for (const operand of op.operands) {\r\n processObject(operand, op);\r\n }\r\n break;\r\n } else if (currentObj instanceof Uint8Array) {\r\n const arr = currentObj as Uint8Array;\r\n for (let i = 0; i < arr.length; i++) {\r\n buf[position + i] = arr[i];\r\n }\r\n position += arr.length;\r\n opos += arr.length;\r\n break;\r\n } else if (typeof currentObj === 'string') {\r\n const str = currentObj as string;\r\n let label = str;\r\n\r\n let ix = 0;\r\n while (ix < label.length && RomProcessingConstants.ADDRESS_SPACE.includes(label[ix])) {\r\n ix++;\r\n }\r\n\r\n if (ix > 0) {\r\n label = label.substring(ix);\r\n }\r\n\r\n let loc: number;\r\n const isRelative = parentOp && \r\n (parentOp.mode === 'PCRelative' || \r\n parentOp.mode === 'PCRelativeLong');\r\n\r\n const operatorIdx = this.indexOfAny(label, RomProcessingConstants.OPERATORS);\r\n let offset: number | null = null;\r\n let useMarker = false;\r\n\r\n if (operatorIdx > 0) {\r\n if (label[operatorIdx + 1] === 'M') {\r\n useMarker = true;\r\n } else {\r\n offset = parseInt(label.substring(operatorIdx + 1), 16);\r\n if (label[operatorIdx] === '-') {\r\n offset = -offset;\r\n }\r\n }\r\n label = label.substring(0, operatorIdx);\r\n }\r\n\r\n // Search local labels first\r\n const labelUpper = label.toUpperCase();\r\n let target: AsmBlock | null = null;\r\n\r\n if(includeLookup.has(labelUpper)) {\r\n target = includeLookup.get(labelUpper)!;\r\n loc = target.location;\r\n } else if(fileLookup.has(labelUpper)) {\r\n loc = fileLookup.get(labelUpper)!;\r\n } else {\r\n // Handle direct hex values\r\n if (label.startsWith('#')) {\r\n label = label.substring(1);\r\n }\r\n if (label.startsWith('$')) {\r\n label = label.substring(1);\r\n }\r\n\r\n if (isRelative && label.length > 4) {\r\n throw new Error(`Invalid relative operand '${label}'`);\r\n //const off = parseInt(label, 16) - (block.location + opos);\r\n //currentObj = parentOp?.size === 2 ? (off & 0xFF) : (off & 0xFFFF);\r\n //continue; // goto Top\r\n } else {\r\n let num: number;\r\n switch (label.length) {\r\n case 1:\r\n case 2:\r\n currentObj = new Byte(parseInt(label, 16));\r\n continue;\r\n case 3:\r\n case 4:\r\n currentObj = new Word(parseInt(label, 16));\r\n continue;\r\n case 5:\r\n case 6:\r\n currentObj = new Long(parseInt(label, 16));\r\n continue;\r\n default:\r\n throw new Error(`Invalid operand '${label}'`);\r\n }\r\n }\r\n }\r\n\r\n let type = isRelative ? (parentOp?.size === 3 ? AddressType.WRelative : AddressType.Relative) : Address.typeFromCode(str[0]);\r\n if (type === AddressType.Unknown) {\r\n type = parentOp?.size === 4 ? AddressType.Address\r\n : parentOp?.size === 2 ? AddressType.Unknown : AddressType.Offset;\r\n }\r\n\r\n if (isRelative) {\r\n loc -= block.location + opos;\r\n if (type === AddressType.Unknown && !(loc < 0x80 || loc >= 0x3FFF80)) {\r\n throw new Error('Relative out of range');\r\n }\r\n }\r\n\r\n if (offset !== null) {\r\n loc += offset;\r\n } else if (useMarker && target instanceof AsmBlock) {\r\n let markerOffset = 0;\r\n for (const part of target.objList) {\r\n if (this.isStringMarker(part)) {\r\n loc += markerOffset;\r\n break;\r\n } else {\r\n markerOffset += RomProcessingConstants.getSize(part);\r\n }\r\n }\r\n }\r\n\r\n if(!isRelative && type !== AddressType.Location) {\r\n const address = Address.fromLocation(loc, this.root.config.memoryMode, this.root.config.cpuMode);\r\n loc = address.toInt();\r\n }\r\n\r\n switch (type) {\r\n case AddressType.Offset:\r\n case AddressType.WRelative:\r\n currentObj = new Word(loc);\r\n continue;\r\n case AddressType.Bank:\r\n currentObj = new Byte(loc >> 16);\r\n continue;\r\n case AddressType.WBank:\r\n currentObj = new Word(loc >> 16);\r\n continue;\r\n case AddressType.Address:\r\n case AddressType.Location:\r\n currentObj = new Long(loc);\r\n continue;\r\n case AddressType.Unknown:\r\n case AddressType.Relative:\r\n default:\r\n currentObj = new Byte(loc);\r\n continue;\r\n }\r\n \r\n } else if (currentObj instanceof TypedNumber) {\r\n let value = currentObj.value;\r\n for (let i = 0; i < currentObj.size; i++) {\r\n buf[position++] = value & 0xFF;\r\n value >>= 8;\r\n }\r\n break;\r\n } else if (typeof currentObj === 'number') {\r\n const num = currentObj as number;\r\n const size = parentOp?.size ?? 0;\r\n \r\n if (num <= 0xFF && size <= 2) {\r\n // byte\r\n buf[position] = num & 0xFF;\r\n position++;\r\n } else if (num <= 0xFFFF && size <= 3) {\r\n // ushort\r\n buf[position] = num & 0xFF;\r\n buf[position + 1] = (num >> 8) & 0xFF;\r\n position += 2;\r\n } else if (num <= 0xFFFFFF && size <= 4) {\r\n // 3-byte\r\n buf[position] = num & 0xFF;\r\n buf[position + 1] = (num >> 8) & 0xFF;\r\n buf[position + 2] = (num >> 16) & 0xFF;\r\n position += 3;\r\n } else {\r\n // 4-byte\r\n buf[position] = num & 0xFF;\r\n buf[position + 1] = (num >> 8) & 0xFF;\r\n buf[position + 2] = (num >> 16) & 0xFF;\r\n buf[position + 3] = (num >> 24) & 0xFF;\r\n position += 4;\r\n }\r\n break;\r\n } else if (this.isStringMarker(currentObj)) {\r\n // StringMarker - no operation needed\r\n break;\r\n } else {\r\n throw new Error(`Unable to process '${currentObj}'`);\r\n }\r\n }\r\n };\r\n\r\n for (const obj of objList) {\r\n oix++;\r\n processObject(obj);\r\n }\r\n\r\n // Position management no longer needed since we use absolute locations\r\n\r\n bix++;\r\n }\r\n }\r\n\r\n /**\r\n * Helper method to find index of any character from an array in a string\r\n */\r\n private indexOfAny(str: string, chars: string[]): number {\r\n for (let i = 0; i < str.length; i++) {\r\n if (chars.includes(str[i])) {\r\n return i;\r\n }\r\n }\r\n return -1;\r\n }\r\n\r\n /**\r\n * Helper method to check if an object is a StringMarker\r\n */\r\n private isStringMarker(obj: unknown): obj is StringMarker {\r\n return typeof obj === 'object' && obj !== null && 'offset' in obj;\r\n }\r\n\r\n private isTableEntry(obj: unknown): obj is TableEntry {\r\n return typeof obj === 'object' && obj !== null && 'location' in obj && 'object' in obj;\r\n }\r\n}\r\n\r\n\r\n","import { DbRoot, DbStringCommand, DbStringLayer, DbStringType } from '../../database';\r\nimport { MemberType, StringMarker } from '../../types';\r\nimport type { Assembler } from './assembler';\r\n\r\n/**\r\n * String processor for assembly parsing\r\n * Converted from GaiaLib/Rom/Rebuild/StringProcessor.cs\r\n */\r\nexport class StringProcessor {\r\n private memBuffer: number[] = [];\r\n private totalSize: number = 0;\r\n private fixedStr: number = 0;\r\n private readonly context: Assembler;\r\n private readonly root: DbRoot;\r\n private readonly stringCharLookup: Record<string, DbStringType>;\r\n private readonly testRegex: RegExp;\r\n private inShift: boolean = false;\r\n\r\n constructor(context: Assembler) {\r\n this.context = context;\r\n this.root = context.root;\r\n this.stringCharLookup = context.root.stringDelimiterLookup;\r\n this.testRegex = new RegExp(/^[0-9A-F]+$/i);\r\n }\r\n\r\n public consumeString(typeChar: string): void {\r\n let str: string | null = null;\r\n let fixedStr: number = 0;\r\n\r\n // Get character code of string type\r\n //const typeChar = this.context.lineBuffer[0];\r\n\r\n // Find last index of character code\r\n const endIx = this.context.lineBuffer.indexOf(typeChar, 1);\r\n if (endIx >= 0) {\r\n // Take the line up until the type code\r\n str = this.context.lineBuffer.substring(1, endIx);\r\n // Line takes content after and code\r\n this.context.lineBuffer = this.context.lineBuffer.substring(endIx + 1)\r\n .replace(/^[\\s,\\t]+/, '');\r\n if(this.context.lineBuffer.startsWith('(')) {\r\n const endIx = this.context.lineBuffer.indexOf(')');\r\n if(endIx >= 0) {\r\n fixedStr = parseInt(this.context.lineBuffer.substring(1, endIx), 10);\r\n this.context.lineBuffer = this.context.lineBuffer.substring(endIx + 1)\r\n .replace(/^[\\s,\\t]+/, '');\r\n }\r\n }\r\n } else {\r\n // Take the remaining line\r\n str = this.context.lineBuffer.substring(1);\r\n this.context.lineBuffer = '';\r\n }\r\n\r\n // Reset memory buffer for new string\r\n this.memBuffer.length = 0;\r\n this.totalSize = 0;\r\n this.fixedStr = fixedStr;\r\n\r\n this.processString(str!, typeChar);\r\n }\r\n\r\n private flushBuffer(stringType: DbStringType, wrap: boolean = false): void {\r\n const size = this.memBuffer.length;\r\n if (size > 0) {\r\n const newSize = this.totalSize + size;\r\n if(this.fixedStr && newSize > this.fixedStr) {\r\n const buffer = new Uint8Array(this.memBuffer.slice(0, this.fixedStr - this.totalSize));\r\n this.context.currentBlock!.objList.push(buffer);\r\n this.context.currentBlock!.size += buffer.length;\r\n this.totalSize = this.fixedStr;\r\n } else {\r\n const buffer = new Uint8Array(this.memBuffer);\r\n this.context.currentBlock!.objList.push(buffer);\r\n this.context.currentBlock!.size += size;\r\n this.totalSize += size;\r\n }\r\n this.memBuffer.length = 0;\r\n }\r\n }\r\n\r\n private processString(str: string, typeChar: string): void {\r\n const stringType = this.stringCharLookup[typeChar];\r\n const dictionary = stringType.dictionaryLookup;\r\n const cmdLookup = stringType.commands;\r\n let currentLayer = stringType.layers[0];\r\n\r\n //const charMap = stringType.characterMap;\r\n //const shift = this.getShiftUp(stringType.shiftType);\r\n let lastCmd: DbStringCommand | null = null;\r\n\r\n let fullMatch = false;\r\n for(const entry of dictionary) {\r\n let index : number;\r\n while((index = str.indexOf(entry.text)) >= 0) {\r\n if(index === 0 && str.length === entry.text.length) {\r\n fullMatch = true;\r\n break;\r\n }\r\n str = str.substring(0, index) + `[${(entry.id).toString(16).toUpperCase()}]` + str.substring(index + entry.text.length);\r\n }\r\n if(fullMatch) break;\r\n }\r\n\r\n\r\n for (let x = 0; x < str.length; x++) {\r\n const c = str[x];\r\n if (c === '[') {\r\n const endIx = str.indexOf(']', x + 1);\r\n const splitChars = [':', ',', ' '];\r\n\r\n const parts = str.substring(x + 1, endIx)\r\n .split(new RegExp(`[${splitChars.join('')}]`))\r\n .filter(p => p.length > 0);\r\n\r\n x = endIx;\r\n\r\n // Marker\r\n if (parts.length === 0) {\r\n this.flushBuffer(stringType, true);\r\n this.context.currentBlock!.objList.push({\r\n offset: this.context.currentBlock!.size\r\n } as StringMarker);\r\n continue;\r\n }\r\n\r\n const cmd = cmdLookup[parts[0]];\r\n if (cmd) {\r\n lastCmd = cmd;\r\n this.memBuffer.push(cmd.id);\r\n this.processStringCommand(cmd, stringType, parts);\r\n continue;\r\n }\r\n\r\n //Direct values for dictionary commands etc\r\n if(parts.length === 1 && this.testRegex.test(parts[0])) {\r\n const value = parseInt(parts[0], 16);\r\n if(value < 0x100) this.memBuffer.push(value);\r\n else this.memBuffer.push((value >> 8) & 0xFF, value & 0xFF);\r\n continue;\r\n }\r\n }\r\n\r\n lastCmd = null;\r\n\r\n // Process string layers\r\n let found = false;\r\n for (const layer of stringType.layers) {\r\n for (let i = 0, len = layer.map.length; i < len; i++) {\r\n const v = layer.map[i];\r\n if (c === v) {\r\n //Toggle layers if they are not active\r\n if(layer.on !== undefined && currentLayer !== layer) {\r\n this.memBuffer.push(layer.on);\r\n currentLayer = layer;\r\n }\r\n\r\n let value = i + (layer.base ?? 0);\r\n if(typeof layer.shiftBit === 'number') {\r\n const shiftBit = 1 << layer.shiftBit;\r\n const lowerFlag = shiftBit - 1;\r\n const upperFlag = ~lowerFlag;\r\n value = ((value & upperFlag) << 1) | (value & lowerFlag);\r\n }\r\n this.memBuffer.push(value);\r\n found = true; \r\n break;\r\n }\r\n }\r\n if(found) break;\r\n }\r\n }\r\n\r\n if(this.fixedStr) {\r\n let count = this.fixedStr - this.totalSize;\r\n while(count--) this.memBuffer.push(stringType.terminator);\r\n } else if (lastCmd === null || !lastCmd.halt) {\r\n this.memBuffer.push(stringType.terminator);\r\n }\r\n\r\n this.flushBuffer(stringType, true);\r\n }\r\n\r\n private processStringCommand(cmd: DbStringCommand, stringType: DbStringType, parts: string[]): void {\r\n const hasPointer = cmd.types.includes(MemberType.Address) || cmd.types.includes(MemberType.Offset);\r\n if (hasPointer) {\r\n this.flushBuffer(stringType, true);\r\n }\r\n\r\n for (let y = 0, pix = 1; y < cmd.types.length; y++, pix++) {\r\n switch (cmd.types[y]) {\r\n case MemberType.Byte:\r\n this.memBuffer.push(parseInt(parts[pix], 16));\r\n break;\r\n\r\n case MemberType.Word:\r\n const us = parseInt(parts[pix], 16);\r\n this.memBuffer.push(us & 0xFF);\r\n this.memBuffer.push((us >> 8) & 0xFF);\r\n break;\r\n\r\n case MemberType.Binary:\r\n while (pix < parts.length) {\r\n const ch = parseInt(parts[pix], 16);\r\n this.memBuffer.push(ch);\r\n pix++;\r\n }\r\n if (cmd.delimiter !== undefined) {\r\n this.memBuffer.push(cmd.delimiter);\r\n }\r\n break;\r\n\r\n case MemberType.Offset:\r\n case MemberType.Address:\r\n // Have to keep these for later since we don't have lookups yet\r\n this.flushBuffer(stringType, false);\r\n this.context.currentBlock!.objList.push(parts[pix]);\r\n this.context.currentBlock!.size += cmd.types[y] === MemberType.Offset ? 2 : 3;\r\n break;\r\n }\r\n }\r\n\r\n if (hasPointer) {\r\n this.flushBuffer(stringType, false);\r\n }\r\n }\r\n}\r\n","/**\r\n * A map that sorts keys by length in descending order, then alphabetically\r\n * This is used for tag replacement where longer tags should be replaced first\r\n * to avoid conflicts (e.g., \"ABCD\" should be replaced before \"ABC\")\r\n */\r\nexport class SortedMap<V> {\r\n private map = new Map<string, V>();\r\n private _keys: string[] = [];\r\n\r\n public get size(): number {\r\n return this.map.size;\r\n }\r\n\r\n public set(key: string, value: V): this {\r\n if (!this.map.has(key)) {\r\n this._keys.push(key);\r\n this.sortKeys();\r\n }\r\n this.map.set(key, value);\r\n return this;\r\n }\r\n\r\n public get(key: string): V | undefined {\r\n return this.map.get(key);\r\n }\r\n\r\n public has(key: string): boolean {\r\n return this.map.has(key);\r\n }\r\n\r\n public delete(key: string): boolean {\r\n const result = this.map.delete(key);\r\n if (result) {\r\n const index = this._keys.indexOf(key);\r\n if (index >= 0) {\r\n this._keys.splice(index, 1);\r\n }\r\n }\r\n return result;\r\n }\r\n\r\n public clear(): void {\r\n this.map.clear();\r\n this._keys.length = 0;\r\n }\r\n\r\n public keys(): string[] {\r\n return [...this._keys];\r\n }\r\n\r\n public values(): V[] {\r\n return this._keys.map(key => this.map.get(key)!);\r\n }\r\n\r\n public entries(): [string, V][] {\r\n return this._keys.map(key => [key, this.map.get(key)!]);\r\n }\r\n\r\n public *[Symbol.iterator](): Generator<[string, V], void, unknown> {\r\n for (const key of this._keys) {\r\n yield [key, this.map.get(key)!];\r\n }\r\n }\r\n\r\n private sortKeys(): void {\r\n this._keys.sort((a, b) => {\r\n // Sort by length descending first\r\n if (a.length !== b.length) {\r\n return b.length - a.length;\r\n }\r\n // Then alphabetically\r\n return a.localeCompare(b);\r\n });\r\n }\r\n}\r\n","import { Byte, RomProcessingConstants, AsmBlock, Op } from '../../types';\r\nimport { DbRoot, DbStruct, OpCode } from '../../database';\r\nimport type { Assembler } from './assembler';\r\nimport { AsmReader } from '../extraction/asm';\r\n\r\n/**\r\n * Assembler state machine for processing assembly text\r\n * Converted from GaiaLib/Rom/Rebuild/AssemblerState.cs\r\n */\r\nexport class AssemblerState {\r\n private readonly dbStruct: DbStruct | null;\r\n private readonly parentStruct: DbStruct | null;\r\n private readonly root: DbRoot;\r\n private readonly discriminator: number | null;\r\n private delimiter: number | null;\r\n private memberOffset: number;\r\n private dataOffset: number;\r\n private readonly memberTypes: string[] | null;\r\n private currentType: string | null;\r\n private readonly context: Assembler;\r\n\r\n constructor(context: Assembler, structType: string | null = null, saveDelimiter: boolean = false) {\r\n this.context = context;\r\n this.root = context.root;\r\n\r\n this.dbStruct = structType === null ? null\r\n : Object.values(this.root.structs).find(x =>\r\n x.name.toLowerCase() === structType.toLowerCase()\r\n ) || null;\r\n\r\n this.parentStruct = !this.dbStruct || !this.dbStruct.parent ? null\r\n : Object.values(this.root.structs).find(x =>\r\n x.name.toLowerCase() === this.dbStruct!.parent!.toLowerCase()\r\n ) || null;\r\n\r\n this.discriminator = this.parentStruct?.discriminator ?? null;\r\n this.delimiter = this.dbStruct?.delimiter ?? null;\r\n this.memberOffset = 0;\r\n this.dataOffset = 0;\r\n this.memberTypes = this.dbStruct?.types || null;\r\n this.currentType = this.memberTypes?.[this.memberOffset] || null;\r\n\r\n if (saveDelimiter) {\r\n this.context.lastDelimiter = this.dbStruct?.delimiter ?? this.parentStruct?.delimiter ?? null;\r\n }\r\n }\r\n\r\n private checkDisc(): void {\r\n if (this.discriminator === this.dataOffset) {\r\n // Discriminator is always 1 byte\r\n this.context.currentBlock!.objList.push(this.dbStruct!.discriminator!);\r\n this.context.currentBlock!.size += 1;\r\n this.dataOffset += 1;\r\n }\r\n }\r\n\r\n private advancePart(): void {\r\n if (this.currentType != null && this.discriminator != null) {\r\n this.dataOffset += RomProcessingConstants.getSize(this.currentType);\r\n }\r\n\r\n if (this.memberTypes != null && this.memberOffset + 1 < this.memberTypes.length) {\r\n this.currentType = this.memberTypes[++this.memberOffset];\r\n }\r\n }\r\n\r\n private processOrigin(): void {\r\n this.context.lineBuffer = this.context.lineBuffer.substring(3).replace(/^[\\s,\\t]+/, '');\r\n if (this.context.lineBuffer.startsWith('$')) {\r\n this.context.lineBuffer = this.context.lineBuffer.substring(1);\r\n }\r\n\r\n let hex: string;\r\n const endIx = this.context.lineBuffer.search(/[\\s,\\t]/);\r\n if (endIx >= 0) {\r\n hex = this.context.lineBuffer.substring(0, endIx);\r\n this.context.lineBuffer = this.context.lineBuffer.substring(endIx + 1).replace(/^[\\s,\\t]+/, '');\r\n } else {\r\n hex = this.context.lineBuffer;\r\n this.context.lineBuffer = '';\r\n }\r\n\r\n const location = parseInt(hex, 16);\r\n\r\n this.context.blocks.push(this.context.currentBlock = new AsmBlock(location));\r\n //this.context.blockIndex++;\r\n }\r\n\r\n private static doMath(operand: string): string {\r\n const ix = operand.search(/[-+]/);\r\n if (ix >= 0) {\r\n const op = operand[ix];\r\n\r\n const vix = operand.lastIndexOf('$', ix) + 1;\r\n\r\n const valueStr = operand.substring(vix, ix);\r\n if (valueStr.match(/^[a-fA-F0-9]+$/)) {\r\n const value = parseInt(valueStr, 16);\r\n \r\n let endIx = operand.substring(ix + 1).search(RomProcessingConstants.SYMBOL_SPACE_REGEX);\r\n if(endIx < 0) {\r\n endIx = operand.length;\r\n }\r\n \r\n const number = parseInt(operand.substring(ix + 1, endIx), 16);\r\n\r\n let result: number;\r\n if (op === '-') {\r\n result = value - number;\r\n } else {\r\n result = value + number;\r\n }\r\n\r\n const len = (ix - vix) <= 2 ? 2 : (ix - vix) <= 4 ? 4 : 6;\r\n\r\n operand = operand.substring(0, vix) + result.toString(16).toUpperCase().padStart(len, '0') + operand.substring(endIx);\r\n }\r\n }\r\n return operand;\r\n }\r\n\r\n private tryCreateLabel(mnemonic: string, operand?: string): boolean {\r\n // Check that the operand has content\r\n if (!operand || operand.length === 0) {\r\n return false;\r\n }\r\n\r\n const labelChar = operand[0];\r\n\r\n // If our operand starts with a label space character, create a label\r\n if (!RomProcessingConstants.LABEL_SPACE.includes(labelChar)) {\r\n return false;\r\n }\r\n\r\n // Create new block for this label\r\n const newBlock = new AsmBlock(\r\n this.context.currentBlock!.location + this.context.currentBlock!.size,\r\n 0,\r\n this.root.stringDelimiters.includes(operand[0]),\r\n mnemonic\r\n );\r\n\r\n // const conditionBlock = this.context.conditionBlock;\r\n // if(conditionBlock) {\r\n // conditionBlock.objList.push(newBlock);\r\n // } else {\r\n this.context.blocks.push(newBlock);\r\n //}\r\n\r\n // Set as current\r\n this.context.currentBlock = newBlock;\r\n\r\n // Increment current block index\r\n //this.context.blockIndex++;\r\n\r\n // Remove label marker\r\n if (labelChar === ':') {\r\n this.context.lineBuffer = this.context.lineBuffer.substring(1);\r\n } else if (labelChar === '[' || labelChar === '{') {\r\n this.context.lineBuffer = operand.substring(1).replace(/^[\\s,\\t]+/, '');\r\n\r\n // Process the next \r\n const state = new AssemblerState(this.context, this.currentType);\r\n state.processText(labelChar);\r\n\r\n // Advance to next part\r\n this.advancePart();\r\n }\r\n\r\n return true;\r\n }\r\n\r\n public processText(openTag?: string): void {\r\n this.checkDisc();\r\n\r\n while (!this.context.eof) {\r\n if (!this.context.getLine()) {\r\n return;\r\n }\r\n\r\n // if (this.context.lineBuffer.startsWith('DB')) {\r\n // const hex = this.context.lineBuffer.substring(2).replace(HEX_REGEX, '');\r\n // const data = this.hexStringToBytes(hex);\r\n // this.context.currentBlock!.objList.push(data);\r\n // this.context.currentBlock!.size += data.length;\r\n // this.context.lineBuffer = '';\r\n // continue;\r\n // }\r\n\r\n let mnemonic: string | null = null;\r\n let operand: string | null = null;\r\n let operand2: string | null = null;\r\n\r\n while (this.context.lineBuffer.length > 0) {\r\n const lineSymbol = this.context.lineBuffer[0];\r\n\r\n // Process strings\r\n if (this.root.stringDelimiters.includes(lineSymbol)) {\r\n this.context.stringProcessor.consumeString(lineSymbol);\r\n this.advancePart();\r\n continue;\r\n }\r\n\r\n // Process raw data\r\n if (RomProcessingConstants.ADDRESS_SPACE.includes(lineSymbol)) {\r\n this.context.processRawData();\r\n\r\n if (openTag === '[') {\r\n this.context.lastDelimiter = null;\r\n }\r\n\r\n this.advancePart();\r\n continue;\r\n }\r\n\r\n if (lineSymbol === '>') {\r\n if (openTag === '<') {\r\n this.context.lineBuffer = this.context.lineBuffer.substring(1).replace(/^[\\s,\\t]+/, '');\r\n this.checkDisc();\r\n }\r\n return;\r\n }\r\n\r\n // Array Close\r\n if (lineSymbol === ']') {\r\n this.context.lineBuffer = this.context.lineBuffer.substring(1).replace(/^[\\s,\\t]+/, '');\r\n\r\n this.delimiter = this.delimiter ?? this.context.lastDelimiter;\r\n\r\n // Apply delimiter if set\r\n if (this.delimiter != null) {\r\n if (this.delimiter >= 0x100) {\r\n // When over the word boundary use two bytes\r\n this.context.currentBlock!.objList.push(this.delimiter);\r\n this.context.currentBlock!.size += 2;\r\n } else {\r\n // Otherwise default to single byte\r\n this.context.currentBlock!.objList.push(this.delimiter);\r\n this.context.currentBlock!.size += 1;\r\n }\r\n }\r\n\r\n return;\r\n }\r\n\r\n // Block close\r\n if (lineSymbol === '}') {\r\n if (openTag === '{') {\r\n this.context.lineBuffer = this.context.lineBuffer.substring(1).replace(/^[\\s,\\t]+/, '');\r\n }\r\n return;\r\n }\r\n\r\n // Array Open\r\n if (lineSymbol === '[') {\r\n this.context.lineBuffer = this.context.lineBuffer.substring(1).replace(/^[\\s,\\t]+/, '');\r\n const state = new AssemblerState(this.context, this.currentType);\r\n state.processText('[');\r\n this.advancePart();\r\n continue;\r\n }\r\n\r\n // Process origin tags\r\n if (this.context.lineBuffer.startsWith('ORG')) {\r\n this.processOrigin();\r\n continue;\r\n }\r\n\r\n // Separate instructions into mnemonic and operand parts\r\n const symbolIndex = this.context.lineBuffer.search(RomProcessingConstants.SYMBOL_SPACE_REGEX);\r\n if (symbolIndex > 0) {\r\n mnemonic = this.context.lineBuffer.substring(0, symbolIndex);\r\n operand = this.context.lineBuffer.substring(symbolIndex).replace(/^[, \\t]+/, '');\r\n\r\n // Process object tags\r\n if (operand && operand.startsWith('<')) {\r\n this.context.lineBuffer = operand.substring(1).replace(/^[, \\t]+/, '');\r\n const state = new AssemblerState(this.context, mnemonic, openTag === '[' && this.currentType == null);\r\n state.processText('<');\r\n mnemonic = null;\r\n continue;\r\n }\r\n \r\n this.context.lineBuffer = operand;\r\n } else {\r\n mnemonic = this.context.lineBuffer;\r\n this.context.lineBuffer = '';\r\n }\r\n\r\n break;\r\n }\r\n\r\n if (mnemonic && mnemonic.length > 0) {\r\n // Get list of opcodes from mnemonic\r\n const codes = this.root.opLookup[mnemonic.toUpperCase()];\r\n\r\n // If no codes were found, try to create a label\r\n if (!codes || codes.length === 0) {\r\n if (this.tryCreateLabel(mnemonic, operand || undefined)) {\r\n continue;\r\n }\r\n\r\n // If label creation fails, throw exception\r\n throw new Error(`Unknown instruction line ${this.context.lineCount}: '${mnemonic}'`);\r\n }\r\n\r\n // Reset current assembler line\r\n this.context.lineBuffer = '';\r\n\r\n // No operand instructions\r\n if (!operand) {\r\n const opCode = codes.find(x => this.root.addrLookup[x.mode].size === 1);\r\n this.context.currentBlock!.objList.push(new Op (opCode!, 0, [], 1));\r\n this.context.currentBlock!.size++;\r\n continue;\r\n }\r\n\r\n // Do maths before regex processing\r\n operand = AssemblerState.doMath(operand);\r\n\r\n // COP processing\r\n let opCode: OpCode | null = codes[0];\r\n if (opCode?.mnem === 'COP') {\r\n const parts = operand.split(/[\\s\\t,()[\\]$#]/).filter(p => p.length > 0);\r\n const cmd = parts[0];\r\n\r\n const cop = this.root.copLookup[cmd];\r\n if (!cop) {\r\n throw new Error(`Unknown COP command ${cmd}`);\r\n }\r\n\r\n this.context.currentBlock!.objList.push(new Op(opCode, 0, [new Byte(cop.id), ...parts.slice(1)], cop.size + 2));\r\n\r\n this.context.currentBlock!.size += cop.size + 2;\r\n\r\n continue;\r\n }\r\n\r\n opCode = null;\r\n for (const code of codes) {\r\n // Keep branch operands until all blocks are processed (for labels)\r\n if (code.mode === 'PCRelative' || code.mode === 'PCRelativeLong') {\r\n opCode = code;\r\n break;\r\n }\r\n\r\n // Regex parse operand based on addressing mode\r\n const addrMode = this.root.addrLookup[code.mode]; \r\n const regex = addrMode.parseRegex;\r\n if (regex) {\r\n const match = new RegExp(regex).exec(operand);\r\n if (match) {\r\n // Keep the current code\r\n opCode = code;\r\n\r\n // Operand is the \"first\" matched group\r\n operand = match[1];\r\n\r\n // Support for second operand (MVN/MVP)\r\n if (match.length > 2) {\r\n operand2 = match[2];\r\n }\r\n\r\n break;\r\n }\r\n }\r\n }\r\n\r\n if (operand!.startsWith('#')) {\r\n operand = operand!.substring(1);\r\n }\r\n\r\n if (operand!.startsWith('$')) {\r\n operand = operand!.substring(1);\r\n }\r\n\r\n if (opCode == null) {\r\n const addrIx = operand!.search(RomProcessingConstants.ADDRESS_SPACE_REGEX);\r\n if (addrIx && addrIx >= 0) {\r\n const eix = operand!.search(/[\\s\\t,\\])]/);\r\n if (eix && eix >= 0) {\r\n operand = operand!.substring(addrIx, eix);\r\n }\r\n }\r\n\r\n opCode = codes.find(x => x.mode === 'Immediate')\r\n ?? codes.find(x => x.mode === 'AbsoluteLong')\r\n ?? codes.find(x => x.mode === 'Absolute')\r\n ?? null;\r\n\r\n if (opCode == null) {\r\n throw new Error(`Unable to determine mode/code line ${this.context.lineCount}: '${this.context.lineBuffer}'`);\r\n }\r\n }\r\n\r\n const opnd1 = this.context.parseOperand(operand!);\r\n\r\n const addrMode = this.root.addrLookup[opCode.mode];\r\n let size = addrMode.size;\r\n if (size === AsmReader.VARIABLE_SIZE_INDICATOR || opCode.mode === 'Immediate') {\r\n size = operand?.startsWith('^') || operand?.length === 2 ? 2 : 3;\r\n }\r\n\r\n const operands: unknown[] = operand2 != null ? [opnd1, this.context.parseOperand(operand2)] : [opnd1];\r\n\r\n this.context.currentBlock!.objList.push(new Op(opCode, 0, operands, size));\r\n\r\n this.context.currentBlock!.size += size;\r\n }\r\n }\r\n }\r\n\r\n private hexStringToBytes(hex: string): Uint8Array {\r\n const result = new Uint8Array(hex.length / 2);\r\n for (let i = 0; i < hex.length; i += 2) {\r\n result[i / 2] = parseInt(hex.substring(i, i + 2), 16);\r\n }\r\n return result;\r\n }\r\n}\r\n","import { RomProcessingConstants, Word, Byte, Long } from '../../types';\r\nimport { DbRoot } from '../../database';\r\nimport { AsmBlock } from '../../types/assembly';\r\nimport { StringProcessor } from './string-processor';\r\nimport { SortedMap } from './sorted-map';\r\nimport { AssemblerState } from './assembler-state';\r\n\r\n// export class ConditionBlock extends AsmBlock {\r\n// public condition: string;\r\n// //public next: ConditionBlock | null = null;\r\n\r\n// constructor(location: number = 0, condition: string) {\r\n// super(location, 0, false, undefined, undefined, undefined);\r\n// this.condition = condition;\r\n// }\r\n// }\r\n\r\n/**\r\n * Main assembler class for parsing assembly files\r\n * Converted from GaiaLib/Rom/Rebuild/Assembler.cs\r\n */\r\nexport class Assembler {\r\n public readonly root: DbRoot;\r\n private readonly lines: string[];\r\n private currentLineIndex: number = 0;\r\n public readonly stringProcessor: StringProcessor;\r\n\r\n public lineBuffer: string = '';\r\n public includes = new Set<string>();\r\n public blocks: AsmBlock[] = [];\r\n public tags = new SortedMap<string | null>();\r\n public currentBlock: AsmBlock | null = null;\r\n public lineCount: number = 0;\r\n //public blockIndex: number = 0;\r\n public lastDelimiter: number | null = null;\r\n public reqBank: number | null = null;\r\n public eof: boolean = false;\r\n public strDelimRegex: RegExp;\r\n public conditionFiles: string[];\r\n private inCondition: boolean = false;\r\n private exitCondition: boolean = false;\r\n private failCondition: boolean = false;\r\n\r\n constructor(dbRoot: DbRoot, textData: string, conditionFiles: string[]) {\r\n this.root = dbRoot;\r\n // Handle both Windows (\\r\\n) and Unix (\\n) line endings\r\n this.lines = textData.split(/\\r?\\n/);\r\n this.stringProcessor = new StringProcessor(this);\r\n this.strDelimRegex = new RegExp(`[${this.root.stringDelimiters.map(c => c.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')).join('')}]`);\r\n this.conditionFiles = conditionFiles;\r\n }\r\n\r\n public parseAssembly(): { blocks: AsmBlock[], includes: Set<string>, reqBank: number | null } {\r\n // Initialize root block (no label, location 0) and set as current\r\n this.blocks.push(this.currentBlock = new AsmBlock());\r\n\r\n // Initialize state machine and process text\r\n const state = new AssemblerState(this);\r\n state.processText();\r\n\r\n return { \r\n blocks: this.blocks, \r\n includes: this.includes, \r\n reqBank: this.reqBank \r\n };\r\n }\r\n\r\n public getLine(): boolean {\r\n // This can happen\r\n if (this.eof) {\r\n return false;\r\n }\r\n\r\n // Keep processing what we already have\r\n if (this.lineBuffer.length > 0) {\r\n return true;\r\n }\r\n\r\n let rawLine: string | null = null;\r\n \r\n while (true) {\r\n // Read next line\r\n if (this.currentLineIndex >= this.lines.length) {\r\n if (this.lineBuffer.length === 0) {\r\n this.eof = true;\r\n return false;\r\n } else {\r\n rawLine = '';\r\n }\r\n } else {\r\n rawLine = this.lines[this.currentLineIndex++];\r\n this.lineBuffer += rawLine;\r\n }\r\n\r\n this.lineCount++;\r\n\r\n // Ignore comments\r\n this.trimComments('--');\r\n this.trimComments(';');\r\n this.trimComments('//');\r\n\r\n // Trim\r\n this.lineBuffer = this.lineBuffer.replace(RomProcessingConstants.COMMA_SPACE_TRIM_REGEX, '');\r\n\r\n // This can happen\r\n if (this.lineBuffer.length === 0) {\r\n continue;\r\n }\r\n\r\n // Process hard line continuations\r\n if (this.lineBuffer.endsWith('\\\\')) {\r\n this.lineBuffer = this.lineBuffer.slice(0, -1);\r\n continue;\r\n }\r\n\r\n // Process directives\r\n if (this.lineBuffer[0] === '?') {\r\n this.processDirectives();\r\n this.lineBuffer = '';\r\n continue;\r\n }\r\n\r\n if(this.failCondition) {\r\n this.lineBuffer = '';\r\n continue;\r\n }\r\n\r\n // Process tags\r\n if (this.lineBuffer[0] === '!') {\r\n this.processTags();\r\n this.lineBuffer = '';\r\n continue;\r\n }\r\n\r\n this.resolveTags();\r\n\r\n return true;\r\n }\r\n }\r\n\r\n private trimComments(sequence: string): void {\r\n // Look for the first instance of the comment sequence\r\n const index = this.lineBuffer.indexOf(sequence);\r\n if (index >= 0) {\r\n // Make sure it's not inside a string\r\n const strIndex = this.lineBuffer.search(this.strDelimRegex);\r\n \r\n // This works with line continuations because the string ending will not be on this line yet\r\n // If no string, string starts after comment, or last delimiter is before comment, trim it\r\n if (strIndex < 0 || \r\n strIndex > index || \r\n this.lineBuffer.lastIndexOf(this.lineBuffer[strIndex] || '') < index) {\r\n this.lineBuffer = this.lineBuffer.substring(0, index);\r\n }\r\n }\r\n }\r\n\r\n private processDirectives(): void {\r\n // Find end of directive\r\n let endIx = this.lineBuffer.search(RomProcessingConstants.COMMA_SPACE_REGEX);\r\n\r\n // Default to line length if no end characters\r\n if (endIx < 0) {\r\n endIx = this.lineBuffer.length;\r\n }\r\n\r\n let value = this.lineBuffer.substring(endIx).replace(/^[\\s,\\t]+/, '');\r\n\r\n switch (this.lineBuffer.substring(1, endIx).toUpperCase()) {\r\n // This is taken care of by the loader\r\n case 'BANK':\r\n this.reqBank = parseInt(value, 16);\r\n break;\r\n\r\n case 'INCLUDE':\r\n if (value.length > 0) {\r\n this.includes.add(value.toUpperCase().replace(/'/g, ''));\r\n }\r\n break;\r\n\r\n case 'IF':\r\n if(this.inCondition) throw new Error('IF without ENDIF');\r\n value = value.replace(/'/g, '');\r\n if(!value) throw new Error('IF without condition');\r\n this.inCondition = true;\r\n if(!this.conditionFiles.includes(value)) { this.failCondition = true; this.exitCondition = false; }\r\n else { this.failCondition = false; this.exitCondition = true; }\r\n break;\r\n \r\n case 'ELSEIF':\r\n if(!this.inCondition) throw new Error('ELSEIF without IF');\r\n value = value.replace(/'/g, '');\r\n if(!value) throw new Error('ELSEIF without condition');\r\n if(this.exitCondition || !this.conditionFiles.includes(value)) this.failCondition = true;\r\n else { this.exitCondition = true; this.failCondition = false; }\r\n break;\r\n \r\n case 'ELSE':\r\n if(!this.inCondition) throw new Error('ELSE without IF');\r\n if(value) throw new Error('ELSE with condition');\r\n\r\n if(this.exitCondition) this.failCondition = true;\r\n else { this.failCondition = false; this.exitCondition = true; }\r\n break;\r\n\r\n case 'ENDIF':\r\n if(!this.inCondition) throw new Error('ENDIF without IF');\r\n if(value) throw new Error('ENDIF with condition');\r\n this.failCondition = false;\r\n this.exitCondition = false;\r\n this.inCondition = false;\r\n break;\r\n }\r\n }\r\n\r\n private processTags(): void {\r\n // Remove the '!' prefix and trim leading spaces\r\n this.lineBuffer = this.lineBuffer.substring(1).replace(/^[\\s,\\t]+/, '');\r\n\r\n // Process as many pairs as we can\r\n while (this.lineBuffer.length > 0) {\r\n // Default name and value\r\n let name = this.lineBuffer;\r\n let value: string | null = null;\r\n\r\n // Find first index of comma/space/tab\r\n let endIx = this.lineBuffer.search(/[\\s,\\t]/);\r\n\r\n if (endIx >= 0) {\r\n // Split into name and value\r\n name = this.lineBuffer.substring(0, endIx);\r\n value = this.lineBuffer.substring(endIx + 1).replace(/^[\\s,\\t]+/, '');\r\n\r\n // Find next index of comma/space/tab inside value\r\n const nextIx = value.search(/[\\s,\\t]/);\r\n if (nextIx >= 0) {\r\n // Line buffer then take the remainder\r\n this.lineBuffer = value.substring(nextIx + 1).replace(/^[\\s,\\t]+/, '');\r\n // Value takes up to next index\r\n value = value.substring(0, nextIx);\r\n } else {\r\n this.lineBuffer = ''; // No more pairs, clear buffer\r\n }\r\n } else {\r\n this.lineBuffer = ''; // Take all as name, clear buffer\r\n }\r\n\r\n // Assign name/value pair to tags\r\n this.tags.set(name, value);\r\n }\r\n }\r\n\r\n private resolveTags(): void {\r\n // Tags are sorted by length descending so longer tags are replaced first (avoids minor conflicts)\r\n for (const [key, value] of this.tags) {\r\n let ix: number;\r\n while ((ix = this.lineBuffer.toLowerCase().indexOf(key.toLowerCase())) >= 0) {\r\n this.lineBuffer = this.lineBuffer.substring(0, ix) + (value || '') + \r\n this.lineBuffer.substring(ix + key.length);\r\n }\r\n }\r\n }\r\n\r\n public parseOperand(opnd: string): unknown {\r\n if (!opnd) return null;\r\n\r\n if(opnd.match(/^[a-fA-F0-9]{2,6}$/)){\r\n switch(opnd.length){\r\n case 2:\r\n return new Byte(parseInt(opnd, 16));\r\n case 4:\r\n return new Word(parseInt(opnd, 16));\r\n case 6:\r\n return new Long(parseInt(opnd, 16));\r\n }\r\n }\r\n\r\n return opnd;\r\n }\r\n\r\n public processRawData(): void {\r\n let reverse = false;\r\n\r\n // Immediate binary marker\r\n if (this.lineBuffer[0] === '#') {\r\n this.lineBuffer = this.lineBuffer.substring(1);\r\n }\r\n\r\n // Reverse binary marker\r\n if (this.lineBuffer[0] === '$') {\r\n reverse = true;\r\n this.lineBuffer = this.lineBuffer.substring(1);\r\n }\r\n\r\n let hex: string;\r\n const symbolIx = this.lineBuffer.search(RomProcessingConstants.SYMBOL_SPACE_REGEX);\r\n if (symbolIx >= 0) {\r\n hex = this.lineBuffer.substring(0, symbolIx);\r\n this.lineBuffer = this.lineBuffer.substring(symbolIx).replace(/^[, \\t]+/, '');\r\n } else {\r\n hex = this.lineBuffer;\r\n this.lineBuffer = '';\r\n }\r\n\r\n if (hex.length > 0) {\r\n // Keep string values of address markers so they can be resolved later\r\n if (RomProcessingConstants.ADDRESS_SPACE.includes(hex[0])) {\r\n this.currentBlock!.objList.push(hex);\r\n this.currentBlock!.size += RomProcessingConstants.getSize(hex);\r\n } else {\r\n const data = this.hexStringToBytes(hex);\r\n if (data.length === 1) {\r\n this.currentBlock!.objList.push(new Byte(data[0]));\r\n this.currentBlock!.size++;\r\n } else {\r\n if (reverse) {\r\n data.reverse();\r\n }\r\n\r\n // Explicitly change two-byte data into number for easier processing later\r\n if (data.length === 2) {\r\n this.currentBlock!.objList.push(new Word(data[0] | (data[1] << 8)));\r\n this.currentBlock!.size += 2;\r\n } else {\r\n this.currentBlock!.objList.push(data);\r\n this.currentBlock!.size += data.length;\r\n }\r\n }\r\n }\r\n }\r\n }\r\n\r\n private hexStringToBytes(hex: string): Uint8Array {\r\n const result = new Uint8Array(hex.length / 2);\r\n for (let i = 0; i < hex.length; i += 2) {\r\n result[i / 2] = parseInt(hex.substring(i, i + 2), 16);\r\n }\r\n return result;\r\n }\r\n}\r\n","import type { DbPart } from './parts';\r\nimport { DbTransform } from './transforms';\r\n\r\n/**\r\n * Database block definition\r\n * Converted from GaiaLib/Database/DbBlock.cs\r\n */\r\nexport class DbBlock {\r\n public name: string;\r\n public movable: boolean;\r\n public group?: string;\r\n public scene?: string;\r\n public parts: DbPart[];\r\n public transforms?: DbTransform[];\r\n public postProcess?: string;\r\n public order?: number;\r\n //public id?: string;\r\n\r\n constructor(data: Partial<DbBlock>) {\r\n this.name = data.name ?? '';\r\n this.movable = data.movable ?? false;\r\n this.group = data.group ?? undefined;\r\n this.scene = data.scene ?? undefined;\r\n this.parts = (data.parts ?? []).sort((a, b) => {\r\n const orderA = a.order ?? 0;\r\n const orderB = b.order ?? 0;\r\n if (orderA !== orderB) {\r\n return orderA - orderB;\r\n }\r\n return a.start - b.start;\r\n });\r\n this.transforms = data.transforms ?? [];\r\n this.postProcess = data.postProcess ?? undefined;\r\n this.order = data.order ?? undefined;\r\n //this.id = data.id ?? undefined;\r\n\r\n\r\n if(!this.name) throw new Error('Name is required');\r\n }\r\n}\r\n","import { BinType } from '../types/resources';\r\n\r\nexport class DbFile {\r\n //public id?: string;\r\n public name: string;\r\n public type: string;\r\n public start: number;\r\n public end: number;\r\n public compressed?: boolean;\r\n public upper?: boolean;\r\n public group?: string;\r\n public scene?: string;\r\n\r\n constructor(data: Partial<DbFile>) {\r\n if(!data.name) throw new Error('Name is required');\r\n if(!data.type) throw new Error('Type is required');\r\n if(typeof data.start !== 'number') throw new Error('Start is required');\r\n if(typeof data.end !== 'number') throw new Error('End is required');\r\n\r\n this.name = data.name;\r\n this.type = data.type;\r\n this.start = data.start;\r\n this.end = data.end;\r\n this.compressed = data.compressed ?? undefined;\r\n this.upper = data.upper ?? undefined;\r\n this.group = data.group || undefined;\r\n this.scene = data.scene || undefined;\r\n }\r\n} \r\n\r\nexport class DbFileType {\r\n public name: string;\r\n public extension: string;\r\n public type: string;\r\n public isPatch: boolean;\r\n public isBlock: boolean;\r\n public header: number;\r\n public compressed?: boolean;\r\n\r\n constructor(data: Partial<DbFileType>) {\r\n this.name = data.name ?? '';\r\n this.extension = data.extension ?? '';\r\n this.type = data.type ?? '';\r\n this.isPatch = data.isPatch ?? false;\r\n this.isBlock = data.isBlock ?? false;\r\n this.header = data.header ?? 0;\r\n this.compressed = data.compressed ?? undefined;\r\n \r\n if(!this.name) throw new Error('Name is required');\r\n if(!this.extension) throw new Error('Extension is required');\r\n if(!this.type) throw new Error('Type is required');\r\n }\r\n}","/**\r\n * Database structure definition\r\n * Converted from GaiaLib/Database/DbStruct.cs\r\n */\r\nexport class DbStruct {\r\n public name: string;\r\n public types?: string[];\r\n public parent?: string;\r\n public delimiter?: number;\r\n public discriminator?: number;\r\n\r\n constructor(data: Partial<DbStruct>) {\r\n this.name = data.name ?? '';\r\n this.types = data.types ?? undefined;\r\n this.parent = data.parent ?? undefined;\r\n this.delimiter = data.delimiter ?? undefined;\r\n this.discriminator = data.discriminator ?? undefined;\r\n\r\n if(!this.name) throw new Error('Name is required');\r\n }\r\n} ","\r\nexport class DbAddressingMode {\r\n public name: string;\r\n public shorthand: string;\r\n public operands: string[];\r\n public size: number;\r\n public formatString?: string;\r\n public parseRegex?: string;\r\n public instructions: Record<string, number>;\r\n\r\n constructor(data: Partial<DbAddressingMode>) {\r\n if(!data.name) throw new Error('Addressing mode name is required');\r\n if(!data.shorthand) throw new Error('Addressing mode shorthand is required');\r\n if(!data.instructions) throw new Error('Addressing mode instructions are required');\r\n if(!data.size) throw new Error('Addressing mode size is required');\r\n\r\n this.name = data.name;\r\n this.shorthand = data.shorthand;\r\n this.operands = data.operands ?? [];\r\n this.size = data.size ?? 1;\r\n this.formatString = data.formatString ?? undefined;\r\n this.parseRegex = data.parseRegex ?? undefined;\r\n this.instructions = data.instructions;\r\n }\r\n}\r\n","import { MemberType } from '../types/members';\r\n\r\n/**\r\n * Database string command definition\r\n * Converted from GaiaLib/Database/DbStringCommand.cs\r\n */\r\nexport class DbStringCommand {\r\n public id: number;\r\n public name: string;\r\n public types: string[];\r\n public delimiter?: number;\r\n public halt: boolean;\r\n public dictionary?: DbStringDictionary;\r\n\r\n constructor(data: Partial<DbStringCommand>) {\r\n if(typeof data.id !== 'number') throw new Error('Id is required');\r\n if(!data.name) throw new Error('Name is required');\r\n\r\n this.id = data.id;\r\n this.name = data.name;\r\n this.types = data.types ?? [];\r\n this.delimiter = data.delimiter ?? undefined;\r\n this.halt = data.halt ?? false;\r\n this.dictionary = data.dictionary ?? undefined;\r\n }\r\n}\r\n\r\n/**\r\n * Database string layer definition\r\n * Converted from GaiaLib/Database/DbStringLayer.cs\r\n */\r\nexport interface DbStringLayer {\r\n base?: number;\r\n range?: number;\r\n on?: number;\r\n shiftBit?: number;\r\n map: string[];\r\n}\r\n\r\nexport class DbStringDictionary {\r\n public base?: number;\r\n public range: number;\r\n public command?: number;\r\n public name: string;\r\n //public suffix: string;\r\n public entries: string[];\r\n\r\n constructor(data: Partial<DbStringDictionary>) {\r\n if(typeof data.base !== 'number' && typeof data.command !== 'number') throw new Error('Base or command is required');\r\n if(!data.name) throw new Error('Name is required');\r\n if(!data.entries || data.entries.length === 0) throw new Error('Entries is required');\r\n\r\n this.base = data.base ?? undefined;\r\n this.range = data.range ?? 0;\r\n this.command = data.command ?? undefined;\r\n this.name = data.name;\r\n this.entries = data.entries;\r\n //this.suffix = data.suffix ?? '';\r\n\r\n if(this.base !== undefined) this.range = this.base + this.entries.length;\r\n }\r\n}\r\n\r\n/**\r\n * Database string type definition\r\n * Converted from GaiaLib/Database/DbStringType.cs\r\n */\r\nexport class DbStringType {\r\n public name: string;\r\n public delimiter: string;\r\n public terminator: number;\r\n public commands: Record<string, DbStringCommand>;\r\n public commandLookup: Record<number, DbStringCommand>;\r\n public layers: DbStringLayer[];\r\n public greedyTerminator: boolean;\r\n public dictionaries: Record<string, DbStringDictionary>;\r\n public dictionaryLookup: { text: string, id: number }[];\r\n\r\n constructor(data: Partial<DbStringType>) {\r\n if(!data.name) throw new Error('Name is required');\r\n if(!data.delimiter) throw new Error('Delimiter is required');\r\n if(typeof data.terminator !== 'number') throw new Error('Terminator is required');\r\n if(!data.layers || !data.layers.length) throw new Error('Layers are required');\r\n\r\n this.name = data.name;\r\n this.delimiter = data.delimiter;\r\n this.terminator = data.terminator;\r\n this.commands = data.commands ?? {};\r\n this.layers = data.layers;\r\n this.greedyTerminator = data.greedyTerminator ?? false;\r\n this.dictionaries = data.dictionaries ?? {};\r\n this.commandLookup = Object.values(this.commands).reduce((acc, x) => {\r\n acc[x.id] = x;\r\n return acc;\r\n }, {} as Record<number, DbStringCommand>);\r\n this.dictionaryLookup = Object.values(this.dictionaries)\r\n .flatMap((y) => y.entries.map((z, ix) => ({ text: z, id: ((y.command ?? 0) << 8) | (y.base ?? 0 + ix) })))\r\n //.map((y, z) => ({ text: y.entries[z], id: (y.command << 8) | (y.base + z) }))\r\n .sort((a, b) => b.text.length - a.text.length);\r\n }\r\n}\r\n","\r\n/**\r\n * COP instruction definition\r\n * Converted from GaiaLib/Database/CopDef.cs\r\n */\r\nexport class CopDef {\r\n public id: number;\r\n public name: string;\r\n public size: number;\r\n public parts: string[];\r\n public halt: boolean;\r\n\r\n constructor(data: Partial<CopDef>) {\r\n if(!data.name) throw new Error('Name is required');\r\n if(typeof data.id !== 'number') throw new Error('ID is required');\r\n\r\n this.name = data.name;\r\n this.id = data.id;\r\n this.parts = data.parts ?? [];\r\n this.halt = data.halt ?? false;\r\n this.size = data.size ?? 0;\r\n }\r\n}\r\n","\r\n/**\r\n * Database part definition\r\n * Converted from GaiaLib/Database/DbPart.cs\r\n */\r\nexport class DbPart {\r\n public name: string;\r\n public start: number;\r\n public end: number;\r\n public type: string;\r\n public bank?: number;\r\n public order?: number;\r\n\r\n constructor(data: Partial<DbPart>) {\r\n if(typeof data.start !== 'number') throw new Error('Start is required');\r\n if(!data.name) throw new Error('Name is required');\r\n if(!data.end) throw new Error('End is required');\r\n if(!data.type) throw new Error('Struct is required');\r\n\r\n this.name = data.name;\r\n this.start = data.start;\r\n this.end = data.end;\r\n this.type = data.type;\r\n this.bank = data.bank ?? undefined;\r\n this.order = data.order ?? undefined;\r\n\r\n }\r\n}\r\n","\r\nexport class DbTransform {\r\n key: string; \r\n value: string;\r\n\r\n constructor(data: Partial<DbTransform>) {\r\n this.key = data.key ?? '';\r\n this.value = data.value ?? '';\r\n\r\n if(!this.key) throw new Error('Key is required');\r\n }\r\n} ","import { DbAsset } from \"./assets\";\r\n\r\nexport class DbScene {\r\n public name: string;\r\n public id: number;\r\n public description?: string;\r\n public assets: DbAsset[];\r\n \r\n constructor(data: Partial<DbScene>) {\r\n this.name = data.name ?? '';\r\n this.id = data.id ?? 0;\r\n this.description = data.description ?? '';\r\n this.assets = data.assets ?? [];\r\n\r\n if(!this.name) throw new Error('Scene name is required');\r\n if(!this.id) throw new Error('Scene id is required');\r\n }\r\n}","import { DbScene } from \"./scenes\";\r\n\r\nexport class DbGroup {\r\n public name: string;\r\n public prefix: string;\r\n public description?: string;\r\n public scenes: Record<string, DbScene>;\r\n\r\n constructor(data: Partial<DbGroup>) {\r\n this.name = data.name ?? '';\r\n this.prefix = data.prefix ?? '';\r\n this.description = data.description ?? '';\r\n this.scenes = data.scenes ?? {};\r\n }\r\n}","import { BitStream } from '../types/bitstream';\nimport { type ICompressionProvider } from '../types/compression';\n\n/**\n * QuintetLZ compression algorithm implementation\n * Dictionary-based compression used in Quintet games\n */\nexport class QuintetLZ implements ICompressionProvider {\n public static readonly DICTIONARY_SIZE = 0x100;\n public static readonly DICTIONARY_INIT = 0x20;\n public static readonly DICTIONARY_OFFSET = 0xEF;\n private static readonly DEFAULT_PAGE_SIZE = 0x8000;\n\n /**\n * Expand (decompress) data using QuintetLZ algorithm\n * @param srcData Source data buffer\n * @param srcPosition Starting position in source data\n * @param srcLen Length of source data to process\n * @returns Expanded data\n */\n public expand(srcData: Uint8Array, srcPosition: number = 0, srcLen: number = QuintetLZ.DEFAULT_PAGE_SIZE): Uint8Array {\n const bitStream = new BitStream(srcData, srcPosition);\n const srcStop = srcPosition + srcLen;\n\n // Initialize dictionary with spaces (0x20)\n const dictionary = new Uint8Array(QuintetLZ.DICTIONARY_SIZE);\n dictionary.fill(QuintetLZ.DICTIONARY_INIT);\n\n // Initialize positions\n let dictPosition = QuintetLZ.DICTIONARY_OFFSET;\n let outPosition = 0;\n\n // First two bytes is decompressed size\n let dstLen = bitStream.readShort();\n\n if(dstLen === 0){\n return srcData.slice(srcPosition + 2, srcStop);\n } else if(dstLen & 0x8000) {\n dstLen = 0x10000 - dstLen;\n }\n\n // Create output buffer with the expected size\n const outBuffer = new Uint8Array(dstLen);\n\n while (bitStream.currentPosition < srcStop && outPosition < dstLen) {\n // If current bit is set, read byte and add to output buffer and dictionary\n if (bitStream.readBit()) {\n // Read byte from bitstream\n const sample = bitStream.readByte();\n\n // Add byte to output buffer and increment\n if (outPosition < dstLen) {\n outBuffer[outPosition++] = sample;\n }\n\n // Add byte to dictionary\n dictionary[dictPosition] = sample;\n\n // Wrap dictionary index\n dictPosition = (dictPosition + 1) & 0xFF;\n }\n // If current bit is not set, read sequence from dictionary\n else {\n // Read wordIndex and wordLength from bitstream\n let wordIndex = bitStream.readByte();\n let wordLength = bitStream.readNibble() + 2;\n\n // Continue while there are remaining bytes to copy\n while (wordLength-- > 0) {\n // Read byte at wordIndex\n const sample = dictionary[wordIndex];\n\n // Wrap dictionary index\n wordIndex = (wordIndex + 1) & 0xFF;\n\n // Copy byte to output buffer and increment, but only if there is space\n if (outPosition < dstLen) {\n outBuffer[outPosition++] = sample;\n }\n\n // Add byte to dictionary and increment\n dictionary[dictPosition] = sample;\n\n // Wrap dictionary index\n dictPosition = (dictPosition + 1) & 0xFF;\n }\n }\n }\n\n // Return only the used portion of the buffer\n if (outPosition < dstLen) {\n return outBuffer.slice(0, outPosition);\n }\n\n return outBuffer;\n }\n\n /**\n * Compact (compress) data using QuintetLZ algorithm\n * @param srcData Source data to compress\n * @returns Compressed data\n */\n public compact(srcData: Uint8Array, srcPosition?: number, srcLen?: number): Uint8Array {\n // Initialize dictionary with spaces\n const dictionary = new Uint8Array(QuintetLZ.DICTIONARY_SIZE);\n dictionary.fill(QuintetLZ.DICTIONARY_INIT);\n\n let offset = QuintetLZ.DICTIONARY_OFFSET;\n let srcIx = srcPosition ?? 0;\n let dstIx = 0;\n if(!srcLen) srcLen = srcData.length - srcIx;\n let endIx = srcIx + srcLen;\n\n\n //const srcLen = srcData.length;\n const outputBuffer = new Uint8Array(srcLen * 2); // Allocate extra space for safety\n\n // Write header (16-bit length in little-endian)\n outputBuffer[dstIx++] = srcLen & 0xFF;\n outputBuffer[dstIx++] = (srcLen >> 8) & 0xFF;\n\n const bitStream = new BitStream(outputBuffer, 2); // Start after header\n\n /**\n * Find the best match in the dictionary\n * @returns Tuple of [startByte, length]\n */\n const getCommand = (): [number, number] => {\n const maxLen = Math.min(endIx - srcIx, 17);\n if (maxLen < 2) {\n return [0, 0];\n }\n\n let startByte = 0;\n let bestLen = 0;\n let baseIndex = offset;\n\n for (let i = 0; i < 0x100; i++, baseIndex = (baseIndex + 1) & 0xFF) {\n let size = 0;\n let currentIndex = baseIndex;\n let sourceIndex = srcIx;\n let isEnd = false;\n\n while (size < maxLen) {\n if(isEnd) { if(srcData[sourceIndex++] !== srcData[srcIx + size]) break; } \n else if(dictionary[currentIndex] !== srcData[sourceIndex++]) break; \n else {\n currentIndex = (currentIndex + 1) & 0xFF;\n if (currentIndex === offset) {\n sourceIndex = srcIx;\n isEnd = true;\n }\n }\n \n size++;\n }\n\n if (size > bestLen) {\n startByte = baseIndex;\n bestLen = size;\n\n if (bestLen >= maxLen) {\n break;\n }\n }\n }\n\n return [startByte, bestLen];\n };\n\n while (srcIx < endIx) {\n const [cmdStart, cmdLen] = getCommand();\n\n if (cmdLen >= 2) {\n // Write dictionary reference\n bitStream.writeBit(false);\n bitStream.writeByte(cmdStart);\n bitStream.writeNibble(cmdLen - 2);\n\n // Copy bytes to dictionary\n for (let i = 0; i < cmdLen; i++) {\n dictionary[offset] = srcData[srcIx++];\n offset = (offset + 1) & 0xFF;\n }\n } else {\n // Write literal byte\n bitStream.writeBit(true);\n const val = srcData[srcIx++];\n bitStream.writeByte(val);\n dictionary[offset] = val;\n offset = (offset + 1) & 0xFF;\n }\n }\n bitStream.flush();\n\n // Get the final size including the bit stream data\n const finalSize = Math.max(dstIx, bitStream.currentPosition);\n return outputBuffer.slice(0, finalSize);\n }\n} ","import { ICompressionProvider } from '../types/compression';\nimport { QuintetLZ } from './QuintetLZ';\n\nexport * from './QuintetLZ';\n\nexport const CompressionAlgorithms = {\n 'QuintetLZ': () => new QuintetLZ(),\n} as Record<string, () => ICompressionProvider>;\n","\r\nexport class DbHeader {\r\n public bank: number;\r\n public address: number;\r\n public condition?: string;\r\n public parts: DbHeaderPart[];\r\n\r\n constructor(data: Partial<DbHeader>) {\r\n if(typeof data.address !== 'number') throw new Error('Address is required');\r\n if(!data.parts || !data.parts.length) throw new Error('Parts are required');\r\n\r\n this.bank = data.bank ?? 0;\r\n this.address = data.address;\r\n this.condition = data.condition ?? undefined;\r\n this.parts = data.parts.map(p => new DbHeaderPart(p));\r\n }\r\n}\r\n\r\nexport class DbHeaderPart {\r\n public name: string;\r\n public size: number;\r\n public type: string;\r\n public value?: any;\r\n\r\n constructor(data: Partial<DbHeaderPart>) {\r\n if(!data.name) throw new Error('Name is required');\r\n\r\n this.name = data.name;\r\n this.size = data.size ?? 0;\r\n this.type = data.type ?? '';\r\n this.value = data.value ?? undefined;\r\n }\r\n}","import { BinType } from '../types/resources';\r\nimport type { ICompressionProvider } from '../types/compression';\r\nimport { DbBlock } from './blocks';\r\nimport type { DbConfig } from './config';\r\nimport type { DbEntryPoint } from './entrypoints';\r\nimport { DbFile, DbFileType } from './files';\r\nimport { DbOverride } from './overrides';\r\nimport { DbStruct } from './structs';\r\nimport { DbAddressingMode } from './addressingMode';\r\nimport { DbStringType, DbStringCommand, DbStringLayer, DbStringDictionary } from './strings';\r\nimport { CopDef } from './cop';\r\nimport { listDirectory, readFileAsBinary, readJsonFile, saveFileAsText, saveFileAsBinary, readFileAsText } from '../utils';\r\nimport type { DbMnemonic } from './mnemonics';\r\nimport type { DbRewrite } from './rewrites';\r\nimport { DbPart } from './parts';\r\nimport type { DbLabel } from './labels';\r\nimport { DbTransform } from './transforms';\r\nimport type { BaseRomFileData, ProjectFileData, ProjectPayload } from '../supabase/types';\r\nimport { OpCode } from './opcode';\r\nimport { fromSupabaseByProject, fromSupabaseByGameRom } from '../supabase/rom-loader';\r\nimport { RomProcessingConstants } from '../types/constants';\r\nimport { ChunkFile } from '../types/files';\r\nimport { DbScene } from './scenes';\r\nimport { DbGroup } from './groups';\r\nimport { DbAsset } from './assets';\r\nimport { CompressionAlgorithms } from '../compression';\r\nimport { DbBaseRomModule, DbGameRomModule, DbProjectModule } from './modules';\r\nimport { BlockWriter } from '../rom/extraction/writer';\r\nimport { BlockReader } from '../rom/extraction/blocks';\r\nimport { RomWriter } from '../rom/rebuild/writer';\r\nimport { DbHeader } from './header';\r\n\r\n/**\r\n * Main database root class\r\n * Converted from GaiaLib/Database/DbRoot.cs\r\n */\r\nexport interface DbRoot {\r\n copDef: Record<number, CopDef>;\r\n copLookup: Record<string, CopDef>;\r\n mnemonics: Record<number, string>;\r\n //paths: Record<BinType, DbPath>;\r\n structs: Record<string, DbStruct>;\r\n stringTypes: Record<string, DbStringType>;\r\n stringDelimiters: string[];\r\n stringDelimiterLookup: Record<string, DbStringType>;\r\n //stringCharLookup: Record<string, DbStringType>;\r\n headers: DbHeader[];\r\n files: DbFile[];\r\n config: DbConfig;\r\n blocks: DbBlock[];\r\n overrides: Record<number, Record<string, any>>;\r\n labels: Record<number, string>;\r\n rewrites: Record<number, number>;\r\n entryPoints: DbEntryPoint[];\r\n opCodes: Record<number, OpCode>;\r\n opLookup: Record<string, OpCode[]>;\r\n addrLookup: Record<string, DbAddressingMode>;\r\n compression?: ICompressionProvider;\r\n baseRomFiles?: ChunkFile[];\r\n projectFiles?: ChunkFile[];\r\n groups: Record<string, DbGroup>;\r\n scenes: Record<number, DbScene>;\r\n fileTypes: Record<string, DbFileType>;\r\n fileExtLookup: Record<string, DbFileType>;\r\n}\r\n\r\n/**\r\n * Database root utilities\r\n */\r\nexport class DbRootUtils {\r\n /**\r\n * JSON serialization options\r\n */\r\n // public static readonly JSON_OPTIONS = {\r\n // propertyNamingPolicy: 'camelCase',\r\n // readCommentHandling: 'skip',\r\n // writeIndented: true\r\n // };\r\n\r\n // /**\r\n // * Load database from a single file\r\n // */\r\n // // public static async fromFile(dbFilePath: string): Promise<DbRoot> {\r\n // // return await readJsonFile<DbRoot>(dbFilePath);\r\n // // }\r\n\r\n // public static async fromFolder(folderPath: string, systemPath: string) : Promise<DbRoot> {\r\n // return this.fromGameModule(await this.gameModuleFromFolder(folderPath, systemPath));\r\n // }\r\n\r\n // /**\r\n // * Load database from folder structure\r\n // */\r\n // public static async gameModuleFromFolder(folderPath: string, systemPath: string): Promise<DbGameRomModule> {\r\n // return {\r\n // mnemonics: await readJsonFile<Record<number, string>>(`${folderPath}/mnemonics.json`),\r\n // overrides: await readJsonFile<Record<number, Record<string, any>>>(`${folderPath}/overrides.json`),\r\n // rewrites: await readJsonFile<Record<string, number>>(`${folderPath}/rewrites.json`),\r\n // blocks: await readJsonFile<Record<string, Record<string, Partial<DbBlock>>>>(`${folderPath}/blocks.json`),\r\n // files: await readJsonFile<Record<string, Record<string, Record<string, Partial<DbFile>>>>>(`${folderPath}/files.json`),\r\n // config: await readJsonFile<DbConfig>(`${folderPath}/config.json`),\r\n // labels: await readJsonFile<DbLabel[]>(`${folderPath}/labels.json`),\r\n // structs: await readJsonFile<Record<string, DbStruct>>(`${folderPath}/structs.json`),\r\n // copdef: await readJsonFile<Record<string, Partial<CopDef>>>(`${folderPath}/copdef.json`),\r\n // addrModes: await readJsonFile<Record<string, Partial<DbAddressingMode>>>(`${systemPath}/addressingModes.json`),\r\n // strings: await readJsonFile<Record<string, Partial<DbStringType>>>(`${folderPath}/stringTypes.json`),\r\n // transforms: await readJsonFile<Record<string, Partial<DbTransform>[]>>(`${folderPath}/transforms.json`),\r\n // groups: await readJsonFile<Record<string, Partial<DbGroup>>>(`${folderPath}/groups.json`),\r\n // fileTypes: await readJsonFile<Record<string, Partial<DbFileType>>>(`${folderPath}/fileTypes.json`),\r\n // }\r\n // }\r\n\r\n public static fromGameModule(module: DbGameRomModule): DbRoot {\r\n // Build lookup tables\r\n\r\n const opCodes = {} as Record<number, OpCode>;\r\n const opLookup = {} as Record<string, OpCode[]>;\r\n const addrLookup = Object.entries(module.addrModes).reduce((acc, x) => {\r\n const modeData = x[1];\r\n const modeName = x[0];\r\n for(const [mnem, code] of Object.entries(modeData.instructions ?? [])) {\r\n const opCode = new OpCode(code, mnem, modeName);\r\n opCodes[code] = opCode;\r\n if (!opLookup[mnem]) opLookup[mnem] = [];\r\n opLookup[mnem].push(opCode);\r\n }\r\n acc[modeName] = new DbAddressingMode({...modeData, name: modeName});\r\n return acc;\r\n }, {} as Record<string, DbAddressingMode>);\r\n\r\n const blocksArray: DbBlock[] = [];\r\n for (const [groupName, groupData] of Object.entries(module.blocks)) {\r\n for(const [blockName, blockData] of Object.entries(groupData)) {\r\n\r\n const partsData = blockData.parts as unknown as Record<string, Partial<DbPart>> ?? {};\r\n const parts = Object.entries(partsData).map((p) => {\r\n return new DbPart({...p[1], name: p[0]});\r\n });\r\n\r\n const transformList = (module.transforms[blockName] ?? []).map((t) => {\r\n return new DbTransform(t);\r\n });\r\n\r\n const block = new DbBlock({\r\n ...blockData, \r\n name: blockName, \r\n group: groupName,\r\n parts: parts,\r\n transforms: transformList\r\n });\r\n\r\n blocksArray.push(block);\r\n }\r\n }\r\n\r\n const sceneLookup = {} as Record<number, DbScene>;\r\n const groupLookup = Object.entries(module.groups).reduce((acc, x) => {\r\n const groupData = x[1];\r\n const groupName = x[0];\r\n\r\n const scenes = Object.entries(groupData.scenes ?? {}).reduce((acc, y) => {\r\n const sceneData = y[1];\r\n const sceneName = y[0];\r\n const scene = new DbScene({...sceneData, name: sceneName });\r\n sceneLookup[scene.id] = scene;\r\n acc[sceneName] = scene;\r\n return acc;\r\n }, {} as Record<string, DbScene>);\r\n \r\n acc[groupName] = new DbGroup({...groupData, name: groupName, scenes: scenes });\r\n return acc;\r\n }, {} as Record<string, DbGroup>);\r\n\r\n const fileList: DbFile[] = [];\r\n for(const [groupName, groupData] of Object.entries(module.files)) {\r\n for(const [sceneName, sceneData] of Object.entries(groupData)) {\r\n for(const [fileName, fileData] of Object.entries(sceneData)) {\r\n fileList.push(new DbFile({...fileData, name: fileName, group: groupName, scene: sceneName }));\r\n }\r\n }\r\n }\r\n\r\n const stringDelimiterLookup = {} as Record<string, DbStringType>;\r\n const stringDelimiterList: string[] = [];\r\n const stringLookup = Object.entries(module.strings).reduce((acc, x) => {\r\n const stringType = x[1];\r\n const name = x[0];\r\n const commands = Object.entries(stringType.commands ?? {}).reduce((acc, y) => {\r\n acc[y[0]] = new DbStringCommand({...y[1], name: y[0]});\r\n return acc;\r\n }, {} as Record<string, DbStringCommand>);\r\n const dictionaries = Object.entries(stringType.dictionaries ?? {}).reduce((acc, y) => {\r\n const dictionary = new DbStringDictionary({...y[1], name: y[0]});\r\n acc[y[0]] = dictionary;\r\n if(dictionary.command !== undefined) {\r\n commands[dictionary.command] = new DbStringCommand({id: dictionary.command, name: dictionary.name, dictionary: dictionary});\r\n }\r\n return acc;\r\n }, {} as Record<string, DbStringDictionary>);\r\n const st = new DbStringType({...stringType, name, commands, dictionaries});\r\n acc[name] = st;\r\n stringDelimiterLookup[st.delimiter] = st;\r\n stringDelimiterList.push(st.delimiter);\r\n return acc;\r\n }, {} as Record<string, DbStringType>);\r\n\r\n const structLookup = Object.entries(module.structs).reduce((acc, x) => {\r\n acc[x[0]] = new DbStruct({...x[1], name: x[0]});\r\n return acc;\r\n }, {} as Record<string, DbStruct>);\r\n\r\n\r\n const copCodes = {} as Record<number, CopDef>;\r\n const copLookup = Object.entries(module.copdef).reduce((acc, x) => {\r\n const copDef = x[1];\r\n const name = x[0];\r\n const def = new CopDef({...copDef, name});\r\n copCodes[def.id] = def;\r\n acc[name] = def;\r\n return acc;\r\n }, {} as Record<string, CopDef>);\r\n\r\n const extLookup = {} as Record<string, DbFileType>;\r\n const fileTypeLookup = {} as Record<string, DbFileType>;\r\n const fileTypes = Object.entries(module.fileTypes).reduce((acc, x) => {\r\n const fileType = x[1];\r\n const name = x[0];\r\n const type = new DbFileType({...fileType, name});\r\n extLookup[type.extension] = type;\r\n fileTypeLookup[type.name] = type;\r\n acc[name] = type;\r\n return acc;\r\n }, {} as Record<string, DbFileType>);\r\n\r\n const cfg = module.config;\r\n\r\n const compression = cfg.compression ? CompressionAlgorithms[cfg.compression]() : undefined;\r\n\r\n \r\n const baseRomChunks = (module as DbBaseRomModule).baseRomFiles ?? module.supaBaseRomFiles?.map((file: BaseRomFileData) => {\r\n const chunkFile = new ChunkFile(file.name, 0, 0, fileTypeLookup[file.type]);\r\n if(file.isText) {\r\n chunkFile.textData = file.text ?? undefined;\r\n chunkFile.size = file.text?.length ?? 0;\r\n } else {\r\n chunkFile.rawData = file.data;\r\n chunkFile.size = file.data?.length ?? 0;\r\n }\r\n return chunkFile;\r\n });\r\n \r\n const projectChunks = (module as DbProjectModule).projectFiles ?? module.supaProjectFiles?.map((file: ProjectFileData) => {\r\n const chunkFile = new ChunkFile(file.name, 0, 0, fileTypeLookup[file.type]);\r\n chunkFile.group = file.module ?? undefined;\r\n if(file.isText) {\r\n chunkFile.textData = file.text ?? undefined;\r\n chunkFile.size = file.text?.length ?? 0;\r\n } else {\r\n chunkFile.rawData = file.data;\r\n chunkFile.size = file.data?.length ?? 0;\r\n }\r\n return chunkFile;\r\n });\r\n\r\n // Build the database root\r\n const root: DbRoot = {\r\n headers: module.headers.map((h) => new DbHeader(h)),\r\n mnemonics: module.mnemonics,\r\n overrides: module.overrides,\r\n rewrites: module.rewrites,\r\n labels: module.labels,\r\n structs: structLookup,\r\n blocks: blocksArray.sort((a, b) => {\r\n const orderA = a.order ?? 0;\r\n const orderB = b.order ?? 0;\r\n if (orderA !== orderB) return orderA - orderB;\r\n return a.parts[0].start - b.parts[0].start;\r\n }),\r\n files: fileList,\r\n fileTypes,\r\n fileExtLookup: extLookup,\r\n copDef: copCodes,\r\n copLookup,\r\n config: cfg,\r\n opCodes,\r\n opLookup,\r\n addrLookup,\r\n entryPoints: cfg.entryPoints,\r\n stringTypes: stringLookup,\r\n stringDelimiters: stringDelimiterList,\r\n stringDelimiterLookup,\r\n compression,\r\n groups: groupLookup,\r\n scenes: sceneLookup,\r\n baseRomFiles: baseRomChunks,\r\n projectFiles: projectChunks\r\n };\r\n\r\n return root;\r\n }\r\n\r\n public static async applyFolder(root: DbRoot, folderPath: string, sourceFiles: ChunkFile[] = []) : Promise<ChunkFile[]> {\r\n const chunkFiles = sourceFiles;\r\n const folderEntries = await listDirectory(folderPath, { recursive: true });\r\n for(const entry of folderEntries) {\r\n if(!entry.isFile || !entry.extension) continue; //await this.applyFolder(root, entry.path, chunkFiles);\r\n \r\n const type = root.fileExtLookup[entry.extension];\r\n if(!type) continue;\r\n\r\n const existing = chunkFiles.find(x => x.name === entry.name && x.type.type === type.type);\r\n const chunkFile = existing ?? new ChunkFile(entry.name, 0, 0, type);\r\n\r\n if(chunkFile.type.type === 'Assembly' || chunkFile.type.type === 'Patch') {\r\n const chunkData = await readFileAsText(entry.path);\r\n chunkFile.textData = chunkData;\r\n chunkFile.size = chunkData.length;\r\n } else {\r\n const chunkData = await readFileAsBinary(entry.path);\r\n chunkFile.rawData = chunkData;\r\n chunkFile.size = chunkData.length;\r\n }\r\n if(!existing){\r\n const sourceFile = root.files.find(x => x.name === entry.name && x.type === type.type);\r\n if (sourceFile) {\r\n chunkFile.location = sourceFile.start;\r\n chunkFile.upper = sourceFile.upper;\r\n chunkFile.compressed = sourceFile.compressed;\r\n }\r\n \r\n chunkFiles.push(chunkFile);\r\n }\r\n }\r\n return chunkFiles;\r\n }\r\n\r\n \r\n public static async extractAllContent(root: DbRoot, romPath: string, outPath: string) : Promise<void> {\r\n const romData = await readFileAsBinary(romPath);\r\n const reader = new BlockReader(romData, root);\r\n const chunkFiles = reader.analyzeAndResolve();\r\n const writer = new BlockWriter(reader);\r\n\r\n for(const block of chunkFiles) {\r\n const ext = block.type.extension;\r\n const filePath = `${outPath}/${block.group ? (block.group + '/') : ''}${block.scene ? (block.scene + '/') : ''}${block.name}${ext ? '.' + ext : ''}`;\r\n if(block.parts?.length) {\r\n if(!block.textData) block.textData = writer.generateAsm(block);\r\n await saveFileAsText(filePath, block.textData);\r\n } else {\r\n if (!block.rawData) continue;\r\n await saveFileAsBinary(filePath, block.rawData);\r\n }\r\n }\r\n }\r\n\r\n public static async rebuildAllContent(root: DbRoot, inPath: string[], outPath: string) : Promise<ChunkFile[]> {\r\n var sourceFiles: ChunkFile[] = [];\r\n for(const path of inPath) {\r\n sourceFiles = await this.applyFolder(root, path, sourceFiles);\r\n }\r\n\r\n const romWriter = new RomWriter(root);\r\n const outData = await romWriter.repack(sourceFiles);\r\n await saveFileAsBinary(outPath, outData);\r\n\r\n return sourceFiles;\r\n }\r\n\r\n\r\n // /**\r\n // * Get path configuration for a resource type\r\n // */\r\n // public static getPath(root: DbRoot, type: BinType): DbPath {\r\n // return root.paths[type] || root.paths[BinType.Unknown];\r\n // }\r\n\r\n // /**\r\n // * Get resource path for a file\r\n // */\r\n // public static getResource(root: DbRoot, baseDir: string, name: string, type: BinType): string {\r\n // const res = this.getPath(root, type);\r\n // return `${baseDir}/${res.folder}/${name}.${res.extension}`;\r\n // }\r\n\r\n /**\r\n * Load database from Supabase using BaseRomBranch ID\r\n * @param baseRomBranchId - The ID of the BaseRomBranch to load\r\n * @returns Promise<DbRoot> containing the complete database root\r\n * @throws {Error} If the branch is not found or loading fails\r\n * \r\n * @example\r\n * ```typescript\r\n * const dbRoot = await DbRootUtils.fromSupabaseById('clm1234567890');\r\n * console.log(dbRoot.files.length);\r\n * ```\r\n */\r\n // public static async fromSupabaseById(baseRomBranchId: string): Promise<DbRoot> {\r\n // const payload = await fromSupabaseById(baseRomBranchId);\r\n // return this.fromSupabasePayload(payload);\r\n // }\r\n\r\n /**\r\n * Load database from Supabase using name-based lookup\r\n * @param options - Options for name-based lookup (optional)\r\n * @returns Promise<DbRoot> containing the complete database root\r\n * @throws {Error} If the branch is not found or loading fails\r\n * \r\n * @example\r\n * ```typescript\r\n * // Load default ROM (GaiaLabs BaseROM, main branch)\r\n * const dbRoot1 = await DbRootUtils.fromSupabase({});\r\n * \r\n * // Load specific ROM and branch\r\n * const dbRoot2 = await DbRootUtils.fromSupabase({\r\n * baseRomName: 'My Custom ROM',\r\n * branchName: 'development',\r\n * branchVersion: null\r\n * });\r\n * ```\r\n */\r\n // public static async fromSupabase(options?: FromSupabaseByNameOptions): Promise<DbRoot> {\r\n // const payload = await fromSupabaseByName(options);\r\n // return this.fromSupabasePayload(payload);\r\n // }\r\n\r\n // public static async fromSupabaseProject(projectName?: string, branchId?: string): Promise<DbRoot> {\r\n // const payload = await fromSupabaseByProject(projectName, branchId);\r\n // return this.fromSupabasePayload(payload);\r\n // }\r\n\r\n /**\r\n * Load database from GameRomBranch data (for ROM-only processing)\r\n * @param gameRomBranchData - Direct GameRomBranch data from Supabase API\r\n * @returns Promise<DbRoot> containing the complete database root\r\n */\r\n // public static async fromSupabaseGameRom(gameRomName?: string, branchId?: string): Promise<DbRoot> {\r\n // const payload = await fromSupabaseByGameRom(gameRomName, branchId);\r\n // return this.fromSupabasePayload(payload);\r\n // }\r\n\r\n /**\r\n * Convert Supabase payload to DbRoot structure\r\n * @private\r\n * @param payload - The ROM payload from Supabase\r\n * @returns DbRoot containing the processed database structure\r\n */\r\n // private static async fromSupabasePayload(payload: ProjectPayload): Promise<DbRoot> {\r\n \r\n // // Extract data from the Supabase payload\r\n // const gameRomBranch = payload.baseRomBranch.gameRomBranch;\r\n \r\n // const config = gameRomBranch.config;\r\n // const copDef = gameRomBranch.coplib;\r\n // const romFiles = gameRomBranch.files;\r\n // const romBlocks = gameRomBranch.blocks;\r\n // const romStrings = gameRomBranch.strings;\r\n // const romStructs = gameRomBranch.structs;\r\n // const romFixups = gameRomBranch.fixups;\r\n // const romScenes = gameRomBranch.scenes;\r\n\r\n // const platformBranch = gameRomBranch.platformBranch;\r\n // const instructionSet = platformBranch.instructionSet;\r\n // const addressingModes = platformBranch.addressingModes;\r\n // //const vectors = platformBranch.vectors;\r\n\r\n // const transforms = romFixups.transforms || [];\r\n\r\n // // Build configuration from available data\r\n // const compression = config.compression ? CompressionAlgorithms[config.compression]() : null;\r\n \r\n // const files: DbFile[] = Object.entries(romFiles).map((x: any) => {\r\n // const file = x[1];\r\n // file.start = file.location;\r\n // file.end = file.location + file.size;\r\n // //file.type = BinType[file.type as keyof typeof BinType] || BinType.Unknown;\r\n // file.name = x[0];\r\n // return file;\r\n // });\r\n \r\n // const blocks: DbBlock[] = Object.entries(romBlocks).map((x: any) => {\r\n // const block = x[1];\r\n // block.name = x[0];\r\n\r\n // const transform = transforms[block.name];\r\n // block.transforms = transform ? Object.entries(transform).map((t: any) => { return { key: t[0], value: t[1] } }) : [];\r\n \r\n // block.parts = Object.entries(block.parts)\r\n // .sort((a: any, b: any) => {\r\n // const orderA = a[1].order ?? 0;\r\n // const orderB = b[1].order ?? 0;\r\n // if (orderA !== orderB) {\r\n // return orderA - orderB;\r\n // }\r\n // return a[1].location - b[1].location;\r\n // })\r\n // .map((p: any) => {\r\n // const part = p[1];\r\n // part.name = p[0];\r\n // part.start = part.location;\r\n // part.end = part.location + part.size;\r\n // part.struct = part.type;\r\n // return part;\r\n // });\r\n\r\n // return block;\r\n // }).sort((a: any, b: any) => a.parts[0].location - b.parts[0].location);\r\n \r\n // const baseRomFiles : ChunkFile[] = payload.baseRomFiles && payload.baseRomFiles.map((file: BaseRomFileData) => {\r\n // const chunkFile = new ChunkFile(file.name, 0, 0, file.type as BinType);\r\n // if(file.isText) {\r\n // chunkFile.textData = file.text ?? undefined;\r\n // chunkFile.size = file.text?.length ?? 0;\r\n // } else {\r\n // chunkFile.rawData = file.data;\r\n // chunkFile.size = file.data?.length ?? 0;\r\n // }\r\n // return chunkFile;\r\n // });\r\n \r\n // const projectFiles : ChunkFile[] = payload.projectFiles && payload.projectFiles.map((file: ProjectFileData) => {\r\n // const chunkFile = new ChunkFile(file.name, 0, 0, file.type as BinType);\r\n // chunkFile.group = file.module ?? undefined;\r\n // if(file.isText) {\r\n // chunkFile.textData = file.text ?? undefined;\r\n // chunkFile.size = file.text?.length ?? 0;\r\n // } else {\r\n // chunkFile.rawData = file.data;\r\n // chunkFile.size = file.data?.length ?? 0;\r\n // }\r\n // return chunkFile;\r\n // });\r\n\r\n // // Extract other data from the JSON structures\r\n // const mnemonics = romFixups.mnemonics || {};\r\n // const opCodes = this.extractOpCodesFromInstructionSet(instructionSet);\r\n // const overrides = romFixups.overrides || {};\r\n // const rewrites = romFixups.rewrites || {};\r\n // const labels = romFixups.labels || {};\r\n // const structs = romStructs || {};\r\n // //const parts: DbPart[] = Array.isArray(typesJson.parts) ? typesJson.parts : [];\r\n // //const transforms: DbTransform[] = Array.isArray(typesJson.transforms) ? typesJson.transforms : [];\r\n // //const stringTypes = romTypes.strings || {};\r\n // //const stringCommands = romTypes.stringCommands || {};\r\n // //const stringLayers = Array.isArray(romTypes.stringLayers) ? romTypes.stringLayers : [];\r\n // //const copDef = Array.isArray(romTypes.copDef) ? romTypes.copDef : [];\r\n // const entryPoints = Array.isArray(config.entryPoints) ? config.entryPoints : [];\r\n \r\n\r\n // const stringTypes = Object.entries(romStrings).reduce((acc: any, x: any) => {\r\n // const strType = x[1];\r\n // strType.name = x[0];\r\n\r\n // const commands = Object.entries(strType.commands).reduce((acc: any, x: any) => {\r\n // const cmd = x[1];\r\n // acc[cmd.code] = {\r\n // key: cmd.code,\r\n // value: x[0],\r\n // types: cmd.types,\r\n // delimiter: cmd.delimiter,\r\n // halt: cmd.halt\r\n // };\r\n // return acc;\r\n // }, {} as Record<number, any>);\r\n // strType.commands = commands;\r\n\r\n // acc[strType.name] = strType;\r\n // return acc;\r\n // }, {} as Record<string, DbStringType>);\r\n \r\n // // Build lookup tables\r\n // const copLookup = Object.entries(copDef).reduce((acc: any, x: any) => {\r\n // const def = x[1];\r\n // def.mnem = x[0];\r\n // def.size = RomProcessingConstants.getSize(def.parts);\r\n // acc[x[0]] = def;\r\n // return acc;\r\n // }, {} as Record<string, CopDef>);\r\n \r\n // const copDefLookup = Object.values(copDef).reduce((acc: any, x: any) => {\r\n // acc[x.code] = x;\r\n // return acc;\r\n // }, {} as Record<number, CopDef>);\r\n \r\n \r\n // const opLookup = Object.entries(instructionSet).reduce((acc: any, x: any) => {\r\n // acc[x[0]] = Object.entries(x[1]).map((y: any) => new OpCode(y[1], x[0], y[0]));\r\n // return acc;\r\n // }, {});\r\n\r\n // const stringDelimiters = Object.values(stringTypes).map((x: any) => x?.delimiter).filter(Boolean);\r\n // const stringCharLookup = Object.values(stringTypes).reduce((acc: any, x: any) => {\r\n // if (x?.delimiter) {\r\n // acc[x.delimiter] = x;\r\n // }\r\n // return acc;\r\n // }, {});\r\n \r\n\r\n // const scenes = {} as Record<number, DbScene>;\r\n // const sceneGroups = Object.entries(romScenes ?? {}).reduce((acc: any, x: any) => {\r\n // const group = x[1];\r\n // const groupName = x[0];\r\n // const newGroup = {\r\n // name: groupName,\r\n // scenes: Object.entries(group).reduce((accy: any, y: any) => {\r\n // const scene = y[1];\r\n // const sceneName = y[0];\r\n // const newScene = {\r\n // name: sceneName,\r\n // id: scene.id,\r\n // group: groupName,\r\n // assets: scene.assets.map((asset: any, index: number) : DbAsset => {\r\n // const meta = { ...asset };\r\n // delete meta.type;\r\n // delete meta.data;\r\n // return { \r\n // index,\r\n // type: asset.type,\r\n // file: asset.data,\r\n // scene: sceneName,\r\n // meta\r\n // };\r\n // }),\r\n // };\r\n // if(scene.id) {\r\n // scenes[scene.id] = newScene;\r\n // }\r\n // accy[sceneName] = newScene;\r\n // return accy;\r\n // }, {} as Record<string, DbScene>)\r\n // }\r\n\r\n // acc[groupName] = newGroup;\r\n // return acc;\r\n // }, {} as Record<string, DbGroup>);\r\n \r\n \r\n // // Build the complete DbRoot structure\r\n // const root: DbRoot = {\r\n // mnemonics: Object.entries(mnemonics).reduce((acc: any, x: any) => {\r\n // acc[x[1]] = x[0];\r\n // return acc;\r\n // }, {} as Record<number, string>),\r\n // overrides: Array.isArray(overrides) ? overrides.reduce((acc: any, x: any) => {\r\n // acc[x.location] = x;\r\n // return acc;\r\n // }, {}) : overrides,\r\n // rewrites: Array.isArray(rewrites) ? rewrites.reduce((acc: any, x: any) => {\r\n // acc[x.location] = x.value;\r\n // return acc;\r\n // }, {}) : rewrites,\r\n // labels: Array.isArray(labels) ? labels.reduce((acc: any, x: any) => {\r\n // acc[x.location] = x.label;\r\n // return acc;\r\n // }, {}) : labels,\r\n // structs: Object.entries(structs).reduce((acc: any, x: any) => {\r\n // const struct = x[1];\r\n // struct.name = x[0];\r\n // acc[x[0]] = struct;\r\n // return acc;\r\n // }, {} as Record<string, DbStruct>),\r\n // blocks,\r\n // files,\r\n // copDef: copDefLookup as Record<number, CopDef>,\r\n // copLookup,\r\n // baseRomFiles,\r\n // projectFiles,\r\n // config,\r\n // opCodes,\r\n // opLookup,\r\n // addrLookup: addressingModes,\r\n // entryPoints,\r\n // //paths: config.paths,\r\n // stringTypes: stringTypes,\r\n // stringDelimiters,\r\n // //stringCharLookup: stringCharLookup as Record<string, DbStringType>,\r\n // compression,\r\n // groups: sceneGroups,\r\n // scenes\r\n // };\r\n\r\n // console.log('✅ Successfully transformed Supabase payload to DbRoot');\r\n // console.log(`📁 Files: ${files.length}, 🧱 Blocks: ${blocks.length}`);\r\n // console.log(`🎯 ROM: ${payload.baseRomBranch.baseRom.name} (${payload.baseRomBranch.name || 'main'})`);\r\n // console.log(`💾 BaseRom files: ${root?.baseRomFiles?.length} files, ${root.baseRomFiles?.reduce((sum, f) => sum + f.size, 0)} bytes total`);\r\n // console.log(`💾 Project files: ${root?.projectFiles?.length} files, ${root.projectFiles?.reduce((sum, f) => sum + f.size, 0)} bytes total`);\r\n \r\n // return root;\r\n // }\r\n\r\n /**\r\n * Extract and flatten OpCodes from the instruction set schema\r\n * @private\r\n * @param instructionSet - The instruction set object from the schema\r\n * @returns Array of OpCode objects with code, mnem, mode, and size properties\r\n */\r\n // private static extractOpCodesFromInstructionSet(instructionSet: any): OpCode[] {\r\n // const opCodes: OpCode[] = [];\r\n \r\n // for (const mnem in instructionSet) {\r\n // for (const mode in instructionSet[mnem]) {\r\n // const op = instructionSet[mnem][mode];\r\n // opCodes[op] = new OpCode(op, mnem, mode);\r\n // }\r\n // }\r\n \r\n // return opCodes;\r\n // }\r\n\r\n // /**\r\n // * Convert GameRomBranch data directly to DbRoot structure\r\n // * @private\r\n // * @param gameRomBranchData - Direct GameRomBranch data from Supabase API\r\n // * @returns DbRoot containing the processed database structure\r\n // */\r\n // private static async fromGameRomBranchData(gameRomBranchData: any): Promise<DbRoot> {\r\n \r\n // // Extract data from the GameRomBranch data\r\n // const config = gameRomBranchData.config;\r\n // const copDef = gameRomBranchData.coplib;\r\n // const romFiles = gameRomBranchData.files;\r\n // const romBlocks = gameRomBranchData.blocks;\r\n // const romTypes = gameRomBranchData.types;\r\n // const romFixups = gameRomBranchData.fixups;\r\n // const structs = gameRomBranchData.structs;\r\n\r\n // // Note: For direct GameRomBranch processing, we won't have platformBranch data\r\n // // So we'll use defaults or extract from what's available\r\n // const instructionSet = {}; // Will be empty for now\r\n // const addressingModes = {}; // Will be empty for now\r\n \r\n // const transforms = romFixups?.transforms || [];\r\n\r\n // // Build configuration from available data\r\n // const compression = CompressionRegistry.get(config?.compression || 'QuintetLZ');\r\n \r\n // const files: DbFile[] = romFiles ? Object.entries(romFiles).map((x: any) => {\r\n // const file = x[1];\r\n // file.start = file.location;\r\n // file.end = file.location + file.size;\r\n // file.name = x[0];\r\n // return file;\r\n // }) : [];\r\n \r\n // const blocks: DbBlock[] = romBlocks ? Object.entries(romBlocks).map((x: any) => {\r\n // const block = x[1];\r\n // block.name = x[0];\r\n\r\n // const transform = transforms[block.name];\r\n // block.transforms = transform ? Object.entries(transform).map((t: any) => { return { key: t[0], value: t[1] } }) : [];\r\n \r\n // block.parts = Object.entries(block.parts || {})\r\n // .sort((a: any, b: any) => {\r\n // const orderA = a[1].order ?? 0;\r\n // const orderB = b[1].order ?? 0;\r\n // if (orderA !== orderB) {\r\n // return orderA - orderB;\r\n // }\r\n // return a[1].location - b[1].location;\r\n // })\r\n // .map((p: any) => {\r\n // const part = p[1];\r\n // part.name = p[0];\r\n // part.start = part.location;\r\n // part.end = part.location + part.size;\r\n // part.struct = part.type;\r\n // return part;\r\n // });\r\n\r\n // return block;\r\n // }).sort((a: any, b: any) => a.parts[0]?.location || 0 - b.parts[0]?.location || 0) : [];\r\n \r\n // // For GameRomBranch direct processing, we don't have baseRomFiles or projectFiles\r\n // const baseRomFiles: ChunkFile[] = [];\r\n // const projectFiles: ChunkFile[] = [];\r\n \r\n // const entryPoints: DbEntryPoint[] = [];\r\n \r\n // // Extract overrides from configs (if available)\r\n // const overrides: Record<number, DbOverride> = {};\r\n \r\n // // Build OpCode array from instruction set\r\n // const opCodes = this.extractOpCodesFromInstructionSet(instructionSet);\r\n \r\n // // Build lookup tables\r\n // const copDefLookup = Object.values(copDef || {}).reduce((acc: any, x: any) => {\r\n // acc[x.code] = x;\r\n // return acc;\r\n // }, {} as Record<number, CopDef>);\r\n \r\n // const opLookup = Object.entries(instructionSet).reduce((acc: any, x: any) => {\r\n // acc[x[0]] = Object.entries(x[1]).map((y: any) => new OpCode(y[1], x[0], y[0]));\r\n // return acc;\r\n // }, {});\r\n\r\n // const stringDelimiters = Object.values(romTypes || {}).map((x: any) => x?.delimiter).filter(Boolean);\r\n // const stringCharLookup = Object.values(romTypes || {}).reduce((acc: any, x: any) => {\r\n // if (x?.delimiter) {\r\n // acc[x.delimiter] = x;\r\n // }\r\n // return acc;\r\n // }, {});\r\n \r\n // // Create the root object\r\n // const dbRoot: DbRoot = {\r\n // copDef: copDefLookup as Record<number, CopDef>,\r\n // copLookup: copDef || {},\r\n // stringTypes: romTypes || {},\r\n // stringDelimiters,\r\n // stringCharLookup: stringCharLookup as Record<string, DbStringType>,\r\n // structs: structs || {},\r\n // files,\r\n // blocks,\r\n // entryPoints,\r\n // overrides,\r\n // labels: {},\r\n // rewrites: {},\r\n // compression,\r\n // opCodes,\r\n // opLookup,\r\n // addrLookup: addressingModes,\r\n // mnemonics: {},\r\n // baseRomFiles,\r\n // projectFiles,\r\n // config: config || {}\r\n // };\r\n \r\n // return dbRoot;\r\n // }\r\n} ","\r\nexport class DbOverride {\r\n location: number;\r\n register: string;\r\n value: number;\r\n\r\n constructor(values: Partial<DbOverride>) {\r\n if(typeof values.value !== 'number') throw new Error('Value is required');\r\n if(typeof values.location !== 'number') throw new Error('Location is required');\r\n if(!values.register) throw new Error('Register is required');\r\n\r\n this.location = values.location;\r\n this.register = values.register;\r\n this.value = values.value;\r\n\r\n }\r\n} ","/**\r\n * Database path configuration\r\n * Converted from GaiaLib/Database/DbPath.cs\r\n */\r\nexport interface DbPath {\r\n folder: string;\r\n extension: string;\r\n}\r\n\r\n/**\r\n * Creates a default DbPath\r\n */\r\nexport function createDbPath(folder: string = 'misc', extension: string = 'bin'): DbPath {\r\n return {\r\n folder,\r\n extension\r\n };\r\n} ","/**\r\n * Supabase client configuration and initialization\r\n */\r\n\r\nimport { createClient, SupabaseClient } from '@supabase/supabase-js';\r\n\r\n/**\r\n * Database interface definitions based on Prisma schema\r\n * These types represent the structure of data returned from Supabase queries\r\n */\r\nexport interface Database {\r\n public: {\r\n Tables: {\r\n BaseRom: {\r\n Row: {\r\n id: string;\r\n name: string;\r\n gameId: string;\r\n gameRomId: string;\r\n createdAt: string;\r\n updatedAt: string;\r\n };\r\n };\r\n BaseRomBranch: {\r\n Row: {\r\n id: string;\r\n name: string | null;\r\n version: number | null;\r\n isPublic: boolean;\r\n baseRomId: string;\r\n gameRomBranchId: string;\r\n fileCrcs: number[];\r\n createdAt: string;\r\n updatedAt: string;\r\n };\r\n };\r\n GameRomBranch: {\r\n Row: {\r\n id: string;\r\n name: string | null;\r\n version: number | null;\r\n isPublic: boolean;\r\n gameRomId: string;\r\n platformBranchId: string;\r\n coplib: any | null;\r\n config: any | null;\r\n files: any | null;\r\n blocks: any | null;\r\n fixups: any | null;\r\n strings: any | null;\r\n structs: any | null;\r\n scenes: any | null;\r\n createdAt: string;\r\n updatedAt: string;\r\n };\r\n };\r\n GameRomBranchAsset: {\r\n Row: {\r\n id: string;\r\n name: string;\r\n type: string;\r\n gameRomBranchId: string;\r\n text: string | null;\r\n data: string | null;\r\n createdAt: string;\r\n updatedAt: string;\r\n };\r\n };\r\n PlatformBranch: {\r\n Row: {\r\n id: string;\r\n name: string | null;\r\n version: number | null;\r\n isPublic: boolean;\r\n platformId: string;\r\n addressingModes: any | null;\r\n instructionSet: any | null;\r\n vectors: any | null;\r\n createdAt: string;\r\n updatedAt: string;\r\n };\r\n };\r\n BaseRomFile: {\r\n Row: {\r\n id: string;\r\n name: string;\r\n type: string;\r\n version: number | null;\r\n crc: number | null;\r\n meta: any | null;\r\n baseRomId: string;\r\n data: string; // Base64 encoded binary data\r\n createdAt: string;\r\n updatedAt: string;\r\n };\r\n };\r\n };\r\n };\r\n}\r\n\r\n/**\r\n * Singleton Supabase client instance\r\n */\r\nlet supabaseClient: SupabaseClient<Database> | null = null;\r\n\r\n/**\r\n * Create and configure a Supabase client instance\r\n * @returns Configured Supabase client\r\n */\r\nexport function createSupabaseClient(): SupabaseClient<Database> {\r\n // Validate required environment variables\r\n //validateEnvironmentVariables(['SUPABASE_URL', 'SUPABASE_ANON_KEY']);\r\n \r\n const supabaseUrl = 'https://adwobxutnpmjbmhdxrzx.supabase.co';\r\n const supabaseAnonKey = 'sb_publishable_uBZdKmgGql5sDNGpj1DVMQ_opZ2V4kV';\r\n \r\n return createClient<Database>(supabaseUrl, supabaseAnonKey, {\r\n auth: {\r\n // Disable auth for public data access\r\n persistSession: false,\r\n autoRefreshToken: false,\r\n },\r\n db: {\r\n // Configure database connection\r\n schema: 'public',\r\n },\r\n });\r\n}\r\n\r\n/**\r\n * Get the singleton Supabase client instance\r\n * Creates the instance if it doesn't exist\r\n * @returns Supabase client instance\r\n */\r\nexport function getSupabaseClient(): SupabaseClient<Database> {\r\n if (!supabaseClient) {\r\n supabaseClient = createSupabaseClient();\r\n }\r\n return supabaseClient;\r\n}\r\n\r\n/**\r\n * Reset the singleton client instance (useful for testing)\r\n */\r\nexport function resetSupabaseClient(): void {\r\n supabaseClient = null;\r\n}\r\n\r\n// /**\r\n// * Test the Supabase connection by performing a simple query\r\n// * @returns Promise that resolves to true if connection is successful\r\n// * @throws Error if connection fails\r\n// */\r\n// export async function testSupabaseConnection(): Promise<boolean> {\r\n// try {\r\n// const client = getSupabaseClient();\r\n \r\n// // Perform a simple query to test the connection\r\n// const { data, error } = await client\r\n// .from('BaseRom')\r\n// .select('id')\r\n// .limit(1);\r\n \r\n// if (error) {\r\n// throw new Error(`Supabase connection test failed: ${error.message}`);\r\n// }\r\n \r\n// return true;\r\n// } catch (error) {\r\n// throw new Error(`Failed to connect to Supabase: ${error instanceof Error ? error.message : 'Unknown error'}`);\r\n// }\r\n// }\r\n","/**\r\n * Utility functions for Supabase integration\r\n */\r\n\r\n/**\r\n * Get environment variable value that works in both browser and Node.js contexts\r\n * @param key - The environment variable key to retrieve\r\n * @throws {Error} If the environment variable is not set\r\n * @returns The environment variable value\r\n */\r\nexport function getEnvVar(key: string): string {\r\n let value = '';\r\n\r\n // Try different environment variable sources in order of preference\r\n try {\r\n // Browser with Vite (import.meta.env) - check if we're in a browser environment\r\n if (typeof globalThis !== 'undefined' &&\r\n typeof (globalThis as any).window !== 'undefined' &&\r\n typeof import.meta !== 'undefined' &&\r\n (import.meta as any).env) {\r\n const env = (import.meta as any).env;\r\n // Try the exact key first\r\n value = env[key] ||\r\n // Try with VITE_ prefix if not already prefixed\r\n (key.startsWith('VITE_') ? '' : env[`VITE_${key}`]) ||\r\n '';\r\n }\r\n } catch (error) {\r\n // import.meta might not be available in all contexts, continue to Node.js fallback\r\n }\r\n\r\n // Node.js (process.env) - fallback or primary for server-side\r\n if (!value && typeof process !== 'undefined' && process.env) {\r\n value = process.env[key] ||\r\n // Try with VITE_ prefix if not already prefixed (for Node.js build tools)\r\n (key.startsWith('VITE_') ? '' : process.env[`VITE_${key}`]) ||\r\n '';\r\n }\r\n\r\n if (!value) {\r\n throw new Error(`Required environment variable ${key} is not set`);\r\n }\r\n\r\n return value;\r\n}\r\n\r\n/**\r\n * Convert base64 string to Uint8Array for binary data processing\r\n * @param base64 - Base64 encoded string\r\n * @returns Uint8Array containing the binary data\r\n */\r\nexport function base64ToUint8Array(base64: string): Uint8Array {\r\n // Handle data URLs by extracting just the base64 part\r\n const base64Data = base64.includes(',') ? base64.split(',')[1] : base64;\r\n \r\n try {\r\n // Use browser's built-in atob if available\r\n if (typeof atob !== 'undefined') {\r\n const binaryString = atob(base64Data);\r\n const bytes = new Uint8Array(binaryString.length);\r\n for (let i = 0; i < binaryString.length; i++) {\r\n bytes[i] = binaryString.charCodeAt(i);\r\n }\r\n return bytes;\r\n }\r\n \r\n // Node.js fallback\r\n if (typeof Buffer !== 'undefined') {\r\n return new Uint8Array(Buffer.from(base64Data, 'base64'));\r\n }\r\n \r\n throw new Error('No base64 decoding method available');\r\n } catch (error) {\r\n throw new Error(`Failed to decode base64 data: ${error instanceof Error ? error.message : 'Unknown error'}`);\r\n }\r\n}\r\n\r\n/**\r\n * Convert hex-encoded string to Uint8Array\r\n * @param hexString - Hex encoded string (with or without \\x prefix)\r\n * @returns Uint8Array containing the binary data\r\n */\r\nexport function hexToUint8Array(hexString: string): Uint8Array {\r\n try {\r\n // Remove \\x prefixes and any whitespace\r\n let cleanHex = hexString.replace(/\\\\x/g, '').replace(/\\s/g, '');\r\n\r\n // Ensure even length\r\n if (cleanHex.length % 2 !== 0) {\r\n throw new Error('Hex string must have even length');\r\n }\r\n\r\n const bytes = new Uint8Array(cleanHex.length / 2);\r\n for (let i = 0; i < cleanHex.length; i += 2) {\r\n const hexByte = cleanHex.substring(i, i + 2);\r\n const byte = parseInt(hexByte, 16);\r\n if (isNaN(byte)) {\r\n throw new Error(`Invalid hex character at position ${i}: ${hexByte}`);\r\n }\r\n bytes[i / 2] = byte;\r\n }\r\n\r\n return bytes;\r\n } catch (error) {\r\n throw new Error(`Failed to decode hex data: ${error instanceof Error ? error.message : 'Unknown error'}`);\r\n }\r\n}\r\n\r\n/**\r\n * Convert binary data to appropriate format based on the input string\r\n * Automatically detects if the input is hex-encoded or base64\r\n * @param dataString - Either hex-encoded string (starting with \\x) or base64 string\r\n * @returns Uint8Array containing the binary data\r\n */\r\nexport function decodeDataString(dataString: string): Uint8Array {\r\n // Check if it's hex-encoded (starts with \\x)\r\n if (dataString.startsWith('\\\\x')) {\r\n return hexToUint8Array(dataString);\r\n }\r\n\r\n // Otherwise assume it's base64\r\n return base64ToUint8Array(dataString);\r\n}\r\n\r\n/**\r\n * Convert Uint8Array to base64 string\r\n * @param uint8Array - Binary data as Uint8Array\r\n * @returns Base64 encoded string\r\n */\r\nexport function uint8ArrayToBase64(uint8Array: Uint8Array): string {\r\n try {\r\n // Use browser's built-in btoa if available\r\n if (typeof btoa !== 'undefined') {\r\n const binaryString = Array.from(uint8Array)\r\n .map(byte => String.fromCharCode(byte))\r\n .join('');\r\n return btoa(binaryString);\r\n }\r\n \r\n // Node.js fallback\r\n if (typeof Buffer !== 'undefined') {\r\n return Buffer.from(uint8Array).toString('base64');\r\n }\r\n \r\n throw new Error('No base64 encoding method available');\r\n } catch (error) {\r\n throw new Error(`Failed to encode base64 data: ${error instanceof Error ? error.message : 'Unknown error'}`);\r\n }\r\n}\r\n\r\n/**\r\n * Validate that required environment variables are set\r\n * @param requiredVars - Array of environment variable names that must be set\r\n * @throws {Error} If any required environment variable is missing\r\n */\r\nexport function validateEnvironmentVariables(requiredVars: string[]): void {\r\n const missingVars: string[] = [];\r\n \r\n for (const varName of requiredVars) {\r\n try {\r\n getEnvVar(varName);\r\n } catch {\r\n missingVars.push(varName);\r\n }\r\n }\r\n \r\n if (missingVars.length > 0) {\r\n throw new Error(\r\n `Missing required environment variables: ${missingVars.join(', ')}\\n` +\r\n 'For web/Vite environments, use VITE_ prefixed variables (e.g., VITE_SUPABASE_URL, VITE_SUPABASE_ANON_KEY)\\n' +\r\n 'For Node.js environments, use the variable names directly (e.g., SUPABASE_URL, SUPABASE_ANON_KEY)'\r\n );\r\n }\r\n}\r\n","/**\n * TypeScript interfaces for Supabase API responses\n * These types represent the structured data returned from ROM database queries\n */\n\nexport interface PlatformData {\n id: string;\n name: string;\n meta: any | null;\n createdAt: string;\n updatedAt: string;\n}\n\nexport interface BranchBaseData {\n id: string;\n name: string | null;\n version: number | null;\n isActive?: boolean | null;\n notes?: string[] | null;\n createdAt: string;\n updatedAt: string;\n}\n\nexport interface FileBaseData {\n id: string;\n name: string;\n type: string;\n version: number | null;\n crc: number | null;\n meta: any | null;\n isText: boolean;\n text: string | null;\n data: Uint8Array | null;\n createdAt: string;\n updatedAt: string;\n}\n\nexport interface FileBaseRaw extends Omit<FileBaseData, 'data'> {\n data: string | null;\n}\n\n/**\n * Platform branch information containing instruction set and addressing modes\n */\nexport interface PlatformBranchData extends BranchBaseData {\n platformId: string;\n addressingModes: any | null; // JSON field\n headers: any | null; // JSON field\n vectors: any | null; // JSON field\n types: any | null; // JSON field\n platform: PlatformData;\n}\n\n/**\n * Game ROM branch information with platform reference\n */\nexport interface GameRomBranchData extends BranchBaseData {\n gameRomId: string;\n platformBranchId: string;\n coplib: any | null; // JSON field\n config: any | null; // JSON field\n files: any | null; // JSON field\n blocks: any | null; // JSON field\n rewrites: any | null; // JSON field\n transforms: any | null; // JSON field\n overrides: any | null; // JSON field\n labels: any | null; // JSON field\n mnemonics: any | null; // JSON field\n fileTypes: any | null; // JSON field\n groups: any | null; // JSON field\n strings: any | null; // JSON field\n structs: any | null; // JSON field\n gameRom: GameRomData;\n platformBranch: PlatformBranchData;\n}\n\nexport interface GameRomArtifactData extends FileBaseData {\n gameRomId: string;\n}\n\nexport interface GameRomArtifactRaw extends FileBaseRaw {\n gameRomId: string;\n}\n\nexport interface GameRomBranchArtifactRaw {\n id: string;\n branchId: string;\n artifactId: string;\n artifact: GameRomArtifactRaw;\n}\n\n/**\n * Base ROM information\n */\nexport interface BaseRomData {\n id: string;\n name: string;\n gameId: string;\n gameRomId: string;\n createdAt: string;\n updatedAt: string;\n}\n\nexport interface GameData {\n id: string;\n name: string;\n createdAt: string;\n updatedAt: string;\n}\n\nexport interface DeveloperData {\n id: string;\n name: string;\n meta: any | null;\n createdAt: string;\n updatedAt: string;\n}\n\nexport interface GameDeveloperData {\n id: string;\n gameId: string;\n developerId: string;\n createdAt: string;\n updatedAt: string;\n game: GameData;\n developer: DeveloperData;\n}\n\nexport interface RegionData {\n id: string;\n name: string;\n meta: any | null;\n createdAt: string;\n updatedAt: string;\n}\n\nexport interface GameRomData {\n id: string;\n crc: number;\n meta: any | null;\n gameId: string;\n regionId: string;\n createdAt: string;\n updatedAt: string;\n game: GameData;\n region: RegionData;\n}\n\n\n/**\n * Base ROM branch with complete relationship chain\n */\nexport interface BaseRomBranchData extends BranchBaseData {\n baseRomId: string;\n gameRomBranchId: string;\n gameRomBranch: GameRomBranchData;\n baseRom: BaseRomData;\n}\n\n/**\n * Base ROM file containing binary data\n */\nexport interface BaseRomFileData extends FileBaseData {\n baseRomId: string;\n}\n\nexport interface BaseRomBranchFileRaw {\n id: string;\n branchId: string;\n fileId: string;\n file: BaseRomFileRaw;\n}\n\n/**\n * Raw BaseRomFile data as returned from Supabase (before conversion)\n */\nexport interface BaseRomFileRaw extends FileBaseRaw {\n baseRomId: string;\n}\n\n/**\n * Complete ROM payload containing branch data and files\n */\nexport interface BaseRomPayload {\n baseRomBranch: BaseRomBranchData;\n files: BaseRomFileData[];\n}\n\n/**\n * Options for loading ROM data by name\n */\nexport interface FromSupabaseByNameOptions {\n /**\n * Name of the game to load\n * @default 'Illusion of Gaia'\n */\n gameName: string;\n\n /**\n * Name of the base ROM to load\n * @default 'GaiaLabs BaseROM'\n */\n baseRomName: string;\n \n /**\n * Name of the branch to load\n * Set to null to load the main/develop branch\n * Set to undefined to not filter by branch name\n */\n branchName?: string | null;\n \n /**\n * Version of the branch to load\n * Set to null to load the latest/main version\n * Set to undefined to not filter by version\n */\n branchVersion?: number | null;\n}\n\n/**\n * Error codes for Supabase operations\n */\nexport enum SupabaseErrorCode {\n BRANCH_NOT_FOUND = 'BRANCH_NOT_FOUND',\n ROM_NOT_FOUND = 'ROM_NOT_FOUND',\n FILES_NOT_FOUND = 'FILES_NOT_FOUND',\n NETWORK_ERROR = 'NETWORK_ERROR',\n INVALID_DATA = 'INVALID_DATA',\n ENVIRONMENT_ERROR = 'ENVIRONMENT_ERROR',\n PERMISSION_ERROR = 'PERMISSION_ERROR',\n}\n\n/**\n * Custom error class for Supabase operations\n */\nexport class SupabaseFromError extends Error {\n constructor(\n message: string, \n public readonly code: SupabaseErrorCode,\n public readonly details?: any\n ) {\n super(message);\n this.name = 'SupabaseFromError';\n }\n}\n\n/**\n * Result type for async operations that may fail\n */\nexport type SupabaseResult<T> = {\n data: T;\n error: null;\n} | {\n data: null;\n error: SupabaseFromError;\n};\n\n/**\n * Project information\n */\nexport interface ProjectData {\n id: string;\n name: string;\n meta: any | null; // JSON field\n gameId: string;\n baseRomId: string;\n createdAt: string;\n updatedAt: string;\n}\n\n/**\n * Project branch with complete relationship chain\n */\nexport interface ProjectBranchData extends BranchBaseData {\n projectId: string;\n baseRomBranchId: string;\n modules: any[]; // JSON array\n project: ProjectData;\n baseRomBranch: BaseRomBranchData;\n}\n\n/**\n * Project file containing binary data\n */\nexport interface ProjectFileData extends FileBaseData {\n module: string | null;\n projectId: string;\n}\n\nexport interface ProjectBranchFileRaw {\n id: string;\n branchId: string;\n fileId: string;\n file: ProjectFileRaw;\n}\n\n/**\n * Raw ProjectFile data as returned from Supabase (before conversion)\n */\nexport interface ProjectFileRaw extends FileBaseRaw {\n module: string | null;\n projectId: string;\n}\n\n/**\n * Complete Project payload containing branch data and files\n */\nexport interface ProjectPayload {\n projectBranch: ProjectBranchData;\n projectFiles: ProjectFileData[];\n baseRomBranch: BaseRomBranchData;\n baseRomFiles: BaseRomFileData[];\n}\n\n/**\n * Options for loading Project data by name\n */\nexport interface FromSupabaseByProjectOptions {\n projectName: string;\n /**\n * Name of the branch to load\n * Set to null to load the main/develop branch\n * Set to undefined to not filter by branch name\n */\n branchName?: string | null;\n \n /**\n * Version of the branch to load\n * Set to null to load the latest/main version\n * Set to undefined to not filter by version\n */\n branchVersion?: number | null;\n}\n\n/**\n * Query statistics for performance monitoring\n */\nexport interface QueryStats {\n branchQueryTime: number;\n fileQueryTime: number;\n totalTime: number;\n fileCount: number;\n}\n","/**\n * ROM data loading functions for Supabase integration\n * \n * This module provides functions to load ROM branch data and files from Supabase,\n * enabling cloud-based ROM database functionality for the GaiaLabs platform.\n */\n\nimport { getSupabaseClient } from './client';\nimport { decodeDataString } from './utils';\nimport {\n BaseRomPayload,\n BaseRomBranchData,\n BaseRomFileData,\n FromSupabaseByNameOptions,\n ProjectPayload,\n ProjectBranchData,\n ProjectFileData,\n SupabaseFromError,\n SupabaseErrorCode,\n QueryStats,\n GameRomBranchData,\n ProjectData,\n FileBaseRaw,\n FileBaseData,\n ProjectBranchFileRaw,\n BaseRomBranchFileRaw\n} from './types';\nimport { DbGameRomModule } from '../database';\n\n/**\n * Load ROM data from Supabase using a BaseRomBranch ID\n * \n * @param baseRomBranchId - The ID of the BaseRomBranch to load\n * @returns Promise<BaseRomPayload> containing the branch data and files\n * @throws {SupabaseFromError} If the branch is not found or other errors occur\n * \n * @example\n * ```typescript\n * const payload = await fromSupabaseById('clm1234567890');\n * console.log(payload.baseRomBranch.name);\n * console.log(`Loaded ${payload.files.length} files`);\n * ```\n */\nexport async function fromSupabaseById(baseRomBranchId: string): Promise<BaseRomPayload> {\n const startTime = performance.now();\n let branchQueryTime = 0;\n let fileQueryTime = 0;\n \n try {\n const client = getSupabaseClient();\n \n // Step 1: Get the BaseRomBranch with all related data using joins\n const branchStart = performance.now();\n \n const { data: branchData, error: branchError } = await client\n .from('BaseRomBranch')\n .select(`\n id,\n name,\n version,\n isActive,\n notes,\n baseRomId,\n gameRomBranchId,\n createdAt,\n updatedAt,\n gameRomBranch:GameRomBranch!inner(\n id,\n name,\n version,\n isActive,\n notes,\n gameRomId,\n platformBranchId,\n config,\n files,\n blocks,\n rewrites,\n transforms,\n overrides,\n labels,\n mnemonics,\n fileTypes,\n groups,\n strings,\n structs,\n createdAt,\n updatedAt,\n platformBranch:PlatformBranch!inner(\n id,\n name,\n version,\n isActive,\n notes,\n platformId,\n addressingModes,\n vectors,\n types,\n createdAt,\n updatedAt\n )\n ),\n baseRom:BaseRom!inner(\n id,\n name,\n gameId,\n gameRomId,\n createdAt,\n updatedAt\n )\n `)\n .eq('id', baseRomBranchId)\n .single();\n \n branchQueryTime = performance.now() - branchStart;\n \n if (branchError || !branchData) {\n throw new SupabaseFromError(\n `BaseRomBranch not found with ID: ${baseRomBranchId}`,\n SupabaseErrorCode.BRANCH_NOT_FOUND,\n { baseRomBranchId, error: branchError }\n );\n }\n \n // Step 2: Load all the BaseRomFile data using the fileCrcs array\n const files = await loadBaseRomFiles(baseRomBranchId);\n \n fileQueryTime = performance.now() - branchStart - branchQueryTime;\n \n const payload: BaseRomPayload = {\n baseRomBranch: branchData as unknown as BaseRomBranchData,\n files,\n };\n \n // Log performance statistics\n const totalTime = performance.now() - startTime;\n const stats: QueryStats = {\n branchQueryTime,\n fileQueryTime,\n totalTime,\n fileCount: files.length,\n };\n \n console.log('ROM load stats:', stats);\n \n return payload;\n \n } catch (error) {\n if (error instanceof SupabaseFromError) {\n throw error;\n }\n \n throw new SupabaseFromError(\n `Failed to load ROM data: ${error instanceof Error ? error.message : 'Unknown error'}`,\n SupabaseErrorCode.NETWORK_ERROR,\n { baseRomBranchId, error }\n );\n }\n}\n\n/**\n * Load ROM data from Supabase using name-based lookup\n * \n * @param options - Options for name-based lookup\n * @returns Promise<BaseRomPayload> containing the branch data and files\n * @throws {SupabaseFromError} If the branch is not found or other errors occur\n * \n * @example\n * ```typescript\n * // Load default ROM (GaiaLabs BaseROM, main branch)\n * const payload1 = await fromSupabaseByName({});\n * \n * // Load specific ROM and branch\n * const payload2 = await fromSupabaseByName({\n * baseRomName: 'My Custom ROM',\n * branchName: 'development',\n * branchVersion: null // latest version\n * });\n * \n * // Load main branch explicitly\n * const payload3 = await fromSupabaseByName({\n * baseRomName: 'GaiaLabs BaseROM',\n * branchName: null, // main branch\n * branchVersion: null // latest version\n * });\n * ```\n */\nexport async function fromSupabaseByName(\n options: FromSupabaseByNameOptions\n): Promise<BaseRomPayload> {\n const {\n gameName,\n baseRomName,\n branchName,\n branchVersion,\n } = options;\n \n const startTime = performance.now();\n let branchQueryTime = 0;\n let fileQueryTime = 0;\n \n try {\n const client = getSupabaseClient();\n \n // Step 1: Build query with filters\n const branchStart = performance.now();\n \n let query = client\n .from('BaseRomBranch')\n .select(`\n id,\n name,\n version,\n isActive,\n notes,\n baseRomId,\n gameRomBranchId,\n createdAt,\n updatedAt,\n gameRomBranch:GameRomBranch!inner(\n id,\n name,\n version,\n isActive,\n notes,\n gameRomId,\n platformBranchId,\n config,\n coplib,\n files,\n blocks,\n rewrites,\n transforms,\n overrides,\n labels,\n mnemonics,\n fileTypes,\n strings,\n structs,\n groups,\n createdAt,\n updatedAt,\n platformBranch:PlatformBranch!inner(\n id,\n name,\n version,\n isActive,\n notes,\n platformId,\n addressingModes,\n vectors,\n headers,\n types,\n createdAt,\n updatedAt\n )\n ),\n baseRom:BaseRom!inner(\n id,\n name,\n gameId,\n gameRomId,\n createdAt,\n updatedAt,\n game:Game!inner(\n id,\n name,\n createdAt,\n updatedAt\n )\n )\n `);\n \n // Filter by Game name\n query = query.eq('baseRom.game.name', gameName);\n \n // Filter by BaseRom name\n query = query.eq('baseRom.name', baseRomName);\n \n // Filter by branch name if specified\n if (branchName !== undefined) {\n if (branchName === null) {\n query = query.is('name', null);\n } else {\n query = query.eq('name', branchName);\n }\n }\n \n // Filter by branch version if specified\n if (branchVersion !== undefined) {\n if (branchVersion === null) {\n query = query.is('version', null);\n } else {\n query = query.eq('version', branchVersion);\n }\n }\n \n // Execute query - get single result\n const { data: branchData, error: branchError } = await query.single<BaseRomBranchData>();\n \n branchQueryTime = performance.now() - branchStart;\n \n if (branchError || !branchData) {\n throw new SupabaseFromError(\n `BaseRomBranch not found for criteria: gameName=\"${gameName}\", baseRomName=\"${baseRomName}\", branchName=${branchName}, branchVersion=${branchVersion}`,\n SupabaseErrorCode.BRANCH_NOT_FOUND,\n { options, error: branchError }\n );\n }\n \n // Step 2: Load all the BaseRomFile data using the fileCrcs array\n const files = await loadBaseRomFiles(branchData.id);\n \n fileQueryTime = performance.now() - branchStart - branchQueryTime;\n \n const payload: BaseRomPayload = {\n baseRomBranch: branchData as unknown as BaseRomBranchData,\n files,\n };\n \n // Log performance statistics\n const totalTime = performance.now() - startTime;\n const stats: QueryStats = {\n branchQueryTime,\n fileQueryTime,\n totalTime,\n fileCount: files.length,\n };\n \n console.log('ROM load stats:', stats);\n \n return payload;\n \n } catch (error) {\n if (error instanceof SupabaseFromError) {\n throw error;\n }\n \n throw new SupabaseFromError(\n `Failed to load ROM data: ${error instanceof Error ? error.message : 'Unknown error'}`,\n SupabaseErrorCode.NETWORK_ERROR,\n { options, error }\n );\n }\n}\n\n/**\n * Load BaseRomFile data using CRCs with parallel requests\n * \n * @param baseRomId - The BaseRom ID to filter files\n * @param fileCrcs - Array of CRC values to fetch\n * @returns Promise<BaseRomFileData[]> Array of file data with converted binary content\n * @throws {SupabaseFromError} If files are not found or conversion fails\n */\nasync function loadBaseRomFiles(\n baseRomBranchId: string\n): Promise<BaseRomFileData[]> {\n\n try {\n const client = getSupabaseClient();\n \n // Query all files with matching CRCs in one request\n const { data: filesData, error: filesError } = await client\n .from('BaseRomBranchFile')\n .select<string, BaseRomBranchFileRaw>('*,file:BaseRomFile!inner(*)')\n .eq('branchId', baseRomBranchId);\n \n if (filesError) {\n throw new SupabaseFromError(\n `Failed to load BaseRomFiles: ${filesError.message}`,\n SupabaseErrorCode.FILES_NOT_FOUND,\n { baseRomBranchId, error: filesError }\n );\n }\n \n if (!filesData || filesData.length === 0) {\n throw new SupabaseFromError(\n `No BaseRomFiles found for baseRomBranchId: ${baseRomBranchId}`,\n SupabaseErrorCode.FILES_NOT_FOUND,\n { baseRomBranchId }\n );\n }\n \n // Convert data to Uint8Array for each file (handles both hex and base64 formats)\n const convertedFiles: BaseRomFileData[] = await convertRawData<BaseRomFileData>(filesData.map(f => f.file));\n \n return convertedFiles;\n \n } catch (error) {\n if (error instanceof SupabaseFromError) {\n throw error;\n }\n \n throw new SupabaseFromError(\n `Failed to load and convert BaseRomFiles: ${error instanceof Error ? error.message : 'Unknown error'}`,\n SupabaseErrorCode.NETWORK_ERROR,\n { baseRomBranchId, error }\n );\n }\n}\n\nasync function convertRawData<T extends FileBaseData>(files: FileBaseRaw[]): Promise<T[]> {\n return files.map((file: FileBaseRaw) => {\n try {\n return {\n ...file,\n data: file.data ? decodeDataString(file.data) : undefined,\n } as T;\n } catch (error) {\n throw new SupabaseFromError(\n `Failed to convert data for file ${file.name}: ${error instanceof Error ? error.message : 'Unknown error'}`,\n SupabaseErrorCode.INVALID_DATA,\n { file, error }\n );\n }\n });\n}\n\n/**\n * Load ProjectFile data using CRCs with parallel requests\n * \n * @param projectId - The Project ID to filter files\n * @param fileCrcs - Array of CRC values to fetch\n * @returns Promise<ProjectFileData[]> Array of file data with converted binary content\n * @throws {SupabaseFromError} If files are not found or conversion fails\n */\nasync function loadProjectFiles(\n projectBranchId: string\n): Promise<ProjectFileData[]> {\n try {\n const client = getSupabaseClient();\n \n // Query all files with matching CRCs in one request\n const { data: filesData, error: filesError } = await client\n .from('ProjectBranchFile')\n .select<string, ProjectBranchFileRaw>('*,file:ProjectFile!inner(*)')\n .eq('branchId', projectBranchId);\n \n if (filesError) {\n throw new SupabaseFromError(\n `Failed to load ProjectFiles: ${filesError.message}`,\n SupabaseErrorCode.FILES_NOT_FOUND,\n { projectBranchId, error: filesError }\n );\n }\n \n if (!filesData || filesData.length === 0) {\n throw new SupabaseFromError(\n `No ProjectFiles found for projectBranchId: ${projectBranchId}`,\n SupabaseErrorCode.FILES_NOT_FOUND,\n { projectBranchId }\n );\n }\n \n // Convert data to Uint8Array for each file (handles both hex and base64 formats)\n const convertedFiles: ProjectFileData[] = await convertRawData<ProjectFileData>(filesData.map(f => f.file));\n \n return convertedFiles;\n \n } catch (error) {\n if (error instanceof SupabaseFromError) {\n throw error;\n }\n \n throw new SupabaseFromError(\n `Failed to load and convert ProjectFiles: ${error instanceof Error ? error.message : 'Unknown error'}`,\n SupabaseErrorCode.NETWORK_ERROR,\n { projectBranchId, error }\n );\n }\n}\n\n/**\n * Load Project data from Supabase using project name-based lookup\n * \n * @param projectName - The name of the project to load\n * @param options - Options for branch filtering\n * @returns Promise<ProjectPayload> containing the project branch data and files\n * @throws {SupabaseFromError} If the project branch is not found or other errors occur\n * \n * @example\n * ```typescript\n * // Load default project branch (main/latest)\n * const payload1 = await fromSupabaseByProject('My Game Project');\n * \n * // Load specific branch\n * const payload2 = await fromSupabaseByProject('My Game Project', {\n * branchName: 'development',\n * branchVersion: null // latest version\n * });\n * \n * // Load main branch explicitly\n * const payload3 = await fromSupabaseByProject('My Game Project', {\n * branchName: null, // main branch\n * branchVersion: null // latest version\n * });\n * ```\n */\nexport async function fromSupabaseByProject(projectName?: string, branchId?: string): Promise<DbGameRomModule> {\n const startTime = performance.now();\n let branchQueryTime = 0;\n let fileQueryTime = 0;\n \n //Use default project name if not provided\n if(!projectName && !branchId){\n throw new Error('Project name or branch ID are required');\n }\n\n try {\n const client = getSupabaseClient();\n \n // Step 1: Build query with filters\n const branchStart = performance.now();\n \n let query = client\n .from('ProjectBranch')\n .select(`\n id,\n name,\n version,\n isActive,\n notes,\n projectId,\n baseRomBranchId,\n modules,\n createdAt,\n updatedAt,\n project:Project!inner(\n id,\n name,\n meta,\n gameId,\n baseRomId,\n createdAt,\n updatedAt\n ),\n baseRomBranch:BaseRomBranch!inner(\n id,\n name,\n version,\n isActive,\n notes,\n baseRomId,\n gameRomBranchId,\n createdAt,\n updatedAt,\n baseRom:BaseRom!inner(\n id,\n name,\n gameId,\n gameRomId,\n createdAt,\n updatedAt\n ),\n gameRomBranch:GameRomBranch!inner(\n id,\n name,\n version,\n isActive,\n notes,\n gameRomId,\n platformBranchId,\n config,\n coplib,\n files,\n blocks,\n rewrites,\n transforms,\n overrides,\n labels,\n mnemonics,\n fileTypes,\n groups,\n strings,\n structs,\n createdAt,\n updatedAt,\n gameRom:GameRom!inner(\n id,\n crc,\n gameId,\n regionId,\n createdAt,\n updatedAt,\n game:Game!inner(\n id,\n name,\n createdAt,\n updatedAt\n ),\n region:Region!inner(\n id,\n name,\n meta,\n createdAt,\n updatedAt\n )\n ),\n platformBranch:PlatformBranch!inner(\n id,\n name,\n version,\n isActive,\n notes,\n platformId,\n addressingModes,\n vectors,\n headers,\n types,\n createdAt,\n updatedAt,\n platform:Platform!inner(\n id,\n name,\n meta,\n createdAt,\n updatedAt\n )\n )\n )\n )\n `);\n \n\n // Filter by Project name\n if(projectName) query = query.eq('project.name', projectName);\n\n // Make sure we use the selected or current active branch\n if(branchId) query = query.eq('id', branchId);\n else query = query.eq('isActive', true);\n \n // Execute query - get single result\n const { data: branchData, error: branchError } = await query.single<ProjectBranchData>();\n \n branchQueryTime = performance.now() - branchStart;\n \n if (branchError || !branchData) {\n throw new SupabaseFromError(\n `ProjectBranch not found for criteria: projectName=\"${projectName}\"`,\n SupabaseErrorCode.BRANCH_NOT_FOUND,\n { projectName, error: branchError }\n );\n }\n\n const baseRomBranch = branchData.baseRomBranch;\n \n // Step 2: Load all the ProjectFile data using the fileCrcs array\n const projectFiles = await loadProjectFiles(branchData.id);\n \n const baseRomFiles = await loadBaseRomFiles(baseRomBranch.id);\n\n fileQueryTime = performance.now() - branchStart - branchQueryTime;\n \n const payload: ProjectPayload = {\n projectBranch: branchData as unknown as ProjectBranchData,\n projectFiles,\n baseRomBranch,\n baseRomFiles\n };\n \n // Log performance statistics\n const totalTime = performance.now() - startTime;\n const stats: QueryStats = {\n branchQueryTime,\n fileQueryTime,\n totalTime,\n fileCount: projectFiles.length,\n };\n \n console.log('Project ROM load stats:', stats);\n \n const module : DbGameRomModule = {\n supaProjectFiles: projectFiles,\n supaBaseRomFiles: baseRomFiles,\n mnemonics: baseRomBranch.gameRomBranch.mnemonics,\n overrides: baseRomBranch.gameRomBranch.overrides,\n rewrites: baseRomBranch.gameRomBranch.rewrites,\n blocks: baseRomBranch.gameRomBranch.blocks,\n files: baseRomBranch.gameRomBranch.files,\n config: baseRomBranch.gameRomBranch.config,\n labels: baseRomBranch.gameRomBranch.labels,\n structs: baseRomBranch.gameRomBranch.structs,\n copdef: baseRomBranch.gameRomBranch.coplib,\n strings: baseRomBranch.gameRomBranch.strings,\n transforms: baseRomBranch.gameRomBranch.transforms,\n groups: baseRomBranch.gameRomBranch.groups,\n fileTypes: baseRomBranch.gameRomBranch.fileTypes,\n addrModes: baseRomBranch.gameRomBranch.platformBranch.addressingModes,\n headers: baseRomBranch.gameRomBranch.platformBranch.headers,\n };\n\n return module;\n \n } catch (error) {\n if (error instanceof SupabaseFromError) {\n throw error;\n }\n \n throw new SupabaseFromError(\n `Failed to load Project data: ${error instanceof Error ? error.message : 'Unknown error'}`,\n SupabaseErrorCode.NETWORK_ERROR,\n { projectName, error }\n );\n }\n}\n\nexport async function fromSupabaseByGameRom(gameName?: string, regionName?: string, platformName?: string, branchId?: string): Promise<ProjectPayload> {\n const startTime = performance.now();\n let branchQueryTime = 0;\n let fileQueryTime = 0;\n \n //Use default project name if not provided\n if(!branchId && !gameName && !regionName && !platformName) { \n throw new Error('Game name, region name, and platform name are required');\n }\n\n try {\n const client = getSupabaseClient();\n \n // Step 1: Build query with filters\n const branchStart = performance.now();\n \n let query = client\n .from('GameRomBranch')\n .select(`\n id,\n name,\n version,\n isActive,\n notes,\n gameRomId,\n platformBranchId,\n coplib,\n config,\n files,\n blocks,\n rewrites,\n transforms,\n overrides,\n labels,\n mnemonics,\n fileTypes,\n groups,\n strings,\n structs,\n createdAt,\n updatedAt,\n gameRom:GameRom!inner(\n id,\n crc,\n meta,\n gameId,\n regionId,\n createdAt,\n updatedAt,\n game:Game!inner(\n id,\n name,\n createdAt,\n updatedAt\n ),\n region:Region!inner(\n id,\n name,\n meta,\n createdAt,\n updatedAt\n )\n ),\n platformBranch:PlatformBranch!inner(\n id,\n name,\n version,\n isActive,\n platformId,\n addressingModes,\n headers,\n vectors,\n types,\n createdAt,\n updatedAt,\n platform:Platform!inner(\n id,\n name,\n meta,\n createdAt,\n updatedAt\n )\n )\n `);\n \n\n // Filter by Project name\n if(gameName) query = query.eq('gameRom.game.name', gameName);\n if(regionName) query = query.eq('gameRom.region.name', regionName);\n if(platformName) query = query.eq('platformBranch.platform.name', platformName);\n\n // Make sure we use the selected or current active branch\n if(branchId) query = query.eq('id', branchId);\n else query = query.eq('isActive', true);\n \n // Execute query - get single result\n const { data: branchData, error: branchError } = await query.single<GameRomBranchData>();\n \n branchQueryTime = performance.now() - branchStart;\n \n if (branchError || !branchData) {\n throw new SupabaseFromError(\n `GameRomBranch not found for criteria: gameName=\"${gameName}\", regionName=\"${regionName}\", platformName=\"${platformName}\"`,\n SupabaseErrorCode.BRANCH_NOT_FOUND,\n { gameName, regionName, platformName, error: branchError }\n );\n }\n\n // Construct a minimal BaseRomBranch wrapper so downstream code can consume a unified ProjectPayload\n const baseRomBranch: BaseRomBranchData = {\n id: '',\n name: null,\n version: null,\n baseRomId: '',\n gameRomBranchId: branchData.id,\n gameRomBranch: branchData,\n baseRom: {\n id: '',\n name: '',\n gameId: '',\n gameRomId: '',\n createdAt: '',\n updatedAt: ''\n },\n createdAt: '',\n updatedAt: ''\n };\n\n const project: ProjectData = {\n id: '',\n name: '',\n meta: null,\n gameId: '',\n baseRomId: '',\n createdAt: '',\n updatedAt: '',\n };\n\n const projectBranch: ProjectBranchData = {\n id: '',\n name: null,\n version: null,\n projectId: '',\n baseRomBranchId: '',\n modules: [],\n project,\n baseRomBranch,\n createdAt: '',\n updatedAt: ''\n };\n\n const payload: ProjectPayload = {\n projectBranch,\n projectFiles: [],\n baseRomBranch,\n baseRomFiles: []\n };\n\n fileQueryTime = performance.now() - branchStart - branchQueryTime;\n\n // Log performance statistics\n const totalTime = performance.now() - startTime;\n const stats: QueryStats = {\n branchQueryTime,\n fileQueryTime,\n totalTime,\n fileCount: 0,\n };\n\n console.log('Game ROM load stats:', stats);\n\n return payload;\n \n } catch (error) {\n if (error instanceof SupabaseFromError) {\n throw error;\n }\n \n throw new SupabaseFromError(\n `Failed to load GameRomBranch data: ${error instanceof Error ? error.message : 'Unknown error'}`,\n SupabaseErrorCode.NETWORK_ERROR,\n { gameName, regionName, platformName, error }\n );\n }\n}\n\nexport async function summaryFromSupabaseByProject(projectName?: string): Promise<ProjectBranchData> {\n const startTime = performance.now();\n let branchQueryTime = 0;\n let fileQueryTime = 0;\n \n //Use default project name if not provided\n if(!projectName){\n throw new Error('Project name or branch ID are required');\n }\n\n try {\n const client = getSupabaseClient();\n\n // Step 1: Build query with filters\n const branchStart = performance.now();\n \n let query = client\n .from('ProjectBranch')\n .select(`\n id,\n name,\n version,\n isActive,\n notes,\n projectId,\n baseRomBranchId,\n modules,\n createdAt,\n updatedAt,\n project:Project!inner(\n id,\n name,\n meta,\n gameId,\n baseRomId,\n createdAt,\n updatedAt\n ),\n baseRomBranch:BaseRomBranch!inner(\n id,\n name,\n version,\n isActive,\n notes,\n baseRomId,\n gameRomBranchId,\n createdAt,\n updatedAt,\n baseRom:BaseRom!inner(\n id,\n name,\n gameId,\n gameRomId,\n createdAt,\n updatedAt\n ),\n gameRomBranch:GameRomBranch!inner(\n id,\n name,\n version,\n isActive,\n notes,\n gameRomId,\n platformBranchId,\n createdAt,\n updatedAt,\n gameRom:GameRom!inner(\n id,\n crc,\n gameId,\n regionId,\n createdAt,\n updatedAt,\n game:Game!inner(\n id,\n name,\n createdAt,\n updatedAt\n ),\n region:Region!inner(\n id,\n name,\n meta,\n createdAt,\n updatedAt\n )\n ),\n platformBranch:PlatformBranch!inner(\n id,\n name,\n version,\n isActive,\n notes,\n platformId,\n createdAt,\n updatedAt,\n platform:Platform!inner(\n id,\n name,\n meta,\n createdAt,\n updatedAt\n )\n )\n )\n )\n `);\n \n // Filter by Project name\n query = query.eq('project.name', projectName);\n \n // Make sure we use the current active branch\n query = query.eq('isActive', true);\n \n // Execute query - get single result\n const { data: branchData, error: branchError } = await query.single();\n \n branchQueryTime = performance.now() - branchStart;\n \n if (branchError || !branchData) {\n throw new SupabaseFromError(\n `ProjectBranch not found for criteria: projectName=\"${projectName}\"`,\n SupabaseErrorCode.BRANCH_NOT_FOUND,\n { projectName, error: branchError }\n );\n }\n\n const projectBranch = branchData as unknown as ProjectBranchData;\n \n\n fileQueryTime = performance.now() - branchStart - branchQueryTime;\n \n const payload = projectBranch;\n \n // Log performance statistics\n const totalTime = performance.now() - startTime;\n const stats: QueryStats = {\n branchQueryTime,\n fileQueryTime,\n totalTime,\n fileCount: 0,\n };\n \n console.log('Project ROM load stats:', stats);\n \n return payload;\n \n } catch (error) {\n if (error instanceof SupabaseFromError) {\n throw error;\n }\n \n throw new SupabaseFromError(\n `Failed to load Project data: ${error instanceof Error ? error.message : 'Unknown error'}`,\n SupabaseErrorCode.NETWORK_ERROR,\n { projectName, error }\n );\n }\n}\n","import { crc32_buffer } from '../utils';\r\nimport { DbRoot, DbRootUtils } from '../database';\r\nimport { ChunkFile } from '../types/files';\r\nimport { summaryFromSupabaseByProject } from '../supabase/rom-loader';\r\nimport { BlockReader, BlockWriter } from './extraction';\r\nimport { RomWriter } from './rebuild';\r\nimport { fromSupabaseByProject } from '../supabase/rom-loader';\r\n\r\nexport class RomGenerator {\r\n //private readonly patchFiles: ChunkFile[] = [];\r\n public readonly projectName: string;\r\n public readonly crc: number;\r\n //public branchId: string;\r\n //private chunkFiles: ChunkFile[] = [];\r\n //private asmFiles: ChunkFile[] = [];\r\n public dbRoot: DbRoot = {} as DbRoot;\r\n private sourceData: Uint8Array = new Uint8Array();\r\n\r\n constructor(projectName: string, crc: number) {\r\n this.projectName = projectName;\r\n this.crc = crc;\r\n }\r\n\r\n // public async initialize(){\r\n // var projectData = await summaryFromSupabaseByProject(this.projectName);\r\n // this.crc = projectData.baseRomBranch.gameRomBranch.gameRom.crc;\r\n // this.branchId = projectData.id;\r\n // }\r\n\r\n public async validateAndDownload(sourceData: Uint8Array): Promise<boolean> {\r\n const calc = crc32_buffer(sourceData);\r\n if(this.crc !== calc) return false;\r\n\r\n const moduleData = await fromSupabaseByProject(this.projectName);\r\n this.dbRoot = DbRootUtils.fromGameModule(moduleData);\r\n this.sourceData = sourceData;\r\n return true;\r\n }\r\n\r\n public async generateProject(modules: string[], manualFiles?: ChunkFile[], unshiftManualFiles: boolean = false): Promise<Uint8Array> {\r\n if(!this.dbRoot) throw new Error('Database not initialized');\r\n if(!this.sourceData) throw new Error('Source data not initialized');\r\n\r\n //Initialize chunks\r\n const reader = new BlockReader(this.sourceData, this.dbRoot);\r\n const chunkFiles = reader.analyzeAndResolve();\r\n const asmFiles = chunkFiles.filter(b => b.type.type === 'Assembly');\r\n const patchFiles: ChunkFile[] = [];\r\n\r\n //Convert asm blocks to text\r\n const writer = new BlockWriter(reader);\r\n for(const block of asmFiles) block.textData = writer.generateAsm(block);\r\n \r\n //Apply baserom files\r\n for (const chunkFile of this.dbRoot.baseRomFiles!) this.applyPatchFile(chunkFile, chunkFiles, asmFiles, patchFiles);\r\n\r\n //Apply base project files and collect module files\r\n const moduleLookup = this.applyProjectInit(chunkFiles, asmFiles, patchFiles);\r\n\r\n //Apply manual files (before modules)\r\n if(unshiftManualFiles) {\r\n for(const file of manualFiles ?? []) this.applyPatchFile(file, chunkFiles, asmFiles, patchFiles);\r\n }\r\n\r\n //Apply selected modules\r\n for(const module of modules) {\r\n for(const file of moduleLookup.get(module)!) this.applyPatchFile(file, chunkFiles, asmFiles, patchFiles);\r\n }\r\n\r\n //Apply manual files\r\n if(!unshiftManualFiles) {\r\n for(const file of manualFiles ?? []) this.applyPatchFile(file, chunkFiles, asmFiles, patchFiles);\r\n }\r\n\r\n const romWriter = new RomWriter(this.dbRoot);\r\n const outRom = await romWriter.repack(chunkFiles);\r\n \r\n // this.assembleCodeFromText(asmFiles);\r\n\r\n // //Apply code patches\r\n // RomProcessor.applyPatches(asmFiles, patchFiles);\r\n\r\n // //Calculate sizes\r\n // for (const asm of chunkFiles) ChunkFileUtils.calculateSize(asm);\r\n\r\n // //Assign locations\r\n // const layout = new RomLayout(chunkFiles, this.dbRoot);\r\n // const pages = layout.organize();\r\n\r\n // //Rebase assemblies\r\n // for (const file of asmFiles) ChunkFileUtils.rebase(file);\r\n\r\n // this.generateAsmIncludeLookups(asmFiles);\r\n\r\n // //Generate block lookup\r\n // const blockLookup = new Map<string, number>();\r\n // for (const f of chunkFiles) blockLookup.set(f.name.toUpperCase(), f.location);\r\n\r\n // const outRom = await this.writeRom(blockLookup, chunkFiles, asmFiles, pages);\r\n\r\n\r\n return outRom;\r\n }\r\n\r\n private applyProjectInit(chunkFiles: ChunkFile[], asmFiles: ChunkFile[], patchFiles: ChunkFile[]){\r\n const moduleLookup: Map<string, ChunkFile[]> = new Map();\r\n\r\n //Run a single pass to collect all the module files, and apply base files\r\n for (const chunkFile of this.dbRoot.projectFiles!) {\r\n // Parse the patch file with the assembler\r\n console.log(`Processing patch: ${chunkFile.name}`);\r\n\r\n //ChunkFile.group is the module name\r\n if(chunkFile.group){\r\n let modArray = moduleLookup.get(chunkFile.group);\r\n if(!modArray) moduleLookup.set(chunkFile.group, modArray = []);\r\n modArray.push(chunkFile);\r\n } else this.applyPatchFile(chunkFile, chunkFiles, asmFiles, patchFiles); //If chunk file is not part of a group, apply it now\r\n }\r\n\r\n return moduleLookup;\r\n }\r\n\r\n // //Assemble code from script text\r\n // private assembleCodeFromText(asmFiles: ChunkFile[]){\r\n // for(const block of asmFiles) {\r\n // const assembler = new Assembler(this.dbRoot, block.textData!);\r\n // const { blocks, includes, reqBank } = assembler.parseAssembly();\r\n // block.parts = blocks;\r\n // block.includes = includes;\r\n // block.bank = reqBank ?? undefined;\r\n // }\r\n // }\r\n\r\n // // Build include lookup map per asm file\r\n // private generateAsmIncludeLookups(asmFiles: ChunkFile[]){\r\n // for (const f of asmFiles) {\r\n // const includeBlocks = asmFiles\r\n // .filter(x => f.includes?.has(x.name.toUpperCase()))\r\n // .flatMap(x => x.parts!)\r\n // .filter(b => !!b.label);\r\n\r\n // f.includeLookup = new Map<string, AsmBlock>();\r\n\r\n // for (const b of includeBlocks) {\r\n // if (b.label) f.includeLookup.set(b.label.toUpperCase(), b);\r\n // }\r\n\r\n // for (const b of f.parts) {\r\n // if (b.label) f.includeLookup.set(b.label.toUpperCase(), b);\r\n // }\r\n // }\r\n // }\r\n\r\n public applyPatchFile(chunkFile: ChunkFile, chunkFiles: ChunkFile[], asmFiles: ChunkFile[], patchFiles: ChunkFile[]): void {\r\n console.log(`Processing patch: ${chunkFile.name}`);\r\n const existing = chunkFiles.find(x => x.name === chunkFile.name);\r\n\r\n if(chunkFile.textData) {\r\n if(existing){\r\n existing.textData = chunkFile.textData;\r\n } else {\r\n if(chunkFile.type.type === 'Patch') {\r\n patchFiles.push(chunkFile);\r\n }\r\n asmFiles.push(chunkFile);\r\n chunkFiles.push(chunkFile);\r\n }\r\n } else {\r\n if(existing){\r\n existing.rawData = chunkFile.rawData;\r\n existing.size = chunkFile.size;\r\n } else {\r\n chunkFiles.push(chunkFile);\r\n }\r\n }\r\n }\r\n\r\n // private async writeRom(blockLookup: Map<string, number>, chunkFiles: ChunkFile[], asmFiles: ChunkFile[], pages: number){\r\n // //Create rom writer\r\n // const romWriter = new RomWriter(this.dbRoot);\r\n\r\n // romWriter.allocate(pages);\r\n\r\n // // Write all files\r\n // for (const file of chunkFiles) await romWriter.writeFile(file, blockLookup);\r\n\r\n // //Write header\r\n // romWriter.writeHeaders();\r\n\r\n // //Write entry points\r\n // //romWriter.writeEntryPoints(asmFiles);\r\n\r\n // //Write checksum\r\n // romWriter.writeChecksum();\r\n\r\n // return romWriter.outBuffer;\r\n // }\r\n}","/**\r\n * Represents a single frame in a sprite animation sequence\r\n */\r\nexport class SpriteFrame {\r\n public duration: number;\r\n public groupIndex: number;\r\n \r\n /**\r\n * Internal offset to the group data (not serialized)\r\n */\r\n public groupOffset: number;\r\n\r\n constructor(duration: number = 0, groupIndex: number = 0, groupOffset: number = 0) {\r\n this.duration = duration;\r\n this.groupIndex = groupIndex;\r\n this.groupOffset = groupOffset;\r\n }\r\n} ","/**\r\n * Represents a single part/piece of a sprite\r\n */\r\nexport class SpritePart {\r\n public isLarge: boolean;\r\n public xOffset: number;\r\n public xOffsetMirror: number;\r\n public yOffset: number;\r\n public yOffsetMirror: number;\r\n public vMirror: boolean;\r\n public hMirror: boolean;\r\n public someOffset: number;\r\n public paletteIndex: number;\r\n public tileIndex: number;\r\n\r\n constructor() {\r\n this.isLarge = false;\r\n this.xOffset = 0;\r\n this.xOffsetMirror = 0;\r\n this.yOffset = 0;\r\n this.yOffsetMirror = 0;\r\n this.vMirror = false;\r\n this.hMirror = false;\r\n this.someOffset = 0;\r\n this.paletteIndex = 0;\r\n this.tileIndex = 0;\r\n }\r\n} ","import { SpritePart } from './SpritePart';\r\n\r\n/**\r\n * Represents a group of sprite parts that form a complete sprite frame\r\n */\r\nexport class SpriteGroup {\r\n public xOffset: number;\r\n public xOffsetMirror: number;\r\n public yOffset: number;\r\n public yOffsetMirror: number;\r\n public xRecoilHitboxOffset: number;\r\n public yRecoilHitboxOffset: number;\r\n public xRecoilHitboxTilesize: number;\r\n public yRecoilHitboxTilesize: number;\r\n public xHostileHitboxOffset: number;\r\n public xHostileHitboxSize: number;\r\n public yHostileHitboxOffset: number;\r\n public yHostileHitboxSize: number;\r\n public parts: SpritePart[];\r\n\r\n constructor() {\r\n this.xOffset = 0;\r\n this.xOffsetMirror = 0;\r\n this.yOffset = 0;\r\n this.yOffsetMirror = 0;\r\n this.xRecoilHitboxOffset = 0;\r\n this.yRecoilHitboxOffset = 0;\r\n this.xRecoilHitboxTilesize = 0;\r\n this.yRecoilHitboxTilesize = 0;\r\n this.xHostileHitboxOffset = 0;\r\n this.xHostileHitboxSize = 0;\r\n this.yHostileHitboxOffset = 0;\r\n this.yHostileHitboxSize = 0;\r\n this.parts = [];\r\n }\r\n} ","import { SpriteFrame } from './SpriteFrame';\r\nimport { SpriteGroup } from './SpriteGroup';\r\nimport { SpritePart } from './SpritePart';\r\n\r\n/**\r\n * Represents a complete sprite map with frame sets and groups\r\n */\r\nexport class SpriteMap {\r\n public frameSets: SpriteFrame[][];\r\n public groups: SpriteGroup[];\r\n\r\n constructor() {\r\n this.frameSets = [];\r\n this.groups = [];\r\n }\r\n\r\n /**\r\n * Create a SpriteMap from binary data\r\n * @param data Binary data buffer\r\n * @returns SpriteMap instance\r\n */\r\n public static fromBytes(data: Uint8Array): SpriteMap {\r\n let position = 0;\r\n\r\n const getByte = (): number => {\r\n if (position >= data.length) return 0;\r\n return data[position++];\r\n };\r\n\r\n const getUshort = (): number => {\r\n if (position + 1 >= data.length) return 0;\r\n const low = data[position++];\r\n const high = data[position++];\r\n return low | (high << 8);\r\n };\r\n\r\n const spriteMap = new SpriteMap();\r\n const setOffsets = new Set<number>();\r\n const groupOffsets = new Set<number>();\r\n\r\n // Read frame set offsets\r\n position = 0;\r\n while (!setOffsets.has(position)) {\r\n const offset = getUshort() - 0x4000;\r\n setOffsets.add(offset);\r\n }\r\n\r\n // Read frame sets\r\n for (const offStart of setOffsets) {\r\n position = offStart;\r\n const frameList: SpriteFrame[] = [];\r\n\r\n while (true) {\r\n const duration = getUshort();\r\n if (duration === 0xFFFF) {\r\n break;\r\n }\r\n\r\n const groupOffset = getUshort() - 0x4000;\r\n frameList.push(new SpriteFrame(duration, 0, groupOffset));\r\n groupOffsets.add(groupOffset);\r\n }\r\n\r\n spriteMap.frameSets.push(frameList);\r\n }\r\n\r\n // Read groups\r\n let grpIx = 0;\r\n const sortedGroupOffsets = Array.from(groupOffsets).sort((a, b) => a - b);\r\n \r\n for (const offStart of sortedGroupOffsets) {\r\n position = offStart;\r\n\r\n // Update frame group indices\r\n for (const set of spriteMap.frameSets) {\r\n for (const frame of set) {\r\n if (frame.groupOffset === offStart) {\r\n frame.groupIndex = grpIx;\r\n }\r\n }\r\n }\r\n\r\n const grp = new SpriteGroup();\r\n grp.xOffset = getByte();\r\n grp.xOffsetMirror = getByte();\r\n grp.yOffset = getByte();\r\n grp.yOffsetMirror = getByte();\r\n grp.xRecoilHitboxOffset = getByte();\r\n grp.yRecoilHitboxOffset = getByte();\r\n grp.xRecoilHitboxTilesize = getByte();\r\n grp.yRecoilHitboxTilesize = getByte();\r\n grp.xHostileHitboxOffset = getByte();\r\n grp.xHostileHitboxSize = getByte();\r\n grp.yHostileHitboxOffset = getByte();\r\n grp.yHostileHitboxSize = getByte();\r\n\r\n let numParts = getByte();\r\n while (numParts-- > 0) {\r\n const part = new SpritePart();\r\n part.isLarge = getByte() !== 0;\r\n part.xOffset = getByte();\r\n part.xOffsetMirror = getByte();\r\n part.yOffset = getByte();\r\n part.yOffsetMirror = getByte();\r\n\r\n const props = getUshort();\r\n part.vMirror = (props & 0x8000) !== 0;\r\n part.hMirror = (props & 0x4000) !== 0;\r\n part.someOffset = (props >> 12) & 0x3;\r\n part.paletteIndex = (props >> 9) & 0x7;\r\n part.tileIndex = props & 0x1FF;\r\n\r\n grp.parts.push(part);\r\n }\r\n\r\n spriteMap.groups.push(grp);\r\n grpIx++;\r\n }\r\n\r\n return spriteMap;\r\n }\r\n\r\n /**\r\n * Convert this SpriteMap to binary data\r\n * @returns Binary data buffer\r\n */\r\n public toBytes(): Uint8Array {\r\n // Calculate buffer size (estimate)\r\n let size = this.frameSets.length * 2; // Frame set offsets\r\n \r\n for (const set of this.frameSets) {\r\n size += (set.length * 4) + 2; // Frames + terminator\r\n }\r\n \r\n for (const grp of this.groups) {\r\n size += (grp.parts.length * 7) + 13; // Parts + group header\r\n }\r\n\r\n const buffer = new Uint8Array(size);\r\n let position = 0;\r\n\r\n const writeShort = (val: number): void => {\r\n buffer[position++] = val & 0xFF;\r\n buffer[position++] = (val >> 8) & 0xFF;\r\n };\r\n\r\n const writeLoc = (val: number): void => writeShort(val + 0x4000);\r\n\r\n let pos = this.frameSets.length << 1;\r\n const groupPos = new Array<number>(this.groups.length);\r\n\r\n // Write frame set offsets\r\n for (const set of this.frameSets) {\r\n writeLoc(pos);\r\n pos += (set.length << 2) + 2;\r\n }\r\n\r\n // Calculate group positions\r\n for (let i = 0; i < this.groups.length; i++) {\r\n groupPos[i] = pos;\r\n pos += this.groups[i].parts.length * 7 + 13;\r\n }\r\n\r\n // Write frame sets\r\n for (const set of this.frameSets) {\r\n for (const frm of set) {\r\n writeShort(frm.duration);\r\n writeLoc(groupPos[frm.groupIndex]);\r\n }\r\n writeShort(0xFFFF);\r\n }\r\n\r\n // Write groups\r\n for (const grp of this.groups) {\r\n buffer[position++] = grp.xOffset;\r\n buffer[position++] = grp.xOffsetMirror;\r\n buffer[position++] = grp.yOffset;\r\n buffer[position++] = grp.yOffsetMirror;\r\n buffer[position++] = grp.xRecoilHitboxOffset;\r\n buffer[position++] = grp.yRecoilHitboxOffset;\r\n buffer[position++] = grp.xRecoilHitboxTilesize;\r\n buffer[position++] = grp.yRecoilHitboxTilesize;\r\n buffer[position++] = grp.xHostileHitboxOffset;\r\n buffer[position++] = grp.xHostileHitboxSize;\r\n buffer[position++] = grp.yHostileHitboxOffset;\r\n buffer[position++] = grp.yHostileHitboxSize;\r\n buffer[position++] = grp.parts.length;\r\n\r\n for (const prt of grp.parts) {\r\n buffer[position++] = prt.isLarge ? 1 : 0;\r\n buffer[position++] = prt.xOffset;\r\n buffer[position++] = prt.xOffsetMirror;\r\n buffer[position++] = prt.yOffset;\r\n buffer[position++] = prt.yOffsetMirror;\r\n\r\n const accum = (prt.vMirror ? 0x8000 : 0)\r\n | (prt.hMirror ? 0x4000 : 0)\r\n | ((prt.someOffset & 0x3) << 12)\r\n | ((prt.paletteIndex & 0x7) << 9)\r\n | prt.tileIndex;\r\n\r\n writeShort(accum);\r\n }\r\n }\r\n\r\n // Return trimmed buffer\r\n return buffer.slice(0, position);\r\n }\r\n} ","import snesAddressingModes from '../snes/addressingModes.json' with { type: 'json' };\nimport snesVectors from '../snes/vectors.json' with { type: 'json' };\nimport snesHeaders from '../snes/headers.json' with { type: 'json' };\n\nexport const snes = {\n addressingModes: snesAddressingModes,\n vectors: snesVectors,\n headers: snesHeaders\n}\n\n// Core modules\nexport * from './rom';\nexport * from './assembly';\nexport * from './compression';\nexport * from './sprites';\n\n// Core types\nexport * from './types'\nexport * from './project'\nexport * from './collaboration'\n\n// Database\nexport * from './database'\n\n// Supabase integration\nexport * from './supabase'\n\n// Utilities\nexport * from './utils' \n\n// All core modules have been converted and are exported above\n\n\n// Platform detection\n//export const isPlatformBrowser = typeof window !== 'undefined';\nexport const isPlatformNode = typeof process !== 'undefined' && process.versions?.node;\n//export const isPlatformWebWorker = typeof importScripts !== 'undefined'; \n\n"],"mappings":"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"}
|