diff --git a/README.md b/README.md index 502946b..a1c0db4 100644 --- a/README.md +++ b/README.md @@ -179,6 +179,7 @@ Everything will immediately show up in ImHex's Content Store and gets bundled wi | XGT | | [`patterns/xgt.hexpat`](patterns/xgstexture.hexpat) | Exient XGS Engine Texture | | Xilinx BIT | | [`patterns/xilinx_bit.hexpat`](patterns/xilinx_bit.hexpat) | Xilinx FPGA Bitstreams | | Xilinx Bootgen | `application/x-xilinx-boot-zynqmp` | [`patterns/xilinx_bootgen.hexpat`](patterns/xilinx_bootgen.hexpat) | Xilinx ZynqMP Boot Images | +| ZIM | | [`patterns/zim.hexpat`](patterns/zim.hexpat) | [ZIM](https://openzim.org) file format | | ZIP | `application/zip` | [`patterns/zip.hexpat`](patterns/zip.hexpat) | End of Central Directory Header, Central Directory File Headers | | ZLIB | `application/zlib` | [`patterns/zlib.hexpat`](patterns/zlib.hexpat) | ZLIB compressed data format | | ZSTD | `application/zstd` | [`patterns/zstd.hexpat`](patterns/zstd.hexpat) | Zstandard compressed data format | diff --git a/patterns/zim.hexpat b/patterns/zim.hexpat new file mode 100644 index 0000000..4eeb086 --- /dev/null +++ b/patterns/zim.hexpat @@ -0,0 +1,79 @@ +#pragma endian little +#pragma description ZIM file format +#pragma magic [ 5A 49 4D 04 ] @ 0x00 + +u32 maxEntries in; + +import std.string; +import std.mem; +import std.math; +import std.core; + +struct Header { + char signature[4]; + u16 majorVersion; + u16 minorVersion; + u128 uid; + u32 entryCount, clusterCount; + u64 pathPtrPos, titlePtrPos, clusterPtrPos, mimeListPos; + u32 mainPage; + u32 layoutPage; + u64 checksumPos; +}; + + +Header header @ 0x00; +std::string::NullString mimeTypes[while(std::mem::read_unsigned($, 1) != 0x00)] @ header.mimeListPos; + +fn mimename(u16 index) { + if(index == 0xFFFF) { + return "redirect"; + } else { + return mimeTypes[index]; + } +}; + +enum CompressionType : u8 { + None = 0x01, + LZMA2 = 0x04, + zstd = 0x05 +}; + +bitfield ClusterInfo { + CompressionType compression: 4; + offsetSize: 1; +} [[bitfield_order(std::core::BitfieldOrder::LeastToMostSignificant, 8)]]; + +struct Cluster { + ClusterInfo info; +} [[inline]]; + +struct ClusterPointer { + Cluster *cluster: u64; +} [[inline]]; + +struct Entry { + u16 mimetype [[format("mimename")]]; + u8 parameterlen [[hidden]]; + char _namespace [[name("namespace")]]; + u32 revision; + if (mimetype == 0xFFFF) { + u32 redirectIndex; + } else { + u32 clusterNumber; + ClusterPointer cluster @ (header.clusterPtrPos + clusterNumber * 8); + u32 blobNumber; + } + + std::string::NullString path; + std::string::NullString title; + padding[parameterlen]; +} [[inline]]; + +struct EntryPointer { + Entry *entry : u64; +} [[inline]]; + +EntryPointer pathPointerList[std::math::min(header.entryCount, maxEntries == 0 ? 1500 : maxEntries)] @ header.pathPtrPos; +u32 titlePointerList[header.entryCount] @ header.titlePtrPos; + diff --git a/tests/patterns/test_data/zim.hexpat.zim b/tests/patterns/test_data/zim.hexpat.zim new file mode 100644 index 0000000..99ea098 Binary files /dev/null and b/tests/patterns/test_data/zim.hexpat.zim differ