From 559faebec3ced702dd3d043971d70fe7f5a7d608 Mon Sep 17 00:00:00 2001 From: Nik Date: Sat, 28 Dec 2024 19:57:48 +0100 Subject: [PATCH] patterns: Added simple SQLite3 database pattern --- README.md | 1 + patterns/sqlite3.hexpat | 95 +++++++++++++++++++++ tests/patterns/test_data/sqlite3.hexpat.db | Bin 0 -> 16384 bytes 3 files changed, 96 insertions(+) create mode 100644 patterns/sqlite3.hexpat create mode 100644 tests/patterns/test_data/sqlite3.hexpat.db diff --git a/README.md b/README.md index 1367144..0a87ccd 100644 --- a/README.md +++ b/README.md @@ -140,6 +140,7 @@ Everything will immediately show up in ImHex's Content Store and gets bundled wi | SPIRV | | [`patterns/spirv.hexpat`](patterns/spirv.hexpat) | SPIR-V header and instructions | | STL | `model/stl` | [`patterns/stl.hexpat`](patterns/stl.hexpat) | STL 3D Model format | | StuffItV5 | `application/x-stuffit` | [`patterns/sit5.hexpat`](patterns/sit5.hexpat) | StuffIt V5 archive | +| SQLite3 | `application/vnd.sqlite3` | [`patterns/sqlite3.hexpat`](patterns/sqlite3.hexpat) | SQLite3 Database | | SWF | |[`patterns/swf.hexpat`](patterns/swf.hexpat) | Shockwave Flash file format | | TAR | `application/x-tar` | [`patterns/tar.hexpat`](patterns/tar.hexpat) | Tar file format | | TES | | [`patterns/wintec_tes.hexpat`](patterns/wintec_tes.hexpat) | Wintec TES GPS log | diff --git a/patterns/sqlite3.hexpat b/patterns/sqlite3.hexpat new file mode 100644 index 0000000..70f5e73 --- /dev/null +++ b/patterns/sqlite3.hexpat @@ -0,0 +1,95 @@ +#pragma description SQLite 3 database +#pragma author WerWolv +#pragma MIME application/vnd.sqlite3 + +import type.magic; + +enum FileFormatVersion : u8 { + Legacy = 1, + WAL = 2 +}; + +enum TextEncoding : u32 { + UTF8 = 1, + UTF16LE = 2, + UTF16BE = 3 +}; + +struct SQLiteVersion { + u32 rawValue; + + u8 major = (rawValue / 1000000) % 1000 [[export]]; + u8 minor = (rawValue / 1000) % 1000 [[export]]; + u8 patch = (rawValue / 1) % 1000 [[export]]; +} [[sealed, format("format_sqlite_version")]]; + +fn format_sqlite_version(ref auto version) { + return std::format("v{}.{}.{} [{}]", version.major, version.minor, version.patch, version.rawValue); +}; + +u16 globalPageSize = 0; + +enum PageType : u8 { + InteriorIndexBTreePage = 0x02, + InteriorTableBTreePage = 0x05, + LeafIndexBTreePage = 0x0A, + LeafTableBTreePage = 0x0D +}; + +struct Page { + PageType pageType; + u16 freeBlockStart; + u16 numCells; + u16 cellContentAreaStart; + u8 fragmentedFreeBytesCount; + + if (pageType == PageType::InteriorIndexBTreePage || pageType == PageType::InteriorTableBTreePage) + u32 rightMostPointer; +} [[fixed_size(le u16(globalPageSize))]]; + +struct DatabaseHeader { + type::Magic<"SQLite format 3\x00"> magic; + u16 pageSizeValue; + u16 pageSize = pageSizeValue == 1 ? 65536 : le u16(pageSizeValue) [[export]]; + globalPageSize = pageSize; + + FileFormatVersion readVersion, writeVersion; + padding[1]; + u8 maxEmbeddedPayloadFraction; + if (maxEmbeddedPayloadFraction != 64) + std::warning("Unexpected Max Embedded Payload Fraction"); + + u8 minEmbeddedPayloadFraction; + if (minEmbeddedPayloadFraction != 32) + std::warning("Unexpected Min Embedded Payload Fraction"); + + u8 leafPayloadFraction; + if (leafPayloadFraction != 32) + std::warning("Unexpected Leaf Payload Fraction"); + + u32 fileChangeCounter; + u32 totalPageCount; + + u32 freelistTrunkPageNumber; + u32 totalFreeListPageCount; + + u32 schemaCookie; + u32 schemaFormatNumber; + u32 defaultPageCacheSize; + u32 largestRootBTreePage; + TextEncoding textEncoding; + u32 userVersion; + u32 incrementalVacuumMode; + u32 applicationId; + padding[20]; + u32 versionValidForNumber; + SQLiteVersion sqliteVersionNumber; +}; + +struct SQLite3 { + be DatabaseHeader header; + + be Page pages[le u16(header.totalPageCount) - 1] @ le u16(header.pageSize); +}; + +SQLite3 sqlite3 @ 0x00; \ No newline at end of file diff --git a/tests/patterns/test_data/sqlite3.hexpat.db b/tests/patterns/test_data/sqlite3.hexpat.db new file mode 100644 index 0000000000000000000000000000000000000000..42e078d9a9d33ac51df24742a574a5f769ac5b1f GIT binary patch literal 16384 zcmeI3-Etc>6vsD>L#V+(DWTZ;=&51A&e)C?2p)Qu`gl= zv2^Tw^!Mmj(fi}iv-vpmsx<*kKoigeGyzRO6VL=S0Zl*?&;&FAO+XXS1T+CnKoige zGyzTEStkI|kP*!nt+G|Oh9%srRd-;J%lX8`#7yB0wD5Ot7crYNEGHVlw(8LI_-Y~E z_rzfw_O`8>rS7a1;*$C@zI|!Nh@Q-rDz;Ut4@)Rj>eWdn3FRR*=#_-Ko8?{0hD4k` zBug~KwUBW!Z{I1~$F3v~ zVKgRi))1JUx^XdNECz&SN)GAJE$%fS4L!G$f(Jb;I;;(z09y*?b`lNZ)Ag%K*e^Cr z&YFh@AiVy?SJA^fdN4iii8u4Pe2%o1FW@Y9@aC@IT`7D1wUrhBGmfvhdM;-!%``n{ zrCc&CgtqWX$heSSU8@961M_BHTVcXMWtTeCUwS!YT-vZPZ$?c)3BD)W3mP~$F2Fs6 z;?~T!tS!ROk0@V69>f?XNUhbjax`R|EGDH$5B|lZ6g-gZR~O z$XG2sZdUD4*9V8V$3R-RNL)MN&_-&3pnmdv$atrK0MyIIxy;p#%$lN6b<6lb05RPn zN5pOl){|d{pGR8XPTO5iNHD8K%U>Si9V9Xf@1rWzCOx%1RZ}GFx1VT;k2G*_a*w1p zGH*V`JaA=VIr+Fff1>@QOa@b|){0gQw(hC)D-1;}!#Vx>pu zUBs;-il1OD%qRQIRX>KnR5JSdd(VZ8%gv9NKovkGGnQe$-_I!R&=zwCGGy*4X`&{s z%%G-n!_A@8T2VW%LtRj}upg=i-zG2boy<-;JqoxK1CJjF+AieRbNP++Y&w7ILv}>r z*bCsTTs8~R0|Ff-Ww?9W2I98B(SRiT-}H=-8jkIP~o5>y*=u zAP!)%-bGbHpUEz`wC@9HcmZbZyBLK2^JeAfUq5~K4Q!KM?-(ky5BDe$_8(xDq(v=4Kq$vTN_cZr%JB!oEsT literal 0 HcmV?d00001