From 1e69cd7fb28932e39f3d70ec66b0a1c59d58a306 Mon Sep 17 00:00:00 2001 From: "Sewer." Date: Thu, 12 Dec 2024 20:56:13 +0000 Subject: [PATCH] patterns: Added BZip3 File Header Pattern (#329) * Added: BZip3 Compression * Fixed: Bound the SmallBlock data by parent's size * Improved: Now uses the name 'Chunk' for block wrappers, such that the name 'block' matches with what the BZ3 API does * Improved: Import rather than Include std::mem * Added: Missing 'description' field in pragma --- README.md | 1 + patterns/bzip3.hexpat | 64 ++++++++++++++++++++++ tests/patterns/test_data/bzip3.hexpat.bz3 | Bin 0 -> 845 bytes 3 files changed, 65 insertions(+) create mode 100644 patterns/bzip3.hexpat create mode 100644 tests/patterns/test_data/bzip3.hexpat.bz3 diff --git a/README.md b/README.md index e9a378b..aa5a783 100644 --- a/README.md +++ b/README.md @@ -42,6 +42,7 @@ Everything will immediately show up in ImHex's Content Store and gets bundled wi | BSON | `application/bson` | [`patterns/bson.hexpat`](patterns/bson.hexpat) | BSON (Binary JSON) format | | bplist | | [`patterns/bplist.hexpat`](patterns/bplist.hexpat) | Apple's binary property list format (bplist) | | BSP | | [`patterns/bsp_goldsrc.hexpat`](patterns/bsp_goldsrc.hexpat) | GoldSrc engine maps format (used in Half-Life 1) | +| BZIP3 | | [`patterns/bzip3.hexpat`](patterns/bzip3.hexpat) | GoldSrc engine maps format (used in Half-Life 1) | | CCHVA | | [`patterns/cchva.hexpat`](patterns/cchva.hexpat) | Command and Conquer Voxel Animation | | CCVXL | | [`patterns/ccvxl.hexpat`](patterns/ccvxl.hexpat) | Command and Conquer Voxel Model | | CCPAL | | [`patterns/ccpal.hexpat`](patterns/ccpal.hexpat) | Command and Conquer Voxel Palette | diff --git a/patterns/bzip3.hexpat b/patterns/bzip3.hexpat new file mode 100644 index 0000000..fe3dd71 --- /dev/null +++ b/patterns/bzip3.hexpat @@ -0,0 +1,64 @@ +#pragma author Sewer56 +#pragma description Parses BZip3 compression (file format) by Kamila Szewczyk +#pragma MIME application/x-bzip3 +#pragma endian little +#pragma magic [42 5A 33 76 31] @ 0x00 +import std.mem; + +// Helper function for bit counting +fn popcount(u8 b) { + u32 count = 0; + while (b != 0) { + count = count + (b & 1); + b = b >> 1; + } + return count; +}; + +// Frame header structure +struct FrameHeader { + char magic[5]; // "BZ3v1" + u32 blockSize; // Maximum block size +}; + +// Small block header (for blocks < 64 bytes) +struct SmallBlock { + u32 crc32; // CRC32 checksum + u32 literal; // Always 0xFFFFFFFF for small blocks + u8 data[parent.compressedSize - 8]; // Uncompressed data +}; + +// Regular block (blocks > 64 bytes) +struct Block { + u32 crc32; // CRC32 checksum of uncompressed data + u32 bwtIndex; // Burrows-Wheeler transform index + u8 model; // Compression model flags + + if ((model & 0x02) != 0) + u32 lzpSize; // Size after LZP compression + if ((model & 0x04) != 0) + u32 rleSize; // Size after RLE compression + + u8 data[parent.compressedSize - (popcount(model) * 4 + 9)]; +}; + +// Main block structure +struct Chunk { + u32 compressedSize; // Size of compressed block + u32 origSize; // Original uncompressed size + + if (compressedSize < 64) { + SmallBlock block; + } else { + Block block; + } +}; + +// Main parsing structure +struct BZip3File { + FrameHeader header; + // Read blocks until end of file + Chunk chunks[while(!std::mem::eof())]; +}; + +BZip3File file @ 0x0; \ No newline at end of file diff --git a/tests/patterns/test_data/bzip3.hexpat.bz3 b/tests/patterns/test_data/bzip3.hexpat.bz3 new file mode 100644 index 0000000000000000000000000000000000000000..0eac3e29eda3be73f2d107970089551cb5a23a63 GIT binary patch literal 845 zcmV-T1G4-=S~GSr00002JOcm#k_G?(@9$2q6aWAK1gZuA0K~8aEx-T&|NrBOU!b>v zn5n6HJ$|qc*_sr}V~&`4<_@ZV65{;#+G2oKSwjvp#cF3db_)EsKdMt>T-~Pkzo@>+j9k*B@_ndaDY{dX&X~k`r$uEjm7Sp zg&TCEkc22082S+VlXpDte9x#rN2&zZKJykQ4Ynwu{ML}Tk<=(v4~gceDySJk)e(pF zsU!35mNA5sv03shN$w8HtbjlCkj@-e2sv}cefZ);>bS!vif62t3e}8NrfC0Tx`@j# z(!hcT*Y!YVOCKUX51litc02*(euIy9VQNe43@(5r!;X8Z%A}05l5d zQ6fQ%;f+DI5mKC$%X@04TS_nahiNq^mtJ~HvtXQQp11V?>FTg_NCmC;gU}!Q1^1^iw8>-h%V{kv% zC&Qu8JPS&1k0x7zf>$Sd3Aw#qqQ)^->GE5qdEmOh?Y&hV@Fe=HQlxzkJ;0#hRNKoI zy-e4P0%=A7P`Bh!8CzZ{T=?S|D`IS81soP=0TKEzMU6{3Y+hZ_F^eRwW1hI0Elw&z--m@|b1n)Z5dw+8c}9Hp!g z9q(ZhY-7e@&C^$}n?9uC{I(P>&L0`B4{*7JM*)x7fjlD^Ep{r$8?GIb`IEh=HNSVv zYM0k%5`)330fI*8?oJ@|E1;{$Lijt}(@~FJ%nEBXiGmyxAI9YY$n*3mYF;UYWeX$LJlb@Ha08x9>a|0Ry;D$uEZYjjY#u%KYMv)FZk X0ln?%d=>rJ8Js+uq