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 0000000..0eac3e2 Binary files /dev/null and b/tests/patterns/test_data/bzip3.hexpat.bz3 differ