From d7278a7ee0bfb34eea7b7e8c99d7cf496bbe2890 Mon Sep 17 00:00:00 2001 From: gmestanley Date: Wed, 17 Sep 2025 23:49:45 -0300 Subject: [PATCH 01/17] Add credit to ne.hexpat --- patterns/ne.hexpat | 1 + 1 file changed, 1 insertion(+) diff --git a/patterns/ne.hexpat b/patterns/ne.hexpat index 3cae5c2f..6c825b11 100644 --- a/patterns/ne.hexpat +++ b/patterns/ne.hexpat @@ -1,3 +1,4 @@ +#pragma author gmestanley #pragma description Microsoft DOS NE executable #pragma MIME application/x-ms-ne-executable From b37a4ac924bd9db8b1fe426a5c152c5f3cdc64bb Mon Sep 17 00:00:00 2001 From: gmestanley Date: Thu, 18 Sep 2025 00:06:47 -0300 Subject: [PATCH 02/17] Add many changes to nes.hexpat --- patterns/nes.hexpat | 306 ++++++++++++++++++++++++++++++++++---------- 1 file changed, 241 insertions(+), 65 deletions(-) diff --git a/patterns/nes.hexpat b/patterns/nes.hexpat index 1fdce899..2d049448 100644 --- a/patterns/nes.hexpat +++ b/patterns/nes.hexpat @@ -2,87 +2,263 @@ #pragma description Nintendo Entertainment System ROM (.nes) #pragma MIME application/x-nes-rom -import std.mem; import std.string; -bitfield iNES07Flags { - mirroringIsVertical : 1; - batterybackedPRGRAM : 1; - trainerOf512Bytes : 1; - ignoreMirroring : 1; - mapperLowerNybble : 4; - vsUnisystem : 1; - playchoice10 : 1; - nes2Format : 2 [[name("nes2.0Format")]]; - mapperHigherNybble : 4; -} [[name("iNES0.7Flags")]]; - -bitfield Flags9 { - isPAL : 1; - padding : 7; -}; - -bitfield Flags10 { - tvSystem : 2; - padding : 2; - prgRAM : 1; - busConflicts : 1; - padding : 2; -}; - -struct iNESFlags { - iNES07Flags ines07Flags [[name("ines0.7Flags")]]; - if (!ines07Flags.nes2Format) { - u8 prgRAM8KBMultiplier; - Flags9 flags9; - Flags10 flags10; - restLength = 5; - } - else { - restLength = 9; - } -}; - -u8 restLength; +bitfield Flags { + mirroringIsHorizontal : 1; + ignoreMirroring : 1; + batterybackedPRGRAM : 1; + trainerOf512Bytes : 1; + lowerMapperNybble : 4; +}; + +enum ConsoleType : u8 { + Regular, + VsSystem, + PlayChoice10, + ExtendedConsoleType +}; + +fn consoleType(u8 bits) { + ConsoleType type = bits; + return type; +}; + +fn nes2Format(u8 bits) { + return std::string::to_string(bits == 2) + " (" + std::string::to_string(bits) + ")"; +}; + +bitfield iNESFlags7 { + consoleType : 2 [[format("consoleType")]]; + nes2Format : 2 [[format("nes2Format"), name("nes2.0Format")]]; + higherMapperNybble : 4; +}; + +bitfield iNESFlags9 { + tvSystem : 1 [[comment("0 = NTSC, 1 = PAL")]]; + padding : 7; +}; + +fn formatDualTVSystem(u8 bits) { + match (bits) { + (0): return "NTSC"; + (2): return "PAL"; + (1 || 3): return "Dual Compatible"; + } +}; + +bitfield iNESFlags10 { + dualTVSystem : 2 [[format("formatDualTVSystem")]]; + padding : 2; + prgRAM : 1; + busConflicts : 1; +}; + +bitfield MapperExtra { + highestMapperNybble : 4; + submapper : 4; +}; + +bitfield ROMSize { + extraPRGROMSize : 4; + extraCHRROMSize : 4; +}; + +bitfield PRGRAMSize { + prgRAMShiftCount : 4; + eepromShiftCount : 4 [[comment("EEPROM = Non-volatile PRG RAM")]]; +}; + +bitfield CHRRAMSize { + chrRAMSizeShiftCount : 4; + chrNVRAMSizeShiftCount : 4; +}; + +enum TimingList : u8 { + NTSC, + PAL, + MultiRegion, + Dendy +}; + +fn Timing(u8 value) { + TimingList type = value; + return type; +}; + +bitfield Timing { + processorTiming : 2 [[format("Timing")]]; + padding : 6; +}; + +bitfield VsSystemType { + vsPPUType : 4; + vsHardwareType: 4; +}; + +enum ExtendedConsoleType : ConsoleType { + DecimalModeFamiclone = 3, + PlugThrough, + VT01, + VT02, + VT03, + VT09, + VT32, + VT3xx, + UM6578, + FamicomNetworkSystem +}; + +fn formatExtendedConsoleType(u8 nybble) { + ExtendedConsoleType type = nybble; + return type; +}; + +bitfield ExtendedConsoleTypeByte { + type : 4 [[format("formatExtendedConsoleType")]]; + padding : 4; +}; + +bitfield MiscellaneousROMs { + numberOfMiscellaneousROMs : 2; + padding : 6; +}; + +bitfield DefaultExpansionDevice { + defaultExpansionDevice : 6; +}; + +struct NES2Attributes { + MapperExtra mapperExtra; + ROMSize romSize; + PRGRAMSize prgRAMSize; + CHRRAMSize chrRAMSize; + Timing timing; + if (parent.inesFlags7.consoleType == ConsoleType::VsSystem) { + VsSystemType vsSystemType; + } + else if (parent.inesFlags7.consoleType == ConsoleType::ExtendedConsoleType) { + ExtendedConsoleTypeByte ExtendedConsoleTypeByte; + } + else { + padding[1]; + } + MiscellaneousROMs miscellaneousROMs; + DefaultExpansionDevice defaultExpansionDevice; +}; + +fn renderEOF(str string) { + return "\"NES\""; +}; struct Header { - char identifier[4]; - u8 prgROM16KBMultiplier; - u8 chrROM8KBMultiplier; - iNESFlags inesFlags; - char rest[restLength]; + char identifier[4] [[format("renderEOF")]]; + u8 prgROMSizeBy16KiBs; + u8 chrROMSizeBy8KiBs; + Flags flags; + if ($[0x07] & 12 != 4) { + iNESFlags7 inesFlags7; + if (inesFlags7.nes2Format) + NES2Attributes nes2Attributes; + else if ($[0x07] & 12 == 0 && !std::mem::read_unsigned($, 4)) { + u8 prgRAMSizeBy8KiBs; + iNESFlags9 inesFlags9; + iNESFlags10 inesFlags10; + } + } }; Header header @ 0x00; +u8 trainer[512*header.flags.trainerOf512Bytes] @ 0x10; + +enum CHRType : u8 { + CHRROM, + CHRRAM +}; + +fn chrType(u8 value) { + CHRType enumValue = value; + return enumValue; +}; + +fn chrSize(u8 value) { + u24 actualSize; + if (value == 4) actualSize = 262144; + else actualSize = 8192 * header.chrROMSizeBy8KiBs; + return std::string::to_string(value) + " (" + std::string::to_string(actualSize) + ")"; +}; + +bitfield MemorySize { + prgROMSizeBy16KiBs : 4; + chrType : 1 [[format("chrType")]]; + chrSize : 3 [[format("chrSize")]]; +}; + +enum ArrangementList : u8 { + Horizontal, + Vertical +}; + +fn arrangement(u8 value) { + ArrangementList enumValue = value; + return enumValue; +}; + +enum MapperList : u8 { + NROM, + CNROM, + UNROM, + GNROM, + MMC +}; + +fn mapper(u8 value) { + MapperList enumValue = value; + return enumValue; +}; + +bitfield CartridgeType { + nametableArrangement : 1 [[format("arrangement")]]; + mapper : 7 [[format("mapper")]]; +}; + enum EncodingType : u8 { - ASCII = 1 + None, + ASCII, + JIS }; +fn titleLength(u8 value) { return value+1; }; + struct OfficialHeader { - char title[16] [[hex::spec_name("Title Registration Area")]]; - u16 programChecksum; - u16 characterChecksum; - u8 memorySize [[hex::spec_name("Cartridge Memory Size")]]; - u8 cartridgeType; - EncodingType encodingType [[hex::spec_name("Registration Character Type Distinction")]]; - u8 titleLength [[hex::spec_name("Registration Characters Count")]]; - u8 makerID [[hex::spec_name("Maker Code")]]; - u8 complementaryChecksum; + char title[16] [[hex::spec_name("Title Registration Area")]]; + u16 programChecksum; + u16 characterChecksum; + MemorySize memorySize [[hex::spec_name("Cartridge Memory Size")]]; + CartridgeType cartridgeType; + EncodingType encodingType [[hex::spec_name("Registration Characters Type Distinction")]]; + u8 titleLength [[hex::spec_name("Registration Characters Count"), transform("titleLength")]]; + u8 licenseeID [[hex::spec_name("Maker Code")]]; + u8 complementaryChecksum [[hex::spec_name("Checksum for characterChecksum~makerID")]]; }; -union OfficialHeaderUnion { - u8 miscellaneousData[26]; - OfficialHeader officialHeader; +fn hasOfficialHeader() { + u8 sum; + for (u8 i = 0, i < 8, i += 1) { + sum += $[(16384 * ((0x0100*header.nes2Attributes.romSize.extraPRGROMSize)*($[7] & 12==8))+header.prgROMSizeBy16KiBs - 14)+i]; + } + return !sum; }; struct PRGROM { - u8 data[16384*header.prgROM16KBMultiplier-32]; - OfficialHeaderUnion officialHeaderUnion; - u16 nmi; - u16 entryPoint; - u16 externalIRQ; + u8 data[16384 * (((0x0100*header.nes2Attributes.romSize.extraPRGROMSize)*($[7] & 12==8)) + header.prgROMSizeBy16KiBs) - 26 * hasOfficialHeader() - 6]; + if (hasOfficialHeader()) + OfficialHeader officialHeader; + u16 nmi; + u16 resetVector [[comment("Entry Point")]]; + u16 externalIRQ; }; -PRGROM prgROM @ sizeof(header); -u8 chrROM[8192*header.chrROM8KBMultiplier] @ sizeof(header)+sizeof(prgROM); \ No newline at end of file +PRGROM prgROM @ 0x10 + sizeof(trainer); +u8 chrROM[8192 * (((0x0100*header.nes2Attributes.romSize.extraCHRROMSize)*($[7] & 12==8)) + header.chrROMSizeBy8KiBs)] @ addressof(prgROM) + 16384 * header.prgROMSizeBy16KiBs; From 4756598636985112b23786dde542821d02139f62 Mon Sep 17 00:00:00 2001 From: gmestanley Date: Mon, 22 Sep 2025 01:59:54 -0300 Subject: [PATCH 03/17] Fixing dependance on variables declared in if statement --- patterns/nes.hexpat | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/patterns/nes.hexpat b/patterns/nes.hexpat index 2d049448..6292ada0 100644 --- a/patterns/nes.hexpat +++ b/patterns/nes.hexpat @@ -243,16 +243,18 @@ struct OfficialHeader { u8 complementaryChecksum [[hex::spec_name("Checksum for characterChecksum~makerID")]]; }; +u24 calculatedPRGROMSize = 16384 * ((0x0100 * $[9] & 0x0F) * ($[7] & 12 == 8) + header.prgROMSizeBy16KiBs); + fn hasOfficialHeader() { u8 sum; for (u8 i = 0, i < 8, i += 1) { - sum += $[(16384 * ((0x0100*header.nes2Attributes.romSize.extraPRGROMSize)*($[7] & 12==8))+header.prgROMSizeBy16KiBs - 14)+i]; + sum += $[(calculatedPRGROMSize - 14) + i]; } return !sum; }; struct PRGROM { - u8 data[16384 * (((0x0100*header.nes2Attributes.romSize.extraPRGROMSize)*($[7] & 12==8)) + header.prgROMSizeBy16KiBs) - 26 * hasOfficialHeader() - 6]; + u8 data[calculatedPRGROMSize - 26 * hasOfficialHeader() - 6]; if (hasOfficialHeader()) OfficialHeader officialHeader; u16 nmi; @@ -261,4 +263,4 @@ struct PRGROM { }; PRGROM prgROM @ 0x10 + sizeof(trainer); -u8 chrROM[8192 * (((0x0100*header.nes2Attributes.romSize.extraCHRROMSize)*($[7] & 12==8)) + header.chrROMSizeBy8KiBs)] @ addressof(prgROM) + 16384 * header.prgROMSizeBy16KiBs; +u8 chrROM[8192 * ((0x0100 * $[9] >> 4) * ($[7] & 12 == 8) + header.chrROMSizeBy8KiBs)] @ addressof(prgROM) + 16384 * header.prgROMSizeBy16KiBs; From 3bac92d64eead63e667ffa0400880cfe3c3e2c34 Mon Sep 17 00:00:00 2001 From: gmestanley Date: Thu, 9 Oct 2025 22:33:31 -0300 Subject: [PATCH 04/17] Added mappers and inline to NES 2.0 header, removed needless parenthesises --- patterns/nes.hexpat | 147 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 144 insertions(+), 3 deletions(-) diff --git a/patterns/nes.hexpat b/patterns/nes.hexpat index 6292ada0..797d8ec2 100644 --- a/patterns/nes.hexpat +++ b/patterns/nes.hexpat @@ -145,7 +145,7 @@ struct NES2Attributes { } MiscellaneousROMs miscellaneousROMs; DefaultExpansionDevice defaultExpansionDevice; -}; +} [[inline]]; fn renderEOF(str string) { return "\"NES\""; @@ -243,7 +243,7 @@ struct OfficialHeader { u8 complementaryChecksum [[hex::spec_name("Checksum for characterChecksum~makerID")]]; }; -u24 calculatedPRGROMSize = 16384 * ((0x0100 * $[9] & 0x0F) * ($[7] & 12 == 8) + header.prgROMSizeBy16KiBs); +u24 calculatedPRGROMSize = 16384 * ((0x0100 * ($[9] & 0x0F)) * ($[7] & 12 == 8) + header.prgROMSizeBy16KiBs); fn hasOfficialHeader() { u8 sum; @@ -263,4 +263,145 @@ struct PRGROM { }; PRGROM prgROM @ 0x10 + sizeof(trainer); -u8 chrROM[8192 * ((0x0100 * $[9] >> 4) * ($[7] & 12 == 8) + header.chrROMSizeBy8KiBs)] @ addressof(prgROM) + 16384 * header.prgROMSizeBy16KiBs; +u8 chrROM[8192 * ((0x0100 * ($[9] >> 4)) * ($[7] & 12 == 8) + header.chrROMSizeBy8KiBs)] @ addressof(prgROM) + 16384 * header.prgROMSizeBy16KiBs; + +fn identifyMapper(u16 mapperValue, u8 submapperValue) { + str mapper; + str submapper; + str designation; + match (mapperValue) { + (0): mapper = "NROM"; + (1): mapper = "MMC1B"; + (2): mapper = "UxROM"; + (3): mapper = "CNROM-32"; + (4): mapper = "MMC3"; + (5): mapper = "MMC5"; + (6): mapper = "Front Fareast Magic Card 1/2M RAM Cartridge"; + (7): mapper = "AxROM"; + (8): mapper = "Front Fareast Magic Card 1/2M RAM Cartridge (Initial latch-based banking mode 4)"; + (9): mapper = "MMC2"; + (10): mapper = "MMC4"; + (11): mapper = "Color Dreams"; + (12): mapper = "(See submapper)"; + (13): mapper = "CPROM"; + (14): mapper = "SL-1632"; + (15): mapper = "K-102xx"; + (16): mapper = "Bandai FCG boards"; + (17): mapper = "Front Fareast Super Magic Card RAM cartridge"; + (18): mapper = "SS88006 (Jaleco)"; + (19): mapper = "Namco 129/163"; + (20): mapper = "Famicom Disk System"; + (21): mapper = "VRC4a/VRC4c"; + (22): mapper = "VRC2a"; + (23): mapper = "VRC4e or VRC2b + VRC4f"; + (24): mapper = "VRC6a"; + (25): mapper = "VRC4d or VRC2c + VRC4b"; + (26): mapper = "VRC6b"; + (27): mapper = "World Hero"; + (28): mapper = "Action 53"; + (29): mapper = "RET-CUFROM"; + (30): mapper = "UNROM 512"; + (31): mapper = "NSF"; + (32): mapper = "G-101"; + (33): mapper = "TC0190"; + (34): mapper = "(See submapper)"; + (35): mapper = "J.Y. Company (8KiB WRAM)"; + (36): mapper = "01-22000-400"; + (37): mapper = "SMB+Tetris+NWC"; + (38): mapper = "Crime Busters"; + (39): mapper = "Study & Game 32-in-1"; + (40): mapper = "NTDEC 27xx"; + (41): mapper = "Caltron 6-in-1"; + (42): mapper = "FDS -> NES Hacks"; + (43): mapper = "TONY-I/YS-612"; + (44): mapper = "Super Big 7-in-1"; + (45): mapper = "GA23C"; + (46): mapper = "Rumble Station"; + (47): mapper = "Super Spike V'Ball + NWC"; + (48): mapper = "TC0690"; + (49): mapper = "Super HIK 4-in-1"; + (50): mapper = "761214"; + (51): mapper = "11-in-1 Ball Games"; + (52): mapper = "Realtec 8213"; + (53): mapper = "Supervision 16-in-1"; + (54): mapper = "Novel Diamond 9999999-in-1"; + (55): mapper = "QFJ"; + (56): mapper = "KS202"; + (57): mapper = "GK"; + (58): mapper = "WQ"; + (59): mapper = "T3H53"; + (60): mapper = "Reset-based NROM-128 4-in-1"; + (61): mapper = "(See submapper)"; + (62): mapper = "Super 700-in-1"; + (63): mapper = "(See submapper)"; + (64): mapper = "RAMBO-1"; + (65): mapper = "H3001"; + (66): mapper = "GxROM"; + (67): mapper = "Sunsoft-3"; + (68): mapper = "Sunsoft-4"; + (69): mapper = "Sunsoft FME-7/Sunsoft 5A/Sunsoft 5B"; + (70): mapper = "Family Trainer Mat"; + (71): mapper = "Camerica"; + (72): mapper = "JF-17"; + (73): mapper = "VRC3"; + (74): mapper = "860908C"; + (75): mapper = "VRC1"; + (76): mapper = "NAMCOT-3446"; + (77): mapper = "Napoleon Senki"; + (78): mapper = "74HC161/32"; + (79): mapper = "NINA-003/NINA-006"; + (80): mapper = "X1-005"; + (81): mapper = "N715021"; + (82): mapper = "X1-017"; + } + if (mapperValue == 3) { + match (submapperValue) { + (0): submapper = "Bus conflict"; + (1): submapper = "No bus conflicts"; + (2): submapper = "AND-type bus conflicts"; + } + } + else if (mapperValue == 4) designation = "TxROM"; + else if (mapperValue == 12) { + match (submapperValue) { + (0): submapper = "SL-5020B (Gouder)"; + (1): submapper = "Front Fareast Magic Card 4M RAM Cartridge"; + } + } + else if (mapperValue == 16) { + match (submapperValue) { + (0): submapper = "FCG-1/2 or LZ93D50"; + (4): submapper = "FCG-1/2"; + (5): submapper = "LZ93D50"; + } + } + else if (mapperValue == 34) { + match (submapperValue) { + (0): submapper = "NINA-001/NINA-002"; + (1): submapper = "BNROM"; + } + } + else if (mapperValue == 40) { + match (submapperValue) { + (0): submapper = "NTDEC 2722"; + (1): submapper = "NTDEC 2752"; + } + } + else if (mapperValue == 61) { + match (submapperValue) { + (0): submapper = "NTDEC 0324"; + (1): submapper = "NTDEC BS-N032"; + (_): submapper = "GS-2017"; + } + } + else if (mapperValue == 63) { + match (submapperValue) { + (0): submapper = "TH2291-3"; + (1): submapper = "82AB"; + } + } + std::print("Mapper: " + mapper + "(" + std::string::to_string(mapperValue) + ")"); + if (submapper) std::print("Submapper: " + submapper + "(" + std::string::to_string(submapperValue) + ")"); + if (designation) std::print("Designation: " + designation); +}; +identifyMapper(0x0100 * ($[8] & 0x0F) + 0x10 * ($[7] & 0x0F) + header.flags.lowerMapperNybble, $[8] >> 4); From 2d9aaa896bf527ccf799918e1b0f873cf13bc12e Mon Sep 17 00:00:00 2001 From: gmestanley Date: Thu, 9 Oct 2025 22:51:13 -0300 Subject: [PATCH 05/17] Add files via upload --- patterns/snes.hexpat | 110 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 110 insertions(+) create mode 100644 patterns/snes.hexpat diff --git a/patterns/snes.hexpat b/patterns/snes.hexpat new file mode 100644 index 00000000..63a14592 --- /dev/null +++ b/patterns/snes.hexpat @@ -0,0 +1,110 @@ +#pragma author gmestanley +#pragma description SNES ROM header +#pragma sources snes.nesdev.org/wiki/ROM_header CPU_vectors en.wikibooks.org/wiki/Super_NES_Programming/SNES_memory_map + +import std.string; + +u24 headerPosition = 0x7FC0; + +fn calculateHeaderPosition() { + if (std::mem::size() > 0x20000 && std::mem::size() < 0x600000) headerPosition += 0x8000; + else if (std::mem::size() >= 0x600000) headerPosition += 0x400000; +}; +calculateHeaderPosition(); + +enum ChipsetSubtype : u8 { + SPC7110, + ST01x, + ST018, + CX4 +}; + +struct ExpandedHeader { + char makerID[2]; + char gameID[4]; + padding[6]; + u8 expansionFlashSize [[comment("1 << N")]]; + u8 expansionRAMSize [[comment("1 << N")]]; + u8 specialVersion; + ChipsetSubtype chipsetSubtype; +}; + +struct ConditionalStruct { + if ($[headerPosition+0x1A] == 0x33) ExpandedHeader expandedHeader @ headerPosition - 0x10; + else if (!$[headerPosition+0x14]) ChipsetSubtype chipsetSubtype @ headerPosition - 1; +} [[inline]]; + +ConditionalStruct conditionalStruct @ $; + +enum MappingMode : u8 { + LoROM, + HiROM, + ExHiROM = 5 +}; + +fn formatMappingMode(u8 value) { + MappingMode enumValue = value; + return enumValue; +}; + +bitfield ROMType { + mappingMode : 4 [[format("formatMappingMode")]]; + speed : 1; + unknown : 1; +}; + +enum CoprocessorType : u8 { + DSP, + GSU, + OBC1, + SA1, + SDD1, + SRTC, + Other = 0x0E, + Custom +}; + +fn formatExtraHardwareType(u8 value) { + str valueMeaning = " (ROM"; + if (!value) valueMeaning += " only"; + else if (value) { + if (value > 3) valueMeaning += " + coprocessor"; + if (value != 3 || value != 6) valueMeaning += " + RAM"; + if (value == 2 || value > 5) valueMeaning += " + battery"; + } + return std::string::to_string(value) + valueMeaning + ")"; +}; + +fn formatCoprocessorType(u8 value) { + CoprocessorType enumValue = value; + return enumValue; +}; + +bitfield ExtraHardware { + extraHardwareType : 4 [[format("formatExtraHardwareType")]]; + coprocessorType : 4 [[format("formatCoprocessorType")]]; +}; + +enum Country : u8 { + NTSC = 1, + PAL +}; + +struct Header { + char title[21]; + ROMType romType; + ExtraHardware extraHardware; + u8 romSize [[comment("1 << N, rounded up")]]; + u8 ramSize [[comment("1 << N")]]; + Country country; + u8 developerID; + u8 romVersion; + u16 checksumComplement; + u16 checksum; + padding[4]; + u16 vectors[6]; + padding[4]; + u16 emulationModeVectors[6]; +}; + +Header header @ headerPosition; \ No newline at end of file From 020e4fa9bd2ab9966e82fee95d9c7356132aff24 Mon Sep 17 00:00:00 2001 From: gmestanley Date: Thu, 9 Oct 2025 22:54:20 -0300 Subject: [PATCH 06/17] Add files via upload --- patterns/nsfe.hexpat | 7 +++++++ patterns/nsfmetadata.hexpat | 42 +++++++++++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+) create mode 100644 patterns/nsfe.hexpat create mode 100644 patterns/nsfmetadata.hexpat diff --git a/patterns/nsfe.hexpat b/patterns/nsfe.hexpat new file mode 100644 index 00000000..047f57c0 --- /dev/null +++ b/patterns/nsfe.hexpat @@ -0,0 +1,7 @@ +#pragma author gmestanley +#pragma description NSFe file format + +#include <./nsfmetadata.hexpat> + +char signature[4] @ 0x00; +Chunk chunks[while($ Date: Thu, 9 Oct 2025 22:57:08 -0300 Subject: [PATCH 07/17] Create nsf.hexpat --- patterns/nsf.hexpat | 68 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) create mode 100644 patterns/nsf.hexpat diff --git a/patterns/nsf.hexpat b/patterns/nsf.hexpat new file mode 100644 index 00000000..1c80c32c --- /dev/null +++ b/patterns/nsf.hexpat @@ -0,0 +1,68 @@ +#pragma author gmestanley +#pragma description NES Sound Format file + +#include <./nsfmetadata.hexpat> + +bitfield NSF2Flags { + padding : 4; + irq : 1; + nonReturningInitNotUsed : 1; + playSubroutineNotUsed : 1; + playbackNSFeChunk : 1; +}; + +bitfield Region { + isPAL : 1; + palNTSCDual : 1; +}; + +enum ExtraSoundChipSupport : u8 { + None, + VRC6, + VRC7, + FDS = 4, + MMC5 = 8, + Namco163 = 16, + Sunsoft5B = 32, + VTxx = 64 +}; + +fn formatName(str string) { + for (u8 nameIndex = 0, nameIndex < 32, nameIndex += 1) { + if (!$[$+nameIndex] || nameIndex == 31) + return "\"" + std::string::substr(string, 0, nameIndex) + "\""; + } +}; + +fn renderEOF(str value) { + return "\"NESM\""; +}; + +struct Header { + char signature[5] [[format("renderEOF")]]; + u8 version; + u8 songAmount; + u8 startingSong; + u16 dataLoadAddress; + u16 dataInitAddress; + u16 dataPlayAddress; + char gameName[32] [[format("formatName")]]; + char songwriting[32] [[format("formatName")]]; + char copyrightHolder[32] [[format("formatName")]]; + u16 ntscPlaySpeed; + u8 bankswitchInitValues[8]; + u16 palPlaySpeed; + Region region; + ExtraSoundChipSupport extraSoundChipSupport; + NSF2Flags nsf2flags; + u24 dataLength; +}; + +Header header @ 0x00; + +struct Chunks { + if (header.dataLength) + Chunk chunks[while($ Date: Thu, 9 Oct 2025 22:57:51 -0300 Subject: [PATCH 08/17] Used full name of the SNES on description --- patterns/snes.hexpat | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/patterns/snes.hexpat b/patterns/snes.hexpat index 63a14592..4a6b690f 100644 --- a/patterns/snes.hexpat +++ b/patterns/snes.hexpat @@ -1,5 +1,5 @@ #pragma author gmestanley -#pragma description SNES ROM header +#pragma description Super Nintendo Entertainment System ROM header #pragma sources snes.nesdev.org/wiki/ROM_header CPU_vectors en.wikibooks.org/wiki/Super_NES_Programming/SNES_memory_map import std.string; @@ -107,4 +107,4 @@ struct Header { u16 emulationModeVectors[6]; }; -Header header @ headerPosition; \ No newline at end of file +Header header @ headerPosition; From 0ff848281359f0844f4b808c0db2d70490223205 Mon Sep 17 00:00:00 2001 From: gmestanley Date: Fri, 10 Oct 2025 00:31:19 -0300 Subject: [PATCH 09/17] Add SNES, NSF & NSFe, new description for NES --- README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 3d2f2d70..e0474ac0 100644 --- a/README.md +++ b/README.md @@ -122,7 +122,9 @@ Everything will immediately show up in ImHex's Content Store and gets bundled wi | NBT | | [`patterns/nbt.hexpat`](patterns/nbt.hexpat) | Minecraft NBT format | | NDS | `application/x-nintendo-ds-rom` | [`patterns/nds.hexpat`](patterns/nds.hexpat) | DS Cartridge Header | | NE | `application/x-ms-ne-executable` | [`patterns/ne.hexpat`](patterns/ne.hexpat) | NE header and Standard NE fields | -| nes | | [`patterns/nes.hexpat`](patterns/nes.hexpat) | .nes file format | +| nes | | [`patterns/nes.hexpat`](patterns/nes.hexpat) | Nintendo Entertainment System ROM | +| NSF | | [`patterns/nsf.hexpat`](patterns/nsf.hexpat) | NES Sound Format | +| NSFe | | [`patterns/nsfe.hexpat`](patterns/nsfe.hexpat) | NES Sound Format extended | | NotepadCache | | [`patterns/notepad-cache.hexpat`](patterns/notepad-cache.hexpat) | Windows Notepad Cache | | NotepadWindowState | | [`patterns/notepadwindowstate.hexpat`](patterns/notepadwindowstate.hexpat) | Windows 11 Notepad - Window State .bin file | | NRO | | [`patterns/nro.hexpat`](patterns/nro.hexpat) | Nintendo Switch NRO files | @@ -167,6 +169,7 @@ Everything will immediately show up in ImHex's Content Store and gets bundled wi | SHR | | [`patterns/SHR.hexpat`](patterns/SHR.hexpat) | Apple IIgs Super Hi-Res (SHR) + PaintWorks Animation (ANI) | | shx | | [`patterns/shx.hexpat`](patterns/shx.hexpat) | ESRI index file | | smk | | [`patterns/smk.hexpat`](patterns/smk.hexpat) | Smacker video file | +| SNES | | [`patterns/snes.hexpat`](patterns/snes.hexpat) | Super Nintendo Entertainment System ROM header | | sup | | [`patterns/sup.hexpat`](patterns/sup.hexpat) | PGS Subtitle | | SPIRV | | [`patterns/spirv.hexpat`](patterns/spirv.hexpat) | SPIR-V header and instructions | | STDF | | [`patterns/stdfv4.hexpat`](patterns/stdfv4.hexpat) | Standard test data format for IC testers | From 0524fbff9d9f22d5c26236bbb91fce815bef6c20 Mon Sep 17 00:00:00 2001 From: gmestanley Date: Fri, 10 Oct 2025 00:32:46 -0300 Subject: [PATCH 10/17] Removing erroneous condition in ips.hexpat's truncatedSize --- patterns/ips.hexpat | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/patterns/ips.hexpat b/patterns/ips.hexpat index bccee99d..de01d044 100644 --- a/patterns/ips.hexpat +++ b/patterns/ips.hexpat @@ -23,7 +23,7 @@ struct IPS { char signature[5]; Hunk hunks[while($ < std::mem::size() - (3 + 3 * (std::mem::read_string(std::mem::size()-3, 3) != "EOF")))]; char eof[3]; - u24 truncatedSize[3+(std::mem::read_string(std::mem::size()-3, 3) != "EOF")>3]; + u24 truncatedSize[3+(std::mem::read_string(std::mem::size()-3, 3) != "EOF")]; }; IPS ips @ 0x00; From a1a058044d2a9ae32dcbde38db307ac2ac6d7304 Mon Sep 17 00:00:00 2001 From: gmestanley Date: Fri, 10 Oct 2025 00:35:43 -0300 Subject: [PATCH 11/17] Removing unnecessary std.string import in ips.hexpat --- patterns/ips.hexpat | 1 - 1 file changed, 1 deletion(-) diff --git a/patterns/ips.hexpat b/patterns/ips.hexpat index de01d044..dfea729d 100644 --- a/patterns/ips.hexpat +++ b/patterns/ips.hexpat @@ -5,7 +5,6 @@ #pragma endian big import std.mem; -import std.string; struct Hunk { u24 offset; From 89bfdebbe4776c229523007b05deaf0d3564c78d Mon Sep 17 00:00:00 2001 From: gmestanley Date: Mon, 3 Nov 2025 15:44:23 -0300 Subject: [PATCH 12/17] Added both locations for sections in PE, clearer variable names, reorganized DOS stub --- patterns/pe.hexpat | 1857 ++++++++++++++++++++++---------------------- 1 file changed, 931 insertions(+), 926 deletions(-) diff --git a/patterns/pe.hexpat b/patterns/pe.hexpat index b57a9181..4958bbfb 100644 --- a/patterns/pe.hexpat +++ b/patterns/pe.hexpat @@ -5,311 +5,315 @@ #pragma MIME application/x-msdownload #pragma MIME application/vnd.microsoft.portable-executable +import hex.dec; import std.core; import std.string; import type.guid; import type.time; -struct DOSHeader { - char signature[2] [[hex::spec_name("e_magic")]]; - u16 extraPageSize [[hex::spec_name("e_cblp")]]; - u16 numberOfPages [[hex::spec_name("e_cp")]]; - u16 relocations [[name("stubRelocations"), hex::spec_name("e_crlc")]]; - u16 headerSizeInParagraphs [[hex::spec_name("e_cparhdr")]]; - u16 minimumAllocatedParagraphs [[hex::spec_name("e_minalloc")]]; - u16 maximumAllocatedParagraphs [[hex::spec_name("e_maxalloc")]]; - u16 initialSSValue [[hex::spec_name("e_ss")]]; - u16 initialRelativeSPValue [[hex::spec_name("e_sp")]]; - u16 checksum [[name("stubChecksum"), hex::spec_name("e_csum")]]; - u16 initialRelativeIPValue [[hex::spec_name("e_ip")]]; - u16 initialCSValue [[hex::spec_name("e_cs")]]; - u16 relocationsTablePointer [[hex::spec_name("e_lfarlc")]]; - u16 overlayNumber [[hex::spec_name("e_ovno")]]; - u16 reservedWords[4] [[hex::spec_name("e_res")]]; - u16 oemIdentifier [[hex::spec_name("e_oemid")]]; - u16 oemInformation [[hex::spec_name("e_oeminfo")]]; - u16 otherReservedWords[10] [[hex::spec_name("e_res2")]]; - u32 coffHeaderPointer [[hex::spec_name("e_lfanew")]]; -}; - -u16 dosMessageOffset; - -fn isstubdata(char c) { - return c == 0x0D || c == 0x0A || c == '$'; -}; - -struct DOSStub { - u8 code[while($ < addressof(this) + dosMessageOffset)]; - char message[while(!isstubdata(std::mem::read_unsigned($, 1)))]; - char data[while(std::mem::read_string($-1, 1) != "$")]; +fn formatNullTerminatedString(str string) { + return "\"" + std::string::substr(string, 0, std::string::length(string)-1) + "\""; +}; + +s16 dosMessageOffset; + +struct DOSProgramData { + u8 code[while($ < addressof(this) + dosMessageOffset)]; + // $ is the character that ends text on DOS + char message[while(std::mem::read_string($-1, 1) != "$")] @ addressof(this) + dosMessageOffset [[format("formatNullTerminatedString")]]; } [[hex::spec_name("e_program")]]; fn finddosmessage() { - for (u8 i = $, i < $+16, i += 1) { - if (std::mem::read_unsigned(i, 1) == 0xBA) { // Message offset instruction - dosMessageOffset = std::mem::read_unsigned(i+1, 2); - break; - } - } + for (u8 cursor = $, cursor < $+16, cursor += 1) { + if ($[cursor] == 0xBA) { // Message offset instruction + dosMessageOffset = std::mem::read_unsigned(cursor+1, 2); + break; + } + } +}; + +struct DOSHeader { + char signature[2] [[hex::spec_name("e_magic")]]; + u16 extraPageSize [[hex::spec_name("e_cblp")]]; + u16 numberOfPages [[hex::spec_name("e_cp")]]; + u16 relocations [[name("stubRelocations"), hex::spec_name("e_crlc")]]; + u16 headerSizeInParagraphs [[hex::spec_name("e_cparhdr")]]; + u16 minimumAllocatedParagraphs [[hex::spec_name("e_minalloc")]]; + u16 maximumAllocatedParagraphs [[hex::spec_name("e_maxalloc")]]; + u16 initialSSValue [[hex::spec_name("e_ss")]]; + u16 initialRelativeSPValue [[hex::spec_name("e_sp")]]; + u16 checksum [[name("stubChecksum"), hex::spec_name("e_csum")]]; + u16 initialRelativeIPValue [[hex::spec_name("e_ip")]]; + u16 initialCSValue [[hex::spec_name("e_cs")]]; + u16 relocationsTablePointer [[hex::spec_name("e_lfarlc")]]; + u16 overlayNumber [[hex::spec_name("e_ovno")]]; + u16 reservedWords[4] [[hex::spec_name("e_res")]]; + u16 oemIdentifier [[hex::spec_name("e_oemid")]]; + u16 oemInformation [[hex::spec_name("e_oeminfo")]]; + u16 otherReservedWords[10] [[hex::spec_name("e_res2")]]; + u32 coffHeaderPointer [[hex::spec_name("e_lfanew")]]; }; struct PEHeader { - DOSHeader dosHeader; - finddosmessage(); - if (!dosMessageOffset) - u8 dosStub[while(std::mem::read_unsigned($, 4))] [[hex::spec_name("e_program")]]; - else DOSStub dosStub; + DOSHeader dosHeader; + finddosmessage(); + if (!dosMessageOffset) + /* Some newer executables have garbage data instead. Four 00 + characters is when 00 (null) stops being part of it instead + of being the threshold, so it can be used as a limit */ + u8 dosProgramData[while(std::mem::read_unsigned($, 5))] [[hex::spec_name("e_program")]]; + else DOSProgramData dosProgramData; }; PEHeader peHeader @ 0x00; enum ArchitectureType : u16 { - Unknown = 0x00, - ALPHAAXPOld = 0x183, - ALPHAAXP = 0x184, - ALPHAAXP64Bit = 0x284, - AM33 = 0x1D3, - AMD64 = 0x8664, - ARM = 0x1C0, - ARM64 = 0xAA64, - ARMNT = 0x1C4, - CLRPureMSIL = 0xC0EE, - EBC = 0xEBC, - I386 = 0x14C, - I860 = 0x14D, - IA64 = 0x200, - LOONGARCH32 = 0x6232, - LOONGARCH64 = 0x6264, - M32R = 0x9041, - MIPS16 = 0x266, - MIPSFPU = 0x366, - MIPSFPU16 = 0x466, - MOTOROLA68000 = 0x268, - POWERPC = 0x1F0, - POWERPCFP = 0x1F1, - POWERPC64 = 0x1F2, - R3000 = 0x162, - R4000 = 0x166, - R10000 = 0x168, - RISCV32 = 0x5032, - RISCV64 = 0x5064, - RISCV128 = 0x5128, - SH3 = 0x1A2, - SH3DSP = 0x1A3, - SH4 = 0x1A6, - SH5 = 0x1A8, - THUMB = 0x1C2, - WCEMIPSV2 = 0x169 + Unknown = 0x00, + ALPHAAXPOld = 0x183, + ALPHAAXP = 0x184, + ALPHAAXP64Bit = 0x284, + AM33 = 0x1D3, + AMD64 = 0x8664, + ARM = 0x1C0, + ARM64 = 0xAA64, + ARMNT = 0x1C4, + CLRPureMSIL = 0xC0EE, + EBC = 0xEBC, + I386 = 0x14C, + I860 = 0x14D, + IA64 = 0x200, + LOONGARCH32 = 0x6232, + LOONGARCH64 = 0x6264, + M32R = 0x9041, + MIPS16 = 0x266, + MIPSFPU = 0x366, + MIPSFPU16 = 0x466, + MOTOROLA68000 = 0x268, + POWERPC = 0x1F0, + POWERPCFP = 0x1F1, + POWERPC64 = 0x1F2, + R3000 = 0x162, + R4000 = 0x166, + R10000 = 0x168, + RISCV32 = 0x5032, + RISCV64 = 0x5064, + RISCV128 = 0x5128, + SH3 = 0x1A2, + SH3DSP = 0x1A3, + SH4 = 0x1A6, + SH5 = 0x1A8, + THUMB = 0x1C2, + WCEMIPSV2 = 0x169 } [[hex::spec_name("MachineType")]]; enum PEFormat : u16 { - ROM = 0x107, - PE32 = 0x10B, - PE32Plus = 0x20B + ROM = 0x107, + PE32 = 0x10B, + PE32Plus = 0x20B }; enum SubsystemType : u16 { - Unknown = 0x00, - Native = 0x01, - WindowsGUI = 0x02, - WindowsCUI = 0x03, - OS2CUI = 0x05, - POSIXCUI = 0x07, - Windows9xNative = 0x08, - WindowsCEGUI = 0x09, - EFIApplication = 0x0A, - EFIBootServiceDriver = 0x0B, - EFIRuntimeDriver = 0x0C, - EFIROM = 0x0D, - Xbox = 0x0E, - WindowsBootApplication = 0x10 + Unknown = 0x00, + Native = 0x01, + WindowsGUI = 0x02, + WindowsCUI = 0x03, + OS2CUI = 0x05, + POSIXCUI = 0x07, + Windows9xNative = 0x08, + WindowsCEGUI = 0x09, + EFIApplication = 0x0A, + EFIBootServiceDriver = 0x0B, + EFIRuntimeDriver = 0x0C, + EFIROM = 0x0D, + Xbox = 0x0E, + WindowsBootApplication = 0x10 }; bitfield Characteristics { - baseRelocationsStripped : 1 [[hex::spec_name("IMAGE_FILE_RELOCS_STRIPPED")]]; - executableImage : 1 [[hex::spec_name("IMAGE_FILE_EXECUTABLE_IMAGE")]]; - lineNumbersStripped : 1 [[hex::spec_name("IMAGE_FILE_LINE_NUMS_STRIPPED")]]; - symbolsStripped : 1 [[hex::spec_name("IMAGE_FILE_LOCAL_SYMS_STRIPPED")]]; - aggressivelyTrimWorkingSet : 1 [[hex::spec_name("IMAGE_FILE_AGGRESSIVE_WS_TRIM")]]; - largeAddressAware : 1 [[hex::spec_name("IMAGE_FILE_LARGE_ADDRESS_AWARE")]]; - padding : 1; - bytesReversedLo : 1 [[hex::spec_name("IMAGE_FILE_BYTES_REVERSED_LO")]]; - machine32Bit : 1 [[hex::spec_name("IMAGE_FILE_32BIT_MACHINE")]]; - debugInfoStripped : 1 [[hex::spec_name("IMAGE_FILE_DEBUG_STRIPPED")]]; - removableRunFromSwap : 1 [[hex::spec_name("IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP")]]; - netRunFromSwap : 1 [[hex::spec_name("IMAGE_FILE_NET_RUN_FROM_SWAP")]]; - systemFile : 1 [[hex::spec_name("IMAGE_FILE_SYSTEM")]]; - dll : 1 [[hex::spec_name("IMAGE_FILE_DLL")]]; - uniprocessorMachineOnly : 1 [[hex::spec_name("IMAGE_FILE_UP_SYSTEM_ONLY")]]; - bytesReversedHi : 1 [[hex::spec_name("IMAGE_FILE_BYTES_REVERSED_HI")]]; + baseRelocationsStripped : 1 [[hex::spec_name("IMAGE_FILE_RELOCS_STRIPPED")]]; + executableImage : 1 [[hex::spec_name("IMAGE_FILE_EXECUTABLE_IMAGE")]]; + lineNumbersStripped : 1 [[hex::spec_name("IMAGE_FILE_LINE_NUMS_STRIPPED")]]; + symbolsStripped : 1 [[hex::spec_name("IMAGE_FILE_LOCAL_SYMS_STRIPPED")]]; + aggressivelyTrimWorkingSet : 1 [[hex::spec_name("IMAGE_FILE_AGGRESSIVE_WS_TRIM")]]; + largeAddressAware : 1 [[hex::spec_name("IMAGE_FILE_LARGE_ADDRESS_AWARE")]]; + padding : 1; + bytesReversedLo : 1 [[hex::spec_name("IMAGE_FILE_BYTES_REVERSED_LO")]]; + machine32Bit : 1 [[hex::spec_name("IMAGE_FILE_32BIT_MACHINE")]]; + debugInfoStripped : 1 [[hex::spec_name("IMAGE_FILE_DEBUG_STRIPPED")]]; + removableRunFromSwap : 1 [[hex::spec_name("IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP")]]; + netRunFromSwap : 1 [[hex::spec_name("IMAGE_FILE_NET_RUN_FROM_SWAP")]]; + systemFile : 1 [[hex::spec_name("IMAGE_FILE_SYSTEM")]]; + dll : 1 [[hex::spec_name("IMAGE_FILE_DLL")]]; + uniprocessorMachineOnly : 1 [[hex::spec_name("IMAGE_FILE_UP_SYSTEM_ONLY")]]; + bytesReversedHi : 1 [[hex::spec_name("IMAGE_FILE_BYTES_REVERSED_HI")]]; }; bitfield DLLCharacteristics { - callWhenLoaded : 1; - callWhenThreadTerminates : 1; - callWhenThreadStarts : 1; - callWhenExiting : 1; - padding : 1; - highEntropyVA : 1 [[hex::spec_name("IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA")]]; - dynamicBase : 1 [[hex::spec_name("IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE")]]; - forceIntegrity : 1 [[hex::spec_name("IMAGE_DLLCHARACTERISTICS_FORCE_INTEGRITY")]]; - nxCompatible : 1 [[hex::spec_name("IMAGE_DLLCHARACTERISTICS_NX_COMPAT")]]; - noIsolation : 1 [[hex::spec_name("IMAGE_DLLCHARACTERISTICS_NO_ISOLATION")]]; - noSEH : 1 [[hex::spec_name("IMAGE_DLLCHARACTERISTICS_NO_SEH")]]; - doNotBind : 1 [[hex::spec_name("IMAGE_DLLCHARACTERISTICS_NO_BIND")]]; - appContainer : 1 [[hex::spec_name("IMAGE_DLLCHARACTERISTICS_APPCONTAINER")]]; - isWDMDriver : 1 [[hex::spec_name("IMAGE_DLLCHARACTERISTICS_WDM_DRIVER")]]; - supportsControlFlowGuard : 1 [[hex::spec_name("IMAGE_DLLCHARACTERISTICS_GUARD_CF")]]; - terminalServerAware : 1 [[hex::spec_name("IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE ")]]; + callWhenLoaded : 1; + callWhenThreadTerminates : 1; + callWhenThreadStarts : 1; + callWhenExiting : 1; + padding : 1; + highEntropyVA : 1 [[hex::spec_name("IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA")]]; + dynamicBase : 1 [[hex::spec_name("IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE")]]; + forceIntegrity : 1 [[hex::spec_name("IMAGE_DLLCHARACTERISTICS_FORCE_INTEGRITY")]]; + nxCompatible : 1 [[hex::spec_name("IMAGE_DLLCHARACTERISTICS_NX_COMPAT")]]; + noIsolation : 1 [[hex::spec_name("IMAGE_DLLCHARACTERISTICS_NO_ISOLATION")]]; + noSEH : 1 [[hex::spec_name("IMAGE_DLLCHARACTERISTICS_NO_SEH")]]; + doNotBind : 1 [[hex::spec_name("IMAGE_DLLCHARACTERISTICS_NO_BIND")]]; + appContainer : 1 [[hex::spec_name("IMAGE_DLLCHARACTERISTICS_APPCONTAINER")]]; + isWDMDriver : 1 [[hex::spec_name("IMAGE_DLLCHARACTERISTICS_WDM_DRIVER")]]; + supportsControlFlowGuard : 1 [[hex::spec_name("IMAGE_DLLCHARACTERISTICS_GUARD_CF")]]; + terminalServerAware : 1 [[hex::spec_name("IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE ")]]; }; bitfield LoaderFlags { - prestartBreakpoint : 1 [[comment("Invoke a breakpoint instruction before starting the process")]]; - postloadingDebugger : 1 [[comment("Invoke a debugger on the process after it's been loaded")]]; - padding : 30; + prestartBreakpoint : 1 [[comment("Invoke a breakpoint instruction before starting the process")]]; + postloadingDebugger : 1 [[comment("Invoke a debugger on the process after it's been loaded")]]; + padding : 30; } [[comment("(Officially declared reserved by Microsoft)")]]; struct DataDirectory { - u32 rva; - u32 size; + u32 rva; + u32 size; }; struct OptionalHeader { - PEFormat magic; - u8 majorLinkerVersion; - u8 minorLinkerVersion; - u32 sizeOfCode; - u32 sizeOfInitializedData; - u32 sizeOfUninitializedData; - u32 addressOfEntryPoint; - u32 baseOfCode; - if (magic == PEFormat::PE32Plus) { - u64 imageBase; - } - else { - u32 baseOfData; - u32 imageBase; - } - u32 virtualSectionAlignment [[hex::spec_name("sectionAlignment")]]; - u32 rawSectionAlignment [[hex::spec_name("fileAlignment")]]; - u16 majorOperatingSystemVersion; - u16 minorOperatingSystemVersion; - u16 majorImageVersion; - u16 minorImageVersion; - u16 majorSubsystemVersion; - u16 minorSubsystemVersion; - u32 win32VersionValue; - u32 sizeOfImage; - u32 sizeOfHeaders; - u32 checksum; - SubsystemType subsystem; - DLLCharacteristics dllCharacteristics; - if (magic == PEFormat::PE32Plus) { - u64 sizeOfStackReserve; - u64 sizeOfStackCommit; - u64 sizeOfHeapReserve; - u64 sizeOfHeapCommit; - } - else { - u32 sizeOfStackReserve; - u32 sizeOfStackCommit; - u32 sizeOfHeapReserve; - u32 sizeOfHeapCommit; - } - LoaderFlags loaderFlags; - u32 numberOfRVAsAndSizes [[hex::spec_name("numberOfRvaAndSizes")]]; - DataDirectory directories[numberOfRVAsAndSizes]; + PEFormat magic; + u8 majorLinkerVersion; + u8 minorLinkerVersion; + u32 sizeOfCode; + u32 sizeOfInitializedData; + u32 sizeOfUninitializedData; + u32 addressOfEntryPoint; + u32 baseOfCode; + if (magic == PEFormat::PE32Plus) { + u64 imageBase; + } + else { + u32 baseOfData; + u32 imageBase; + } + u32 virtualSectionAlignment [[hex::spec_name("sectionAlignment")]]; + u32 rawSectionAlignment [[hex::spec_name("fileAlignment")]]; + u16 majorOperatingSystemVersion; + u16 minorOperatingSystemVersion; + u16 majorImageVersion; + u16 minorImageVersion; + u16 majorSubsystemVersion; + u16 minorSubsystemVersion; + u32 win32VersionValue; + u32 sizeOfImage; + u32 sizeOfHeaders; + u32 checksum; + SubsystemType subsystem; + DLLCharacteristics dllCharacteristics; + if (magic == PEFormat::PE32Plus) { + u64 sizeOfStackReserve; + u64 sizeOfStackCommit; + u64 sizeOfHeapReserve; + u64 sizeOfHeapCommit; + } + else { + u32 sizeOfStackReserve; + u32 sizeOfStackCommit; + u32 sizeOfHeapReserve; + u32 sizeOfHeapCommit; + } + LoaderFlags loaderFlags; + u32 numberOfRVAsAndSizes [[hex::spec_name("numberOfRvaAndSizes")]]; + DataDirectory directories[numberOfRVAsAndSizes]; }; struct COFFHeader { - char signature[4]; - ArchitectureType architecture [[hex::spec_name("machine")]]; - u16 numberOfSections; - type::time32_t timeDateStamp; - u32 pointerToSymbolTable; - u32 numberOfSymbols; - u16 sizeOfOptionalHeader; - Characteristics characteristics; + char signature[4]; + ArchitectureType architecture [[hex::spec_name("machine")]]; + u16 numberOfSections; + type::time32_t timeDateStamp; + u32 pointerToSymbolTable; + u32 numberOfSymbols; + u16 sizeOfOptionalHeader; + Characteristics characteristics; - OptionalHeader optionalHeader; + OptionalHeader optionalHeader; }; COFFHeader coffHeader @ peHeader.dosHeader.coffHeaderPointer; enum AlignmentType : u8 { - BoundaryOf1Byte = 1, - BoundaryOf2Bytes, - BoundaryOf4Bytes, - BoundaryOf8Bytes, - BoundaryOf16Bytes, - BoundaryOf32Bytes, - BoundaryOf64Bytes, - BoundaryOf128Bytes, - BoundaryOf256Bytes, - BoundaryOf512Bytes, - BoundaryOf1024Bytes, - BoundaryOf2048Bytes, - BoundaryOf4096Bytes, - BoundaryOf8192Bytes, + BoundaryOf1Byte = 1, + BoundaryOf2Bytes, + BoundaryOf4Bytes, + BoundaryOf8Bytes, + BoundaryOf16Bytes, + BoundaryOf32Bytes, + BoundaryOf64Bytes, + BoundaryOf128Bytes, + BoundaryOf256Bytes, + BoundaryOf512Bytes, + BoundaryOf1024Bytes, + BoundaryOf2048Bytes, + BoundaryOf4096Bytes, + BoundaryOf8192Bytes, }; fn formatAlignmentBits(u8 value) { - if (value > 0) { - AlignmentType enumValue = value; - return enumValue; - } - return value; + if (value) { + AlignmentType enumValue = value; + return enumValue; + } + return value; }; bitfield SectionFlags { - padding : 3; - doNotPad : 1 [[hex::spec_name("IMAGE_SCN_TYPE_NO_PAD")]]; - padding : 1; - containsCode : 1 [[hex::spec_name("IMAGE_SCN_CNT_CODE")]]; - containsInitializedData : 1 [[hex::spec_name("IMAGE_SCN_CNT_INITIALIZED_DATA")]]; - containsUninitializedData : 1 [[hex::spec_name("IMAGE_SCN_CNT_UNINITIALIZED_DATA")]]; - linkOther : 1 [[hex::spec_name("IMAGE_SCN_LNK_OTHER")]]; - linkHasInformation : 1 [[hex::spec_name("IMAGE_SCN_LNK_INFO")]]; - padding : 1; - linkRemove : 1 [[hex::spec_name("IMAGE_SCN_LNK_REMOVE")]]; - linkHasCOMDAT : 1 [[hex::spec_name("IMAGE_SCN_LNK_COMDAT")]]; - padding : 1; - resetSpeculativeExceptions : 1 [[hex::spec_name("")]]; - globalPointerRelocations : 1 [[hex::spec_name("IMAGE_SCN_GPREL")]]; - purgeable : 1 [[hex::spec_name("IMAGE_SCN_MEM_PURGEABLE")]]; - is16Bit : 1 [[hex::spec_name("IMAGE_SCN_MEM_16BIT")]]; - locked : 1 [[hex::spec_name("IMAGE_SCN_MEM_LOCKED")]]; - preloaded : 1 [[hex::spec_name("IMAGE_SCN_MEM_PRELOAD")]]; - dataAlignment : 4 [[format("formatAlignmentBits")]]; - linkExtendedRelocations : 1 [[hex::spec_name("IMAGE_SCN_LNK_NRELOC_OVFL")]]; - discardable : 1 [[hex::spec_name("IMAGE_SCN_MEM_DISCARDABLE")]]; - notCached : 1 [[hex::spec_name("IMAGE_SCN_MEM_NOT_CACHED")]]; - notPageable : 1 [[hex::spec_name("IMAGE_SCN_MEM_NOT_PAGED")]]; - shared : 1 [[hex::spec_name("IMAGE_SCN_MEM_SHARED")]]; - executed : 1 [[hex::spec_name("IMAGE_SCN_MEM_EXECUTE")]]; - read : 1 [[hex::spec_name("IMAGE_SCN_MEM_READ")]]; - writtenOn : 1 [[hex::spec_name("IMAGE_SCN_MEM_WRITE")]]; + padding : 3; + doNotPad : 1 [[hex::spec_name("IMAGE_SCN_TYPE_NO_PAD")]]; + padding : 1; + containsCode : 1 [[hex::spec_name("IMAGE_SCN_CNT_CODE")]]; + containsInitializedData : 1 [[hex::spec_name("IMAGE_SCN_CNT_INITIALIZED_DATA")]]; + containsUninitializedData : 1 [[hex::spec_name("IMAGE_SCN_CNT_UNINITIALIZED_DATA")]]; + linkOther : 1 [[hex::spec_name("IMAGE_SCN_LNK_OTHER")]]; + linkHasInformation : 1 [[hex::spec_name("IMAGE_SCN_LNK_INFO")]]; + padding : 1; + linkRemove : 1 [[hex::spec_name("IMAGE_SCN_LNK_REMOVE")]]; + linkHasCOMDAT : 1 [[hex::spec_name("IMAGE_SCN_LNK_COMDAT")]]; + padding : 1; + resetSpeculativeExceptions : 1 [[hex::spec_name("")]]; + globalPointerRelocations : 1 [[hex::spec_name("IMAGE_SCN_GPREL")]]; + purgeable : 1 [[hex::spec_name("IMAGE_SCN_MEM_PURGEABLE")]]; + is16Bit : 1 [[hex::spec_name("IMAGE_SCN_MEM_16BIT")]]; + locked : 1 [[hex::spec_name("IMAGE_SCN_MEM_LOCKED")]]; + preloaded : 1 [[hex::spec_name("IMAGE_SCN_MEM_PRELOAD")]]; + dataAlignment : 4 [[format("formatAlignmentBits")]]; + linkExtendedRelocations : 1 [[hex::spec_name("IMAGE_SCN_LNK_NRELOC_OVFL")]]; + discardable : 1 [[hex::spec_name("IMAGE_SCN_MEM_DISCARDABLE")]]; + notCached : 1 [[hex::spec_name("IMAGE_SCN_MEM_NOT_CACHED")]]; + notPageable : 1 [[hex::spec_name("IMAGE_SCN_MEM_NOT_PAGED")]]; + shared : 1 [[hex::spec_name("IMAGE_SCN_MEM_SHARED")]]; + executed : 1 [[hex::spec_name("IMAGE_SCN_MEM_EXECUTE")]]; + read : 1 [[hex::spec_name("IMAGE_SCN_MEM_READ")]]; + writtenOn : 1 [[hex::spec_name("IMAGE_SCN_MEM_WRITE")]]; }; fn formatSectionName(str string) { - for (u8 i = 0, i < 8, i += 1) { - if (std::mem::read_unsigned($+i, 1) == 0) { - return "\"" + std::string::substr(string, 0, i) + "\""; - } - } + for (u8 i = 0, i < 8, i += 1) { + if (std::mem::read_unsigned($+i, 1) == 0) { + return "\"" + std::string::substr(string, 0, i) + "\""; + } + } }; struct SectionHeader { - char name[8] [[name("sectionName"), hex::spec_name("name"), format("formatSectionName")]]; - u32 virtualSize; - u32 rva [[hex::spec_name("virtualAddress")]]; - u32 sizeOfRawData; - u32 ptrRawData; - u32 ptrRelocations; - u32 ptrLineNumbers; - u16 numberOfRelocations; - u16 numberOfLineNumbers; - SectionFlags characteristics; + char name[8] [[name("sectionName"), hex::spec_name("name"), format("formatSectionName")]]; + u32 virtualSize; + u32 rva [[hex::spec_name("virtualAddress")]]; + u32 sizeOfRawData; + u32 ptrRawData; + u32 ptrRelocations; + u32 ptrLineNumbers; + u16 numberOfRelocations; + u16 numberOfLineNumbers; + SectionFlags characteristics; }; SectionHeader sectionsTable[coffHeader.numberOfSections] @ addressof(coffHeader.optionalHeader) + coffHeader.sizeOfOptionalHeader; @@ -318,886 +322,887 @@ SectionHeader sectionsTable[coffHeader.numberOfSections] @ addressof(coffHeader. u16 currentSectionIndex; fn relativeVirtualDifference() { - return sectionsTable[currentSectionIndex].rva - sectionsTable[currentSectionIndex].ptrRawData; + return sectionsTable[currentSectionIndex].rva - sectionsTable[currentSectionIndex].ptrRawData; }; fn wordsize() { - return std::mem::read_unsigned(addressof(coffHeader.optionalHeader.magic), 2) / 0x41; -}; - -fn formatNullTerminatedString(str string) { - return "\"" + std::string::substr(string, 0, std::string::length(string)-1) + "\""; + return std::mem::read_unsigned(addressof(coffHeader.optionalHeader.magic), 2) / 0x41; }; // Exception Table bitfield FunctionBitfield { - prologLength : 8; - functionLength : 22; - instructions32Bit : 1; - exceptionHandler : 1; + prologLength : 8; + functionLength : 22; + instructions32Bit : 1; + exceptionHandler : 1; }; struct FunctionTableEntry { - if (coffHeader.architecture == ArchitectureType::MIPSFPU || coffHeader.architecture == ArchitectureType::R3000) { - u32 beginVA; - u32 endVA; - u32 exceptionHandlerPointer; - u32 handlerDataPointer; - u32 prologEndVA; - } else if (coffHeader.architecture == ArchitectureType::ARM || coffHeader.architecture == ArchitectureType::ARM64 || coffHeader.architecture == ArchitectureType::ARMNT || - coffHeader.architecture == ArchitectureType::POWERPC || coffHeader.architecture == ArchitectureType::POWERPCFP || - coffHeader.architecture == ArchitectureType::SH3 || coffHeader.architecture == ArchitectureType::SH3DSP || coffHeader.architecture == ArchitectureType::SH4) { - u32 beginVA; - FunctionBitfield miscellaneousBits; - } else if (coffHeader.architecture == ArchitectureType::AMD64 || coffHeader.architecture == ArchitectureType::IA64) { - u32 beginRVA; - u32 endRVA; - u32 unwindInformationRVA; - } + if (coffHeader.architecture == ArchitectureType::MIPSFPU || coffHeader.architecture == ArchitectureType::R3000) { + u32 beginVA; + u32 endVA; + u32 exceptionHandlerPointer; + u32 handlerDataPointer; + u32 prologEndVA; + } else if (coffHeader.architecture == ArchitectureType::ARM || coffHeader.architecture == ArchitectureType::ARM64 || coffHeader.architecture == ArchitectureType::ARMNT || + coffHeader.architecture == ArchitectureType::POWERPC || coffHeader.architecture == ArchitectureType::POWERPCFP || + coffHeader.architecture == ArchitectureType::SH3 || coffHeader.architecture == ArchitectureType::SH3DSP || coffHeader.architecture == ArchitectureType::SH4) { + u32 beginVA; + FunctionBitfield miscellaneousBits; + } else if (coffHeader.architecture == ArchitectureType::AMD64 || coffHeader.architecture == ArchitectureType::IA64) { + u32 beginRVA; + u32 endRVA; + u32 unwindInformationRVA; + } }; struct ExceptionTable { - FunctionTableEntry functionTableEntries[while($ < (coffHeader.optionalHeader.directories[3].rva - relativeVirtualDifference()) + coffHeader.optionalHeader.directories[3].size)] [[inline]]; + FunctionTableEntry functionTableEntries[while($ < (coffHeader.optionalHeader.directories[3].rva - relativeVirtualDifference()) + coffHeader.optionalHeader.directories[3].size)] [[inline]]; }; // Exports Table struct ExportDirectoryTable { - u32 flags [[name("exportFlags")]]; - type::time32_t timeDateStamp [[name("exportTimeDateStamp")]]; - u16 majorVersion; - u16 minorVersion; - u32 imageNameRVA; - u32 ordinalBase [[name("exportOrdinalBase")]]; - u32 addressesAmount [[name("exportAddressesAmount")]]; - u32 namePointersAmount [[name("exportNamePointersAmount")]]; - u32 addressTableRVA [[name("exportAddressTableRVA")]]; - u32 namePointerTableRVA [[name("exportNamePointerTableRVA")]]; - u32 ordinalTableRVA [[name("exportOrdinalTableRVA")]]; + u32 flags [[name("exportFlags")]]; + type::time32_t timeDateStamp [[name("exportTimeDateStamp")]]; + u16 majorVersion; + u16 minorVersion; + u32 imageNameRVA; + u32 ordinalBase [[name("exportOrdinalBase")]]; + u32 addressesAmount [[name("exportAddressesAmount")]]; + u32 namePointersAmount [[name("exportNamePointersAmount")]]; + u32 addressTableRVA [[name("exportAddressTableRVA")]]; + u32 namePointerTableRVA [[name("exportNamePointerTableRVA")]]; + u32 ordinalTableRVA [[name("exportOrdinalTableRVA")]]; }; struct ExportAddress { - if (sectionsTable[currentSectionIndex].ptrRawData > std::mem::read_unsigned($, 4) > sectionsTable[currentSectionIndex].sizeOfRawData) { - u32 exportRVA; - } - else { - u32 forwarderRVA; - } + if (sectionsTable[currentSectionIndex].ptrRawData > std::mem::read_unsigned($, 4) > sectionsTable[currentSectionIndex].sizeOfRawData) { + u32 exportRVA; + } + else { + u32 forwarderRVA; + } }; struct ExportNamePointer { - u32 exportNameRVA; - char exportName[] @ exportNameRVA - relativeVirtualDifference() [[format("formatNullTerminatedString")]]; + u32 exportNameRVA; + char exportName[] @ exportNameRVA - relativeVirtualDifference() [[format("formatNullTerminatedString")]]; }; struct ExportsTable { - ExportDirectoryTable directoryTable; - ExportAddress exportAddressTable[directoryTable.addressesAmount] @ directoryTable.addressTableRVA - relativeVirtualDifference(); - ExportNamePointer exportNamePointerTable[directoryTable.namePointersAmount] @ directoryTable.namePointerTableRVA - relativeVirtualDifference(); - if (directoryTable.ordinalTableRVA > relativeVirtualDifference()) { - u16 exportOrdinalTable[directoryTable.namePointersAmount] @ directoryTable.ordinalTableRVA - relativeVirtualDifference(); - } - if (directoryTable.imageNameRVA > relativeVirtualDifference()) { - char imageName[] @ directoryTable.imageNameRVA - relativeVirtualDifference() [[format("formatNullTerminatedString")]]; - } - $ = addressof(this)+coffHeader.optionalHeader.directories[0].size; + ExportDirectoryTable directoryTable; + ExportAddress exportAddressTable[directoryTable.addressesAmount] @ directoryTable.addressTableRVA - relativeVirtualDifference(); + ExportNamePointer exportNamePointerTable[directoryTable.namePointersAmount] @ directoryTable.namePointerTableRVA - relativeVirtualDifference(); + if (directoryTable.ordinalTableRVA > relativeVirtualDifference()) { + u16 exportOrdinalTable[directoryTable.namePointersAmount] @ directoryTable.ordinalTableRVA - relativeVirtualDifference(); + } + if (directoryTable.imageNameRVA > relativeVirtualDifference()) { + char imageName[] @ directoryTable.imageNameRVA - relativeVirtualDifference() [[format("formatNullTerminatedString")]]; + } + $ = addressof(this)+coffHeader.optionalHeader.directories[0].size; }; // Imports Table bitfield OrdinalFlagByte { - padding : 7; - flag : 1 [[name("ordinalFlag")]]; + padding : 7; + flag : 1 [[name("ordinalFlag")]]; +}; + +fn formatMangledString(str string) { + return hex::dec::demangle(formatNullTerminatedString(string)); }; struct ImportsName { - u16 hint; - char name[] [[format("formatNullTerminatedString")]]; - if ($ % 2 == 1) { u8 pad; } + u16 hint; + if (std::mem::read_string($, 1) == "?") + char name[] [[format("formatMangledString")]]; + else + char name[] [[format("formatNullTerminatedString")]]; + if ($ % 2 == 1) { u8 pad; } }; struct ImportsAddress { - OrdinalFlagByte ordinalFlagByte @ $+(wordsize()-1); - if (ordinalFlagByte.flag) { - u16 ordinalNumber; - padding[wordsize()-2]; - } else { - u32 nameTableRVA; - if (coffHeader.optionalHeader.magic == PEFormat::PE32Plus) { - padding[4]; - } - } + OrdinalFlagByte ordinalFlagByte @ $+(wordsize()-1); + if (ordinalFlagByte.flag) { + u16 ordinalNumber; + padding[wordsize()-2]; + } else { + u32 nameTableRVA; + if (coffHeader.optionalHeader.magic == PEFormat::PE32Plus) { + padding[4]; + } + } }; struct ImportsLookup : ImportsAddress { - if (!ordinalFlagByte.flag && std::mem::read_unsigned($-wordsize(), wordsize()) > 0) { - ImportsName name @ nameTableRVA - relativeVirtualDifference(); - } + if (!ordinalFlagByte.flag && std::mem::read_unsigned($-wordsize(), wordsize()) > 0) { + ImportsName name @ nameTableRVA - relativeVirtualDifference(); + } }; struct ImportsDirectory { - u32 lookupTableRVA; - u32 timeDateStamp; - u32 forwarderChain; - u32 dllNameRVA; - u32 addressTableRVA; + u32 lookupTableRVA; + u32 timeDateStamp; + u32 forwarderChain; + u32 dllNameRVA; + u32 addressTableRVA; }; struct ImportsStructure { - if (parent.importsDirectoryTable[std::core::array_index()].lookupTableRVA > 0) { - ImportsLookup lookupTable[while(std::mem::read_unsigned($, wordsize()) != 0)] @ parent.importsDirectoryTable[std::core::array_index()].lookupTableRVA - relativeVirtualDifference(); - } - if (parent.importsDirectoryTable[std::core::array_index()].addressTableRVA > 0) { - ImportsAddress addressTable[while(std::mem::read_unsigned($, wordsize()) != 0)] @ parent.importsDirectoryTable[std::core::array_index()].addressTableRVA - relativeVirtualDifference(); - } - if (parent.importsDirectoryTable[std::core::array_index()].dllNameRVA > 0) { - char dllName[] @ parent.importsDirectoryTable[std::core::array_index()].dllNameRVA - relativeVirtualDifference() [[format("formatNullTerminatedString")]]; - } + if (parent.importsDirectoryTable[std::core::array_index()].lookupTableRVA > 0) { + ImportsLookup lookupTable[while(std::mem::read_unsigned($, wordsize()) != 0)] @ parent.importsDirectoryTable[std::core::array_index()].lookupTableRVA - relativeVirtualDifference(); + } + if (parent.importsDirectoryTable[std::core::array_index()].addressTableRVA > 0) { + ImportsAddress addressTable[while(std::mem::read_unsigned($, wordsize()) != 0)] @ parent.importsDirectoryTable[std::core::array_index()].addressTableRVA - relativeVirtualDifference(); + } + if (parent.importsDirectoryTable[std::core::array_index()].dllNameRVA > 0) { + char dllName[] @ parent.importsDirectoryTable[std::core::array_index()].dllNameRVA - relativeVirtualDifference() [[format("formatNullTerminatedString")]]; + } } [[inline]]; struct ImportsTable { - ImportsDirectory importsDirectoryTable[while(std::mem::read_unsigned($, 16) != 0)]; - ImportsStructure importsStructures[sizeof(importsDirectoryTable)/sizeof(importsDirectoryTable[0])] [[inline]]; - $ = addressof(this)+coffHeader.optionalHeader.directories[1].size; + ImportsDirectory importsDirectoryTable[while(std::mem::read_unsigned($, 16) != 0)]; + ImportsStructure importsStructures[sizeof(importsDirectoryTable)/sizeof(importsDirectoryTable[0])] [[inline]]; + $ = addressof(this)+coffHeader.optionalHeader.directories[1].size; }; struct DelayedImportsDirectory { - u32 attributes; - u32 name; - u32 moduleHandle; - u32 delayImportAddressTable; - u32 delayImportNameTable; - u32 boundDelayImportTable; - u32 unloadDelayImportTable; - u32 timeStamp; + u32 attributes; + u32 name; + u32 moduleHandle; + u32 delayImportAddressTable; + u32 delayImportNameTable; + u32 boundDelayImportTable; + u32 unloadDelayImportTable; + u32 timeStamp; }; struct DelayImportsStructure { - if (parent.delayImportsDirectoryTable[std::core::array_index()].delayImportNameTable > 0) { - ImportsLookup delayedLookupTable[while(std::mem::read_unsigned($, wordsize()) != 0)] @ parent.delayImportsDirectoryTable[std::core::array_index()].delayImportNameTable - relativeVirtualDifference(); - } - if (parent.delayImportsDirectoryTable[std::core::array_index()].name > 0) { - char dllName[] @ parent.delayImportsDirectoryTable[std::core::array_index()].name - relativeVirtualDifference() [[format("formatNullTerminatedString")]]; - } + if (parent.delayImportsDirectoryTable[std::core::array_index()].delayImportNameTable > 0) { + ImportsLookup delayedLookupTable[while(std::mem::read_unsigned($, wordsize()) != 0)] @ parent.delayImportsDirectoryTable[std::core::array_index()].delayImportNameTable - relativeVirtualDifference(); + } + if (parent.delayImportsDirectoryTable[std::core::array_index()].name > 0) { + char dllName[] @ parent.delayImportsDirectoryTable[std::core::array_index()].name - relativeVirtualDifference() [[format("formatNullTerminatedString")]]; + } } [[inline]]; // https://learn.microsoft.com/en-us/windows/win32/debug/pe-format#delay-load-import-tables-image-only struct DelayedImportsTable { - DelayedImportsDirectory delayImportsDirectoryTable[while(std::mem::read_unsigned($, 16) != 0)]; - DelayImportsStructure delayImportsStructures[sizeof(delayImportsDirectoryTable)/sizeof(delayImportsDirectoryTable[0])] [[inline]]; - $ = addressof(this)+coffHeader.optionalHeader.directories[1].size; + DelayedImportsDirectory delayImportsDirectoryTable[while(std::mem::read_unsigned($, 16) != 0)]; + DelayImportsStructure delayImportsStructures[sizeof(delayImportsDirectoryTable)/sizeof(delayImportsDirectoryTable[0])] [[inline]]; + $ = addressof(this)+coffHeader.optionalHeader.directories[1].size; }; // General Resource Table things fn formatNullTerminatedString16(str string) { - return "\"" + std::string::substr(string, 0, std::string::length(string)) + "\""; + return "\"" + std::string::substr(string, 0, std::string::length(string)) + "\""; }; // * Bitmap Resource struct BitmapHeader { - u32 size [[name("bitmapSize")]]; - u32 width [[name("bitmapWidth")]]; - u32 height [[name("bitmapHeight")]]; - u16 planes [[name("bitmapPlanes")]]; - u16 bitCount [[name("bitmapBitCount")]]; - u32 compression [[name("bitmapCompression")]]; - u32 imageSize [[name("bitmapImageSize")]]; - u32 xPelsPerMeter [[name("bitmapXPelsPerMeter")]]; - u32 yPelsPerMeter [[name("bitmapYPelsPerMeter")]]; - u32 clrUsed [[name("bitmapClrUsed")]]; - u32 clrImportant [[name("bitmapClrImportant")]]; + u32 size [[name("bitmapSize")]]; + u32 width [[name("bitmapWidth")]]; + u32 height [[name("bitmapHeight")]]; + u16 planes [[name("bitmapPlanes")]]; + u16 bitCount [[name("bitmapBitCount")]]; + u32 compression [[name("bitmapCompression")]]; + u32 imageSize [[name("bitmapImageSize")]]; + u32 xPelsPerMeter [[name("bitmapXPelsPerMeter")]]; + u32 yPelsPerMeter [[name("bitmapYPelsPerMeter")]]; + u32 clrUsed [[name("bitmapClrUsed")]]; + u32 clrImportant [[name("bitmapClrImportant")]]; }; struct Colors { - u8 blue [[color("1F77B4")]]; - u8 green [[color("2CA02C")]]; - u8 red [[color("D62728")]]; - u8 reserved [[color("828282")]]; + u8 blue [[color("1F77B4")]]; + u8 green [[color("2CA02C")]]; + u8 red [[color("D62728")]]; + u8 reserved [[color("828282")]]; }; u32 imageDataSize; struct Bitmap { - BitmapHeader bmh [[name("bitmapHeader")]]; + BitmapHeader bmh [[name("bitmapHeader")]]; - if ((bmh.bitCount != 24) && (bmh.bitCount != 32)) { - Colors rgbq[bmh.clrUsed*((1 << bmh.bitCount)*!bmh.clrUsed)]; - imageDataSize = imageDataSize - sizeof(rgbq); - } + if ((bmh.bitCount != 24) && (bmh.bitCount != 32)) { + Colors rgbq[bmh.clrUsed*((1 << bmh.bitCount)*!bmh.clrUsed)]; + imageDataSize = imageDataSize - sizeof(rgbq); + } - u8 imageData[imageDataSize-sizeof(bmh)]; + u8 imageData[imageDataSize-sizeof(bmh)]; }; // * Cursor Resource struct Cursor { - u16 reserved; - u16 type; - if (!type) { - imageDataSize = parent.size-4; - Bitmap bitmapData [[inline]]; - } + u16 reserved; + u16 type; + if (!type) { + imageDataSize = parent.size-4; + Bitmap bitmapData [[inline]]; + } }; // * Dialog Resource enum AtomType : u16 { - Button = 0x80, - Edit, - Static, - ListBox, - ScrollBar, - ComboBox + Button = 0x80, + Edit, + Static, + ListBox, + ScrollBar, + ComboBox }; struct VLSElement { - if (std::mem::read_unsigned($, 2) == 0xFFFF) { - u16 atomDefiner; - } - else { - AtomType atom; - } + if (std::mem::read_unsigned($, 2) == 0xFFFF) { + u16 atomDefiner; + } + else { + AtomType atom; + } }; struct VariableLengthStructure { - if (std::mem::read_unsigned($, 2) == 0xFFFF) { - VLSElement vlsElement[2]; - } - else { - char16 string[] [[format("formatNullTerminatedString16")]]; - } + if (std::mem::read_unsigned($, 2) == 0xFFFF) { + VLSElement vlsElement[2]; + } + else { + char16 string[] [[format("formatNullTerminatedString16")]]; + } }; struct DialogTemplate { - if (parent.parent.parent.parent.id == 0x411) { - u16 version; - u16 signature; - u32 helpContextIdentifier; - u32 extendedStyles; - u32 style; - } - else { - u32 style; - u32 extendedStyles; - } - u16 numberOfItems; - u16 x; - u16 y; - u16 width; - u16 height; - if (parent.parent.parent.parent.id == 0x409 || parent.parent.parent.parent.id == 0x411) { - VariableLengthStructure dialogMenu; - VariableLengthStructure dialogClass; - char16 dialogTitle[] [[format("formatNullTerminatedString16")]]; - u16 dialogFontSize; - if (parent.parent.parent.parent.id == 0x411) { - u16 weight; - bool italic; - u8 charset; - } - char16 dialogFontTypeface[] [[format("formatNullTerminatedString16")]]; - if (($+2)%16 == 0 || 4 || 8 || 12) - u16 alignment; - } + if (parent.parent.parent.parent.id == 0x411) { + u16 version; + u16 signature; + u32 helpContextIdentifier; + u32 extendedStyles; + u32 style; + } + else { + u32 style; + u32 extendedStyles; + } + u16 numberOfItems; + u16 x; + u16 y; + u16 width; + u16 height; + if (parent.parent.parent.parent.id == 0x409 || parent.parent.parent.parent.id == 0x411) { + VariableLengthStructure dialogMenu; + VariableLengthStructure dialogClass; + char16 dialogTitle[] [[format("formatNullTerminatedString16")]]; + u16 dialogFontSize; + if (parent.parent.parent.parent.id == 0x411) { + u16 weight; + bool italic; + u8 charset; + } + char16 dialogFontTypeface[] [[format("formatNullTerminatedString16")]]; + if (($+2)%16 == 0 || 4 || 8 || 12) + u16 alignment; + } }; struct DialogItemTemplate { - if (parent.parent.parent.parent.parent.id == 0x411) { - u32 helpContextIdentifier; - u32 extendedStyles [[name("itemExtendedStyles")]]; - u32 style [[name("itemStyle")]]; - } - else { - u32 style [[name("itemStyle")]]; - u32 extendedStyles [[name("itemExtendedStyles")]]; - } - u16 x; - u16 y; - u16 width; - u16 height; - if (parent.parent.parent.parent.parent.id == 0x409 || parent.parent.parent.parent.parent.id == 0x411) { - u32 controlID; - VariableLengthStructure windowClass; - VariableLengthStructure dialogItemTitle; - u16 extraCount; - } else { - u16 controlID; - } - if (($+2)%16 == 0 || 4 || 8) - u16 alignment; + if (parent.parent.parent.parent.parent.id == 0x411) { + u32 helpContextIdentifier; + u32 extendedStyles [[name("itemExtendedStyles")]]; + u32 style [[name("itemStyle")]]; + } + else { + u32 style [[name("itemStyle")]]; + u32 extendedStyles [[name("itemExtendedStyles")]]; + } + u16 x; + u16 y; + u16 width; + u16 height; + if (parent.parent.parent.parent.parent.id == 0x409 || parent.parent.parent.parent.parent.id == 0x411) { + u32 controlID; + VariableLengthStructure windowClass; + VariableLengthStructure dialogItemTitle; + u16 extraCount; + } else { + u16 controlID; + } + if (($+2)%16 == 0 || 4 || 8) + u16 alignment; }; struct DialogItem { - DialogItemTemplate template [[inline]]; - /*if (parent.parent.parent.parent.id == 0x409 || parent.parent.parent.parent.id == 0x411) { - u8 itemCreationData[template.extraCount]; - }*/ + DialogItemTemplate template [[inline]]; + /*if (parent.parent.parent.parent.id == 0x409 || parent.parent.parent.parent.id == 0x411) { + u8 itemCreationData[template.extraCount]; + }*/ }; struct Dialog { - DialogTemplate dialogTemplate; - DialogItem items[dialogTemplate.numberOfItems]; + DialogTemplate dialogTemplate; + DialogItem items[dialogTemplate.numberOfItems]; }; // * String Resource struct StringTableResource { - std::string::SizedString16 strings[while($ < (parent.dataRVA - relativeVirtualDifference()) + parent.size)]; + std::string::SizedString16 strings[while($ < (parent.dataRVA - relativeVirtualDifference()) + parent.size)]; }; // * GroupCursor Resource struct GroupCursor { - u16 assorteddata; - u16 colors; - u16 otherassorteddata; - u16 pixels; - u16 assorteddataarray[5]; - u16 ordinalName; + u16 assorteddata; + u16 colors; + u16 otherassorteddata; + u16 pixels; + u16 assorteddataarray[5]; + u16 ordinalName; }; // * GroupIcon Resource struct GroupIconHeader { - u16 reserved; - u16 type; - u16 count; + u16 reserved; + u16 type; + u16 count; }; struct GroupIconEntry { - u8 width; - u8 height; - u8 colorCount; - u8 reserved; - u16 planes; - u16 bitCount; - u32 bytesInResource; - u16 id; + u8 width; + u8 height; + u8 colorCount; + u8 reserved; + u16 planes; + u16 bitCount; + u32 bytesInResource; + u16 id; }; struct GroupIcon { - GroupIconHeader header; - GroupIconEntry entries[header.count]; + GroupIconHeader header; + GroupIconEntry entries[header.count]; }; // * Version Resource struct VersionEntryHeader { - u16 length; - u16 valueLength; - u16 type; - char16 key[] [[format("formatNullTerminatedString16")]]; - padding[while(std::mem::read_unsigned($, 1) == 0 && $ < addressof(key)+sizeof(key)+5)]; + u16 length; + u16 valueLength; + u16 type; + char16 key[] [[format("formatNullTerminatedString16")]]; + padding[while(!$[$] && $ < addressof(key)+sizeof(key)+5)]; }; struct StringInfo { - VersionEntryHeader stringInfoHeader; - if (stringInfoHeader.valueLength > 0) { - char16 string[] [[format("formatNullTerminatedString16")]]; - padding[while(std::mem::read_unsigned($, 1) == 0)]; - } + VersionEntryHeader stringInfoHeader; + if (stringInfoHeader.valueLength > 0) { + char16 string[] [[format("formatNullTerminatedString16")]]; + padding[while(!$[$])]; + } }; struct VersionEntry { - VersionEntryHeader header [[inline]]; - if (header.key == "StringFileInfo") { - VersionEntryHeader stringTableHeader; - StringInfo strings[while($ < addressof(stringTableHeader) + stringTableHeader.length)]; - } - else if (header.key == "VarFileInfo") { - VersionEntryHeader varHeader; - u16 translation[varHeader.valueLength / 2]; - } - else { - u8 value[header.valueLength]; - padding[while(std::mem::read_unsigned($, 1) == 0)]; - } + VersionEntryHeader header [[inline]]; + if (header.key == "StringFileInfo") { + VersionEntryHeader stringTableHeader; + StringInfo strings[while($ < addressof(stringTableHeader) + stringTableHeader.length)]; + } + else if (header.key == "VarFileInfo") { + VersionEntryHeader varHeader; + u16 translation[varHeader.valueLength / 2]; + } + else { + u8 value[header.valueLength]; + padding[while(!$[$])]; + } }; struct Version { - VersionEntryHeader header [[inline]]; - u32 signature; - u16 structVersion[2]; - u16 fileVersion[4]; - u16 productVersion[4]; - u32 fileFlagsMask[2]; - u32 fileFlags; - u32 fileOS; - u32 fileType; - u32 fileSubType; - u32 fileTimestamp; - VersionEntry children[while($ < (parent.dataRVA - relativeVirtualDifference()) + parent.size)]; + VersionEntryHeader header [[inline]]; + u32 signature; + u16 structVersion[2]; + u16 fileVersion[4]; + u16 productVersion[4]; + u32 fileFlagsMask[2]; + u32 fileFlags; + u32 fileOS; + u32 fileType; + u32 fileSubType; + u32 fileTimestamp; + VersionEntry children[while($ < (parent.dataRVA - relativeVirtualDifference()) + parent.size)]; }; // * Resources Using TrueChar fn displayTrueChar(u8 value) { - str notation = "0x"; - if (value < 0x10) - notation += "0"; - if (value == 0) - return "'␀' (" + std::format(notation + "{:X}", value) + ")"; - else - return "'" + char(value) + "' (" + std::format(notation + "{:X}", value) + ")"; + char chr = char(value); + str notation = "0x"; + if (value < 0x10) notation += "0"; + if (!value) chr = "␀"; + return "'" + chr + "' (" + std::format(notation + "{:X}", value) + ")"; }; +using TrueChar = u8 [[format("displayTrueChar")]]; + // Resource Table enum ResourceID : u32 { - Cursor = 0x01, - Bitmap, - Icon, - Menu, - Dialog, - String, - Accelerator = 0x09, - StringData, - GroupCursor = 0x0C, - GroupIcon = 0x0E, - Version = 0x10, - Manifest = 0x18 + Cursor = 0x01, + Bitmap, + Icon, + Menu, + Dialog, + String, + Accelerator = 0x09, + StringData, + GroupCursor = 0x0C, + GroupIcon = 0x0E, + Version = 0x10, + Manifest = 0x18 }; ResourceID resourceIDType; -using TrueChar = u8 [[format("displayTrueChar")]]; - struct DataEntry { - u32 dataRVA; - u32 size; - u32 codepage; - u32 reserved; - - if (resourceIDType == ResourceID::Cursor) { - Cursor cursor @ dataRVA - relativeVirtualDifference(); - } - else if (resourceIDType == ResourceID::Bitmap || (resourceIDType == ResourceID::Icon && std::mem::read_string((dataRVA - relativeVirtualDifference())+1, 3) != "PNG")) { - imageDataSize = size; - Bitmap bitmap @ dataRVA - relativeVirtualDifference(); - } - else if (resourceIDType == ResourceID::Dialog) { - Dialog dialog @ dataRVA - relativeVirtualDifference(); - } - else if (resourceIDType == ResourceID::String) { - StringTableResource stringTableResource @ dataRVA - relativeVirtualDifference(); - } - else if (resourceIDType == ResourceID::StringData) { - TrueChar stringData[size] @ dataRVA - relativeVirtualDifference(); - } - else if (resourceIDType == ResourceID::GroupCursor) { - GroupCursor groupCursor @ dataRVA - relativeVirtualDifference(); - } - else if (resourceIDType == ResourceID::GroupIcon) { - GroupIcon groupIcon @ dataRVA - relativeVirtualDifference(); - } - else if (resourceIDType == ResourceID::Version) { - Version version @ dataRVA - relativeVirtualDifference(); - } - else if (resourceIDType == ResourceID::Manifest) { - TrueChar manifest[size] @ dataRVA - relativeVirtualDifference(); - } - else { - u8 resource[size] @ dataRVA - relativeVirtualDifference(); - } + u32 dataRVA; + u32 size; + u32 codepage; + u32 reserved; + + if (resourceIDType == ResourceID::Cursor) { + Cursor cursor @ dataRVA - relativeVirtualDifference(); + } + else if (resourceIDType == ResourceID::Bitmap || (resourceIDType == ResourceID::Icon && std::mem::read_string((dataRVA - relativeVirtualDifference())+1, 3) != "PNG")) { + imageDataSize = size; + Bitmap bitmap @ dataRVA - relativeVirtualDifference(); + } + else if (resourceIDType == ResourceID::Dialog) { + Dialog dialog @ dataRVA - relativeVirtualDifference(); + } + else if (resourceIDType == ResourceID::String) { + StringTableResource stringTableResource @ dataRVA - relativeVirtualDifference(); + } + else if (resourceIDType == ResourceID::StringData) { + TrueChar stringData[size] @ dataRVA - relativeVirtualDifference(); + } + else if (resourceIDType == ResourceID::GroupCursor) { + GroupCursor groupCursor @ dataRVA - relativeVirtualDifference(); + } + else if (resourceIDType == ResourceID::GroupIcon) { + GroupIcon groupIcon @ dataRVA - relativeVirtualDifference(); + } + else if (resourceIDType == ResourceID::Version) { + Version version @ dataRVA - relativeVirtualDifference(); + } + else if (resourceIDType == ResourceID::Manifest) { + TrueChar manifest[size] @ dataRVA - relativeVirtualDifference(); + } + else { + u8 resource[size] @ dataRVA - relativeVirtualDifference(); + } }; using ResourceDirectory; bitfield OffsetField { - offset : 31; - pointingToDirectory : 1; + offset : 31; + pointingToDirectory : 1; }; struct DataField { - if (std::mem::read_unsigned($+3, 1) >= 0x80) { - OffsetField offsetToData; - ResourceDirectory directory @ coffHeader.optionalHeader.directories[2].rva - relativeVirtualDifference() + offsetToData.offset; - } - else { - u32 offsetToData; - DataEntry dataEntry @ coffHeader.optionalHeader.directories[2].rva - relativeVirtualDifference() + offsetToData; - } + if ($[$+3] >= 0x80) { + OffsetField offsetToData; + ResourceDirectory directory @ coffHeader.optionalHeader.directories[2].rva - relativeVirtualDifference() + offsetToData.offset; + } + else { + u32 offsetToData; + DataEntry dataEntry @ coffHeader.optionalHeader.directories[2].rva - relativeVirtualDifference() + offsetToData; + } } [[inline]]; struct IdDirectoryEntry { - if ($ > coffHeader.optionalHeader.directories[2].rva - relativeVirtualDifference() + 0x10 + 8*(parent.directoryTable.nameEntriesAmount + parent.directoryTable.idEntriesAmount)) { - u32 id; - } - else { - ResourceID id; - resourceIDType = std::mem::read_unsigned(addressof(id), 4); - } + if ($ > coffHeader.optionalHeader.directories[2].rva - relativeVirtualDifference() + 0x10 + 8*(parent.directoryTable.nameEntriesAmount + parent.directoryTable.idEntriesAmount)) { + u32 id; + } + else { + ResourceID id; + resourceIDType = std::mem::read_unsigned(addressof(id), 4); + } - DataField datafield; + DataField datafield; }; struct NameDirectoryEntry { - OffsetField offsetToName; - std::string::SizedString16 name @ coffHeader.optionalHeader.directories[2].rva - relativeVirtualDifference() + offsetToName.offset; + OffsetField offsetToName; + std::string::SizedString16 name @ coffHeader.optionalHeader.directories[2].rva - relativeVirtualDifference() + offsetToName.offset; - DataField datafield; + DataField datafield; }; struct ResourceDirectoryTable { - u32 characteristics; - u32 timeDateStamp; - u16 majorVersion; - u16 minorVersion; - u16 nameEntriesAmount; - u16 idEntriesAmount; + u32 characteristics; + u32 timeDateStamp; + u16 majorVersion; + u16 minorVersion; + u16 nameEntriesAmount; + u16 idEntriesAmount; }; struct ResourceDirectory { - ResourceDirectoryTable directoryTable [[hex::spec_name("resourceDirectoryTable")]]; - NameDirectoryEntry nameEntries[directoryTable.nameEntriesAmount]; - IdDirectoryEntry idEntries[directoryTable.idEntriesAmount]; + ResourceDirectoryTable directoryTable [[hex::spec_name("resourceDirectoryTable")]]; + NameDirectoryEntry nameEntries[directoryTable.nameEntriesAmount]; + IdDirectoryEntry idEntries[directoryTable.idEntriesAmount]; }; struct ResourceTable { - ResourceDirectory rootDirectory; - $ = addressof(this)+coffHeader.optionalHeader.directories[2].size; + ResourceDirectory rootDirectory; + $ = addressof(this)+coffHeader.optionalHeader.directories[2].size; }; // Base Relocations Table enum BaseRelocationType : u8 { - Absolute, - High, - Low, - HighLow, - HighAdjacent, - Reserved = 6, - DIR64 = 10 + Absolute, + High, + Low, + HighLow, + HighAdjacent, + Reserved = 6, + DIR64 = 10 }; enum MIPSBaseRelocationType : u8 { - Absolute, - High, - Low, - HighLow, - HighAdjacent, - MIPSJMPAddress, - Reserved, - MIPSJMPAddress16 = 9, - DIR64 + Absolute, + High, + Low, + HighLow, + HighAdjacent, + MIPSJMPAddress, + Reserved, + MIPSJMPAddress16 = 9, + DIR64 }; enum ARMBaseRelocationType : u8 { - Absolute, - High, - Low, - HighLow, - HighAdjacent, - ARMMOV32, - Reserved, - DIR64 = 10 + Absolute, + High, + Low, + HighLow, + HighAdjacent, + ARMMOV32, + Reserved, + DIR64 = 10 }; enum RISCVBaseRelocationType : u8 { - Absolute, - High, - Low, - HighLow, - HighAdjacent, - RISCVHigh20, - Reserved, - RISCVLow12I, - RISCVLow12S, - DIR64 = 10 + Absolute, + High, + Low, + HighLow, + HighAdjacent, + RISCVHigh20, + Reserved, + RISCVLow12I, + RISCVLow12S, + DIR64 = 10 }; enum THUMBBaseRelocationType : u8 { - Absolute, - High, - Low, - HighLow, - HighAdjacent, - ARMMOV32, - Reserved, - ThumbMOV32, - DIR64 = 10 + Absolute, + High, + Low, + HighLow, + HighAdjacent, + ARMMOV32, + Reserved, + ThumbMOV32, + DIR64 = 10 }; enum LoongarchBaseRelocationType : u8 { - Absolute, - High, - Low, - HighLow, - HighAdjacent, - Reserved = 6, - MarkLA = 8, - DIR64 = 10 + Absolute, + High, + Low, + HighLow, + HighAdjacent, + Reserved = 6, + MarkLA = 8, + DIR64 = 10 }; fn formatBaseRelocationType(u8 value) { - if (coffHeader.architecture == ArchitectureType::MIPS16 || coffHeader.architecture == ArchitectureType::MIPSFPU || coffHeader.architecture == ArchitectureType::MIPSFPU16 || - coffHeader.architecture == ArchitectureType::R3000 || coffHeader.architecture == ArchitectureType::R4000 || coffHeader.architecture == ArchitectureType::R10000) { - MIPSBaseRelocationType mipsTypeBits = value; - return mipsTypeBits; - } - else if (coffHeader.architecture == ArchitectureType::ARM || coffHeader.architecture == ArchitectureType::ARM64 || coffHeader.architecture == ArchitectureType::ARMNT) { - ARMBaseRelocationType armTypeBits = value; - return armTypeBits; - } - else if (coffHeader.architecture == ArchitectureType::RISCV32 || coffHeader.architecture == ArchitectureType::RISCV64 || coffHeader.architecture == ArchitectureType::RISCV128) { - RISCVBaseRelocationType riscvTypeBits = value; - return riscvTypeBits; - } - else if (coffHeader.architecture == ArchitectureType::THUMB) { - THUMBBaseRelocationType thumbTypeBits = value; - return thumbTypeBits; - } - else if (coffHeader.architecture == ArchitectureType::LOONGARCH32 || coffHeader.architecture == ArchitectureType::LOONGARCH64) { - LoongarchBaseRelocationType loongarchTypeBits = value; - return loongarchTypeBits; - } - else { - BaseRelocationType genericTypeBits = value; - return genericTypeBits; - } + if (coffHeader.architecture == ArchitectureType::MIPS16 || coffHeader.architecture == ArchitectureType::MIPSFPU || coffHeader.architecture == ArchitectureType::MIPSFPU16 || + coffHeader.architecture == ArchitectureType::R3000 || coffHeader.architecture == ArchitectureType::R4000 || coffHeader.architecture == ArchitectureType::R10000) { + MIPSBaseRelocationType mipsTypeBits = value; + return mipsTypeBits; + } + else if (coffHeader.architecture == ArchitectureType::ARM || coffHeader.architecture == ArchitectureType::ARM64 || coffHeader.architecture == ArchitectureType::ARMNT) { + ARMBaseRelocationType armTypeBits = value; + return armTypeBits; + } + else if (coffHeader.architecture == ArchitectureType::RISCV32 || coffHeader.architecture == ArchitectureType::RISCV64 || coffHeader.architecture == ArchitectureType::RISCV128) { + RISCVBaseRelocationType riscvTypeBits = value; + return riscvTypeBits; + } + else if (coffHeader.architecture == ArchitectureType::THUMB) { + THUMBBaseRelocationType thumbTypeBits = value; + return thumbTypeBits; + } + else if (coffHeader.architecture == ArchitectureType::LOONGARCH32 || coffHeader.architecture == ArchitectureType::LOONGARCH64) { + LoongarchBaseRelocationType loongarchTypeBits = value; + return loongarchTypeBits; + } + else { + BaseRelocationType genericTypeBits = value; + return genericTypeBits; + } }; bitfield BaseRelocationWord { - offset : 12; - type : 4 [[format("formatBaseRelocationType")]]; + offset : 12; + type : 4 [[format("formatBaseRelocationType")]]; }; struct BaseRelocationBlock { - u32 pageRVA; - u32 blockSize; - BaseRelocationWord word[while($ < addressof(this) + this.blockSize)] [[inline]]; + u32 pageRVA; + u32 blockSize; + BaseRelocationWord word[while($ < addressof(this) + this.blockSize)] [[inline]]; }; struct BaseRelocationTable { - BaseRelocationBlock baseRelocationBlocks[while($ < addressof(this) + coffHeader.optionalHeader.directories[5].size)] [[inline]]; + BaseRelocationBlock baseRelocationBlocks[while($ < addressof(this) + coffHeader.optionalHeader.directories[5].size)] [[inline]]; }; // Debug Table enum DebugType : u32 { - Unknown, - COFF, - Codeview, - FPO, - Misc, - Exception, - Fixup, - OmapToSRC, - OmapFromSRC, - Borland, - Reserved10, - CLSID, - REPRO = 16, - ExtendedDLLCharacteristics = 20 + Unknown, + COFF, + Codeview, + FPO, + Misc, + Exception, + Fixup, + OmapToSRC, + OmapFromSRC, + Borland, + CLSID = 11, + REPRO = 16, + ExtendedDLLCharacteristics = 20 }; struct RSDS { - char signature[4]; - type::GUID guid; - u32 age; - char path[] [[format("formatNullTerminatedString")]]; + char signature[4]; + type::GUID guid; + u32 age; + char path[] [[format("formatNullTerminatedString")]]; }; struct DebugDirectory { - u32 characteristics; - type::time32_t timeDateStamp; - u16 majorVersion; - u16 minorVersion; - DebugType type; - u32 sizeOfData; - u32 virtualAddressOfRawData; - u32 pointerOfRawData; + u32 characteristics; + type::time32_t timeDateStamp; + u16 majorVersion; + u16 minorVersion; + DebugType type; + u32 sizeOfData; + u32 virtualAddressOfRawData; + u32 pointerOfRawData; }; struct DebugData { - DebugDirectory directory; - if (std::mem::read_string(directory.pointerOfRawData, 4) == "RSDS") { - RSDS rsds @ directory.pointerOfRawData; - } - else { - u8 data[directory.sizeOfData] @ directory.pointerOfRawData; - } - $ = addressof(this)+coffHeader.optionalHeader.directories[6].size; + DebugDirectory directory; + if (std::mem::read_string(directory.pointerOfRawData, 4) == "RSDS") { + RSDS rsds @ directory.pointerOfRawData; + } + else { + u8 data[directory.sizeOfData] @ directory.pointerOfRawData; + } + $ = addressof(this)+coffHeader.optionalHeader.directories[6].size; }; // TLS Table struct TLSTable { - if (coffHeader.optionalHeader.magic == PEFormat::PE32Plus) { - u64 rawDataStartVA; - u64 rawDataEndVA; - u64 indexAddress; - u64 callbacksAddress; - } - else { - u32 rawDataStartVA; - u32 rawDataEndVA; - u32 indexAddress; - u32 callbacksAddress; - } - u32 zeroFillSize; - u32 characteristics; - $ = addressof(this)+coffHeader.optionalHeader.directories[9].size; + if (coffHeader.optionalHeader.magic == PEFormat::PE32Plus) { + u64 rawDataStartVA; + u64 rawDataEndVA; + u64 indexAddress; + u64 callbacksAddress; + } + else { + u32 rawDataStartVA; + u32 rawDataEndVA; + u32 indexAddress; + u32 callbacksAddress; + } + u32 zeroFillSize; + u32 characteristics; + $ = addressof(this)+coffHeader.optionalHeader.directories[9].size; }; // CRT Section struct CRTSection { - u64 virtualAddresses[while($ < sectionsTable[currentSectionIndex].ptrRawData + sectionsTable[currentSectionIndex].sizeOfRawData)]; + u64 virtualAddresses[while($ < sectionsTable[currentSectionIndex].ptrRawData + sectionsTable[currentSectionIndex].sizeOfRawData)]; }; // Sections struct LineNumber { - if (std::mem::read_unsigned($+4) > 0) { - u32 virtualAddress; - } else { - u32 symbolTableIndex; - } - u32 lineNumber; + if (std::mem::read_unsigned($+4) > 0) { + u32 virtualAddress; + } else { + u32 symbolTableIndex; + } + u32 lineNumber; }; bool dataDirectoryInSection[coffHeader.optionalHeader.numberOfRVAsAndSizes]; fn checkForDataDirectory() { - for (u32 i = 0, i < coffHeader.optionalHeader.numberOfRVAsAndSizes, i += 1) - if (coffHeader.optionalHeader.directories[i].rva - relativeVirtualDifference() < sectionsTable[currentSectionIndex].ptrRawData+sectionsTable[currentSectionIndex].sizeOfRawData - && coffHeader.optionalHeader.directories[i].rva - relativeVirtualDifference() >= $) - dataDirectoryInSection[i] = true; + for (u32 i = 0, i < coffHeader.optionalHeader.numberOfRVAsAndSizes, i += 1) + if (coffHeader.optionalHeader.directories[i].rva - relativeVirtualDifference() < sectionsTable[currentSectionIndex].ptrRawData+sectionsTable[currentSectionIndex].sizeOfRawData + && coffHeader.optionalHeader.directories[i].rva - relativeVirtualDifference() >= $) + dataDirectoryInSection[i] = true; }; fn noDataDirectories() { - for (u32 i = 0, i < coffHeader.optionalHeader.numberOfRVAsAndSizes, i += 1) - if (dataDirectoryInSection[i]) return false; - return true; + for (u32 i = 0, i < coffHeader.optionalHeader.numberOfRVAsAndSizes, i += 1) + if (dataDirectoryInSection[i]) return false; + return true; }; -fn clearBoolArray() { - for (u32 i = 0, i < coffHeader.optionalHeader.numberOfRVAsAndSizes, i += 1) - dataDirectoryInSection[i] = false; +fn clearDirectoryChecks() { + for (u32 i = 0, i < coffHeader.optionalHeader.numberOfRVAsAndSizes, i += 1) + dataDirectoryInSection[i] = false; }; struct Section { - checkForDataDirectory(); - if (noDataDirectories()) { - if (std::string::starts_with(sectionsTable[currentSectionIndex].name, ".CRT")) // CRT section - CRTSection crtSection; - else - u8 freeformSection[sectionsTable[currentSectionIndex].sizeOfRawData]; // Freeform data section - } - else { - if (dataDirectoryInSection[0]) { - ExportsTable exportTable @ coffHeader.optionalHeader.directories[0].rva - relativeVirtualDifference(); - } - if (dataDirectoryInSection[1]) { - ImportsTable importTable @ coffHeader.optionalHeader.directories[1].rva - relativeVirtualDifference(); - } - if (dataDirectoryInSection[2]) { - ResourceTable resourceTable @ coffHeader.optionalHeader.directories[2].rva - relativeVirtualDifference(); - } - if (dataDirectoryInSection[3]) { - ExceptionTable exceptionTable @ coffHeader.optionalHeader.directories[3].rva - relativeVirtualDifference(); - } - if (dataDirectoryInSection[5]) { - BaseRelocationTable baseRelocationTable @ coffHeader.optionalHeader.directories[5].rva - relativeVirtualDifference(); - } - if (dataDirectoryInSection[6]) { - DebugData debugData @ coffHeader.optionalHeader.directories[6].rva - relativeVirtualDifference(); - } - if (dataDirectoryInSection[7]) { - char copyright[] @ coffHeader.optionalHeader.directories[7].rva - relativeVirtualDifference() [[format("formatNullTerminatedString")]]; - } - if (dataDirectoryInSection[9]) { - TLSTable tlsTable @ coffHeader.optionalHeader.directories[9].rva - relativeVirtualDifference(); - } - if (dataDirectoryInSection[13]) { - DelayedImportsTable delayedImportTable @ coffHeader.optionalHeader.directories[13].rva - relativeVirtualDifference(); - } - } - clearBoolArray(); - - LineNumber lineNumbers[sectionsTable[currentSectionIndex].numberOfLineNumbers] @ sectionsTable[currentSectionIndex].ptrLineNumbers; - - // Next section - if (sectionsTable[currentSectionIndex].sizeOfRawData > 0) // If the size of the next section is bigger than 0 - $ = addressof(this) + sectionsTable[currentSectionIndex].sizeOfRawData; // Put the current offset at the start of it to account for any bytes left - if (currentSectionIndex < coffHeader.numberOfSections-1) // If it's not the last section (to not make $ the address of an inexistent section) - $ = sectionsTable[currentSectionIndex+1].ptrRawData; // Put the current offset at the next section's address - currentSectionIndex += 1; // Make the current section index the next section's index + checkForDataDirectory(); + if (noDataDirectories()) { + if (std::string::starts_with(sectionsTable[currentSectionIndex].name, ".CRT")) // CRT section + CRTSection crtSection; + else + u8 freeformSection[sectionsTable[currentSectionIndex].sizeOfRawData]; // Freeform data section + } + else { + if (dataDirectoryInSection[0]) { + ExportsTable exportTable @ coffHeader.optionalHeader.directories[0].rva - relativeVirtualDifference(); + } + if (dataDirectoryInSection[1]) { + ImportsTable importTable @ coffHeader.optionalHeader.directories[1].rva - relativeVirtualDifference(); + } + if (dataDirectoryInSection[2]) { + ResourceTable resourceTable @ coffHeader.optionalHeader.directories[2].rva - relativeVirtualDifference(); + } + if (dataDirectoryInSection[3]) { + ExceptionTable exceptionTable @ coffHeader.optionalHeader.directories[3].rva - relativeVirtualDifference(); + } + if (dataDirectoryInSection[5]) { + BaseRelocationTable baseRelocationTable @ coffHeader.optionalHeader.directories[5].rva - relativeVirtualDifference(); + } + if (dataDirectoryInSection[6]) { + DebugData debugData @ coffHeader.optionalHeader.directories[6].rva - relativeVirtualDifference(); + } + if (dataDirectoryInSection[7]) { + char copyright[] @ coffHeader.optionalHeader.directories[7].rva - relativeVirtualDifference() [[format("formatNullTerminatedString")]]; + } + if (dataDirectoryInSection[9]) { + TLSTable tlsTable @ coffHeader.optionalHeader.directories[9].rva - relativeVirtualDifference(); + } + if (dataDirectoryInSection[13]) { + DelayedImportsTable delayedImportTable @ coffHeader.optionalHeader.directories[13].rva - relativeVirtualDifference(); + } + } + clearDirectoryChecks(); + + LineNumber lineNumbers[sectionsTable[currentSectionIndex].numberOfLineNumbers] @ sectionsTable[currentSectionIndex].ptrLineNumbers; + + // Next section + if (sectionsTable[currentSectionIndex].sizeOfRawData > 0) // If the size of the next section is bigger than 0 + $ = addressof(this) + sectionsTable[currentSectionIndex].sizeOfRawData; // Put the current offset at the start of it to account for any bytes left + if (currentSectionIndex < coffHeader.numberOfSections-1) // If it's not the last section (to not make $ the address of an inexistent section) + $ = sectionsTable[currentSectionIndex+1].ptrRawData; // Put the current offset at the next section's address + currentSectionIndex += 1; // Make the current section index the next section's index } [[name(sectionsTable[currentSectionIndex-1].name)]]; -Section sections[coffHeader.numberOfSections] @ sectionsTable[0].ptrRawData; +Section sections[coffHeader.numberOfSections] @ coffHeader.optionalHeader.sizeOfHeaders * !sectionsTable[0].sizeOfRawData + + sectionsTable[0].ptrRawData * sectionsTable[0].sizeOfRawData>0; // Symbol & String Tables enum SectionNumberType : s16 { - Undefined = 0, - Absolute = -1, - Debug = -2 + Undefined = 0, + Absolute = -1, + Debug = -2 }; enum SymbolTypeMSB : u8 { - Null = 0x00, - Pointer = 0x10, - Function = 0x20, - Array = 0x30 + Null = 0x00, + Pointer = 0x10, + Function = 0x20, + Array = 0x30 }; enum SymbolTypeLSB : u8 { - Null = 0x00, - Void = 0x01, - Char = 0x02, - Short = 0x03, - Integer = 0x04, - Long = 0x05, - Float = 0x06, - Double = 0x07, - Struct = 0x08, - Union = 0x09, - Enum = 0x0A, - MemberOfEnum = 0x0B, - Byte = 0x0C, - Word = 0x0D, - UInt = 0x0E, - DWord = 0x0F + Null = 0x00, + Void = 0x01, + Char = 0x02, + Short = 0x03, + Integer = 0x04, + Long = 0x05, + Float = 0x06, + Double = 0x07, + Struct = 0x08, + Union = 0x09, + Enum = 0x0A, + MemberOfEnum = 0x0B, + Byte = 0x0C, + Word = 0x0D, + UInt = 0x0E, + DWord = 0x0F }; enum StorageClassType : s8 { - EndOfFunction = -1, - Null = 0, - Automatic = 1, - External = 2, - Static = 3, - Register = 4, - DefinedExternally = 5, - Label = 6, - UndefinedLabel = 7, - MemberOfStruct = 8, - Argument = 9, - StructTag = 10, - MemberOfUnion = 11, - UnionTag = 12, - TypeDefinition = 13, - UndefinedStatic = 14, - EnumTag = 15, - MemberOfEnum = 16, - RegisterParameter = 17, - Bitfield = 18, - Block = 100, - BlockFunction = 101, - EndOfStruct = 102, - File = 103, - Section = 104, - WeakExternal = 105, - CLRToken = 107 + EndOfFunction = -1, + Null = 0, + Automatic = 1, + External = 2, + Static = 3, + Register = 4, + DefinedExternally = 5, + Label = 6, + UndefinedLabel = 7, + MemberOfStruct = 8, + Argument = 9, + StructTag = 10, + MemberOfUnion = 11, + UnionTag = 12, + TypeDefinition = 13, + UndefinedStatic = 14, + EnumTag = 15, + MemberOfEnum = 16, + RegisterParameter = 17, + Bitfield = 18, + Block = 100, + BlockFunction = 101, + EndOfStruct = 102, + File = 103, + Section = 104, + WeakExternal = 105, + CLRToken = 107 }; struct SymbolNameOffset { - padding[4]; - u32 offset [[name("nameOffset")]]; + padding[4]; + u32 offset [[name("nameOffset")]]; } [[inline]]; struct SymbolType { - SymbolTypeMSB msb; - SymbolTypeLSB lsb; + SymbolTypeMSB msb; + SymbolTypeLSB lsb; }; fn formatSymbolType(SymbolType value) { - return "{ " + std::string::to_string(value.msb) + " | " + std::string::to_string(value.lsb) + " }"; + return "{ " + std::string::to_string(value.msb) + " | " + std::string::to_string(value.lsb) + " }"; }; struct Symbol { - if (std::mem::read_unsigned($, 4) == 0) - SymbolNameOffset nameOffset; - else char shortName[8]; - u32 value; - SectionNumberType sectionNumber; - SymbolType type [[format("formatSymbolType")]]; - StorageClassType storageClass; - u8 numberOfAuxSymbols; + if (std::mem::read_unsigned($, 4) == 0) + SymbolNameOffset nameOffset; + else char shortName[8]; + u32 value; + SectionNumberType sectionNumber; + SymbolType type [[format("formatSymbolType")]]; + StorageClassType storageClass; + u8 numberOfAuxSymbols; }; bool checkForSymbols in; @@ -1205,12 +1210,12 @@ bool checkForSymbols in; Symbol symbolTable[checkForSymbols * coffHeader.numberOfSymbols] @ coffHeader.pointerToSymbolTable; struct SymbolString { - char string[] [[format("formatNullTerminatedString")]]; + char string[] [[format("formatNullTerminatedString")]]; } [[inline]]; struct StringTable { - u32 size; - SymbolString strings[while($ < addressof(this) + size)]; + u32 size; + SymbolString strings[while($ < addressof(this) + size)]; } [[inline]]; StringTable stringTable[sizeof(symbolTable)>0] @ addressof(symbolTable) + sizeof(symbolTable); @@ -1220,87 +1225,87 @@ bool checkForRichHeader in; u16 richHeaderEndPosition; u32 richHeaderPosition; fn findRichHeader() { - if (checkForRichHeader) { - for (u16 richEndCursor = peHeader.dosHeader.coffHeaderPointer, richEndCursor > peHeader.dosHeader.headerSizeInParagraphs*16, richEndCursor -= 1) { - if (std::mem::read_string(richEndCursor, 4) == "Rich") { - richHeaderEndPosition = richEndCursor; - //0x18 is the size of a Rich Header body with one product - for (u16 richCursor = richHeaderEndPosition - 0x18, richCursor > peHeader.dosHeader.headerSizeInParagraphs*16, richCursor -= 1) { - if (str(std::mem::read_unsigned(richCursor, 4) ^ std::mem::read_unsigned(richHeaderEndPosition+4, 4)) == "DanS") { - richHeaderPosition = richCursor; - break; - } - } - break; - } - } - } + if (checkForRichHeader) { + for (u16 richEndCursor = peHeader.dosHeader.coffHeaderPointer, richEndCursor > peHeader.dosHeader.headerSizeInParagraphs*16, richEndCursor -= 1) { + if (std::mem::read_string(richEndCursor, 4) == "Rich") { + richHeaderEndPosition = richEndCursor; + //0x18 is the size of a Rich Header body with one product + for (u16 richCursor = richHeaderEndPosition - 0x18, richCursor > peHeader.dosHeader.headerSizeInParagraphs*16, richCursor -= 1) { + if (str(std::mem::read_unsigned(richCursor, 4) ^ std::mem::read_unsigned(richHeaderEndPosition+4, 4)) == "DanS") { + richHeaderPosition = richCursor; + break; + } + } + break; + } + } + } }; findRichHeader(); fn formatHexadecimally(auto value) { - return std::string::to_string(value) + " (" + std::format("0x{:X}", value) + ")"; + return std::string::to_string(value) + " (" + std::format("0x{:X}", value) + ")"; }; fn unmask(u32 value) { - return formatHexadecimally(value ^ std::mem::read_unsigned(richHeaderEndPosition+4, 4)); + return formatHexadecimally(value ^ std::mem::read_unsigned(richHeaderEndPosition+4, 4)); }; fn unmaskBuild(u32 value) { - return formatHexadecimally(value ^ std::mem::read_unsigned(richHeaderEndPosition+4, 2)); + return formatHexadecimally(value ^ std::mem::read_unsigned(richHeaderEndPosition+4, 2)); }; fn unmaskProduct(u16 type) { - str value = "Unknown"; - str notation = "0x"; - if (type ^ std::mem::read_unsigned(richHeaderEndPosition+6, 2) < 0x10) { notation += "0"; } - match(type ^ std::mem::read_unsigned(richHeaderEndPosition+6, 2)) { - (0x00): value = "Unmarked"; - (0x01): value = "Imports"; - (0x04): value = "STDLIBDLL"; - (0x06): value = "VS97CVTRes"; - (0x0A): value = "VS98CCompiler"; - (0x0B): value = "VS98CPPCompiler"; - (0x0C): value = "OldNames"; - (0x0E): value = "MASM613"; - (0x0F): value = "VS2003Assembler"; - (0x16): value = "VC6SP5"; - (0x19): value = "VS2002Linker"; - (0x1C): value = "VS2002CCompiler"; - (0x1D): value = "VS2002CPPCompiler"; - (0x5D): value = "VS2003SDKIMP"; - (0x60): value = "VS2003CPPCompiler"; - (0x6D): value = "VS2005CCompiler"; - (0x6E): value = "VS2005CPPCompiler"; - (0x7B): value = "VS2005Linker"; - (0x93): value = "VS2008Linker"; - (0x9D): value = "Linker12"; - (0x9E): value = "MASM10"; - (0xAA): value = "VS2010CCompiler"; - (0xAB): value = "VS2010CPPCompiler"; - (0xFF): value = "VS2015CVTRes"; - (0x101 | 0x102): value = "VS2015Linker"; - (0x103): value = "VS2015Assembler"; - (0x104): value = "VS2015CCompiler"; - (0x105): value = "VS2015CPPCompiler"; - } - return value + " (" + std::format(notation + "{:X}", type ^ std::mem::read_unsigned(richHeaderEndPosition+6, 2)) + ")"; + str value = "Unknown"; + str notation = "0x"; + if (type ^ std::mem::read_unsigned(richHeaderEndPosition+6, 2) < 0x10) { notation += "0"; } + match(type ^ std::mem::read_unsigned(richHeaderEndPosition+6, 2)) { + (0x00): value = "Unmarked"; + (0x01): value = "Imports"; + (0x04): value = "STDLIBDLL"; + (0x06): value = "VS97CVTRes"; + (0x0A): value = "VS98CCompiler"; + (0x0B): value = "VS98CPPCompiler"; + (0x0C): value = "OldNames"; + (0x0E): value = "MASM613"; + (0x0F): value = "VS2003Assembler"; + (0x16): value = "VC6SP5"; + (0x19): value = "VS2002Linker"; + (0x1C): value = "VS2002CCompiler"; + (0x1D): value = "VS2002CPPCompiler"; + (0x5D): value = "VS2003SDKIMP"; + (0x60): value = "VS2003CPPCompiler"; + (0x6D): value = "VS2005CCompiler"; + (0x6E): value = "VS2005CPPCompiler"; + (0x7B): value = "VS2005Linker"; + (0x93): value = "VS2008Linker"; + (0x9D): value = "Linker12"; + (0x9E): value = "MASM10"; + (0xAA): value = "VS2010CCompiler"; + (0xAB): value = "VS2010CPPCompiler"; + (0xFF): value = "VS2015CVTRes"; + (0x101 | 0x102): value = "VS2015Linker"; + (0x103): value = "VS2015Assembler"; + (0x104): value = "VS2015CCompiler"; + (0x105): value = "VS2015CPPCompiler"; + } + return value + " (" + std::format(notation + "{:X}", type ^ std::mem::read_unsigned(richHeaderEndPosition+6, 2)) + ")"; }; struct Product { - u16 buildNumber [[format("unmaskBuild")]]; - u16 productID [[format("unmaskProduct")]]; - u32 objectCount [[format("unmask")]]; + u16 buildNumber [[format("unmaskBuild")]]; + u16 productID [[format("unmaskProduct")]]; + u32 objectCount [[format("unmask")]]; }; fn formatSignature(auto value) { - return "\"DanS\""; + return "\"DanS\""; }; using NullPadding = u32 [[format("unmask")]]; struct RichHeader { - char maskedSignature[4] [[format("formatSignature")]]; - NullPadding nullPadding[3]; - Product products[while($ < richHeaderEndPosition)]; - char signature[4]; - u32 mask; + char maskedSignature[4] [[format("formatSignature")]]; + NullPadding nullPadding[3]; + Product products[while($ < richHeaderEndPosition)]; + char signature[4]; + u32 mask; }; struct RichHeaderContainer { if (checkForRichHeader) RichHeader richHeader; }; From 6ec0df69e5b9f32ae3e653c9e0997c08e69046b6 Mon Sep 17 00:00:00 2001 From: gmestanley Date: Mon, 3 Nov 2025 19:26:36 -0300 Subject: [PATCH 13/17] Delete patterns/nsfe.hexpat --- patterns/nsfe.hexpat | 7 ------- 1 file changed, 7 deletions(-) delete mode 100644 patterns/nsfe.hexpat diff --git a/patterns/nsfe.hexpat b/patterns/nsfe.hexpat deleted file mode 100644 index 047f57c0..00000000 --- a/patterns/nsfe.hexpat +++ /dev/null @@ -1,7 +0,0 @@ -#pragma author gmestanley -#pragma description NSFe file format - -#include <./nsfmetadata.hexpat> - -char signature[4] @ 0x00; -Chunk chunks[while($ Date: Mon, 3 Nov 2025 19:27:02 -0300 Subject: [PATCH 14/17] Delete patterns/nsfmetadata.hexpat --- patterns/nsfmetadata.hexpat | 42 ------------------------------------- 1 file changed, 42 deletions(-) delete mode 100644 patterns/nsfmetadata.hexpat diff --git a/patterns/nsfmetadata.hexpat b/patterns/nsfmetadata.hexpat deleted file mode 100644 index 3be754b2..00000000 --- a/patterns/nsfmetadata.hexpat +++ /dev/null @@ -1,42 +0,0 @@ -import std.string; - -struct ChunkMetadata { - u32 length; - char ID[4]; -} [[inline]]; - -struct TimeChunkData { - u32 trackLengths[while($ Date: Mon, 3 Nov 2025 19:27:44 -0300 Subject: [PATCH 15/17] Added chunks from NSFe to NSF --- patterns/nsf.hexpat | 45 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 43 insertions(+), 2 deletions(-) diff --git a/patterns/nsf.hexpat b/patterns/nsf.hexpat index 1c80c32c..b80465e6 100644 --- a/patterns/nsf.hexpat +++ b/patterns/nsf.hexpat @@ -1,7 +1,48 @@ #pragma author gmestanley #pragma description NES Sound Format file -#include <./nsfmetadata.hexpat> +import std.string; + +struct ChunkMetadata { + u32 length; + char ID[4]; +} [[inline]]; + +struct TimeChunkData { + u32 trackLengths[while($ Date: Mon, 3 Nov 2025 19:28:18 -0300 Subject: [PATCH 16/17] Added NSFe --- patterns/nsfe.hexpat | 48 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 patterns/nsfe.hexpat diff --git a/patterns/nsfe.hexpat b/patterns/nsfe.hexpat new file mode 100644 index 00000000..63da15bb --- /dev/null +++ b/patterns/nsfe.hexpat @@ -0,0 +1,48 @@ +#pragma author gmestanley +#pragma description NSFe file format + +import std.string; + +struct ChunkMetadata { + u32 length; + char ID[4]; +} [[inline]]; + +struct TimeChunkData { + u32 trackLengths[while($ Date: Mon, 3 Nov 2025 19:33:13 -0300 Subject: [PATCH 17/17] Fix size of truncatedSize in ips.hexpat --- patterns/ips.hexpat | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/patterns/ips.hexpat b/patterns/ips.hexpat index dfea729d..91121ae4 100644 --- a/patterns/ips.hexpat +++ b/patterns/ips.hexpat @@ -4,25 +4,25 @@ #pragma endian big -import std.mem; +import std.string; struct Hunk { - u24 offset; - u16 length; - if (!length) { - u16 runCount; - u8 payload; - } - else { - u8 payload[length]; - } + u24 offset; + u16 length; + if (!length) { + u16 runCount; + u8 payload; + } + else { + u8 payload[length]; + } }; struct IPS { - char signature[5]; - Hunk hunks[while($ < std::mem::size() - (3 + 3 * (std::mem::read_string(std::mem::size()-3, 3) != "EOF")))]; - char eof[3]; - u24 truncatedSize[3+(std::mem::read_string(std::mem::size()-3, 3) != "EOF")]; + char signature[5]; + Hunk hunks[while($ < std::mem::size() - (3 + 3 * (std::mem::read_string(std::mem::size()-3, 3) != "EOF")))]; + char eof[3]; + u24 truncatedSize[std::mem::read_string(std::mem::size()-3, 3) != "EOF"]; }; IPS ips @ 0x00;