From 7fd79ec9fd7a8a326939b14f3c757eb1b273a02d Mon Sep 17 00:00:00 2001 From: Lexi Mayfield Date: Wed, 20 Aug 2025 13:32:11 -0400 Subject: [PATCH] patterns: Added AppleSingle, AppleDouble, CHD, TARC patterns (#431) * Commit patterns I've collected - AppleSingle/AppleDouble pattern, used for macOS resource forks. - MAME CHD file format, currently only supports v5. - KEX Engine proprietary TARC format, used by various Nightdive games. * Add to README --- README.md | 4 ++ patterns/apple_single_double.hexpat | 50 +++++++++++++ patterns/chd.hexpat | 105 ++++++++++++++++++++++++++++ patterns/tarc.hexpat | 50 +++++++++++++ 4 files changed, 209 insertions(+) create mode 100644 patterns/apple_single_double.hexpat create mode 100644 patterns/chd.hexpat create mode 100644 patterns/tarc.hexpat diff --git a/README.md b/README.md index 6f0cc41..c5459fc 100644 --- a/README.md +++ b/README.md @@ -29,6 +29,8 @@ Everything will immediately show up in ImHex's Content Store and gets bundled wi | ADTS | `audio/x-hx-aac-adts` | [`patterns/adts.hexpat`](patterns/adts.hexpat) | ADTS/AAC audio files | | AFE2 | | [`patterns/afe2.hexpat`](patterns/afe2.hexpat) | Nintendo Switch Atmosphère CFW Fatal Error log | | ANI | `application/x-navi-animation` | [`patterns/ani.hexpat`](patterns/ani.hexpat) | Windows Animated Cursor file | +| AppleSingle | `application/applefile` | [`patterns/apple_single_double.hexpat`](patterns/apple_single_double.hexpat) | AppleSingle Dual Fork file | +| AppleDouble | `multipart/appledouble` | [`patterns/apple_single_double.hexpat`](patterns/apple_single_double.hexpat) | AppleDouble Resource Fork/Finder Metadata file | | AR | `application/x-archive` | [`patterns/ar.hexpat`](patterns/ar.hexpat) | Static library archive files | | ARC | | [`patterns/arc.hexpat`](patterns/arc.hexpat) | Minecraft Legacy Console Edition ARC files | | ARIA2 | | [`patterns/aria2.hexpat`](patterns/aria2.hexpat) | ARIA2 Download Manager Control files | @@ -50,6 +52,7 @@ Everything will immediately show up in ImHex's Content Store and gets bundled wi | CCVXL | | [`patterns/ccvxl.hexpat`](patterns/ccvxl.hexpat) | Command and Conquer Voxel Model | | CCPAL | | [`patterns/ccpal.hexpat`](patterns/ccpal.hexpat) | Command and Conquer Voxel Palette | | CDA | | [`patterns/cda.hexpat`](patterns/cda.hexpat) | Compact Disc Audio track | +| CHD | | [`patterns/chd.hexpat`](patterns/chd.hexpat) | MAME Compressed Hunks of Data file | | CHM | `application/vnd.ms-htmlhelp` | [`patterns/chm.hexpat`](patterns/chm.hexpat) | Windows HtmlHelp Data (ITSF / CHM) | | COFF | `application/x-coff` | [`patterns/coff.hexpat`](patterns/coff.hexpat) | Common Object File Format (COFF) executable | | CPIO | `application/x-cpio` | [`patterns/cpio.hexpat`](patterns/cpio.hexpat) | Old Binary CPIO Format | @@ -168,6 +171,7 @@ Everything will immediately show up in ImHex's Content Store and gets bundled wi | SWF | `application/x-shockwave-flash` |[`patterns/swf.hexpat`](patterns/swf.hexpat) | Shockwave Flash file format | | TA | | [`patterns/optee_ta.hexpat`](patterns/optee_ta.hexpat) | OPTEE Trusted Application Executable | | TAR | `application/x-tar` | [`patterns/tar.hexpat`](patterns/tar.hexpat) | Tar file format | +| TARC | | [`patterns/tarc.hexpat`](patterns/tarc.hexpat) | KEX Engine TARC file format | | TES | | [`patterns/wintec_tes.hexpat`](patterns/wintec_tes.hexpat) | Wintec TES GPS log | | Thumbcache | | [`patterns/thumbcache.hexpat`](patterns/thumbcache.hexpat) | Windows thumbcache_*.db | | TIFF | `image/tiff` | [`patterns/tiff.hexpat`](patterns/tiff.hexpat) | Tag Image File Format | diff --git a/patterns/apple_single_double.hexpat b/patterns/apple_single_double.hexpat new file mode 100644 index 0000000..e1b38b4 --- /dev/null +++ b/patterns/apple_single_double.hexpat @@ -0,0 +1,50 @@ +#pragma author Lexi Mayfield +#pragma description AppleSingle/AppleDouble file format +#pragma endian big +#pragma magic [00 05 16 0?] @ 0x00 + +import type.magic; + +enum EntryID : u32 { + DataFork = 1, + ResourceFork = 2, + RealName = 3, + Comment = 4, + IconBW = 5, + IconColor = 6, + FileDatesInfo = 8, + FinderInfo = 9, + MacFileInfo = 10, + ProDOSFileInfo = 11, + MSDOSFileInfo = 12, + ShortName = 13, + AFPFileInfo = 14, + DirectoryID = 15, +}; + +struct Entry { + EntryID entryID; + u32 offset; + u32 length; + u8 data[length] @ offset [[sealed]]; +}; + +enum FileType : u32 { + AppleSingle = 0x00051600, + AppleDouble = 0x00051607, +}; + +enum Version : u32 { + V1 = 0x00010000, + V2 = 0x00020000, +}; + +struct AppleSingleDouble { + FileType fileType; + Version version; + char homeFileSystem[16]; + u16 numEntries; + Entry entryDescs[numEntries]; +}; + +AppleSingleDouble appleSingleDouble @ 0x00; \ No newline at end of file diff --git a/patterns/chd.hexpat b/patterns/chd.hexpat new file mode 100644 index 0000000..d10ced8 --- /dev/null +++ b/patterns/chd.hexpat @@ -0,0 +1,105 @@ +#pragma author Lexi Mayfield +#pragma description MAME Compressed Hunks of Data +#pragma endian big + +fn CHD_MAKE_TAG(char a, char b, char c, char d) { + return (u32(u8(a)) << 24) | + u32(u8((b)) << 16) | + u32(u8((c)) << 8) | + u32(u8(d)); +}; + +enum CHDv5_CODEC : u32 { + NONE = 0, + ZLIB = CHD_MAKE_TAG('z','l','i','b'), + ZSTD = CHD_MAKE_TAG('z','s','t','d'), + LZMA = CHD_MAKE_TAG('l','z','m','a'), + HUFFMAN = CHD_MAKE_TAG('h','u','f','f'), + FLAC = CHD_MAKE_TAG('f','l','a','c'), + CD_ZLIB = CHD_MAKE_TAG('c','d','z','l'), + CD_ZSTD = CHD_MAKE_TAG('c','d','z','s'), + CD_LZMA = CHD_MAKE_TAG('c','d','l','z'), + CD_FLAC = CHD_MAKE_TAG('c','d','f','l'), + AVHUFF = CHD_MAKE_TAG('a','v','h','u'), +}; + +enum CHDv5_METADATA_TAG : u32 { + CHDMETATAG_WILDCARD = 0, + HARD_DISK_METADATA_TAG = CHD_MAKE_TAG('G','D','D','D'), + HARD_DISK_IDENT_METADATA_TAG = CHD_MAKE_TAG('I','D','N','T'), + HARD_DISK_KEY_METADATA_TAG = CHD_MAKE_TAG('K','E','Y',' '), + PCMCIA_CIS_METADATA_TAG = CHD_MAKE_TAG('C','I','S',' '), + CDROM_OLD_METADATA_TAG = CHD_MAKE_TAG('C','H','C','D'), + CDROM_TRACK_METADATA_TAG = CHD_MAKE_TAG('C','H','T','R'), + CDROM_TRACK_METADATA2_TAG = CHD_MAKE_TAG('C','H','T','2'), + GDROM_OLD_METADATA_TAG = CHD_MAKE_TAG('C','H','G','T'), + GDROM_TRACK_METADATA_TAG = CHD_MAKE_TAG('C','H','G','D'), + DVD_METADATA_TAG = CHD_MAKE_TAG('D','V','D',' '), + AV_METADATA_TAG = CHD_MAKE_TAG('A','V','A','V'), + AV_LD_METADATA_TAG = CHD_MAKE_TAG('A','V','L','D'), +}; + +struct CHDv5UncompressedMap { + u32 offset; +}; + +struct CHDv5CompressedMapEntry { + u8 compression; + u24 complength; + u48 offset; + u16 crc; +}; + +struct CHDv5CompressedMap { + u32 length; + u48 datastart; + u16 crc; + u8 lengthbits; + u8 hunkbits; + u8 parentunitbits; + u8 reserved; +}; + +struct CHDv5MetadataEntry { + CHDv5_METADATA_TAG metatag; + u8 flags; + u24 length; + u64 next; + char entry[length]; + + if (next != 0) { + CHDv5MetadataEntry nextMeta @ next; + } +}; + +struct CHDv5 { + CHDv5_CODEC compressors[4]; + u64 logicalbytes; + u64 mapoffset; + u64 metaoffset; + u32 hunkbytes; + u32 unitbytes; + u8 rawsha1[20]; + u8 sha1[20]; + u8 parentsha1[20]; + + if (compressors[0] == CHDv5_CODEC::NONE) { + CHDv5UncompressedMap map @ mapoffset; + } else { + CHDv5CompressedMap map @ mapoffset; + } + + CHDv5MetadataEntry meta @ metaoffset; +}; + +struct CHD { + char tag[8]; + u32 length; + u32 version; + + if (version == 5) { + CHDv5 chd; + } +}; + +CHD chd @ 0x00; \ No newline at end of file diff --git a/patterns/tarc.hexpat b/patterns/tarc.hexpat new file mode 100644 index 0000000..93ce6ad --- /dev/null +++ b/patterns/tarc.hexpat @@ -0,0 +1,50 @@ +#pragma author Lexi Mayfield +#pragma description KEX Engine TARC format +#pragma magic [0x54 0x41 0x52 0x43] @ 0x00 + +enum PixelFormat : u16 { + DXT1 = 14, + DXT5 = 16, + BC7 = 33, +}; + +struct TARCEntry1 { + char fileName[64]; + u64 offset; + u32 size; + u16 width; + u16 height; + u16 numMipMaps; + PixelFormat pixelFormat; +}; + +struct TARCEntry2 { + char fileName[64]; + u64 offset; + u32 size; + u16 x; + u16 y; + u16 width; + u16 height; + u16 numMipMaps; + PixelFormat pixelFormat; + u16 origWidth; + u16 origHeight; + s16 offsetX; + s16 offsetY; +}; + +struct TARC { + char id[4]; + u32 version; + u32 numEntries; + u64 pixelDataOffset; + + if (version == 1) { + TARCEntry1 entries[numEntries]; + } else if (version == 2) { + TARCEntry2 entries[numEntries]; + } +}; + +TARC tarc @ 0x00; \ No newline at end of file