Compare commits

...

151 Commits

Author SHA1 Message Date
Stéphane Bisinger
a534e2a23b Add missing #pragma once to includes (#494) 2026-02-07 12:58:31 -07:00
MrClock
525f3ad4d6 patterns/magic: Add more Arma 3 files (#479)
* patterns/texheaders: Added pattern for Arma 3 texHeaders.bin

* magic/arma3: Added texHeaders.bin magic

* patterns/texheaders: Added test file

* patterns/paa: Small improvements

Added extra data description, and better indication of internally compressed data mipmap data.

* patterns/a3: Moved Arma 3 patterns into common folder

* patterns/a3: Added pattern for MLOD P3D

* patterns/a3: Added pattern for RAP

* magic/arma3: Added P3D and RAP to magic file

* patterns/a3: Added test files for P3D and RAP

* patterns/a3: Small correction to type names in TexHeaders format
2026-02-04 07:35:57 +01:00
gmestanley
27480b1da9 encodings: Removing control characters from TBLs (#481)
* Removing control characters from TBLs

* Delete patterns/gbk.tbl

* Delete patterns/jis_x_0211.tbl

* Delete patterns/euc_jp.tbl

* Add files via upload
2026-01-20 08:05:01 +01:00
MrClock
6a2a963a5a patterns: Add pattern and magic for Arma 3 RTM (#478)
* patterns/rtm: Added pattern for Arma 3 plain RTM

* magic/arma3: Added plain RTM to magic file

* patterns/rtm: Added test file

* patterns/rtm: Changed function parameters to refs

* patterns/rtm: Replaced RTM test file

* patterns/rtm: Added extra description to RTM pattern

* pattern/bmtr: Added BMTR pattern, magic and test file
2026-01-13 07:10:43 +01:00
MrClock
cee3a5de77 patterns: Add pattern and magic for Arma 3 PAA (#475)
* patterns/paa: Added pattern for Arma 3 PAA

* patterns/paa: Small correction

* magic/arma3: Added magic file for Arma 3 formats

Only the PAA format for now
2026-01-11 19:10:23 +01:00
gmestanley
fb84bbb5d1 patterns: More accurate variable declarations on nes.hexpat, add n64, gen, and gbx.hexpat (#477)
* Add n64, gen, and gbx.hexpat

* Add n64, gbx, and gen.hexpat to README.md

* Remove leftover string import from n64.hexpat

* More accurate variable declarations on nes.hexpat

* Add source to gbx.hexpat

* Add accidentally missing curly brace in nes.hexpat
2026-01-11 18:59:37 +01:00
Dexrn ZacAttack
097ab49cae patterns: Add SPC pattern (#476)
* feat: SPC700 hexpat

* chore: add pattern to readme
2026-01-11 09:53:20 +01:00
Illia Trukhanov
5a04a4256b pattern: Add Lua 5.0 pattern (#466)
* patterns: Add Lua 5.0 pattern

Based on Lua 5.1 pattern.

* tests: Add Lua 5.0 test file

function fac(n)
    if n < 2 then
        return 1
    end
    return n * fac(n - 1)
end

./luac - < test.lua
Lua compiled with make ARFLAGS=rv CC="gcc -m32"
at commit 762c7370376dbd13cd8aeb4d8c8da0bb153269c3
luac compiled with make LUA=../lua CC="gcc -m32"
at commit d002063c4605d3ea12d419b34a23c562f9add318

---------

Co-authored-by: Nik <werwolv98@gmail.com>
2026-01-03 20:31:40 +01:00
gmestanley
8a9bd577ad patterns: Fix quirks of nes.hexpat with famiclones and miscellaneous fixes (#467)
* Add credit to ne.hexpat

* Add many changes to nes.hexpat

* Fixing dependance on variables declared in if statement

* Added mappers and inline to NES 2.0 header, removed needless parenthesises

* Add files via upload

* Add files via upload

* Create nsf.hexpat

* Used full name of the SNES on description

* Add SNES, NSF & NSFe, new description for NES

* Removing erroneous condition in ips.hexpat's truncatedSize

* Removing unnecessary std.string import in ips.hexpat

* Added both locations for sections in PE, clearer variable names, reorganized DOS stub

* Delete patterns/nsfe.hexpat

* Delete patterns/nsfmetadata.hexpat

* Added chunks from NSFe to NSF

* Added NSFe

* Fix size of truncatedSize in ips.hexpat

* More mappers, deprecated tag, and constants to nes

* Fixed official header's constants

* Various corrections

* Fix on declaration of sections, reserved words made into padding

* Added hacked algorithm for longer PRG ROM size, fixed iNES check

* For nes.hexpat, fixed mapper 51 still having its submapper's name

* Fix bug that makes size negative on standard roms

---------

Co-authored-by: Nik <werwolv98@gmail.com>
2026-01-03 20:25:48 +01:00
Jarkko Pöyry
190f9d891b patterns: Add ASCII CPIO patterns. (#473) 2026-01-03 20:24:31 +01:00
Jack Manning
2d92bfca13 pattern: Add Chromium pak file (#474)
* Add Chromium pak file pattern

* Show aliases & fix brotli check bug

* Add decompressed size

* Add notes

* Add PakEncoding enum
2026-01-03 20:23:53 +01:00
elyashiv
0e4040fae1 patterns/elf: Added binding and symbol info (#471) 2025-12-30 11:24:19 +01:00
Nik
57c3dd44b8 tests: Fix test failures after library update 2025-12-23 23:26:20 +01:00
Nik
4646e4b965 patterns/xilinx_bootgen: Remove unnecessary parent access after recent pl upgrade 2025-12-06 16:24:17 +01:00
WerWolv
9143996589 patterns/ac_unity: Rename folder to be clonable on Windows 2025-12-06 09:34:44 +01:00
Sean Apeler
7c3dcc1fcc patterns: Add pattern for Vector BLF Frame Logging Format (#409)
* Add Vector Binary Logging Format pattern

* Combine object header extensions into single type

---------

Co-authored-by: Nik <werwolv98@gmail.com>
2025-12-05 22:15:57 +01:00
ellie 🌸
ea8b381ac5 patterns: Add kindle firmware update pattern (#454)
* add kindle update package

* add kindle update pattern to readme

* add header of kindle update as test

* add missing kindle cs2 devices

---------

Co-authored-by: Nik <werwolv98@gmail.com>
2025-12-05 22:15:40 +01:00
Antonio Vazquez
998655f74a patterns/PcapNG: Rewrite hexpat for bugfixing (#462)
PcapNG: Rewrite hexpat.

Co-authored-by: Nik <werwolv98@gmail.com>
2025-12-05 22:15:28 +01:00
haruse23
681b208aab pattern: Add Assassin's Creed: Unity's Forge files and Data files (Compressed and Decompressed) (#448)
* Add Capcom's Devil May Cry 3 HD .mod hexpat

Hex Pattern file for Capcom's Devil May Cry 3 HD Collection's .mod (3D Models) files

* Update DMC3 HD Mod.hexpat

* Update DMC3 HD Mod.hexpat

* Update DMC3 HD Mod.hexpat

* Add files via upload

* Update README.md

* Rename DMC3 HD Mod.hexpat to dmc3_hd_mod.hexpat

* Delete patterns/dmc3_hd_mod.hexpat

* Delete tests/patterns/test_data/dmc3_hd_mod.hexpat.mod

* Add files via upload

* Update dmc3_hd_mod.hexpat

* Add files via upload

* Update README.md

* Update README.md

* Update README.md

* Add files via upload

* Update ACU_FORGE.hexpat

* Update README.md

* Update and rename ACU_DATA_Compressed.hexpat to acu_data_compressed.hexpat

* Update and rename ACU_FORGE.hexpat to acu_forge.hexpat

* Update README.md

* Update acu_data_compressed.hexpat

* Update acu_data_compressed.hexpat

* Add files via upload

* Update and rename ACU_DATA_Decompressed.hexpat to acu_data_decompressed.hexpat

* Update README.md

* Update acu_data_compressed.hexpat

* Update README.md

* Delete patterns/acu_data_compressed.hexpat

* Delete patterns/acu_data_decompressed.hexpat

* Delete patterns/acu_forge.hexpat

* Create acu_forge.hexpat

* Add files via upload

* Update and rename ACU_DATA_Compressed.hexpat to acu_data_compressed.hexpat

* Update and rename ACU_DATA_Decompressed.hexpat to acu_data_decompressed.hexpat

* Update README.md

* Delete patterns/dmc3_hd_mod.hexpat

* Create dmc3_hd_mod.hexpat

* Update README.md

* Update dmc3_hd_mod.hexpat

* Update README.md

---------

Co-authored-by: Nik <werwolv98@gmail.com>
2025-12-05 22:02:07 +01:00
furidosu
64d86cbdd1 pattern: Add parquet.hexpat for Apache Parquet data file (#450)
* Add parquet.hexpat for Apache Parquet data file

> Apache Parquet is an open source, column-oriented data file format designed for efficient data storage and retrieval.
> -- https://parquet.apache.org

* Add parquet.hexpat test file

* Fix parquet.hexpat boolean parsing

* Fix parquet.hexpat ColumnChunkPlacer not placing last chunk

* Fix parquet.hexpat using VarInt = LEB128

---------

Co-authored-by: Nik <werwolv98@gmail.com>
2025-12-05 22:01:54 +01:00
adiee5
285a2fc7d1 pattern: Atari 8-bit binary format (XEX) (#453)
* add atari XEX format

* Update README.md

---------

Co-authored-by: Nik <werwolv98@gmail.com>
2025-12-05 22:01:41 +01:00
tympanicblock61
2a9676238f pattern: Add lua 4.0 pattern (#465)
* add lua 4.0 pattern

* fix offset the top level function is at

* Update README.md

---------

Co-authored-by: Nik <werwolv98@gmail.com>
2025-12-05 21:54:19 +01:00
Hrant
ee340409db patterns: Added APFS pattern (#400)
* updated APFS hexpat

* fix null feature

---------

Co-authored-by: Hrant Tadevosyan <Hrant.Tadevosyan@connectwise.com>
2025-12-05 21:19:37 +01:00
Fabian Neundorf
84dff0c886 patterns: Add json support for glb files (#412)
* patterns: Add json support for glb files

This makes it possible to separate display the different buffer views,
accessors and images (even visualizing them).

Unfortunately the data within the JSON gets sometimes corrupted and this
is the reason, why it parses the JSON multiple times at some places.

* Use original style and only single json variable

* patterns: Reuse json from global variable in gltf

* patterns: Check component type in gltf only once

* patterns: Fix gltf pattern and add formatting

Removes the duplicate definition of `component_type_t` and also removes
the need to pass the `component_type` to `stride_type_t`.
2025-12-05 21:19:19 +01:00
F01TECH
28a297582b patterns: Added DFIR Patterns (#442)
* Added /DFIR/ with patterns

Added /DFIR/ sub-directory.
Contains modified versions of built-in patterns for semi-automated Disk/Volume/Filesystem parsing geared towards Digital Forensics.
Originals in /fs/ should remain in tact for spot placement.

* DFIR_README.md

* DFIR_README.md

* DFIR_README.md

* DISK_PARSER.hexpat

* DISK_PARSER.hexpat

* FAT32.hexpat

* exFAT.hexpat

* README.md

Added DFIR related hexpats to table.

* README.md

---------

Co-authored-by: Xtreme-Liberty <59177844+Xtreme-Liberty@users.noreply.github.com>
2025-12-05 21:18:56 +01:00
Lexi Mayfield
681b1a1ded patterns: Add support for KTX 1.0 textures (#451)
* 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

* Add pattern for KTX 1.0 file

* Use import, add reference ktx file

* Add to README
2025-12-05 21:17:01 +01:00
Stephen Hewitt
0a09efdd20 patterns: Pattern for DOS EXE files (#452)
* Initial DOS file

* Update README.md

* Update README.md

* More README

* More README

* Add DOS EXE

From: https://clasqm.github.io/freedos-repo/Games.html

Name: Champ Galagon
2025-12-05 21:16:36 +01:00
gmestanley
0d8bd76c2c patterns: Improvements to NES & IPS, add SNES, NSF, NSFe (#455)
* Add credit to ne.hexpat

* Add many changes to nes.hexpat

* Fixing dependance on variables declared in if statement

* Added mappers and inline to NES 2.0 header, removed needless parenthesises

* Add files via upload

* Add files via upload

* Create nsf.hexpat

* Used full name of the SNES on description

* Add SNES, NSF & NSFe, new description for NES

* Removing erroneous condition in ips.hexpat's truncatedSize

* Removing unnecessary std.string import in ips.hexpat

* Added both locations for sections in PE, clearer variable names, reorganized DOS stub

* Delete patterns/nsfe.hexpat

* Delete patterns/nsfmetadata.hexpat

* Added chunks from NSFe to NSF

* Added NSFe

* Fix size of truncatedSize in ips.hexpat

---------

Co-authored-by: Nik <werwolv98@gmail.com>
2025-12-05 21:15:50 +01:00
Lucia
a525160243 patterns: Added pattern for PopCap's Lua bytecode (#458)
* patterns: Added PopCap's proprietary Lua bytecode pattern.

* updated README to include new pattern

* fixed README link

* patterns/popcap_luc.hexpat: fixed comments and sources

* patterns/popcap_luc.hexpat: Changed datatype of filename to be more clear about its structure

* patterns/popcap_luc.hexpat: fixed improper handling of Nil type and added test file
2025-12-05 21:14:53 +01:00
Dexrn ZacAttack
c3946d33a7 patterns/java_class: Add class versions up to j26 (#459) 2025-12-05 21:14:31 +01:00
Khoo Hao Yit
cc7eb7d764 patterns: Add support for Unity Asset Bundle (#461) 2025-12-05 21:14:08 +01:00
Gal1leo Gal1lei
53384a4a54 patterns: Added Windows Notepad State File Parser (#463) 2025-12-05 21:12:45 +01:00
Nik
da005f0172 git: Fix json schema checking 2025-12-05 21:10:24 +01:00
Nik
b2f126d22f constants: Update constants to new system 2025-12-02 23:06:30 +01:00
Nik
7ea863269e build: Fix variable name for Git repository reference 2025-12-01 21:44:39 +01:00
Nik
faff9e0364 git: Add option to customize pattern language repo and git hash with workflow call 2025-12-01 21:38:00 +01:00
gmestanley
a35004665f patterns: Credit to NE and improvements on NES (#445)
* Add credit to ne.hexpat

* Add many changes to nes.hexpat

* Fixing dependance on variables declared in if statement

---------

Co-authored-by: Nik <werwolv98@gmail.com>
2025-09-22 07:15:37 +02:00
Tim Schneeberger
4fc11f1b91 patterns: Add ESP32 image pattern (#449)
Co-authored-by: Nik <werwolv98@gmail.com>
2025-09-21 09:30:38 +00:00
ODeux
7a9a5097a2 patterns: Add Python Pickle Pattern (#446)
* Add pickle pattern file

* Add test file

* Update README.md

---------

Co-authored-by: Nik <werwolv98@gmail.com>
2025-09-21 11:17:40 +02:00
Nik
0e67ee102b patterns/ico: Disable BMP processing until issues in the pattern language have been resolved 2025-09-21 10:44:20 +02:00
Zackary Newman
69077b919d patterns/ext4: Increase pattern limit to 2 GiB (#440) 2025-09-12 22:42:55 +02:00
Nightowl
297f611fed patterns: Add terminfo pattern (#437)
* patterns/terminfo: Add pattern for compiled term info entry files.

This adds support for the compiled (legacy and extended) term info entry files that are used for determining terminal capabilities.

* Add .bin extension to the terminfo test file.
2025-09-09 22:39:59 +02:00
DmitriLeon2000
b24ae36638 patterns: Add .gmf (Game Maker 3.x Data) pattern file and its test files (#438)
* Add .fas and .was pattern files (Oska DeskMates)

* Update .was pattern file

* Update .was/.wa3 pattern file

* Update README.md

* Update README.md

* Update .fas & .was pattern files

* Update README.md

* Update fas_oskasoftware_old.hexpat

* Added WAS test file

* Update WAS test file

* Update was_oskasoftware.hexpat

* Update was_oskasoftware.hexpat

* Update fas_oskasoftware_old.hexpat

* Update fas_oskasoftware.hexpat

* Update README.md

Replacing backward slashes with forward ones in the `WAS` row.

* Update fas_oskasoftware_old.hexpat

* Update was_oskasoftware.hexpat

* Add files via upload

* Add Game Maker 3.x Data pattern

* Update gmf.hexpat
2025-09-09 18:22:02 +02:00
Zackary Newman
50d776f497 patterns/ext4: Fix group descriptor table location for non-1024 block sizes (#439) 2025-09-09 18:21:12 +02:00
WerWolv
7dfacc4139 revert: includes/std: Added section parameters to a few std::mem functions 2025-09-06 07:38:18 +02:00
WerWolv
5359e385ea git: Added build folders to gitignore 2025-09-06 07:33:32 +02:00
Nik
75bcb487ee patterns/ico: Fixed duplicate variable name 2025-09-01 22:22:43 +02:00
Ivy Fan-Chiang
fb214600ec patterns/ico: Add embedded BMP and PNG parsing to ICO pattern (#426)
Co-authored-by: Nik <werwolv98@gmail.com>
2025-08-31 14:32:21 +02:00
Kris Dekeyser
d95390ea42 patterns/jpeg: added support for extra data in APP0 section (#417)
Apple Multi-Picture Format JPEGs often have 4 extra bytes in the APP0 section. The pattern now skips any extra bytes beyond the fixed APP0 data.

Co-authored-by: Nik <werwolv98@gmail.com>
2025-08-31 11:40:27 +02:00
Marc Jones
284ca8d325 patterns: Add UEFI Firmare Volume Variable Store pattern (#421)
* Add UEFI Firmare Volume Variable Store pattern

Add a pattern for UEFI Firmare Volume Variable store.
This file type is commonly used with virtual machine UEFI variable files,
like OVMF.fd used with QEMU. You could also extract a UEFI firmware binary
from a flash device, search for the FV Variable Store, and set this pattern
to the FV address.

Signed-off-by: Marc Jones <marcj303@gmail.com>

* Fixed description pragma

---------

Signed-off-by: Marc Jones <marcj303@gmail.com>
Co-authored-by: Nik <werwolv98@gmail.com>
2025-08-31 11:38:32 +02:00
ODeux
6630180276 patterns: Add .NET BinaryFormatter pattern (#416)
* Add dotnet BinaryFormatter pattern

* Add dotnet BinaryFormatter test

* Update README.md

---------

Co-authored-by: Nik <werwolv98@gmail.com>
2025-08-31 11:37:59 +02:00
Henri Asseily
ff68d1e23d patterns: Added Apple IIGS SHR + SHR 3200 + SHR PWA Animation pattern (#432)
* Added SHR pattern

* Added IIGS SHR animation test file

* Added pattern to readme

* Added description and author

---------

Co-authored-by: Nik <werwolv98@gmail.com>
2025-08-31 11:36:00 +02:00
Tom Arrow
70dd55aa6b patterns/q3demo: Quake 3 demos: Handle corrupted files more gracefully (#414)
Quake 3 demos: Basic safeguard against corrupted files

Co-authored-by: Tom <tomarrowtomarrow@hotmail.com>
2025-08-31 11:31:20 +02:00
DmitriLeon2000
76f850c543 patterns/fas/was: Update FAS, WAS/WA3 pattern files and README.md (#425)
* Add .fas and .was pattern files (Oska DeskMates)

* Update .was pattern file

* Update .was/.wa3 pattern file

* Update README.md

* Update README.md

* Update .fas & .was pattern files

* Update README.md

* Update fas_oskasoftware_old.hexpat

* Added WAS test file

* Update WAS test file

* Update was_oskasoftware.hexpat

* Update was_oskasoftware.hexpat

* Update fas_oskasoftware_old.hexpat

* Update fas_oskasoftware.hexpat

* Update README.md

Replacing backward slashes with forward ones in the `WAS` row.

* Update fas_oskasoftware_old.hexpat

* Update was_oskasoftware.hexpat
2025-08-31 11:28:45 +02:00
MicroBlock
74c06b74f7 patterns/lua53: Fix lua53 long string (#427)
Update lua53.hexpat
2025-08-31 11:27:59 +02:00
Vemmi
f13d9d3894 patterns/upk-ue3: Add magic pragma (#436) 2025-08-31 11:23:09 +02:00
mjarduk
c4c75a9ab2 patterns: Add a pattern for Roblox .pack files (#435)
* Added the .pack format

* Clarified some fields by changing the naming
2025-08-25 22:22:32 +02:00
Nik
7278a22eb2 includes/std: Fix MagicSearch implementation not being found 2025-08-24 13:34:47 +02:00
Nik
91fd36097c includes/std: Fix use of std::mem::size and std::mem::base_address in library 2025-08-24 12:04:33 +02:00
Nik
afffd7eced includes/std: Added section parameters to a few std::mem functions 2025-08-24 12:00:05 +02:00
Lexi Mayfield
7fd79ec9fd 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
2025-08-20 19:32:11 +02:00
Mark Jansen
6b9f39cc21 patterns: Add SDB pattern (#424)
Co-authored-by: Nik <werwolv98@gmail.com>
2025-08-15 17:16:50 +02:00
Stephen Hewitt
9207282bcf patterns: Added Commodore BASIC (#428)
* Commodore BASIC

* Update desc

* I made it

* Implemented suggestion

* Implemented suggestion

* Test file

* Rename file

---------

Co-authored-by: Nik <werwolv98@gmail.com>
2025-08-02 20:13:35 +02:00
WerWolv
5ed64f9f08 tests: Include patterns folder as include path to support import * from X as Y
#426
2025-08-02 19:29:16 +02:00
WerWolv
a75a7a5b98 git: Let the CI still work correctly in PRs 2025-07-29 22:26:27 +02:00
WerWolv
60c8d93449 git: Make sure other repos check out the right repo 2025-07-29 21:57:54 +02:00
WerWolv
d3b05fd753 git: Allow test action to be imported by other projects 2025-07-29 21:38:20 +02:00
paxcut
3b2f098b09 fix: fixed two typos in this theme (#423) 2025-07-18 08:39:37 -07:00
paxcut
f4f004f0eb improv: Added new text editor semantic highlighting themes. (#422)
* improv: Added new text editor semantic highlighting themes.

Current themes use the same colors  for all identifier types. These two new themes are just examples of what the new feature makes possible.
One aims to simulate CLion Darcula theme and the other is an extension of the original dark theme.

* fix: corrected entries to readme file

* fix: corrected base for the theme

Made sure readme looks correctly on fork and links go to files.
2025-07-16 07:01:43 -07:00
paxcut
5c6cb9dccc fix: issues with two remaining themes. (#420)
Both one-dark and nocturne used global-doc-comment instead of the correctly named doc-global-comment. Typos in Nocturned didn't prevent the theme from loading, but left annoying messages in the log. As explained by the author, the base color map must be one of the three that imhex loads by default, dark,light and/or classic. Even if that is not the case, the name given in base must be that of a valid color map that has been loaded prior to the ones that use it as a base.
2025-07-11 03:42:45 -07:00
paxcut
44717e9b19 fix: incorrect names and values for some colormap entries of the text editor. (#419)
fix: incorrect names and values for some colormap entries of the test editor.

Some names were changed from the original that need to be changed back to make the old colormaps compatible with the new system.
Also, the colors of the console text were incorrectly set to be equal to each other.
This Pr brings back the old names and hopefully fixes problems of incorrect color being used
2025-07-11 02:25:02 -07:00
Dominik Tamiołło
bc35349e0f PEF - fix export count calculation (#418)
* Initial version of PEF

* add pef test file

* Fixed export hash slot count calculation

---------

Co-authored-by: paxcut <53811119+paxcut@users.noreply.github.com>
2025-07-08 15:21:07 -07:00
Nik
fed5db4109 Add Capcom's Devil May Cry 3 HD .mod hexpat (#415)
* Add Capcom's Devil May Cry 3 HD .mod hexpat

Hex Pattern file for Capcom's Devil May Cry 3 HD Collection's .mod (3D Models) files

* Update DMC3 HD Mod.hexpat

* Update DMC3 HD Mod.hexpat

* Update DMC3 HD Mod.hexpat

* Add files via upload

* Update README.md

* Rename DMC3 HD Mod.hexpat to dmc3_hd_mod.hexpat

* Delete patterns/dmc3_hd_mod.hexpat

* Delete tests/patterns/test_data/dmc3_hd_mod.hexpat.mod

* Add files via upload

* Update dmc3_hd_mod.hexpat

---------

Co-authored-by: haruse23 <mrjokeromar123@outlook.com>
2025-07-08 14:51:54 -07:00
klirktag
1d41392215 Add support for medium and large mp4 files (#413)
add support for medium and large mp4
2025-06-29 07:33:48 -07:00
ruokeqx
0b75336638 feat(pcapng): add support for Decryption Secrets Block (#411)
feat(pcapng): add support for Decryption Secrets Block
2025-06-19 05:13:43 -07:00
C3pa
e3edbd5a6f Small documentation improvements (#408)
doc: add syntax highlighting to std::ptr::NullablePtr example, fix description of type::escape_bytes

Co-authored-by: paxcut <53811119+paxcut@users.noreply.github.com>
2025-06-17 23:55:51 -07:00
C3pa
b10a37af67 Docs: describe how to create multidimensional std::Array (#407)
doc: descirbe how to create multidimensional std::Array

Co-authored-by: paxcut <53811119+paxcut@users.noreply.github.com>
2025-06-17 23:46:33 -07:00
Dominik Tamiołło
103d434cc5 Add PEF (Preffered Executable Format) support (#406)
* Initial version of PEF

* add pef test file

---------

Co-authored-by: paxcut <53811119+paxcut@users.noreply.github.com>
2025-06-17 22:24:54 -07:00
Fabian Neundorf
7716b9d6e7 patterns: Add support for smk (#399)
* patterns: Add support for smk

* patterns: Use builtin function and separate SMK struct

---------

Co-authored-by: paxcut <53811119+paxcut@users.noreply.github.com>
2025-06-17 14:57:36 -07:00
Tom Arrow
ad1e300674 Quake 3 Engine demo pattern & test file (#402)
* Quake 3 Engine demo pattern & test file

* Quake 3 Engine demo: Increase limits (demo files can be big) and additional condition

* Quake 3 demo specify little endian

* Quake 3 demo format: Add message type detection

* Quake 3 demo format: Read serverTime for snapshot messages

* Quake 3 demo pattern: fixed bug/typo/sleepy coding

* Quake 3 demo pattern: Ability to read CS_SERVERINFO

* Quake 3 demo pattern: Read CS_SYSTEMINFO as well

* Quake 3 demo pattern: Read first serverCommand per message

* Added Quake 3 engine demo pattern to readme

* Change Quake 3 engine demo entry in readme table

---------

Co-authored-by: Tom <tomarrowtomarrow@hotmail.com>
2025-06-17 02:06:24 -07:00
zn123
e918ce52b9 Add flv.hexpat (#401)
* Add flv.hexpat

https://veovera.org/docs/enhanced/enhanced-rtmp-v2#flv-file-format-overview

* test flv.hexpat

* Update README.md

add flv patterns

* Update flv.hexpat

Optimize spaces

* Update flv.hexpat

fix
2025-06-16 20:25:54 -07:00
Nik
db4d62aa20 patterns/fs: Refactor all partition types into a FS module 2025-05-25 19:51:32 +02:00
WerWolv
d96bfbb942 tests: Execute and test format functions 2025-05-25 12:43:21 +02:00
Nik
2070c95f58 yara: Added crypto identification rules 2025-05-24 23:56:56 +02:00
Nik
877895741d includes/hex: Fixed Json types being twice the size they need to be 2025-05-17 19:45:30 +02:00
Nik
6b279b8375 patterns/exfat: Fixed eval depth error 2025-05-17 16:07:11 +02:00
Khoo Hao Yit
a692b22ecc patterns: Add support for exFAT (#398) 2025-05-17 13:13:35 +02:00
Claudius Coenen
2ae0499293 patterns/wintec_tes: Slightly nicer formatting in a list of entries (#397)
slightly nicer formatting in a list of entries
2025-05-16 20:25:04 +02:00
thrasher
bd06987e8e patterns/zip: Add zip64 support (#395)
Co-authored-by: Nik <werwolv98@gmail.com>
2025-05-15 21:22:20 +02:00
Fabian Neundorf
74e08623f1 patterns: Add support for flc/flic files (#396)
* patterns: Add support for flc/flic files

* patterns: Add #pragma description for flc

---------

Co-authored-by: Nik <werwolv98@gmail.com>
2025-05-15 20:17:13 +02:00
Nik
a860c396fa patterns: Added Java HPROF pattern 2025-05-15 17:23:06 +02:00
Nik
da934e2045 patterns/optee_ta: Fixed missing author and description pragmas 2025-05-15 08:07:13 +02:00
Nik
394ef80611 patterns: Added OPTEE Trusted Application format 2025-05-13 22:17:05 +02:00
Grant Kim
2ce182b1b3 patterns/tiff: Tags for DNG and TIFF extensions (#376)
Add Tags for DNG and TIFF extensions

References: https://www.loc.gov/preservation/digital/formats/content/tiff_tags.shtml
https://helpx.adobe.com/camera-raw/digital-negative.html

Co-authored-by: Nik <werwolv98@gmail.com>
2025-05-10 13:59:22 +02:00
Glenn Hartmann
6cadad3d1f pattern/protobuf: Allow parsing of nested messages (#378)
Mostly this enables attempted recursive parsing of submessages. Note
that it is inherently impossible to determine the underlying data type
for LengthDelimited for sure, so this is a best-effort attempt. The user
can disable recursive submessage parsing via Settings.

Other minor changes:
* added #pragma MIME and #pragma endian directives
* enabled UTF-8 display for LengthDelimited types
* added signed LEB128 display for Varint types (although this doesn't
  seem to be working on my test case)
* swapped if/else-if structure for match
* fail upon receiving unknown or unsupported WireType

Co-authored-by: Nik <werwolv98@gmail.com>
2025-05-10 13:53:01 +02:00
David Schneider
7ad9cd4f41 patterns: Added support for GNU MO files (#383) 2025-05-10 11:49:02 +00:00
0xZ3R0
bcaeef31d7 pattern: Added DJI Firmware Pattern (#392)
* added IM*H pattern

* improved README
2025-05-10 13:35:14 +02:00
Niketin
ee8d2f50b7 pattern/bencode: Various fixes (#393)
* Fix bencode dictionary

When parsing a bencode dictionary, the end character 'e' was never
consumed. This caused a misinterpretation of the character as struct Value of
an unknown type 'e'.

* Fix bencode list

A list was not included in the Value's parsing logic so it may have
been mistakenly parsed as a string.

* Fix std::ctype::isprint not including space

The space character, 0x20, is considered as a printable character in ASCII
and in >=C89. Adding it to the range of std::ctype::isprint also fixes
other std::ctype functions that use it.

* Fix bencode byte string formatting

Byte strings do not render nicely in pattern data's value column if they
contain non-printable characters. This commit makes the value of byte
strings to be surrounded by quotation marks, and renders a warning text
without quotation marks if the byte string contains non-printable
characters.
2025-05-10 13:34:36 +02:00
DEREFERENC3D
5b8dde19a9 patterns: Added definition for the OpenRGB profile format (#387)
patterns: Add definition for the OpenRGB profile format (up to version 5)
2025-05-10 13:34:16 +02:00
Dhash Shrivathsa
0b0eff0cb6 pattern/macho: Load Commands should include additional specializations (LoadDyLib) (#386)
* add additional command specialization

* address PR feedback
2025-05-10 13:34:01 +02:00
Enaium
3185503be1 patterns: Added valve vpk pattern (#384) 2025-05-10 10:29:50 +00:00
Sabhya
3a64207e58 pattern: Added pcapng capture file pattern (#385)
add: pcapng hexpat
2025-05-10 12:26:39 +02:00
bluisblu
c94d42d5c0 patterns: Added Radcore Cement v1.2 file pattern (#382)
* Add Radcore Cement file pattern

* Update pattern list in README.md
2025-05-10 11:57:51 +02:00
Caleb Denio
45c4c1d35b patterns/uf2: Added magic number (#379) 2025-05-10 11:54:29 +02:00
Jean Pereira
f93be1ea06 themes: Added Nocture theme (#377)
minimal dark theme based on Dracula but more darker
2025-05-10 11:53:28 +02:00
Shadlock0133
5ed9c0fd4d patterns/elf: use Rel{a} structs for parsing REL{A} section data (#375) 2025-05-10 11:52:35 +02:00
C3pa
11d373319f pattern/pe: Check for imageNameRVA in pe.hexpat before reading imageName (#372) 2025-05-10 11:52:00 +02:00
Jonathan Ostrus
e7d366571d pattern/pex: Added formatter for opcode and some other name cleanups (#371) 2025-05-10 11:51:43 +02:00
Caleb Denio
b6df1742b6 patterns: Add ZIM pattern (#367)
* Add ZIM pattern file

* Add test file

* namespace!
2025-05-10 11:51:04 +02:00
Jake Ryan
0b9e83ff8a patterns: Add support for MagicaVoxel .vox files (#390)
* patterns: Added support for MagicaVoxel .vox files

* Fixed incorrect IMAP field size and added basic chunk size mismatch detection and recovery.

* Fixed pattern for "_r" values and added RotationToMat3.

* Added test vox file.

---------

Co-authored-by: paxcut <53811119+paxcut@users.noreply.github.com>
2025-04-30 08:55:53 -07:00
paxcut
c0fc748de6 fix: rgb color attribute is always blue.
The color attribute does not nclude an alpha component but the RGB types were including an alpha of 255 in their color attributes. The 0xFF was being assigned to the blue component hence the error.
2025-04-30 08:40:32 -07:00
Hrant
89307ba8a5 added NTFS pattern (#391)
Thank you!

* added NTFS pattern

* improved the PR

* remove test-data & fixed sd

---------

Co-authored-by: Hrant Tadevosyan <Hrant.Tadevosyan@connectwise.com>
2025-04-30 04:00:52 -07:00
ZHANG Yuntian
a12b5ba406 git: Fix table formatting (#374)
Signed-off-by: ZHANG Yuntian <yt@radxa.com>
2025-03-24 07:33:01 +01:00
ZHANG Yuntian
537ce67895 patterns/partition_table: Added basic MBR and GPT patterns (#358)
Both are conbined into a single pattern due to how GPT always has a pseudo MBR to maintain backward compatibility.
2025-03-24 07:15:25 +01:00
Scrivener07
1771c1f077 patterns: Added support for PEX Papyrus executables (#370)
Added support for PEX, Bethesda's Papyrus executable for compiled script files.
- Skyrim
- Fallout 4
- Fallout 76
- Starfield

Co-authored-by: Jonathan Ostrus <12855515+jbostrus@users.noreply.github.com>
2025-03-23 11:30:43 +01:00
Caleb
cef20e24a7 patterns/zip: Fix 0x5455 extended timestamp fields crash, improve date/time presentation (#363)
Co-authored-by: Nik <werwolv98@gmail.com>
2025-03-22 13:57:42 +01:00
Andreas Wallner
8e7cfd9442 patterns: Add STDFv4 pattern (#326) 2025-03-22 13:54:50 +01:00
5ec1cff
d0ba754dc2 patterns/zip: Handling padded extra fields (#369)
* Handling unresolved extra fields

* Update zip.hexpat

* Update zip.hexpat

* Update zip.hexpat
2025-03-22 13:54:26 +01:00
mheimlich
9f92c38ecf patterns: Add ADTFDAT pattern (#368) 2025-03-22 13:52:59 +01:00
Geky
0844e07056 patterns: Added DS Cartridge Header pattern, updated pyc versions (#366)
* add support for cartridge size type $54

Added support for cartridge size type $54, corresponding to 1.5 MiB (96 banks).

* add missing license

* Add GBA Cartridge Header

* Update README.md

Added GBA information to README.md and corrected a typo.

* Add DS Cartridge Header

* Update ReadMe.md

* Update pyc.hexpat

Included additional versions
2025-03-22 13:51:46 +01:00
C3pa
66fc006b08 includes/std: Update hex::dec::zlib_decompress description (#364)
docs: Update hex::dec::zlib_decompress description
2025-03-22 13:51:00 +01:00
Eddy S.
5bc66df14f patterns/elf: Set endianness globally (#362) 2025-03-22 13:50:17 +01:00
MrMcX
7310a10214 patterns: Add pattern for microsoft prefetch files (uncompressed SCCA format only) (#361)
* Add pattern for microsoft prefetch files (uncompressed SCCA format only)

* Update pf.hexpat

Add longer explanation
2025-03-22 13:49:50 +01:00
MrMcX
34ee3107e2 patterns: Implement Windows thumbcache pattern (#359)
* Implement Windows thumbcache pattern

* Include thumbcache pattern in README.md

* Update thumbcache.hexpat

- Use English warning text
- handle unknown file version
- add thanks to joachimmetz
- create virtual file
- use more elegant magic type

* Update thumbcache.hexpat

- Use padding data type for paddings

* Update thumbcache.hexpat

- make pattern more robust against single erroneous cache record
2025-03-22 13:48:57 +01:00
Shadlock0133
c4378ffb14 patterns/elf: Use e_shstrndx to get section names instead of guessing (#357) 2025-03-22 13:47:43 +01:00
eli_w
5ad7f0c1e7 patterns/ani: Improved compatibility with error size defined in ani files (#354) 2025-03-22 13:46:49 +01:00
Mrmaxmeier
df97fc7257 patterns/includes: More misc cleanups (#353)
* patterns/zip: simplify find_sequence_in_range check

hex(340282366920938463463374607431768211455) =
0xffffffffffffffffffffffffffffffff

* patterns/7z: use Magic<> for signature, add pragma

* patterns/{nro, ogg}: use Magic<> for signature

* patterns/ttf: refactor, check magic

Use the "Field field @ position;" syntax instead of saving and restoring
the cursor position.

* readme: fix copy-paste error in pattern listing
2025-03-22 13:46:06 +01:00
Vemmi
3ad263783d patterns: Added Unreal Engine 3 UPK pattern (#352)
* patterns: Add unreal 3 upk pattern

* readme: Add link to upk-ue3.hexpat
2025-03-22 13:45:25 +01:00
Ilya Sorochan
5ccd431320 patterns: Added RPM pattern (#350) 2025-03-22 13:44:55 +01:00
Nik
fb8e5e3f77 disassemblers/jvm: Fixed mask and mnemonic of areturn and athrow 2025-02-28 11:42:44 +01:00
paxcut
375145e759 include/std: std::ptr::relative_to_base_section not working anymore (#349)
Fixes #348 

In issue #348 it is stated that the pattern fails to find the variable baseAddress in the parent of the parent of the attribute function. One parent is required to access the variables on the pattern that is using the attribute.

That pattern is used in the pattern that contains baseAddress as a pointer to an array of the children pattern and that seems to require an extra parent level to be added in order to access baseAddress without errors. The fix was tested on an xbe file extracted from an xbox cd rom and while it failed without the fix as stated in issue 348 with the fix it ran to completion without issues.
2025-02-16 12:52:01 +01:00
paxcut
71eeed981d patterns/protobuf: Remove global variables
In issue #346 it is noted that the format functions return the same value repeatidly and erroneously. This is due to the use of global variables which result on only their last value being used in format functions due to their delayed evaluation. Fixed by using local variables instead. Also remove tabs from the file and an unused tags variable.
2025-01-30 20:24:11 +01:00
Fabian Neundorf
e779b88a58 patterns/iso: Fix incorrect condition (#344) 2025-01-23 21:44:44 +01:00
Fabian Neundorf
aef3d3451f patterns/iso: Add some improvements to the ISO pattern matching (#343)
* patterns: Load all ISO volume descriptors

* patterns: Parse supplementary volume descriptors

* patterns: Add system use in directory records for iso
2025-01-23 19:23:11 +01:00
Nik
c5fa53dcea includes/type: Make type::Formatted actually work as documented 2025-01-19 18:13:48 +01:00
The Wandering Trader
9a6cbdfe28 patterns: Add CAB pattern (#342)
* Add files via upload

* Add files via upload

* Update README.md
2025-01-19 00:13:04 +01:00
Nik
083042632d includes/hex: Hide implementation data of json types 2025-01-16 19:15:10 +01:00
Nik
4d172cebc3 patterns: Removed invalid zip test file 2025-01-14 20:07:03 +01:00
Nik
53ff0a5d62 patterns/afe2: Fixed misspelled of pragma 2025-01-14 20:06:39 +01:00
WerWolv
b3b730c6e9 patterns: Fixed various test binaries 2025-01-14 20:01:51 +01:00
Nik
8db011b6e5 patterns: Added MIME types and magic numbers to all patterns that have them 2025-01-14 20:01:36 +01:00
Nik
b936c04d21 patterns/gguf: Added #pragma magic to allow auto-loading the pattern 2025-01-14 18:21:16 +01:00
bake
bf56d4ff49 patterns: Add veado pattern (#339)
* Add veado pattern

* Add veado to README

* Add veado example file
2025-01-13 21:21:05 +01:00
Known Rabbit
fdc4a87389 patterns: Add bcss (BeyondCompare SnapShot) file (#338)
* patterns: add bcss (BeyondCompare SnapShot) file

* Add entry to readme

* Change table entries in alphabetical order

* Support both bcss file and uncompressed content

* Remove misleading cases, add warning message

* Add test cases to bcss.hexpat

* ifdef out ImHex-only functionality

---------

Co-authored-by: Nik <werwolv98@gmail.com>
2025-01-13 21:20:36 +01:00
Mia
1f6c701348 patterns: Added sup pattern file (#337)
* Add sup pattern file

* Add files via upload

* Update README.md
2025-01-09 20:01:14 +01:00
JTurtle
4092dad428 includes/type: Fix error in float16 format function (#336) 2025-01-05 09:46:09 +01:00
Nik
559faebec3 patterns: Added simple SQLite3 database pattern 2024-12-28 19:57:48 +01:00
Nik
cde46e1f15 patterns/bgcode: Improve bgcode pattern 2024-12-28 18:51:34 +01:00
Nik
17c200a92e disassemblers/jvm: Added remaining instructions besides lookupswitch and tableswitch 2024-12-27 13:41:46 +01:00
Nik
384d4c7794 disassemblers: Added half of the JVM instructions 2024-12-27 01:07:36 +01:00
Nik
37a7e59c06 disassemblers: Added Intel 8051 architecture 2024-12-26 20:08:42 +01:00
260 changed files with 27136 additions and 2656 deletions

View File

@@ -7,6 +7,12 @@ on:
branches: [ '*' ]
repository_dispatch:
types: [run_tests]
workflow_call:
inputs:
pattern_language_git_repo:
type: string
pattern_language_git_hash:
type: string
jobs:
tests:
@@ -21,6 +27,7 @@ jobs:
- name: 🧰 Checkout
uses: actions/checkout@v4
with:
repository: ${{ github.repository_owner }}/ImHex-Patterns
submodules: recursive
- name: ⬇️ Install dependencies
@@ -61,6 +68,8 @@ jobs:
-DIMHEX_PATTERNS_ENABLE_UNIT_TESTS=ON \
-DLIBPL_ENABLE_TESTS=OFF \
-DLIBPL_ENABLE_CLI=OFF \
-DIMHEX_PATTERNS_LIBPL_GIT_REPO="${{ inputs.pattern_language_git_repo }}" \
-DIMHEX_PATTERNS_LIBPL_GIT_HASH="${{ inputs.pattern_language_git_hash }}" \
-G Ninja \
..
ninja unit_tests
@@ -73,9 +82,9 @@ jobs:
- name: 📎 Validate JSON Files
run: |
cd constants
for file in ./[!_schema.json]*; do jsonschema -i $file _schema.json; done
for file in ./[!_]*; do jsonschema -i $file _schema.json; done
cd ..
cd tips
for file in ./[!_schema.json]*; do jsonschema -i $file _schema.json; done
for file in ./[!_]*; do jsonschema -i $file _schema.json; done
cd ..

1
.gitignore vendored
View File

@@ -2,6 +2,7 @@
tests/cmake*/
tests/build*/
build/
cmake-build-*/
.vscode/
.devcontainer/

View File

@@ -16,10 +16,22 @@ endif()
if(NOT TARGET libpl)
include(FetchContent)
if (NOT DEFINED IMHEX_PATTERNS_LIBPL_GIT_REPO OR IMHEX_PATTERNS_LIBPL_GIT_REPO STREQUAL "")
set(LIBPL_GIT_REPO "https://github.com/WerWolv/PatternLanguage")
else()
set(LIBPL_GIT_REPO ${IMHEX_PATTERNS_LIBPL_GIT_REPO})
endif()
if (NOT DEFINED IMHEX_PATTERNS_LIBPL_GIT_HASH OR IMHEX_PATTERNS_LIBPL_GIT_HASH STREQUAL "")
set(LIBPL_GIT_TAG "master")
else()
set(LIBPL_GIT_TAG ${IMHEX_PATTERNS_LIBPL_GIT_HASH})
endif()
FetchContent_Declare(
pattern_language
GIT_REPOSITORY https://github.com/WerWolv/PatternLanguage
GIT_TAG master
GIT_REPOSITORY ${LIBPL_GIT_REPO}
GIT_TAG ${LIBPL_GIT_TAG}
)
FetchContent_MakeAvailable(pattern_language)
@@ -27,4 +39,4 @@ endif()
if(IMHEX_PATTERNS_ENABLE_UNIT_TESTS)
add_subdirectory(tests)
endif()
endif()

127
README.md
View File

@@ -25,55 +25,86 @@ Everything will immediately show up in ImHex's Content Store and gets bundled wi
|------|------|------|-------------|
| 3DS | | [`patterns/3ds.hexpat`](patterns/3ds.hexpat) | Autodesk 3DS Max Model file |
| 7Z | | [`patterns/7z.hexpat`](patterns/7z.hexpat) | 7z File Format |
| ADTS | | [`patterns/adts.hexpat`](patterns/adts.hexpat) | ADTS/AAC audio files |
| ADTFDAT | | [`patterns/adtfdat.hexpat`](patterns/adtfdat.hexpat) | [ADTFDAT files](https://digitalwerk.gitlab.io/solutions/adtf_content/adtf_base/adtf_file_library) |
| 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 |
| APFS | | [`patterns/fs/apfs.hexpat`](patterns/fs/apfs.hexpat) | Apple File Ssytem (APFS) |
| 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 |
| ARM VTOR | | [`patterns/arm_cm_vtor.hexpat`](patterns/arm_cm_vtor.hexpat) | ARM Cortex M Vector Table Layout |
| Arma 3 config | `application/x.a3-rap` | [`patterns/a3/a3_rap.hexpat`](patterns/a3/a3_rap.hexpat) | Arma 3 binary/rapified config |
| Arma 3 P3D (MLOD) | `model/x.a3-p3d-mlod` | [`patterns/a3/a3_p3d_mlod.hexpat`](patterns/a3/a3_p3d_mlod.hexpat) | Arma 3 P3D model file (MLOD) |
| Arma 3 PAA | `image/x.a3-paa` | [`patterns/a3/a3_paa.hexpat`](patterns/a3/a3_paa.hexpat) | Arma 3 PAA texture file |
| Arma 3 RTM | `application/x.a3-rtm` | [`patterns/a3/a3_rtm.hexpat`](patterns/a3/a3_rtm.hexpat) | Arma 3 RTM animation file (plain) |
| Arma 3 RTM (binarized) | `application/x.a3-bmtr` | [`patterns/a3/a3_bmtr.hexpat`](patterns/a3/a3_bmtr.hexpat) | Arma 3 RTM animation file (binarized) |
| Arma 3 texHeaders.bin | `application/x.a3-texheaders` | [`patterns/a3/a3_texheaders.hexpat`](patterns/a3/a3_texheaders.hexpat) | Arma 3 texture index file |
| Assassin's Creed: Unity | | [`patterns/AC Unity`](patterns/Assassin's Creed: Unity) | Assassin's Creed: Unity archive files -- .forge & .data (compressed and decompressed) -- |
| Bastion | | [`patterns/bastion/*`](https://gitlab.com/EvelynTSMG/imhex-bastion-pats) | Various [Bastion](https://en.wikipedia.org/wiki/Bastion_(video_game)) files |
| BeyondCompare BCSS | | [`patterns/bcss.hexpat`](patterns/bcss.hexpat) | BeyondCompare Snapshot (BCSS) file |
| Bencode | `application/x-bittorrent` | [`patterns/bencode.hexpat`](patterns/bencode.hexpat) | Bencode encoding, used by Torrent files |
| Prusa BGCODE | | [`patterns/bgcode.hexpat`](patterns/bgcode.hexpat) | PrusaSlicer Binary G-Code files |
| BLEND | | [`patterns/blend.hexpat`](patterns/blend.hexpat) | Blender Project file |
| BLF | | [`patterns/blf.hexpat`](patterns/blf.hexpat) | Vector BLF Frame Logging Files |
| BMP | `image/bmp` | [`patterns/bmp.hexpat`](patterns/bmp.hexpat) | OS2/Windows Bitmap files |
| BIN | | [`patterns/selinux.hexpat`](patterns/selinux.pat) | SE Linux modules |
| BINKA | | [`patterns/binka.hexpat`](patterns/binka.pat) | RAD Game Tools Bink Audio (BINKA) files |
| 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) |
| bplist | `application/x-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) |
| BZIP3 | | [`patterns/bzip3.hexpat`](patterns/bzip3.hexpat) | Parses BZip3 compression (file format) by Kamila Szewczyk |
| CAB | | [`patterns/cab.hexpat`](patterns/cab.hexpat) | Microsoft Cabinet (CAB) Files |
| 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 |
| CDA | | [`patterns/cda.hexpat`](patterns/cda.hexpat) | Compact Disc Audio track |
| CHM | | [`patterns/chm.hexpat`](patterns/chm.hexpat) | Windows HtmlHelp Data (ITSF / CHM) |
| 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) |
| Chromium Pak | | [`patterns/chromium_pak.hexpat`](patterns/chromium_pak.hexpat) | Chromium pak file |
| 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 |
| CPIO | | [`patterns/cpio_portable_ascii.hexpat`](patterns/cpio_portable_ascii.hexpat) | Portable ASCII CPIO Format |
| CPIO | | [`patterns/cpio_new_ascii.hexpat`](patterns/cpio_new_ascii.hexpat) | "New" ASCII CPIO Format |
| CrashLvl | | [`patterns/Crashlvl.hexpat`](patterns/Crashlvl.hexpat) | Crash Bandicoot - Back in Time (fan game) User created level format |
| CREDHIST | | [`patterns/credhist.hexpat`](patterns/credhist.hexpat) | CREDHIST Format |
| DDS | `image/vnd-ms.dds` | [`patterns/dds.hexpat`](patterns/dds.hexpat) | DirectDraw Surface |
| DEX | | [`patterns/dex.hexpat`](patterns/dex.hexpat) | Dalvik EXecutable Format |
| Devil May Cry HD Collection | | [`patterns/Devil May Cry HD Collection`](patterns/Devil May Cry HD Collection) | 3D Model files used in Devil May Cry 3 HD Collection |
| DICOM | `application/dicom` | [`patterns/dicom.hexpat`](patterns/dicom.hexpat) | DICOM image format |
| DISK_PARSER (DFIR) | `application/x-ima` | [`patterns/DFIR/DISK_PARSER.hexpat`](patterns/DFIR/DISK_PARSER.hexpat) | Recursive Disk/Volume/Filesystem parsing |
| DMG | | [`patterns/dmg.hexpat`](patterns/dmg.hexpat) | Apple Disk Image Trailer (DMG) |
| DMP | | [`patterns/dmp64.hexpat`](patterns/dmp64.hexpat) | Windows Kernel Dump(DMP64) |
| DOS | `application/x-dosexec` | [`patterns/dos.hexpat`](patterns/dos.hexpat) | 16-bit real mode DOS EXE files |
| DOTNET_BinaryFormatter | | [`patterns/dotnet_binaryformatter.hexpat`](patterns/dotnet_binaryformatter.hexpat) | .NET BinaryFormatter |
| DPAPI_Blob | | [`patterns/dpapblob.hexpat`](patterns/dpapiblob.hexpat) | Data protection API Blob File Format |
| DPAPI_MasterKey | | [`patterns/dpapimasterkey.hexpat`](patterns/dpapimasterkey.hexpat) | Data protection API MasterKey |
| DS_Store | | [`patterns/dsstore.hexpat`](patterns/dsstore.hexpat) | .DS_Store file format |
| DTA | | [`patterns/max_v104.hexpat`](patterns/max_v104.hexpat) | Mechanized Assault and Exploration v1.04 (strategy game) save file format |
| DTED | | [`patterns/dted.hexpat`](patterns/dted.hexpat) | Digital Terrain Elevation Data (DTED) |
| ELF | `application/x-executable` | [`patterns/elf.hexpat`](patterns/elf.hexpat) | ELF header in elf binaries |
| EVTX | | [`patterns/evtx.hexpat`](patterns/evtx.hexpat) | MS Windows Vista Event Log |
| EXT4 | | [`patterns/ext4.hexpat`](patterns/ext4.hexpat) | Ext4 filesystem |
| ESP32 Image | | [`patterns/esp32_image.hexpat`](patterns/esp32_image.hexpat) | Firmware image format for the ESP32 chip family |
| EVTX | `application/x-ms-evtx` | [`patterns/evtx.hexpat`](patterns/evtx.hexpat) | MS Windows Vista Event Log |
| EXFAT | | [`patterns/fs/exfat.hexpat`](patterns/fs/exfat.hexpat) | Extensible File Allocation Table (exFAT) |
| EXFAT (DFIR) | | [`patterns/DFIR/exFAT.hexpat`](patterns/DFIR/exFAT.hexpat) | Imported by DISK_PARSER.hexpat |
| EXT4 | | [`patterns/fs/ext4.hexpat`](patterns/fs/ext4.hexpat) | Ext4 File System |
| FAS | | [`patterns/fas_oskasoftware.hexpat`](patterns/fas_oskasoftware.hexpat) [`patterns/fas_oskasoftware_old.hexpat`](patterns/fas_oskasoftware_old.hexpat) (Old versions of Oska DeskMate) | Oska Software DeskMates FAS (Frames and Sequences) file |
| FAT32 | | [`patterns/fs/fat32.hexpat`](patterns/fs/fat32.hexpat) | FAT32 File System |
| FAT32 (DFIR) | | [`patterns/DFIR/FAT32.hexpat`](patterns/DFIR/FAT32.hexpat) | Imported by DISK_PARSER.hexpat |
| FBX | | [`patterns/fbx.hexpat`](patterns/fbx.hexpat) | Kaydara FBX Binary |
| FDT | | [`patterns/fdt.hexpat`](patterns/fdt.hexpat) | Flat Linux Device Tree blob |
| FFX | | [`patterns/ffx/*`](https://gitlab.com/EvelynTSMG/imhex-ffx-pats) | Various Final Fantasy X files |
| File System | | [`patterns/fs.hexpat`](patterns/fs.hexpat) | Drive File System |
| File System | `application/x-ima` | [`patterns/fs/pattern.hexpat`](patterns/fs/pattern.hexpat) | Drive File System |
| FLAC | `audio/flac` | [`patterns/flac.hexpat`](patterns/flac.hexpat) | Free Lossless Audio Codec, FLAC Audio Format |
| FLC/FLIC | | [`patterns/flc.hexpat`](patterns/flc.hexpat) | FLC/FLIC animation file |
| FLV | | [`patterns/flv.hexpat`](patterns/flv.hexpat) | FLv animation file |
| Flipper Zero Settings | | [`patterns/flipper_settings.hexpat`](patterns/flipper_settings.hexpat) | Flipper Zero Settings Files |
| GB | `application/x-gameboy-rom` | [`patterns/gb.hexpat`](patterns/gb.hexpat) | Game Boy ROM |
| GBA | `application/x-gameboy-advance-rom` | [`patterns/gba.hexpat`](patterns/gba.hexpat) | Game Boy Advance ROM header |
| GBX | | [`patterns/gbx.hexpat`](patterns/gbx.hexpat) | GameBoy ROM file GBX footer |
| Gen | | [`patterns/gen.hexpat`](patterns/gen.hexpat) | Sega Genesis/MegaDrive ROM |
| GGUF | | [`patterns/gguf.hexpat`](patterns/gguf.hexpat) | GGML Inference Models |
| GIF | `image/gif` | [`patterns/gif.hexpat`](patterns/gif.hexpat) | GIF image files |
| GLTF | `model/gltf-binary` | [`patterns/gltf.hexpat`](patterns/gltf.hexpat) | GL Transmission Format binary 3D model file |
@@ -81,16 +112,23 @@ Everything will immediately show up in ImHex's Content Store and gets bundled wi
| Halo Tag || [`patterns/hinf_tag.hexpat`](patterns/hinf_tag.hexpat) | Halo Infinite Tag Files |
| Halo Module || [`patterns/hinf_module.hexpat`](patterns/hinf_module.hexpat) | Halo Infinite Module Archive Files |
| Halo HavokScript || [`patterns/hinf_luas.hexpat`](patterns/hinf_luas.hexpat) | Halo Infinite HavokScript 5.1 Bytecode |
| HPROF || [`patterns/hprof.hexpat`](patterns/hprof.hexpat) | Java HPROF Profiler Data Format |
| HSDT || [`patterns/hsdt.hexpat`](patterns/hsdt.hexpat) | HiSilicon device-tree table images |
| ICO | | [`patterns/ico.hexpat`](patterns/ico.hexpat) | Icon (.ico) or Cursor (.cur) files |
| ID3 | `audio/mpeg` | [`patterns/id3.hexpat`](patterns/id3.hexpat) | ID3 tags in MP3 files |
| IM*H || [`patterns/imah.hexpat`](patterns/imah.hexpat) | DJI Signed Firmware (IM*H) |
| Intel HEX | | [`patterns/intel_hex.hexpat`](patterns/intel_hex.hexpat) | [Intel hexadecimal object file format definition]("https://en.wikipedia.org/wiki/Intel_HEX") |
| IP | | [`patterns/ip.hexpat`](patterns/ip.hexpat) | Ethernet II Frames (IP Packets) |
| IPS | | [`patterns/ips.hexpat`](patterns/ips.hexpat) | IPS (International Patching System) files |
| ISO | | [`patterns/iso.hexpat`](patterns/iso.hexpat) | ISO 9660 file system |
| ISO | `application/x-iso9660-image` | [`patterns/iso.hexpat`](patterns/iso.hexpat) | ISO 9660 file system |
| Java Class | `application/x-java-applet` | [`patterns/java_class.hexpat`](patterns/java_class.hexpat) | Java Class files |
| JPEG | `image/jpeg` | [`patterns/jpeg.hexpat`](patterns/jpeg.hexpat) | JPEG Image Format |
| Kindle Update | | [`patterns/kindle_update.hexpat`](patterns/kindle_update.hexpat) | Kindle Update Package |
| KTX | `image/ktx` | [`patterns/ktx.hexpat`](patterns/ktx.hexpat) | Khronos TeXture 1.0 |
| LOC | | [`patterns/loc.hexpat`](patterns/loc.hexpat) | Minecraft Legacy Console Edition Language file |
| Lua 4.0 | | [`patterns/lua40.hexpat`](patterns/lua40.hexpat) | Lua 4.0 bytecode |
| LUC | | [`patterns/popcap_luc.hexpat`](patterns/popcap_luc.hexpat) | PopCap's proprietary Lua bytecode |
| Lua 5.0 | | [`patterns/lua50.hexpat`](patterns/lua50.hexpat) | Lua 5.0 bytecode |
| Lua 5.1 | | [`patterns/lua51.hexpat`](patterns/lua51.hexpat) | Lua 5.1 bytecode |
| Lua 5.2 | | [`patterns/lua52.hexpat`](patterns/lua52.hexpat) | Lua 5.2 bytecode |
| Lua 5.3 | | [`patterns/lua53.hexpat`](patterns/lua53.hexpat) | Lua 5.3 bytecode |
@@ -100,25 +138,40 @@ Everything will immediately show up in ImHex's Content Store and gets bundled wi
| Mach-O | `application/x-mach-binary` | [`patterns/macho.hexpat`](patterns/macho.hexpat) | Mach-O executable |
| MIDI | `audio/midi` | [`patterns/midi.hexpat`](patterns/midi.hexpat) | MIDI header, event fields provided |
| MiniDump | `application/x-dmp` | [`patterns/minidump.hexpat`](patterns/minidump.hexpat) | Windows MiniDump files |
| MO | | [`patterns/mo.hexpat`](patterns/mo.hexpat) | GNU Machine Object (MO) files containing translations for gettext |
| mp4 | `video/mp4` | [`patterns/mp4.hexpat`](patterns/mp4.hexpat) | MPEG-4 Part 14 digital multimedia container format |
| msgpack | `application/x-msgpack` | [`patterns/msgpack.hexpat`](patterns/msgpack.hexpat) | MessagePack binary serialization format |
| MSSCMP | | [`patterns/msscmp.hexpat`](patterns/msscmp.hexpat) | Miles Sound System Compressed Archive |
| NACP | | [`patterns/nacp.hexpat`](patterns/nacp.hexpat) | Nintendo Switch NACP files |
| NBT | | [`patterns/nbt.hexpat`](patterns/nbt.hexpat) | Minecraft NBT format |
| NE | | [`patterns/ne.hexpat`](patterns/ne.hexpat) | NE header and Standard NE fields |
| nes | | [`patterns/nes.hexpat`](patterns/nes.hexpat) | .nes file format |
| N64 | | [`patterns/n64.hexpat`](patterns/n64.hexpat) | Nintendo 64 ROM header |
| NDS | `application/x-nintendo-ds-rom` | [`patterns/nds.hexpat`](patterns/nds.hexpat) | DS Cartridge Header |
| NE | `application/x-ms-ne-executable` | [`patterns/ne.hexpat`](patterns/ne.hexpat) | NE header and Standard NE fields |
| nes | | [`patterns/nes.hexpat`](patterns/nes.hexpat) | Nintendo Entertainment System ROM |
| NSF | | [`patterns/nsf.hexpat`](patterns/nsf.hexpat) | NES Sound Format |
| NSFe | | [`patterns/nsfe.hexpat`](patterns/nsfe.hexpat) | NES Sound Format extended |
| NotepadCache | | [`patterns/notepad-cache.hexpat`](patterns/notepad-cache.hexpat) | Windows Notepad Cache |
| NotepadStateFile | | [`patterns/notepad-state.hexpat`](patterns/notepad-state.hexpat) | Windows Notepad .bin State files |
| NotepadWindowState | | [`patterns/notepadwindowstate.hexpat`](patterns/notepadwindowstate.hexpat) | Windows 11 Notepad - Window State .bin file |
| NRO | | [`patterns/nro.hexpat`](patterns/nro.hexpat) | Nintendo Switch NRO files |
| NTAG | | [`patterns/ntag.hexpat`](patterns/ntag.hexpat) | NTAG213/NTAG215/NTAG216, NFC Forum Type 2 Tag compliant IC |
| NTFS | | [`patterns/fs/ntfs.hexpat`](patterns/fs/ntfs.hexpat) | NTFS (NT File System) |
| NTFS (DFIR) | | [`patterns/DFIR/NTFS.hexpat`](patterns/DFIR/NTFS.hexpat) | Imported by DISK_PARSER.hexpat |
| OGG | `audio/ogg` | [`patterns/ogg.hexpat`](patterns/ogg.hexpat) | OGG Audio format |
| ORP / ORS | | [`patterns/orp.hexpat`](patterns/orp.hexpat) | OpenRGB profile format |
| PACK | | [`patterns/roblox_pack.hexpat`](patterns/roblox_pack.hexpat) | Roblox shader archive format |
| PAK | | [`patterns/xgspak.hexpat`](patterns/xgspak.hexpat) | Exient XGS Engine Pak files |
| PCAP | `application/vnd.tcpdump.pcap` | [`patterns/pcap.hexpat`](patterns/pcap.hexpat) | pcap header and packets |
| PcapNG | `application/vnd.tcpdump.pcap` | [`patterns/pcapng.hexpat`](patterns/pcapng.hexpat) | pcapng header and packets |
| PCK | | [`patterns/pck.hexpat`](patterns/pck.hexpat) | Minecraft Legacy Console Edition .pck file |
| PCX | `application/x-pcx` | [`patterns/pcx.hexpat`](patterns/pcx.hexpat) | PCX Image format |
| PE | `application/x-dosexec` `application/x-msdownload` | [`patterns/pe.hexpat`](patterns/pe.hexpat) | PE header, COFF header, Standard COFF fields and Windows Specific fields |
| PP | | [`patterns/selinuxpp.hexpat`](patterns/selinuxpp.pat) | SE Linux package |
| PE | `application/x-dosexec` `application/x-msdownload` | [`patterns/pe.hexpat`](patterns/pe.hexpat) | PE header, COFF header, Standard COFF fields and Windows Specific fields |
| PEF | | [`patterns/pef.hexpat`](patterns/pef.hexpat) | Preffered Executable Format executable (for Mac OS 7.1.2 - Mac OS 10.4 / BeOS) |
| PEX | | [`patterns/pex.hexpat`](patterns/pex.hexpat) | Bethesda Papyrus executable compiled script file |
| PP | | [`patterns/selinuxpp.hexpat`](patterns/selinuxpp.pat) | SE Linux package |
| PFS0 | | [`patterns/pfs0.hexpat`](patterns/pfs0.hexpat) | Nintendo Switch PFS0 archive (NSP files) |
| PF | | [`patterns/pf.hexpat`](patterns/pf.hexpat) | Microsoft uncompressed prefetch files (.pf) |
| Pickle | | [`patterns/pickle.hexpat`](patterns/pickle.hexpat) | Python Pickle Protocol |
| PIF | `image/pif` | [`patterns/pif.hexpat`](patterns/pif.hexpat) | PIF Image Format |
| PKM | | [`patterns/pkm.hexpat`](patterns/pkm.hexpat) | PKM texture format |
| PNG | `image/png` | [`patterns/png.hexpat`](patterns/png.hexpat) | PNG image files |
@@ -126,46 +179,73 @@ Everything will immediately show up in ImHex's Content Store and gets bundled wi
| Protobuf | | [`patterns/protobuf.hexpat`](patterns/protobuf.hexpat) | Google Protobuf encoding |
| psafe3 | | [`patterns/psafe3.hexpat`](patterns/psafe3.hexpat`) | Password Safe V3 |
| PyInstaller | | [`patterns/pyinstaller.hexpat`](patterns/pyinstaller.hexpat) | PyInstaller binray files |
| PYC | | [`patterns/pyc.hexpat`](patterns/pyc.hexpat) | Python bytecode files |
| PYC | `application/x-bytecode.python` | [`patterns/pyc.hexpat`](patterns/pyc.hexpat) | Python bytecode files |
| QBCL | | [`patterns/qbcl.hexpat`](patterns/qbcl.hexpat) | Qubicle voxel scene project file |
| QOI | `image/qoi` | [`patterns/qoi.hexpat`](patterns/qoi.hexpat) | QOI image files |
| QOI | `image/qoi` | [`patterns/qoi.hexpat`](patterns/qoi.hexpat) | QOI image files |
| Quake 3 engine demo | | [`patterns/q3demo.hexpat`](patterns/q3demo.hexpat) | Demos/replays of most Quake 3 engine games |
| quantized-mesh | | [`patterns/quantized-mesh.hexpat`](patterns/quantized-mesh.hexpat) | Cesium quantized-mesh terrain |
| RAR | `application/x-rar` | [`patterns/rar.hexpat`](patterns/rar.hexpat) | RAR archive file format |
| RAS | `image/x-sun-raster` | [`patterns/ras.hexpat`](patterns/ras.hexpat) | RAS image files |
| ReFS | | [`patterns/refs.hexpat`](patterns/refs.hexpat) | Microsoft Resilient File System |
| RAS | `image/x-sun-raster` | [`patterns/ras.hexpat`](patterns/ras.hexpat) | RAS image files |
| RCF 1.2 | | [`patterns/rcf_v1_2.hexpat`](patterns/rcf_v1_2.hexpat) | Radcore Cement Library 1.2 file header |
| ReFS | | [`patterns/refs.hexpat`](patterns/fs/refs.hexpat) | Microsoft Resilient File System |
| RGBDS | | [`patterns/rgbds.hexpat`](patterns/rgbds.hexpat) | [RGBDS](https://rgbds.gbdev.io) object file format |
| RPM | | [`patterns/rpm.hexpat`](patterns/rpm.hexpat) | [RPM](http://ftp.rpm.org/max-rpm/s1-rpm-file-format-rpm-file-format.html) package file format |
| SDB | | [`patterns/sdb.hexpat`](patterns/sdb.hexpat) | [Shim DataBase](https://learn.microsoft.com/en-us/windows/win32/devnotes/application-compatibility-database) file format |
| Shell Link | `application/x-ms-shortcut` | [`patterns/lnk.hexpat`](patterns/lnk.hexpat) | Windows Shell Link file format |
| shp | | [`patterns/shp.hexpat`](patterns/shp.hexpat) | ESRI shape file |
| SHR | | [`patterns/SHR.hexpat`](patterns/SHR.hexpat) | Apple IIgs Super Hi-Res (SHR) + PaintWorks Animation (ANI) |
| shx | | [`patterns/shx.hexpat`](patterns/shx.hexpat) | ESRI index file |
| smk | | [`patterns/smk.hexpat`](patterns/smk.hexpat) | Smacker video file |
| SNES | | [`patterns/snes.hexpat`](patterns/snes.hexpat) | Super Nintendo Entertainment System ROM header |
| sup | | [`patterns/sup.hexpat`](patterns/sup.hexpat) | PGS Subtitle |
| SPC | | [`patterns/spc.hexpat`](patterns/spc.hexpat) | Super Nintendo Entertainment System SPC-700 dump file |
| SPIRV | | [`patterns/spirv.hexpat`](patterns/spirv.hexpat) | SPIR-V header and instructions |
| STDF | | [`patterns/stdfv4.hexpat`](patterns/stdfv4.hexpat) | Standard test data format for IC testers |
| 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 |
| SWF | |[`patterns/swf.hexpat`](patterns/swf.hexpat) | Shockwave Flash file format |
| SQLite3 | `application/vnd.sqlite3` | [`patterns/sqlite3.hexpat`](patterns/sqlite3.hexpat) | SQLite3 Database |
| 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 |
| TGA | `image/tga` | [`patterns/tga.hexpat`](patterns/tga.hexpat) | Truevision TGA/TARGA image |
| TTF | `font/ttf`, `font/otf` | [`patterns/ttf.hexpat`](patterns/ttf.hexpat) | TrueType and OpenType font format |
| Ubiquiti | | [`patterns/ubiquiti.hexpat`](patterns/ubiquiti.hexpat) | Ubiquiti Firmware (update) image |
| UPK | | [`patterns/upk-ue3.hexpat`](patterns/upk-ue3.hexpat) | Unreal Engine 3 UPK file |
| UEFI | | [`patterns/uefi.hexpat`](patterns/uefi.hexpat)` | UEFI structs for parsing efivars |
| UEFI Boot Entry | | [`patterns/uefi_boot_entry.hexpat`](patterns/uefi_boot_entry.hexpat) | UEFI Boot Entry (Load option) |
| UEFI Variable Store | | [`patterns/uefi_fv_varstore.hexpat`](patterns/uefi_fv_varstore.hexpat) | UEFI Firmware Volume Variable Store |
| UF2 | | [`patterns/uf2.hexpat`](patterns/uf2.hexpat) | [USB Flashing Format](https://github.com/microsoft/uf2) |
| Unity Asset Bundle | | [`patterns/unity-asset-bundle.hexpat`](patterns/unity-asset-bundle.hexpat) | Unity Asset Bundle |
| Valve VPK | | [`patterns/valve_vpk.hexpat`](valve_vpk.hexpat) | Valve Package File |
| VBMeta | | [`patterns/vbmeta.hexpat`](patterns/vbmeta.hexpat) | Android VBMeta image |
| VDF | | [`patterns/vdf.hexpat`](patterns/vdf.hexpat) | Binary Value Data Format (.vdf) files |
| VEADO | | [`patterns/veado.hexpat`](patterns/veado.hexpat) | veadotube mini avatar file |
| VGM | | [`patterns/vgm.hexpat`](patterns/vgm.hexpat) | VGM (Video Game Music) sound log |
| VHDX | | [`patterns/vhdx.hexpat`](patterns/vhdx.hexpat) | Microsoft Hyper-V Virtual Hard Disk format |
| VOX | | [`patterns/vox.hexpat`](patterns/vox.hexpat) | MagicaVoxel scene description format |
| WAV | `audio/x-wav` | [`patterns/wav.hexpat`](patterns/wav.hexpat) | RIFF header, WAVE header, PCM header |
| WAS | | [`patterns\was_oskasoftware.hexpat`](patterns\was_oskasoftware.hexpat) | Oska Software DeskMates WAS/WA3 (WAVE/MP3 Set) file
| WAS | | [`patterns/was_oskasoftware.hexpat`](patterns/was_oskasoftware.hexpat) | Oska Software DeskMates WAS/WA3 (WAVE/MP3 Set) file
| WAD | | [`patterns/wad.hexpat`](patterns/wad.hexpat) | DOOM WAD Archive |
| WebP | `image/webp` | [`patterns/webp.hexpat`](patterns/webp.hexpat) | Google WebP image |
| XBEH | `audio/x-xbox-executable` | [`patterns/xbeh.hexpat`](patterns/xbeh.hexpat) | Xbox executable |
| XCI | | [`patterns/xci.hexpat`](patterns/xci.hexpat) | Nintendo Switch XCI cartridge ROM |
| 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 | | [`patterns/xilinx_bootgen.hexpat`](patterns/xilinx_bootgen.hexpat) | Xilinx ZynqMP Boot Images |
| 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 |
| MOD | `3d-model/mod` | [`patterns/DMC3HD-Mod.hexpat`](patterns/dmc3_hd_mod.hexpat) | 3D Model files used in Devil May Cry 3 HD Collection |
| CBM BASIC | | [`commodore_basic.hexpat`](patterns/commodore_basic.hexpat) | Commodore BASIC |
| Atari XEX | | [`xex.hexpat`](patterns/xex.hexpat) | Atari 8-bit binary format |
| Terminfo | `application/x-terminfo` and `application/x-terminfo2` | [`patterns/terminfo.hexpat`](patterns/terminfo.hexpat) | Compiled *(legacy and extended)* term info entry |
### Scripts
@@ -192,6 +272,7 @@ Everything will immediately show up in ImHex's Content Store and gets bundled wi
| Name | Path | Description |
|------|------|-------------|
| Arma 3 | [`magic/arma3_magic`](magic/arma3_magic) | Identifies Arma 3 binary formats |
| Nintendo Switch | [`magic/nintendo_switch_magic`](magic/nintendo_switch_magic) | Identifies common file types used on the Nintendo Switch |
| Portable Executable | [`magic/portable_executable_magic`](magic/portable_executable_magic) | Identifies PE files used on Windows
@@ -261,3 +342,11 @@ Everything will immediately show up in ImHex's Content Store and gets bundled wi
| Catppuccin Frappe | [`themes/catppuccin-frappe.json`](themes/catppuccin-frappe.json) | Catppuccin Frappe Flavor (Dark Theme) |
| Catppuccin Macchiato | [`themes/catppuccin-macchiato.json`](themes/catppuccin-macchiato.json) | Catppuccin Macchiato Flavor (Dark Theme) |
| Catppuccin Mocha | [`themes/catppuccin-mocha.json`](themes/catppuccin-mocha.json) | Catppuccin Mocha Flavor (Dark Theme) |
| Theme Lion | [`themes/theme_lion.json`](themes/theme_lion.json) | Semantic CLion inspired theme (Dark Theme) |
| Retina Dark | [`themes/retina_dark.json`](themes/retina_dark.json) | Semantic theme based on Dark Theme |
### Disassemblers
| Name | Path | Description |
|------|------|-------------|
| 8051 | [`disassemblers/8051.json`](disassemblers/8051.json) | Intel 8051 Architecture |

View File

@@ -29,23 +29,10 @@
"title": "Items",
"type": "object",
"required": [
"type",
"value",
"name"
],
"properties": {
"type": {
"$id": "#root/values/items/type",
"title": "Type",
"type": "string",
"default": "",
"examples": [
"int16be",
"int16le",
"int10"
],
"pattern": "^(int10|int16le|int16be)$"
},
"value": {
"$id": "#root/values/items/value",
"title": "Value",
@@ -54,7 +41,7 @@
"examples": [
"ACDC"
],
"pattern": "^([0-9a-fA-F]+)$"
"pattern": "^.*$"
},
"name": {
"$id": "#root/values/items/name",

View File

@@ -2,118 +2,95 @@
"name": "CRC16 Constants",
"values": [
{
"type": "int16be",
"value": "1021",
"value": "10 21",
"name": "CRC-16/CCITT-FALSE Polynomial"
},
{
"type": "int16be",
"value": "8005",
"value": "80 05",
"name": "CRC-16/ARC Polynomial"
},
{
"type": "int16be",
"value": "1021",
"value": "10 21",
"name": "CRC-16/AUG-CCITT Polynomial"
},
{
"type": "int16be",
"value": "8005",
"value": "80 05",
"name": "CRC-16/BUYPASS Polynomial"
},
{
"type": "int16be",
"value": "C867",
"value": "C8 67",
"name": "CRC-16/CDMA2000 Polynomial"
},
{
"type": "int16be",
"value": "8005",
"value": "80 05",
"name": "CRC-16/DDS-110 Polynomial"
},
{
"type": "int16be",
"value": "0589",
"value": "05 89",
"name": "CRC-16/DECT-R Polynomial"
},
{
"type": "int16be",
"value": "0589",
"value": "05 89",
"name": "CRC-16/DECT-X Polynomial"
},
{
"type": "int16be",
"value": "3D65",
"value": "3D 65",
"name": "CRC-16/DNP Polynomial"
},
{
"type": "int16be",
"value": "3D65",
"value": "3D 65",
"name": "CRC-16/EN-13757 Polynomial"
},
{
"type": "int16be",
"value": "1021",
"value": "10 21",
"name": "CRC-16/GENIBUS Polynomial"
},
{
"type": "int16be",
"value": "8005",
"value": "80 05",
"name": "CRC-16/MAXIM Polynomial"
},
{
"type": "int16be",
"value": "1021",
"value": "10 21",
"name": "CRC-16/MCRF4XX Polynomial"
},
{
"type": "int16be",
"value": "1021",
"value": "10 21",
"name": "CRC-16/RIELLO Polynomial"
},
{
"type": "int16be",
"value": "8BB7",
"value": "8B B7",
"name": "CRC-16/T10-DIF Polynomial"
},
{
"type": "int16be",
"value": "A097",
"value": "A0 97",
"name": "CRC-16/TELEDISK Polynomial"
},
{
"type": "int16be",
"value": "1021",
"value": "10 21",
"name": "CRC-16/TMS37157 Polynomial"
},
{
"type": "int16be",
"value": "8005",
"value": "80 05",
"name": "CRC-16/USB Polynomial"
},
{
"type": "int16be",
"value": "1021",
"value": "10 21",
"name": "CRC-A Polynomial"
},
{
"type": "int16be",
"value": "1021",
"value": "10 21",
"name": "CRC-16/KERMIT Polynomial"
},
{
"type": "int16be",
"value": "8005",
"value": "80 05",
"name": "CRC-16/MODBUS Polynomial"
},
{
"type": "int16be",
"value": "1021",
"value": "10 21",
"name": "CRC-16/X-25 Polynomial"
},
{
"type": "int16be",
"value": "1021",
"value": "10 21",
"name": "CRC-16/XMODEM Polynomial"
}
]

View File

@@ -2,48 +2,39 @@
"name": "CRC32 Constants",
"values": [
{
"type": "int16be",
"value": "04C11DB7",
"value": "04 C1 1D B7",
"name": "CRC-32 Polynomial"
},
{
"type": "int16be",
"value": "04C11DB7",
"value": "04 C1 1D B7",
"name": "CRC-32/BZIP2 Polynomial"
},
{
"type": "int16be",
"value": "1EDC6F41",
"value": "1E DC 6F 41",
"name": "CRC-32C Polynomial"
},
{
"type": "int16be",
"value": "A833982B",
"value": "A8 33 98 2B",
"name": "CRC-32D Polynomial"
},
{
"type": "int16be",
"value": "04C11DB7",
"value": "04 C1 1D B7",
"name": "CRC-32/MPEG-2 Polynomial"
},
{
"type": "int16be",
"value": "04C11DB7",
"value": "04 C1 1D B7",
"name": "CRC-32/POSIX Polynomial"
},
{
"type": "int16be",
"value": "814141AB",
"value": "81 41 41 AB",
"name": "CRC-32Q Polynomial"
},
{
"type": "int16be",
"value": "04C11DB7",
"value": "04 C1 1D B7",
"name": "CRC-32/JAMCRC Polynomial"
},
{
"type": "int16be",
"value": "000000AF",
"value": "00 00 00 AF",
"name": "CRC-32/XFER Polynomial"
}
]

View File

@@ -1,315 +0,0 @@
{
"name": "HTTP Status Codes",
"values": [
{
"type": "int10",
"value": "100",
"name": "Continue"
},
{
"type": "int10",
"value": "101",
"name": "Switching Protocols"
},
{
"type": "int10",
"value": "102",
"name": "Processing (WebDAV; RFC 2518)"
},
{
"type": "int10",
"value": "103",
"name": "Early Hints (RFC 8297)"
},
{
"type": "int10",
"value": "200",
"name": "OK"
},
{
"type": "int10",
"value": "201",
"name": "Created"
},
{
"type": "int10",
"value": "202",
"name": "Accepted"
},
{
"type": "int10",
"value": "203",
"name": "Non-Authoritative Information (since HTTP/1.1)"
},
{
"type": "int10",
"value": "204",
"name": "No Content"
},
{
"type": "int10",
"value": "205",
"name": "Reset Content"
},
{
"type": "int10",
"value": "206",
"name": "Partial Content (RFC 7233)"
},
{
"type": "int10",
"value": "207",
"name": "Multi-Status (WebDAV; RFC 4918)"
},
{
"type": "int10",
"value": "208",
"name": "Already Reported (WebDAV; RFC 5842)"
},
{
"type": "int10",
"value": "226",
"name": "IM Used (RFC 3229)"
},
{
"type": "int10",
"value": "300",
"name": "Multiple Choices"
},
{
"type": "int10",
"value": "301",
"name": "Moved Permanently"
},
{
"type": "int10",
"value": "302",
"name": "Found (Previously \"Moved temporarily\")"
},
{
"type": "int10",
"value": "303",
"name": "See Other (since HTTP/1.1)"
},
{
"type": "int10",
"value": "304",
"name": "Not Modified (RFC 7232)"
},
{
"type": "int10",
"value": "305",
"name": "Use Proxy (since HTTP/1.1)"
},
{
"type": "int10",
"value": "306",
"name": "Switch Proxy"
},
{
"type": "int10",
"value": "307",
"name": "Temporary Redirect (since HTTP/1.1)"
},
{
"type": "int10",
"value": "308",
"name": "Permanent Redirect (RFC 7538)"
},
{
"type": "int10",
"value": "400",
"name": "Bad Request"
},
{
"type": "int10",
"value": "401",
"name": "Unauthorized (RFC 7235)"
},
{
"type": "int10",
"value": "402",
"name": "Payment Required"
},
{
"type": "int10",
"value": "403",
"name": "Forbidden"
},
{
"type": "int10",
"value": "404",
"name": "Not Found"
},
{
"type": "int10",
"value": "405",
"name": "Method Not Allowed"
},
{
"type": "int10",
"value": "406",
"name": "Not Acceptable"
},
{
"type": "int10",
"value": "407",
"name": "Proxy Authentication Required (RFC 7235)"
},
{
"type": "int10",
"value": "408",
"name": "Request Timeout"
},
{
"type": "int10",
"value": "409",
"name": "Conflict"
},
{
"type": "int10",
"value": "410",
"name": "Gone"
},
{
"type": "int10",
"value": "411",
"name": "Length Required"
},
{
"type": "int10",
"value": "412",
"name": "Precondition Failed (RFC 7232)"
},
{
"type": "int10",
"value": "413",
"name": "Payload Too Large (RFC 7231)"
},
{
"type": "int10",
"value": "414",
"name": "URI Too Long (RFC 7231)"
},
{
"type": "int10",
"value": "415",
"name": "Unsupported Media Type (RFC 7231)"
},
{
"type": "int10",
"value": "416",
"name": "Range Not Satisfiable (RFC 7233)"
},
{
"type": "int10",
"value": "417",
"name": "Expectation Failed"
},
{
"type": "int10",
"value": "418",
"name": "I'm a teapot (RFC 2324, RFC 7168)"
},
{
"type": "int10",
"value": "421",
"name": "Misdirected Request (RFC 7540)"
},
{
"type": "int10",
"value": "422",
"name": "Unprocessable Entity (WebDAV; RFC 4918)"
},
{
"type": "int10",
"value": "424",
"name": "Failed Dependency (WebDAV; RFC 4918)"
},
{
"type": "int10",
"value": "425",
"name": "Too Early (RFC 8470)"
},
{
"type": "int10",
"value": "426",
"name": "Upgrade Required"
},
{
"type": "int10",
"value": "428",
"name": "Precondition Required (RFC 6585)"
},
{
"type": "int10",
"value": "429",
"name": "Too Many Requests (RFC 6585)"
},
{
"type": "int10",
"value": "431",
"name": "Request Header Fields Too Large (RFC 6585)"
},
{
"type": "int10",
"value": "451",
"name": "Unavailable For Legal Reasons (RFC 7725)"
},
{
"type": "int10",
"value": "500",
"name": "Internal Server Error"
},
{
"type": "int10",
"value": "501",
"name": "Not Implemented"
},
{
"type": "int10",
"value": "502",
"name": "Bad Gateway"
},
{
"type": "int10",
"value": "503",
"name": "Service Unavailable"
},
{
"type": "int10",
"value": "504",
"name": "Gateway Timeout"
},
{
"type": "int10",
"value": "505",
"name": "HTTP Version Not Supported"
},
{
"type": "int10",
"value": "506",
"name": "Variant Also Negotiates (RFC 2295)"
},
{
"type": "int10",
"value": "507",
"name": "Insufficient Storage (WebDAV; RFC 4918)"
},
{
"type": "int10",
"value": "508",
"name": "Loop Detected (WebDAV; RFC 5842)"
},
{
"type": "int10",
"value": "510",
"name": "Not Extended (RFC 2774)"
},
{
"type": "int10",
"value": "511",
"name": "Network Authentication Required (RFC 6585)"
}
]
}

View File

@@ -1,780 +0,0 @@
{
"name": "Linux Error Codes",
"values": [
{
"type": "int10",
"value": "1",
"name": "EPERM",
"desc": "Operation not permitted"
},
{
"type": "int10",
"value": "2",
"name": "ENOENT",
"desc": "No such file or directory"
},
{
"type": "int10",
"value": "3",
"name": "ESRCH",
"desc": "No such process"
},
{
"type": "int10",
"value": "4",
"name": "EINTR",
"desc": "Interrupted system call"
},
{
"type": "int10",
"value": "5",
"name": "EIO",
"desc": "I/O error"
},
{
"type": "int10",
"value": "6",
"name": "ENXIO",
"desc": "No such device or address"
},
{
"type": "int10",
"value": "7",
"name": "E2BIG",
"desc": "Argument list too long"
},
{
"type": "int10",
"value": "8",
"name": "ENOEXEC",
"desc": "Exec format error"
},
{
"type": "int10",
"value": "9",
"name": "EBADF",
"desc": "Bad file value"
},
{
"type": "int10",
"value": "10",
"name": "ECHILD",
"desc": "No child processes"
},
{
"type": "int10",
"value": "11",
"name": "EAGAIN",
"desc": "Try again"
},
{
"type": "int10",
"value": "12",
"name": "ENOMEM",
"desc": "Out of memory"
},
{
"type": "int10",
"value": "13",
"name": "EACCES",
"desc": "Permission denied"
},
{
"type": "int10",
"value": "14",
"name": "EFAULT",
"desc": "Bad address"
},
{
"type": "int10",
"value": "15",
"name": "ENOTBLK",
"desc": "Block device required"
},
{
"type": "int10",
"value": "16",
"name": "EBUSY",
"desc": "Device or resource busy"
},
{
"type": "int10",
"value": "17",
"name": "EEXIST",
"desc": "File exists"
},
{
"type": "int10",
"value": "18",
"name": "EXDEV",
"desc": "Cross-device link"
},
{
"type": "int10",
"value": "19",
"name": "ENODEV",
"desc": "No such device"
},
{
"type": "int10",
"value": "20",
"name": "ENOTDIR",
"desc": "Not a directory"
},
{
"type": "int10",
"value": "21",
"name": "EISDIR",
"desc": "Is a directory"
},
{
"type": "int10",
"value": "22",
"name": "EINVAL",
"desc": "Invalid argument"
},
{
"type": "int10",
"value": "23",
"name": "ENFILE",
"desc": "File table overflow"
},
{
"type": "int10",
"value": "24",
"name": "EMFILE",
"desc": "Too many open files"
},
{
"type": "int10",
"value": "25",
"name": "ENOTTY",
"desc": "Not a typewriter"
},
{
"type": "int10",
"value": "26",
"name": "ETXTBSY",
"desc": "Text file busy"
},
{
"type": "int10",
"value": "27",
"name": "EFBIG",
"desc": "File too large"
},
{
"type": "int10",
"value": "28",
"name": "ENOSPC",
"desc": "No space left on device"
},
{
"type": "int10",
"value": "29",
"name": "ESPIPE",
"desc": "Illegal seek"
},
{
"type": "int10",
"value": "30",
"name": "EROFS",
"desc": "Read-only file system"
},
{
"type": "int10",
"value": "31",
"name": "EMLINK",
"desc": "Too many links"
},
{
"type": "int10",
"value": "32",
"name": "EPIPE",
"desc": "Broken pipe"
},
{
"type": "int10",
"value": "33",
"name": "EDOM",
"desc": "Math argument out of domain of func"
},
{
"type": "int10",
"value": "34",
"name": "ERANGE",
"desc": "Math result not representable"
},
{
"type": "int10",
"value": "35",
"name": "EDEADLK",
"desc": "Resource deadlock would occur"
},
{
"type": "int10",
"value": "36",
"name": "ENAMETOOLONG",
"desc": "File name too long"
},
{
"type": "int10",
"value": "37",
"name": "ENOLCK",
"desc": "No record locks available"
},
{
"type": "int10",
"value": "38",
"name": "ENOSYS",
"desc": "Function not implemented"
},
{
"type": "int10",
"value": "39",
"name": "ENOTEMPTY",
"desc": "Directory not empty"
},
{
"type": "int10",
"value": "40",
"name": "ELOOP",
"desc": "Too many symbolic links encountered"
},
{
"type": "int10",
"value": "42",
"name": "ENOMSG",
"desc": "No message of desired type"
},
{
"type": "int10",
"value": "43",
"name": "EIDRM",
"desc": "Identifier removed"
},
{
"type": "int10",
"value": "44",
"name": "ECHRNG",
"desc": "Channel value out of range"
},
{
"type": "int10",
"value": "45",
"name": "EL2NSYNC",
"desc": "Level 2 not synchronized"
},
{
"type": "int10",
"value": "46",
"name": "EL3HLT",
"desc": "Level 3 halted"
},
{
"type": "int10",
"value": "47",
"name": "EL3RST",
"desc": "Level 3 reset"
},
{
"type": "int10",
"value": "48",
"name": "ELNRNG",
"desc": "Link value out of range"
},
{
"type": "int10",
"value": "49",
"name": "EUNATCH",
"desc": "Protocol driver not attached"
},
{
"type": "int10",
"value": "50",
"name": "ENOCSI",
"desc": "No CSI structure available"
},
{
"type": "int10",
"value": "51",
"name": "EL2HLT",
"desc": "Level 2 halted"
},
{
"type": "int10",
"value": "52",
"name": "EBADE",
"desc": "Invalid exchange"
},
{
"type": "int10",
"value": "53",
"name": "EBADR",
"desc": "Invalid request descriptor"
},
{
"type": "int10",
"value": "54",
"name": "EXFULL",
"desc": "Exchange full"
},
{
"type": "int10",
"value": "55",
"name": "ENOANO",
"desc": "No anode"
},
{
"type": "int10",
"value": "56",
"name": "EBADRQC",
"desc": "Invalid request code"
},
{
"type": "int10",
"value": "57",
"name": "EBADSLT",
"desc": "Invalid slot"
},
{
"type": "int10",
"value": "59",
"name": "EBFONT",
"desc": "Bad font file format"
},
{
"type": "int10",
"value": "60",
"name": "ENOSTR",
"desc": "Device not a stream"
},
{
"type": "int10",
"value": "61",
"name": "ENODATA",
"desc": "No data available"
},
{
"type": "int10",
"value": "62",
"name": "ETIME",
"desc": "Timer expired"
},
{
"type": "int10",
"value": "63",
"name": "ENOSR",
"desc": "Out of streams resources"
},
{
"type": "int10",
"value": "64",
"name": "ENONET",
"desc": "Machine is not on the network"
},
{
"type": "int10",
"value": "65",
"name": "ENOPKG",
"desc": "Package not installed"
},
{
"type": "int10",
"value": "66",
"name": "EREMOTE",
"desc": "Object is remote"
},
{
"type": "int10",
"value": "67",
"name": "ENOLINK",
"desc": "Link has been severed"
},
{
"type": "int10",
"value": "68",
"name": "EADV",
"desc": "Advertise error"
},
{
"type": "int10",
"value": "69",
"name": "ESRMNT",
"desc": "Srmount error"
},
{
"type": "int10",
"value": "70",
"name": "ECOMM",
"desc": "Communication error on send"
},
{
"type": "int10",
"value": "71",
"name": "EPROTO",
"desc": "Protocol error"
},
{
"type": "int10",
"value": "72",
"name": "EMULTIHOP",
"desc": "Multihop attempted"
},
{
"type": "int10",
"value": "73",
"name": "EDOTDOT",
"desc": "RFS specific error"
},
{
"type": "int10",
"value": "74",
"name": "EBADMSG",
"desc": "Not a data message"
},
{
"type": "int10",
"value": "75",
"name": "EOVERFLOW",
"desc": "Value too large for defined data type"
},
{
"type": "int10",
"value": "76",
"name": "ENOTUNIQ",
"desc": "Name not unique on network"
},
{
"type": "int10",
"value": "77",
"name": "EBADFD",
"desc": "File descriptor in bad state"
},
{
"type": "int10",
"value": "78",
"name": "EREMCHG",
"desc": "Remote address changed"
},
{
"type": "int10",
"value": "79",
"name": "ELIBACC",
"desc": "Can not access a needed shared library"
},
{
"type": "int10",
"value": "80",
"name": "ELIBBAD",
"desc": "Accessing a corrupted shared library"
},
{
"type": "int10",
"value": "81",
"name": "ELIBSCN",
"desc": ".lib section in a.out corrupted"
},
{
"type": "int10",
"value": "82",
"name": "ELIBMAX",
"desc": "Attempting to link in too many shared libraries"
},
{
"type": "int10",
"value": "83",
"name": "ELIBEXEC",
"desc": "Cannot exec a shared library directly"
},
{
"type": "int10",
"value": "84",
"name": "EILSEQ",
"desc": "Illegal byte sequence"
},
{
"type": "int10",
"value": "85",
"name": "ERESTART",
"desc": "Interrupted system call should be restarted"
},
{
"type": "int10",
"value": "86",
"name": "ESTRPIPE",
"desc": "Streams pipe error"
},
{
"type": "int10",
"value": "87",
"name": "EUSERS",
"desc": "Too many users"
},
{
"type": "int10",
"value": "88",
"name": "ENOTSOCK",
"desc": "Socket operation on non-socket"
},
{
"type": "int10",
"value": "89",
"name": "EDESTADDRREQ",
"desc": "Destination address required"
},
{
"type": "int10",
"value": "90",
"name": "EMSGSIZE",
"desc": "Message too long"
},
{
"type": "int10",
"value": "91",
"name": "EPROTOTYPE",
"desc": "Protocol wrong type for socket"
},
{
"type": "int10",
"value": "92",
"name": "ENOPROTOOPT",
"desc": "Protocol not available"
},
{
"type": "int10",
"value": "93",
"name": "EPROTONOSUPPORT",
"desc": "Protocol not supported"
},
{
"type": "int10",
"value": "94",
"name": "ESOCKTNOSUPPORT",
"desc": "Socket type not supported"
},
{
"type": "int10",
"value": "95",
"name": "EOPNOTSUPP",
"desc": "Operation not supported on transport endpoint"
},
{
"type": "int10",
"value": "96",
"name": "EPFNOSUPPORT",
"desc": "Protocol family not supported"
},
{
"type": "int10",
"value": "97",
"name": "EAFNOSUPPORT",
"desc": "Address family not supported by protocol"
},
{
"type": "int10",
"value": "98",
"name": "EADDRINUSE",
"desc": "Address already in use"
},
{
"type": "int10",
"value": "99",
"name": "EADDRNOTAVAIL",
"desc": "Cannot assign requested address"
},
{
"type": "int10",
"value": "100",
"name": "ENETDOWN",
"desc": "Network is down"
},
{
"type": "int10",
"value": "101",
"name": "ENETUNREACH",
"desc": "Network is unreachable"
},
{
"type": "int10",
"value": "102",
"name": "ENETRESET",
"desc": "Network dropped connection because of reset"
},
{
"type": "int10",
"value": "103",
"name": "ECONNABORTED",
"desc": "Software caused connection abort"
},
{
"type": "int10",
"value": "104",
"name": "ECONNRESET",
"desc": "Connection reset by peer"
},
{
"type": "int10",
"value": "105",
"name": "ENOBUFS",
"desc": "No buffer space available"
},
{
"type": "int10",
"value": "106",
"name": "EISCONN",
"desc": "Transport endpoint is already connected"
},
{
"type": "int10",
"value": "107",
"name": "ENOTCONN",
"desc": "Transport endpoint is not connected"
},
{
"type": "int10",
"value": "108",
"name": "ESHUTDOWN",
"desc": "Cannot send after transport endpoint shutdown"
},
{
"type": "int10",
"value": "109",
"name": "ETOOMANYREFS",
"desc": "Too many references: cannot splice"
},
{
"type": "int10",
"value": "110",
"name": "ETIMEDOUT",
"desc": "Connection timed out"
},
{
"type": "int10",
"value": "111",
"name": "ECONNREFUSED",
"desc": "Connection refused"
},
{
"type": "int10",
"value": "112",
"name": "EHOSTDOWN",
"desc": "Host is down"
},
{
"type": "int10",
"value": "113",
"name": "EHOSTUNREACH",
"desc": "No route to host"
},
{
"type": "int10",
"value": "114",
"name": "EALREADY",
"desc": "Operation already in progress"
},
{
"type": "int10",
"value": "115",
"name": "EINPROGRESS",
"desc": "Operation now in progress"
},
{
"type": "int10",
"value": "116",
"name": "ESTALE",
"desc": "Stale NFS file handle"
},
{
"type": "int10",
"value": "117",
"name": "EUCLEAN",
"desc": "Structure needs cleaning"
},
{
"type": "int10",
"value": "118",
"name": "ENOTNAM",
"desc": "Not a XENIX named type file"
},
{
"type": "int10",
"value": "119",
"name": "ENAVAIL",
"desc": "No XENIX semaphores available"
},
{
"type": "int10",
"value": "120",
"name": "EISNAM",
"desc": "Is a named type file"
},
{
"type": "int10",
"value": "121",
"name": "EREMOTEIO",
"desc": "Remote I/O error"
},
{
"type": "int10",
"value": "122",
"name": "EDQUOT",
"desc": "Quota exceeded"
},
{
"type": "int10",
"value": "123",
"name": "ENOMEDIUM",
"desc": "No medium found"
},
{
"type": "int10",
"value": "124",
"name": "EMEDIUMTYPE",
"desc": "Wrong medium type"
},
{
"type": "int10",
"value": "125",
"name": "ECANCELED",
"desc": "Operation Canceled"
},
{
"type": "int10",
"value": "126",
"name": "ENOKEY",
"desc": "Required key not available"
},
{
"type": "int10",
"value": "127",
"name": "EKEYEXPIRED",
"desc": "Key has expired"
},
{
"type": "int10",
"value": "128",
"name": "EKEYREVOKED",
"desc": "Key has been revoked"
},
{
"type": "int10",
"value": "129",
"name": "EKEYREJECTED",
"desc": "Key was rejected by service"
},
{
"type": "int10",
"value": "130",
"name": "EOWNERDEAD",
"desc": "Owner died"
},
{
"type": "int10",
"value": "131",
"name": "ENOTRECOVERABLE",
"desc": "State not recoverable"
}
]
}

730
disassemblers/8051.json Normal file
View File

@@ -0,0 +1,730 @@
{
"name": "Intel 8051",
"includes": [],
"options": [],
"opcodes": [
{
"mask": "0000'0000",
"mnemonic": "NOP",
"format": ""
},
{
"mask": "0000'0010 AAAA'AAAA AAAA'AAAA",
"mnemonic": "LJMP",
"format": "#0x{A:04X}",
"metadata": [
{
"type": "jump",
"data": {
"destination": "A"
}
}
]
},
{
"mask": "1000'0000 AAAA'AAAA",
"mnemonic": "SJMP",
"format": "#0x{A:02X}",
"metadata": [
{
"type": "jump",
"data": {
"destination": "A"
}
}
]
},
{
"mask": "0111'0011",
"mnemonic": "JMP",
"format": "@A+DPTR"
},
{
"mask": "0100'0000 AAAA'AAAA",
"mnemonic": "JC",
"format": "PC + 0x{A:02X}",
"metadata": [
{
"type": "jump",
"data": {
"destination": "offset + 2 + A"
}
}
]
},
{
"mask": "0011'0000 BBBB'BBBB AAAA'AAAA",
"mnemonic": "JNB",
"format": "BIT[0x{B:02X}], PC + 0x{A:02X}",
"metadata": [
{
"type": "jump",
"data": {
"destination": "offset + 3 + A"
}
}
]
},
{
"mask": "0001'0000 BBBB'BBBB AAAA'AAAA",
"mnemonic": "JBC",
"format": "BIT[0x{B:02X}], PC + 0x{A:02X}",
"metadata": [
{
"type": "jump",
"data": {
"destination": "offset + 3 + A"
}
}
]
},
{
"mask": "0010'0000 AAAA'AAAA RRRR'RRRR",
"mnemonic": "JB",
"format": "BIT[0x{A:02X}], PC + 0x{R:02X}",
"metadata": [
{
"type": "jump",
"data": {
"destination": "offset + 3 + A"
}
}
]
},
{
"mask": "0001'0010 AAAA'AAAA AAAA'AAAA",
"mnemonic": "LCALL",
"format": "#0x{A:04X}",
"metadata": [
{
"type": "jump",
"data": {
"destination": "A"
}
}
]
},
{
"mask": "PPP1'0001 AAAA'AAAA",
"mnemonic": "ACALL",
"format": "page{P} #0x{A:04X}",
"metadata": [
{
"type": "jump",
"data": {
"destination": "P * 256 + A"
}
}
]
},
{
"mask": "PPP0'0001 AAAA'AAAA",
"mnemonic": "AJMP",
"format": "page{P} #0x{A:04X}",
"metadata": [
{
"type": "jump",
"data": {
"destination": "P * 256 + A"
}
}
]
},
{
"mask": "0000'0011",
"mnemonic": "RR",
"format": "A"
},
{
"mask": "0001'0011",
"mnemonic": "RRC",
"format": "A"
},
{
"mask": "0010'0011",
"mnemonic": "RL",
"format": "A"
},
{
"mask": "0011'0011",
"mnemonic": "RLC",
"format": "A"
},
{
"mask": "0000'0100",
"mnemonic": "INC",
"format": "A"
},
{
"mask": "0000'0101 AAAA'AAAA",
"mnemonic": "INC",
"format": "IRAM[0x{A:02X}]"
},
{
"mask": "0000'011R",
"mnemonic": "INC",
"format": "@R{R}"
},
{
"mask": "0000'1RRR",
"mnemonic": "INC",
"format": "R{R}"
},
{
"mask": "1010'0011",
"mnemonic": "INC",
"format": "DPTR"
},
{
"mask": "0001'0100",
"mnemonic": "DEC",
"format": "A"
},
{
"mask": "0001'0101 AAAA'AAAA",
"mnemonic": "DEC",
"format": "IRAM[0x{A:02X}]"
},
{
"mask": "0001'0110",
"mnemonic": "DEC",
"format": "@R0"
},
{
"mask": "0001'0111",
"mnemonic": "DEC",
"format": "@R1"
},
{
"mask": "0001'1RRR",
"mnemonic": "DEC",
"format": "R{R}"
},
{
"mask": "1110'0100",
"mnemonic": "CLR",
"format": "A"
},
{
"mask": "1100'0010 AAAA'AAAA",
"mnemonic": "CLR",
"format": "BIT[0x{A:02X}]"
},
{
"mask": "1100'0011",
"mnemonic": "CLR",
"format": "C"
},
{
"mask": "1111'0000",
"mnemonic": "MOVX",
"format": "@DPTR, A"
},
{
"mask": "1110'0000",
"mnemonic": "MOVX",
"format": "A, @DPTR"
},
{
"mask": "1111'001R",
"mnemonic": "MOVX",
"format": "@R{R}, A"
},
{
"mask": "1110'001R",
"mnemonic": "MOVX",
"format": "A, @R{R}"
},
{
"mask": "0111'011R AAAA'AAAA",
"mnemonic": "MOV",
"format": "@R{R}, #0x{A:02X}"
},
{
"mask": "0111'1RRR AAAA'AAAA",
"mnemonic": "MOV",
"format": "R{R}, #0x{A:02X}"
},
{
"mask": "1111'1RRR",
"mnemonic": "MOV",
"format": "R{R}, A"
},
{
"mask": "1110'011R",
"mnemonic": "MOV",
"format": "A, @R{R}"
},
{
"mask": "1111'011R",
"mnemonic": "MOV",
"format": "@R{R}, A"
},
{
"mask": "1110'1RRR",
"mnemonic": "MOV",
"format": "A, R{R}"
},
{
"mask": "1001'0010 AAAA'AAAA",
"mnemonic": "MOV",
"format": "BIT[0x{A:02X}], C"
},
{
"mask": "1010'0010 AAAA'AAAA",
"mnemonic": "MOV",
"format": "C, BIT[0x{A:02X}]"
},
{
"mask": "1001'0000 DDDD'DDDD DDDD'DDDD",
"mnemonic": "MOV",
"format": "DPTR, #0x{D:04X}"
},
{
"mask": "1110'0101 AAAA'AAAA",
"mnemonic": "MOV",
"format": "A, IRAM[0x{A:02X}]"
},
{
"mask": "1111'0101 AAAA'AAAA",
"mnemonic": "MOV",
"format": "IRAM[#0x{A:02X}], A"
},
{
"mask": "0111'0101 AAAA'AAAA DDDD'DDDD",
"mnemonic": "MOV",
"format": "IRAM[0x{A:02X}], #0x{D:02X}"
},
{
"mask": "1000'0101 AAAA'AAAA BBBB'BBBB",
"mnemonic": "MOV",
"format": "IRAM[0x{A:02X}], IRAM[0x{B:02X}]"
},
{
"mask": "0111'0100 DDDD'DDDD",
"mnemonic": "MOV",
"format": "A, #0x{D:02X}"
},
{
"mask": "1000'011R AAAA'AAAA",
"mnemonic": "MOV",
"format": "IRAM[0x{A:02X}], @R{R}"
},
{
"mask": "1000'1RRR AAAA'AAAA",
"mnemonic": "MOV",
"format": "IRAM[0x{A:02X}], R{R}"
},
{
"mask": "1010'011R AAAA'AAAA",
"mnemonic": "MOV",
"format": "@R{R}, IRAM[0x{A:02X}]"
},
{
"mask": "1010'1RRR AAAA'AAAA",
"mnemonic": "MOV",
"format": "R{R}, IRAM[0x{A:02X}]"
},
{
"mask": "0110'0000 AAAA'AAAA",
"mnemonic": "JZ",
"format": "PC + 0x{A:02X}",
"metadata": [
{
"type": "jump",
"data": {
"destination": "offset + 2 + A"
}
}
]
},
{
"mask": "0111'0000 AAAA'AAAA",
"mnemonic": "JNZ",
"format": "PC + 0x{A:02X}",
"metadata": [
{
"type": "jump",
"data": {
"destination": "offset + 2 + A"
}
}
]
},
{
"mask": "1001'0011",
"mnemonic": "MOVC",
"format": "A, @A+DPTR"
},
{
"mask": "1000'0011",
"mnemonic": "MOVC",
"format": "A, @A+PC"
},
{
"mask": "1101'011R",
"mnemonic": "XCHD",
"format": "A, @R{R}"
},
{
"mask": "1100'011R",
"mnemonic": "XCH",
"format": "A, @R{R}"
},
{
"mask": "1100'1RRR",
"mnemonic": "XCH",
"format": "A, R{R}"
},
{
"mask": "1100'0101 AAAA'AAAA",
"mnemonic": "XCH",
"format": "A, IRAM[0x{A:02X}]"
},
{
"mask": "0010'0010",
"mnemonic": "RET",
"format": ""
},
{
"mask": "0011'0010",
"mnemonic": "RETI",
"format": ""
},
{
"mask": "1101'0010 AAAA'AAAA",
"mnemonic": "SETB",
"format": "BIT[0x{A:02X}]"
},
{
"mask": "1101'0011",
"mnemonic": "SETB",
"format": "C"
},
{
"mask": "0101'0010 AAAA'AAAA",
"mnemonic": "ANL",
"format": "IRAM[0x{A:02X}], A"
},
{
"mask": "0101'0101 AAAA'AAAA",
"mnemonic": "ANL",
"format": "A, IRAM[0x{A:02X}]"
},
{
"mask": "0101'0011 AAAA'AAAA DDDD'DDDD",
"mnemonic": "ANL",
"format": "A, IRAM[0x{A:02X}], #0x{D:02X}"
},
{
"mask": "0101'0100 AAAA'AAAA",
"mnemonic": "ANL",
"format": "A, #0x{A:02X}"
},
{
"mask": "0101'011R",
"mnemonic": "ANL",
"format": "A, @R{R}"
},
{
"mask": "0101'1RRR",
"mnemonic": "ANL",
"format": "A, R{R}"
},
{
"mask": "1000'0010 AAAA'AAAA",
"mnemonic": "ANL",
"format": "C, BIT[0x{A:02X}]"
},
{
"mask": "1011'0000 AAAA'AAAA",
"mnemonic": "ANL",
"format": "C, /BIT[0x{A:02X}]"
},
{
"mask": "0100'0010 AAAA'AAAA",
"mnemonic": "ORL",
"format": "IRAM[0x{A:02X}], A"
},
{
"mask": "0100'0011 AAAA'AAAA DDDD'DDDD",
"mnemonic": "ORL",
"format": "IRAM[0x{A:02X}], #0x{D:02X}"
},
{
"mask": "0100'0100 DDDD'DDDD",
"mnemonic": "ORL",
"format": "A, #0x{D:02X}"
},
{
"mask": "0100'011R",
"mnemonic": "ORL",
"format": "A, @R{R}"
},
{
"mask": "0100'1RRR",
"mnemonic": "ORL",
"format": "A, R{R}"
},
{
"mask": "0100'0101 AAAA'AAAA",
"mnemonic": "ORL",
"format": "A, IRAM[0x{A:02X}]"
},
{
"mask": "0111'0010 AAAA'AAAA",
"mnemonic": "ORL",
"format": "C, BIT[0x{A:02X}]"
},
{
"mask": "1010'0000 AAAA'AAAA",
"mnemonic": "ORL",
"format": "C, /BIT[0x{A:02X}]"
},
{
"mask": "0110'0010 AAAA'AAAA",
"mnemonic": "XRL",
"format": "IRAM[0x{A:02X}], A"
},
{
"mask": "0110'0011 AAAA'AAAA DDDD'DDDD",
"mnemonic": "XRL",
"format": "IRAM[0x{A:02X}], #0x{D:02X}"
},
{
"mask": "0110'0100 DDDD'DDDD",
"mnemonic": "XRL",
"format": "A, #0x{D:02X}"
},
{
"mask": "0110'011R",
"mnemonic": "XRL",
"format": "A, @R{R}"
},
{
"mask": "0110'1RRR",
"mnemonic": "XRL",
"format": "A, R{R}"
},
{
"mask": "0110'0101 AAAA'AAAA",
"mnemonic": "XRL",
"format": "A, IRAM[0x{A:02X}]"
},
{
"mask": "0010'0100 DDDD'DDDD",
"mnemonic": "ADD",
"format": "A, #0x{D:02X}"
},
{
"mask": "0010'011R",
"mnemonic": "ADD",
"format": "A, @R{R}"
},
{
"mask": "0010'0101 AAAA'AAAA",
"mnemonic": "ADD",
"format": "A, IRAM[0x{A:02X}]"
},
{
"mask": "0011'0100 DDDD'DDDD",
"mnemonic": "ADDC",
"format": "A, #0x{D:02X}"
},
{
"mask": "0011'011R",
"mnemonic": "ADDC",
"format": "A, @R{R}"
},
{
"mask": "0011'0101 AAAA'AAAA",
"mnemonic": "ADDC",
"format": "A, IRAM[0x{A:02X}]"
},
{
"mask": "0011'1RRR",
"mnemonic": "ADDC",
"format": "A, R{R}"
},
{
"mask": "1001'0100 DDDD'DDDD",
"mnemonic": "SUBB",
"format": "A, #0x{D:02X}"
},
{
"mask": "1001'0101 IIII'IIII",
"mnemonic": "SUBB",
"format": "A, IRAM[0x{I:02X}]"
},
{
"mask": "1001'011R",
"mnemonic": "SUBB",
"format": "A, @R{R}"
},
{
"mask": "1001'1RRR",
"mnemonic": "SUBB",
"format": "A, R{R}"
},
{
"mask": "1010'0100",
"mnemonic": "MUL",
"format": "AB"
},
{
"mask": "1000'0100",
"mnemonic": "DIV",
"format": "AB"
},
{
"mask": "0010'1RRR",
"mnemonic": "ORL",
"format": "A, R{R}"
},
{
"mask": "1011'0101 IIII'IIII AAAA'AAAA",
"mnemonic": "CJNE",
"format": "A, IRAM[0x{I:02X}], PC + 0x{A:02X}",
"metadata": [
{
"type": "jump",
"data": {
"destination": "offset + 3 + A"
}
}
]
},
{
"mask": "1011'0100 DDDD'DDDD AAAA'AAAA",
"mnemonic": "CJNE",
"format": "A, #0x{D:02X}, PC + 0x{A:02X}",
"metadata": [
{
"type": "jump",
"data": {
"destination": "offset + 3 + A"
}
}
]
},
{
"mask": "1011'011R DDDD'DDDD AAAA'AAAA",
"mnemonic": "CJNE",
"format": "@R{R}, #0x{D:02X}, PC + 0x{A:02X}",
"metadata": [
{
"type": "jump",
"data": {
"destination": "offset + 3 + A"
}
}
]
},
{
"mask": "1011'1RRR DDDD'DDDD AAAA'AAAA",
"mnemonic": "CJNE",
"format": "R{R}, #0x{D:02X}, PC + 0x{A:02X}",
"metadata": [
{
"type": "jump",
"data": {
"destination": "offset + 3 + A"
}
}
]
},
{
"mask": "1101'0101 IIII'IIII AAAA'AAAA",
"mnemonic": "DJNZ",
"format": "IRAM[0x{I:02X}], PC + 0x{A:02X}",
"metadata": [
{
"type": "jump",
"data": {
"destination": "offset + 3 + A"
}
}
]
},
{
"mask": "1101'1RRR AAAA'AAAA",
"mnemonic": "DJNZ",
"format": "R{R}, PC + 0x{R:02X}",
"metadata": [
{
"type": "jump",
"data": {
"destination": "offset + 2 + A"
}
}
]
},
{
"mask": "0101'0000 AAAA'AAAA",
"mnemonic": "JNC",
"format": "PC + 0x{A:02X}",
"metadata": [
{
"type": "jump",
"data": {
"destination": "offset + 2 + A"
}
}
]
},
{
"mask": "1101'0000 AAAA'AAAA",
"mnemonic": "POP",
"format": "IRAM[0x{A:02X}]"
},
{
"mask": "1100'0000 AAAA'AAAA",
"mnemonic": "PUSH",
"format": "IRAM[0x{A:02X}]"
},
{
"mask": "1101'0100",
"mnemonic": "DA",
"format": ""
},
{
"mask": "1100'0100",
"mnemonic": "SWAP",
"format": "A"
},
{
"mask": "1111'0100",
"mnemonic": "CPL",
"format": "A"
},
{
"mask": "1011'0011",
"mnemonic": "CPL",
"format": "C"
},
{
"mask": "1011'0010 BBBB'BBBB",
"mnemonic": "CPL",
"format": "BIT[0x{B:02X}]"
},
{
"mask": "1010'0101",
"mnemonic": "INVALID",
"format": ""
},
{
"mask": "XXXX'XXXX",
"mnemonic": "DB",
"format": "#0x{X:02X}",
"metadata": [
{
"type": "data",
"data": {
"value": "X"
}
}
]
}
]
}

1045
disassemblers/jvm.json Normal file

File diff suppressed because it is too large Load Diff

Binary file not shown.

View File

@@ -21884,38 +21884,4 @@ FE4B=﨣
FE4C=﨤
FE4D=﨧
FE4E=﨨
FE4F=﨩
00=
01=
02=
03=
04=
05=
06=
07=
08=
09=
0A=
0B=
0C=
0D=
0E=
0F=
10=
11=
12=
13=
14=
15=
16=
17=
18=
19=
1A=
1B=
1C=
1D=
1E=
1F=
FE4F=﨩

Binary file not shown.

View File

@@ -25,7 +25,7 @@ namespace auto hex::dec {
@param pattern The pattern whose bytes should be decompressed
@param section The section to decompress the data into
@param window_size The window size passed to zlib
@return true if successful, false otherwise
@return A value representing either the number of bytes decompressed or an error code from zlib
*/
fn zlib_decompress(ref auto pattern, std::mem::Section section, u64 window_size = 0) {
return builtin::hex::dec::zlib_decompress(pattern, section, window_size);
@@ -71,5 +71,5 @@ namespace auto hex::dec {
fn lz4_decompress(ref auto pattern, std::mem::Section section, bool frame = true) {
return builtin::hex::dec::lz4_decompress(pattern, section, frame);
};
}

View File

@@ -13,7 +13,7 @@ namespace auto hex::type {
@tparam Size size of the string
*/
struct Json<auto Size> {
char __data[Size];
char __data[Size] [[hidden, no_unique_address]];
builtin::hex::dec::Json<__data> json [[merge]];
};
@@ -22,7 +22,7 @@ namespace auto hex::type {
@tparam Size size of the data
*/
struct Bson<auto Size> {
u8 __data[Size];
u8 __data[Size] [[hidden, no_unique_address]];
builtin::hex::dec::Bson<__data> bson [[merge]];
};
@@ -31,7 +31,7 @@ namespace auto hex::type {
@tparam Size size of the data
*/
struct Cbor<auto Size> {
u8 __data[Size];
u8 __data[Size] [[hidden, no_unique_address]];
builtin::hex::dec::Cbor<__data> cbor [[merge]];
};
@@ -40,7 +40,7 @@ namespace auto hex::type {
@tparam Size size of the data
*/
struct Bjdata<auto Size> {
u8 __data[Size];
u8 __data[Size] [[hidden, no_unique_address]];
builtin::hex::dec::Bjdata<__data> bjdata [[merge]];
};
@@ -49,7 +49,7 @@ namespace auto hex::type {
@tparam Size size of the data
*/
struct Msgpack<auto Size> {
u8 __data[Size];
u8 __data[Size] [[hidden, no_unique_address]];
builtin::hex::dec::Msgpack<__data> msgpack [[merge]];
};
@@ -58,7 +58,7 @@ namespace auto hex::type {
@tparam Size size of the data
*/
struct Ubjson<auto Size> {
u8 __data[Size];
u8 __data[Size] [[hidden, no_unique_address]];
builtin::hex::dec::Ubjson<__data> ubjson [[merge]];
};

View File

@@ -6,6 +6,22 @@ import std.core;
/*!
The array library contains a helper type to make it easier to create multi-dimensional arrays
and pass arrays to functions as parameters.
## Multi-dimensional arrays
The following example shows how to use multi-dimensional arrays with structs.
```rust
import std.array;
struct File {
u8 width, height;
std::Array<std::Array<u8, parent.width>, height> cells;
};
File file @ 0x00;
```
*/
namespace auto std {
@@ -27,7 +43,7 @@ namespace auto std {
struct ByteSizedArray<T, auto NumBytes> {
u64 startAddress = $;
T array[while($ - startAddress < NumBytes)] [[inline]];
std::assert($ - startAddress == NumBytes, "Not enough bytes available to fit a whole number of types");
} [[format("std::impl::format_array")]];

View File

@@ -1,3 +1,5 @@
#pragma once
import std.io;
import std.core;
@@ -67,4 +69,4 @@ namespace auto std::attr {
struct Sealed {}
[[sealed]];
}
}

View File

@@ -85,7 +85,7 @@ namespace auto std::ctype {
@return True if `c` is part of this range, false otherwise
*/
fn isprint(char c) {
return c >= '0' && c <= '~';
return c >= ' ' && c <= '~';
};
/**

View File

@@ -6,23 +6,6 @@
namespace auto std::mem {
namespace impl {
struct MagicSearchImpl<auto Magic, T> {
s128 address = builtin::std::mem::find_string_in_range(0, $, builtin::std::mem::size(), Magic);
if (address < 0)
break;
$ = address;
try {
T data [[inline]];
} catch {
T data;
}
};
}
/**
A Handle for a custom Section
*/
@@ -91,8 +74,8 @@ namespace auto std::mem {
@return The address of the sequence
*/
fn find_sequence(u128 occurrence_index, auto ... bytes) {
const u128 address = builtin::std::mem::base_address();
return builtin::std::mem::find_sequence_in_range(occurrence_index, address, address + builtin::std::mem::size(), bytes);
const u128 address = std::mem::base_address();
return builtin::std::mem::find_sequence_in_range(occurrence_index, address, address + std::mem::size(), bytes);
};
/**
@@ -115,8 +98,8 @@ namespace auto std::mem {
@return The address of the sequence
*/
fn find_string(u128 occurrence_index, str string) {
const u128 address = builtin::std::mem::base_address();
return builtin::std::mem::find_string_in_range(occurrence_index, address, address + builtin::std::mem::size(), string);
const u128 address = std::mem::base_address();
return builtin::std::mem::find_string_in_range(occurrence_index, address, address + std::mem::size(), string);
};
/**
@@ -242,16 +225,6 @@ namespace auto std::mem {
return builtin::std::mem::current_bit_offset();
};
/**
Searches for a sequence of bytes and places the given type at that address
@tparam Magic The magic sequence to search for
@tparam T The type to place at the address
*/
struct MagicSearch<auto Magic, T> {
std::mem::impl::MagicSearchImpl<Magic, T> impl[while(!std::mem::eof())] [[inline]];
};
/**
Reinterprets a value as a different one
@tparam From The type to reinterpret from
@@ -285,6 +258,28 @@ namespace auto std::mem {
return "";
};
struct MagicSearchImpl<auto Magic, T> {
s128 address = builtin::std::mem::find_string_in_range(0, $, std::mem::size(), Magic);
if (address < 0)
break;
$ = address;
try {
T data [[inline]];
} catch {
T data;
}
};
}
/**
Searches for a sequence of bytes and places the given type at that address
@tparam Magic The magic sequence to search for
@tparam T The type to place at the address
*/
struct MagicSearch<auto Magic, T> {
std::mem::impl::MagicSearchImpl<Magic, T> impl[while(!std::mem::eof())] [[inline]];
};
}

View File

@@ -47,9 +47,9 @@ namespace auto std::ptr {
Example:
A struct field called `p_myInfo` which is a nullable 64-bit pointer to an
element of type `MyInfoTy` would be written as:
```
```rust
struct MyStruct {
std::ptr::NullablePtr<MyInfoTy, u64> p_myInfo;
std::ptr::NullablePtr<MyInfoTy, u64> p_myInfo;
}
```
*/

View File

@@ -1,3 +1,4 @@
#pragma once
import std.io;
import std.string;
import std.mem;

View File

@@ -21,7 +21,7 @@ namespace auto type {
g : G;
b : B;
if (A > 0) a : A;
} [[sealed, format("type::impl::format_color"), color(std::format("{0:02X}{1:02X}{2:02X}FF", r, g, b))]];
} [[sealed, format("type::impl::format_color"), color(std::format("{0:02X}{1:02X}{2:02X}", r, g, b))]];
/**
Type representing a generic RGB color with a variable number of bits for each color
@@ -77,4 +77,4 @@ namespace auto type {
}
}
}

View File

@@ -52,7 +52,7 @@ namespace auto type {
std::mem::Reinterpreter<u32, float> converter;
converter.from_value = result;
return std::format("{}", converter.to);
return std::format("{}", converter.to_value);
};
}

View File

@@ -30,7 +30,7 @@ namespace auto type {
namespace impl {
fn format_formatted(ref auto formatted) {
return std::format(std::format("{{0:{}}}", formatted.FormatString), formatted.value);
return std::format(formatted.FormatString, formatted.value);
};
fn transform_formatted(ref auto formatted) {
@@ -39,4 +39,4 @@ namespace auto type {
}
}
}

View File

@@ -1,3 +1,5 @@
#pragma once
import std.string;
import std.sys;
import std.io;
@@ -11,7 +13,7 @@ namespace auto type
{
/**
Escapes all bytes in a string to only contain printable characters. All non-printable bytes will be transformed to sequences in the form form \xFF
Escapes all bytes in a string to only contain printable characters. All non-printable bytes will be transformed to sequences in the \xFF form
@param value Byte array to escape
@return Escaped string
*/
@@ -42,4 +44,4 @@ namespace auto type
return std::format("\"{}\"", type::escape_bytes(magic.value));
};
}
}
}

View File

@@ -1,3 +1,5 @@
#pragma once
import std.mem;
/*!

View File

@@ -1,3 +1,5 @@
#pragma once
import std.io;
/*!
@@ -69,4 +71,4 @@ namespace auto type {
}
}
}

41
magic/arma3_magic Normal file
View File

@@ -0,0 +1,41 @@
# A libmagic database containing definitions for files used by the Arma 3 game by Bohemia Interactive
# Arma 3 PAA image
0x02 string GGAT Arma 3 PAA image file
!:mime image/x.a3-paa
!:ext paa
>0 leshort 0xff01 DXT1 compression
>0 leshort 0xff02 DXT2 compression
>0 leshort 0xff03 DXT3 compression
>0 leshort 0xff04 DXT4 compression
>0 leshort 0xff05 DXT5 compression
>0 leshort 0x4444 RGBA4 format
>0 leshort 0x1555 RGBA5 format
>0 leshort 0x8888 RGBA8 format
>0 leshort 0x8080 Grayscale format
# Arma 3 RTM animation
0 string RTM_ Arma 3 RTM animation file (plain)
!:mime application/x.a3-rtm
!:ext rtm
# Arma 3 binarized RTM animation
0 string BMTR Arma 3 RTM animation file (binarized)
!:mime application/x.a3-bmtr
!:ext rtm
# Arma 3 texture index
0 string 0DHT Arma 3 texture index file
!:mime application/x.a3-texheaders
!:ext bin
# Arma 3 MLOD P3D model
0 string MLOD Arma 3 P3D model file (MLOD)
!:mime model/x.a3-p3d-mlod
!:ext p3d
>0x0c string P3DM P3DM LOD type
# Arma 3 binarized config
0x01 string raP Arma 3 binary configuration file
!:mime application/x.a3-rap
!:ext bin

View File

@@ -1,9 +1,11 @@
#pragma description 7z Archive
#pragma MIME application/x-7z-compressed
#pragma magic [ 37 7A BC AF 27 1C ] @ 0x00
import std.io;
import std.mem;
import std.math;
import type.magic;
enum Type:u8{
@@ -11,13 +13,9 @@ enum Type:u8{
sizeStartHeader = 0x20, // Size of start Header
};
enum TypeB:u48{
sevenZipSignature = 0x1C27AFBC7A37, // Defining 7z signature
};
struct StartHeader {
// File signature
u48 signature [[color("FF0000")] ];
type::Magic<"7z\xBC\xAF\x27\x1C"> signature [[color("FF0000")] ];
// Version format
u16 formatVersion [[color("00FF00")]];
// CRC start header
@@ -62,13 +60,6 @@ struct EndHeader {
EndHeader endheader @ Type::sizeStartHeader;
// Check 7z type
if(startheader.signature == TypeB::sevenZipSignature){
std::print("It is a 7z File Type");
}else{
std::print("The file is not 7z type");
}
std::print("Format Version {} ",startheader.formatVersion);
// Version verification

View File

@@ -0,0 +1,47 @@
#pragma description Assassin's Creed: Unity's Compressed .data file
#pragma author haru233
// many thanks to AxCut
// ImHex Hex Pattern File for Assassin's Creed: Unity's Compressed .data files
import std.core;
import std.mem;
enum CompressionType : u8 {
LZO1X_ = 0x00, // Both 0x00 and 0x01 mean LZO1X
LZO1X = 0x01,
LZO2A = 0x02,
xmemdecompress = 0x03,
LZO1C = 0x05
};
struct CHUNK {
u16 Uncompressed_Size;
u16 Compressed_Size;
};
struct CHUNK_Data {
u32 Hash;
u64 i = std::core::array_index();
u8 data[parent.chunk[i].Compressed_Size];
};
struct PACK {
u64 ID;
padding[2];
CompressionType Compression_Type;
padding[3];
u8 Version;
u16 CHUNK_Count;
CHUNK chunk[CHUNK_Count];
CHUNK_Data data[CHUNK_Count];
};
PACK pack[while(!std::mem::eof())] @0x00;

View File

@@ -0,0 +1,93 @@
#pragma description Assassin's Creed: Unity's Decompressed .data file
#pragma author haru233
// Thanks to yretenai on GitHub for helping with the Block Allocator part
import std.core;
import std.mem;
struct Block_Allocator_Type0 {
padding[4];
u32 Class_ID;
u32 Size;
};
struct Block_Allocator_Type1 {
padding[4];
u32 Type_ID;
u32 Size;
};
struct Block_Allocator {
u16 Version;
if (Version == 0) {
u32 Block_Allocator_Number;
Block_Allocator_Type0 block_allocator_type0[Block_Allocator_Number];
}
else if (Version == 1) {
u32 Block_Allocator_Number;
Block_Allocator_Type1 block_allocator_type1_[Block_Allocator_Number];
}
else if (Version == 2) {
bool Has_Secondary_Block_Allocator;
u32 Main_Block_Allocator_Number;
Block_Allocator_Type1 block_allocator_type1__[Main_Block_Allocator_Number];
if (Has_Secondary_Block_Allocator) {
u32 Secondary_Block_Allocator_Number;
Block_Allocator_Type1 block_allocator_type1___[Secondary_Block_Allocator_Number+1];
}
}
};
struct File {
u32 Object_Hash;
u32 File_Size;
u32 Filename_Length;
if (File_Size > 0) {
if (Filename_Length == 0) {
bool HasBlockAllocator;
if (HasBlockAllocator) {
Block_Allocator block_allocator;
u8 File_Data[File_Size];
}
else
u8 File_Data[File_Size];
}
else {
char Filename[Filename_Length];
bool HasBlockAllocator;
if (HasBlockAllocator) {
Block_Allocator block_allocator;
u8 File_Data[File_Size];
}
else
u8 File_Data[File_Size];
}
}
else
continue;
};
File file[while(!std::mem::eof())] @0x00;

View File

@@ -0,0 +1,64 @@
#pragma description Assassin's Creed: Unity's .forge archive file
#pragma author haru233
// many thanks to AxCut
// ImHex Hex Pattern File for Assassin's Creed: Unity's .forge files
import std.core;
struct Forge_Header {
char MAGIC[8];
padding[1];
u32 Version;
u32 File_Data_Header_Offset;
};
struct File_Data_Header {
u32 File_Count;
padding[32];
u64 File_Data_Header2_Offset;
};
struct File_Data_Header2 {
u32 File_Count2;
padding[4];
u64 File_Table_Offset;
padding[12];
u32 File_Count3;
u64 File_Name_Table_Offset;
padding[8];
};
struct File_Table {
u64 Raw_Data_Offset;
u64 File_ID;
u32 Raw_Data_Size;
};
struct File_Name_Table {
u32 Raw_Data_Size;
padding[40];
char Filename[128];
padding[20];
};
Forge_Header forge_header @0x00;
File_Data_Header file_data_header @(forge_header.File_Data_Header_Offset);
File_Data_Header2 file_data_header2 @(file_data_header.File_Data_Header2_Offset);
File_Table file_table[file_data_header.File_Count] @(file_data_header2.File_Table_Offset);
File_Name_Table file_name_table[file_data_header.File_Count] @(file_data_header2.File_Name_Table_Offset);
struct Raw_Data_Table {
u64 i = std::core::array_index();
u8 Raw_Data[file_table[i].Raw_Data_Size] @ file_table[i].Raw_Data_Offset;
};
Raw_Data_Table raw_data_table[file_data_header.File_Count] @0x00;

View File

@@ -1,5 +1,6 @@
#pragma author AdventureT
#pragma description Crash Bandicoot - Back in Time (fan game) User created level
#pragma magic [ 43 52 41 53 48 4C 56 4C ] @ 0x00
#pragma history
#pragma 0.3 2024-05-15 Added support for version 0.95
#pragma 0.2 2023-10-29 Added support for version 0.94c

View File

@@ -0,0 +1,81 @@
ImHex Pattern Files - Digital Forensics:
- [ImHex-DFIR-Patterns](https://github.com/Xtreme-Liberty/ImHex-DFIR-Patterns)
Enhanced features of the stock Disk/Filesystem pattern files for forensic review of disk content.
- [ImHex](https://github.com/WerWolv/ImHex)
- [ImHex Patterns](https://github.com/WerWolv/ImHex-Patterns)
Use:
- Open a physical disk via Raw Provider (read-only)
- EXAMPLE: /dev/disk6
- Import Pattern File
- EXAMPLE: DISK_PARSER.hexpat
- [Pattern_Selection (screenshot)](https://github.com/Xtreme-Liberty/ImHex-DFIR-Patterns/blob/main/screenshots/2-DISK_PARSER-Pattern.png)
- DISK_PARSER.hexpat
- Recognize MBR/GPT Disks and parse MPT/GPT
- Including Logical Volumes in an Extended Partition (container)
- Auto load file system patterns for FAT32, exFAT, NTFS formatted volumes
- Optional Disk Report
- [DISK > MBR/GPT (screenshot)](https://github.com/Xtreme-Liberty/ImHex-DFIR-Patterns/blob/main/screenshots/3-DISK-HYBRID.png)
- [DISK > MBR > MPT > 3 Primaries | 2 Logicals in an Extended (screenshot)](https://github.com/Xtreme-Liberty/ImHex-DFIR-Patterns/blob/main/screenshots/3a-DISK-MBR.png)
- FAT32.hexpat
- Auto loaded by DISK_PARSER.hexpat
- Parse VBR, FAT1, FAT2, Root Dir, and 1 level of SubDirs
- FAT1/FAT2 Cluster chaining with SFN resolution
- LFN/SFN Alias grouping in Root Dir
- Recognize deleted entries (xE5)
- File Content pointer
- D/T Conversions
- Optional FAT32 Volume Report
- [VOLUME > FAT32 > FAT1 (screenshot)](https://github.com/Xtreme-Liberty/ImHex-DFIR-Patterns/blob/main/screenshots/4-FAT32-1_SMALL_TXT.png)
- [VOLUME > FAT32 > Root Dir (screenshot)](https://github.com/Xtreme-Liberty/ImHex-DFIR-Patterns/blob/main/screenshots/5-FAT32_ROOT_DIR.png)
- [VOLUME > FAT32 > Data Pointer (screenshot)](https://github.com/Xtreme-Liberty/ImHex-DFIR-Patterns/blob/main/screenshots/6-FAT32_SFN_POINTER.png)
- exFAT.hexpat
- Auto loaded by DISK_PARSER.hexpat
- Parse VBR/Boot Sector/Extended Sectors, FAT1, Root Dir
- Recognize active directory entries (x85, xC0, xC1)
- Recognize inactive directory entries (x05, x40, x41)
- xC0/x40 File Content pointer
- D/T Conversions
- Optional exFAT Volume Report
- [VOLUME > exFAT (screenshot)](https://github.com/Xtreme-Liberty/ImHex-DFIR-Patterns/blob/main/screenshots/7-exFAT-1.png)
- [VOLUME > exFAT > Root Dir > xC0 (screenshot)](https://github.com/Xtreme-Liberty/ImHex-DFIR-Patterns/blob/main/screenshots/8-exFAT_xC0.png)
- [VOLUME > exFAT > Data Pointer (screenshot)](https://github.com/Xtreme-Liberty/ImHex-DFIR-Patterns/blob/main/screenshots/9-exFAT-Data_Pointer.png)
- NTFS.hexpat
- Auto loaded by DISK_PARSER.hexpat
- Parse VBR (Boot Sector), $MFT, Root Dir, and Indexes
- Recursively parse the $Metadata files, $Attributes, and user files/dirs
- Added file record | parent [MFT#] [SEQ#] indicators
- Parse x80/xB0 Data Runs
- File Content pointer
- D/T Conversions
- Optional NTFS Volume Report
- [VOLUME > NTFS > $MFT > D/T Conversion (screenshot)](https://github.com/Xtreme-Liberty/ImHex-DFIR-Patterns/blob/main/screenshots/10-NTFS-DT.png)
- [VOLUME > NTFS > $MFT > x80 Run List (screenshot)](https://github.com/Xtreme-Liberty/ImHex-DFIR-Patterns/blob/main/screenshots/11-NTFS-DATA_RUN.png)
- [VOLUME > NTFS > Data Pointer (screenshot)](https://github.com/Xtreme-Liberty/ImHex-DFIR-Patterns/blob/main/screenshots/12-NTFS-DATA_POINTER.png)
- Optional Reports
- Simply copy the console output to a file...
- To enable/disable the reports:
- Open each DFIR related .hexpat
- Find the report constant (near the top)
- "true" = enabled
- "false" = disabled
Example Report: GPT > FAT32|exFAT
- [exFAT_Report](https://github.com/Xtreme-Liberty/ImHex-DFIR-Patterns/blob/main/reports/exFAT_Report.txt)
Example Report: MBR > 5 Logical Volumes (2 in an Extended) > All FAT32 Volumes
- [MBR_5_VOLs](https://github.com/Xtreme-Liberty/ImHex-DFIR-Patterns/blob/main/reports/MBR_5_VOLs.txt)

View File

@@ -0,0 +1,677 @@
#pragma author Formula Zero One Technologies
#pragma description DFIR_DISK_PARSER_v2.0
#pragma MIME application/x-ima
#pragma endian little
// -----------------------------------------------------------------------------
// CREDIT
// -----------------------------------------------------------------------------
// Based on /fs/pattern.hexpat by WerWolv
// -----------------------------------------------------------------------------
// TODO
// -----------------------------------------------------------------------------
// Refine File System Detection/Match
// -----------------------------------------------------------------------------
// IMPORTS
// -----------------------------------------------------------------------------
import std.core;
import std.io;
import std.time;
import type.guid;
import type.magic;
import type.time;
import type.base;
import hex.provider;
// WORKING IMPORTS
import * from DFIR.FAT32 as FAT32Pat;
import * from DFIR.exFAT as EXFATPat;
import * from DFIR.NTFS as NTFSPat;
// ------------------------------------
// DISABLED IMPORTS
// REFS - UNTESTED
// EXT4 - GROUP DESC ERRORS
// APFS - PARTIALLY WORKS
// Comment out "using uuid_t = type::GUID"
// Replace all instances of "uuid_t" with "type::GUID"
// Comment out line 1456-EOF
// JPEG/PNG - OFFSET ERRORS
// ------------------------------------
//import * from fs.apfs as APFSPat;
//import * from fs.ext4 as EXT4Pat;
//import * from fs.refs as REFSPat;
//import * from jpeg as JPEGPat;
//import * from png as PNGPat;
// -----------------------------------------------------------------------------
// FWD DECs - GLOBAL
// -----------------------------------------------------------------------------
bool has_ext = false;
bool has_gpt = false;
u64 partitionOffset = 0;
u64 containerStartOffset = 0;
u32 mptIndex = 0;
u32 extIndex = 0;
str entryName = "";
u32 MPT_Count = 0;
u32 EXT_VolCount = 0;
u32 GPT_Count = 0;
u32 memory_size = std::mem::size();
str disk_path = hex::prv::get_information("file_path","");
u128 sector_size = hex::prv::get_information("sector_size","");
// -----------------------------------------------------------------------------
// REPORT HEADER ** ATTENTION **
// -----------------------------------------------------------------------------
// ---******---*******---vvvv--- |
const bool DISK_REPORT = true;
// ---******---*******---^^^^--- |
if (DISK_REPORT) {
std::print(" # # # # # # ");
std::print(" # # # ");
std::print(" # # # ");
std::print(" # # # # # # # ");
std::print(" I m H e x ");
std::print(" ");
std::print("-----------------------------------------");
std::print(" ");
std::print(" ENTITY: _____________________");
std::print(" ");
std::print("EXAMINER: _____________________");
std::print(" ");
u128 timestamp = std::time::epoch();
std::time::Time local_ts = std::time::to_local(timestamp);
std::time::Time utc_ts = std::time::to_utc(timestamp);
std::print("-----------------------------------------");
std::print(" LOCAL: {}",
std::format("{:02}/{:02}/{:04} @ {:02}:{:02}:{:02}",
local_ts.mon + 1,
local_ts.mday,
local_ts.year + 1900,
local_ts.hour,
local_ts.min,
local_ts.sec
));
std::print(" UTC: {}",
std::format("{:02}/{:02}/{:04} @ {:02}:{:02}:{:02}",
utc_ts.mon + 1,
utc_ts.mday,
utc_ts.year + 1900,
utc_ts.hour,
utc_ts.min,
utc_ts.sec
));
std::print("-----------------------------------------");
std::print(" ");
}
// -----------------------------------------------------------------------------
// SIGNATURE HELPER
// -----------------------------------------------------------------------------
enum MBRSignature : u16 {
MBR_SIG = 0xAA55 // 0x55AA -> Read LE
};
// -----------------------------------------------------------------------------
// CHS HELPER
// -----------------------------------------------------------------------------
bitfield CHS_Decoder {
head : 8;
sector : 6;
cylinder : 10;
} [[format("chs_formatter")]];
fn chs_formatter(CHS_Decoder CHS) {
return std::format("({:X}, {:X}, {:X}) | 0x{:X}", CHS.cylinder, CHS.head, CHS.sector, (CHS.cylinder * 16 + CHS.head) * 63 + (CHS.sector - 1));
};
// -----------------------------------------------------------------------------
// TIMESTAMP HELPER
// -----------------------------------------------------------------------------
struct DiskTimeStamp {
u8 seconds, minutes, hours;
};
// -----------------------------------------------------------------------------
// DISK PROTECTION HELPER
// -----------------------------------------------------------------------------
enum DiskProtection : u16 {
NotProtected = 0x0000,
CopyProtected = 0x5A5A
};
// -----------------------------------------------------------------------------
// PARTITION STATUS HELPER
// -----------------------------------------------------------------------------
enum PartitionStatus : u8 {
Not_Active = 0x00, // not_bootable
Active = 0x80 // bootable
};
enum MPTPartLabel : u8 {
UNUSED_OR_HIDDEN_ENTRY = 0x00,
PRIMARY = 0x07,
PRIMARY_F32_SMALL = 0x0B,
PRIMARY_0C_BIG = 0x0C,
EXTENDED_CONT_SMALL = 0x05,
EXTENDED_CONT_BIG = 0x0F,
LEGACY_MBR = 0xEE
};
// -----------------------------------------------------------------------------
// PARTITION TYPE HELPER
// -----------------------------------------------------------------------------
enum PartitionTypeCode : u8 {
UNUSED_ENTRY = 0x00,
FAT12_HDD = 0x01,
FAT12_HIDDEN = 0x11,
FAT16_SMALL = 0x04,
FAT16_SMALL_HIDDEN = 0x14,
FAT16_BIG = 0x06,
FAT16_BIG_HIDDEN = 0x16,
FAT32_SMALL = 0x0B,
FAT32_SMALL_HIDDEN = 0x1B,
FAT32_BIG = 0x0C,
FAT32_BIG_HIDDEN = 0x1C,
EXT_PART_SMALL = 0x05,
EXT_PART_SMALL_HIDDEN = 0x15,
EXT_PART_BIG = 0x0F,
EXT_PART_BIG_HIDDEN = 0x1F,
NTFS_EXFAT = 0x07,
NTFS_EXFAT_HIDDEN = 0x17,
WINDOWS_RECOVERY = 0x27,
NTFS_VOL_SET_1 = 0x86,
NTFS_VOL_SET_2 = 0x87,
macOSX = 0xA8,
OS2_HIDDEN_CDRIVE = 0x84,
LINUX_EXT = 0x83,
LINUX_EXT2 = 0x85,
LINUX_LVM = 0x8E,
LINUX_PA_RISC = 0xF0,
LINUX_RAID = 0xFD,
FREE_BSD = 0xA5,
OPEN_BSD = 0xA6,
QNX_1 = 0x4D,
QNX_2 = 0x4E,
QNX_3 = 0x4F,
GPT_DISK_STD = 0xEE,
GPT_DISK_SYS = 0xEF,
UNKNOWN = 0xFF,
};
// -----------------------------------------------------------------------------
// GUID PARTITION TABLE (GPT) PARTIONING SCHEME RELATED
// -----------------------------------------------------------------------------
// V V V V V V V V V V
// -----------------------------------------------------------------------------
// GPT PARTITION LABEL HELPER
// -----------------------------------------------------------------------------
enum GUIDPartLabel : u128 {
// ---------------- COMMON ----------------
UNUSED_ENTRY = 0x00000000000000000000000000000000,
EFI_SYSTEM_PART = 0x3BC93EC9A0004BBA11D2F81FC12A7328,
APPLE_APFS_CONT = 0xACEC4365300011AA11AA00007C3457EF,
APPLE_HFS_PLUS_PART = 0xACEC4365300011AA11AA000048465300,
MICROSOFT_RESERVED_PART = 0xAE1502F92DF97D81B84D5C0BE3E3C9E3,
WINDOWS_REC_ENVIRONMENT = 0xACD67901D5BF6AA1404DD106A4BB94DE,
BASIC_DATA_PART = 0xC79926B7B668C0874433B9E5EBD0A0A2,
// ---------------- LINUX ----------------
LINUX_FILE_SYSTEM = 0xE47D47D8693D798E477284830FC63DAF,
RAID_PART = 0x1E91840F3F7406A04D3B05FCA19D880F,
ROOT_PART_X86 = 0x8A45F0D531D1F79A41B2F29744479540,
ROOT_PART_X86_64 = 0x09B784F9CAFBE7964DB1E8CD4F68BCE3,
ROOT_PART_ARM = 0xD3BE9AD4A1216CB14E3C2CE469DAD710,
ROOT_PART_ARM_64 = 0xAE3F0D286F4C44AF41C31DF0B921B045,
BOOT_PART = 0x72716FFD75B252A3426259E6BC13C2FF,
SWAP_PART = 0x4F4F4BC83309E58443C4A4AB0657FD6D,
LOGICAL_VOLUME_MGR_PART = 0x28F93D2A8F233CA244C2F507E6D6D379,
HOME_PART = 0x15F9AEE2140E44B84F132EB4933AC7E1,
SRV_SERVER_DATA_PART = 0xE8986FA7251A7F904F3B20E03B8F8425,
PLAIN_DMCRYPT_PART = 0xB786550AA13E418949B72D007FFEC5C9,
LUKS_PART = 0xCC59605342171C864C5363EDCA7D7CCB,
// ---------------- APPLE ----------------
APPLE_UFS_CONT = 0xACEC4365300011AA11AA000055465300,
APPLE_ZFS = 0x316673200008A69911B21DD26A898CC3,
APPLE_RAID_PART = 0xACEC4365300011AA11AA000052414944,
APPLE_RAID_PART_OFFLINE = 0xACEC4365300011AA11AA5F4F52414944,
APPLE_BOOT_PART_REC_HD = 0xACEC4365300011AA11AA0000426F6F74,
APPLE_LABEL = 0xACEC4365300011AA11AA6C004C616265,
APPLE_TV_RECOVERY_PART = 0xACEC4365300011AA11AA76655265636F,
APPLE_CORE_STORAGE_CONT = 0xACEC4365300011AA11AA616753746F72,
HFS_FILEVAULT_VOLUME_CONT = 0xACEC4365300011AA11AA616753746F72,
APPLE_APFS_PREBOOT_PART = 0xACEC4365300011AA11AA006769646961,
APPLE_APFS_RECOVERY_PART = 0xACEC4365300011AA11AA007972637652,
// ---------------- WINDOWS ----------------
LOGICAL_DISK_MGR_META_PART = 0xB3CF34E104E1D28542E08F7EAAC80858,
LOGICAL_DISK_MGR_DATA_PART = 0xAD694A71113368BC4F621431A0609BAF,
IBM_GENERAL_PARALLEL_FILE_SYS_PART = 0x74B155E07A2DC3914E4EEF7D90FFAA37,
STORAGE_SPACES_PART = 0x2DECF6E501B0A3AFEE4CF6808FAF5CE7,
STORAGE_REPLICA_PART = 0xD123292BD147C8AAC043A1ACC58D4355,
};
// -----------------------------------------------------------------------------
// BASIC DATA PARTITION ATTRIBUTES
// -----------------------------------------------------------------------------
bitfield GPT_BDP_Attributes {
bool platform_required : 1 [[comment("Bit 0: RequiredPartition - Volume must be preserved")]];
bool io_ignore : 1 [[comment("Bit 1: NoBlockIOProtocol - EFI ignores this Volume, no FS Mapping")]];
bool legacy_flag : 1 [[comment("Bit 2: LegacyBIOSBootable - Active/Bootable under BIOS")]];
reserved_UEFI : 45 [[comment("Bits 347: Reserved for UEFI")]];
reserved_MS : 12 [[comment("Bits 4859: Reserved for Microsoft")]];
bool read_only : 1 [[comment("Bit 60: BasicDataPart - Read-Only Volume")]];
bool shadow_copy : 1 [[comment("Bit 61: BasicDataPart - Shadow Copy Volume")]];
bool hidden : 1 [[comment("Bit 62: BasicDataPart - Hidden Volume")]];
bool no_drive_letter : 1 [[comment("Bit 63: BasicDataPart - Do not Auto-Assign Drive Letter")]];
} [[bitfield_order(
std::core::BitfieldOrder::LeastToMostSignificant, 64)]];
// -----------------------------------------------------------------------------
// GPT ENTRIES PARSER
// LBA2-LBA33
// EACH ENTRY IS 128 BYTES (DESCRIBES A VOLUME)
// -----------------------------------------------------------------------------
union PartitionUnion {
le type::GUID PartTypeGUID; // HUMAN READABLE GUID
GUIDPartLabel PartTypeLabel [[name(std::format("PartTypeLabel (DERIVED)"))]]; // OBJECT LABEL
};
struct GPT_PartitionEntry {
PartitionUnion Type [[comment("Known Partition Type GUID: Global Identifier")]];
le type::GUID Unique_GUID [[comment("Unique Partition GUID: Every Volume has its own Unique GUID")]];
u64 Start_LBA [[comment("The first Sector of the Volume (Offset by 1)")]];
u64 End_LBA [[comment("The last Sector of the Volume (Offset by 1)")]];
GPT_BDP_Attributes ATTR [[comment("ATTRs for a Basic Data Partition may not be the same as a Microsoft Reserved Partition")]];
char16 PartName[36] [[comment("Partition Name: Based on Known Partition Type GUID, except for Disk Images")]];
if (Type.PartTypeLabel != GUIDPartLabel::UNUSED_ENTRY) {
GPT_Count += 1;
}
u64 GPTpartitionOffset = Start_LBA * sector_size
[[name(std::format("VOL_OFFSET {} | 0x{:02X} (DERIVED)", Start_LBA * sector_size, Start_LBA * sector_size)),
export]];
match (Type.PartTypeLabel) {
(GUIDPartLabel::UNUSED_ENTRY):
continue;
(GUIDPartLabel::EFI_SYSTEM_PART):
FAT32Pat EFI_SYS_VOL @ GPTpartitionOffset;
(GUIDPartLabel::BASIC_DATA_PART |
GUIDPartLabel::WINDOWS_REC_ENVIRONMENT): {
char gpt_fat32_magic[8] @ GPTpartitionOffset + 82 [[hidden]];
char gpt_ntfs_magic[8] @ GPTpartitionOffset + 3 [[hidden]];
char gpt_exfat_magic[8] @ GPTpartitionOffset + 3 [[hidden]];
if (gpt_fat32_magic == "FAT32 ")
FAT32Pat FAT32_VOL @ GPTpartitionOffset;
if (gpt_ntfs_magic == "NTFS ")
NTFSPat NTFS_VOL @ GPTpartitionOffset;
else if (gpt_exfat_magic == "EXFAT ")
EXFATPat EXFAT_VOL @ GPTpartitionOffset;
}
// --------- DISABLED -----------------
// EXT4 PATTERN WAS INOP WHEN TESTED
//(GUIDPartLabel::LINUX_FILE_SYSTEM):
//EXT4Pat EXT4_VOL @ GPTpartitionOffset;
//(GUIDPartLabel::APPLE_APFS_CONT):
// APFSPat APFS_VOL @ GPTpartitionOffset;
}
} [[name(std::format("GPT_ENTRY [{}]", std::core::array_index()))]];
// -----------------------------------------------------------------------------
// GPT HEADER PARSER
// LBA1 OFFSETS 0-91 (92 bytes of 512 bytes used)
// -----------------------------------------------------------------------------
struct GPT_Header {
type::Magic<"EFI PART"> signature [[comment("Signature (EFI PART)")]];
u32 revision [[comment("Header Revision Value")]];
u32 header_size [[comment("Size of Header - 92 Bytes")]];
type::Hex<u32> header_crc32 [[comment("GPT Header Checksum")]];
u32 reserved [[comment("Zeros")]];
u64 current_lba [[comment("Current LBA - GPT Header Location")]];
u64 backup_lba [[comment("Location of Backup - Header & GPT")]];
u64 first_usable_lba [[comment("1st Sector Available for Logical VOL")]];
u64 last_usable_lba [[comment("Last Sector Available for Logical VOL")]];
type::GUID disk_guid [[comment("Unique Disk GUID")]];
u64 partition_entries_lba [[comment("1st Sector of GPT")]];
u32 num_partition_entries [[comment("Total Number of Partition Entries Available - 128 on Windows")]];
u32 size_of_partition_entry [[comment("Size in Bytes of each GPT Entry")]];
type::Hex<u32> partition_entries_crc32 [[comment("GPT Array Checksum")]];
};
// -----------------------------------------------------------------------------
// MASTER BOOT RECORD (MBR) PARTIONING SCHEME RELATED
// -----------------------------------------------------------------------------
// V V V V V V V V V V
// -----------------------------------------------------------------------------
// MASTER PARTITION TABLE (MPT)
// LBA0 > 0FFSETS 446-509
// Each Entry Describes a Logical Volume (type/start_loc/size)
// -----------------------------------------------------------------------------
union MBRPartitionUnion {
PartitionTypeCode Part_Type;
MPTPartLabel PartTypeLabel; // overlay for 0x00
};
struct PartitionTableEntry {
// partition table fields
PartitionStatus ActiveFlag;
CHS_Decoder Starting_CHS;
MBRPartitionUnion Type;
CHS_Decoder Ending_CHS;
u32 Start_LBA;
u32 Total_Sectors;
if (Type.PartTypeLabel != MPTPartLabel::UNUSED_OR_HIDDEN_ENTRY) {
// Track Count of Logical Volumes in the Extended Container
//MPT_Count += 1;
if (containerStartOffset == 0) {
// top-level MBR entry
MPT_Count = MPT_Count + 1;
} else {
// a logical inside an extended container
EXT_VolCount = EXT_VolCount + 1;
}
}
partitionOffset = containerStartOffset + (Start_LBA * sector_size);
match (Type.PartTypeLabel) {
(PartitionTypeCode::UNUSED_ENTRY): continue;
(PartitionTypeCode::FAT32_SMALL | PartitionTypeCode::FAT32_BIG): {
FAT32Pat FAT32_VOL @ partitionOffset;
}
(PartitionTypeCode::NTFS_EXFAT): {
char magic[8] @ partitionOffset + 3;
if (magic == "NTFS ")
NTFSPat NTFS_VOL @ partitionOffset;
else
EXFATPat EXFAT_VOL @ partitionOffset;
}
(PartitionTypeCode::EXT_PART_SMALL | PartitionTypeCode::EXT_PART_BIG): {
// Save parent state
bool parent_has_ext = has_ext;
has_ext = true;
containerStartOffset = partitionOffset;
// Parse first two entries of the extended partition
PartitionTableEntry EXTENDED_PARTITION[2] @ partitionOffset + 446;
has_ext = parent_has_ext;
}
(PartitionTypeCode::GPT_DISK_STD | PartitionTypeCode::GPT_DISK_SYS):
// Set global flag
has_gpt = true;
}
if (!has_ext) {
entryName = std::format("MPT_ENTRY [{}]", mptIndex);
mptIndex += 1;
} else {
if (std::core::array_index() <= 0) {
entryName = std::format("LOGICAL_VOL (EXT) [{}]", extIndex);
} else if (std::core::array_index() == 1) {
entryName = "NEXT VOL POINTER (EXT)";
} else {
entryName = std::format("LOGICAL_VOL (EXT) [{}]", extIndex);
}
extIndex += 1;
}
} [[name(entryName)]];
// -----------------------------------------------------------------------------
// MBR PARSER
// LBA0 > OFFSETS 0-511 (512 bytes)
// -----------------------------------------------------------------------------
struct MasterBootRecord {
u8 bootstrapCodeArea1[218] [[comment("Boot Strapping Code")]];
padding[2] [[comment("Zeros")]];
u8 originalPhysicalDrive [[comment("???")]];
DiskTimeStamp diskTimeStamp [[comment("Timestamp of Disk OG Partitioning")]];
u8 bootstrapCodeArea2[216] [[comment("Boot Strapping Code")]];
u32 diskSignature [[comment("Disk Signature")]];
DiskProtection diskProtection [[comment("Disk Protection - 0x0000=Not | 0x5A5A=Prot")]];
PartitionTableEntry PT[4] [[comment("Master Partition Table (MPT) Offset 446-509")]];
MBRSignature MBR_SIG [[comment("End of MBR - 0x55AA")]];
};
// -----------------------------------------------------------------------------
// DISK PARSER
// -----------------------------------------------------------------------------
struct DiskRoot {
// Master Boot Record at LBA 0 (1st physical sector)
MasterBootRecord MBR @ 0x00;
if (has_gpt) {
// GPT Header at LBA 1 (2nd physical sector)
GPT_Header GPT_HEADER @ 0x200;
// The GPT (table) at LBA 2 (3rd physical sector) to LBA 33 (34th physical sector)
// 32 sectors total (Windows) that can define up to 128 - (primary) logical volumes
GPT_PartitionEntry GPT_ENTRIES[GPT_HEADER.num_partition_entries] @ (GPT_HEADER.partition_entries_lba * 512);
}
};
// -----------------------------------------------------------------------------
// ROOT OBJECT
// -----------------------------------------------------------------------------
// ---
DiskRoot DISK @ 0x0;
// ---
// ------------------------------
// DISK REPORT
// ------------------------------
if (DISK_REPORT) {
std::print("-----------------------------------------");
std::print("-------------- DISK_REPORT --------------");
std::print("-----------------------------------------");
// Disk Basics
std::print("DISK_PATH = {}", disk_path);
std::print("SECTOR_SIZE = {} BYTES", sector_size);
std::print("DISK_SIZE = {} SECTORS", memory_size / sector_size);
std::print("DISK_SIZE = {:.4f} GB @ 1000", memory_size / 1000.0 / 1000.0 / 1000.0);
std::print("DISK_SIZE = {:.4f} GiB @ 1024", memory_size / 1024.0 / 1024.0 / 1024.0);
// Disk Protection
str diskProtectionStr;
if (DISK.MBR.diskProtection == DiskProtection::NotProtected) {
diskProtectionStr = "NOT_COPY_PROTECTED";
} else if (DISK.MBR.diskProtection == DiskProtection::CopyProtected) {
diskProtectionStr = "COPY_PROTECTED";
} else {
diskProtectionStr = "UNKNOWN";
}
std::print("DISK_PROTECT = {}", diskProtectionStr);
// Partition Scheme
if (MPT_Count >= 1 && GPT_Count == 0) {
std::print("PART_SCHEME = MBR");
} else if (GPT_Count >= 1 && MPT_Count == 0) {
std::print("PART_SCHEME = GPT");
} else if (GPT_Count >= 1 && MPT_Count >= 1) {
std::print("PART_SCHEME = HYBRID (MBR + GPT)");
} else {
std::print("PART_SCHEME = UNKNOWN");
}
// MBR MPT Partitions
for (u32 i = 0, i < MPT_Count, i = i + 1) {
std::print("-----------------------------------------");
std::print("-------------- MBR_MPT [{}] --------------", i);
std::print("-----------------------------------------");
// STATUS
str statusStr;
if (DISK.MBR.PT[i].ActiveFlag == PartitionStatus::Active) {
statusStr = "ACTIVE/BOOTABLE";
} else if (DISK.MBR.PT[i].ActiveFlag == PartitionStatus::Not_Active) {
statusStr = "INACTIVE/NOT_BOOTABLE";
} else {
statusStr = "UNKNOWN";
}
std::print(" STATUS = {}", statusStr);
// TYPE_CODE
str typeStr;
if (DISK.MBR.PT[i].Type.Part_Type == PartitionTypeCode::FAT32_SMALL) {
typeStr = "FAT32 (CHS) (0x0B)";
} else if (DISK.MBR.PT[i].Type.Part_Type == PartitionTypeCode::FAT32_BIG) {
typeStr = "FAT32 (LBA) (0x0C)";
} else if (DISK.MBR.PT[i].Type.Part_Type == PartitionTypeCode::NTFS_EXFAT) {
typeStr = "NTFS/EXFAT (0x07)";
} else if (DISK.MBR.PT[i].Type.Part_Type == PartitionTypeCode::GPT_DISK_STD) {
typeStr = "GPT_PROTECTIVE (0xEE)";
} else if (DISK.MBR.PT[i].Type.Part_Type == PartitionTypeCode::EXT_PART_BIG) {
typeStr = "EXTENDED (0x0F)";
} else {
typeStr = "OTHER/UNKNOWN";
}
std::print(" TYPE_CODE = {}", typeStr);
// LBA and size
std::print(" FIRST_LBA = {:02}", DISK.MBR.PT[i].Start_LBA);
std::print(" LAST_LBA = {:02}", DISK.MBR.PT[i].Start_LBA + DISK.MBR.PT[i].Total_Sectors - 1);
std::print(" VOL_SIZE = {:02} SECTORS", DISK.MBR.PT[i].Total_Sectors);
std::print(" VOL_SIZE = {:.4f} GB", (DISK.MBR.PT[i].Total_Sectors * sector_size) / 1000.0 / 1000.0 / 1000.0);
std::print(" VOL_SIZE = {:.4f} GiB", (DISK.MBR.PT[i].Total_Sectors * sector_size) / 1024.0 / 1024.0 / 1024.0);
if (DISK.MBR.PT[i].Type.PartTypeLabel == MPTPartLabel::EXTENDED_CONT_SMALL ||
DISK.MBR.PT[i].Type.PartTypeLabel == MPTPartLabel::EXTENDED_CONT_BIG) {
u32 logicalCount = std::core::member_count(DISK.MBR.PT[i].EXTENDED_PARTITION);
//u32 logicalCount = std::mem::size(DISK.MBR.PT[i].EXTENDED_PARTITION);
for (u32 e = 0, e < logicalCount, e = e + 1) {
if (DISK.MBR.PT[i].EXTENDED_PARTITION[e].Type.PartTypeLabel == MPTPartLabel::UNUSED_OR_HIDDEN_ENTRY)
continue;
std::print("-----------------------------------------");
std::print("---------- LOGICAL (EXT) [{}] ------------", e);
std::print("-----------------------------------------");
// STATUS
str EXTstatusStr;
if (DISK.MBR.PT[i].EXTENDED_PARTITION[e].ActiveFlag == PartitionStatus::Active) {
EXTstatusStr = "ACTIVE/BOOTABLE";
} else if (DISK.MBR.PT[i].EXTENDED_PARTITION[e].ActiveFlag == PartitionStatus::Not_Active) {
EXTstatusStr = "INACTIVE/NOT_BOOTABLE";
} else {
EXTstatusStr = "UNKNOWN";
}
std::print(" STATUS = {}", EXTstatusStr);
// TYPE_CODE
str EXTtypeStr;
if (DISK.MBR.PT[i].EXTENDED_PARTITION[e].Type.Part_Type == PartitionTypeCode::FAT32_SMALL) {
EXTtypeStr = "FAT32 (CHS) (0x0B)";
} else if (DISK.MBR.PT[i].EXTENDED_PARTITION[e].Type.Part_Type == PartitionTypeCode::FAT32_BIG) {
EXTtypeStr = "FAT32 (LBA) (0x0C)";
} else if (DISK.MBR.PT[i].EXTENDED_PARTITION[e].Type.Part_Type == PartitionTypeCode::NTFS_EXFAT) {
EXTtypeStr = "NTFS/EXFAT (0x07)";
} else if (DISK.MBR.PT[i].EXTENDED_PARTITION[e].Type.Part_Type == PartitionTypeCode::GPT_DISK_STD) {
EXTtypeStr = "GPT_PROTECTIVE (0xEE)";
} else if (DISK.MBR.PT[i].EXTENDED_PARTITION[e].Type.Part_Type == PartitionTypeCode::EXT_PART_BIG) {
EXTtypeStr = "EXTENDED (0x0F)";
} else {
EXTtypeStr = "OTHER/UNKNOWN";
}
std::print(" TYPE_CODE = {}", EXTtypeStr);
std::print(" FIRST_LBA = {}", DISK.MBR.PT[i].EXTENDED_PARTITION[e].Start_LBA);
std::print(" LAST_LBA = {}", DISK.MBR.PT[i].EXTENDED_PARTITION[e].Start_LBA +
DISK.MBR.PT[i].EXTENDED_PARTITION[e].Total_Sectors - 1);
std::print(" VOL_SIZE = {} SECTORS", DISK.MBR.PT[i].EXTENDED_PARTITION[e].Total_Sectors);
std::print(" VOL_SIZE = {:.4f} GB",
(DISK.MBR.PT[i].EXTENDED_PARTITION[e].Total_Sectors * sector_size) / 1000.0 / 1000.0 / 1000.0);
std::print(" VOL_SIZE = {:.4f} GiB",
(DISK.MBR.PT[i].EXTENDED_PARTITION[e].Total_Sectors * sector_size) / 1024.0 / 1024.0 / 1024.0);
}
}
}
// GPT Header
if (GPT_Count >= 1) {
std::print("-----------------------------------------");
std::print("-------------- GPT_HEADER ---------------");
std::print("-----------------------------------------");
std::print("SIGNATURE = {}", DISK.GPT_HEADER.signature);
std::print("REVISION = 0x{:02X}", DISK.GPT_HEADER.revision);
std::print("GPT_HDR_CRC = 0x{:02X}", DISK.GPT_HEADER.header_crc32);
std::print("GPT_HDR_BACKUP_LBA = {}", DISK.GPT_HEADER.backup_lba);
std::print("DISK_GUID = {}", DISK.GPT_HEADER.disk_guid);
std::print("FIRST_USABLE_LBA = {}", DISK.GPT_HEADER.first_usable_lba);
std::print("LAST_USABLE_LBA = {}", DISK.GPT_HEADER.last_usable_lba);
std::print("MAX_GPT_ENTRIES = {:02}", DISK.GPT_HEADER.num_partition_entries);
std::print("GPT_ENTRY_SIZE = {:02} BYTES", DISK.GPT_HEADER.size_of_partition_entry);
std::print("GPT_ARRAY_CRC = 0x{:02X}", DISK.GPT_HEADER.partition_entries_crc32);
// GPT Partitions
for (u32 j = 0, j < GPT_Count, j = j + 1) {
std::print("-----------------------------------------");
std::print("------------- GPT_PART [{}] --------------", j);
std::print("-----------------------------------------");
std::print(" PART_TYPE_LABEL = {}", DISK.GPT_ENTRIES[j].Type.PartTypeLabel);
std::print(" PART_TYPE_GUID = {}", DISK.GPT_ENTRIES[j].Type.PartTypeGUID);
std::print(" UNIQUE_PART_GUID = {}", DISK.GPT_ENTRIES[j].Unique_GUID);
std::print(" FIRST_LBA = {:02}", DISK.GPT_ENTRIES[j].Start_LBA);
std::print(" LAST_LBA = {:02}", DISK.GPT_ENTRIES[j].End_LBA);
bool _any = false;
std::print(" ATTR_FLAGS |");
if(DISK.GPT_ENTRIES[j].ATTR.platform_required) {
std::print(" |- - - - > PlatformRequired");
_any = true;
}
if(DISK.GPT_ENTRIES[j].ATTR.io_ignore) {
std::print(" |- - - - > NO_FS_MAP");
_any = true;
}
if(DISK.GPT_ENTRIES[j].ATTR.legacy_flag) {
std::print(" |- - - - > LEGACY_BOOT");
_any = true;
}
if(DISK.GPT_ENTRIES[j].Type.PartTypeLabel == GUIDPartLabel::BASIC_DATA_PART) {
if(DISK.GPT_ENTRIES[j].ATTR.read_only) {
std::print(" |- - - - > READ_ONLY");
_any = true;
}
if(DISK.GPT_ENTRIES[j].ATTR.shadow_copy) {
std::print(" |- - - - > SHADOW_COPY");
_any = true;
}
if(DISK.GPT_ENTRIES[j].ATTR.hidden) {
std::print(" |- - - - > HIDDEN");
_any = true;
}
if(DISK.GPT_ENTRIES[j].ATTR.no_drive_letter) {
std::print(" |- - - - > NO_AUTO_MOUNT");
_any = true;
}
}
// if nothing was printed, say "NONE"
if (!_any) {
//std::print(" |> NONE");
std::print(" |- - - - > NONE");
}
std::print(" PART_TYPE_NAME = {}", DISK.GPT_ENTRIES[j].PartName);
}
}
std::print("-----------------------------------------");
std::print("------------------ END ------------------");
std::print("-----------------------------------------");
std::print(" ");
}

789
patterns/DFIR/FAT32.hexpat Normal file
View File

@@ -0,0 +1,789 @@
#pragma author Formula Zero One Technologies
#pragma description FAT32 File System (FAT32_v2.0)
#pragma MIME application/x-ima
#pragma endian little
// -----------------------------------------------------------------------------
// CREDIT
// -----------------------------------------------------------------------------
// OG AUTHOR: WerWolv
// OG DESC: fs/fat32.hexpat_v1.0
// -----------------------------------------------------------------------------
// NOTES FOR v2.0 ** GLOBALS NEED YOUR INPUT **
// -----------------------------------------------------------------------------
// Imported by DISK_PARSER.hexpat
// Added section separators for organization
// Added recursive parsing for Root Dir and a next level
// Added D/T conversions
// Show filenames on hover
// Added comments to DFIR fields of interest
// Changed pattern output naming/structure.
// Parse FAT1/FAT2
// Show SFN <-> Starting Cluster Relation Overlay
// -----------------------------------------------------------------------------
// TODO
// -----------------------------------------------------------------------------
// Parse all SFN/LFN entries, not just Root + 1
// -----------------------------------------------------------------------------
// IMPORTS
// -----------------------------------------------------------------------------
import std.core;
import std.io;
import std.mem;
import std.time;
import std.string;
import type.time;
// -----------------------------------------------------------------------------
// FORWARD DECS/GLOBALS
// -----------------------------------------------------------------------------
// *** ATTENTION ***
// SET MAXIMUM NUMBER OF 4 BYTE CHUNKS TO PARSE FROM FAT1
// DEFAULT IS 4096
// Choose a value greater than 1 and less than 65536 OR increase the Array size limit with "#define... "
// -------**************---vvvv--- |
const u64 MAX_FAT_CHUNKS = 4096;
// -------**************---^^^^--- |
// *** ATTENTION ***
// SET MAXIMUM NUMBER OF SFN = STARTING CLUSTER TO PROCESS
// DEFAULT IS 100 (2 LEVELS DEEP | ROOT DIR + 1)
// Choose a value greater than 1 and less than 65536 OR increase the Array size limit with "#define... "
// ---**************---************---vvv--- |
const u64 MAX_SFN_CLUSTER_RELATIONS = 100;
// ---**************---************---^^^--- |
// ---*******---*******----vvvv--- |
const bool VOLUME_REPORT = true;
// ---*******---*******----^^^^--- |
u64 bytesPerCluster = 0;
u64 rootDirSectors = 0;
u64 firstDataSector = 0;
u64 dataRegionStart = 0;
u64 sfn_count = 0;
u64 sfn_del_count = 0;
u64 lfn_count = 0;
u64 lfn_del_count = 0;
u64 start_index = 0;
u64 root_dir_start = 0;
u64 allocated_file_count = 0;
u64 VBR_OFFSET = 0;
u64 FAT1_start_offset = 0;
u64 FAT2_start_offset = 0;
u64 FAT_ClusterHeap_Count = 0;
u64 abs_FAT1_start_offset = 0;
u64 abs_FAT2_start_offset = 0;
u64 abs_rootDirStart_offset = 0;
// -----------------------------------------------------------------------------
// FILE ALLOCATION TABLE RELATED
// -----------------------------------------------------------------------------
// V V V V V V V V V V
// -----------------------------------------------------------------------------
// ------------------------------
// SFN <-> CLUSTER OVERLAY
// ------------------------------
struct INFO_Overlay {
u64 index = std::core::array_index();
u64 start_location = FAT1_start_offset + 8 + (index * 4);
u32 current_cluster = 2 + index;
str filename = overlay_func_name(current_cluster);
if (filename != "") {
char hover_label[4] @ start_location [[
name(std::format(
"SFN: {} | CLUSTER {}",
filename,
current_cluster
))]];
}
} [[inline]];
fn overlay_func_name(u32 cluster_num) {
str fname = "";
str ext = "";
str combo = "";
// Loop through all ROOT_DIR_ENTRIES
for (u32 i = 0, i < std::core::member_count(ROOT_DIR_ENTRIES), i = i + 1) {
// Check SFN_ALIAS and SFN_ENTRY in root entries
if (std::core::has_member(ROOT_DIR_ENTRIES[i], "SFN_ALIAS")) {
if (ROOT_DIR_ENTRIES[i].SFN_ALIAS.first_cluster == cluster_num) {
combo = std::format("{}.{}",
ROOT_DIR_ENTRIES[i].SFN_ALIAS.fileName,
ROOT_DIR_ENTRIES[i].SFN_ALIAS.extension);
return combo;
}
} else if (std::core::has_member(ROOT_DIR_ENTRIES[i], "SFN_ENTRY")) {
if (ROOT_DIR_ENTRIES[i].SFN_ENTRY.first_cluster == cluster_num) {
combo = std::format("{}.{}",
ROOT_DIR_ENTRIES[i].SFN_ENTRY.fileName,
ROOT_DIR_ENTRIES[i].SFN_ENTRY.extension);
return combo;
}
}
// Loop through all SUB_DIR_INDEX arrays for this root entry
if (std::core::has_member(ROOT_DIR_ENTRIES[i], "SUB_DIR_INDEX")) {
for (u32 j = 0, j < std::core::member_count(ROOT_DIR_ENTRIES[i].SUB_DIR_INDEX), j = j + 1) {
if (std::core::has_member(ROOT_DIR_ENTRIES[i].SUB_DIR_INDEX[j], "SFN_ALIAS")) {
if (ROOT_DIR_ENTRIES[i].SUB_DIR_INDEX[j].SFN_ALIAS.first_cluster == cluster_num) {
combo = std::format("{}.{}",
ROOT_DIR_ENTRIES[i].SUB_DIR_INDEX[j].SFN_ALIAS.fileName,
ROOT_DIR_ENTRIES[i].SUB_DIR_INDEX[j].SFN_ALIAS.extension);
return combo;
}
} else if (std::core::has_member(ROOT_DIR_ENTRIES[i].SUB_DIR_INDEX[j], "SFN_ENTRY")) {
if (ROOT_DIR_ENTRIES[i].SUB_DIR_INDEX[j].SFN_ENTRY.first_cluster == cluster_num) {
combo = std::format("{}.{}",
ROOT_DIR_ENTRIES[i].SUB_DIR_INDEX[j].SFN_ENTRY.fileName,
ROOT_DIR_ENTRIES[i].SUB_DIR_INDEX[j].SFN_ENTRY.extension);
return combo;
}
}
}
}
}
return ""; // no match found
};
// -----------------------------------------------------------------------------
// FAT32 FILE ALLOCATION TABLE (FAT) PARSER
// -----------------------------------------------------------------------------
const u32 CLUSTER_SIZE_BYTES = 4; // Each FAT32 entry = 4 bytes
const u32 FAT32_EOF = 0x0FFFFFFF; // End-of-file marker
const u32 FAT32_BAD = 0x0FFFFFF7; // Bad cluster marker
const u32 FIRST_ALLOC_CLUSTER = 2; // First usable cluster after reserved
enum FAT_Flags : u32 {
UNALLOCATED = 0x00000000,
END_OF_FILE = 0x0FFFFFFF, // L.END
BAD_CLUSTER = 0xFFFFFFF7, // L.END
//POINTER = Num >= 1 // INFO
};
union FAT_Union {
u32 DECIMAL [[hidden]];
FAT_Flags FAT_FLAG;
};
// ------------------------------
// Helper function for pointer label
// ------------------------------
fn cluster_label(u32 val) {
if (val == FAT_Flags::UNALLOCATED)
return "UNALLOCATED";
if (val == FAT_Flags::BAD_CLUSTER)
return "BAD";
if (val >= 0x0FFFFFF8)
return "EOF";
return std::format("{}", val);
};
// ------------------------------
// FAT1/FAT2 HEAPS/CHAINS
// ------------------------------
struct FAT_Entry {
FAT_Union FAT [[inline]];
u32 cluster_num = (FIRST_ALLOC_CLUSTER) + (std::core::array_index());
u32 next_cluster = FAT.DECIMAL & 0x0FFFFFFF;
char hover_label[4] @ $ - 4 [[
name(std::format(
"Cluster: {} → {}",
cluster_num,
cluster_label(next_cluster)
))
]];
bool is_eof = next_cluster >= 0x0FFFFFF8;
bool is_bad = next_cluster == FAT32_BAD;
bool is_free = next_cluster == 0;
if (is_eof) {
allocated_file_count += 1;
}
} [[name(format_fat_entry(FAT.DECIMAL, std::core::array_index(), FIRST_ALLOC_CLUSTER))]];
// ------------------------------
// FAT FORMATTER FUNC
// ------------------------------
fn format_fat_entry(u32 raw_value, u32 cluster_index, u32 first_alloc_cluster) {
u32 next_cluster = raw_value & 0x0FFFFFFF;
str next_label;
if (next_cluster == 0)
next_label = "UNALLOCATED";
else if (next_cluster == FAT32_BAD)
next_label = "BAD";
else if (next_cluster == 0x0FFFFFFF)
next_label = "EOF";
else
next_label = std::format("{}", next_cluster);
u32 logical_cluster = first_alloc_cluster + cluster_index;
if (next_label == "UNALLOCATED" || next_label == "BAD" || next_label == "EOF")
return std::format("Cluster {}: {}", logical_cluster, next_label);
else
return std::format("Cluster {} → {}", logical_cluster, next_label);
};
// ------------------------------
// MEDIA DESCRIPTOR HELPER
// ------------------------------
enum Media_Descriptor : u8 {
SINGLE_SIDE_FLOPPY = 0xF0,
DOUBLE_SIDE_FLOPPY = 0xF9,
HARD_DISK_DRIVE = 0xF8,
};
// ------------------------------
// FAT1/FAT2 HEADER PARSER
// ------------------------------
struct FAT_Header {
Media_Descriptor mediaDescriptor [[comment("0xF8=FIXED DISK | 0xF0=REMOVABLE")]];;
u8 FAT32_FAT_HEADER[7] [[comment("8 BYTES TOTAL: 4 BYTES REPRESENT PSUEDO CLUSTER 0 (SYSTEM) | 4 BYTES REPRESENT PSUEDO CLUSTER 1 (SYSTEM)(EOF)")]];
char root_dir_label[4] @ $ [[
name(std::format(
"ROOT_DIRECTORY"
))
]];
// WHICH IS WHY THE ROOT DIRECTORY (FIRST DATA AREA ITEM) STARTS IN CLUSTER 2
};
// -----------------------------------------------------------------------------
// ROOT DIRECTORY RELATED
// -----------------------------------------------------------------------------
// V V V V V V V V V V
// -----------------------------------------------------------------------------
// ------------------------------
// ACTIVE LFN SEQUENCE NUMBER BITFIELD
// * EXCEPT DELETED ENTRIES - 0xE5 *
// ------------------------------
bitfield LFN_Sequence {
padding : 1;
IS_LAST_ENTRY : 1 [[name("IS_LAST_ENTRY: [0=NO | 1=YES] ==")]];
padding : 1;
LFN_SEQ_NUM : 5;
} [[bitfield_order(
std::core::BitfieldOrder::MostToLeastSignificant, 8)]];
// ------------------------------
// DIRECTORY ENTRY STATUS/SEQUENCE HELPERS
// ------------------------------
enum Entry_Status : u8 {
EMPTY_ENTRY = 0x00,
DOT_ENTRY = 0x2E,
DELETED_ENTRY = 0xE5,
ACTIVE_1ST_ENTRY = 0x01,
ACTIVE_2ND_ENTRY = 0x02,
ACTIVE_3RD_ENTRY = 0x03,
ACTIVE_4TH_ENTRY = 0x04,
ACTIVE_5TH_ENTRY = 0x05,
ACTIVE_6TH_ENTRY = 0x06,
ACTIVE_7TH_ENTRY = 0x07,
ACTIVE_8TH_ENTRY = 0x08,
ACTIVE_9TH_ENTRY = 0x09,
ACTIVE_10TH_ENTRY = 0x0A,
ACTIVE_11TH_ENTRY = 0x0B,
ACTIVE_12TH_ENTRY = 0x0C,
ACTIVE_13TH_ENTRY = 0x0D,
ACTIVE_14TH_ENTRY = 0x0E,
ACTIVE_15TH_ENTRY = 0x0F,
ACTIVE_16TH_ENTRY = 0x10,
ACTIVE_17TH_ENTRY = 0x11,
ACTIVE_18TH_ENTRY = 0x12,
ACTIVE_19TH_ENTRY = 0x13,
ACTIVE_20TH_ENTRY = 0x14,
ACTIVE_1ST_ENTRY_LAST = 0x41,
ACTIVE_2ND_ENTRY_LAST = 0x42,
ACTIVE_3RD_ENTRY_LAST = 0x43,
ACTIVE_4TH_ENTRY_LAST = 0x44,
ACTIVE_5TH_ENTRY_LAST = 0x45,
ACTIVE_6TH_ENTRY_LAST = 0x46,
ACTIVE_7TH_ENTRY_LAST = 0x47,
ACTIVE_8TH_ENTRY_LAST = 0x48,
ACTIVE_9TH_ENTRY_LAST = 0x49,
ACTIVE_10TH_ENTRY_LAST = 0x4A,
ACTIVE_11TH_ENTRY_LAST = 0x4B,
ACTIVE_12TH_ENTRY_LAST = 0x4C,
ACTIVE_13TH_ENTRY_LAST = 0x4D,
ACTIVE_14TH_ENTRY_LAST = 0x4E,
ACTIVE_15TH_ENTRY_LAST = 0x4F,
ACTIVE_16TH_ENTRY_LAST = 0x50,
ACTIVE_17TH_ENTRY_LAST = 0x51,
ACTIVE_18TH_ENTRY_LAST = 0x52,
ACTIVE_19TH_ENTRY_LAST = 0x53,
ACTIVE_20TH_ENTRY_LAST = 0x54,
};
// ------------------------------
// HELPER FOR LFN FIRST BYTE
// ------------------------------
union LFNEntry_FirstByte {
Entry_Status status;
LFN_Sequence seq_num;
};
// ------------------------------
// SFN ATTRIBUTE HELPER
// ------------------------------
bitfield Attributes {
readOnly : 1;
hidden : 1;
systemFile : 1;
volumeLabel : 1;
subDirectory : 1;
archive : 1;
padding : 2;
} [[bitfield_order(
std::core::BitfieldOrder::LeastToMostSignificant, 8)]];
// ------------------------------
// ROOT DIRECTORY ENTRY FUNC
// ------------------------------
fn dir_entry_marker(u64 abs_off) {
u8 first @ abs_off;
return first;
};
// ------------------------------
// ROOT DIRECTORY ENTRY FUNC
// ------------------------------
fn dir_entry_attr(u64 abs_off) {
u8 attr @ abs_off + 0x0B;
return attr;
};
// ------------------------------
// DATES AND TIMES FUNC
// ------------------------------
fn format_dos_time_field(std::time::DOSTime t) {
return std::time::format_dos_time(t, "{:02}:{:02}:{:02}");
};
fn format_dos_date_field(std::time::DOSDate d) {
return std::time::format_dos_date(d, "{1:02}-{0:02}-{2:04}");
};
// ------------------------------
// SHORT FILE NAME ALIAS PARSER
// ------------------------------
struct SFN_Entry_Alias {
char fileName[8] [[name("SFN"), comment("Short File Name (8dot3)")]];
char extension[3] [[name("EXT"), comment("File Extension (8dot3)")]];
Attributes attributes [[name("RASH ATTR"), comment("Read-Only | Archive | System | Hidden | SubDir...")]];
u8 reserved [[comment("Zeros")]];
u8 milliseconds [[comment("Add to Times for Refinement")]];
std::time::DOSTime Created_Time [[format("format_dos_time_field")]];
std::time::DOSDate Created_Date [[format("format_dos_date_field")]];
std::time::DOSDate Accessed_Date [[format("format_dos_date_field")]];
u16 Cluster_Hi [[comment("High Cluster if Needed")]];
std::time::DOSTime Modified_Time [[format("format_dos_time_field")]];
std::time::DOSDate Modified_Date [[format("format_dos_date_field")]];
u16 Cluster_Lo [[comment("Starting Cluster or Combine with Cluster_Hi")]];
u32 fileSize [[name("FILE_SIZE"), comment("File Size in Bytes")]];
u32 first_cluster = (Cluster_Hi << 16) | Cluster_Lo;
u8 FILE_DATA[fileSize] @ dataRegionStart + (first_cluster -2) * bytesPerCluster [[comment("Pointer to the Files Content")]];
sfn_count += 1;
if (fileName[0] == 0xE5) {
sfn_del_count += 1;
}
};
// ------------------------------
// LOOOONG FILE NAME PARSER
// ------------------------------
struct LFN_Entry {
u64 curr_first_byte = $;
u8 curr_attr = dir_entry_attr(curr_first_byte);
LFNEntry_FirstByte SeqByte [[name("SEQUENCE_NUM"), comment("0x01-0x20 | Add 0x40 to Last LFN Entry")]];
char16 NAME_1[5] [[comment("First 5 Characters of LFN")]];
Attributes attributes [[name("LFN_ATTR"), comment("0x0F = LFN")]];
padding[1] [[comment("Zeros")]];
u8 nameChecksum [[name("Checksum"), comment("Checksum Calculated on SFN_ALIAS")]];
char16 NAME_2[6] [[comment("Next 6 Characters of LFN")]];
padding[2] [[comment("Zeros")]];
char16 NAME_3[2] [[comment("Next 2 Characters of LFN")]];
// ATTEMPT TO CLEANUP UNICODE LFN... DOES NOT ACCOUNT FOR MULTI LFN ENTRIES
if (curr_attr == 0x0F) {
char display_name[32] @ $ - 32 [[
name(
(NAME_1[0] >= 0x20 && NAME_1[0] <= 0x7E ? std::string::to_string(NAME_1[0]) : "") +
(NAME_1[1] >= 0x20 && NAME_1[1] <= 0x7E ? std::string::to_string(NAME_1[1]) : "") +
(NAME_1[2] >= 0x20 && NAME_1[2] <= 0x7E ? std::string::to_string(NAME_1[2]) : "") +
(NAME_1[3] >= 0x20 && NAME_1[3] <= 0x7E ? std::string::to_string(NAME_1[3]) : "") +
(NAME_1[4] >= 0x20 && NAME_1[4] <= 0x7E ? std::string::to_string(NAME_1[4]) : "") +
(NAME_2[0] >= 0x20 && NAME_2[0] <= 0x7E ? std::string::to_string(NAME_2[0]) : "") +
(NAME_2[1] >= 0x20 && NAME_2[1] <= 0x7E ? std::string::to_string(NAME_2[1]) : "") +
(NAME_2[2] >= 0x20 && NAME_2[2] <= 0x7E ? std::string::to_string(NAME_2[2]) : "") +
(NAME_2[3] >= 0x20 && NAME_2[3] <= 0x7E ? std::string::to_string(NAME_2[3]) : "") +
(NAME_2[4] >= 0x20 && NAME_2[4] <= 0x7E ? std::string::to_string(NAME_2[4]) : "") +
(NAME_2[5] >= 0x20 && NAME_2[5] <= 0x7E ? std::string::to_string(NAME_2[5]) : "") +
(NAME_3[0] >= 0x20 && NAME_3[0] <= 0x7E ? std::string::to_string(NAME_3[0]) : "") +
(NAME_3[1] >= 0x20 && NAME_3[1] <= 0x7E ? std::string::to_string(NAME_3[1]) : "")
)
]];
}
lfn_count += 1;
if (SeqByte.status == Entry_Status::DELETED_ENTRY) {
lfn_del_count += 1;
}
};
// ------------------------------
// SHORT FILE NAME PARSER
// ------------------------------
struct SFN_Entry {
char fileName[8] [[name("SFN"), comment("Short File Name (8dot3)")]];
char extension[3] [[name("EXT"), comment("File Extension (8dot3)")]];
Attributes attributes [[name("RASH ATTR"), comment("Read-Only | Archive | System | Hidden | SubDir...")]];
u8 reserved [[comment("Zeros")]];
u8 milliseconds [[comment("Add to Times for Refinement")]];
std::time::DOSTime Created_Time [[format("format_dos_time_field")]];
std::time::DOSDate Created_Date [[format("format_dos_date_field")]];
std::time::DOSDate Accessed_Date [[format("format_dos_date_field")]];
u16 Cluster_Hi [[comment("High Cluster if Needed")]];
std::time::DOSTime Modified_Time [[format("format_dos_time_field")]];
std::time::DOSDate Modified_Date [[format("format_dos_date_field")]];
u16 Cluster_Lo [[comment("Starting Cluster or Combine with Cluster_Hi")]];
u32 fileSize [[name("FILE_SIZE"), comment("File Size in Bytes")]];
u32 first_cluster = (Cluster_Hi << 16) | Cluster_Lo;
u8 FILE_DATA[fileSize] @ dataRegionStart + (first_cluster -2) * bytesPerCluster [[comment("Pointer to the File Content")]];
sfn_count += 1;
if (fileName[0] == 0xE5) {
sfn_del_count += 1;
}
};
// ------------------------------
// SUBDIRECTORY PARSER | LEVEL 2
// ------------------------------
struct SubDirParser {
u8 first = dir_entry_marker($);
u8 attr = dir_entry_attr($);
u64 next_first_byte = $ + 32;
u8 next_attr = dir_entry_attr(next_first_byte); // current offset plus 12 bytes (offset 0x0B of entry)
if (first != 0x00 && attr == 0x0F) {
LFN_Entry LFN_ENTRY;
if (next_first_byte != 0x00 && next_first_byte != 0xE5 && next_attr == 0x0F) {
LFN_Entry next_LFN_ENTRY;
SFN_Entry_Alias SFN_ALIAS;
}
} else if (first != 0x00 && attr != 0x0F) {
SFN_Entry SFN_ENTRY;
}
};
// ------------------------------
// ROOT DIRECTORY ENTRY PARSER
// ROUGH METHOD OF PARSING SFN/LFN/SFN_ALIAS/SUBDIR TWO LEVELS DEEP
// IF THE PATTERN CRASHES - THIS IS LIKELY WHY
// ------------------------------
struct RootDirParser {
u64 curr_first_byte = $;
u8 curr_attr = dir_entry_attr(curr_first_byte); // current offset plus 12 bytes (offset 0x0B of entry)
u64 next_first_byte = $ + 32;
u8 next_attr = dir_entry_attr(next_first_byte); // current offset plus 12 bytes (offset 0x0B of entry)
bool is_subdir = false;
if (curr_first_byte != 0x00 && curr_first_byte != 0xE5 && curr_attr == 0x0F) {
LFN_Entry LFN_ENTRY;
if (next_first_byte != 0x00 && next_first_byte != 0xE5 && next_attr == 0x0F) {
LFN_Entry next_LFN_ENTRY;
SFN_Entry_Alias SFN_ALIAS;
is_subdir = SFN_ALIAS.attributes.subDirectory;
if (SFN_ALIAS.attributes.subDirectory && next_first_byte != 0x00 && next_attr != 0xE5) {
is_subdir = SFN_ALIAS.attributes.subDirectory;
u64 dir_start_addr = dataRegionStart + (SFN_ALIAS.first_cluster - 2) * bytesPerCluster;
SubDirParser SUB_DIR_INDEX[while(std::mem::read_unsigned($, 1) != 0x00)] @ dir_start_addr;
}
}
if (next_first_byte != 0x00 && next_first_byte != 0xE5 && next_attr != 0x0F) {
SFN_Entry_Alias SFN_ALIAS;
is_subdir = SFN_ALIAS.attributes.subDirectory;
if (SFN_ALIAS.attributes.subDirectory && next_first_byte != 0x00 && next_attr != 0xE5) {
is_subdir = SFN_ALIAS.attributes.subDirectory;
u64 dir_start_addr = dataRegionStart + (SFN_ALIAS.first_cluster - 2) * bytesPerCluster;
SubDirParser SUB_DIR_INDEX[while(std::mem::read_unsigned($, 1) != 0x00)] @ dir_start_addr;
}
}
} else if (curr_first_byte != 0x00 && curr_first_byte != 0xE5 && curr_attr != 0x0F) {
SFN_Entry SFN_ENTRY;
is_subdir = SFN_ENTRY.attributes.subDirectory;
if (SFN_ENTRY.attributes.subDirectory && next_first_byte != 0x00 && next_attr != 0xE5) {
is_subdir = SFN_ENTRY.attributes.subDirectory;
u64 dir_start_addr = dataRegionStart + (SFN_ENTRY.first_cluster - 2) * bytesPerCluster;
SubDirParser SUB_DIR_INDEX[while(std::mem::read_unsigned($, 1) != 0x00)] @ dir_start_addr;
}
} else if (curr_first_byte != 0x00 && current_first_byte == 0xE5) {
if (next_first_byte != 0x00 && next_attr == 0x0F) {
LFN_Entry LFN_ENTRY;
if (next_first_byte != 0x00 && next_first_byte != 0xE5) {
if (next_attr != 0x0F) {
SFN_Entry_Alias SFN_ALIAS;
is_subdir = SFN_ALIAS.attributes.subDirectory;
if (next_first_byte != 0x00 && next_first_byte != 0xE5 && next_attr != 0x0F) {
SFN_Entry_Alias SFN_ALIAS2; // otherwise switch to SFN
is_subdir = SFN_ALIAS.attributes.subDirectory;
if (SFN_ALIAS.attributes.subDirectory && next_first_byte != 0x00 && next_attr != 0xE5) {
is_subdir = SFN_ALIAS.attributes.subDirectory;
u64 dir_start_addr = dataRegionStart + (SFN_ALIAS.first_cluster - 2) * bytesPerCluster;
SubDirParser SUB_DIR_INDEX[while(std::mem::read_unsigned($, 1) != 0x00)] @ dir_start_addr;
}
}
}
}
} else {
SFN_Entry SFN_ENTRY;
is_subdir = SFN_ENTRY.attributes.subDirectory;
}
}
} [[name(format_element($, start_index, is_subdir)), comment("FILE/DIR [INDX #]")]];
// ------------------------------
// NAME FORMATTER
// ------------------------------
fn format_element(auto v, u64 offset, bool subdir) {
if (subdir) {
return std::format("SUB_DIR [{:02}]", std::core::array_index() + offset);
} else {
return std::format("FILE [{:02}]", std::core::array_index() + offset);
}
};
// ------------------------------
// ROOT DIRECTORY HEADER PARSER
// ------------------------------
struct RootDirHeader {
char VolumeName[11] [[comment("User Defined Name of the VOL")]];
u8 VolumeLabelFlag [[comment("Indicates the Preceding VOL LABEL")]];
padding[10] [[comment("Zeros")]];
std::time::DOSTime Created_Time [[format("format_dos_time_field"), comment("Last Write Time - Typically when Created/Formatted, but NOT ALWAYS...(DISK IMAGE/FAT DRIVERS)")]];
std::time::DOSDate Created_Date [[format("format_dos_date_field"), comment("Last Write Date - Typically when Created/Formatted, but NOT ALWAYS...(DISK IMAGE/FAT DRIVERS)")]];
padding[6] [[comment("Zeros")]];
};
// ------------------------------
// VBR SIGNATURE HELPER
// ------------------------------
enum VBRSignature : u16 {
VBR_SIG = 0xAA55
};
// ------------------------------
// FILE SYSTEM INFO BLOCK
// ------------------------------
struct FSInfo {
u32 leadSignature [[comment("RRaA")]];
padding[480] [[comment("Zeros")]];
u32 structSignature [[comment("FSINFO Signature")]];
u32 freeClusterCount [[comment("Approximate Free Cluster Count")]];
u32 nextFreeCluster [[comment("FAT1: Suggested Starting Point")]];
padding[14] [[comment("Zeros")]];
VBRSignature VBR_SIG [[comment("0x55AA")]];
};
// ------------------------------
// FAT12/16/32 BIOS PARAMETER BLOCK (BPB)
// ------------------------------
struct BPB_Common {
u8 jmp_boot[3] [[comment("Assembly Instructions to Jump to Boot Code")]];
char oem_name[8] [[comment("MSDOS/BSD")]];
u16 bytes_per_sector [[comment("512,1024,2048,4096")]];
u8 sectors_per_cluster [[comment("Under 32K - Must be a power of 2")]];
u16 reserved_sectors [[comment("Size of Reserved Area in Sectors")]];
u8 num_fats [[comment("Typically 2, but can be 1 for Small Volumes")]];
u16 root_entry_count [[comment("Max Num of Entries -- 0 for FAT32| 512 for FAT16")]];
u16 total_sectors16 [[comment("if 0, use total_sectors32")]];
u8 media_type [[comment("0xF8=FIXED DISK | 0xF0=REMOVABLE")]];
u16 fat_size16 [[comment("Size of each FAT in Sectors for FAT12/16; 0 for FAT32")]];
u16 sectors_per_track [[comment("Legacy")]];
u16 num_heads [[comment("Legacy")]];
u32 hidden_sectors [[comment("Num of Sectors before the Volume")]];
u32 total_sectors32 [[comment("32bit Value of Total Num of Sectors in Volume")]];
// ----------------------vvv-----
// FAT32 EXTENDED
// ----------------------vvv-----
u32 FAT_Sector_Count [[comment("Total Sectors per FAT")]];
u16 ext_flags [[comment("16bit Value: BIT_7 = 1 == 1 FAT USED | Otherwise both FATs USED")]];
u16 fs_version [[comment("Major and Minor | None")]];
u32 root_cluster [[comment("Cluster Num of Root Dir")]];
u16 fs_info_sector [[comment("FS_INFO Location")]];
u16 backup_boot_sector [[comment("VBR Backup Location")]];
u8 reserved[12] [[comment("Zeros")]];
u8 drive_number [[comment("BIOS INT13h Drive Num")]];
u8 reserved1 [[comment("Zeros")]];
u8 boot_signature [[comment("Extended Boot Sig = 0x29")]];
u32 volume_id [[comment("Volume Serial Number - Based on Created Date/Time")]];
char volume_label[11] [[comment("No Name | User Defined Name | Check Root Dir")]];
char fs_type[8] [[comment("FAT32 ")]];
u8 bootstrap[420] [[comment("Until Signature")]];
VBRSignature VBR_SIG [[comment("0x55AA")]];
// ----------------------vvv-----
// UPDATE CONSTANTS/GLOBALS
// ----------------------vvv-----
bytesPerCluster = sectors_per_cluster * bytes_per_sector;
rootDirSectors = ((root_entry_count * 32) + (bytes_per_sector - 1)) / bytes_per_sector;
firstDataSector = reserved_sectors + (num_fats * FAT_Sector_Count) + rootDirSectors;
dataRegionStart = firstDataSector * bytes_per_sector;
};
// -----------------------------------------------------------------------------
// FAT32 MAIN RELATED
// -----------------------------------------------------------------------------
// V V V V V V V V V V
// -----------------------------------------------------------------------------
// ------------------------------
// FAT32 VOLUME BOOT RECORD
// ------------------------------
BPB_Common F32_VBR @ $;
VBR_OFFSET = F32_VBR.hidden_sectors * F32_VBR.bytes_per_sector;
/// ------------------------------
// FILE SYSTEM INFO BLOCK
// ------------------------------
FSInfo FS_INFO @ F32_VBR.fs_info_sector * F32_VBR.bytes_per_sector;
root_dir_start = dataRegionStart + ((F32_VBR.root_cluster - 2) * bytesPerCluster) + 32;
// ------------------------------
// FILE ALLOCATION TABLE
// *** HAS GLOBAL AT TOP ***
// ------------------------------
FAT1_start_offset = F32_VBR.reserved_sectors * F32_VBR.bytes_per_sector;
FAT2_start_offset = FAT1_start_offset + (F32_VBR.FAT_Sector_Count * F32_VBR.bytes_per_sector);
FAT_ClusterHeap_Count = F32_VBR.FAT_Sector_Count * F32_VBR.bytes_per_sector / CLUSTER_SIZE_BYTES;
FAT_Header FAT1_HEADER @ FAT1_start_offset;
FAT_Entry FAT1[MAX_FAT_CHUNKS] @ FAT1_start_offset + 8;
FAT_Header FAT2_HEADER @ FAT2_start_offset;
FAT_Entry FAT2[MAX_FAT_CHUNKS] @ FAT2_start_offset + 8;
// ------------------------------
// ROOT DIRECTORY HEADER
// ------------------------------
RootDirHeader ROOT_DIR_HEADER @ dataRegionStart + ((F32_VBR.root_cluster - 2) * bytesPerCluster);
// ----*-----*------*------*-----
// * * ROOT DIRECTORY PARSER * *
// ----*-----*------*------*-----
RootDirParser ROOT_DIR_ENTRIES[while(std::mem::read_unsigned($, 1) != 0x00)] @ root_dir_start;
// ------------------------------
// SFN <-> CLUSTER RELATION OVERLAY
// *** HAS GLOBAL AT TOP ***
// ------------------------------
INFO_Overlay SFN_CLUSTER_LIST[MAX_SFN_CLUSTER_RELATIONS] @ FAT1_start_offset [[name("SFN <-> CLUSTER (DERIVED)")]];
// ------------------------------
// FAT32 VOLUME REPORT
// *** HAS GLOBAL AT TOP ***
// ------------------------------
abs_FAT1_start_offset = VBR_OFFSET + (F32_VBR.reserved_sectors * F32_VBR.bytes_per_sector);
abs_FAT2_start_offset = abs_FAT1_start_offset + (F32_VBR.FAT_Sector_Count * F32_VBR.bytes_per_sector);
abs_rootDirStart_offset = VBR_OFFSET + dataRegionStart;
if (VOLUME_REPORT) {
std::print(" ");
std::print("-----------------------------------------");
std::print("---------- FAT32 VOLUME_REPORT ----------");
std::print("-----------------------------------------");
std::print("VOL_LABEL = {}", F32_VBR.volume_label);
std::print("FILE_SYSTEM = {}", F32_VBR.fs_type);
std::print("SERIAL_NUMBER = 0x{:X}", F32_VBR.volume_id);
std::print("-----------------------------------------");
std::print("BYTES/SECTOR = {:02}", F32_VBR.bytes_per_sector);
std::print("SECTORS/CLUSTER = {:02}", F32_VBR.sectors_per_cluster);
std::print("BYTES/CLUSTER = {:02}", bytesPerCluster);
std::print("ROOT_ENTRIES = {:02}", F32_VBR.root_entry_count);
std::print("CLUSTER_COUNT = {:02}", (F32_VBR.total_sectors32 - firstDataSector) / F32_VBR.sectors_per_cluster);
std::print("-----------------------------------------");
std::print("VOLUME_SIZE = {:02} SECTORS", F32_VBR.total_sectors32);
std::print("VOLUME_SIZE = {:.4f} GB @ 1000", (F32_VBR.total_sectors32 * F32_VBR.bytes_per_sector) / 1000.0 / 1000.0 / 1000.0);
std::print("VOLUME_SIZE = {:.4f} GiB @ 1024", (F32_VBR.total_sectors32 * F32_VBR.bytes_per_sector) / 1024.0 / 1024.0 / 1024.0);
std::print("-----------------------------------------");
std::print("RESERVED_SECTORS = {:02}", F32_VBR.reserved_sectors);
std::print("FAT_COUNT = {:02}", F32_VBR.num_fats);
std::print("FAT_SIZE = {:02} SECTORS", F32_VBR.FAT_Sector_Count);
std::print("FAT1_START_OFF = {} | 0x{:02X}", abs_FAT1_start_offset, abs_FAT1_start_offset);
std::print("FAT2_START_OFF = {} | 0x{:02X}", abs_FAT2_start_offset, abs_FAT2_start_offset);
std::print("ROOT_DIR_CLUSTER = {:02}", F32_VBR.root_cluster);
std::print("ROOT_DIR_OFFSET = {} | 0x{:02X}", abs_rootDirStart_offset, abs_rootDirStart_offset);
std::print("-----------------------------------------");
if (sfn_del_count >= 1) {
std::print("SFN_DEL(xE5) = DETECTED");
}
if (lfn_del_count >= 1) {
std::print("LFN_DEL(xE5) = DETECTED");
}
std::print("FAT1_EOF_COUNT = {:02}", allocated_file_count / 2); // divided by 2 (FAT1/FAT2)
std::print("-----------------------------------------");
std::print("------------------ END ------------------");
std::print("-----------------------------------------");
std::print(" ");
}

1571
patterns/DFIR/NTFS.hexpat Normal file

File diff suppressed because it is too large Load Diff

616
patterns/DFIR/exFAT.hexpat Normal file
View File

@@ -0,0 +1,616 @@
#pragma author Formula Zero One Technologies
#pragma description exFAT Filesystem (exFAT_v2.0)
#pragma MIME application/x-ima
#pragma endian little
// -----------------------------------------------------------------------------
// CREDIT
// -----------------------------------------------------------------------------
// Based on /fs/exfat.hexpat by WerWolv
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
// NOTES
// -----------------------------------------------------------------------------
// Imported by DISK_PARSER.hexpat
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
// TODO
// -----------------------------------------------------------------------------
// Recursive parsing of Root Directory / SubDirs
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
// IMPORTS
// -----------------------------------------------------------------------------
import std.core;
import std.io;
import std.time;
import std.mem;
import type.guid;
import type.magic;
import type.base;
// ------------------------------
// FORWARD DECS/GLOBALS
// ------------------------------
// *** ATTENTION ***
// SET MAXIMUM NUMBER OF 4 BYTE CHUNKS TO PARSE FROM FAT1
// SET MAXIMUM NUMBER OF DIRECTORY ENTRIES TO PARSE FROM ROOT DIRECTORY
// DEFAULTS ARE 4096 | 2500
// Choose a value greater than 1 and less than 65536 OR increase the Array size limit with "#define... "
// -------**************---vvvv--- |
const u64 MAX_FAT_CHUNKS = 4096;
// -------**************---^^^^--- |
// -------**************---vvvv--- |
const u64 MAX_DIR_ENTRIES = 2500;
// -------**************---^^^^--- |
// *** ATTENTION ***
// ---*******---*******----vvvv--- |
const bool VOLUME_REPORT = true;
// ---*******---*******----^^^^--- |
u64 allocated_file_count;
u64 rdc;
// --------------------------
// exFAT DIRECTORY ENTRY HELPER
// --------------------------
enum EntryType : u8 {
UNUSED_ENTRY = 0x00,
ACTIVE_VOLUME_GUID_ENTRY = 0xA0,
INACTIVE_VOLUME_GUID_ENTRY = 0x20,
ACTIVE_TEXFAT_ENTRY = 0xA1,
INACTIVE_TEXFAT_ENTRY = 0x21,
ACTIVE_ACCESS_CONTROL_ENTRY = 0xA2,
INACTIVE_ACCESS_CONTROL_ENTRY = 0x22,
ACTIVE_VOLUME_LABEL_ENTRY = 0x83,
INACTIVE_VOLUME_LABEL_ENTRY = 0x03,
ACTIVE_ALLOCATION_BITMAP_ENTRY = 0x81,
INACTIVE_ALLOCATION_BITMAP_ENTRY = 0x01,
ACTIVE_UPCASE_TABLE_ENTRY = 0x82,
INACTIVE_UPCASE_TABLE_ENTRY = 0x02,
ACTIVE_FILE_INFO_ENTRY = 0x85,
INACTIVE_FILE_INFO_ENTRY = 0x05,
ACTIVE_STREAM_ENTRY = 0xC0,
INACTIVE_STREAM_ENTRY = 0x40,
ACTIVE_FILENAME_ENTRY = 0xC1,
INACTIVE_FILENAME_ENTRY = 0x41,
};
// ------------------------------
// DATES AND TIMES FUNC
// ------------------------------
fn format_dos_time_field(std::time::DOSTime t) {
return std::time::format_dos_time(t, "{:02}:{:02}:{:02}");
};
fn format_dos_date_field(std::time::DOSDate d) {
return std::time::format_dos_date(d, "{1:02}-{0:02}-{2:04}");
};
// ------------------------------
// BITFIELD HELPERS
// ------------------------------
bitfield Entry_Flags {
unsigned TypeCode : 5;
unsigned Importance : 1;
unsigned Category : 1;
unsigned InUse : 1;
} [[bitfield_order(std::core::BitfieldOrder::LeastToMostSignificant, 8)]];
bitfield Bitmap_Flags {
unsigned Bitmap_1 : 1;
unsigned Bitmap_2 : 1;
} [[bitfield_order(std::core::BitfieldOrder::LeastToMostSignificant, 8)]];
bitfield General_Primary_Flags {
unsigned Allocation_Possible : 1;
unsigned No_FAT_Chain : 1;
unsigned Reserved : 6;
} [[bitfield_order(std::core::BitfieldOrder::LeastToMostSignificant, 8)]];
bitfield General_Secondary_Flags {
unsigned Allocation_Possible : 1;
unsigned No_FAT_Chain : 1;
unsigned Reserved : 6;
} [[bitfield_order(std::core::BitfieldOrder::LeastToMostSignificant, 8)]];
bitfield File_Attr_Flags {
unsigned Read_Only : 1;
unsigned Hidden : 1;
unsigned System : 1;
unsigned Directory : 1;
unsigned Archive : 1;
Reserved : 11;
} [[bitfield_order(std::core::BitfieldOrder::LeastToMostSignificant, 16)]];
// --------------------------
// exFAT DIRECTORY ENTRY STRUCTURES
// --------------------------
// xA0 / x20 = Volume GUID Entry
struct VolumeGUID_Entry {
Entry_Flags EntryFlags [[comment("ENTRY TYPE IDENTIFIER")]];
u8 SecondaryCount[3] [[comment("COUNT OF SUBSEQUENT ENTRIES")]];
type::Hex<u16> SetChecksum [[comment("16bit CHECKSUM")]];
General_Primary_Flags PrimaryFlags;
type::GUID GUID;
u8 Reserved_1[9];
};
// xA1 / x21 = TexFAT / Padding Entry
struct TexFATPadding_Entry {
Entry_Flags Flags [[comment("ENTRY TYPE IDENTIFIER")]];
u8 Reserved_1[31];
};
// xA2 / x22 = Access Control Entry
struct AccessControl_Entry {
Entry_Flags Flags [[comment("ENTRY TYPE IDENTIFIER")]];
u8 Reserved[31];
};
// x83 / x03 = Volume Label Entry
struct VolumeLabel_Entry {
Entry_Flags Flags [[comment("ENTRY TYPE IDENTIFIER")]];
u8 LabelLength [[comment("NUMBER OF UTF-16 CHARACTERS")]];
char16 Label[LabelLength] [[comment("VOLUME LABEL: UTF-16")]];
u8 Reserved[32-2-(LabelLength * 2)];
};
// x81 / x01 = Allocation Bitmap Entry
struct AllocationBitmap_Entry {
Entry_Flags Flags [[comment("ENTRY TYPE IDENTIFIER")]];
Bitmap_Flags BitmapFlags;
u8 Reserved_1[18];
u32 FirstCluster [[comment("FIRST LOGICAL CLUSTER NUMBER")]];
u64 DataLength [[comment("DATA SIZE")]];
u8 FILE_DATA[DataLength] @ temp_root_location + (FirstCluster - exFAT_VBR.root_dir_cluster) * bytesPerCluster [[comment("POINTER TO THE CLUSTER CONTENT")]];
};
// x82 / x02 = UpCase Table Entry
struct UpCaseTable_Entry {
Entry_Flags Flags [[comment("ENTRY TYPE IDENTIFIER")]];
u8 Reserved_1[3];
type::Hex<u32> TableChecksum [[comment("16bit CHECKSUM")]];
u8 Reserved_2[12];
u32 FirstCluster [[comment("FIRST LOGICAL CLUSTER NUMBER")]];
u64 DataLength [[comment("DATA SIZE")]];
u8 FILE_DATA[DataLength] @ temp_root_location + (FirstCluster - exFAT_VBR.root_dir_cluster) * bytesPerCluster [[comment("POINTER TO THE CLUSTER CONTENT")]];
};
// x85 / x05 = File Info Entry
struct FileInfo_Entry {
Entry_Flags EntryFlags [[comment("ENTRY TYPE IDENTIFIER")]];
u8 SecondaryCount [[comment("COUNT OF SUBSEQUENT ENTRIES")]];
type::Hex<u16> SetChecksum [[comment("16bit CHECKSUM")]];
File_Attr_Flags AttrFlags [[comment("FILE ATTRS: RASH")]];
u16 Reserved_1;
std::time::DOSTime Created_Time [[format("format_dos_time_field")]];
std::time::DOSDate Created_Date [[format("format_dos_date_field")]];
std::time::DOSTime Accessed_Time [[format("format_dos_time_field")]];
std::time::DOSDate Accessed_Date [[format("format_dos_date_field")]];
std::time::DOSTime Modified_Time [[format("format_dos_time_field")]];
std::time::DOSDate Modified_Date [[format("format_dos_date_field")]];
u8 Created_10ms_Increments [[comment("Add to Times for Refinement")]];
u8 Modified_10ms_Increments [[comment("Add to Times for Refinement")]];
s8 Created_UTC_Diff [[comment("Add to Times for Refinement")]];
s8 Modified_UTC_Diff [[comment("Add to Times for Refinement")]];
s8 Accessed_UTC_Diff [[comment("Add to Times for Refinement")]];
u8 Reserved[7];
};
// xC1 / x41 = File Name Entry
struct FileName_Entry {
Entry_Flags EntryFlags [[comment("ENTRY TYPE IDENTIFIER")]];
General_Secondary_Flags SecondaryFlags [[comment("COUNT OF SUBSEQUENT ENTRIES")]];
char16 FileName[15] [[comment("FILE NAME: UTF-16")]];
};
// xC0 / x40 = Stream Extension Entry
struct Stream_Entry {
Entry_Flags EntryFlags [[comment("ENTRY TYPE IDENTIFIER")]];;
General_Secondary_Flags SecondaryFlags [[comment("COUNT OF SUBSEQUENT ENTRIES")]];
u8 Reserved_1;
u8 NameLength [[comment("STREAM LENGTH")]];
type::Hex<u16> NameHash [[comment("16bit QUICK HASH: USED FOR FILE SEARCHING")]];
u16 Reserved_2;
u64 InitSize [[comment("INITIALIZED SIZE")]];
u32 Reserved_3;
u32 FirstCluster [[comment("FIRST LOGICAL CLUSTER NUMBER")]];
u64 ActualSize [[comment("PHYSICAL DATA SIZE")]];;
u8 FILE_DATA[InitSize] @ temp_root_location + (FirstCluster - exFAT_VBR.root_dir_cluster) * bytesPerCluster [[comment("POINTER TO THE CLUSTER CONTENT")]];
};
// --------------------------
// exFAT ROOT DIRECTORY
// --------------------------
struct RootDir {
EntryType Type;
padding[31];
match (Type) {
(EntryType::UNUSED_ENTRY): {
continue;
}
(EntryType::ACTIVE_VOLUME_GUID_ENTRY | EntryType::INACTIVE_VOLUME_GUID_ENTRY):{
VolumeGUID_Entry VOLUME_GUID_ENTRY @ $ - 32;
}
(EntryType::ACTIVE_TEXFAT_ENTRY | EntryType::INACTIVE_TEXFAT_ENTRY):{
TexFATPadding_Entry TEXFAT_PADDING_ENTRY @ $ - 32;
}
(EntryType::ACTIVE_ACCESS_CONTROL_ENTRY | EntryType::INACTIVE_ACCESS_CONTROL_ENTRY):{
AccessControl_Entry ACCESS_CONTROL_ENTRY @ $ - 32;
}
(EntryType::ACTIVE_VOLUME_LABEL_ENTRY | EntryType::INACTIVE_VOLUME_LABEL_ENTRY):{
VolumeLabel_Entry VOLUME_LABEL_ENTRY @ $ - 32;
}
(EntryType::ACTIVE_ALLOCATION_BITMAP_ENTRY | EntryType::INACTIVE_ALLOCATION_BITMAP_ENTRY):{
AllocationBitmap_Entry ALLOCATION_BITMAP_ENTRY @ $ - 32;
u64 bitmap_cluster = ALLOCATION_BITMAP_ENTRY.FirstCluster;
char dolla_BITMAP_label[4] @ FAT1_start_offset + (bitmap_cluster * 4) [[name(std::format("$Bitmap"))]];
}
(EntryType::ACTIVE_UPCASE_TABLE_ENTRY | EntryType::INACTIVE_UPCASE_TABLE_ENTRY):{
UpCaseTable_Entry UPCASE_TABLE_ENTRY @ $ - 32;
u64 upcase_cluster = UPCASE_TABLE_ENTRY.FirstCluster;
char dolla_UPCASE_label[4] @ FAT1_start_offset + (upcase_cluster * 4) [[name(std::format("$UpCase"))]];
}
(EntryType::ACTIVE_FILE_INFO_ENTRY | EntryType::INACTIVE_FILE_INFO_ENTRY):{
FileInfo_Entry FILE_INFO_ENTRY @ $ - 32;
}
(EntryType::ACTIVE_STREAM_ENTRY | EntryType::INACTIVE_STREAM_ENTRY):{
Stream_Entry STREAM_EXT_ENTRY @ $ - 32;
}
(EntryType::ACTIVE_FILENAME_ENTRY | EntryType::INACTIVE_FILENAME_ENTRY):{
FileName_Entry FILE_NAME_ENTRY @ $ - 32;
}
}
} [[name(format_entry_name(std::mem::read_unsigned($-32, 1), std::core::array_index()))]];
fn format_entry_name(auto entry_type, u64 idx) {
return std::format("{}[{}]", type_name(entry_type), idx);
};
// ------------------------------
// TYPE RE-NAMER
// ------------------------------
fn type_name(u32 type) {
if (type == EntryType::UNUSED_ENTRY) return "UNUSED_ENTRY";
if (type == EntryType::ACTIVE_VOLUME_GUID_ENTRY) return "ACTIVE_VOLUME_GUID_ENTRY";
if (type == EntryType::INACTIVE_VOLUME_GUID_ENTRY) return "INACTIVE_VOLUME_GUID_ENTRY";
if (type == EntryType::ACTIVE_TEXFAT_ENTRY) return "ACTIVE_TEXFAT_ENTRY";
if (type == EntryType::INACTIVE_TEXFAT_ENTRY) return "INACTIVE_TEXFAT_ENTRY";
if (type == EntryType::ACTIVE_ACCESS_CONTROL_ENTRY) return "ACTIVE_ACCESS_CONTROL_ENTRY";
if (type == EntryType::INACTIVE_ACCESS_CONTROL_ENTRY) return "INACTIVE_ACCESS_CONTROL_ENTRY";
if (type == EntryType::ACTIVE_VOLUME_LABEL_ENTRY) return "ACTIVE_VOLUME_LABEL_ENTRY";
if (type == EntryType::INACTIVE_VOLUME_LABEL_ENTRY) return "INACTIVE_VOLUME_LABEL_ENTRY";
if (type == EntryType::ACTIVE_ALLOCATION_BITMAP_ENTRY) return "ACTIVE_ALLOCATION_BITMAP_ENTRY";
if (type == EntryType::INACTIVE_ALLOCATION_BITMAP_ENTRY) return "INACTIVE_ALLOCATION_BITMAP_ENTRY";
if (type == EntryType::ACTIVE_UPCASE_TABLE_ENTRY) return "ACTIVE_UPCASE_TABLE_ENTRY";
if (type == EntryType::INACTIVE_UPCASE_TABLE_ENTRY) return "INACTIVE_UPCASE_TABLE_ENTRY";
if (type == EntryType::ACTIVE_FILE_INFO_ENTRY) return "ACTIVE_FILE_INFO_ENTRY";
if (type == EntryType::INACTIVE_FILE_INFO_ENTRY) return "INACTIVE_FILE_INFO_ENTRY";
if (type == EntryType::ACTIVE_STREAM_ENTRY) return "ACTIVE_STREAM_ENTRY";
if (type == EntryType::INACTIVE_STREAM_ENTRY) return "INACTIVE_STREAM_ENTRY";
if (type == EntryType::ACTIVE_FILENAME_ENTRY) return "ACTIVE_FILENAME_ENTRY";
if (type == EntryType::INACTIVE_FILENAME_ENTRY) return "INACTIVE_FILENAME_ENTRY";
return "UNKNOWN";
};
// -----------------------------------------------------------------------------
// exFAT FILE ALLOCATION TABLE (FAT1) PARSER
// -----------------------------------------------------------------------------
const u32 CLUSTER_SIZE_BYTES = 4; // Each FAT32 entry = 4 bytes
const u32 FAT_EOF = 0x0FFFFFFF; // End-of-file marker
const u32 FAT_BAD = 0x0FFFFFF7; // Bad cluster marker
const u32 FIRST_ALLOC_CLUSTER = 2; // First usable cluster after reserved
enum FAT_Flags : u32 {
UNALLOCATED = 0x00000000,
END_OF_FILE = 0xFFFFFFFF, // L.END
BAD_CLUSTER = 0xFFFFFFF7, // L.END
};
union FAT_Union {
u32 DECIMAL [[hidden]];
FAT_Flags FAT_FLAG;
};
// ------------------------------
// Helper function for pointer label
// ------------------------------
fn cluster_label(u32 val) {
if (val == FAT_Flags::UNALLOCATED)
return "UNALLOCATED";
if (val == FAT_Flags::BAD_CLUSTER)
return "BAD";
if (val >= 0x0FFFFFF8)
return "EOF";
return std::format("{}", val);
};
// ------------------------------
// FAT1 HEAPS/CHAINS
// ------------------------------
struct FAT_Entry {
FAT_Union FAT [[inline]];
u32 cluster_num = (FIRST_ALLOC_CLUSTER) + (std::core::array_index());
u32 next_cluster = FAT.DECIMAL & 0x0FFFFFFF;
char hover_label[4] @ $ - 4 [[
name(std::format(
"Cluster: {} → {}",
cluster_num,
cluster_label(next_cluster)
))
]];
bool is_eof = next_cluster >= 0x0FFFFFF8;
bool is_bad = next_cluster == FAT_BAD;
bool is_free = next_cluster == 0;
if (is_eof) {
allocated_file_count += 1;
}
} [[name(format_fat_entry(FAT.DECIMAL, std::core::array_index(), FIRST_ALLOC_CLUSTER))]];
// ------------------------------
// FAT FORMATTER FUNC
// ------------------------------
fn format_fat_entry(u32 raw_value, u32 cluster_index, u32 first_alloc_cluster) {
u32 next_cluster = raw_value & 0x0FFFFFFF;
str next_label;
if (next_cluster == 0)
next_label = "UNALLOCATED";
else if (next_cluster == FAT_BAD)
next_label = "BAD";
else if (next_cluster == 0x0FFFFFFF)
next_label = "EOF";
else
next_label = std::format("{}", next_cluster);
u32 logical_cluster = first_alloc_cluster + cluster_index;
if (next_label == "UNALLOCATED" || next_label == "BAD" || next_label == "EOF")
return std::format("Cluster {}: {}", logical_cluster, next_label);
else
return std::format("Cluster {} → {}", logical_cluster, next_label);
};
// ------------------------------
// MEDIA DESCRIPTOR HELPER
// ------------------------------
enum Media_Descriptor : u8 {
SINGLE_SIDE_FLOPPY = 0xF0,
DOUBLE_SIDE_FLOPPY = 0xF9,
HARD_DISK_DRIVE = 0xF8,
};
// ------------------------------
// FAT HEADER PARSER
// ------------------------------
struct FAT_Header {
Media_Descriptor mediaDescriptor [[comment("0xF8=FIXED DISK | 0xF0=REMOVABLE")]];;
u8 exFAT_FAT_HEADER[7] [[comment("8 BYTES TOTAL: 4 BYTES REPRESENT PSUEDO CLUSTER 0 (SYSTEM) | 4 BYTES REPRESENT PSUEDO CLUSTER 1 (SYSTEM)(EOF)")]];
//Bitmap and UpCase overlays handled in RootDir parser
char root_dir_label[4] @ $ + ((rdc - 2) * 4) [[
name(std::format(
"ROOT_DIRECTORY"
))
]];
};
// ------------------------------
//SIGNATURE HELPER
// ------------------------------
enum VBRSignature : u16 {
VBR_SIG = 0xAA55
};
// ------------------------------
// EXTENDED BOOT REGION
// ------------------------------
struct ExtendedBoot {
u8 Extended_Boot_Sector[1 * bytesPerSector];
VBRSignature VBR_SIG @ $ - 2;
};
// ------------------------------
// BOOT SECTOR BITFIELD FLAGS
// ------------------------------
bitfield VolumeFlags {
unsigned Active : 1;
unsigned VolumeDirty : 1;
unsigned Media_Failure : 1;
unsigned Clear_to_Zero : 1;
Rserved : 12;
} [[bitfield_order(std::core::BitfieldOrder::LeastToMostSignificant, 16)]];
// ------------------------------
// EXFAT VOLUME BOOT RECORD
// ------------------------------
struct exFAT_BootSector {
u8 jmp_boot[3];
char fs_name[8]; // "EXFAT "
u8 must_be_zero[53];
u64 partition_offset; // in sectors
u64 volume_length; // in sectors
u32 fat_offset; // in sectors
u32 fat_length; // in sectors
u32 cluster_heap_offset; // in sectors
u32 cluster_count;
u32 root_dir_cluster;
u32 volume_serial;
u16 fs_revision;
VolumeFlags volume_flags;
u8 bytes_per_sector_shift; // 2^n
u8 sectors_per_cluster_shift; // 2^n
u8 number_of_fats;
u8 drive_select;
u8 percent_in_use;
u8 reserved[7];
u8 bootstrap[390];
VBRSignature VBR_SIG; // 0x55AA
rdc = root_dir_cluster;
};
// -------------------------------------------------------------------------
// MAIN
// -------------------------------------------------------------------------
// V V V V V V V V V
// -------------------------------------------------------------------------
exFAT_BootSector exFAT_VBR @ 0x0;
// -------------------------------------------------------------------------
// DERIVED CONSTANTS
// -------------------------------------------------------------------------
// ============= SIZES ===================================================================
u32 bytesPerSector = 1 << exFAT_VBR.bytes_per_sector_shift;
u32 bytesPerCluster = bytesPerSector << exFAT_VBR.sectors_per_cluster_shift;
// ============= OFFSETS =================================================================
u64 volumeStartSector = exFAT_VBR.partition_offset;
u64 volumeStartOffset = volumeStartSector * bytesPerSector;
u64 volumeSize = exFAT_VBR.volume_length * bytesPerSector;
u64 FAT1_start_offset = exFAT_VBR.fat_offset * bytesPerSector;
//For printing absolute offset
u64 RootDir_Offset = (exFAT_VBR.cluster_heap_offset +
((exFAT_VBR.root_dir_cluster - 2) << exFAT_VBR.sectors_per_cluster_shift))
* bytesPerSector + volumeStartOffset;
// ============= CLUSTERS ================================================================
u32 clusterSize = bytesPerCluster;
u32 clusterCount = exFAT_VBR.cluster_count;
u64 clusterHeapOffset = exFAT_VBR.cluster_heap_offset * bytesPerSector;
// -------------------------------------------------------------------------
// SECONDARY
// -------------------------------------------------------------------------
// V V V V V V V V V
// -------------------------------------------------------------------------
// ============= USAGE ===================================================================
u8 percentInUse = exFAT_VBR.percent_in_use;
// ============= EBS =====================================================================
ExtendedBoot Extended_Boot_Sectors[8] @ $;
// ============= OEM =====================================================================
u8 OEM_Parameters[1 * bytesPerSector] @ $;
// ============= ER ======================================================================
u8 Extended_Reserved[1 * bytesPerSector] @ $;
// ============= BCS =====================================================================
u8 Boot_Checksum[1 * bytesPerSector] @ $;
// ============= BBS =====================================================================
exFAT_BootSector Backup_Boot_Sector @ $;
// ============= BEBS ====================================================================
ExtendedBoot Backup_Extended_Boot_Sectors[8] @ $;
// ============= BOEM ====================================================================
u8 Backup_OEM_Parameters[1 * bytesPerSector] @ $;
// ============= BER =====================================================================
u8 Backup_Extended_Reserved[1 * bytesPerSector] @ $;
// ============= BBCS ====================================================================
u8 Backup_Boot_Checksum[1 * bytesPerSector] @ $;
// ============= FAT =====================================================================
// *** HAS GLOBAL AT TOP ***
FAT_Header FAT1_HEADER @ FAT1_start_offset;
FAT_Entry FAT1[MAX_FAT_CHUNKS] @ FAT1_start_offset + 8;
// ============= ROOT ====================================================================
// ROOT DIRECTORY
// *** HAS GLOBAL AT TOP ***
// for locating root directory within memory
u64 temp_root_location = (exFAT_VBR.root_dir_cluster - 2) * clusterSize + clusterHeapOffset;
RootDir ROOT_DIRECTORY[MAX_DIR_ENTRIES] @ temp_root_location;
// ============= REPORT ==================================================================
// VOLUME REPORT
// *** HAS GLOBAL AT TOP ***
if (VOLUME_REPORT) {
std::print(" ");
std::print("-----------------------------------------");
std::print("---------- EXFAT VOLUME_REPORT ----------");
std::print("-----------------------------------------");
std::print("FILE_SYSTEM = {}", exFAT_VBR.fs_name);
std::print("SERIAL_NUMBER = 0x{:X}", exFAT_VBR.volume_serial);
std::print("FS_REVISION = {}.{}", (exFAT_VBR.fs_revision >> 8) & 0xFF, exFAT_VBR.fs_revision & 0xFF);
bool _any = false;
if(exFAT_VBR.volume_flags.Active) {
std::print("FAT_FLAG = 0b{:X}", exFAT_VBR.volume_flags.Active);
_any = true;
}
if(exFAT_VBR.volume_flags.VolumeDirty) {
std::print("DIRTY_FLAG = 0b{:X}", exFAT_VBR.volume_flags.Volume_Dirty);
_any = true;
}
if(exFAT_VBR.volume_flags.Media_Failure) {
std::print("FAILURE_FLAG = 0b{:X}", exFAT_VBR.volume_flags.Media_Failure);
_any = true;
}
if(exFAT_VBR.volume_flags.Clear_to_Zero) {
std::print("CLEAR_TO_ZERO_FLAG = 0b{:X}", exFAT_VBR.volume_flags.Clear_to_Zero);
_any = true;
}
if (!_any){
std::print("VOL_FLAGS = NONE");
}
std::print("-----------------------------------------");
std::print("BYTES/SECTOR = {}", bytesPerSector);
std::print("SECTORS/CLUSTER = {}", 1 << exFAT_VBR.sectors_per_cluster_shift);
std::print("BYTES/CLUSTER = {}", bytesPerCluster);
std::print("CLUSTER_COUNT = {}", clusterCount);
std::print("-----------------------------------------");
std::print("VOLUME_SIZE = {} SECTORS", exFAT_VBR.volume_length);
std::print("VOLUME_SIZE = {:.4f} GB @ 1000", volumeSize / 1000.0 / 1000.0 / 1000.0);
std::print("VOLUME_SIZE = {:.4f} GiB @ 1024", volumeSize / 1024.0 / 1024.0 / 1024.0);
std::print("-----------------------------------------");
std::print("VOLUME_START_SEC = {}", volumeStartSector);
std::print("VOLUME_START_OFF = 0x{:X}", volumeStartOffset);
std::print("FAT1_START_OFF = 0x{:02X}", FAT1_start_offset);
std::print("CLUSTER_HEAP_OFF = 0x{:02X}", clusterHeapOffset);
std::print("ROOT_DIR_CLUSTER = {:02}", exFAT_VBR.root_dir_cluster);
std::print("ROOT_DIR_OFFSET = 0x{:02X}", RootDir_Offset);
std::print("-----------------------------------------");
std::print("PERCENT_IN_USE = {:02} %", percentInUse);
std::print("NUMBER_OF_FATS = {:02}", exFAT_VBR.number_of_fats);
std::print("DRIVE_SELECT = 0x{:02X}", exFAT_VBR.drive_select);
std::print("-----------------------------------------");
std::print("------------------ END ------------------");
std::print("-----------------------------------------");
std::print(" ");
}

View File

@@ -0,0 +1,165 @@
#pragma description Devil May Cry 3 HD .mod 3D model file
#pragma author haru233
// many thanks to AxCut
// ImHex Hex Pattern File for Capcom's Devil May Cry 3 HD .mod files
import std.core;
struct ModelHeader {
char ID[4];
float Version;
padding[8];
u8 objectCount;
u8 boneCount;
u8 numberTextures;
u8;
u32;
u64;
u64 skeletonOffset;
padding[24];
};
struct ObjectInfo {
u8 meshCount;
u8;
u16 numberVertices;
padding[4];
u64 meshOffset;
u32 flags;
padding[28];
float X, Y, Z;
float radius;
};
struct Positions {
float positions[3];
};
struct Normals {
float normal[3];
};
struct UVs {
s16 uv[2];
};
struct BoneIndices {
u8 boneindex[4];
};
struct Weights {
u16 weight[1];
};
struct MeshSCM {
u16 numberVertices;
u16 textureIndex;
padding[12];
u64 VerticesPositionsOffset;
u64 NormalsPositionsOffset;
u64 UVsPositionsOffset;
padding[16];
u64 unknownOffset;
u64;
padding[8];
Positions positions[numberVertices] @VerticesPositionsOffset;
Normals normals[numberVertices] @NormalsPositionsOffset;
UVs uvs[numberVertices] @UVsPositionsOffset;
};
struct Mesh {
u16 numberVertices;
u16 textureIndex;
padding[12];
u64 VerticesPositionsOffset;
u64 NormalsPositionsOffset;
u64 UVsPositionsOffset;
u64 BoneIndicesOffset;
u64 WeightsOffset;
padding[8];
u64;
padding[8];
Positions positions[numberVertices] @VerticesPositionsOffset;
Normals normals[numberVertices] @NormalsPositionsOffset;
UVs uvs[numberVertices] @UVsPositionsOffset;
BoneIndices b_index[numberVertices] @BoneIndicesOffset;
Weights weights[numberVertices] @WeightsOffset;
};
struct Hierarchy {
u8 hierarchy;
};
struct HierarchyOrder {
u8 hierarchyorder;
};
struct Unknown {
u8;
};
struct Transform {
float x;
float y;
float z;
float length; // sqrt(x*x + y*y + z*z)
padding[16];
};
struct Skeleton{
u32 hierarchyOffset;
u32 hierarchyOrderOffset;
u32 unknownOffset;
u32 transformsOffset;
};
ModelHeader modelheader @ 0x00;
ObjectInfo objects_info[modelheader.objectCount] @ 0x40;
u32 objectOffset;
struct Object {
u64 i = std::core::array_index();
if (modelheader.ID == "SCM ") {
objectOffset = objects_info[0].meshOffset;
MeshSCM meshscm[objects_info[i].meshCount] @ objects_info[i].meshOffset;
} else {
objectOffset = objects_info[0].meshOffset;
Mesh mesh[objects_info[i].meshCount] @ objects_info[i].meshOffset;
}
};
Object objects[modelheader.objectCount] @objectOffset;
Skeleton skeleton @modelheader.skeletonOffset;
Hierarchy hierarchy[modelheader.boneCount] @(modelheader.skeletonOffset + skeleton.hierarchyOffset);
HierarchyOrder hierarchyorder[modelheader.boneCount] @(modelheader.skeletonOffset + skeleton.hierarchyOrderOffset);
Unknown unknown[modelheader.boneCount] @(modelheader.skeletonOffset + skeleton.unknownOffset);
Transform transform[modelheader.boneCount] @(modelheader.skeletonOffset + skeleton.transformsOffset);

189
patterns/SHR.hexpat Normal file
View File

@@ -0,0 +1,189 @@
/*!
Apple IIgs Super Hi-Res (SHR) + PaintWorks Animation (ANI) — ImHex pattern
Supports:
• PIC $C1/$0000 — 32 KB uncompressed SHR screen image
• PIC $C1/$0002 — 3200-color (“Brooks”) per-scanline palettes
• ANI $C2/$0000 — PaintWorks animation:
0x0000..0x7FFF : base SHR $C1/$0000 image
0x8000.. : animation header + chunks
PaintWorks animation structure (per reversed docs):
- Base image: uncompressed SHR ($C1/$0000)
- +0x8000 u32: total animation data length after header (file_len - 0x8008)
- +0x8004 u16: global frame delay in VBLs
- +0x8006 u16: flag/? (commonly 0x00C0 or 0x00C1)
- +0x8008 ...: one or more animation chunks:
chunk:
u32 chunk_len (includes this length field)
repeated { u16 offset; u16 value; } pairs
offset==0x0000 marks End-of-Frame (value is ignored)
- Offsets may target any byte in the 32 KB SHR space (pixels, SCBs, palettes).
This enables palette-cycling and SCB effects.
References:
- CiderPress2 PaintWorks Animation notes (file structure, fields, semantics).
*/
import std.core;
import std.sys;
import std.math;
#pragma endian little
#include <std/mem.pat>
#pragma description Apple IIgs Super Hi-Res (SHR) + PaintWorks Animation (ANI)
#pragma author hasseily
// ------------------------------ Constants ------------------------------
const u32 SHR_ROWS = 200;
const u32 SHR_BYTES_PER_ROW = 160;
const u32 SHR_PIXEL_DATA_SIZE = SHR_ROWS * SHR_BYTES_PER_ROW; // 32000 (0x7D00)
const u32 PIC0000_FILE_SIZE = 0x8000; // 32768
const u32 PIC0002_FILE_SIZE = 0x9600; // 38400 (32000 + 200*32)
const u32 PIC0000_OFF_PIXELS = 0x0000;
const u32 PIC0000_OFF_SCB = 0x7D00;
const u32 PIC0000_OFF_RESERVED = 0x7DC8;
const u32 PIC0000_OFF_PALETTES = 0x7E00;
const u32 PALETTE_COUNT = 16;
const u32 PALETTE_COLORS = 16;
const u32 ANI_BASE_SHR_SIZE = 0x8000; // First 32 KB is a $C1/$0000 image
const u32 ANI_HDR_OFF = 0x8000; // Animation header starts here
const u32 ANI_MIN_TOTAL_SIZE = 0x8008; // base + header (no chunks)
// ------------------------------ Types: SHR core ------------------------------
struct Row160 { u8 data[SHR_BYTES_PER_ROW]; };
// Scanline Control Byte
bitfield ShrSCB {
palette : 4; // 0..15
reserved : 1;
color_fill : 1;
interrupt : 1;
mode_640 : 1; // 0=320, 1=640
};
// helper: expand a 4-bit channel to 8-bit (0x0..0xF -> 0x00..0xFF)
fn expand4(u8 v) { return (v << 4) | v; };
bitfield Colors_gb {
blue : 4; // Blue (B3..B0)
green : 4; // Green (G3..G0)
};
bitfield Colors_r0 {
red : 4; // Red (R3..R0)
unused : 4; // Unused / reserved
};
// RGB444 stored as 0RGB
struct Rgb444_0RGB {
Colors_gb gb;
Colors_r0 r0;
} [[color(std::format("{:02X}{:02X}{:02X}", expand4(r0.red), expand4(gb.green), expand4(gb.blue)))]];
struct Palette16 { Rgb444_0RGB color[PALETTE_COLORS]; };
// $C1/$0000 raw 32 KB screen dump
struct SHR_PIC0000 {
Row160 pixels[SHR_ROWS] @ PIC0000_OFF_PIXELS;
ShrSCB scb[SHR_ROWS] @ PIC0000_OFF_SCB;
u8 reserved[56] @ PIC0000_OFF_RESERVED;
Palette16 palettes[PALETTE_COUNT] @ PIC0000_OFF_PALETTES;
};
// “Brooks” 3200-color: pixels + 200 per-line palettes (no SCBs)
struct BrooksLinePalette { Rgb444_0RGB color[PALETTE_COLORS]; };
struct SHR_PIC0002 {
Row160 pixels[SHR_ROWS] @ 0x0000;
BrooksLinePalette line_palettes[SHR_ROWS] @ SHR_PIXEL_DATA_SIZE; // 0x7D00
};
// ------------------------------ Types: PaintWorks ANI ($C2/$0000) ------------------------------
/* Each operation modifies 1 word at an absolute offset in the 32 KB SHR area.
End-of-frame marker: offset == 0x0000 (value is ignored). */
struct AniOp {
u16 offset [[color("0000AA")]]; // 0x0000..0x7FFE valid; 0x0000 = End-of-Frame
u16 value [[color("00AAAA")]]; // word to store at [offset]
// For convenience in the sidebar:
bool is_eof = (offset == 0x0000);
};
// A contiguous animation chunk: length + packed AniOp pairs.
// Most files have exactly one chunk that spans all frames.
struct AniChunk {
u32 chunk_len; // includes this field
// ops_count = (chunk_len - 4)/4, unless chunk_len == 4
// in which case: (__file_size - 0x8000 - 12)/4
u64 ops_count64 =
(chunk_len == 4)
? ( (__file_size > (0x8000 + 12)) ? ((__file_size - 0x8000 - 12) / 4) : 0 )
: ( (chunk_len >= 4) ? (u64(chunk_len - 4) / 4) : 0 );
u32 ops_count = u32(ops_count64);
// ops start immediately after chunk_len (offset +4)
AniOp ops[ops_count];
};
// Header located at 0x8000 after the base 32 KB image
struct AniHeader {
u32 anim_data_len [[color("660000")]]; // total bytes of animation data after header
u16 frame_delay_vbl [[color("CC0000")]]; // global per-frame delay in VBLs (NTSC/PAL differ)
u16 flag_unknown; // usually 0x00C0 or 0x00C1
};
// Full PaintWorks animation container
struct ANI_PaintWorks {
// Base frame: a normal uncompressed SHR image
SHR_PIC0000 base @ 0x0000;
// Global animation header
AniHeader hdr @ ANI_HDR_OFF;
// One or more chunks, typically exactly one:
AniChunk chunks[ std::math::min(
u32(16), // cap to keep ImHex happy in pathological cases
u32((__file_size - (ANI_HDR_OFF + sizeof(AniHeader))) > 3 ?
1 + u32((__file_size - (ANI_HDR_OFF + sizeof(AniHeader))) / 0x10000000) :
1)
) ] @ (ANI_HDR_OFF + sizeof(AniHeader));
// Helpful computed values for inspection:
u64 file_len = __file_size;
u64 expected_anim_end = ANI_HDR_OFF + sizeof(AniHeader) + u64(hdr.anim_data_len);
};
// ------------------------------ Dispatcher ------------------------------
u64 __file_size = std::mem::size();
if (__file_size == PIC0000_FILE_SIZE) {
// Plain SHR dump
SHR_PIC0000 pic0000 @ 0x0000;
} else if (__file_size == PIC0002_FILE_SIZE) {
// Brooks 3200-color
SHR_PIC0002 pic0002 @ 0x0000;
} else if (__file_size >= ANI_MIN_TOTAL_SIZE) {
// Heuristic: treat as PaintWorks ANI if theres room for base+header.
// (Many PW ANI files use ProDOS type $C2/$0000.)
ANI_PaintWorks ani @ 0x0000;
} else if (__file_size >= SHR_PIXEL_DATA_SIZE) {
// Fallback: show pixels only for odd dumps
Row160 pixels_only[SHR_ROWS] @ 0x0000;
}
ANI_PaintWorks ani_paintworks_at_0 @ 0;

129
patterns/a3/a3_bmtr.hexpat Normal file
View File

@@ -0,0 +1,129 @@
#pragma author MrClock
#pragma description Arma 3 RTM animation format (binarized)
#pragma endian little
#pragma MIME application/x.a3-bmtr
fn get_data_description() {
return "Binarized RTM (BMTR) animation files are the PBO packed versions of plain RTMs.\n Binarized files are optimized for use by the game engine, and they are not editable.\nBone transformations are stored as relative quaternion-vector pairs.\nData blocks are conditionally LZO1X compressed (these are not supported by this pattern).";
};
import std.string;
import std.sys;
import type.float16;
using asciiz = std::string::NullString [[format("formatAsciiz")]];
using half = type::float16 ;
struct s16float {
s16 data;
} [[sealed,static,transform("transforms16float"), format("transforms16float")]];
struct Property {
padding[4];
asciiz name;
float phase;
asciiz value;
} [[format("formatProperty")]];
struct Vector<DataType> {
DataType x [[comment("+Left/-Right")]];
DataType y [[comment("+Up/-Down (UNUSED)")]];
DataType z [[comment("+Forward/-Backward")]];
} [[static]];
struct Quaternion {
s16float x;
s16float y;
s16float z;
s16float w;
} [[static,format("formatQuaternion")]];
struct Transform {
Quaternion orientation;
Vector<half> position [[format("formatVectorHalf")]];
} [[static]];
struct Frame {
u32 count_bones;
bool compressed = count_bones * sizeof(Transform) >= 1024;
if (parent.version > 4) {
u8 lzo_flag;
compressed = lzo_flag > 0;
}
if (compressed) {
std::error("Transformations are LZO compressed and compressed length is unknown");
} else {
Transform transforms[count_bones];
}
};
struct BMTR {
char signature[4];
u32 version;
padding[1];
Vector<float> motion [[format("formatVectorFloat")]];
u32 count_frames;
padding[4];
u32 count_bones;
u32 count_bones_again;
std::assert_warn(count_bones == count_bones_again, "Mismatch between bone counts");
asciiz bones[count_bones];
if (version >= 4) {
padding[4];
u32 count_properties;
Property properties[count_properties];
}
u32 count_phases;
std::assert_warn(count_frames == count_phases, "Frame and phase counts do not match");
bool compressed = count_phases * sizeof(float) >= 1024;
if (version > 4) {
u8 lzo_flag;
compressed = lzo_flag > 0;
}
if (compressed) {
std::error("Phases are LZO compressed and compressed length is unknown");
} else {
float phases[count_phases];
}
Frame frames[count_frames];
};
fn transforms16float(ref s16float value) {
return float(value.data) / 16384;
};
fn formatAsciiz(ref asciiz value) {
return std::format("\"{:s}\"", value);
};
fn formatProperty(ref Property prop) {
return std::format("\"{0:s}\" = \"{1:s}\" @ {2:.4f}", prop.name, prop.value, prop.phase);
};
fn formatVectorHalf(ref Vector<half> vec) {
return std::format(
"[{0}, {1}, {2}]",
type::impl::format_float16(vec.x),
type::impl::format_float16(vec.y),
type::impl::format_float16(vec.z)
);
};
fn formatVectorFloat(ref Vector<float> vec) {
return std::format("[{0:.2f}, {1:.2f}, {2:.2f}]", vec.x, vec.y, vec.z);
};
fn formatQuaternion(ref Quaternion q) {
return std::format("[{0:.2f}, {1:.2f}, {2:.2f}, {3:.2f}]", q.x, q.y, q.z, q.w);
};
BMTR file @ 0x0000;

View File

@@ -0,0 +1,222 @@
#pragma author MrClock
#pragma description Arma 3 P3D model format (MLOD)
#pragma endian little
#pragma MIME model/x.a3-p3d-mlod
fn get_data_description() {
return "MLOD type P3D files are used for authoring 3D models for Arma 3.\nThese files can be carated in and edited in the Object Builder application.\nAll data is stored uncompressed for ease of editing.\nDuring the PBO packing process they are further \"binarized\" into ODOL type P3D files, that are optimized for use by the game engine. (These are no longer editable, the conversion is irreversible.)\n\nP3D model files can by quite large, so by default only the 1st LOD is processed by this pattern. Processing of all LODs can be enabled in the pattern settings.";
};
import std.string;
import std.core;
bool process_all_lods in;
using asciiz = std::string::NullString;
enum FaceType: u32 {
TRIANGLE = 3,
QUAD = 4
};
struct Vector {
float x;
float y;
float z;
} [[static,format("formatVector")]];
struct UV {
float u;
float v;
} [[static,format("formatUV")]];
enum SurfaceFitting: u8 {
NORMAL = 0,
ON_SURFACE = 1,
ABOVE_SURFACE = 2,
UNDER_SURFACE = 4,
KEEP_HEIGHT = 8
};
enum Lighting: u8 {
NORMAL = 0,
SHINING = 1,
SHADOWED = 2,
FULL_LIT = 4,
HALF_LIT = 8
};
enum DecalMode: u8 {
NORMAL = 0,
DECAL = 1,
RADIO12 = 2
};
enum Fog: u8 {
NORMAL = 0,
NONE = 1,
SKY = 2
};
enum NormalCalculation: u8 {
FACE_AREA = 0,
HIDDE_VERTEX = 1,
FIXED = 2,
FACE_ANLGE = 4
};
bitfield VertexFlags {
padding : 5;
NormalCalculation normals : 3;
u8 user;
padding : 2;
Fog fog : 2;
padding : 2;
DecalMode decal : 2;
Lighting lighting : 4;
SurfaceFitting surface : 4;
} [[bitfield_order(std::core::BitfieldOrder::MostToLeastSignificant, 32)]];
struct Vertex {
Vector position;
VertexFlags flags;
}[[static,format("formatVertex")]];
struct FacePoint {
u32 vertex_index;
u32 normal_index;
UV uv;
} [[static]];
enum ZBiasFlag: u8 {
NONE = 0,
LOW = 1,
MIDDLE = 2,
HIGH = 3
};
bitfield FaceFlags {
user : 7;
disable_texture_merging : 1;
padding : 2;
flat_lighting : 1;
reversed_face : 1;
padding : 10;
ZBiasFlag zbias : 2;
position : 1;
padding : 1;
double_sided_face : 1;
disable_shadow : 1;
padding : 4;
} [[bitfield_order(std::core::BitfieldOrder::MostToLeastSignificant, 32)]];
struct Face {
FaceType type;
FacePoint points[4];
FaceFlags flags;
asciiz texture;
asciiz material;
} [[format("formatFace")]];
struct Edge {
u32 vertex_1;
u32 vertex_2;
} [[sealed,static,format("formatEdge")]];
struct Property {
char name[64] [[transform("std::string::to_string")]];
char value[64] [[transform("std::string::to_string")]];
} [[static,sealed,format("formatProperty")]];
struct Tagg {
bool active;
asciiz name;
u32 length;
if (name == "#EndOfFile#") {
break;
}
match (name) {
("#SharpEdges#"): Edge edges[length/8];
("#Property#"): Property property;
("#Mass#"): float masses[parent.count_verticies];
("#UVSet#"): {
u32 channel;
UV coordinates[(length - 4) / 8];
}
(_): if (std::string::starts_with(name, "#") && std::string::ends_with(name, "#")) {
u8 unknown_data[length];
} else {
u8 vertex_weights[parent.count_verticies];
u8 face_weights[parent.count_faces];
}
}
} [[format("formatTagg")]];
struct P3dmLod {
char signature[4];
u32 version_major;
u32 version_minor;
u32 count_verticies;
u32 count_normals;
u32 count_faces;
u32; // Unknown data (might be unused model flags)
Vertex verticies[count_verticies];
Vector normals[count_normals];
Face faces[count_faces];
char tagg_signature[4];
Tagg taggs[while(true)];
float resolution;
} [[format("formatP3dmLod")]];
struct P3D {
char signature[4];
u32 version;
u32 count_lods;
if (!process_all_lods) {
P3dmLod lod_0;
} else {
P3dmLod lods[count_lods];
}
};
fn formatVector(ref Vector pos) {
return std::format("[{0:.3f}, {1:.3f}, {1:.3f}]", pos.x, pos.y, pos.z);
};
fn formatUV(ref UV pos) {
return std::format("[{0:.3f}, {1:.3f}]", pos.u, pos.v);
};
fn formatVertex(ref Vertex vert) {
return formatVector(vert.position);
};
fn formatFace(ref Face face) {
return face.type == FaceType::TRIANGLE ? "triangle" : "quad";
};
fn formatEdge(ref Edge edge) {
return std::format("{0:d} <-> {1:d}", edge.vertex_1, edge.vertex_2);
};
fn formatProperty(ref Property prop) {
return std::format("\"{0:s}\" = \"{1:s}\"", prop.name, prop.value);
};
fn formatTagg(ref Tagg tagg) {
if (std::core::has_member(tagg, "vertex_weights")) {
return std::format("\"{0:s}\" selection", tagg.name);
} else {
return std::format("\"{0:s}\"", tagg.name);
}
};
fn formatP3dmLod(ref P3dmLod lod) {
return std::format("Resolution: {0}", lod.resolution);
};
P3D file @ 0x0000;

141
patterns/a3/a3_paa.hexpat Normal file
View File

@@ -0,0 +1,141 @@
#pragma author MrClock
#pragma description Arma 3 PAA image format
#pragma endian little
#pragma MIME image/x.a3-paa
fn get_data_description() {
return "PAA texture files are the proprietary image format used for textures in Arma 3.\nSimilar to most other formats used in game engines, the PAA stores not only a single resolution, but a series of precomputed mipmaps.\nPAA supports multiple pixel encoding formats, such as DXT1, DXT5, RGBA5551, grayscale, and others. Mipmap data in DXT encoded files is optionally compressed with the LZO1X algorithm. All other types are unconditionally LZSS compressed.";
};
import type.color;
import std.mem;
import std.sys;
struct Color<auto alpha> {
u8 b;
u8 g;
u8 r;
if (alpha) u8 a;
} [[sealed, format("type::impl::format_color"), color(std::format("{0:02X}{1:02X}{2:02X}", r, g, b))]];
using BGR8 = Color<false>;
using BGRA8 = Color<true>;
enum PixelFormat: u16 {
DXT1 = 0xFF01,
DXT2 = 0xFF02,
DXT3 = 0xFF03,
DXT4 = 0xFF04,
DXT5 = 0xFF05,
RGBA4 = 0x4444,
RGBA5 = 0x1555,
RGBA8 = 0x8888,
GRAY = 0x8080
};
enum AlphaMode: u32 {
NONE = 0,
INTERPOLATED = 1,
BINARY = 2
};
enum Swizzle: u8 {
ALPHA = 0,
RED = 1,
GREEN = 2,
BLUE = 3,
INVERTED_ALPHA = 4,
INVERTED_RED = 5,
INVERTED_GREEN = 6,
INVERTED_BLUE = 7,
BLANK_WHITE = 8,
BLANK_BLACK = 9
};
enum Compression: u8 {
NONE = 0,
LZO1X = 1,
LZSS = 2
};
struct Tagg {
char signature[8];
u32 length;
match (signature) {
("GGATCGVA"): BGRA8 color;
("GGATCXAM"): BGRA8 color;
("GGATGALF"): AlphaMode alpha;
("GGATSFFO"): u32 offsets[16];
("GGATZIWS"): Swizzle copies[4];
(_): u8 data[length];
}
} [[format("format_tagg_name")]];
struct Palette {
u16 length;
BGR8 colors[length];
};
struct Mipmap {
u16 width_and_lzo [[format("format_width_lzo")]];
u16 height;
u16 width = width_and_lzo;
Compression compression = Compression::NONE;
if ((u32(parent.format) & 0xFF00) == 0xFF00) {
width = width_and_lzo & 0x7FFF;
compression = width_and_lzo & 0x8000 ? Compression::LZO1X : Compression::NONE;
} else {
compression = Compression::LZSS;
}
if (width == 0 && height == 0) {
break;
}
u24 size;
match (compression) {
(Compression::NONE): u8 encoded_data[size];
(Compression::LZO1X): u8 lzo_compressed_data[size];
(Compression::LZSS): u8 lzss_compressed_data[size];
}
} [[format("format_resolution")]];
struct PAA {
PixelFormat format;
Tagg taggs[while(std::mem::read_string($, 4) == "GGAT")];
Palette palette;
Mipmap mipmaps[while(true)];
u16 EOF;
std::assert_warn(EOF == 0, "Invalid EOF sentinel");
};
fn format_resolution(ref auto mip) {
return std::format("{0:d} x {1:d}", mip.width, mip.height);
};
fn format_width_lzo(u16 value) {
u16 width = value & 0x7FFF;
if (value & 0x8000) {
return std::format("{0:d} (+LZO flag)", width);
} else {
return std::format("{0:d}", width);
}
};
fn format_tagg_name(Tagg data) {
match (data.signature) {
("GGATCGVA"): return "Average color";
("GGATCXAM"): return "Max color";
("GGATGALF"): return "Alpha flag";
("GGATZIWS"): return "Swizzle";
("GGATSFFO"): return "Mipmap offsets";
(_): return "Unknown";
}
};
PAA file @ 0x0000;

165
patterns/a3/a3_rap.hexpat Normal file
View File

@@ -0,0 +1,165 @@
#pragma author MrClock
#pragma description Arma 3 binary configuration format
#pragma endian little
#pragma MIME application/x.a3-rap
fn get_data_description() {
return "The RAP format is the binarized/\"rapified\" version of configuration files for Arma 3. Plain text configuration, material definition, scenario description and other files using the configuration syntax are rapified during the PBO packing process. The game can work with the plain text versions (they are actually rapified during boot), but properly converting them into the binary format ahead of time makes the booting easier.";
};
import std.mem;
import std.string;
import std.core;
import std.io;
using asciiz = std::string::NullString [[format("formatAsciiz")]];
/*
Item counts are stored in 7-bit encoded integers. In each byte the top bit signals
if the next byte belongs to the number as well.
*/
struct CompressedUint {
u8 extras[while(std::mem::read_unsigned($, 1) & 0x80)];
u8 last;
} [[sealed,transform("transformCompressedUint"),format("formatCompressedUint")]];
enum MemberType: u8 {
CLASS = 0,
LITERAL = 1,
ARRAY = 2,
EXTERNAL = 3,
DELETE = 4,
ARRAY_EXTENSION = 5
};
enum ValueType: u8 {
STRING = 0,
FLOAT = 1,
INTEGER = 2,
ARRAY = 3,
VARIABLE = 4
};
using Array;
struct ArrayItem {
ValueType type;
match (type) {
(ValueType::STRING): asciiz value;
(ValueType::FLOAT): float value;
(ValueType::INTEGER): s32 value;
(ValueType::ARRAY): Array value;
(ValueType::VARIABLE): asciiz value;
}
} [[format("formatArrayItem")]];
struct Array {
CompressedUint count_items;
ArrayItem items[count_items];
} [[format("formatArray")]];
using ClassBody;
struct Member {
MemberType type;
match(type) {
(MemberType::CLASS): {
asciiz name;
ClassBody *body : u32;
}
(MemberType::LITERAL): {
ValueType subtype;
asciiz name;
match (subtype) {
(ValueType::STRING): asciiz value;
(ValueType::FLOAT): float value;
(ValueType::INTEGER): s32 value;
(_): std::error(std::format("Unexpected subtype for literal: {}", subtype));
}
}
(MemberType::ARRAY | MemberType::ARRAY_EXTENSION): {
asciiz name;
Array value;
}
(MemberType::EXTERNAL): {
asciiz name;
}
(MemberType::DELETE): {
asciiz name;
}
}
} [[format("formatMember")]];
using Enums;
struct ClassBody {
asciiz parent_name;
CompressedUint count_members;
Member members[count_members];
u8 *pointer : u32 [[comment("In the root body this points to the enum list.\nIn all others it points to the next body on the same level.")]];
};
struct EnumItem {
asciiz name;
s32 value;
} [[format("formatEnumItem")]];
struct Enums {
u32 count_items;
EnumItem items[count_items];
};
struct RAP {
char signature[4];
u32;
u32;
Enums *enums : u32;
ClassBody root;
};
fn formatAsciiz(ref asciiz value) {
return std::format("\"{0:s}\"", value);
};
fn transformCompressedUint(ref CompressedUint value) {
u64 result = 0;
for (u8 i = 0, i < sizeof(value.extras), i += 1) {
result += (value.extras[i] & 0x7F) << (7*i);
}
result += value.last << (sizeof(value.extras) * 7);
return result;
};
fn formatCompressedUint(ref CompressedUint value) {
return value;
};
fn formatArrayItem(ref ArrayItem value) {
return value.value;
};
fn formatArray(ref Array value) {
return "{...}";
};
fn formatMember(ref Member item) {
match (item.type) {
(MemberType::CLASS): return std::format("class {0:s} {{...}};", item.name);
(MemberType::LITERAL): return std::format("{0:s} = {1};", item.name, item.value);
(MemberType::ARRAY): return std::format("{0:s}[] = {{...}};", item.name);
(MemberType::EXTERNAL): return std::format("class {0:s};", item.name);
(MemberType::DELETE): return std::format("del {0:s};", item.name);
}
};
fn formatEnumItem(ref EnumItem value) {
return std::format("{0:s} = {1}", item.name, item.value);
};
RAP file @ 0x0000;

93
patterns/a3/a3_rtm.hexpat Normal file
View File

@@ -0,0 +1,93 @@
#pragma author MrClock
#pragma description Arma 3 RTM animation format (plain)
#pragma endian little
#pragma MIME application/x.a3-rtm
fn get_data_description() {
return "Plain RTM animation files are used in animation authoring for Arma 3.\nThey can be created and edited in Object Builder.\nBone transformations are stored as absolute transformation matrices.\nPlain RTMs must be converted to their \"binarized\" versions by an appropriate PBO packing tool for use in game.";
};
import std.mem;
import std.sys;
import std.string;
import std.io;
using lascii = std::string::SizedString<u8> [[format("formatLascii")]];
struct Property {
float phase;
lascii name;
lascii value;
} [[format("formatProperty")]];
struct Bone {
char name[32];
} [[sealed,static,transform("transformBone"),format("formatBone")]];
struct Transform {
Bone bone;
float matrix[12] [[comment("4x4 transformation matrix (with last row omitted)")]];
} [[static,format("formatTransform")]];
struct Frame {
float phase;
Transform transforms[parent.count_bones];
} [[static,format("formatFrame")]];
struct Vector {
float x [[comment("+Left/-Right")]];
float y [[comment("+Up/-Down (UNUSED)")]];
float z [[comment("+Forward/-Backward")]];
} [[static,format("formatVector")]];
struct RTM {
if (std::mem::read_string($, 8) == "RTM_MDAT") {
char properties_signature[8];
padding[4];
u32 count_properties;
Property properties[count_properties];
}
std::assert(std::mem::read_string($, 8) == "RTM_0101", "Missing animation data");
char animation_signature[8];
Vector motion;
u32 count_frames;
u32 count_bones;
Bone bones[count_bones];
Frame frames[count_frames];
std::assert_warn(std::mem::eof(), "Data ended before EOF");
};
fn formatLascii(ref lascii value) {
return std::format("\"{:s}\"", value);
};
fn formatProperty(ref Property prop) {
return std::format("\"{0:s}\" = \"{1:s}\" @ {2:.4f}", prop.name, prop.value, prop.phase);
};
fn transformBone(ref Bone value) {
return std::string::to_string(value.name);
};
fn formatBone(ref Bone value) {
return std::format("\"{0:s}\"", value);
};
fn formatTransform(ref Transform transform) {
return std::format("\"{0:s}\" transform", transform.bone);
};
fn formatFrame(ref Frame frame) {
return std::format("frame @ {0:.4f}", frame.phase);
};
fn formatVector(ref Vector vec) {
return std::format("[{0:.2f}, {1:.2f}, {2:.2f}]", vec.x, vec.y, vec.z);
};
RTM file @ 0x0000;

View File

@@ -0,0 +1,131 @@
#pragma author MrClock
#pragma description Arma 3 texture index file format
#pragma endian little
#pragma MIME application/x.a3-texheaders
fn get_data_description() {
return "TexHeaders.bin files are texture index files used in Arma 3 PBO archives.\nThe files are generated during the PBO packing process, and contain basic information about all the PAA texture files in the PBO.\nThe index for each texture includes the file paths relative to the PBO root, pixel format, suffix, number of mipmaps and their resolutions among other things.";
};
import std.string;
import std.math;
import type.color;
using asciiz = std::string::NullString;
struct BGRA8 {
u8 b;
u8 g;
u8 r;
u8 a;
} [[
static,
sealed,
format("type::impl::format_color"),
color(std::format("{0:02X}{1:02X}{2:02X}", r, g, b))
]];
struct RGBAfloat {
float r [[transform("float2u8")]];
float g [[transform("float2u8")]];
float b [[transform("float2u8")]];
float a [[transform("float2u8")]];
} [[
static,
sealed,
format("type::impl::format_color"),
color(std::format("{0:02X}{1:02X}{2:02X}", r, g, b))
]];
enum PixelFormat: u8 {
INDEXED = 0,
GRAY = 1,
RGB565 = 2,
RGBA5551 = 3,
RGBA4444 = 4,
RGBA8888 = 5,
DXT1 = 6,
DXT2 = 7,
DXT3 = 8,
DXT4 = 9,
DXT5 = 10
};
enum Suffix: u32 {
DIFFUSE = 0,
DIFFUSE_LINEAR = 1,
DETAIL = 2,
NORMAL = 3,
IRRADIANCE = 4,
RANDOM = 5,
TREECROWN = 6,
MACRO = 7,
SHADOW = 8,
SPECULAR = 9,
DITHERING = 10,
DETAIL_SPECULAR = 11,
MASK = 12,
THERMAL = 13
};
struct Mipmap {
u16 width;
u16 height;
padding[2];
PixelFormat format;
padding[1];
u32 offset [[comment("Byte offset in file")]];
} [[static,format("formatMipmap")]];
struct Texture {
u32 count_color_pallets [[comment("Always 1")]];
u32 pallet_pointer [[comment("Always 0")]];
RGBAfloat average_color_float;
BGRA8 average_color;
BGRA8 max_color;
u32 clamp_flags [[comment("Always 0")]];
u32 transparency [[comment("Always 0xffffffff")]];
bool maxcolor_defined [[comment("GGATCXAM was found in PAA")]];
bool alpha_interpolated;
bool alpha_binary;
bool non_opaque [[comment("Interpolated alpha and average alpha < 127")]];
u32 count_mipmaps;
/*
Technically the format is listed as u32 on the community wiki, but
for the sake of reusability in the Mipmap struct, it is broken up into
a u8 + 3 padding bytes here. (The enum values are in the u8 range
anyway.)
*/
PixelFormat format;
padding[3];
bool little_endian [[comment("Always true")]];
bool is_paa [[comment("File is PAA not PAC")]];
asciiz path [[comment("Path relative to texHeaders.bin file")]];
Suffix suffix;
u32 count_mipmaps_again;
Mipmap mipmaps[count_mipmaps];
u32 filesize;
}[[format("formatTexture")]];
struct TexHeaders {
char signature[4];
u32 version [[comment("Always 1")]];
u32 count_textures;
Texture textures[count_textures];
};
fn float2u8(float value) {
return u8(std::math::round(value * 255));
};
fn formatMipmap(ref Mipmap mip) {
return std::format("{0:d} x {1:d}", mip.width, mip.height);
};
fn formatTexture(ref Texture tex) {
return std::format("{0:d} x {1:d} @ {2:s}", tex.mipmaps[0].width, tex.mipmaps[0].height, tex.path);
};
TexHeaders file @ 0x0000;

176
patterns/adtfdat.hexpat Normal file
View File

@@ -0,0 +1,176 @@
#pragma description ADTFDAT File
#pragma magic [ 49 46 48 44 ] @ 0x00
#pragma endian little
import std.io;
import std.mem;
import type.time;
enum FileVersion : u32 {
with_history_end_offset = 0x00000301,
v500 = 0x00000500
};
bitfield ChunkFlags {
key : 1;
info : 1;
marker : 1;
type : 1;
trigger : 1;
reserved: 11;
};
struct Extension
{
char identifier[384];
u16 stream_id;
u8 reserved1[2];
u32 user_id;
u32 type_id;
u32 version_id;
u64 data_pos;
u64 data_size;
u8 reserved[96];
u8 payload[data_size] @ data_pos;
};
struct ChunkHeader {
u64 time_stamp [[format("format_timestamp_with_offset")]];;
u32 ref_master_table_index;
u32 offset_to_last;
u32 size;
u16 stream_id;
ChunkFlags flags;
u64 stream_index;
};
struct SampleInfo {
u8 memory_layout_version;
u32 size;
u8 payload[size];
};
struct Sample {
s64 timestamp [[format("format_timestamp")]];;
s32 flags;
u64 buffer_size;
u8 payload[buffer_size];
if (flags & 0x100) {
SampleInfo sample_info;
}
if (flags & 0x200) {
u32 substream_id;
} else {
u32 substream_id = 0 [[export]];
}
};
struct Chunk {
auto start_address = $;
ChunkHeader header;
if (header.size < 32 || start_address + header.size > std::mem::size()) {
std::warning(std::format("Invalid header size {} in chunk {} at offset 0x{:X}, last valid chunk at 0x{:X}.", header.size, chunk_index, start_address, last_valid_chunk_offset));
break;
}
last_valid_chunk_offset = start_address;
u8 payload[header.size - 32];
if (!skip_valid_chunks) {
if (!header.flags.info && !header.flags.marker && !header.flags.type && !header.flags.trigger) {
try {
Sample sample @ addressof(payload);
} catch {
std::warning(std::format("Invalid sample payload at chunk {} at 0x{:X}", chunk_index, start_address));
}
}
}
chunk_index += 1;
// Padding with 0xEE to the next chunk header
std::mem::AlignTo<16>;
if (skip_valid_chunks) {
continue;
}
};
struct Header {
u32 file_id;
u32 version_id;
u32 flags;
u32 extension_count;
u64 extension_offset;
u64 data_offset;
u64 data_size;
u64 chunk_count;
u64 max_chunk_size;
u64 duration;
type::time64_t filetime;
u8 header_byte_order;
u64 time_offset [[format("format_timestamp")]];
u8 patch_number;
u64 first_chunk_offset;
u64 continuous_offset;
u64 ring_buffer_end_offset;
u8 reserved[30];
char description[1912];
};
struct IndexedFile {
Header header;
Extension extensions[header.extension_count] @ header.extension_offset;
if (header.version_id >= FileVersion::with_history_end_offset &&
header.continuous_offset != header.data_offset) {
try {
Chunk ring_front[while($ < header.continuous_offset)] @ header.first_chunk_offset;
Chunk ring_back[while($ < header.ring_buffer_end_offset)] @ header.data_offset;
Chunk continueous[header.chunk_count - chunk_index] @ header.continuous_offset;
} catch {
std::warning("Too many chunks. Performing check only.");
skip_valid_chunks = true;
chunk_index = 0;
Chunk ring_front[while($ < header.continuous_offset)] @ header.first_chunk_offset;
Chunk ring_back[while($ < header.ring_buffer_end_offset)] @ header.data_offset;
Chunk continueous[while(chunk_index < header.chunk_count)] @ header.continuous_offset;
}
} else {
try {
Chunk chunks[header.chunk_count] @ header.data_offset;
} catch {
std::warning("Too many chunks. Performing check only.");
skip_valid_chunks = true;
chunk_index = 0;
Chunk chunks[while(chunk_index < header.chunk_count)] @ header.data_offset;
}
}
};
fn format_timestamp(u64 data) {
double seconds = 0;
if (file.header.version_id < FileVersion::v500) {
// microseconds
seconds = data / double(1000000);
} else {
// nanoseconds
seconds = data / double(1000000000);
}
std::time::Time time64 = std::time::to_utc(seconds);
return std::time::format(time64);
};
fn format_timestamp_with_offset(u64 data) {
return format_timestamp(data + file.header.time_offset);
};
bool skip_valid_chunks = false;
u64 last_valid_chunk_offset = 0;
u64 chunk_index = 0;
IndexedFile file @ 0x00;

View File

@@ -1,6 +1,6 @@
#pragma author zhoubo
#pragma description AAC ADTSn (Audio Data Transport Stream) Audio
#pragma magic [ FF F? ] @ 0x00
#pragma MIME audio/x-hx-aac-adts
#pragma pattern_limit 0xFFFFFF
// History

View File

@@ -1,6 +1,10 @@
#pragma author WerWolv
#pragma description Nintendo Switch Atmosphère CFW Fatal Error log
#pragma magic [ 41 46 45 30 ] @ 0x00
#pragma magic [ 41 46 45 31 ] @ 0x00
#pragma magic [ 41 46 45 32 ] @ 0x00
#pragma endian little
import std.io;

View File

@@ -36,7 +36,12 @@ struct RiffChunk {
u32 size;
if (signature == "RIFF" || signature == "LIST") {
char type[4];
RiffChunk chunks[while($ - addressof(type) < size)];
// Compatible with error size defined in ani files
u32 remain = sizeof($) - addressof(type);
u32 marked = size > remain ? remain : size;
RiffChunk chunks[while($ - addressof(type) < marked)];
} else if (signature[0] == 'I' && parent.type == "INFO") {
char info[size];
} else if (signature == "anih") {

View File

@@ -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;

168
patterns/bcss.hexpat Normal file
View File

@@ -0,0 +1,168 @@
#pragma author ttimasdf
#pragma description BeyondCompare Snapshot (BCSS) file
#pragma magic [42 43 53 53] @ 0x00
#pragma array_limit 4294967295
#pragma pattern_limit 4294967295
import std.io;
import std.mem;
import std.array;
import std.string;
import type.magic;
#ifdef __IMHEX__
import hex.dec;
import hex.core;
#endif
const u8 max_path_size = 1000;
str current_path[max_path_size];
u8 current_path_level = 0;
enum EntryType : u8 {
DIRECTORY = 0x01,
FILE = 0x02,
SYMLINK = 0x03,
// NULL = 0x00,
DIR_END = 0xFF,
};
struct BCSSEntry {
EntryType type;
match (type) {
(EntryType::DIRECTORY) : {
// FileName name;
std::string::SizedString<u8> name;
if (name.size != 0) {
u8 unknown[12];
on_dir_enter(name.data); // std::string::to_string(name)
} else {
// some buggy edge cases
u8 unknown[6];
std::warning(std::format("invalid empty entry current_lvl={} current_pos=0x{:02x}", current_path_level, $));
}
}
(EntryType::FILE) : {
std::string::SizedString<u8> name;
if (name.size != 0) {
u8 unknown[20];
#ifdef __IMHEX__
hex::core::add_virtual_file(get_vfs_path(name), this); // std::string::to_string(name)
#endif
} else {
// some buggy edge cases
u8 unknown[6];
std::warning(std::format("invalid empty entry current_lvl={} current_pos=0x{:02x}", current_path_level, $));
}
//try {
// u8 unknown[20];
//} catch {
// u8 unknown[0];
//}
}
(EntryType::SYMLINK) : {
std::string::SizedString<u8> name;
u8 unknown[23];
std::string::SizedString<u8> target;
#ifdef __IMHEX__
hex::core::add_virtual_file(get_vfs_path(name + " [s]"), this); // std::string::to_string(name)
#endif
}
(EntryType::DIR_END) : {
on_dir_exit();
}
// (EntryType::NULL) : {
// // some buggy edge cases
// u8 unknown[7];
// std::warning(std::format("invalid empty entry current_lvl={} current_pos=0x{:02x}", current_path_level, $));
// }
(_): {
std::error(std::format("unknown EntryType idx={} current_pos=0x{:02x}", std::core::array_index(), $));
}
}
}[[format_read("fmt_BCSSEntry")]];
fn on_dir_enter(str folder_name) {
// std::print("on_dir_enter folder={} current_lvl={}", folder_name, current_path_level);
if (std::string::length(folder_name) > 0) {
current_path[current_path_level] = folder_name;
current_path_level += 1;
} else {
std::warning(std::format("invalid folder name {} current_lvl={} current_pos=0x{:02x}", folder_name, current_path_level, $));
}
};
fn on_dir_exit() {
if (current_path_level > 0) {
current_path_level -= 1;
} else if (!std::mem::eof()) {
std::warning(std::format("on_dir_exit current_lvl already == 0 current_pos=0x{:02x}", $));
}
// std::print("on_dir_exit current_lvl={}", current_path_level);
};
fn get_vfs_path(str file_name) {
str vfs_path = "";
if (current_path_level > 0) {
vfs_path = current_path[0];
for(u8 i = 1, i < current_path_level, i += 1) {
//hash_hex = hash_hex + std::format("{:02X}",bytes[i]);
vfs_path = vfs_path + "/" + current_path[i];
}
return vfs_path + "/" + file_name;
} else {
return file_name;
}
};
fn fmt_BCSSEntry(BCSSEntry e) {
try {
match (e.type) {
(EntryType::DIRECTORY | EntryType::FILE) : {
return std::format("{}: {}", (e.type == EntryType::DIRECTORY ? "Dir" : "File"), e.name.data);
}
(EntryType::SYMLINK) : {
return std::format("Symlink: {} -> {}", e.name.data, e.target.data);
}
(EntryType::DIR_END) : {
return "Directory End";
}
}
} catch {
return "[FmtErr]";
}
};
struct BCSSFile {
if (std::mem::read_unsigned(0, 4) == 0x53534342) {
type::Magic<"BCSS"> magic;
u8 unknown[14];
std::string::SizedString<u16> root_path;
u8 zlib_content[std::mem::size()-$];
// manually add zlib header which is essential for hex::dec::zlib_decompress
const str zlib_header = "\x78\x9c";
std::mem::Section zlib_compressed = std::mem::create_section("zlib_compressed");
std::mem::copy_value_to_section(zlib_header, zlib_compressed, 0);
std::mem::copy_value_to_section(zlib_content, zlib_compressed, 2);
u8 zlib[std::mem::get_section_size(zlib_compressed)] @ 0x00 in zlib_compressed;
#ifdef __IMHEX__
std::mem::Section zlib_decompressed = std::mem::create_section("zlib_decompressed");
hex::dec::zlib_decompress(zlib, zlib_decompressed, 15);
u8 decompressed_content[std::mem::get_section_size(zlib_decompressed)] @ 0x00 in zlib_decompressed;
hex::core::add_virtual_file("bcss_content", decompressed_content);
std::warning("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n! BCSS file content is compressed !\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\nopen `bcss_content` file from the Virtual Filesystem tab and run this pattern on it.");
#endif
} else {
BCSSEntry entries[while(!std::mem::eof())];
}
};
BCSSFile bcss_file @ 0x00;

View File

@@ -38,10 +38,15 @@ namespace bencode {
ASCIIDecimal length;
char separator [[hidden]];
char value[length];
} [[sealed, format("bencode::format_string"), transform("bencode::format_string")]];
} [[sealed, format("bencode::format_string")]];
fn format_string(String string) {
return string.value;
for (u64 i = 0, i < string.length, i = i + 1) {
if (!std::ctype::isprint(string.value[i])) {
return "Contains non-printable characters";
}
}
return std::format("\"{}\"", string.value);
};
using Bencode;
@@ -57,6 +62,10 @@ namespace bencode {
if (type == Type::Dictionary) {
DictionaryEntry entry[while(std::mem::read_unsigned($, 1) != 'e')];
char end;
} else if (type == Type::List) {
Value entry[while(std::mem::read_unsigned($, 1) != 'e')];
char end;
} else if (type == Type::Integer) {
ASCIIDecimal value;
char end;

View File

@@ -1,80 +1,101 @@
#pragma author Shadlock0133 (aka Aurora)
#pragma author Shadlock0133 (aka Aurora) / WerWolv
#pragma description Prusa Binary G-Code
#pragma magic [ 47 43 44 45 ] @ 0x00
import type.magic;
import std.mem;
enum ChecksumType : u16 {
None,
CRC32,
None = 0,
CRC32 = 1
};
enum BlockType : u16 {
FileMetadata,
GCode,
SlicerMetadata,
PrinterMetadata,
PrintMetadata,
Thumbnail,
FileMetadata = 0,
GCode = 1,
SlicerMetadata = 2,
PrinterMetadata = 3,
PrintMetadata = 4,
Thumbnail = 5
};
enum Compression : u16 {
None,
Deflate,
Heatshrink11_4,
Heatshrink12_4,
enum CompressionType : u16 {
NoCompression = 0,
Deflate = 1,
HeatshrinkWindowSize11 = 2,
HeatshrinkWindowSize12 = 3
};
struct BlockHeader {
BlockType type;
CompressionType compressionType;
u32 uncompressedSize;
if (compressionType != CompressionType::NoCompression) {
u32 compressedSize;
}
u32 dataSize = compressionType == CompressionType::NoCompression ? uncompressedSize : compressedSize;
};
enum Encoding : u16 {
Ini,
INI = 0
};
struct Metadata {
Encoding encoding;
char data[parent.header.dataSize];
};
enum ImageFormat : u16 {
Png,
Jpg,
Qoi,
PNG = 0,
JPG = 1,
QOI = 2
};
struct Header {
type::Magic<"GCDE"> magic;
u32 version;
ChecksumType checksum_type;
struct Thumbnail {
ImageFormat format;
u16 width, height;
std::mem::Bytes<parent.header.dataSize> imageData;
} [[hex::visualize("image", imageData)]];
enum GCodeEncoding : u16 {
NoEncoding = 0,
MeatPack = 1,
MeatPackWithComments = 2
};
Header header @ 0;
std::assert(header.version == 1, "only version 1 supported");
struct GCode {
GCodeEncoding encoding;
std::mem::Bytes<parent.header.dataSize> gcode;
};
struct Block {
BlockType type;
Compression compression;
u32 uncompressed_size;
auto size = uncompressed_size;
if (compression != Compression::None) {
u32 compressed_size;
size = compressed_size;
}
match (type) {
(BlockType::FileMetadata
| BlockType::PrinterMetadata
| BlockType::PrintMetadata
| BlockType::SlicerMetadata): {
Encoding encoding;
}
(BlockType::Thumbnail): {
ImageFormat image_format;
u16 width;
u16 height;
}
(BlockType::GCode): {
u16;
}
(_): { std::assert(false, "unknown type"); }
}
u8 data[size];
match (header.checksum_type) {
(ChecksumType::None): {}
(ChecksumType::CRC32): { u32 checksum; }
BlockHeader header;
match (header.type) {
(BlockType::FileMetadata): Metadata fileMetadata;
(BlockType::PrinterMetadata): Metadata printerMetadata;
(BlockType::Thumbnail): Thumbnail thumbnail;
(BlockType::PrintMetadata): Metadata printMetadata;
(BlockType::SlicerMetadata): Metadata slicerMetadata;
(BlockType::GCode): GCode gcode;
(_): std::error("Invalid Block type!");
}
if (parent.checksumType != ChecksumType::None)
u32 checksum;
};
Block blocks[while(!std::mem::eof())] @ $;
struct BGCode {
type::Magic<"GCDE"> magic;
u32 version;
std::assert(version == 1, "Only Version 1 is supported");
ChecksumType checksumType;
Block blocks[while(!std::mem::eof())];
};
BGCode bgcode @ 0x00;

533
patterns/blf.hexpat Normal file
View File

@@ -0,0 +1,533 @@
// Pattern for binary logging files (Vector BLF)
// References used for writing this:
// https://python-can.readthedocs.io/en/stable/_modules/can/io/blf.html
// https://bitbucket.org/tobylorenz/vector_blf
#pragma magic [ 4C 4F 47 47 ] @ 0x00
#pragma description Vector BLF Frame Logging Files
#pragma array_limit 4194304
#pragma pattern_limit 4294967296
#pragma endian little
import hex.dec;
import std.io;
import type.magic;
enum object_type : u32 {
unknown = 0, //< unknown object
can_message = 1, //< CAN message object
can_error = 2, //< CAN error frame object
can_overload = 3, //< CAN overload frame object
can_statistic = 4, //< CAN driver statistics object
app_trigger = 5, //< application trigger object
env_integer = 6, //< environment integer object
env_double = 7, //< environment double object
env_string = 8, //< environment string object
env_data = 9, //< environment data object
log_container = 10, //< container object
lin_message = 11, //< LIN message object
lin_crc_error = 12, //< LIN CRC error object
lin_dlc_info = 13, //< LIN DLC info object
lin_rcv_error = 14, //< LIN receive error object
lin_snd_error = 15, //< LIN send error object
lin_slv_timeout = 16, //< LIN slave timeout object
lin_sched_modch = 17, //< LIN scheduler mode change object
lin_syn_error = 18, //< LIN sync error object
lin_baudrate = 19, //< LIN baudrate event object
lin_sleep = 20, //< LIN sleep mode event object
lin_wakeup = 21, //< LIN wakeup event object
most_spy = 22, //< MOST spy message object
most_ctrl = 23, //< MOST control message object
most_lightlock = 24, //< MOST light lock object
most_statistic = 25, //< MOST statistic object
flexray_data = 29, //< FLEXRAY data object
flexray_sync = 30, //< FLEXRAY sync object
can_driver_error = 31, //< CAN driver error object
most_pkt = 32, //< MOST Packet
most_pkt2 = 33, //< MOST Packet including original timestamp
most_hwmode = 34, //< MOST hardware mode event
most_reg = 35, //< MOST register data (various chips)
most_genreg = 36, //< MOST register data (MOST register)
most_netstate = 37, //< MOST NetState event
most_datalost = 38, //< MOST data lost
most_trigger = 39, //< MOST trigger
flexray_cycle = 40, //< FLEXRAY V6 start cycle object
flexray_message = 41, //< FLEXRAY V6 message object
lin_checksum_info = 42, //< LIN checksum info event object
lin_spike_event = 43, //< LIN spike event object
can_driver_sync = 44, //< CAN driver hardware sync
flexray_status = 45, //< FLEXRAY status event object
gps_event = 46, //< GPS event object
flexray_error = 47, //< FLEXRAY error event object
flexray_status = 48, //< FLEXRAY status event object
flexray_startcycle = 49, //< FLEXRAY start cycle event object
flexray_rcv_message = 50, //< FLEXRAY receive message event object
realtime_clock = 51, //< Realtime clock object
lin_statistic = 54, //< LIN statistic event object
j1708_message = 55, //< J1708 message object
j1708_virtual_message = 56, //< J1708 message object with more than 21 data bytes
lin_message2 = 57, //< LIN frame object - extended
lin_snd_error2 = 58, //< LIN transmission error object - extended
lin_syn_error2 = 59, //< LIN sync error object - extended
lin_crc_error2 = 60, //< LIN checksum error object - extended
lin_crv_error2 = 61, //< LIN receive error object
lin_wakeup2 = 62, //< LIN wakeup event object - extended
lin_spike_event2 = 63, //< LIN spike event object - extended
lin_long_dom_sig = 64, //< LIN long dominant signal object
app_text = 65, //< text object
flexray_rcvmessage_ex = 66, //< FLEXRAY receive message ex event object
most_statistic_ex = 67, //< MOST extended statistic event
most_txlight = 68, //< MOST TxLight event
most_alloctab = 69, //< MOST Allocation table event
most_stress = 70, //< MOST Stress event
ethernet_frame = 71, //< Ethernet frame object
sys_variable = 72, //< system variable object
can_error_ext = 73, //< CAN error frame object (extended)
can_driver_error_ext = 74, //< CAN driver error object (extended)
lin_long_dom_sig2 = 75, //< LIN long dominant signal object - extended
most_150_message = 76, //< MOST150 Control channel message
most_150_pkt = 77, //< MOST150 Asynchronous channel message
most_ethernet_pkt = 78, //< MOST Ethernet channel message
most_150_message_fragment = 79, //< Partial transmitted MOST50/150 Control channel message
most_150_pkt_fragment = 80, //< Partial transmitted MOST50/150 data packet on asynchronous channel
most_ethernet_pkt_fragment = 81, //< Partial transmitted MOST Ethernet packet on asynchronous channel
most_system_event = 82, //< Event for various system states on MOST
most_150_alloctab = 83, //< MOST50/150 Allocation table event
most_50_message = 84, //< MOST50 Control channel message
most_50_pkg = 85, //< MOST50 Asynchronous channel message
can_message2 = 86, //< CAN message object - extended
lin_unexpected_wakeup = 87,
lin_short_or_slow_response = 88,
lin_disturbance_event = 89,
serial_event = 90,
overrun_error = 91, //< driver overrun event
event_comment = 92,
wlan_frame = 93,
wlan_statistic = 94,
most_ecl = 95, //< MOST Electrical Control Line event
global_marker = 96,
afdx_frame = 97,
afdx_statistic = 98,
kline_statusevent = 99, //< E.g. wake-up pattern
can_fd_message = 100, //< CAN FD message object
can_fd_message_64 = 101, //< CAN FD message object
ethernet_rx_error = 102, //< Ethernet RX error object
ethernet_status = 103, //< Ethernet status object
can_fd_error_64 = 104, //< CAN FD Error Frame object
lin_short_or_slow_response2 = 105,
afdx_status = 106, //< AFDX status object
afdx_bus_statistic = 107, //< AFDX line-dependent busstatistic object
afdx_error_event = 109, //< AFDX asynchronous error event
a429_error = 110, //< A429 error object
a429_status = 111, //< A429 status object
a429_bus_statistic = 112, //< A429 busstatistic object
a429_message = 113, //< A429 Message
ethernet_statistic = 114, //< Ethernet statistic object
restore_point_container = 115, //< Restore point container, use unknown
test_structure = 118, //< Event for test execution flow
diag_request_information = 119, //< Event for correct interpretation of diagnostic requests
ethernet_frame_ex = 120, //< Ethernet packet extended object
ethernet_frame_forwarded = 121, //< Ethernet packet forwarded object
ethernet_error_ex = 122, //< Ethernet error extended object
ethernet_error_forwarded = 123, //< Ethernet error forwarded object
function_bus = 124, //< FunctionBus object
data_lost_begin = 125, //< Data lost begin
data_lost_end = 126, //< Data lost end
water_mark_event = 127, //< Watermark event
trigger_condition = 128, //< Trigger Condition event
can_setting_changed = 129, //< CAN Settings Changed object
distributed_object_member = 130, //< Distributed object member (communication setup)
attribute_event = 131, //< ATTRIBUTE event (communication setup)
};
bitfield can_msg_flags {
is_tx : 1;
padding : 4;
nerr : 1;
wu : 1;
rtr : 1;
};
struct can_msg {
u16 channel;
can_msg_flags flags;
u8 dlc;
u32 id;
u8 data[8];
};
struct can_msg2 {
u16 channel;
can_msg_flags flags;
u8 dlc;
u32 id;
auto struct_len = 2 + 1 + 1 + 4 + 4 + 1 + 1 + 2; // TODO: Alternative way of doing this?
u8 data[parent.header.object_size - parent.header.header_size - struct_len];
// The frame length in nanoseconds
u32 frame_length;
// Total number of bits of the CAN frame
u8 bit_count;
padding[1];
padding[2];
};
bitfield can_fd_msg_flags {
edl : 1; //< Extended data length
brs : 1; //< Bit rate switch
esi : 1; //< Error state indicator
padding : 5;
};
fn format_can_fd_dlc(u8 dlc) {
if (dlc > 8)
return 8 + (dlc - 8) * 4;
return dlc;
};
struct can_fd_msg {
u16 channel;
u8 flags;
u8 dlc [[format("format_can_fd_dlc")]];
u32 id;
// The frame length in nanoseconds
u32 frame_length;
u8 arbitration_bit_count;
can_fd_msg_flags fd_flags;
u8 valid_data_bytes;
padding[1];
padding[4];
u8 data[64];
padding[4];
};
bitfield can_fd_msg_64_flags {
padding : 2;
nerr : 1;
hv_wake_up : 1;
remote_frame : 1;
padding : 1;
tx_ack : 1;
tx_req : 1;
padding : 1;
srr : 1;
r0 : 1;
r1 : 1;
edl : 1; //< Extended data length
brs : 1; //< Bit rate switch
esi : 1; //< Error state indicator
padding : 2;
burst : 1;
padding : 13;
};
struct can_bitrate_cfg {
u8 quartz_frequency;
u8 prescaler;
u8 btl_cycles;
u8 sampling_point;
};
struct can_fd_msg_64 {
u8 channel;
u8 dlc [[format("format_can_fd_dlc")]];
u8 valid_data_bytes;
u8 tx_count;
u32 id;
u32 frame_length;
can_fd_msg_64_flags flags;
can_bitrate_cfg arbitration_bitrate;
can_bitrate_cfg data_bitrate;
u32 brs_time_offset;
u32 crc_time_offset;
u16 bit_length;
u8 direction;
u8 data_offset;
u32 crc;
u8 data[valid_data_bytes];
};
fn format_bus_load(u16 bus_load) {
return std::format("{}%", float(bus_load) / 100.f);
};
struct can_statistic {
u16 channel;
// Bus load in 1/100 percent
u16 bus_load [[format("format_bus_load")]];
u32 standard_data_frames;
u32 extended_data_frames;
u32 standard_remote_frames;
u32 extended_remote_frames;
u32 error_frames;
u32 overload_frames;
u32 reserved;
};
struct can_driver_error {
u16 channel;
u8 tx_errors;
u8 rx_errors;
u32 error_code;
};
enum app_text_source : u32 {
comment = 0,
database_info = 1,
metadata = 2,
};
enum database_bus_type : u8 {
can = 1,
lin = 5,
most = 6,
flexray = 7,
j1708 = 9,
ethernet = 10,
wlan = 13,
afdx = 14,
};
bitfield app_text_database_info {
version : 8;
channel_num : 8;
database_bus_type bus_type : 8;
is_can_fd : 1;
padding : 7;
};
struct app_text {
app_text_source source;
if (source == 1)
app_text_database_info database_info;
else
padding[4]; // TODO: This is not necessarily padding, there's data here
u32 text_length;
padding[4];
char text[text_length];
};
// No idea what this is or does
struct restore_point_container {
u8 rpc[14];
u16 data_len;
u8 data[data_len];
};
enum compression_method : u16 {
no_compression = 0,
zlib = 2,
};
// The following section contains all of the decompressed data at once
std::mem::Section decompressed_data = std::mem::create_section("Decompressed data");
// This section is used only for decompressing data
std::mem::Section zlib_decompress_result = std::mem::create_section("zlib decompress result");
struct log_container {
u64 container_begin = $;
compression_method compression_method;
padding[2];
padding[4];
u32 uncompressed_size;
padding[4];
if (compression_method == compression_method::zlib) {
std::mem::set_section_size(zlib_decompress_result, uncompressed_size);
// Create a pattern that defines the compressed array data
auto compressed_byte_len = parent.header.object_size - parent.header.header_size - ($ - container_begin);
u8 compressed[compressed_byte_len];
if (uncompressed_size != 0)
padding[parent.header.object_size % 4]; // Idk, the format wants this... for some reason
std::assert(hex::dec::zlib_decompress(compressed, zlib_decompress_result) == compressed_byte_len,
"zlib decompress needs to succeed");
// Copy the decompressed data to the end of the section
std::mem::copy_section_to_section(zlib_decompress_result, 0,
decompressed_data, std::mem::get_section_size(decompressed_data),
std::mem::get_section_size(zlib_decompress_result));
} else if (compression_method == compression_method::no_compression) {
u8 data[uncompressed_size];
std::mem::copy_value_to_section(data, decompressed_data, std::mem::get_section_size(decompressed_data));
} else {
std::assert(false, "Invalid/unknown compression method");
}
};
enum object_flags : u32 {
// Timestamps are stored with a unit of 10us (10 microseconds)
time_10_us = 1,
// Timestamps are stored with a unit of 1ns (1 nanosecond)
time_1_ns = 2,
};
enum timestamp_status : u8 {
// Means original timestamps are valid
orig = 0x01,
// Timestamp is generated by software (1) or by hardware (0)
swhw = 0x02,
user = 0x10,
};
struct obj_header_ext {
object_flags flags;
if (parent.header.header_version == 1)
u16 client_index;
else if (parent.header.header_version == 2) {
timestamp_status timestamp_status;
padding[1];
}
u16 object_version;
u64 object_timestamp;
if (parent.header.header_version == 2)
u64 original_timestamp;
};
struct obj_header {
type::Magic<"LOBJ"> magic; // 4C 4F 42 4A
u16 header_size;
u16 header_version;
u32 object_size;
object_type object_type;
std::assert(header_version == 1 || header_version == 2, "Invalid/unknown header version");
};
struct obj_struct {
auto object_begin = $;
obj_header header [[inline]];
if (header.object_type == object_type::log_container) {
// Log containers seem to never include additional V1 or V2 headers
log_container log [[inline]];
} else {
obj_header_ext ext_header [[inline]];
match(header.object_type) {
(object_type::can_message): {
can_msg message [[inline]];
}
(object_type::can_statistic): {
can_statistic statistics [[inline]];
}
(object_type::can_driver_error): {
can_driver_error errors [[inline]];
}
(object_type::can_message2): {
can_msg2 message [[inline]];
}
(object_type::can_fd_message): {
can_fd_msg message [[inline]];
}
(object_type::can_fd_message_64): {
can_fd_msg_64 message [[inline]];
padding[header.object_size - ($ - object_begin)]; // TODO: This pattern doesn't support the extra data for this object
}
(object_type::app_text): {
app_text text [[inline]];
padding[header.object_size % 4];
}
(object_type::restore_point_container): {
restore_point_container rpc [[inline]];
}
(_): u8 bytes[header.object_size - header.header_size];
}
}
};
enum application_id : u8 {
unknown = 0,
canalyzer = 1,
canoe = 2,
canstress = 3,
canlog = 4,
canape = 5,
cancasexl = 6,
vlconfig = 7,
porsche_logger = 200,
caetec_logger = 201,
vector_net_sim = 202,
ipetronik_logger = 203,
rtpk = 204,
piketec = 205,
sparks = 206,
};
fn format_api_version(u32 api_version) {
return std::format("{}.{}.{}",
api_version / 1000000,
(api_version % 1000000) / 1000,
(api_version % 1000) / 100);
};
// Mostly just the zlib compression levels, but with some extras
enum compression_level : u8 {
no_compression = 0,
best_speed = 1,
default_compression = 6,
best_compression = 9,
// This means that the file contains only log containers, usually compressed at level 6
default_container_compression = 10,
};
struct timestamp {
u16 year;
u16 month;
u16 day_of_week;
u16 day;
u16 hour;
u16 minute;
u16 second;
u16 millisecond;
} [[format("format_timestamp")]];
fn format_timestamp(timestamp ts) {
return std::format("{}-{}-{}_{}-{}-{}",
ts.year, ts.month, ts.day, ts.hour, ts.minute, ts.second);
};
struct file_header {
type::Magic<"LOGG"> magic; // 4C 4F 47 47
u32 header_length;
u32 api_version [[format("format_api_version")]];
application_id app_id;
compression_level compression_level;
u8 app_major;
u8 app_minor;
u64 file_length;
u64 uncompressed_length;
u32 object_count;
u32 application_build;
timestamp start_timestamp;
timestamp stop_timestamp;
u64 restore_point_offset; // ?
} [[inline]];
struct file_layout {
file_header header;
padding[header.header_length - sizeof(header)];
obj_struct objects[while($ < std::mem::size())];
// Decode all objects from the zlib compressed data
if (std::mem::get_section_size(decompressed_data) != 0)
obj_struct decompressed_objects[header.object_count] @ 0x00 in decompressed_data;
} [[inline]];
file_layout file @ 0x00;
std::assert_warn(std::mem::size() == file.header.file_length, "file size mismatch");

View File

@@ -1,4 +1,5 @@
#pragma description Apple binary property list
#pragma MIME application/x-bplist
import std.math;
import std.core;

110
patterns/cab.hexpat Normal file
View File

@@ -0,0 +1,110 @@
#pragma author The Wandering Trader
#pragma description Microsoft Cabinet (CAB) Files
#pragma magic [4D 53 43 46] @ 0x00
import type.time;
import type.magic;
import type.size;
fn format_string(auto string) {
return std::format("{}",string);
};
bitfield flags {
bool cfhdrPREV_CABINET : 1;
bool cfhdrNEXT_CABINET : 1;
bool cfhdrRESERVE_PRESENT : 1;
padding : 13;
};
struct CFHEADER {
type::Magic<"MSCF"> signature;
u32 reserved1;
type::Size32 cbCabinet;
u32 reserved2;
u32 coffFiles;
u32 reserved3;
u8 versionMajor;
u8 versionMinor;
u16 cFolders;
u16 cFiles;
flags flags;
u16 setID;
u16 iCabinet;
if (flags.cfhdrRESERVE_PRESENT) {
type::Size16 cbCFHeader;
type::Size8 cbCFFolder;
type::Size8 cbCFData;
u8 abReserve[cbCFHeader];
}
if (flags.cfhdrPREV_CABINET) {
char szCabinetPrev[] [[format("format_string")]];
char szDiskPrev[] [[format("format_string")]];
}
if (flags.cfhdrNEXT_CABINET) {
char szCabinetNext[] [[format("format_string")]];
char szDiskNext[] [[format("format_string")]];
}
};
enum typeCompress : u8{
tcompMASK_TYPE = 0x000F,
tcompTYPE_NONE = 0x0000,
tcompTYPE_MSZIP = 0x0001,
tcompTYPE_QUANTUM = 0x0002,
tcompTYPE_LZX = 0x0003,
};
using CFDATA;
struct CFFOLDER {
u32 coffCabStart;
u16 cCfData;
typeCompress typeCompress;
u8 compressionLevel;
if (CFHEADER.flags.cfhdrRESERVE_PRESENT) {
u8 abReserve[CFHEADER.cbCFFolder];
}
CFDATA CFDATA[cCfData] @ coffCabStart;
};
bitfield attribs {
bool _A_RDONLY : 1;
bool _A_HIDDEN : 1;
bool _A_SYSTEM : 1;
padding : 2;
bool _A_ARCH : 1;
bool _A_EXEC : 1;
bool _A_NAME_IS_UTF : 1;
padding : 8;
};
struct CFFILE {
type::Size32 cbFile;
u32 uoffFolderStart;
u16 iFolder;
type::DOSDate date;
type::DOSTime time;
attribs attribs;
if (attribs._A_NAME_IS_UTF) {
char16 szName[];
} else {
char szName[] [[format("format_string")]];
}
};
struct CFDATA {
u32 csum;
type::Size16 cbData;
type::Size16 cbUncomp;
if (CFHEADER.flags.cfhdrRESERVE_PRESENT) {
u8 abReserve[CFHEADER.cbCFData];
}
u8 ab[cbData];
};
CFHEADER CFHEADER @ 0;
CFFOLDER CFFOLDER[CFHEADER.cFolders] @ $;
CFFILE CFFILE[CFHEADER.cFiles] @ $;

View File

@@ -1,29 +1,29 @@
#pragma description Compact Disc Audio track
#pragma magic [ 52 49 46 46 ] @ 0x00
struct Header {
u32 RIFF;
s32 size;
u32 CDDA;
u32 fmt;
u32 lenghtofthechunck;
u16 versionofcdformat;
u16 numberofrange;
u32 identifier;
u32 RIFF;
s32 size;
u32 CDDA;
u32 fmt;
u32 lenghtofthechunck;
u16 versionofcdformat;
u16 numberofrange;
u32 identifier;
};
struct DataInfo {
u32 range;
u32 duration;
u8 rangepositionframes;
u8 rangepositionseconds;
u8 rangepositionminutes;
u8 nullbyte;
u8 durationtrackframes;
u8 durationtrackseconds;
u8 durationtrackminutes;
u8 nullbytee;
u32 range;
u32 duration;
u8 rangepositionframes;
u8 rangepositionseconds;
u8 rangepositionminutes;
u8 nullbyte;
u8 durationtrackframes;
u8 durationtrackseconds;
u8 durationtrackminutes;
u8 nullbytee;
};

105
patterns/chd.hexpat Normal file
View File

@@ -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;

View File

@@ -1,5 +1,6 @@
#pragma author WerWolv
#pragma description Windows HtmlHelp Data (ITSF / CHM)
#pragma MIME application/vnd.ms-htmlhelp
import type.magic;
import type.size;

View File

@@ -0,0 +1,81 @@
#pragma author East_Arctica
#pragma description Chromium Pak File
import std.core;
import std.io;
struct IndexEntry {
u16 id;
u32 offset;
};
struct AliasEntry {
u16 id;
u16 index;
};
struct ResourceView {
u32 i = std::core::array_index();
u16 id = parent.entries[i].id;
u32 start = parent.entries[i].offset;
u32 end = parent.entries[i + 1].offset;
u32 length = (end >= start) ? (end - start) : 0;
u8 data[length] @ start;
// pak_util.py implies that this may also be gzip with a header of 0x1f 0x8b
bool is_brotli = (length > 8 && data[0] == 0x1e && data[1] == 0x9b);
if (is_brotli) {
u8 magic[2] @ start;
u48 decompressed_size @ start + 2;
// TODO: If brotli decompression is added to ImHex, add it here.
}
};
struct AliasResourceView {
u32 i = std::core::array_index();
u16 id = parent.aliases[i].id;
u16 idx = parent.aliases[i].index;
bool valid = (idx < parent.resource_count);
u32 start = valid ? parent.entries[idx].offset : 0;
u32 end = valid ? parent.entries[idx + 1].offset : 0;
u32 length = (valid && end >= start) ? (end - start) : 0;
u8 data[length] @ start;
};
enum PakEncoding : u8 {
binary = 0,
utf8 = 1,
utf16 = 2
};
struct Pak {
u32 version;
if (version == 4) {
u32 resource_count;
PakEncoding encoding;
IndexEntry entries[resource_count + 1];
ResourceView resources[resource_count];
} else if (version == 5) {
PakEncoding encoding;
padding[3];
u16 resource_count;
u16 alias_count;
IndexEntry entries[resource_count + 1];
AliasEntry aliases[alias_count];
ResourceView resources[resource_count];
AliasResourceView alias_resources[alias_count];
} else {
std::error("Unsupported pak version");
}
};
// Some pack files are stored gzipped and need to be gunzipped first
Pak pak @ 0x00;

View File

@@ -0,0 +1,158 @@
#pragma description Commodore BASIC
#pragma author Stephen Hewitt
import std.io;
import std.mem;
bool in_quotes = false;
le u16 LoadAddress @0 [[color("ff0000")]];
fn formatll(u16 offset) {
if (offset&0xff00 == 0)
return "No next line";
u16 fo = offset-LoadAddress+2;
return std::format("Next line: ${:04X} (offset ${:04X})", offset, fo);
};
enum Token : u8 {
END = 0x80,
FOR = 0x81,
NEXT = 0x82,
DATA = 0x83,
INPUT_ = 0x84,
INPUT = 0x85,
DIM = 0x86,
READ = 0x87,
LET = 0x88,
GOTO = 0x89,
RUN = 0x8a,
IF = 0x8b,
RESTORE = 0x8c,
GOSUB = 0x8d,
RETURN = 0x8e,
REM = 0x8f,
STOP = 0x90,
ON = 0x91,
WAIT = 0x92,
LOAD = 0x93,
SAVE = 0x94,
VERIFY = 0x95,
DEF = 0x96,
POKE = 0x97,
PRINT_ = 0x98,
PRINT = 0x99,
CONT = 0x9a,
LIST = 0x9b,
CLR = 0x9c,
CMD = 0x9d,
SYS = 0x9e,
OPEN = 0x9f,
CLOSE = 0xa0,
GET = 0xa1,
NEW = 0xa2,
TAB_ = 0xa3,
TO = 0xa4,
FN = 0xa5,
SPC_ = 0xa6,
THEN = 0xa7,
NOT = 0xa8,
STEP = 0xa9,
PLUS_ = 0xaa,
MINUS_ = 0xab,
TIMES_ = 0xac,
DIVIDE_ = 0xad,
POW_ = 0xae,
AND = 0xaf,
OR = 0xb0,
GT_ = 0xb1,
EQ_ = 0xb2,
LT_ = 0xb3,
SGN = 0xb4,
INT = 0xb5,
ABS = 0xb6,
USR = 0xb7,
FRE = 0xb7,
POS = 0xb9,
SQR = 0xba,
RND = 0xbb,
LOG = 0xbc,
EXP = 0xbd,
COS = 0xbe,
SIN = 0xbf,
TAN = 0xc0,
ATN = 0xc1,
PEEK = 0xc2,
LEN = 0xc3,
STR_ = 0xc4,
VAL = 0xc5,
ASC = 0xc6,
CHR_ = 0xc7,
LEFT_ = 0xc8,
RIGHT_ = 0xc9,
MID_ = 0xca,
PI_ = 0xff
} [[format("formate")]];
// Can't seem to put attributes on enum members. Hack around it.
fn formate(Token t) {
match (t) {
(Token::INPUT_): return "INPUT#"; // $84
(Token::PRINT_): return "PRINT#"; // $98
(Token::TAB_): return "TAB("; // $a3
(Token::SPC_): return "SPC("; // $a6
(Token::PLUS_): return "+"; // $aa
(Token::MINUS_): return "-"; // $ab
(Token::TIMES_): return "*"; // $ac
(Token::DIVIDE_): return "/"; // $ad
//(Token::POW_): return "↑"; // $ae
(Token::GT_): return ">"; // $b1
(Token::EQ_): return "="; // $b2
(Token::LT_): return "<"; // $b3
(Token::STR_): return "STR$"; // $c4
(Token::CHR_): return "CHR$"; // $c7
(Token::LEFT_): return "LEFT$"; // $c8
(Token::RIGHT_): return "RIGHT$"; // $c9
(Token::MID_): return "MID$"; // $ca
//(Token::PI_): return "π"; // $ff
}
return t;
};
fn NotZero() {
u8 b = std::mem::read_unsigned($, 1);
return b!=0;
};
fn IsToken() {
u8 b = std::mem::read_unsigned($, 1);
return b&0x80!=0;
};
fn IsPETSCII() {
u8 b = std::mem::read_unsigned($, 1);
if (b == '"')
in_quotes = !in_quotes;
return (b!=0) && (in_quotes || (b&0x80)==0);
};
struct LineSegment
{
Token tokens[while(IsToken())] [[color("a040a0")]];
char petscii[while(IsPETSCII())] [[color("a0a0a0")]];
};
struct Line
{
in_quotes = false;
u16 next [[color("8080ff"), format("formatll")]];
if (next&0xff00 == 0)
break;
le u16 line_number [[color("00FF00")]];
LineSegment contents[while(NotZero())];
u8 eol [[color("00ffff")]];
};
Line Lines[while(!std::mem::eof())] @ 2;

View File

@@ -19,7 +19,7 @@ namespace old_binary {
};
fn format_time(u32 value) {
return std::time::format(std::time::to_utc(swap_32bit(value)));
return std::time::format(std::time::to_utc(old_binary::swap_32bit(value)));
};
using SwappedU32 = u32 [[transform("old_binary::swap_32bit"), format("old_binary::swap_32bit")]];

View File

@@ -0,0 +1,46 @@
#pragma author gunjambi
#pragma description "New" ASCII CPIO
#pragma magic [ 30 37 30 37 30 31 ] @ 0x00
import std.time;
import std.string;
namespace new_ascii {
fn format_hex_time(str value) {
return std::time::format(std::time::to_utc(std::string::parse_int(value, 16)));
};
fn parse_hex(str field) {
return std::string::parse_int(field, 16);
};
struct Cpio {
char c_magic[6];
if (c_magic != "070701") {
std::error("Invalid CPIO Magic!");
}
char c_ino[8] [[format("new_ascii::parse_hex"), transform("new_ascii::parse_hex")]];
char c_mode[8];
char c_uid[8] [[format("new_ascii::parse_hex"), transform("new_ascii::parse_hex")]];
char c_gid[8] [[format("new_ascii::parse_hex"), transform("new_ascii::parse_hex")]];
char c_nlink[8] [[format("new_ascii::parse_hex"), transform("new_ascii::parse_hex")]];
char c_mtime[8] [[format("new_ascii::format_hex_time")]];
char c_filesize[8] [[format("new_ascii::parse_hex"), transform("new_ascii::parse_hex")]];
char c_devmajor[8] [[format("new_ascii::parse_hex"), transform("new_ascii::parse_hex")]];
char c_devminor[8] [[format("new_ascii::parse_hex"), transform("new_ascii::parse_hex")]];
char c_rdevmajor[8] [[format("new_ascii::parse_hex"), transform("new_ascii::parse_hex")]];
char c_rdevminor[8] [[format("new_ascii::parse_hex"), transform("new_ascii::parse_hex")]];
char c_namesize[8] [[format("new_ascii::parse_hex"), transform("new_ascii::parse_hex")]];
char c_check[8] [[format("new_ascii::parse_hex"), transform("new_ascii::parse_hex")]];
char filename[c_namesize - 1];
padding[1];
if (filename == "TRAILER!!!")
break;
padding[(4 - ((6 + c_namesize) % 4)) % 4];
u8 data[c_filesize];
padding[(4 - (c_filesize % 4)) % 4];
};
}
new_ascii::Cpio cpio[while(true)] @ 0x00;

View File

@@ -0,0 +1,41 @@
#pragma author gunjambi
#pragma description Portable ASCII CPIO
#pragma magic [ 30 37 30 37 30 37 ] @ 0x00
import std.time;
import std.string;
namespace portable_ascii {
fn format_octal_time(str value) {
return std::time::format(std::time::to_utc(std::string::parse_int(value, 8)));
};
fn parse_octal_string(str field) {
return std::string::parse_int(field, 8);
};
struct Cpio {
char c_magic[6];
if (c_magic != "070707") {
std::error("Invalid CPIO Magic!");
}
char c_dev[6] [[format("portable_ascii::parse_octal_string"), transform("portable_ascii::parse_octal_string")]];
char c_ino[6] [[format("portable_ascii::parse_octal_string"), transform("portable_ascii::parse_octal_string")]];
char c_mode[6];
char c_uid[6] [[format("portable_ascii::parse_octal_string"), transform("portable_ascii::parse_octal_string")]];
char c_gid[6] [[format("portable_ascii::parse_octal_string"), transform("portable_ascii::parse_octal_string")]];
char c_nlink[6] [[format("portable_ascii::parse_octal_string"), transform("portable_ascii::parse_octal_string")]];
char c_rdev[6] [[format("portable_ascii::parse_octal_string"), transform("portable_ascii::parse_octal_string")]];
char c_mtime[11] [[format("portable_ascii::format_octal_time")]];
char c_namesize[6] [[format("portable_ascii::parse_octal_string"), transform("portable_ascii::parse_octal_string")]];
char c_filesize[11] [[format("portable_ascii::parse_octal_string"), transform("portable_ascii::parse_octal_string")]];
char filename[c_namesize - 1];
padding[1];
if (filename == "TRAILER!!!")
break;
u8 data[c_filesize];
};
}
portable_ascii::Cpio cpio[while(true)] @ 0x00;

View File

@@ -1,4 +1,5 @@
#pragma description Dalvik EXecutable
#pragma magic [ 64 65 78 0A ?? ?? ?? 00 ]
import type.leb128;

165
patterns/dmc3_hd_mod.hexpat Normal file
View File

@@ -0,0 +1,165 @@
#pragma description Devil May Cry 3 HD .mod 3D model file
#pragma MIME 3d-model/capcom.dmc3-hd-mod
// author = haru233, many thanks to AxCut
// ImHex Hex Pattern File for Capcom's Devil May Cry 3 HD .mod files
import std.core;
struct ModelHeader {
char ID[4];
float Version;
padding[8];
u8 objectCount;
u8 boneCount;
u8 numberTextures;
u8;
u32;
u64;
u64 skeletonOffset;
padding[24];
};
struct ObjectInfo {
u8 meshCount;
u8;
u16 numberVertices;
padding[4];
u64 meshOffset;
u32 flags;
padding[28];
float X, Y, Z;
float radius;
};
struct Positions {
float positions[3];
};
struct Normals {
float normal[3];
};
struct UVs {
s16 uv[2];
};
struct BoneIndices {
u8 boneindex[4];
};
struct Weights {
u16 weight[1];
};
struct MeshSCM {
u16 numberVertices;
u16 textureIndex;
padding[12];
u64 VerticesPositionsOffset;
u64 NormalsPositionsOffset;
u64 UVsPositionsOffset;
padding[16];
u64 unknownOffset;
u64;
padding[8];
Positions positions[numberVertices] @VerticesPositionsOffset;
Normals normals[numberVertices] @NormalsPositionsOffset;
UVs uvs[numberVertices] @UVsPositionsOffset;
};
struct Mesh {
u16 numberVertices;
u16 textureIndex;
padding[12];
u64 VerticesPositionsOffset;
u64 NormalsPositionsOffset;
u64 UVsPositionsOffset;
u64 BoneIndicesOffset;
u64 WeightsOffset;
padding[8];
u64;
padding[8];
Positions positions[numberVertices] @VerticesPositionsOffset;
Normals normals[numberVertices] @NormalsPositionsOffset;
UVs uvs[numberVertices] @UVsPositionsOffset;
BoneIndices b_index[numberVertices] @BoneIndicesOffset;
Weights weights[numberVertices] @WeightsOffset;
};
struct Hierarchy {
u8 hierarchy;
};
struct HierarchyOrder {
u8 hierarchyorder;
};
struct Unknown {
u8;
};
struct Transform {
float x;
float y;
float z;
float length; // sqrt(x*x + y*y + z*z)
padding[16];
};
struct Skeleton{
u32 hierarchyOffset;
u32 hierarchyOrderOffset;
u32 unknownOffset;
u32 transformsOffset;
};
ModelHeader modelheader @ 0x00;
ObjectInfo objects_info[modelheader.objectCount] @ 0x40;
u32 objectOffset;
struct Object {
u64 i = std::core::array_index();
if (modelheader.ID == "SCM ") {
objectOffset = objects_info[0].meshOffset;
MeshSCM meshscm[objects_info[i].meshCount] @ objects_info[i].meshOffset;
} else {
objectOffset = objects_info[0].meshOffset;
Mesh mesh[objects_info[i].meshCount] @ objects_info[i].meshOffset;
}
};
Object objects[modelheader.objectCount] @objectOffset;
Skeleton skeleton @modelheader.skeletonOffset;
Hierarchy hierarchy[modelheader.boneCount] @(modelheader.skeletonOffset + skeleton.hierarchyOffset);
HierarchyOrder hierarchyorder[modelheader.boneCount] @(modelheader.skeletonOffset + skeleton.hierarchyOrderOffset);
Unknown unknown[modelheader.boneCount] @(modelheader.skeletonOffset + skeleton.unknownOffset);
Transform transform[modelheader.boneCount] @(modelheader.skeletonOffset + skeleton.transformsOffset);

View File

@@ -1,4 +1,5 @@
#pragma description Apple Disk Image Trailer (DMG)
#pragma magic [ 6B 6F 6C 79 ] @ -512
#pragma endian big

View File

@@ -1,4 +1,4 @@
#pragma magic [50 41 47 45] // PAGE
#pragma magic [ 50 41 47 45 ] @ 0x00 // PAGE
#pragma author "5h4rrK"
#pragma description "KERNEL DUMP"
@@ -99,4 +99,4 @@ struct DUMP_HEADER64 {
};
DUMP_HEADER64 dmp @0x00 [[name("DumpHeader")]];
DUMP_HEADER64 dmp @ 0x00 [[name("DumpHeader")]];

242
patterns/dos.hexpat Normal file
View File

@@ -0,0 +1,242 @@
#pragma author Stephen Hewitt
#pragma description MSDOS executable file
#pragma MIME application/x-dosexec
#pragma MIME application/x-msdownload
#pragma MIME application/x-dosexecapplication/zip
#pragma MIME application/vnd.microsoft.portable-executable
import type.magic;
import std.io;
import std.mem;
import std.math;
import std.string;
/*
* A DOS EXE file, at a high level, consists of three regions:
*
* Header
* As it's name suggests. Contains info the loader uses.
*
* Load module
* Contains the program data that is loaded into memory.
*
* Extra data
* Data appended to the file that isn't loaded into memory.
*
* We'll call the combined header and load module the
* "program image". It's what the DOS loader cares about.
*/
/*
* Wikipedia: The New Executable (NE or NewEXE) is a 16-bit executable
* file format, a successor to the DOS MZ executable format. It was used
* in Windows 1.03.x, Windows 9x, multitasking MS-DOS 4.0,[1] OS/2 1.x,
* and the OS/2 subset of Windows NT up to version 5.0 (Windows 2000).
*
* Since it was used in DOS we'll support it.
*
* We'll make it optional since some programs increased
* 'headerSizeInParagraphs' and stashed all kind of stuff there.
*/
bool EnableNEHeaderExt in;
/*
* DOS file offsets/sizes. DOS uses INT 21h for file I/O. File positions and
* lengths are tracked using 32-bit signed integers. DOS INT 21h functions
* treat the offset as signed, so the highest positive offset is 0x7FFFFFFF.
* Attempting to seek beyond that or read/write beyond that will fail.
* We'll use a u32.
*/
u32 g_loadModule;
u32 g_loadModuleSize;
u32 g_programImageSize;
fn formatNumber(u32 num, str msg="") {
if (std::string::length(msg)==0)
return std::format("0x{:x} ({})", num, num);
else
return std::format("{} 0x{:x} ({})", msg, num, num);
};
fn inLoadModule(u32 off, u32 sz) {
return off>=g_loadModule && off+sz<=g_loadModule+g_loadModuleSize;
};
struct Relocation {
u16 offset [[color("9AE630")]];
u16 segment [[color("FE9A37")]];
};
struct RelocationAnnotated : Relocation {
u32 fileOffset = g_loadModule+offset+segment*16;
if (inLoadModule(fileOffset, 2)) {
u16 __goto__target @ fileOffset [[highlight_hidden]];
}
else {
str __goto__target = formatNumber(fileOffset, "Not in load module") [[export, highlight_hidden]];
}
};
struct Relocations {
if (parent.dosHeader.relocations>0) {
Relocation __goto__firstReloc @ $ [[highlight_hidden]];
Relocation __goto__lastReloc @ $+(parent.dosHeader.relocations-1)*sizeof(Relocation) [[highlight_hidden]];
}
RelocationAnnotated data[parent.dosHeader.relocations] [[inline]];
};
struct DOSHeader {
type::Magic<"MZ"> signature [[hex::spec_name("e_magic")]];
u16 extraPageSize [[hex::spec_name("e_cblp")]];
u16 numberOfPages [[hex::spec_name("e_cp")]];
g_programImageSize = (extraPageSize==0) ?
(numberOfPages*512) :
(numberOfPages-1)*512 + extraPageSize;
str __programImageSize = formatNumber(g_programImageSize) [[export, highlight_hidden]];
u8 __goto__lastByteInProgramImage @ g_programImageSize-1 [[highlight_hidden]];
u16 relocations [[name("stubRelocations"), hex::spec_name("e_crlc")]];
u16 headerSizeInParagraphs [[hex::spec_name("e_cparhdr")]];
u32 headerSize = headerSizeInParagraphs*16;
g_loadModule = headerSizeInParagraphs*16;
g_loadModuleSize = g_programImageSize - headerSize;
str __headerSize = formatNumber(headerSize) [[export, highlight_hidden]];
u8 __goto__lastByteInHeader @ headerSize-1 [[highlight_hidden]];
u16 minimumAllocatedParagraphs [[hex::spec_name("e_minalloc")]];
u16 maximumAllocatedParagraphs [[hex::spec_name("e_maxalloc")]];
u16 initialSSValue [[hex::spec_name("e_ss")]];
u16 initialRelativeSPValue [[hex::spec_name("e_sp")]];
u16 checksum [[name("stubChecksum"), hex::spec_name("e_csum")]];
u16 initialRelativeIPValue [[hex::spec_name("e_ip")]];
u16 initialCSValue [[hex::spec_name("e_cs")]];
u32 csAddrFirst = initialCSValue<<4;
u32 csAddrLast = (csAddrFirst+0xffff) & ((1<<20)-1);
u32 csEndGap = 0;
if (csAddrFirst <= csAddrLast) {
u32 csOffsetFirst = headerSize+csAddrFirst;
u32 csOffsetLast = csOffsetFirst+std::math::min(0x10000, g_loadModuleSize)-1;
}
else {
u32 csOffsetFirst = headerSize;
csEndGap = (1<<20)-csAddrFirst;
u32 csOffsetLast = headerSize+(0x10000-csEndGap-1);
std::warning("EXE has 'initialCSValue' set such that 20-bit address wraps.");
std::warning(" My guess would be to get the PSP into the CS.");
}
/*
* Adding `csEndGap` to the `initialIP` calculation below is required because the
* program is started by transferring execution to CS:IP. If `csEndGap` is non-zero
* CS and the start of the load-module value do not align; theres some extra data
* the CPU can see before the data in the EXE. What confused me for a bit was why
* its not required in the relocation target locations I make. The reason, I think,
* is that when the loader loads the load-module into memory and then proceeds to
* apply the relocations, the offsets are relative to the segment the code is loaded
* in and not the execution environment (the CS register from `initialCSValue`).
*/
u32 initialIP = csOffsetFirst+initialRelativeIPValue-csEndGap;
if (inLoadModule(initialIP, 1))
u8 __goto__initiaIP @ initialIP [[highlight_hidden]];
else
str __goto__initiaIP = formatNumber(initialIP, "Not in load module!") [[export, highlight_hidden]];
u32 csSize = csOffsetLast-csOffsetFirst+1;
if (inLoadModule(csOffsetFirst, csSize)) {
std::mem::Bytes<csSize> __select__InitialCS @ csOffsetFirst [[highlight_hidden]];
u8 __goto__InitialCS_first @ csOffsetFirst [[highlight_hidden]];
u8 __goto__InitialCS_last @ csOffsetFirst+csSize-1 [[highlight_hidden]];
}
else {
str __select__CS = formatNumber(csOffsetFirst, "Not in image!") [[export, highlight_hidden]];
}
u16 relocationsTablePointer [[hex::spec_name("e_lfarlc")]];
u32 sizeofRelocations = relocations*sizeof(Relocation);
if (relocations>0 && relocationsTablePointer+sizeofRelocations<g_programImageSize) {
std::mem::Bytes<sizeofRelocations> __select__relocationsTable
@ relocationsTablePointer [[highlight_hidden]];
}
else {
str __select__relocationsTable =
"Not in image or zero length" [[export, highlight_hidden]];
}
u16 overlayNumber [[hex::spec_name("e_ovno")]];
};
struct NEDOSHeaderExt {
u16 reservedWords[4] [[hex::spec_name("e_res")]];
u16 oemIdentifier [[hex::spec_name("e_oemid")]];
u16 oemInformation [[hex::spec_name("e_oeminfo")]];
u16 otherReservedWords[10] [[hex::spec_name("e_res2")]];
u32 newHeaderPointer [[hex::spec_name("e_lfanew")]];
};
struct NEDOSHeaderExtAnnotated : NEDOSHeaderExt {
if (newHeaderPointer < std::mem::size())
u8 __goto__newHeader @ newHeaderPointer [[highlight_hidden]];
else
str __goto__newHeader
= formatNumber(newHeaderPointer, "Not in image!") [[export, highlight_hidden]];
};
/*
* The header of a DOS EXE file consists of three regions.
*
* DOSHeader
* Present in all DOS EXEs. Used by the loader.
*
* NEDOSHeaderExt
* An extension to the header. Optional.
*
* Relocations
* An array of segment relocations to the apply to the load module. Optional.
*
* The header is followed by the load module. There can be gaps between
* DOSHeader (or NEDOSHeaderExt if present) and Relocations, and between the
* Relocations and the load module. It is not uncommon for EXEs to stash candy
* in these gaps.
*/
struct Header {
DOSHeader dosHeader;
if (EnableNEHeaderExt) {
if (dosHeader.relocationsTablePointer < $+sizeof(NEDOSHeaderExt)) {
std::warning("NEHeaderExt and Relocations overlap. Disabling NEHeaderExt.");
}
else {
NEDOSHeaderExtAnnotated extHeader;
}
}
if (dosHeader.relocations > 0) {
if (dosHeader.relocationsTablePointer < $) {
std::warning("Relocation table overlaps previous header members");
}
if (dosHeader.relocationsTablePointer+dosHeader.relocations*sizeof(Relocation) > g_loadModule) {
std::warning("Relocation table ends past header.");
}
}
if (dosHeader.relocationsTablePointer > $) {
u8 header_reloc_gap[dosHeader.relocationsTablePointer-$] [[highlight_hidden]];
}
Relocations relocations;
if (g_loadModule > $) {
u8 reloc_loadModule_gap[g_loadModule-$] [[highlight_hidden]];
}
};
struct LoadModule {
u8 __goto__first @ $ [[highlight_hidden]];
u8 __goto__last @ $+g_loadModuleSize-1 [[highlight_hidden]];
u8 data[g_loadModuleSize];
} [[color("7393B3")]];
Header header @0;
LoadModule loadModule @g_loadModule;;

View File

@@ -0,0 +1,921 @@
/*
References:
.NET BinaryFormatter Specification "MS-NRBF":
https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-nrbf/75b9fe09-be15-475f-85b8-ae7b7558cfe5
.NET runtime:
https://github.com/dotnet/runtime/blob/v8.0.17/src/libraries/System.Runtime.Serialization.Formatters/src/System/Runtime/Serialization/Formatters/Binary/BinaryParser.cs
.NET Library for Parsing MS-NRBF streams:
https://github.com/bbowyersmyth/BinaryFormatDataStructure
*/
#pragma author ODeux
#pragma description .NET BinaryFormatter (System.Runtime.Serialization.Formatters.Binary, obsolete)
#pragma endian little
import std.core;
import std.sys;
import std.mem;
import std.ptr;
fn offsetOf(ref auto value, ref auto value_field){
return addressof(value_field) - addressof(value);
};
struct NullableArrayPtr<T, pointerSize, auto size>{
pointerSize pointerValue [[no_unique_address, hidden]];
if(pointerValue != 0)
T *data[size]: pointerSize;
else
padding[sizeof(pointerSize)];
};
using _Ptr<T, PointerSize> = std::ptr::NullablePtr<T, PointerSize>;
using _ArrayPtr<T, PointerSize, auto size> = NullableArrayPtr<T, PointerSize, size>;
fn append_value_to_section(ref auto value, std::mem::Section section){
u128 old_section_size = std::mem::get_section_size(section);
std::mem::copy_value_to_section(value, section, old_section_size);
return old_section_size;
};
fn todo(auto message){
std::error(std::format("@0x{:08X} TODO: " + message, $));
};
using _Trackers;
std::mem::Section _TrackersSection = std::mem::create_section("_TrackersSection");
_Trackers _trackers @ 0x0 in _TrackersSection;
bool NeedUpdateTrackers = false;
bool IsUpdatingTrackers = false;
enum _ObjEnum: u64{
Empty = 0,
SerializedStreamHeader = 1,
ClassWithId = 2, Object = _ObjEnum::ClassWithId,
SystemClassWithMembers = 3, ObjectWithMap = _ObjEnum::SystemClassWithMembers,
ClassWithMembers = 4, ObjectWithMapAssemId = _ObjEnum::ClassWithMembers,
SystemClassWithMembersAndTypes = 5, ObjectWithMapTyped = _ObjEnum::SystemClassWithMembersAndTypes,
ClassWithMembersAndTypes = 6, ObjectWithMapTypedAssemId = _ObjEnum::ClassWithMembersAndTypes,
BinaryObjectString = 7, ObjectString = _ObjEnum::BinaryObjectString,
BinaryArray = 8, Array = _ObjEnum::BinaryArray,
MemberPrimitiveTyped = 9,
MemberReference = 10,
BinaryLibrary = 11, Assembly = _ObjEnum::BinaryLibrary,
ObjectNullMultiple256 = 12,
ObjectNullMultiple = 13,
ArraySinglePrimitive = 14,
ArraySingleObject = 15,
ArraySingleString = 16,
CrossAppDomainMap = 17,
CrossAppDomainString = 18,
CrossAppDomainAssembly = 19,
MethodCall = 20,
MethodReturn = 21
};
fn zeroedCurrObjTrackers(){
_trackers.currentObj.TypeName.pointerValue = 0;
_trackers.currentObj.AssemblyName.pointerValue = 0;
_trackers.currentObj.objEnum = _ObjEnum::Empty;
_trackers.currentObj.RawPtr = 0;
};
fn copyCurrObjAtIdTrackers(auto id){
NeedUpdateTrackers = true;
_trackers.objs[id].TypeName.pointerValue = _trackers.currentObj.TypeName.pointerValue;
_trackers.objs[id].AssemblyName.pointerValue = _trackers.currentObj.AssemblyName.pointerValue;
/* ! Enum does not get copied if we don't use a cast here for some reason ! */
_trackers.objs[id].objEnum = u64(_trackers.currentObj.objEnum);
_trackers.objs[id].RawPtr = _trackers.currentObj.RawPtr;
};
using BitfieldOrder = std::core::BitfieldOrder;
using TimeSpan = s64;
enum PrimitiveTypeEnum: u8{
Invalid = 0,
Boolean = 1,
Byte = 2,
Char = 3,
Currency = 4, /* Not Used in this protocol */
Decimal = 5,
Double = 6,
Int16 = 7,
Int32 = 8,
Int64 = 9,
SByte = 10,
Single = 11,
TimeSpan = 12,
DateTime = 13,
UInt16 = 14,
UInt32 = 15,
UInt64 = 16,
Null = 17,
String = 18
};
struct PrimitiveTypeEnumT<auto _primitiveTypeEnumT>{
PrimitiveTypeEnum primitiveTypeEnumT = _primitiveTypeEnumT;
PrimitiveTypeEnum primitiveTypeEnum;
if(_primitiveTypeEnumT > 0)
std::assert(primitiveTypeEnum == primitiveTypeEnumT, std::format("Expected {} but got {}", primitiveTypeEnumT, primitiveTypeEnum));
};
enum BinaryTypeEnum: u8{
Primitive = 0,
String = 1,
Object = 2,
SystemClass = 3, ObjectUrt = BinaryTypeEnum::SystemClass,
Class = 4, ObjectUser = BinaryTypeEnum::Class,
ObjectArray = 5,
StringArray = 6,
PrimitiveArray = 7
};
enum BinaryArrayTypeEnum: u8{
Single = 0,
Jagged = 1,
Rectangular = 2,
SingleOffset = 3,
JaggedOffset = 4,
RectangularOffset = 5
};
enum RecordTypeEnum: u8{
SerializedStreamHeader = 0,
ClassWithId = 1, Object = RecordTypeEnum::ClassWithId,
SystemClassWithMembers = 2, ObjectWithMap = RecordTypeEnum::SystemClassWithMembers,
ClassWithMembers = 3, ObjectWithMapAssemId = RecordTypeEnum::ClassWithMembers,
SystemClassWithMembersAndTypes = 4, ObjectWithMapTyped = RecordTypeEnum::SystemClassWithMembersAndTypes,
ClassWithMembersAndTypes = 5, ObjectWithMapTypedAssemId = RecordTypeEnum::ClassWithMembersAndTypes,
BinaryObjectString = 6, ObjectString = RecordTypeEnum::BinaryObjectString,
BinaryArray = 7, Array = RecordTypeEnum::BinaryArray,
MemberPrimitiveTyped = 8,
MemberReference = 9,
ObjectNull = 10,
MessageEnd = 11,
BinaryLibrary = 12, Assembly = RecordTypeEnum::BinaryLibrary,
ObjectNullMultiple256 = 13,
ObjectNullMultiple = 14,
ArraySinglePrimitive = 15,
ArraySingleObject = 16,
ArraySingleString = 17,
CrossAppDomainMap = 18,
CrossAppDomainString = 19,
CrossAppDomainAssembly = 20,
MethodCall = 21,
MethodReturn = 22
};
using BinaryHeaderEnum = RecordTypeEnum;
struct RecordTypeEnumT<auto _recordTypeEnumT>{
RecordTypeEnum recordTypeEnumT = _recordTypeEnumT;
RecordTypeEnum recordTypeEnum;
if(_recordTypeEnumT > 0)
std::assert(recordTypeEnum == recordTypeEnumT, std::format("Expected {} but got {}", recordTypeEnumT, recordTypeEnum));
};
bitfield MessageFlags{
bool NoArgs: 1; /* Arg Category */
bool ArgsInline: 1; /* Arg Category */
bool ArgsIsArray: 1; /* Arg Category */
bool ArgsInArray: 1; /* Arg Category */
bool NoContext: 1; /* Context Category */
bool ContextInline: 1; /* Context Category */
bool ContextInArray: 1; /* Context Category */
bool MethodSignatureInArray: 1; /* Signature Category */
bool PropertiesInArray: 1; /* Property Category */
bool NoReturnValue: 1; /* Return Category */
bool ReturnValueVoid: 1; /* Return Category */
bool ReturnValueInline: 1; /* Return Category */
bool ReturnValueInArray: 1; /* Return Category */
bool ExceptionInArray: 1; /* Exception Category */
bool GenericMethod: 1; /* Generic Category */
unsigned unused: 17;
} [[bitfield_order(BitfieldOrder::LeastToMostSignificant, 32)]];
fn validate_MessageFlags(MessageFlags flags){
u8 arg_cnt = flags.NoArgs + flags.ArgsInline + flags.ArgsIsArray + flags.ArgsInArray;
u8 ctx_cnt = flags.NoContext + flags.ContextInline + flags.ContextInArray;
u8 sig_cnt = flags.MethodSignatureInArray;
u8 ret_cnt = flags.NoReturnValue + flags.ReturnValueVoid + flags.ReturnValueInline + flags.ReturnValueInArray;
u8 excep_cnt = flags.ExceptionInArray;
u8 prop_cnt = flags.PropertiesInArray;
u8 gen_cnt = flags.GenericMethod;
if(arg_cnt > 1 || ctx_cnt > 1 || sig_cnt > 1 || ret_cnt > 1 || excep_cnt > 1 || prop_cnt > 1 || gen_cnt > 1)
return -1;
if(arg_cnt != 0 && excep_cnt != 0) return -1;
if(ret_cnt != 0 && excep_cnt != 0) return -1;
if(ret_cnt != 0 && sig_cnt != 0) return -1;
if(excep_cnt != 0 && sig_cnt != 0) return -1;
return 1;
};
enum DateTimeKind: u8{
NOT_SPECIFIED = 0,
UTC = 1,
Local = 2
};
bitfield DateTime{
s64 Ticks: 62;
DateTimeKind kind: 2;
} [[bitfield_order(BitfieldOrder::LeastToMostSignificant, 64)]];
struct vLength{
/*
Can't use that, it breaks when struct get re-parsed in _TrackersSection
u8 data[while(std::mem::read_unsigned($, 1) & 0x80)];
u8 last;
*/
u64 bytes [[no_unique_address, hidden]];
u8 cnt = 0;
if(bytes & 0x80){
if(bytes & 0x8000){
if(bytes & 0x800000){
if(bytes & 0x80000000){
if(bytes & 0x8000000000){
/* exceeding vLength 5 bytes, caller should crash */
cnt = 5;
}else cnt = 4;
}else cnt = 3;
}else cnt = 2;
}else cnt = 1;
}else cnt = 0;
u8 data[cnt];
u8 last;
} [[sealed, transform("LPS_Length_decode"), format("LPS_Length_decode")]];
fn LPS_Length_decode(auto Length){
u64 length = 0;
u8 i = 0;
for(i = 0, i < sizeof(Length.data), i += 1)
length |= u64(Length.data[i] & 0x7F) << i * 7;
length |= u64(Length.last) << i * 7;
return length;
};
struct LengthPrefixedString{
vLength Length;
std::assert(sizeof(Length) <= 5, "LengthPrefixedString.Length must be at most 5 bytes long");
char String[Length];
};
using Decimal = LengthPrefixedString;
struct ClassTypeInfo{
LengthPrefixedString TypeName;
s32 LibraryId;
};
struct ValueWithCode{
PrimitiveTypeEnum PrimitiveType;
match(PrimitiveType){
(PrimitiveTypeEnum::Boolean): bool Value;
(PrimitiveTypeEnum::Byte): u8 Value;
(PrimitiveTypeEnum::Char): char Value;
(PrimitiveTypeEnum::Currency): std::error("Primitive currency not used in this protocol");
(PrimitiveTypeEnum::Decimal): Decimal Value;
(PrimitiveTypeEnum::Double): double Value;
(PrimitiveTypeEnum::Int16): s16 Value;
(PrimitiveTypeEnum::Int32): s32 Value;
(PrimitiveTypeEnum::Int64): s64 Value;
(PrimitiveTypeEnum::SByte): s8 Value;
(PrimitiveTypeEnum::Single): float Value;
(PrimitiveTypeEnum::TimeSpan): TimeSpan Value;
(PrimitiveTypeEnum::DateTime): DateTime Value;
(PrimitiveTypeEnum::UInt16): u16 Value;
(PrimitiveTypeEnum::UInt32): u32 Value;
(PrimitiveTypeEnum::UInt64): u64 Value;
(PrimitiveTypeEnum::Null): {}
(PrimitiveTypeEnum::String): LengthPrefixedString Value;
(_): std::error(std::format("Unexpected {}", PrimitiveType));
}
};
struct StringValueWithCode: PrimitiveTypeEnumT<PrimitiveTypeEnum::String>{
LengthPrefixedString StringValue;
};
struct ArrayOfValueWithCode{
s32 Length;
ValueWithCode ListOfValueWithCode[Length];
};
struct ArrayInfo{
s32 ObjectId;
s32 Length;
};
struct ClassInfo{
s32 ObjectId;
LengthPrefixedString Name;
s32 MemberCount;
LengthPrefixedString MemberNames[MemberCount];
};
struct AdditionalInfo<auto _binaryTypeEnum>{
BinaryTypeEnum binaryTypeEnum = _binaryTypeEnum;
match(binaryTypeEnum){
(BinaryTypeEnum::SystemClass): /* ObjectUrt */
LengthPrefixedString String;
(BinaryTypeEnum::Class): /* ObjectUser */
ClassTypeInfo classTypeInfo;
(BinaryTypeEnum::Primitive | BinaryTypeEnum::PrimitiveArray): {
PrimitiveTypeEnum primitiveType;
std::assert(primitiveType != PrimitiveTypeEnum::Null &&
primitiveType != PrimitiveTypeEnum::String, "Must not be Null or String");
}
(BinaryTypeEnum::String | BinaryTypeEnum::Object |
BinaryTypeEnum::ObjectArray | BinaryTypeEnum::StringArray):
{/* not using continue here, need to keep array index matching */}
(_): std::error(std::format("Unrecognized {}", binaryTypeEnum));
}
};
struct MemberTypeInfo<auto MemberCount>{
BinaryTypeEnum binaryTypeEnums[MemberCount];
AdditionalInfo<binaryTypeEnums[std::core::array_index()]> additionalInfo[MemberCount];
};
struct UntypedMember<auto _className, auto classInfo>{
str className = _className;
u64 MemberCount = classInfo.MemberCount;
if(className == "System.Guid" && MemberCount == 11){
match(std::core::array_index()){
(0): s32 _a;
(1): s16 _b;
(2): s16 _c;
(3): u8 _d;
(4): u8 _e;
(5): u8 _f;
(6): u8 _g;
(7): u8 _h;
(8): u8 _i;
(9): u8 _j;
(10): u8 _k;
(_): std::error("unreachable");
}
}else if(MemberCount == 1 && classInfo.MemberNames[0].String == "value__"){
str Name = classInfo.MemberNames[0].String;
s32 member [name(Name)];
}else
std::error(std::format("Unsupported untyped member: {}", className));
};
using Record;
struct Members<auto _Name, auto memberTypeInfo>{
u64 i = std::core::array_index();
str Name = _Name;
BinaryTypeEnum binaryTypeEnum = memberTypeInfo.binaryTypeEnums[i];
if(binaryTypeEnum == BinaryTypeEnum::Primitive){
PrimitiveTypeEnum primitiveTypeEnum = memberTypeInfo.additionalInfo[i].primitiveType;
match(primitiveTypeEnum){
(PrimitiveTypeEnum::Boolean): bool Value [[name(Name)]];
(PrimitiveTypeEnum::Byte): u8 Value [[name(Name)]];
(PrimitiveTypeEnum::Char): char Value [[name(Name)]];
(PrimitiveTypeEnum::Currency): std::error("Primitive currency not used in this protocol");
(PrimitiveTypeEnum::Decimal): Decimal Value [[name(Name)]];
(PrimitiveTypeEnum::Double): double Value [[name(Name)]];
(PrimitiveTypeEnum::Int16): s16 Value [[name(Name)]];
(PrimitiveTypeEnum::Int32): s32 Value [[name(Name)]];
(PrimitiveTypeEnum::Int64): s64 Value [[name(Name)]];
(PrimitiveTypeEnum::SByte): s8 Value [[name(Name)]];
(PrimitiveTypeEnum::Single): float Value [[name(Name)]];
(PrimitiveTypeEnum::TimeSpan): TimeSpan Value [[name(Name)]];
(PrimitiveTypeEnum::DateTime): DateTime Value [[name(Name)]];
(PrimitiveTypeEnum::UInt16): u16 Value [[name(Name)]];
(PrimitiveTypeEnum::UInt32): u32 Value [[name(Name)]];
(PrimitiveTypeEnum::UInt64): u64 Value [[name(Name)]];
(PrimitiveTypeEnum::Null): {}
(PrimitiveTypeEnum::String): LengthPrefixedString Value [[name(Name)]];
(_): std::error(std::format("Unexpected {}", primitiveTypeEnum));
}
}else{
Record record [[name(Name)]];
}
};
struct ClassWithMembersAndTypes: RecordTypeEnumT<RecordTypeEnum::ClassWithMembersAndTypes>{
ClassInfo classInfo;
MemberTypeInfo<classInfo.MemberCount> memberTypeInfo;
s32 LibraryId;
Members<classInfo.MemberNames[std::core::array_index()].String, memberTypeInfo> members[classInfo.MemberCount];
};
struct ClassWithMembers: RecordTypeEnumT<RecordTypeEnum::ClassWithMembers>{
ClassInfo classInfo;
s32 LibraryId;
UntypedMember<classInfo.Name.String, classInfo> members[classInfo.MemberCount];
};
struct SystemClassWithMembersAndTypes: RecordTypeEnumT<RecordTypeEnum::SystemClassWithMembersAndTypes>{
ClassInfo classInfo;
MemberTypeInfo<classInfo.MemberCount> memberTypeInfo;
Members<classInfo.MemberNames[std::core::array_index()].String, memberTypeInfo> members[classInfo.MemberCount];
};
struct SystemClassWithMembers: RecordTypeEnumT<RecordTypeEnum::SystemClassWithMembers>{
ClassInfo classInfo;
UntypedMember<classInfo.Name.String, classInfo> members[classInfo.MemberCount];
};
struct ClassWithId: RecordTypeEnumT<RecordTypeEnum::ClassWithId>{
s32 ObjectId;
s32 MetadataId;
if(!IsUpdatingTrackers && NeedUpdateTrackers){
IsUpdatingTrackers = true;
_Trackers _trackers @ 0x0 in _TrackersSection;
IsUpdatingTrackers = false;
NeedUpdateTrackers = false;
}
match(_trackers.objs[MetadataId].objEnum){
(_ObjEnum::ClassWithMembersAndTypes): {
u32 MemberCount = _trackers.objs[MetadataId].classWithMembersAndTypes.data.classInfo.MemberCount;
Members<_trackers.objs[MetadataId].classWithMembersAndTypes.data.classInfo.MemberNames[std::core::array_index()].String, _trackers.objs[MetadataId].classWithMembersAndTypes.data.memberTypeInfo> members[MemberCount];
}
(_ObjEnum::SystemClassWithMembersAndTypes): {
u32 MemberCount = _trackers.objs[MetadataId].systemClassWithMemberAndTypes.data.classInfo.MemberCount;
Members<_trackers.objs[MetadataId].systemClassWithMemberAndTypes.data.classInfo.MemberNames[std::core::array_index()].String, _trackers.objs[MetadataId].systemClassWithMemberAndTypes.data.memberTypeInfo> members[MemberCount];
}
(_ObjEnum::SystemClassWithMembers): {
str className = _trackers.objs[MetadataId].TypeName.data.String;
u32 MemberCount = _trackers.objs[MetadataId].systemClassWithMembers.data.classInfo.MemberCount;
UntypedMember<className, _trackers.objs[MetadataId].systemClassWithMembers.data.classInfo> members[MemberCount];
}
(_ObjEnum::ClassWithMembers): {
str className = _trackers.objs[MetadataId].TypeName.data.String;
u32 MemberCount = _trackers.objs[MetadataId].classWithMembers.data.classInfo.MemberCount;
UntypedMember<className, _trackers.objs[MetadataId].classWithMembers.data.classInfo> members[MemberCount];
}
(_): std::error(std::format("Unexpected {}", _trackers.objs[MetadataId].objEnum));
}
};
struct BinaryArray: RecordTypeEnumT<RecordTypeEnum::BinaryArray>{
s32 ObjectId;
BinaryArrayTypeEnum binaryArrayTypeEnum;
s32 Rank;
s32 Length[Rank];
if(binaryArrayTypeEnum == BinaryArrayTypeEnum::SingleOffset ||
binaryArrayTypeEnum == BinaryArrayTypeEnum::JaggedOffset ||
binaryArrayTypeEnum == BinaryArrayTypeEnum::RectangularOffset)
s32 LowerBounds[Rank];
BinaryTypeEnum TypeEnum;
AdditionalInfo<TypeEnum> additionalInfo;
};
struct ArraySinglePrimitive: RecordTypeEnumT<RecordTypeEnum::ArraySinglePrimitive>{
ArrayInfo arrayInfo;
PrimitiveTypeEnum primitiveTypeEnum;
std::assert(primitiveTypeEnum != PrimitiveTypeEnum::Null &&
primitiveTypeEnum != PrimitiveTypeEnum::String, "Can't be one of those");
match(primitiveTypeEnum){
(PrimitiveTypeEnum::Boolean): bool Values[arrayInfo.Length];
(PrimitiveTypeEnum::Byte): u8 Value[arrayInfo.Length];
(PrimitiveTypeEnum::Char): char Value[arrayInfo.Length];
(PrimitiveTypeEnum::Currency): std::error("Primitive currency not used in this protocol");
(PrimitiveTypeEnum::Decimal): Decimal Value[arrayInfo.Length];
(PrimitiveTypeEnum::Double): double Value[arrayInfo.Length];
(PrimitiveTypeEnum::Int16): s16 Value[arrayInfo.Length];
(PrimitiveTypeEnum::Int32): s32 Value[arrayInfo.Length];
(PrimitiveTypeEnum::Int64): s64 Value[arrayInfo.Length];
(PrimitiveTypeEnum::SByte): s8 Value[arrayInfo.Length];
(PrimitiveTypeEnum::Single): float Value[arrayInfo.Length];
(PrimitiveTypeEnum::TimeSpan): TimeSpan Value[arrayInfo.Length];
(PrimitiveTypeEnum::DateTime): DateTime Value[arrayInfo.Length];
(PrimitiveTypeEnum::UInt16): u16 Value[arrayInfo.Length];
(PrimitiveTypeEnum::UInt32): u32 Value[arrayInfo.Length];
(PrimitiveTypeEnum::UInt64): u64 Value[arrayInfo.Length];
(PrimitiveTypeEnum::Null): {}
(PrimitiveTypeEnum::String): LengthPrefixedString Value[arrayInfo.Length];
(_): std::error(std::format("Unexpected {}", primitiveTypeEnum));
}
};
u64 ArraySinglElementSkipCount = 0;
struct ArraySingleElement<auto _recordTypeEnum>{
RecordTypeEnum recordTypeEnum = _recordTypeEnum;
if(ArraySinglElementSkipCount > 0)
ArraySinglElementSkipCount -= 1;
else{
if(recordTypeEnum == RecordTypeEnum::ArraySingleString){
Record record [[inline]];
match(record.recordTypeEnum){
(RecordTypeEnum::ObjectNullMultiple):
ArraySinglElementSkipCount = record.objectNullMultiple.NullCount;
(RecordTypeEnum::ObjectNullMultiple256):
ArraySinglElementSkipCount = record.objectNullMultiple256.NullCount;
(_): {}
}
}else{
Record record [[inline]];
if(record.recordTypeEnum == RecordTypeEnum::BinaryLibrary){
Record record2 [[inline]];
match(record2.recordTypeEnum){
(RecordTypeEnum::ObjectNullMultiple):
ArraySinglElementSkipCount = record2.objectNullMultiple.NullCount;
(RecordTypeEnum::ObjectNullMultiple256):
ArraySinglElementSkipCount = record2.objectNullMultiple256.NullCount;
(_): {}
}
}else{
match(record.recordTypeEnum){
(RecordTypeEnum::ObjectNullMultiple):
ArraySinglElementSkipCount = record.objectNullMultiple.NullCount;
(RecordTypeEnum::ObjectNullMultiple256):
ArraySinglElementSkipCount = record.objectNullMultiple256.NullCount;
(_): {}
}
}
}
}
};
struct ArraySingleObject: RecordTypeEnumT<RecordTypeEnum::ArraySingleObject>{
ArrayInfo arrayInfo;
ArraySinglElementSkipCount = 0;
ArraySingleElement<RecordTypeEnum::ArraySingleObject> records[arrayInfo.Length];
};
struct ArraySingleString: RecordTypeEnumT<RecordTypeEnum::ArraySingleString>{
ArrayInfo arrayInfo;
ArraySinglElementSkipCount = 0;
ArraySingleElement<RecordTypeEnum::ArraySingleString> records[arrayInfo.Length];
};
struct MethodReturnCallArray{
if(parent.MessageEnum.ReturnValueInArray)
ArraySingleObject ReturnValue;
if(parent.MessageEnum.ArgsInArray)
ArraySingleObject OutputArguments;
if(parent.MessageEnum.ExceptionInArray)
ArraySingleObject Exception;
if(parent.MessageEnum.ContextInArray)
ArraySingleObject CallContext;
if(parent.MessageEnum.PropertiesInArray)
ArraySingleObject MessageProperties;
};
struct MethodCallArray{
if(parent.MessageEnum.ArgsInArray)
ArraySingleObject InputArguments;
if(parent.MessageEnum.GenericMethod)
ArraySingleObject GenericTypeArguments;
if(parent.MessageEnum.MethodSignatureInArray)
ArraySingleObject MethodSignature;
if(parent.MessageEnum.ContextInArray)
ArraySingleObject CallContext;
if(parent.MessageEnum.PropertiesInArray)
ArraySingleObject MessageProperties;
};
struct BinaryMethodReturn: RecordTypeEnumT<RecordTypeEnum::MethodReturn>{
MessageFlags MessageEnum;
std::assert(validate_MessageFlags(MessageEnum) >= 0, "Validation Failed");
std::assert(!MessageEnum.MethodSignatureInArray && !MessageEnum.GenericMethod, "Can't be one of those");
if(MessageEnum.ReturnValueInline)
ValueWithCode ReturnValue;
if(MessageEnum.ContextInline)
StringValueWithCode CallContext;
if(MessageEnum.ArgsInline)
ArrayOfValueWithCode Args;
MethodReturnCallArray ReturnCallArray;
};
struct BinaryMethodCall: RecordTypeEnumT<RecordTypeEnum::MethodCall>{
MessageFlags MessageEnum;
std::assert(validate_MessageFlags(MessageEnum) >= 0, "Validation Failed");
std::assert(!MessageEnum.NoReturnValue && !MessageEnum.ReturnValueVoid &&
!MessageEnum.ReturnValueInline && !MessageEnum.ReturnValueInArray &&
!MessageEnum.ExceptionInArray, "Can't be one of those");
StringValueWithCode MethodName;
StringValueWithCode TypeName;
if(MessageEnum.ContextInline)
StringValueWithCode CallContext;
if(MessageEnum.ArgsInline)
ArrayOfValueWithCode Args;
MethodCallArray CallArray;
};
struct MemberPrimitiveTyped: RecordTypeEnumT<RecordTypeEnum::MemberPrimitiveTyped>{
PrimitiveTypeEnum primitiveTypeEnum;
std::assert(primitiveTypeEnum != PrimitiveTypeEnum::Null &&
primitiveTypeEnum != PrimitiveTypeEnum::String, "Can't be one of those");
match(primitiveTypeEnum){
(PrimitiveTypeEnum::Boolean): bool Value;
(PrimitiveTypeEnum::Byte): u8 Value;
(PrimitiveTypeEnum::Char): char Value;
(PrimitiveTypeEnum::Currency): std::error("Primitive currency not used in this protocol");
(PrimitiveTypeEnum::Decimal): Decimal Value;
(PrimitiveTypeEnum::Double): double Value;
(PrimitiveTypeEnum::Int16): s16 Value;
(PrimitiveTypeEnum::Int32): s32 Value;
(PrimitiveTypeEnum::Int64): s64 Value;
(PrimitiveTypeEnum::SByte): s8 Value;
(PrimitiveTypeEnum::Single): float Value;
(PrimitiveTypeEnum::TimeSpan): TimeSpan Value;
(PrimitiveTypeEnum::DateTime): DateTime Value;
(PrimitiveTypeEnum::UInt16): u16 Value;
(PrimitiveTypeEnum::UInt32): u32 Value;
(PrimitiveTypeEnum::UInt64): u64 Value;
(_): std::error(std::format("Unexpected {}", primitiveTypeEnum));
}
};
struct MemberPrimitiveUnTyped<auto PrimitiveType>{
match(PrimitiveType){
(PrimitiveTypeEnum::Boolean): bool Value;
(PrimitiveTypeEnum::Byte): u8 Value;
(PrimitiveTypeEnum::Char): char Value;
(PrimitiveTypeEnum::Currency): std::error("Primitive currency not used in this protocol");
(PrimitiveTypeEnum::Decimal): Decimal Value;
(PrimitiveTypeEnum::Double): double Value;
(PrimitiveTypeEnum::Int16): s16 Value;
(PrimitiveTypeEnum::Int32): s32 Value;
(PrimitiveTypeEnum::Int64): s64 Value;
(PrimitiveTypeEnum::SByte): s8 Value;
(PrimitiveTypeEnum::Single): float Value;
(PrimitiveTypeEnum::TimeSpan): TimeSpan Value;
(PrimitiveTypeEnum::DateTime): DateTime Value;
(PrimitiveTypeEnum::UInt16): u16 Value;
(PrimitiveTypeEnum::UInt32): u32 Value;
(PrimitiveTypeEnum::UInt64): u64 Value;
(PrimitiveTypeEnum::Null): {}
(PrimitiveTypeEnum::String):std::error("Can't be String");
(_): std::error(std::format("Unexpected {}", PrimitiveType));
}
};
struct MemberReference: RecordTypeEnumT<RecordTypeEnum::MemberReference>{
s32 IdRef;
};
struct ObjectNull: RecordTypeEnumT<RecordTypeEnum::ObjectNull>{
};
struct ObjectNullMultiple: RecordTypeEnumT<RecordTypeEnum::ObjectNullMultiple>{
s32 NullCount;
};
struct ObjectNullMultiple256: RecordTypeEnumT<RecordTypeEnum::ObjectNullMultiple256>{
u8 NullCount;
};
struct BinaryObjectString: RecordTypeEnumT<RecordTypeEnum::BinaryObjectString>{
s32 ObjectId;
LengthPrefixedString Value;
};
struct SerializationHeaderRecord: RecordTypeEnumT<RecordTypeEnum::SerializedStreamHeader>{
s32 RootId;
s32 HeaderId;
s32 MajorVersion;
std::assert_warn(MajorVersion == 1, "MajorVersion should be 1");
s32 MinorVersion;
std::assert_warn(MinorVersion == 0, "MinorVersion should be 0");
};
struct BinaryLibrary: RecordTypeEnumT<RecordTypeEnum::BinaryLibrary>{
s32 LibraryId;
LengthPrefixedString LibraryName;
};
struct MessageEnd: RecordTypeEnumT<RecordTypeEnum::MessageEnd>{
};
struct CrossAppDomainMap: RecordTypeEnumT<RecordTypeEnum::CrossAppDomainMap>{
s32 crossAppDomainArrayIndex;
};
struct CrossAppDomainString: RecordTypeEnumT<RecordTypeEnum::CrossAppDomainString>{
s32 ObjectId;
s32 Value;
};
struct CrossAppDomainAssembly: RecordTypeEnumT<RecordTypeEnum::CrossAppDomainAssembly>{
s32 LibraryId;
s32 LibraryIndex;
};
struct Record{
RecordTypeEnum recordTypeEnum [[no_unique_address, hidden]];
match(recordTypeEnum){
(RecordTypeEnum::SerializedStreamHeader):
std::error("SerializationStreamHeader can only appear at the top of the document");
(RecordTypeEnum::ClassWithId): { /* RecordTypeEnum::Object */
ClassWithId classWithId;
if(!IsUpdatingTrackers){
zeroedCurrObjTrackers();
_trackers.currentObj.objEnum = _ObjEnum::ClassWithId;
_trackers.currentObj.RawPtr = append_value_to_section(classWithId, _TrackersSection);
_trackers.currentObj.TypeName.pointerValue = _trackers.objs[classWithId.MetadataId].TypeName.pointerValue;
_trackers.currentObj.AssemblyName.pointerValue =_trackers.objs[classWithId.MetadataId].AssemblyName.pointerValue ;
if(classWithId.ObjectId != 0)
copyCurrObjAtIdTrackers(classWithId.ObjectId);
}
}
(RecordTypeEnum::SystemClassWithMembers): { /* RecordTypeEnum::ObjectWithMap */
SystemClassWithMembers systemClassWithMembers;
if(!IsUpdatingTrackers){
zeroedCurrObjTrackers();
_trackers.currentObj.objEnum = _ObjEnum::SystemClassWithMembers;
_trackers.currentObj.RawPtr = append_value_to_section(systemClassWithMembers, _TrackersSection);
_trackers.currentObj.TypeName.pointerValue = _trackers.currentObj.RawPtr + offsetOf(systemClassWithMembers, systemClassWithMembers.classInfo.Name);
if(systemClassWithMembers.classInfo.ObjectId != 0)
copyCurrObjAtIdTrackers(systemClassWithMembers.classInfo.ObjectId);
}
}
(RecordTypeEnum::ClassWithMembers): { /* RecordTypeEnum::ObjectWithMapAssemId */
ClassWithMembers classWithMembers;
if(!IsUpdatingTrackers){
zeroedCurrObjTrackers();
_trackers.currentObj.objEnum = _ObjEnum::ClassWithMembers;
_trackers.currentObj.RawPtr = append_value_to_section(classWithMembers, _TrackersSection);
_trackers.currentObj.TypeName.pointerValue = _trackers.currentObj.RawPtr + offsetOf(classWithMembers, classWithMembers.classInfo.Name);
_trackers.currentObj.AssemblyName.pointerValue = _trackers.libs[classWithMembers.LibraryId].pointerValue;
if(classWithMembers.classInfo.ObjectId != 0)
copyCurrObjAtIdTrackers(classWithMembers.classInfo.ObjectId);
}
}
(RecordTypeEnum::SystemClassWithMembersAndTypes): { /* RecordTypeEnum::ObjectWithMapTyped */
SystemClassWithMembersAndTypes systemClassWithMembersAndTypes;
if(!IsUpdatingTrackers){
zeroedCurrObjTrackers();
_trackers.currentObj.objEnum = _ObjEnum::SystemClassWithMembersAndTypes;
_trackers.currentObj.RawPtr = append_value_to_section(systemClassWithMembersAndTypes, _TrackersSection);
_trackers.currentObj.TypeName.pointerValue = _trackers.currentObj.RawPtr + offsetOf(systemClassWithMembersAndTypes, systemClassWithMembersAndTypes.classInfo.Name);
if(systemClassWithMembersAndTypes.classInfo.ObjectId != 0)
copyCurrObjAtIdTrackers(systemClassWithMembersAndTypes.classInfo.ObjectId);
}
}
(RecordTypeEnum::ClassWithMembersAndTypes): { /* RecordTypeEnum::ObjectWithMapTypedAssemId */
ClassWithMembersAndTypes classWithMembersAndTypes;
if(!IsUpdatingTrackers){
zeroedCurrObjTrackers();
_trackers.currentObj.objEnum = _ObjEnum::ClassWithMembersAndTypes;
_trackers.currentObj.RawPtr = append_value_to_section(classWithMembersAndTypes, _TrackersSection);
_trackers.currentObj.TypeName.pointerValue = _trackers.currentObj.RawPtr + offsetOf(classWithMembersAndTypes, classWithMembersAndTypes.classInfo.Name);
_trackers.currentObj.AssemblyName.pointerValue = _trackers.libs[classWithMembersAndTypes.LibraryId].pointerValue;
if(classWithMembersAndTypes.classInfo.ObjectId != 0)
copyCurrObjAtIdTrackers(classWithMembersAndTypes.classInfo.ObjectId);
}
}
(RecordTypeEnum::BinaryObjectString): { /* RecordTypeEnum::ObjectString */
BinaryObjectString binaryObjectString;
if(!IsUpdatingTrackers){
zeroedCurrObjTrackers();
_trackers.currentObj.objEnum = _ObjEnum::BinaryObjectString;
_trackers.currentObj.RawPtr = append_value_to_section(binaryObjectString, _TrackersSection);
if(binaryObjectString.ObjectId != 0)
copyCurrObjAtIdTrackers(binaryObjectString.ObjectId);
}
}
(RecordTypeEnum::BinaryArray): { /* RecordTypeEnum::Array */
BinaryArray binaryArray;
if(!IsUpdatingTrackers){
zeroedCurrObjTrackers();
_trackers.currentObj.objEnum = _ObjEnum::BinaryArray;
_trackers.currentObj.RawPtr = append_value_to_section(binaryArray, _TrackersSection);
if(binaryArray.ObjectId != 0)
copyCurrObjAtIdTrackers(binaryArray.ObjectId);
}
}
(RecordTypeEnum::MemberPrimitiveTyped): {
MemberPrimitiveTyped memberPrimitiveTyped;
}
(RecordTypeEnum::MemberReference): {
MemberReference memberReference;
}
(RecordTypeEnum::ObjectNull): {}
(RecordTypeEnum::MessageEnd): break;
(RecordTypeEnum::BinaryLibrary): { /* RecordTypeEnum::Assembly */
BinaryLibrary library;
if(!IsUpdatingTrackers)
_trackers.libs[library.LibraryId].pointerValue = append_value_to_section(library.LibraryName, _TrackersSection);
}
(RecordTypeEnum::ObjectNullMultiple256): {
ObjectNullMultiple256 objectNullMultiple256;
}
(RecordTypeEnum::ObjectNullMultiple): {
ObjectNullMultiple objectNullMultiple;
}
(RecordTypeEnum::ArraySinglePrimitive): {
ArraySinglePrimitive arraySinglePrimitive;
if(!IsUpdatingTrackers){
zeroedCurrObjTrackers();
_trackers.currentObj.objEnum = _ObjEnum::ArraySinglePrimitive;
_trackers.currentObj.RawPtr = append_value_to_section(arraySinglePrimitive, _TrackersSection);
if(arraySinglePrimitive.arrayInfo.ObjectId != 0)
copyCurrObjAtIdTrackers(arraySinglePrimitive.arrayInfo.ObjectId);
}
}
(RecordTypeEnum::ArraySingleObject): {
ArraySingleObject arraySingleObject;
}
(RecordTypeEnum::ArraySingleString): {
ArraySingleString arraySingleString;
}
(RecordTypeEnum::CrossAppDomainMap):
CrossAppDomainMap crossAppDomainMap;
(RecordTypeEnum::CrossAppDomainString):
CrossAppDomainString crossAppDomainString;
(RecordTypeEnum::CrossAppDomainAssembly):
CrossAppDomainAssembly crossAppDomainAssembly;
(RecordTypeEnum::MethodCall): {
BinaryMethodCall binaryMethodCall;
}
(RecordTypeEnum::MethodReturn): {
BinaryMethodReturn binaryMethodReturn;
}
(_): std::error(std::format("Unrecognized {}", recordTypeEnum));
}
};
struct DotNetBinnaryFormatter{
SerializationHeaderRecord Header;
Record records[while(std::mem::read_unsigned($, 1) != RecordTypeEnum::MessageEnd)];
MessageEnd End;
if(!IsUpdatingTrackers && NeedUpdateTrackers){
IsUpdatingTrackers = true;
_Trackers _trackers @ 0x0 in _TrackersSection;
IsUpdatingTrackers = false;
NeedUpdateTrackers = false;
}
};
struct _ObjTracker{
_Ptr<LengthPrefixedString, u64> TypeName;
_Ptr<LengthPrefixedString, u64> AssemblyName;
_ObjEnum objEnum;
u64 RawPtr [[no_unique_address]];
/* Only enable the one we actually use to avoid significant slow down */
match(objEnum){
(_ObjEnum::Empty):
u64 ptr;
/*
(_ObjEnum::ClassWithId): // _ObjEnum::Object
_Ptr<ClassWithId, u64> classWithId;
*/
(_ObjEnum::SystemClassWithMembers): // _ObjEnum::ObjectWithMap
_Ptr<SystemClassWithMembers, u64> systemClassWithMembers;
(_ObjEnum::ClassWithMembers): // _ObjEnum::ObjectWithMapAssemId
_Ptr<ClassWithMembers, u64> classWithMembers;
(_ObjEnum::SystemClassWithMembersAndTypes): // _ObjEnum::ObjectWithMapTyped
_Ptr<SystemClassWithMembersAndTypes, u64> systemClassWithMemberAndTypes;
(_ObjEnum::ClassWithMembersAndTypes): // _ObjEnum::ObjectWithMapTypedAssemId
_Ptr<ClassWithMembersAndTypes, u64> classWithMembersAndTypes;
/*
(_ObjEnum::BinaryObjectString): // _ObjEnum::ObjectString
_Ptr<BinaryObjectString, u64> binaryObjectString;
(_ObjEnum::BinaryArray): // _ObjEnum::Array
_Ptr<BinaryArray, u64> binaryArray;
(_ObjEnum::MemberPrimitiveTyped):
_Ptr<MemberPrimitiveTyped, u64> memberPrimitiveTyped;
(_ObjEnum::MemberReference):
_Ptr<MemberReference, u64> memberReference;
(_ObjEnum::BinaryLibrary): // _ObjEnum::Assembly
_Ptr<BinaryLibrary, u64> library;
(_ObjEnum::ObjectNullMultiple256):
_Ptr<ObjectNullMultiple256, u64> objectNullMultiple256;
(_ObjEnum::ObjectNullMultiple):
_Ptr<ObjectNullMultiple, u64> objectNullMultiple;
(_ObjEnum::ArraySinglePrimitive):
_Ptr<ArraySinglePrimitive, u64> arraySinglePrimitive;
(_ObjEnum::ArraySingleObject):
_Ptr<ArraySingleObject, u64> arraySingleObject;
(_ObjEnum::ArraySingleString):
_Ptr<ArraySingleString, u64> arraySingleString;
(_ObjEnum::CrossAppDomainMap):
_Ptr<CrossAppDomainMap, u64> crossAppDomainMap;
(_ObjEnum::CrossAppDomainString):
_Ptr<CrossAppDomainString, u64> crossAppDomainString;
(_ObjEnum::CrossAppDomainAssembly):
_Ptr<CrossAppDomainAssembly, u64> crossAppDomainAssembly;
(_ObjEnum::MethodCall):
_Ptr<BinaryMethodCall, u64> binaryMethodCall;
(_ObjEnum::MethodReturn):
_Ptr<BinaryMethodReturn, u64> binaryMethodReturn;
*/
(_): u64 ptr; //std::error(std::format("Unexpected {}", objEnum));
}
};
/* Should be an In variable with default non zero value in the future until we use a hash map */
#define _OBJECTS_TRACKER_CNT 232
#define _LIBRARIES_CNT 8
struct _Trackers{
_ObjTracker currentObj;
/* TODO: this should really be an hash map, the algorithm that generated is unspecified */
_ObjTracker objs[_OBJECTS_TRACKER_CNT];
_Ptr<LengthPrefixedString, u64> libs[_LIBRARIES_CNT];
};
std::mem::set_section_size(_TrackersSection, sizeof(_trackers));
DotNetBinnaryFormatter dotNetBinnaryFormatter @ 0x0;

View File

@@ -1,4 +1,5 @@
#pragma description macOS .DS_Store
#pragma magic [ 42 75 64 31 ] @ 0x04
// Apple macOS .DS_Store format
#pragma endian big

View File

@@ -1,6 +1,8 @@
#pragma description Digital Terrain Elevation Data
#pragma endian big
#pragma magic [ 4C 48 55 ] @ 0x00
import std.core;
import std.io;
import std.mem;

View File

@@ -473,9 +473,37 @@ bitfield SYMINFO_FLG {
padding : 10;
};
enum STT : u32 {
STT_NOTYPE = 0, /* Symbol type is unspecified */
STT_OBJECT = 1, /* Symbol is a data object */
STT_FUNC = 2, /* Symbol is a code object */
STT_SECTION = 3, /* Symbol associated with a section */
STT_FILE = 4, /* Symbol's name is file name */
STT_COMMON = 5, /* Symbol is a common data object */
STT_TLS = 6, /* Symbol is thread-local data object */
STT_NUM = 7, /* Number of defined types. */
STT_LOOS = 10, /* Start of OS-specific */
STT_GNU_IFUNC = 10, /* Symbol is indirect code object */
STT_HIOS = 12, /* End of OS-specific */
STT_LOPROC = 13, /* Start of processor-specific */
STT_HIPROC = 15, /* End of processor-specific */
};
enum STB : u32 {
STB_LOCAL = 0, /* Local symbol */
STB_GLOBAL = 1, /* Global symbol */
STB_WEAK = 2, /* Weak symbol */
STB_NUM = 3, /* Number of defined types. */
STB_LOOS = 10, /* Start of OS-specific */
STB_GNU_UNIQUE = 10, /* Unique symbol. */
STB_HIOS = 12, /* End of OS-specific */
STB_LOPROC = 13, /* Start of processor-specific */
STB_HIPROC = 15, /* End of processor-specific */
};
bitfield ST {
ST_BIND : 4;
ST_TYPE : 4;
STB ST_BIND : 4;
STT ST_TYPE : 4;
} [[bitfield_order(BitfieldOrder::MostToLeastSignificant, 8)]];
bitfield SHF {
@@ -497,14 +525,15 @@ bitfield SHF {
};
bitfield ELF32_R_INFO {
SYM : 8;
TYPE : 8;
} [[bitfield_order(BitfieldOrder::MostToLeastSignificant, 16)]];
TYPE : 8;
SYM : 8;
padding : 16;
} [[bitfield_order(BitfieldOrder::LeastToMostSignificant, 32)]];
bitfield ELF64_R_INFO {
SYM : 32;
TYPE : 32;
} [[bitfield_order(BitfieldOrder::MostToLeastSignificant, 64)]];
SYM : 32;
} [[bitfield_order(BitfieldOrder::LeastToMostSignificant, 64)]];
bitfield PF {
X : 1;
@@ -643,9 +672,12 @@ struct Elf32_Shdr {
// Section has no data
} else if (sh_type == SHT::STRTAB) {
String stringTable[while($ < (sh_offset + sh_size))] @ sh_offset;
stringTableIndex = std::core::array_index();
} else if (sh_type == SHT::SYMTAB || sh_type == SHT::DYNSYM) {
Elf32_Sym symbolTable[sh_size / sh_entsize] @ sh_offset;
} else if (sh_type == SHT::REL) {
Elf32_Rel relTable[sh_size / sh_entsize] @ sh_offset;
} else if (sh_type == SHT::RELA) {
Elf32_Rela relaTable[sh_size / sh_entsize] @ sh_offset;
} else if (sh_type == SHT::INIT_ARRAY || sh_type == SHT::FINI_ARRAY) {
u32 pointer[while($ < (sh_offset + sh_size))] @ sh_offset;
} else {
@@ -703,9 +735,12 @@ struct Elf64_Shdr {
// Section has no data
} else if (sh_type == SHT::STRTAB) {
String stringTable[while($ < (sh_offset + sh_size))] @ sh_offset;
stringTableIndex = std::core::array_index();
} else if (sh_type == SHT::SYMTAB || sh_type == SHT::DYNSYM) {
Elf64_Sym symbolTable[sh_size / sh_entsize] @ sh_offset;
} else if (sh_type == SHT::REL) {
Elf64_Rel relTable[sh_size / sh_entsize] @ sh_offset;
} else if (sh_type == SHT::RELA) {
Elf64_Rela relaTable[sh_size / sh_entsize] @ sh_offset;
} else if (sh_type == SHT::INIT_ARRAY || sh_type == SHT::FINI_ARRAY) {
u32 pointer[while($ < (sh_offset + sh_size))] @ sh_offset;
} else {
@@ -734,17 +769,24 @@ struct ELF {
if (e_ident.EI_CLASS == EI_CLASS::ELFCLASS32) {
Elf32_Ehdr ehdr;
stringTableIndex = ehdr.e_shstrndx;
Elf32_Phdr phdr[ehdr.e_phnum] @ ehdr.e_phoff;
Elf32_Shdr shdr[ehdr.e_shnum] @ ehdr.e_shoff;
} else if (e_ident.EI_CLASS == EI_CLASS::ELFCLASS64) {
Elf64_Ehdr ehdr;
stringTableIndex = ehdr.e_shstrndx;
Elf64_Phdr phdr[ehdr.e_phnum] @ ehdr.e_phoff;
Elf64_Shdr shdr[ehdr.e_shnum] @ ehdr.e_shoff;
}
};
ELF elf @ 0x00;
EI_DATA endian @ 0x05 [[hidden]];
match (endian) {
(EI_DATA::ELFDATA2LSB): std::core::set_endian(std::mem::Endian::Little);
(EI_DATA::ELFDATA2MSB): std::core::set_endian(std::mem::Endian::Big);
(_): std::core::set_endian(std::mem::Endian::Native);
}
fn gen_shdr_disp_name(ref auto pattern, str member_name, u8 member_index) {
return std::format(

119
patterns/esp32_image.hexpat Normal file
View File

@@ -0,0 +1,119 @@
#pragma author timschneeb
#pragma description ESP32 Firmware Image Format
#pragma endian little
// Reference: https://docs.espressif.com/projects/esp-idf/en/stable/esp32/api-reference/system/app_image_format.html
import std.mem;
enum esp_chip_id_t : u16 {
ESP_CHIP_ID_ESP32 = 0x0000,
ESP_CHIP_ID_ESP32S2 = 0x0002,
ESP_CHIP_ID_ESP32C3 = 0x0005,
ESP_CHIP_ID_ESP32S3 = 0x0009,
ESP_CHIP_ID_ESP32C2 = 0x000C,
ESP_CHIP_ID_ESP32C6 = 0x000D,
ESP_CHIP_ID_ESP32H2 = 0x0010,
ESP_CHIP_ID_ESP32P4 = 0x0012,
ESP_CHIP_ID_ESP32C5 = 0x0017,
ESP_CHIP_ID_ESP32C61 = 0x0014,
ESP_CHIP_ID_ESP32H21 = 0x0019,
ESP_CHIP_ID_ESP32H4 = 0x001C,
ESP_CHIP_ID_INVALID = 0xFFFF
};
enum esp_image_spi_mode_t : u8 {
QIO,
QOUT,
DIO,
DOUT,
FAST_READ,
SLOW_READ
};
enum esp_image_spi_freq_t : u8 {
DIV_2,
DIV_3,
DIV_4,
DIV_1 = 0xF
};
enum esp_image_flash_size_t : u8 {
FLASH_1MB,
FLASH_2MB,
FLASH_4MB,
FLASH_8MB,
FLASH_16MB,
FLASH_32MB,
FLASH_64MB,
FLASH_128MB,
FLASH_MAX
};
bitfield spi_config_t {
esp_image_spi_freq_t spi_speed : 4;
esp_image_flash_size_t spi_size : 4;
};
const u32 ESP_APP_DESC_MAGIC_WORD = 0xABCD5432;
struct esp_app_desc_t {
u32 magic_word; // ESP_APP_DESC_MAGIC_WORD
u32 secure_version;
u32 reserv1[2];
char version[32];
char project_name[32];
char compile_time[16];
char compile_date[16];
char idf_ver[32];
u8 app_elf_sha256[32];
u16 min_efuse_blk_rev_full;
u16 max_efuse_blk_rev_full;
u8 mmu_page_size; // in log2 format
u8 reserv3[3];
u32 reserv2[18];
};
struct esp_image_header_t {
u8 magic; // 0xE9
u8 segment_count;
esp_image_spi_mode_t spi_mode;
spi_config_t spi_cfg;
u32 entry_addr;
u8 wp_pin [[comment("Write protect pin")]];
u8 spi_pin_drv[3] [[comment("Drive settings for the SPI flash pins")]];
esp_chip_id_t chip_id;
u8 min_chip_rev [[comment("Deprecated, replaced by min_chip_rev_full")]];
u16 min_chip_rev_full [[comment("Minimal revision (major*100+minor)")]];
u16 max_chip_rev_full [[comment("Maximal revision (major*100+minor)")]];
u8 reserved[4];
u8 hash_appended [[comment("If 1, a SHA256 digest 'simple hash' (of the entire image) is appended after the checksum")]];
};
struct esp_image_segment_header_t {
u32 load_addr;
u32 data_len;
};
union esp_image_segment_data_t {
u8 data[parent.header.data_len] [[hidden]];
// Application segment
if (std::mem::read_unsigned(addressof(data), 4) == ESP_APP_DESC_MAGIC_WORD) {
esp_app_desc_t app_descriptor;
}
};
struct esp_image_segment_t {
esp_image_segment_header_t header;
esp_image_segment_data_t data;
};
struct esp_image_t {
esp_image_header_t header;
esp_image_segment_t segments[header.segment_count];
};
esp_image_t image @ 0x0;

View File

@@ -1,5 +1,5 @@
#pragma description MS Windows Vista Event Log
#pragma MIME application/x-ms-evtx
#pragma endian little
struct Header {

View File

@@ -1,25 +1,25 @@
#pragma author DmitriLeon2000
#pragma description Oska Software DeskMates FAS (Frames and Sequences) file
#pragma description Oska Software DeskMates FAS (Frames and Sequences)
#pragma endian little
enum Compression : u32 {
BI_RGB,
BI_RLE8,
BI_RLE4,
BI_BITFIELDS,
BI_JPEG,
BI_PNG,
BI_ALPHABITFIELDS,
BI_CMYK,
BI_CMYKRLE8,
BI_CMYKRLE4,
BI_RGB,
BI_RLE8,
BI_RLE4,
BI_BITFIELDS,
BI_JPEG,
BI_PNG,
BI_ALPHABITFIELDS,
BI_CMYK,
BI_CMYKRLE8,
BI_CMYKRLE4,
};
struct Colors {
u8 blue;
u8 green;
u8 red;
u8 reserved;
u8 blue;
u8 green;
u8 red;
u8 reserved;
};
struct FASHeader {
@@ -69,7 +69,7 @@ struct SeqHeader {
};
struct Bitmap {
u8 byte[fas.fasHeader.version >= 3 ? fas.fasHeader.frameSize + (fas.frameSizeHigh << 16) : fas.fasHeader.frameSize];
u8 byte[parent.fasHeader.version >= 3 ? parent.fasHeader.frameSize + (parent.frameSizeHigh << 16) : parent.fasHeader.frameSize] [[sealed]];
};
struct FramesHeader {
@@ -105,7 +105,7 @@ struct FAS {
u8 filenameChecksum; // a checksum for a filename in ASCII
AnimSequence sequences[seqHeader.count];
FramesHeader framesHeader;
Bitmap framesBitmap[framesHeader.count];
};
FAS fas @ 0x00;
Bitmap framesBitmap[fas.framesHeader.count] @ $;

View File

@@ -1,25 +1,25 @@
#pragma author DmitriLeon2000
#pragma description Oska Software DeskMates FAS (Frames and Sequences) file (Oska DeskMate versions 1.3 and 2.06)
#pragma description Oska Software DeskMates FAS (Frames and Sequences) (Oska DeskMate 1.03 and 2.06)
#pragma endian little
enum Compression : u32 {
BI_RGB,
BI_RLE8,
BI_RLE4,
BI_BITFIELDS,
BI_JPEG,
BI_PNG,
BI_ALPHABITFIELDS,
BI_CMYK,
BI_CMYKRLE8,
BI_CMYKRLE4,
BI_RGB,
BI_RLE8,
BI_RLE4,
BI_BITFIELDS,
BI_JPEG,
BI_PNG,
BI_ALPHABITFIELDS,
BI_CMYK,
BI_CMYKRLE8,
BI_CMYKRLE4,
};
struct Colors {
u8 blue;
u8 green;
u8 red;
u8 reserved;
u8 blue;
u8 green;
u8 red;
u8 reserved;
};
struct FASHeader {
@@ -59,14 +59,14 @@ struct AnimSequence {
};
struct SeqHeader {
le u32 size;
le u32 count;
le u32 strPointers[count*2];
le u32 size;
le u32 count;
le u32 strPointers[count*2];
};
struct Frame {
u8 colorBitmap[fas.fasHeader.frameSizeColor];
u8 maskBitmap[fas.fasHeader.frameSizeMask];
u8 colorBitmap[parent.fasHeader.frameSizeColor] [[sealed]];
u8 maskBitmap[parent.fasHeader.frameSizeMask] [[sealed]];
};
struct FramesHeader {
@@ -80,8 +80,7 @@ struct FAS {
SeqHeader seqHeader;
AnimSequence sequences[seqHeader.count];
FramesHeader framesHeader;
Frame frames[framesHeader.count];
};
FAS fas @ 0x00;
Frame frames[fas.framesHeader.count] @ $;

View File

@@ -1,5 +1,6 @@
#pragma author WerWolv
#pragma description Flat Linux Device Tree blob
#pragma magic [ D0 0D FE ED ] @ 0x00
#pragma endian big

View File

@@ -1,5 +1,6 @@
#pragma author WerWolv
#pragma description Free Lossless Audio Codec, FLAC Audio Format
#pragma MIME audio/flac
import std.sys;
import std.core;

268
patterns/flc.hexpat Normal file
View File

@@ -0,0 +1,268 @@
#pragma description FLC/FLIC animation file
#pragma endian little
#pragma magic [12 AF] @ 0x4
// A flic file could contain many DELTA_FLC chunks, which contain many RLE packets
//#define DECODE_DELTA_FLC
import std.mem;
import std.core;
import std.io;
import type.color;
using Color = type::RGB8 [[hex::inline_visualize("color", r, g, b, 0xff)]];
bitfield Color64 {
r : 6;
padding : 2;
g : 6;
padding : 2;
b : 6;
padding : 2;
u8 r8 = r << 2 | r >> 4;
u8 g8 = g << 2 | g >> 4;
u8 b8 = b << 2 | b >> 4;
} [[hex::inline_visualize("color", r8, g8, b8, 0xff)]];
enum FlicType : u16 {
FLI = 0xAF11,
FLC_8bit = 0xAF12,
FLIC_other = 0xAF44,
FLIC_Huffmann = 0xAF30,
FLIC_frame_shift = 0xAF31,
};
enum ChunkType : u16 {
CEL_DATA = 3, // Registration and transparency
COLOR_256 = 4, // 256-level colour palette
DELTA_FLC = 7, // Delta image, word oriented RLE (FLI_SS2)
COLOR_64 = 11, // 64-level colour palette
DELTA_FLI = 12, // Delta image, byte oriented RLE (FLI_LC)
BLACK = 13, // Full black frame (rare)
BYTE_RUN = 15, // Full image, byte oriented RLE (FLI_BRUN)
FLI_COPY = 16, // Uncompressed image (rare)
PSTAMP = 18, // Postage stamp (icon of the first frame)
DTA_BRUN = 25, // Full image, pixel oriented RLE
DTA_COPY = 26, // Uncompressed image
DTA_LC = 27, // Delta image, pixel oriented RLE
LABEL = 31, // Frame label
BMP_MASK = 32, // Bitmap mask
MLEV_MASK = 33, // Multilevel mask
SEGMENT = 34, // Segment information
KEY_IMAGE = 35, // Key image, similar to BYTE_RUN / DTA_BRUN
KEY_PAL = 36, // Key palette, similar to COLOR_256
REGION = 37, // Region of frame differences
WAVE = 38, // Digitized audio
USERSTRING = 39, // General purpose user data
RGN_MASK = 40, // Region mask
LABELEX = 41, // Extended frame label (includes symbolic name)
SHIFT = 42, // Scanline delta shifts (compression)
PATHMAP = 43, // Path map (segment transitions)
PREFIX_TYPE = 0xF100, // Prefix chunk
SCRIPT_CHUNK = 0xF1E0, // Embedded "Small" script
FRAME_TYPE = 0xF1FA, // Frame chunk
SEGMENT_TABLE = 0xF1FB, // Segment table chunk
HUFFMAN_TABLE = 0xF1FC // Huffman compression table chunk
};
bitfield ExtFlags {
segment_table_present : 1;
regular_key_imagees : 1;
identical_palette : 1;
huffmann_compressed : 1;
bwt_huffmann_compressed : 1;
bitmap_masks_present : 1;
multilevel_masks_present : 1;
region_data_present : 1;
password_protected : 1;
digitized_audio : 1;
contains_script : 1;
region_masks_present : 1;
contains_overlays : 1;
frame_shift_compressed : 1;
padding : 2;
};
u16 pixels_per_line = 0;
u16 lines = 0;
struct Header {
u32 size [[comment("Size of FLIC including this header")]];
FlicType type [[comment("File type 0xAF11, 0xAF12, 0xAF30, 0xAF44, ...")]];
u16 frames [[comment("Number of frames in first segment")]];
u16 width [[comment("FLIC width in pixels")]];
u16 height [[comment("FLIC height in pixels")]];
u16 depth [[comment("Bits per pixel (usually 8)")]];
u16 flags [[comment("Set to zero or to three")]];
u32 speed [[comment("Delay between frames")]];
u16 reserved1 [[comment("Set to zero")]];
u32 created [[comment("Date of FLIC creation (FLC only)")]];
u32 creator [[comment("Serial number or compiler id (FLC only)")]];
u32 updated [[comment("Date of FLIC update (FLC only)")]];
u32 updater [[comment("Serial number (FLC only), see creator")]];
u16 aspect_dx [[comment("Width of square rectangle (FLC only)")]];
u16 aspect_dy [[comment("Height of square rectangle (FLC only)")]];
ExtFlags ext_flags [[comment("EGI: flags for specific EGI extensions")]];
u16 keyframes [[comment("EGI: key-image frequency")]];
u16 totalframes [[comment("EGI: total number of frames (segments)")]];
u32 req_memory [[comment("EGI: maximum chunk size (uncompressed)")]];
u16 max_regions [[comment("EGI: max. number of regions in a CHK_REGION chunk")]];
u16 transp_num [[comment("EGI: number of transparent levels")]];
u8 reserved2[24] [[comment("Set to zero")]];
u32 oframe1 [[comment("Offset to frame 1 (FLC only)")]];
u32 oframe2 [[comment("Offset to frame 2 (FLC only)")]];
u8 reserved3[40] [[comment("Set to zero")]];
pixels_per_line = width;
lines = height;
};
namespace DeltaFLCChunk {
enum OpcodeType : u8 {
Count = 0b00,
Undefined = 0b01,
LowByte = 0b10,
LineSkipCount = 0b11,
};
struct Packet {
u8 skip_count;
s8 count;
if (count < 0) {
u8 replicate_bytes[2];
} else {
u8 literal_bytes[count * 2];
}
};
u16 packets_in_line;
fn format_opcode(auto opcode) {
match (opcode.type) {
(OpcodeType::Count): return std::format("Packet(s): {0}", opcode.value);
(OpcodeType::Undefined): return "Undefined";
(OpcodeType::LowByte): return std::format("Last byte: {0:02x}", opcode.value);
(OpcodeType::LineSkipCount): {
s16 total = 0xC000 | opcode.value;
return std::format("Lines skipped: {0}", total);
}
}
};
bitfield Opcode {
value: 14;
OpcodeType type: 2;
if (type == OpcodeType::Count) {
packets_in_line = value;
break;
}
} [[format("DeltaFLCChunk::format_opcode")]];
struct Line {
packets_in_line = 0;
Opcode opcodes[while(true)];
Packet packets[packets_in_line];
};
}
namespace ByteRunChunk {
u16 pixels_in_line_counter = 0;
struct Packet {
s8 count;
if (count < 0) {
pixels_in_line_counter = -count + pixels_in_line_counter;
u8 literal_bytes[-count];
} else {
pixels_in_line_counter = count + pixels_in_line_counter;
u8 replicate_byte;
}
} [[format("format_byte_run_packet")]];
struct Line {
pixels_in_line_counter = 0;
u8 packet_count;
Packet packets[while(pixels_in_line_counter < pixels_per_line)];
};
}
struct ColorPalettePacket<C> {
u8 skip;
u8 copy;
if (copy == 0) {
C color[256];
} else {
C color[copy];
}
};
fn format_chunk(auto chunk) {
return std::format("{}", chunk.type);
};
fn format_byte_run_packet(auto packet) {
if (packet.count == -1) {
return std::format("One {}", packet.literal_bytes[0]);
} else if (packet.count < 0) {
return std::format("{} bytes", -packet.count);
} else {
return std::format("{}x color {}", packet.count, packet.replicate_byte);
}
};
struct Chunk {
u32 size;
ChunkType type;
if (type == ChunkType::FRAME_TYPE) {
u16 chunks;
u16 delay;
u16 reserved;
u16 width;
u16 height;
// Not sure if this is the intended operation here?
if (width > 0) {
pixels_per_line = width;
}
if (height > 0) {
lines = height;
}
Chunk subchunks[chunks];
} else if (type == ChunkType::COLOR_256) {
u16 num_packets;
ColorPalettePacket<Color> packets[num_packets];
} else if (type == ChunkType::COLOR_64) {
u16 num_packets;
ColorPalettePacket<Color64> packets[num_packets];
} else if (type == ChunkType::BYTE_RUN) {
ByteRunChunk::Line lines[lines];
} else if (type == ChunkType::DELTA_FLC) {
u16 line_count;
#ifdef DECODE_DELTA_FLC
DeltaFLCChunk::Line lines[line_count];
#endif
#ifndef DECODE_DELTA_FLC
u8 data[size - ($ - addressof(this))];
#endif
} else if (type == ChunkType::PSTAMP) {
u16 height;
u16 width;
u16 xlate;
u8 data[size - ($ - addressof(this))];
} else if (type == ChunkType::FLI_COPY) {
u8 pixels[lines * pixels_per_line];
}
s128 remainingBytes = size - ($ - addressof(this));
// When the chunk size is rounded up to the next even number, it might need a padding byte.
// Unrecognized chunk types will also fill out the padding
if (remainingBytes > 0) {
padding[size - ($ - addressof(this))];
} else if (remainingBytes < 0) {
std::warning("Chunk size wasn't large enough");
}
} [[format("format_chunk")]];
Header header @ $;
Chunk chunks[while(!std::mem::eof())] @ $;

224
patterns/flv.hexpat Normal file
View File

@@ -0,0 +1,224 @@
#pragma author ZN123 version 1.0
#pragma description flv Archive
#pragma MIME video/x-flv
#pragma magic [46 4C 56] @ 0x00
// zn123@sina.com
// https://veovera.org/docs/enhanced/enhanced-rtmp-v2#flv-file-format-overview
import std.io;
import type.base;
import std.mem;
import std.math;
import std.string;
#pragma endian big
#pragma pattern_limit 2000000
enum TypeB:u24{
flvSignature = 0x564C46, // Defining flv signature
};
#define FLV_HEADER_FLAG_HASVIDEO 1
#define FLV_HEADER_FLAG_HASAUDIO 4
struct FLVHeader {
char signature[3] [[color("FF0000")] ];
u8 version [[color("00FF00")]];
u8 stream_info [[color("0000FF")]]; //si->missing_streams = flags & (FLV_HEADER_FLAG_HASVIDEO | FLV_HEADER_FLAG_HASAUDIO);
if (stream_info & FLV_HEADER_FLAG_HASVIDEO)
std::print("HAS VIDEO");
if (stream_info & FLV_HEADER_FLAG_HASAUDIO)
std::print("HAS AUDIO");
u32 head_size [[color("FFFF00")]];
u32 previous_tag_size [[comment("away 0")]];
};
enum FLV_TAG_TYPE : u8 {
FLV_TAG_TYPE_AUDIO = 8,
FLV_TAG_TYPE_VIDEO = 9,
FLV_TAG_TYPE_META = 18
};
#define FLV_AUDIO_CODECID_MASK 0xf0
#define FLV_VIDEO_CODECID_MASK 0x0f
#define FLV_VIDEO_FRAMETYPE_MASK 0x70
#define FLV_VIDEO_FRAMETYPE_OFFSET 4
// type = (avio_r8(s->pb) & 0x1F);
// dts = avio_rb24(s->pb);
// dts |= (unsigned)avio_r8(s->pb) << 24;
struct BaseTag{
// if (std::mem::eof()) break;
u8 TagType;
u24 offset [[comment("offset+11 = taglen")]];
u24 Timestamp;
u8 TimestampExtended;
u24 StreamID [[comment("away 0")]];
// std::print("TagType= {}",TagType & 0x1F );
// std::print("offset= {}",offset + 11);
// std::print("dts={},{}, {}",Timestamp,TimestampExtended,Timestamp + (TimestampExtended<<3));
};
enum AMFDataType:u8 {
AMF_DATA_TYPE_NUMBER = 0x00,
AMF_DATA_TYPE_BOOL = 0x01,
AMF_DATA_TYPE_STRING = 0x02,
AMF_DATA_TYPE_OBJECT = 0x03,
AMF_DATA_TYPE_NULL = 0x05,
AMF_DATA_TYPE_UNDEFINED = 0x06,
AMF_DATA_TYPE_REFERENCE = 0x07,
AMF_DATA_TYPE_MIXEDARRAY = 0x08,
AMF_DATA_TYPE_OBJECT_END = 0x09,
AMF_DATA_TYPE_ARRAY = 0x0a,
AMF_DATA_TYPE_DATE = 0x0b,
AMF_DATA_TYPE_LONG_STRING = 0x0c,
AMF_DATA_TYPE_UNSUPPORTED = 0x0d,
};
#define TYPE_ONTEXTDATA 1
#define TYPE_ONCAPTION 2
#define TYPE_ONCAPTIONINFO 3
#define TYPE_UNKNOWN 9
fn flv_read_metabody(auto offset){
u8 flags = std::mem::read_unsigned($ , 1, std::mem::Endian::Big);
u64 startOffset = $;
u64 endOffset = $ + offset;
std::print("metabody {},{}",startOffset,endOffset);
if (flags != AMFDataType::AMF_DATA_TYPE_STRING){
return TYPE_UNKNOWN;
}
u16 len = std::mem::read_unsigned($+1 , 2, std::mem::Endian::Big);
if (len > endOffset) return 0;
str name = std::mem::read_string($+3,len);
std::print("AMF_DATA_TYPE_STRING {} {}",len,name);
if (std::string::contains(name, "onMetaData")) {
std::print("onMetaData");
} else if (std::string::contains(name, "onTextData")) {
std::print("onTextData");
} else if (std::string::contains(name, "onCaption")) {
std::print("onCaption");
} else if (std::string::contains(name, "onCaptionInfo")) {
std::print("onCaptionInfo");
} else if (std::string::contains(name, "onTextData")) {
std::print("onTextData");
} else {
std::error("Invalid DataEntryBox");
}
return flags;
};
/***
//#define FLV_AUDIO_CODECID_OFFSET 4
enum FLV_CODECID:u8{
FLV_CODECID_PCM = 0,
FLV_CODECID_ADPCM = 1 ,
FLV_CODECID_MP3 = 2 ,
FLV_CODECID_PCM_LE = 3 ,
FLV_CODECID_NELLYMOSER_16KHZ_MONO = 4 ,
FLV_CODECID_NELLYMOSER_8KHZ_MONO = 5 ,
FLV_CODECID_NELLYMOSER = 6 ,
FLV_CODECID_PCM_ALAW = 7 ,
FLV_CODECID_PCM_MULAW = 8 ,
FLV_CODECID_OPUS = 9 ,//china//1001
FLV_CODECID_AAC = 10,//1010
FLV_CODECID_SPEEX = 11,//11<< FLV_AUDIO_CODECID_OFFSET,1011
};
***/
bitfield FLVTagAudio_flags {
audio_codecid : 4;
sample_rate : 2; //3:44100 2:22k 1:11 0:5.5 [AAC away 3]
channels : 1 [[format("format_channels")]]; //0 mono ,1 stereo [AAC away 1]
bits_per_coded_sample : 1; //0 8bit,1 16bit
} [[inline]];
fn format_channels(u8 value) {
return value;
};
struct FLVTagAudio{
FLVTagAudio_flags flags;
u8 data[parent.offset-1] [[sealed]];
};
/***
enum FrameType:u8{
FLV_FRAME_KEY = 1 , ///< key frame (for AVC, a seekable frame) 001
FLV_FRAME_INTER = 2 , ///< inter frame (for AVC, a non-seekable frame) 010
FLV_FRAME_DISP_INTER = 3 , ///< disposable inter frame (H.263 only) 011
FLV_FRAME_GENERATED_KEY = 4 , ///< generated key frame (reserved for server use only) 100
FLV_FRAME_VIDEO_INFO_CMD = 5 , ///< video info/command frame 101
};
enum {
FLV_CODECID_H263 = 2,
FLV_CODECID_SCREEN = 3,
FLV_CODECID_VP6 = 4,
FLV_CODECID_VP6A = 5,
FLV_CODECID_SCREEN2 = 6,
FLV_CODECID_H264 = 7,
FLV_CODECID_REALH263= 8,
FLV_CODECID_MPEG4 = 9,
FLV_CODECID_HEVC = 12, //china
FLV_CODECID_AV1 = 13, //china
FLV_CODECID_VP8 = 14, //china
FLV_CODECID_VP9 = 15, //china
};
enum {
PacketTypeSequenceStart = 0,
PacketTypeCodedFrames = 1,
PacketTypeSequenceEnd = 2,
PacketTypeCodedFramesX = 3,
PacketTypeMetadata = 4,
PacketTypeMPEG2TSSequenceStart = 5,
};
***/
bitfield FLVTagVideo_flags {
enhanced_flv : 1;
FrameType : 3;
video_codecid : 4;
} [[inline]];
bitfield FLVTagVideoEXT_flags {
enhanced_flv : 1;
FrameType : 3;
PacketType : 4;
} [[inline]];
struct FLVTagVideo{
FLVTagVideo_flags flags;
u8 PacketType;
u8 data[parent.offset-1-1] [[sealed]];
};
struct FLVTagVideoExt{
FLVTagVideoEXT_flags flags;
char video_codecid[4];
u8 data[parent.offset-1-4] [[sealed]];
};
struct FLVTag: BaseTag{
try {
u8 type =(TagType & 0x1F);
if (type == FLV_TAG_TYPE::FLV_TAG_TYPE_META){
std::print("___FLV_TAG_TYPE::FLV_TAG_TYPE_META");
// flv_read_metabody(offset);
u8 data[offset] [[sealed]];
}else if (type == FLV_TAG_TYPE::FLV_TAG_TYPE_VIDEO){
u8 ext = std::mem::read_unsigned($ , 1, std::mem::Endian::Big);
ext = (ext & 0x80) >> 7;
if (ext == 1){
FLVTagVideoExt tagVideoExt;
}else{
FLVTagVideo tagVideo;
}
}else if (type == FLV_TAG_TYPE::FLV_TAG_TYPE_AUDIO){
//u8 data[offset] [[sealed]];
FLVTagAudio tagAudio;
}else{
std::print("___FLV_TAG_TYPE::UNKOWN");
u8 data[offset] [[sealed]];
}
u32 previous_tag_size;
} catch {
std::warning("Invalid sample payload at chunk");
break;
}
} [[name(std::format("FLVTag({})", TagType))]];
struct FLV {
FLVHeader flvheader;
FLVTag flvtag[while(!std::mem::eof())];
};
FLV flv @ 0x00 [[inline]];

View File

@@ -1,5 +1,6 @@
#pragma author WerWolv
#pragma description Drive File System
#pragma MIME application/x-ima
import std.io;
import std.core;

1479
patterns/fs/apfs.hexpat Normal file

File diff suppressed because it is too large Load Diff

311
patterns/fs/exfat.hexpat Normal file
View File

@@ -0,0 +1,311 @@
#pragma magic [45 58 46 41 54 20 20 20] @ 0x03
#pragma description Extensible File Allocation Table (exFAT)
#pragma author Khoo Hao Yit
import std.mem;
import std.string;
import std.core;
#pragma eval_depth 0
struct BootSector {
std::mem::Bytes<3> jumpBoot;
char fileSystemName[8];
std::mem::Bytes<53> mustBeZero;
u64 partitionOffset;
u64 volumeLength;
u32 fatOffset;
u32 fatLength;
u32 clusterHeapOffset;
u32 clusterCount;
u32 firstClusterOfRootDirectory;
u32 volumeSerialNumber;
u16 fileSystemRevision;
u16 volumeFlags;
u8 bytesPerSectorShift;
u8 sectorsPerClusterShift;
u8 numberOfFats;
u8 driveSelect;
u8 percentInUse;
std::mem::Bytes<7> reserved;
std::mem::Bytes<390> bootCode;
std::mem::Bytes<2> bootSignature;
};
struct ExtendedBootSector {
std::mem::Bytes<bytesPerSector - 4> bootCode;
std::mem::Bytes<4> bootSignature;
};
struct Parameter {
std::mem::Bytes<16> guid;
std::mem::Bytes<32> data;
};
struct OemParameter {
Parameter parameters[10];
std::mem::Bytes<bytesPerSector - 480> reserved;
};
u64 bytesPerSector;
u64 startOfClusterHeap;
u64 bytesPerCluster;
u64 fatAddress;
struct BootRegion {
BootSector bootSector;
bytesPerSector = 1 << bootSector.bytesPerSectorShift;
bytesPerCluster = bytesPerSector << bootSector.sectorsPerClusterShift;
ExtendedBootSector extendedBootSectors[8];
OemParameter oemParameter;
std::mem::Bytes<bytesPerSector> reservedSector;
std::mem::Bytes<bytesPerSector> bootChecksum;
};
struct VolumeLabelEntry {
u8 entryType;
u8 characterCount;
char volumeLabel[22];
std::mem::Bytes<8> reserved;
};
bitfield FileAttribute {
readOnly : 1;
hidden : 1;
system : 1;
reserved : 1;
directory : 1;
archive : 1;
reserved1 : 10;
};
auto currentClusterIndex = -1;
auto currentClusterSize = -1;
auto currentIsDirectory = -1;
struct FileEntry {
u8 entryType;
u8 secondayEntryCount;
u16 checksum;
FileAttribute attributes;
std::mem::Bytes<2> reserved;
u32 creationDatetime;
u32 modificationDatetime;
u32 accessDatetime;
u8 creationTimeHundredths;
u8 modificationTimeHundredths;
u8 creationUtcOffset;
u8 modificationUtcOffset;
u8 accessUtcOffset;
std::mem::Bytes<7> reserved1;
currentIsDirectory = attributes.directory;
};
bitfield GeneralSecondaryFlags {
allocationPossible : 1;
noFatChain : 1;
customDefined : 6;
};
struct FileNameEntry {
u8 entryType;
u8 flags;
char16 name[15];
};
fn divideCeil(auto a, auto b) {
auto result = a / b;
auto remain = a % b;
if (remain) {
result += 1;
}
return result;
};
struct ContinuousFatRange<auto ClusterIndex, auto ClusterSize> {
u32 fatRange[ClusterSize] @ fatAddress + ClusterIndex * 4 [[sealed]];
} [[name(std::format("ContinuousFatRange<{}, {}>", ClusterIndex, ClusterSize))]];
struct FatChain {
auto clusterIndex = currentClusterIndex;
auto clusterSize = currentClusterSize;
currentClusterIndex = -1;
currentClusterSize = -1;
if (clusterIndex == -1) {
std::error(std::format("Invalid cluster index: {}", clusterIndex));
}
if (clusterSize == -1) {
auto startingFatRange = fatAddress + clusterIndex * 4;
u32 clusters[while(
$ == startingFatRange
|| $ == fatAddress + std::mem::read_unsigned($ - 4, 4) * 4
)] @ startingFatRange [[hidden]];
clusterSize = std::core::member_count(clusters);
}
ContinuousFatRange<clusterIndex, clusterSize> data @ 0;
try {
auto nextClusterIndex = clusters[clusterSize - 1];
if (nextClusterIndex != 0xffffffff && nextClusterIndex != 0) {
currentClusterIndex = nextClusterIndex;
FatChain next @ 0 [[inline]];
}
}
} [[name(std::format("FatChain<{}>", clusterIndex))]];
struct ContinuousDataRange<auto ClusterIndex, auto ClusterSize> {
std::mem::Bytes<ClusterSize * bytesPerCluster> dataRange @
startOfClusterHeap + ClusterIndex * bytesPerCluster;
} [[name(std::format("ContinuousDataRange<{}, {}>", ClusterIndex, ClusterSize))]];
struct DataChain {
auto clusterIndex = currentClusterIndex;
auto clusterSize = currentClusterSize;
currentClusterIndex = -1;
currentClusterSize = -1;
if (clusterIndex == -1) {
std::error(std::format("Invalid cluster index: {}", clusterIndex));
}
if (clusterSize == -1) {
auto startingFatRange = fatAddress + clusterIndex * 4;
u32 clusters[while(
$ == startingFatRange
|| $ == fatAddress + std::mem::read_unsigned($ - 4, 4) * 4
)] @ startingFatRange [[hidden]];
clusterSize = std::core::member_count(clusters);
}
ContinuousDataRange<clusterIndex, clusterSize> data @ 0;
try {
auto nextClusterIndex = clusters[clusterSize - 1];
if (nextClusterIndex != 0xffffffff && nextClusterIndex != 0) {
currentClusterIndex = nextClusterIndex;
DataChain next @ 0 [[inline]];
}
}
} [[name(std::format("DataChain<{}>", clusterIndex))]];
struct UpcaseTableEntry {
u8 entryType;
std::mem::Bytes<3> reserved;
u32 tableChecksum;
std::mem::Bytes<12> reserved1;
u32 firstCluster;
u64 dataLength;
ContinuousFatRange<firstCluster, 1> fatRange;
ContinuousDataRange<firstCluster, 1> dataRange;
};
struct AllocationBitmapEntry {
u8 entryType;
u8 bitmapFlags;
std::mem::Bytes<18> reserved;
u32 firstCluster;
u64 dataLength;
ContinuousFatRange<firstCluster, 1> fatRange;
ContinuousDataRange<firstCluster, 1> dataRange;
};
using StreamExtensionEntry;
struct DirectoryEntry {
u8 entryType @ addressof(this) [[hidden]];
match (entryType) {
(0x83 | 0x03): VolumeLabelEntry;
(0x81): AllocationBitmapEntry;
(0x82): UpcaseTableEntry;
(0x85 | 0x05): FileEntry;
(0xc0 | 0x40): StreamExtensionEntry;
(0xc1 | 0x41): FileNameEntry;
(_): std::mem::Bytes<32> [[name(std::format("UnknownEntry @ {:#X}", addressof(this)))]];
}
} [[inline]];
struct ContinuousDirectoryEntry<auto ClusterIndex, auto ClusterSize> {
DirectoryEntry entry[ClusterSize * bytesPerCluster / 32] @
startOfClusterHeap + ClusterIndex * bytesPerCluster
[[inline]];
} [[name(std::format("ContinuousDirectoryEntry<{}, {}>", ClusterIndex, ClusterSize))]];
struct DirectoryEntryChain {
auto clusterIndex = currentClusterIndex;
auto clusterSize = currentClusterSize;
currentClusterIndex = -1;
currentClusterSize = -1;
if (clusterIndex == -1) {
std::error(std::format("Invalid cluster index: {}", clusterIndex));
}
if (clusterSize == -1) {
auto startingFatRange = fatAddress + clusterIndex * 4;
u32 clusters[while(
$ == startingFatRange
|| $ == fatAddress + std::mem::read_unsigned($ - 4, 4) * 4
)] @ startingFatRange [[hidden]];
clusterSize = std::core::member_count(clusters);
}
ContinuousDirectoryEntry<clusterIndex, clusterSize> data @ 0;
try {
auto nextClusterIndex = clusters[clusterSize - 1];
if (nextClusterIndex != 0xffffffff && nextClusterIndex != 0) {
currentClusterIndex = nextClusterIndex;
DirectoryEntryChain next @ 0 [[inline]];
}
}
currentIsDirectory = -1;
} [[name(std::format("DirectoryEntryChain<{}>", clusterIndex))]];
struct StreamExtensionEntry {
u8 entryType;
GeneralSecondaryFlags secondaryFlags;
std::mem::Bytes<1> reserved;
u8 nameLength;
u16 nameHash;
std::mem::Bytes<2> reserved1;
u64 validDateLength;
std::mem::Bytes<4> reserved2;
u32 firstCluster;
u64 dataLength;
if (entryType & 0x80 && currentIsDirectory == 1) {
currentClusterIndex = firstCluster;
if (secondaryFlags.noFatChain) {
currentClusterSize = divideCeil(dataLength, bytesPerCluster);
}
FatChain fatChain;
currentClusterIndex = firstCluster;
if (secondaryFlags.noFatChain) {
currentClusterSize = divideCeil(dataLength, bytesPerCluster);
}
DirectoryEntryChain directoryChain;
}
else if (dataLength) {
currentClusterIndex = firstCluster;
if (secondaryFlags.noFatChain) {
currentClusterSize = divideCeil(dataLength, bytesPerCluster);
}
FatChain fatChain;
currentClusterIndex = firstCluster;
if (secondaryFlags.noFatChain) {
currentClusterSize = divideCeil(dataLength, bytesPerCluster);
}
DataChain data @ 0;
}
};
BootRegion bootRegion @ 0 [[name("BootRegion")]];
BootRegion backupBootRegion @ 12 * bytesPerSector [[name("BackupBootRegion")]];
startOfClusterHeap =
bootRegion.bootSector.clusterHeapOffset * bytesPerSector
- 2 * bytesPerCluster;
fatAddress =
bootRegion.bootSector.fatOffset * bytesPerSector;
std::mem::Bytes<bootRegion.bootSector.fatLength * bytesPerSector> fat @ fatAddress [[hidden]];
currentClusterIndex = bootRegion.bootSector.firstClusterOfRootDirectory;
FatChain rootDirectoryFatChain @ 0;
currentClusterIndex = bootRegion.bootSector.firstClusterOfRootDirectory;
DirectoryEntryChain rootDirectory @ 0;

View File

@@ -8,7 +8,7 @@
#pragma endian little
#pragma magic [53 EF] @ 0x438
#pragma pattern_limit 0x90000
#pragma pattern_limit 0x80000000
import type.time;
import type.size;
@@ -540,4 +540,4 @@ struct ext4_group_descriptors {
}
};
ext4_group_descriptors group_descs @ block_to_address(2);
ext4_group_descriptors group_descs @ block_to_address(super_block.s_first_data_block + 1);

108
patterns/fs/fat32.hexpat Normal file
View File

@@ -0,0 +1,108 @@
import std.core;
u64 bytesPerCluster;
struct FSInfo {
u32 leadSignature;
padding[480];
u32 structSignature;
u32 freeClusterCount;
u32 nextFreeCluster;
padding[12];
u32 trailSignature;
};
bitfield SequenceNumber {
padding : 1;
lastLogical : 1;
padding : 1;
number : 5;
} [[bitfield_order(std::core::BitfieldOrder::MostToLeastSignificant, 8)]];
enum EntryStatus : u8 {
Regular = 0x00,
DotEntry = 0x2E,
DeletedEntry = 0xE5
};
union EntryStatusOrSequenceNumber {
EntryStatus entryStatus;
SequenceNumber sequenceNumber;
};
bitfield Attributes {
readOnly : 1;
hidden : 1;
systemFile : 1;
volumeLabel : 1;
subdirectory : 1;
archive : 1;
padding : 2;
} [[bitfield_order(std::core::BitfieldOrder::LeastToMostSignificant, 8)]];
struct DirEntry {
char fileName[8];
char extension[3];
Attributes attributes;
u8 reserved[10];
u16 time, date;
u16 startingCluster;
u32 fileSize;
u8 data[fileSize] @ startingCluster * bytesPerCluster;
};
struct VFATDirEntry {
EntryStatusOrSequenceNumber entryStatusOrSequenceNumber;
char16 name1[5];
Attributes attributes;
u8 type;
u8 nameChecksum;
char16 name2[6];
u16 startingCluster;
char16 name3[2];
if (entryStatusOrSequenceNumber.sequenceNumber.number > 1)
VFATDirEntry nextLogicalEntry;
else
DirEntry physicalEntry;
};
struct FAT32 {
u8 jmpCode[3];
char oemName[8];
u16 bytesPerSector;
u8 sectorsPerCluster;
u16 reservedAreaSize;
u8 numFats;
u16 rootEntryCount;
u16 numSectors;
u8 mediaType;
u16 fatSize;
u16 sectorsPerTrack;
u16 numHeads;
u32 numHiddenSectors;
u32 numFsSectors;
u32 numFatSectors;
u16 extFlags;
u16 fsVersion;
u32 rootCluster;
u16 fsInfoSector;
u16 backupBootSector;
padding[12];
u8 driveNumber;
padding[1];
u8 bootSignature;
u32 volumeID;
char volumeLabel[11];
char fsType[8];
u8 bootstrapCode[420];
u16 signature;
bytesPerCluster = (sectorsPerCluster * 1024) * bytesPerSector;
FSInfo fsInfo @ addressof(this) + fsInfoSector * bytesPerSector;
VFATDirEntry rootDirEntry @ addressof(this) + rootCluster * bytesPerCluster;
};
FAT32 fat32 @ 0x00;

997
patterns/fs/ntfs.hexpat Normal file
View File

@@ -0,0 +1,997 @@
#pragma author Hrant Tadevosyan (Axcient, now ConnectWise)
#pragma description NT File System (NTFS)
#pragma endian little
// refs:
// - https://github.com/libyal/libfsntfs
// - https://github.com/tuxera/ntfs-3g
import std.core;
import std.array;
import std.ptr;
import std.io;
import std.mem;
import type.magic;
using ntfschar = u16;
using leVCN = u64;
using leLCN = u64;
using leLSN = u64;
using leMFT_REF = u64;
struct GUID {
u32 Data1;
u16 Data2;
u16 Data3;
u8 Data4[8];
} [[static]];
bitfield RUNLIST_HEADER {
unsigned offset : 4;
unsigned length : 4;
} [[bitfield_order(std::core::BitfieldOrder::MostToLeastSignificant, 8)]];
struct RUNLIST {
RUNLIST_HEADER header;
u8 count[header.length];
u8 lcn[header.offset];
if (header.length == 0)
break;
};
struct BIOS_PARAMETER_BLOCK {
u16 bytes_per_sector;
u8 sectors_per_cluster;
u16 reserved_sectors;
u8 fats;
u16 root_entries;
u16 sectors;
u8 media_type;
u16 sectors_per_fat;
u16 sectors_per_track;
u16 heads;
u32 hidden_sectors;
u32 large_sectors;
};
enum NTFS_RECORD_TYPES : u32 {
magic_FILE = 0x454c4946,
magic_INDX = 0x58444e49,
magic_HOLE = 0x454c4f48,
magic_RSTR = 0x52545352,
magic_RCRD = 0x44524352,
magic_CHKD = 0x444b4843,
magic_BAAD = 0x44414142,
magic_empty = 0xffffffff,
};
struct NTFS_RECORD {
NTFS_RECORD_TYPES magic;
u16 usa_ofs;
u16 usa_count;
};
enum MFT_RECORD_FLAGS : u16 {
MFT_RECORD_IN_USE = 0x0001,
MFT_RECORD_IS_DIRECTORY = 0x0002,
MFT_RECORD_IS_4 = 0x0004,
MFT_RECORD_IS_VIEW_INDEX = 0x0008,
MFT_REC_SPACE_FILLER = 0xffff,
};
enum ATTR_TYPES : u32 {
AT_UNUSED = 0,
AT_STANDARD_INFORMATION = 0x10,
AT_ATTRIBUTE_LIST = 0x20,
AT_FILE_NAME = 0x30,
AT_OBJECT_ID = 0x40,
AT_SECURITY_DESCRIPTOR = 0x50,
AT_VOLUME_NAME = 0x60,
AT_VOLUME_INFORMATION = 0x70,
AT_DATA = 0x80,
AT_INDEX_ROOT = 0x90,
AT_INDEX_ALLOCATION = 0xa0,
AT_BITMAP = 0xb0,
AT_REPARSE_POINT = 0xc0,
AT_EA_INFORMATION = 0xd0,
AT_EA = 0xe0,
AT_PROPERTY_SET = 0xf0,
AT_LOGGED_UTILITY_STREAM = 0x100,
AT_FIRST_USER_DEFINED_ATTRIBUTE = 0x1000,
AT_END = 0xffffffff,
};
enum ATTR_DEF_FLAGS : u32 {
ATTR_DEF_INDEXABLE = 0x02,
ATTR_DEF_MULTIPLE = 0x04,
ATTR_DEF_NOT_ZERO = 0x08,
ATTR_DEF_INDEXED_UNIQUE = 0x10,
ATTR_DEF_NAMED_UNIQUE = 0x20,
ATTR_DEF_RESIDENT = 0x40,
ATTR_DEF_ALWAYS_LOG = 0x80,
};
enum COLLATION_RULES : u32 {
COLLATION_BINARY = 0,
COLLATION_FILE_NAME = 1,
COLLATION_UNICODE_STRING = 2,
COLLATION_NTOFS_ULONG = 16,
COLLATION_NTOFS_SID = 17,
COLLATION_NTOFS_SECURITY_HASH = 18,
COLLATION_NTOFS_ULONGS = 19,
};
struct ATTR_DEF {
ntfschar name[0x40];
ATTR_TYPES type;
u32 display_rule;
COLLATION_RULES collation_rule;
ATTR_DEF_FLAGS flags;
u64 min_size;
u64 max_size;
};
enum ATTR_FLAGS : u16 {
ATTR_IS_COMPRESSED = 0x0001,
ATTR_COMPRESSION_MASK = 0x00ff,
ATTR_IS_ENCRYPTED = 0x4000,
ATTR_IS_SPARSE = 0x8000,
};
enum RESIDENT_ATTR_FLAGS : u8 {
RESIDENT_ATTR_IS_INDEXED = 0x01
};
enum FILE_ATTR_FLAGS : u32 {
FILE_ATTR_READONLY = 0x00000001,
FILE_ATTR_HIDDEN = 0x00000002,
FILE_ATTR_SYSTEM = 0x00000004,
FILE_ATTR_DIRECTORY = 0x00000010,
FILE_ATTR_ARCHIVE = 0x00000020,
FILE_ATTR_DEVICE = 0x00000040,
FILE_ATTR_NORMAL = 0x00000080,
FILE_ATTR_TEMPORARY = 0x00000100,
FILE_ATTR_SPARSE_FILE = 0x00000200,
FILE_ATTR_REPARSE_POINT = 0x00000400,
FILE_ATTR_COMPRESSED = 0x00000800,
FILE_ATTR_OFFLINE = 0x00001000,
FILE_ATTR_NOT_CONTENT_INDEXED = 0x00002000,
FILE_ATTR_ENCRYPTED = 0x00004000,
FILE_ATTRIBUTE_RECALL_ON_OPEN = 0x00040000,
FILE_ATTR_VALID_FLAGS = 0x00047fb7,
FILE_ATTR_VALID_SET_FLAGS = 0x000031a7,
FILE_ATTR_I30_INDEX_PRESENT = 0x10000000,
FILE_ATTR_VIEW_INDEX_PRESENT = 0x20000000,
};
enum FILE_NAME_TYPE_FLAGS : u8 {
FILE_NAME_POSIX = 0x00,
FILE_NAME_WIN32 = 0x01,
FILE_NAME_DOS = 0x02,
FILE_NAME_WIN32_AND_DOS = 0x03,
};
struct STANDARD_INFORMATION_HEADER {
u64 creation_time;
u64 last_data_change_time;
u64 last_mft_change_time;
u64 last_access_time;
FILE_ATTR_FLAGS file_attributes;
} [[static]];
struct STANDARD_INFORMATION_OLD {
STANDARD_INFORMATION_HEADER header [[inline]];
u8 reserved12[12];
} [[static]];
struct STANDARD_INFORMATION {
STANDARD_INFORMATION_HEADER header [[inline]];
u32 maximum_versions;
u32 version_number;
u32 class_id;
u32 owner_id;
u32 security_id;
u64 quota_charged;
u64 usn;
} [[static]];
struct FILE_NAME_ATTR_PACKED {
u16 packed_ea_size;
u16 reserved;
} [[static]];
union FILE_NAME_ATTR_FORM {
FILE_NAME_ATTR_PACKED packed [[inline]];
u32 reparse_point_tag;
} [[static]];
struct FILE_NAME_ATTR {
leMFT_REF parent_directory;
u64 creation_time;
u64 last_data_change_time;
u64 last_mft_change_time;
u64 last_access_time;
u64 allocated_size;
u64 data_size;
FILE_ATTR_FLAGS file_attributes;
FILE_NAME_ATTR_FORM form [[inline]];
u8 file_name_length;
FILE_NAME_TYPE_FLAGS file_name_type;
ntfschar file_name[file_name_length];
};
struct OBJECT_ID_ATTR_INFO {
GUID birth_volume_id;
GUID birth_object_id;
GUID domain_id;
};
union OBJECT_ID_ATTR_FORM {
OBJECT_ID_ATTR_INFO info [[inline]];
u8 extended_info[48];
};
struct OBJECT_ID_ATTR {
GUID object_id;
OBJECT_ID_ATTR_FORM form [[inline]];
};
enum VOLUME_FLAGS : u16 {
VOLUME_IS_DIRTY = 0x0001,
VOLUME_RESIZE_LOG_FILE = 0x0002,
VOLUME_UPGRADE_ON_MOUNT = 0x0004,
VOLUME_MOUNTED_ON_NT4 = 0x0008,
VOLUME_DELETE_USN_UNDERWAY = 0x0010,
VOLUME_REPAIR_OBJECT_ID = 0x0020,
VOLUME_CHKDSK_UNDERWAY = 0x4000,
VOLUME_MODIFIED_BY_CHKDSK = 0x8000,
VOLUME_FLAGS_MASK = 0xc03f,
};
struct VOLUME_INFORMATION {
u64 reserved;
u8 major_ver;
u8 minor_ver;
VOLUME_FLAGS flags;
} [[static]];
enum SECURITY_DESCRIPTOR_CONTROL : u16 {
SE_OWNER_DEFAULTED = 0x0001,
SE_GROUP_DEFAULTED = 0x0002,
SE_DACL_PRESENT = 0x0004,
SE_DACL_DEFAULTED = 0x0008,
SE_SACL_PRESENT = 0x0010,
SE_SACL_DEFAULTED = 0x0020,
SE_DACL_AUTO_INHERIT_REQ = 0x0100,
SE_SACL_AUTO_INHERIT_REQ = 0x0200,
SE_DACL_AUTO_INHERITED = 0x0400,
SE_SACL_AUTO_INHERITED = 0x0800,
SE_DACL_PROTECTED = 0x1000,
SE_SACL_PROTECTED = 0x2000,
SE_RM_CONTROL_VALID = 0x4000,
SE_SELF_RELATIVE = 0x8000,
};
enum ACE_TYPES : u8 {
ACCESS_MIN_MS_ACE_TYPE = 0,
ACCESS_ALLOWED_ACE_TYPE = 0,
ACCESS_DENIED_ACE_TYPE = 1,
SYSTEM_AUDIT_ACE_TYPE = 2,
SYSTEM_ALARM_ACE_TYPE = 3,
ACCESS_MAX_MS_V2_ACE_TYPE = 3,
ACCESS_ALLOWED_COMPOUND_ACE_TYPE = 4,
ACCESS_MAX_MS_V3_ACE_TYPE = 4,
ACCESS_MIN_MS_OBJECT_ACE_TYPE = 5,
ACCESS_ALLOWED_OBJECT_ACE_TYPE = 5,
ACCESS_DENIED_OBJECT_ACE_TYPE = 6,
SYSTEM_AUDIT_OBJECT_ACE_TYPE = 7,
SYSTEM_ALARM_OBJECT_ACE_TYPE = 8,
ACCESS_MAX_MS_OBJECT_ACE_TYPE = 8,
ACCESS_MAX_MS_V4_ACE_TYPE = 8,
ACCESS_MAX_MS_ACE_TYPE = 8,
ACCESS_ALLOWED_CALLBACK_ACE_TYPE = 9,
ACCESS_DENIED_CALLBACK_ACE_TYPE = 10,
ACCESS_ALLOWED_CALLBACK_OBJECT_ACE_TYPE = 11,
ACCESS_DENIED_CALLBACK_OBJECT_ACE_TYPE = 12,
SYSTEM_AUDIT_CALLBACK_ACE_TYPE = 13,
SYSTEM_ALARM_CALLBACK_ACE_TYPE = 14,
SYSTEM_AUDIT_CALLBACK_OBJECT_ACE_TYPE = 15,
SYSTEM_ALARM_CALLBACK_OBJECT_ACE_TYPE = 16,
SYSTEM_MANDATORY_LABEL_ACE_TYPE = 17,
SYSTEM_RESOURCE_ATTRIBUTE_ACE_TYPE = 18,
SYSTEM_SCOPED_POLICY_ID_ACE_TYPE = 19,
SYSTEM_PROCESS_TRUST_LABEL_ACE_TYPE = 20,
};
enum ACE_FLAGS : u8 {
OBJECT_INHERIT_ACE = 0x01,
CONTAINER_INHERIT_ACE = 0x02,
NO_PROPAGATE_INHERIT_ACE = 0x04,
INHERIT_ONLY_ACE = 0x08,
INHERITED_ACE = 0x10,
VALID_INHERIT_FLAGS = 0x1f,
SUCCESSFUL_ACCESS_ACE_FLAG = 0x40,
FAILED_ACCESS_ACE_FLAG = 0x80,
};
struct ACE_HEADER {
ACE_TYPES type;
ACE_FLAGS flags;
u16 size;
};
struct SID {
u8 revision;
u8 sub_authority_count;
u8 identifier_authority[6];
u32 sub_authority[sub_authority_count];
};
enum ACCESS_MASK : u32 {
FILE_READ_DATA = 0x00000001,
FILE_LIST_DIRECTORY = 0x00000001,
FILE_WRITE_DATA = 0x00000002,
FILE_ADD_FILE = 0x00000002,
FILE_APPEND_DATA = 0x00000004,
FILE_ADD_SUBDIRECTORY = 0x00000004,
FILE_READ_EA = 0x00000008,
FILE_WRITE_EA = 0x00000010,
FILE_EXECUTE = 0x00000020,
FILE_TRAVERSE = 0x00000020,
FILE_DELETE_CHILD = 0x00000040,
FILE_READ_ATTRIBUTES = 0x00000080,
FILE_WRITE_ATTRIBUTES = 0x00000100,
DELETE = 0x00010000,
READ_CONTROL = 0x00020000,
WRITE_DAC = 0x00040000,
WRITE_OWNER = 0x00080000,
SYNCHRONIZE = 0x00100000,
STANDARD_RIGHTS_READ = 0x00020000,
STANDARD_RIGHTS_WRITE = 0x00020000,
STANDARD_RIGHTS_EXECUTE = 0x00020000,
STANDARD_RIGHTS_REQUIRED = 0x000f0000,
STANDARD_RIGHTS_ALL = 0x001f0000,
ACCESS_SYSTEM_SECURITY = 0x01000000,
MAXIMUM_ALLOWED = 0x02000000,
GENERIC_ALL = 0x10000000,
GENERIC_EXECUTE = 0x20000000,
GENERIC_WRITE = 0x40000000,
GENERIC_READ = 0x80000000,
};
struct ACCESS_ALLOWED_ACE {
ACE_HEADER header [[inline]];
ACCESS_MASK mask;
SID sid;
};
using ACCESS_DENIED_ACE = ACCESS_ALLOWED_ACE;
using SYSTEM_ALARM_ACE = ACCESS_ALLOWED_ACE;
using SYSTEM_AUDIT_ACE = ACCESS_ALLOWED_ACE;
enum OBJECT_ACE_FLAGS : u32 {
ACE_OBJECT_TYPE_PRESENT = 1,
ACE_INHERITED_OBJECT_TYPE_PRESENT = 2,
};
struct ACCESS_ALLOWED_OBJECT_ACE {
ACE_HEADER header [[inline]];
ACCESS_MASK mask;
OBJECT_ACE_FLAGS object_flags;
GUID object_type;
GUID inherited_object_type;
SID sid;
};
using ACCESS_DENIED_OBJECT_ACE = ACCESS_ALLOWED_OBJECT_ACE;
using SYSTEM_AUDIT_OBJECT_ACE = ACCESS_ALLOWED_OBJECT_ACE;
using SYSTEM_ALARM_OBJECT_ACE = ACCESS_ALLOWED_OBJECT_ACE;
struct ACL {
u8 revision;
u8 alignment1;
u16 size;
u16 ace_count;
u16 alignment2;
std::mem::AlignTo<4>;
padding[size];
std::mem::AlignTo<4>;
};
#define SECURITY_DESCRIPTOR_RELATIVE_SIZE (20)
struct SECURITY_DESCRIPTOR_RELATIVE {
u32 struct_start = $;
u8 revision;
u8 alignment;
u16 control; // SECURITY_DESCRIPTOR_CONTROL
u32 owner;
u32 group;
u32 sacl;
u32 dacl;
if (owner > 0) {
u32 owner_bytes = $ - struct_start;
if (owner > owner_bytes) {
padding[owner - owner_bytes];
}
SID owner_sid;
}
if (group > 0) {
u32 group_bytes = $ - struct_start;
if (group > group_bytes) {
padding[group - group_bytes];
}
SID group_sid;
}
if (control & SECURITY_DESCRIPTOR_CONTROL::SE_SACL_PRESENT) {
u32 sacl_bytes = $ - struct_start;
if (sacl > sacl_bytes) {
padding[sacl - sacl_bytes];
ACL acl;
}
}
if (control & SECURITY_DESCRIPTOR_CONTROL::SE_DACL_PRESENT) {
u32 dacl_bytes = $ - struct_start;
if (dacl > dacl_bytes) {
padding[dacl - dacl_bytes];
ACL acl;
}
}
};
enum INDEX_HEADER_FLAGS : u8 {
SMALL_INDEX = 0,
LARGE_INDEX = 1,
LEAF_NODE = 0,
INDEX_NODE = 1,
NODE_MASK = 1,
};
struct INDEX_HEADER {
u32 entries_offset;
u32 index_length;
u32 allocated_size;
INDEX_HEADER_FLAGS ih_flags;
u8 reserved[3];
};
struct REPARSE_INDEX_KEY {
u32 reparse_tag;
leMFT_REF file_id;
};
struct SDS_ENTRY {
u32 hash;
u32 security_id;
u64 offset;
u32 length;
SECURITY_DESCRIPTOR_RELATIVE sid;
};
using SII_INDEX_KEY = u32 ;
struct SDH_INDEX_KEY {
u32 hash;
u32 security_id;
};
enum INDEX_ENTRY_FLAGS : u16 {
INDEX_ENTRY_NODE = 1,
INDEX_ENTRY_END = 2,
INDEX_ENTRY_SPACE_FILLER = 0xffff,
};
struct INDEX_ENTR_HEADER_PTR {
u16 data_offset;
u16 data_length;
u32 reservedV;
};
union INDEX_ENTR_HEADER_REF {
leMFT_REF indexed_file;
INDEX_ENTR_HEADER_PTR ptr;
};
struct INDEX_ENTRY_HEADER {
INDEX_ENTR_HEADER_REF file_ref;
u16 length;
u16 key_length;
u16 flags; // INDEX_ENTRY_FLAGS
u16 reserved;
};
struct INDEX_ENTRY_FILE_NAME {
INDEX_ENTRY_HEADER header;
if (!(header.flags & INDEX_ENTRY_FLAGS::INDEX_ENTRY_END)) {
FILE_NAME_ATTR key;
}
if (header.flags & INDEX_ENTRY_FLAGS::INDEX_ENTRY_NODE) {
leVCN vcn;
}
std::mem::AlignTo<8>;
};
struct INDEX_ENTRY_SII {
INDEX_ENTRY_HEADER header;
if (!(header.flags & INDEX_ENTRY_FLAGS::INDEX_ENTRY_END)) {
SII_INDEX_KEY key;
}
if (header.flags & INDEX_ENTRY_FLAGS::INDEX_ENTRY_NODE) {
leVCN vcn;
}
std::mem::AlignTo<8>;
};
struct INDEX_ENTRY_SDH {
INDEX_ENTRY_HEADER header;
if (!(header.flags & INDEX_ENTRY_FLAGS::INDEX_ENTRY_END)) {
SDH_INDEX_KEY key;
}
if (header.flags & INDEX_ENTRY_FLAGS::INDEX_ENTRY_NODE) {
leVCN vcn;
}
std::mem::AlignTo<8>;
};
struct INDEX_ENTRY_OBJ_ID {
INDEX_ENTRY_HEADER header;
if (!(header.flags & INDEX_ENTRY_FLAGS::INDEX_ENTRY_END)) {
GUID key;
}
if (header.flags & INDEX_ENTRY_FLAGS::INDEX_ENTRY_NODE) {
leVCN vcn;
}
std::mem::AlignTo<8>;
};
struct INDEX_ENTRY_REPARSE {
INDEX_ENTRY_HEADER header;
if (!(header.flags & INDEX_ENTRY_FLAGS::INDEX_ENTRY_END)) {
REPARSE_INDEX_KEY key;
}
if (header.flags & INDEX_ENTRY_FLAGS::INDEX_ENTRY_NODE) {
leVCN vcn;
}
std::mem::AlignTo<8>;
};
struct INDEX_ENTRY_SID {
INDEX_ENTRY_HEADER header;
if (!(header.flags & INDEX_ENTRY_FLAGS::INDEX_ENTRY_END)) {
SID key;
}
if (header.flags & INDEX_ENTRY_FLAGS::INDEX_ENTRY_NODE) {
leVCN vcn;
}
std::mem::AlignTo<8>;
};
struct INDEX_ENTRY_OWNER_ID {
INDEX_ENTRY_HEADER header;
if (!(header.flags & INDEX_ENTRY_FLAGS::INDEX_ENTRY_END)) {
u64 key;
}
if (header.flags & INDEX_ENTRY_FLAGS::INDEX_ENTRY_NODE) {
leVCN vcn;
}
std::mem::AlignTo<8>;
};
fn index_get_flags(u64 offset) {
INDEX_ENTRY_HEADER index_entry_header @ offset;
return index_entry_header.flags;
};
struct INDEX_BLOCK {
NTFS_RECORD header [[inline]];
leLSN lsn;
leVCN index_block_vcn;
u32 index_head = $;
INDEX_HEADER index;
if (index.entries_offset > sizeof (index)) {
padding[index.entries_offset - sizeof (index)];
}
INDEX_ENTRY_FILE_NAME ents[while(!(index_get_flags($) & INDEX_ENTRY_FLAGS::INDEX_ENTRY_END))];
INDEX_ENTRY_FILE_NAME ent_end;
u32 index_used = $ - index_head;
if (index.index_length > index_used) {
padding[index.index_length - index_used];
}
};
struct INDEX_ROOT {
ATTR_TYPES type;
COLLATION_RULES collation_rule;
u32 index_block_size;
s8 clusters_per_index_block;
u8 reserved[3];
u32 index_head = $;
INDEX_HEADER index;
if (index.entries_offset > sizeof (index)) {
padding[index.entries_offset - sizeof (index)];
}
match (type) {
(ATTR_TYPES::AT_FILE_NAME): {
INDEX_ENTRY_FILE_NAME ents[while(!(index_get_flags($) & INDEX_ENTRY_FLAGS::INDEX_ENTRY_END))];
INDEX_ENTRY_FILE_NAME ent_end;
}
}
u32 index_used = $ - index_head;
if (index.index_length > index_used) {
padding[index.index_length - index_used];
}
};
struct RESTART_PAGE_HEADER {
NTFS_RECORD_TYPES magic;
u16 usa_ofs;
u16 usa_count;
leLSN chkdsk_lsn;
u32 system_page_size;
u32 log_page_size;
u16 restart_area_offset;
u16 minor_ver;
u16 major_ver;
u16 usn;
};
enum RESTART_AREA_FLAGS : u16 {
RESTART_VOLUME_IS_CLEAN = 0x0002,
RESTART_SPACE_FILLER = 0xffff,
};
struct RESTART_AREA {
leLSN current_lsn;
u16 log_clients;
u16 client_free_list;
u16 client_in_use_list;
RESTART_AREA_FLAGS flags;
u32 seq_number_bits;
u16 restart_area_length;
u16 client_array_offset;
u64 file_size;
u32 last_lsn_data_length;
u16 log_record_header_length;
u16 log_page_data_offset;
u32 restart_log_open_count;
u32 reserved;
};
struct LOG_CLIENT_RECORD {
leLSN oldest_lsn;
leLSN client_restart_lsn;
u16 prev_client;
u16 next_client;
u16 seq_number;
u8 reserved[6];
u32 client_name_length;
ntfschar client_name[64];
};
#define ATTR_RECORD_HEADER_SIZE (16)
#define ATTR_RECORD_RESIDENT_SIZE (16 + 8)
#define ATTR_RECORD_NONRESIDENT_SIZE (16 + 48)
#define ATTR_RECORD_NONRESIDENT_CMPR_SIZE (16 + 48 + 8)
struct ATTR_RECORD {
ATTR_TYPES type;
u32 length;
u8 non_resident;
u8 name_length;
u16 name_offset;
u16 flags; // ATTR_FLAGS
u16 instance;
u32 name_offset_delta = 0;
if (!non_resident) {
u32 value_length;
u16 value_offset;
RESIDENT_ATTR_FLAGS resident_flags;
s8 reservedR;
if (name_offset > ATTR_RECORD_RESIDENT_SIZE) {
name_offset_delta = name_offset - ATTR_RECORD_RESIDENT_SIZE;
padding[name_offset_delta];
}
} else {
leVCN lowest_vcn;
leVCN highest_vcn;
u16 mapping_pairs_offset;
u8 compression_unit;
u8 reserved1[5];
u64 allocated_size;
u64 data_size;
u64 initialized_size;
if (flags & ATTR_FLAGS::ATTR_IS_COMPRESSED) {
u64 compressed_size;
if (name_offset > ATTR_RECORD_NONRESIDENT_CMPR_SIZE) {
name_offset_delta = name_offset - ATTR_RECORD_NONRESIDENT_CMPR_SIZE;
padding[name_offset_delta];
}
} else {
if (name_offset > ATTR_RECORD_NONRESIDENT_SIZE) {
name_offset_delta = name_offset - ATTR_RECORD_NONRESIDENT_SIZE;
padding[name_offset_delta];
}
}
}
u32 name_length_bytes = name_length * sizeof (ntfschar);
if (name_length > 0) {
ntfschar name[name_length];
}
if (non_resident) {
if (flags & ATTR_FLAGS::ATTR_IS_COMPRESSED) {
if (mapping_pairs_offset > (ATTR_RECORD_NONRESIDENT_CMPR_SIZE + name_offset_delta + name_length_bytes)) {
padding[mapping_pairs_offset - (ATTR_RECORD_NONRESIDENT_CMPR_SIZE + name_length_bytes)];
}
} else {
if (mapping_pairs_offset > (ATTR_RECORD_NONRESIDENT_SIZE + name_offset_delta + name_length_bytes)) {
padding[mapping_pairs_offset - (ATTR_RECORD_NONRESIDENT_SIZE + name_length_bytes)];
}
}
RUNLIST runlist[while(true)];
} else {
u32 value_offset_delta = 0;
if (value_offset > (ATTR_RECORD_RESIDENT_SIZE + name_offset_delta + name_length_bytes)) {
value_offset_delta = value_offset - (ATTR_RECORD_RESIDENT_SIZE + name_offset_delta + name_length_bytes);
padding[value_offset_delta];
}
match (type) {
(ATTR_TYPES::AT_UNUSED): {
u32 attr_sum = (ATTR_RECORD_RESIDENT_SIZE + name_offset_delta + name_length_bytes + value_offset_delta);
if (length > attr_sum) {
padding[length - attr_sum];
}
}
(ATTR_TYPES::AT_STANDARD_INFORMATION): {
if (value_length > sizeof (STANDARD_INFORMATION_OLD)) {
STANDARD_INFORMATION info;
} else {
STANDARD_INFORMATION_OLD info;
}
u32 attr_sum = (ATTR_RECORD_RESIDENT_SIZE + name_offset_delta + name_length_bytes + value_offset_delta + sizeof (info));
if (length > attr_sum) {
padding[length - attr_sum];
}
}
(ATTR_TYPES::AT_ATTRIBUTE_LIST): {
u32 attr_sum = (ATTR_RECORD_RESIDENT_SIZE + name_offset_delta + name_length_bytes + value_offset_delta);
if (length > attr_sum) {
padding[length - attr_sum];
}
}
(ATTR_TYPES::AT_FILE_NAME): FILE_NAME_ATTR file;
(ATTR_TYPES::AT_OBJECT_ID): {
u32 attr_sum = (ATTR_RECORD_RESIDENT_SIZE + name_offset_delta + name_length_bytes + value_offset_delta);
if (length > attr_sum) {
padding[length - attr_sum];
}
}
(ATTR_TYPES::AT_SECURITY_DESCRIPTOR): {
SECURITY_DESCRIPTOR_RELATIVE sec;
u32 attr_sum = (ATTR_RECORD_RESIDENT_SIZE + name_offset_delta + name_length_bytes + value_offset_delta + sizeof (sec));
if (length > attr_sum) {
padding[length - attr_sum];
}
}
(ATTR_TYPES::AT_VOLUME_NAME): ntfschar vol_name[value_length / sizeof (ntfschar)];
(ATTR_TYPES::AT_VOLUME_INFORMATION): VOLUME_INFORMATION vol_info;
(ATTR_TYPES::AT_DATA): {
u8 buffer[value_length];
u32 attr_sum = (ATTR_RECORD_RESIDENT_SIZE + name_offset_delta + name_length_bytes + value_offset_delta + sizeof (buffer));
if (length > attr_sum) {
padding[length - attr_sum];
}
}
(ATTR_TYPES::AT_INDEX_ROOT): {
INDEX_ROOT root;
}
(ATTR_TYPES::AT_INDEX_ALLOCATION): {
u32 attr_sum = (ATTR_RECORD_RESIDENT_SIZE + name_offset_delta + name_length_bytes + value_offset_delta);
if (length > attr_sum) {
padding[length - attr_sum];
}
}
(ATTR_TYPES::AT_BITMAP): u8 buffer[value_length];
(ATTR_TYPES::AT_REPARSE_POINT): {
u32 attr_sum = (ATTR_RECORD_RESIDENT_SIZE + name_offset_delta + name_length_bytes + value_offset_delta);
if (length > attr_sum) {
padding[length - attr_sum];
}
}
(ATTR_TYPES::AT_EA_INFORMATION): {
u32 attr_sum = (ATTR_RECORD_RESIDENT_SIZE + name_offset_delta + name_length_bytes + value_offset_delta);
if (length > attr_sum) {
padding[length - attr_sum];
}
}
(ATTR_TYPES::AT_EA): {
u32 attr_sum = (ATTR_RECORD_RESIDENT_SIZE + name_offset_delta + name_length_bytes + value_offset_delta);
if (length > attr_sum) {
padding[length - attr_sum];
}
}
(ATTR_TYPES::AT_PROPERTY_SET): {
u32 attr_sum = (ATTR_RECORD_RESIDENT_SIZE + name_offset_delta + name_length_bytes + value_offset_delta);
if (length > attr_sum) {
padding[length - attr_sum];
}
}
(ATTR_TYPES::AT_LOGGED_UTILITY_STREAM): {
u32 attr_sum = (ATTR_RECORD_RESIDENT_SIZE + name_offset_delta + name_length_bytes + value_offset_delta);
if (length > attr_sum) {
padding[length - attr_sum];
}
}
(ATTR_TYPES::AT_FIRST_USER_DEFINED_ATTRIBUTE): {
u32 attr_sum = (ATTR_RECORD_RESIDENT_SIZE + name_offset_delta + name_length_bytes + value_offset_delta);
if (length > attr_sum) {
padding[length - attr_sum];
}
}
(ATTR_TYPES::AT_END): {
// length is no longer valid
}
}
}
std::mem::AlignTo<8>;
};
fn attr_get_type(u64 offset) {
ATTR_RECORD attr @ offset;
return attr.type;
};
#define MFT_RECORD_SIZE (sizeof (NTFS_RECORD) + 40)
struct MFT_RECORD {
NTFS_RECORD header [[inline]];
leLSN lsn;
u16 sequence_number;
u16 link_count;
u16 attrs_offset;
MFT_RECORD_FLAGS flags;
u32 bytes_in_use;
u32 bytes_allocated;
leMFT_REF base_mft_record;
u16 next_attr_instance;
u16 reserved;
u32 mft_record_number;
if (header.usa_count > 0) {
padding[header.usa_ofs - MFT_RECORD_SIZE];
}
u16 update_sequence[header.usa_count];
std::mem::AlignTo<8>;
ATTR_RECORD attrs[while(attr_get_type($) != ATTR_TYPES::AT_END)];
ATTR_RECORD attr_end;
};
struct NTFS_BOOT_SECTOR {
u8 jump[3];
u64 oem_id;
BIOS_PARAMETER_BLOCK bpb;
u8 physical_drive;
u8 current_head;
u8 extended_boot_signature;
u8 reserved2;
u64 number_of_sectors;
u64 mft_lcn;
u64 mftmirr_lcn;
s8 clusters_per_mft_record;
u8 reserved0[3];
s8 clusters_per_index_record;
u8 reserved1[3];
u64 volume_serial_number;
u32 checksum;
u8 bootstrap[426];
u16 end_of_sector_marker;
};
fn mft_get_dat_attr_lcn(MFT_RECORD record, ATTR_TYPES type = ATTR_TYPES::AT_DATA) {
u64 lcn = 0;
for (u64 i = 0, i < record.next_attr_instance, i += 1) {
if (record.attrs[i].type == type) {
for (s64 j = record.attrs[i].runlist[0].header.offset - 1, j >= 0, j -= 1) {
lcn |= record.attrs[i].runlist[0].lcn[j] << (8 * j);
}
break;
}
}
return lcn;
};
// ============= VBR =============
NTFS_BOOT_SECTOR nbs @ 0x00 [[name("VBR")]];
u32 cluster_size = nbs.bpb.bytes_per_sector * nbs.bpb.sectors_per_cluster;
u32 mft_rec_size = 1 << -nbs.clusters_per_mft_record;
// ============= $MFT =============
MFT_RECORD mft @ nbs.mft_lcn * cluster_size + 0 * mft_rec_size [[name("$MFT")]];
MFT_RECORD mftmirr @ nbs.mftmirr_lcn * cluster_size [[name("$MFT Copy")]];
// ============= $MFTMirr =============
MFT_RECORD mft_mirr @ nbs.mft_lcn * cluster_size + 1 * mft_rec_size [[name("$MFTMirr")]];
// ============= $LogFile =============
MFT_RECORD mft_log @ nbs.mft_lcn * cluster_size + 2 * mft_rec_size [[name("$LogFile")]];
// ============= $Volume =============
MFT_RECORD mft_vol @ nbs.mft_lcn * cluster_size + 3 * mft_rec_size [[name("$Volume")]];
// ============= $AttrDef =============
MFT_RECORD mft_adef @ nbs.mft_lcn * cluster_size + 4 * mft_rec_size [[name("$AttrDef")]];
ATTR_DEF adef_dat_buf[16] @ mft_get_dat_attr_lcn(mft_adef) * cluster_size [[name("$AttrDef, array")]];
// ============= $I30 (Root) =============
MFT_RECORD mft_root @ nbs.mft_lcn * cluster_size + 5 * mft_rec_size [[name("$I30 (Root)")]];
INDEX_BLOCK root_index_block @ mft_get_dat_attr_lcn(mft_root, ATTR_TYPES::AT_INDEX_ALLOCATION) * cluster_size [[name("$I30 (Root), INDEX_BLOCK")]];
// ============= $Bitmap =============
MFT_RECORD mft_bm @ nbs.mft_lcn * cluster_size + 6 * mft_rec_size [[name("$Bitmap")]];
// ============= $Boot =============
MFT_RECORD mft_boot @ nbs.mft_lcn * cluster_size + 7 * mft_rec_size [[name("$Boot")]];
// ============= $BadClus =============
MFT_RECORD mft_badclus @ nbs.mft_lcn * cluster_size + 8 * mft_rec_size [[name("$BadClus")]];
// ============= $Secure ($Quota for NTFS 1.2) =============
MFT_RECORD mft_sec @ nbs.mft_lcn * cluster_size + 9 * mft_rec_size [[name("$Secure")]];
// ============= $UpCase =============
MFT_RECORD mft_uc @ nbs.mft_lcn * cluster_size + 10 * mft_rec_size [[name("$UpCase")]];
u8 uc_tbl[1] @ mft_get_dat_attr_lcn(mft_uc) * cluster_size [[name("$UpCase, tabl")]];
// ============= $Extend =============
MFT_RECORD mft_ext @ nbs.mft_lcn * cluster_size + 11 * mft_rec_size [[name("$Extend")]];

231
patterns/fs/pattern.hexpat Normal file
View File

@@ -0,0 +1,231 @@
#pragma author WerWolv
#pragma description Drive File System
#pragma MIME application/x-ima
import std.io;
import std.core;
import type.magic;
import type.guid;
import type.base;
import * from fs.fat32 as FAT32Partition;
import * from fs.exfat as ExFATPartition;
import * from fs.ntfs as NTFSPartition;
const u32 SectorSize = 512;
struct DiskTimeStamp {
u8 seconds, minutes, hours;
};
enum DiskProtection : u16 {
None = 0x0000,
CopyProtected = 0x5A5A
};
bitfield CHS {
h : 8;
s : 6;
c : 10;
} [[format("chs_formatter")]];
fn chs_formatter(CHS chs) {
return std::format("({:X}, {:X}, {:X}) | 0x{:X}", chs.c, chs.h, chs.s, (chs.c * 16 + chs.h) * 63 + (chs.s - 1));
};
enum PartitionStatus : u8 {
None = 0x00,
Active = 0x80
};
enum MBRPartitionType : u8 {
Empty = 0x00,
FAT12 = 0x01,
XENIXRoot = 0x02,
XENIXUsr = 0x03,
FAT16_16_32MB = 0x04,
ExtendedCHS = 0x05,
FAT16_32MBPlus = 0x06,
NTFS = 0x07,
AIX = 0x08,
AIXBootable = 0x09,
OS2BootManager = 0x0A,
FAT32_CHS = 0x0B,
FAT32_LBA = 0x0C,
FAT16_LBA = 0x0E,
ExtendedLBA = 0x0F,
OPUS = 0x10,
HiddenFAT12 = 0x11,
CompaqDiagnostics = 0x12,
HiddenFAT16_16_32MB = 0x14,
HiddenFAT16_32MBPlus = 0x16,
HiddenNTFS = 0x17,
ASTSmartSleep = 0x18,
HiddenFAT32_CHS = 0x1B,
HiddenFAT32_LBA = 0x1C,
HiddenFAT16_LBA = 0x1E,
NEC_DOS = 0x24,
WindowsRecovery = 0x27,
Plan9 = 0x39,
PowerQuest = 0x3C,
Venix286 = 0x40,
PPC_PReP_Boot = 0x41,
SFS = 0x42,
QNX4_x = 0x4D,
QNX4_x_2ndPart = 0x4E,
QNX4_x_3rdPart = 0x4F,
OnTrackDM = 0x50,
OnTrackDM6Aux1 = 0x51,
CP_M = 0x52,
OnTrackDM6Aux3 = 0x53,
OnTrackDM6 = 0x54,
EZDrive = 0x55,
GoldenBow = 0x56,
PriamEDisk = 0x5C,
SpeedStor = 0x61,
GNU_HURD = 0x63,
NovellNetware286 = 0x64,
NovellNetware386 = 0x65,
DiskSecureMultiBoot = 0x70,
PC_IX = 0x75,
XOSL = 0x78,
OldMinix = 0x80,
LinuxMinix = 0x81,
LinuxSwap = 0x82,
Linux = 0x83,
OS2HiddenCDrive = 0x84,
LinuxExtended = 0x85,
NTFSVolumeSet = 0x86,
NTFSVolumeSet2 = 0x87,
LinuxLVM = 0x8E,
Amoeba = 0x93,
AmoebaBBT = 0x94,
BSD_OS = 0x9F,
IBMThinkpadHibernation = 0xA0,
FreeBSD = 0xA5,
OpenBSD = 0xA6,
NeXTSTEP = 0xA7,
MacOSX = 0xA8,
NetBSD = 0xA9,
BSDIFS = 0xB7,
BSDISwap = 0xB8,
BootWizardHidden = 0xBB,
DRDOSFAT12 = 0xC1,
DRDOSFAT16 = 0xC4,
DRDOSFAT16B = 0xC6,
Syrinx = 0xC7,
NonFSData = 0xDA,
CP_M_CTOS = 0xDB,
DellUtility = 0xDE,
BootIt = 0xDF,
DOSAccess = 0xE1,
DOSRO = 0xE3,
SpeedStor2 = 0xE4,
BeOS = 0xEB,
GPTProtective = 0xEE,
EFI_System = 0xEF,
LinuxPA_RISC = 0xF0,
SpeedStor3 = 0xF1,
DOSSecondary = 0xF2,
LinuxRAID = 0xFD,
LANstep = 0xFE,
Unknown = 0xFF
};
enum GPTPartitionType : u128 {
UnusedEntry = u128("\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"),
MicrosoftReservedPartition = u128("\x16\xE3\xC9\xE3\x5C\x0B\xB8\x4D\x81\x7D\xF9\x2D\xF0\x02\x15\xAE"),
PartitionBasicData = u128("\xA2\xA0\xD0\xEB\xE5\xB9\x33\x44\x87\xC0\x68\xB6\xB7\x26\x99\xC7")
};
bitfield GPTAttributes {
bool platform_required : 1;
padding : 59;
bool read_only : 1;
bool shadow_copy : 1;
bool hidden : 1;
bool no_drive_letter : 1;
};
struct GPTEntry {
GPTPartitionType partitionType [[no_unique_address]];
type::GUID partitionTypeGuid;
type::GUID partitionGuid;
u64 firstLba;
u64 lastLba;
GPTAttributes attribute;
char16 partitionName[36];
padding[parent.entrySize - 128];
u64 partitionOffset = firstLba * SectorSize [[export]];
match (partitionType) {
(GPTPartitionType::UnusedEntry): {}
(GPTPartitionType::MicrosoftReservedPartition):
std::mem::Bytes<(lastLba - firstLba + 1) * SectorSize> microsoftReservedPartition @ partitionOffset;
(GPTPartitionType::PartitionBasicData): {}
(_): std::error(std::format("Unknown GPT Partition Type {}", partitionType));
}
};
struct GUIDPartitionTable {
type::Magic<"EFI PART"> signature;
u16 versionMinor;
u16 versionMajor;
u32 headerSize;
type::Hex<u32> headerCrc32;
u32 reserved;
u64 currentLba;
u64 backupLba;
u64 firstUsableLba;
u64 lastUsableLba;
type::GUID diskGuid;
u64 entryLba;
u32 entryCount;
u32 entrySize;
type::Hex<u32> entryCrc32;
GPTEntry entries[entryCount] @ addressof(this) + (entryLba - currentLba) * SectorSize;
};
struct PartitionEntry {
PartitionStatus status;
CHS chsFirstSectorAddress;
MBRPartitionType type;
CHS chsLastSectorAddress;
u32 lbaFirstSectorAddress;
u32 numSectors;
u64 partitionOffset = lbaFirstSectorAddress * SectorSize [[export]];
match (type) {
(MBRPartitionType::Empty): continue;
(MBRPartitionType::FAT32_LBA | MBRPartitionType::FAT32_CHS):
FAT32Partition fat32Partition @ partitionOffset;
(MBRPartitionType::NTFS): {
char magic[8] @ partitionOffset + 3;
if (magic == "NTFS ")
NTFSPartition ntfsPartition @ partitionOffset;
else if (magic == "EXFAT ")
ExFATPartition exfatPartiton @ partitionOffset;
else
std::error("Unknown MBR partition with NTFS Type ID");
}
(MBRPartitionType::GPTProtective):
GUIDPartitionTable gpt @ partitionOffset;
(_): std::error(std::format("Unknown MBR Partition Type {}", type));
}
};
struct MasterBootRecord {
u8 bootstrapCodeArea1[218];
padding[2];
u8 originalPhysicalDrive;
DiskTimeStamp diskTimeStamp;
u8 bootstrapCodeArea2[216];
u32 diskSignature;
DiskProtection diskProtection;
PartitionEntry partitionEntries[4];
u16 bootSignature;
};
MasterBootRecord mbr @ 0x00;

61
patterns/gbx.hexpat Normal file
View File

@@ -0,0 +1,61 @@
#pragma author gmestanley
#pragma description GameBoy ROM file GBX footer
#pragma source hhug.me/gbx/1.0
import gb;
bitfield SachenMMC2SolderPad {
padding : 5;
opt1 : 1;
openBus512KiBOuterBanks : 1;
openBus1MiBOuterBanks : 1;
};
bitfield VastFameRunningValueType {
TaiwanReleases : 1;
MainlandChinaReleases : 1;
};
enum VastFamePCBType : u8 {
DSHGGB81,
BCR1616T3P
};
fn specialMapper(str value) { return value == "SAM2" || value == "VF01" || value == "GB81"; };
struct MapperVariables {
match(parent.mapper) {
("SAM2"): SachenMMC2SolderPad solderPadConfig;
("VF01"): VastFameRunningValueType runningValue;
("GB81"): VastFamePCBType pcb; }
padding[3*specialMapper(parent.mapper)];
u32 mapperVariables[8-specialMapper(parent.mapper)];
};
struct CartridgeInformation {
char mapper[4];
bool battery;
bool rumble;
bool timer;
padding[1];
u32 romSize;
u32 ramSize;
if (specialMapper(mapper))
MapperVariables mapperVariables;
else
MapperVariables mapperVariables [[inline]];
};
struct GBXMetadata {
u32 footerSize;
u32 majorVersion;
u32 minorVersion;
char signature[4];
};
struct GBXFooter {
CartridgeInformation cartInfo;
GBXMetadata metadata;
};
be GBXFooter gbxFooter @ std::mem::size() - 0x40;

137
patterns/gen.hexpat Normal file
View File

@@ -0,0 +1,137 @@
#pragma author gmestanley
#pragma description Sega Genesis/MegaDrive header
#pragma source plutiedev.com/rom-header wiki.neogeodev.org/index.php?title=68k_vector_table
#pragma endian big
import std.string;
struct M68000Vectors {
u32 stackPointerReset;
u32 programCounterReset [[comment("Entry Point")]];
u32 busError;
u32 addressError;
u32 illegalInstruction;
u32 divisionByZero;
u32 chkInstruction;
u32 trapVInstruction;
u32 privilegeViolation;
u32 trace;
u32 lineAInstruction;
u32 lineFInstruction;
padding[12];
u32 uninitializedInterruptVector;
padding[32];
u32 spuriousInterrupt;
u32 interruptAutovectors[7];
u32 traps[16];
};
M68000Vectors vectors @ 0x00;
struct Info {
char softwareType[2];
char space;
char serialNumber[8];
char dash;
char revision[2];
};
enum DeviceType : char {
NotFilled = ' ',
Button3Controller = 'J',
Button6Controller = '6',
MasterSystemController = '0',
AnalogJoystick = 'A',
Multitap = '4',
Lightgun = 'G',
Activator = 'L',
Mouse = 'M',
Trackball = 'B',
Mouse = 'T',
Trackball = 'V',
Keyboard = 'K',
RS232 = 'R',
Printer = 'P',
CDROM = 'C',
FloppyDrive = 'F',
Download = 'D'
};
bitfield RAMType {
addresses : 1;
padding : 3;
bits : 2;
saves : 1;
sig : 1;
};
enum MemoryType : char {
RAM = ' ',
EEPROM = '@'
};
struct ExtraMemory {
char signature[2];
RAMType ramType;
MemoryType memoryType;
u32 startAddress;
u32 endAddress;
};
fn renderMicrophoneType(str value) {
match(value) {
("00"): value = "NoMicJapanOnly";
("10"): value = "MicJapanOnly";
("20"): value = "NoMicOverseasOnly";
("30"): value = "MicOverseasOnly";
("40"): value = "NoMic";
("50"): value = "Mic";
("60"): value = "NoMicJapan";
("70"): value = "NoMicOverseas";
}
};
struct ModemSupport {
char signature[2];
char publisher[4];
char gameNumber[2];
char comma;
char version;
char microphone[2] [[format("renderMicrophoneType")]];
};
enum RegionType : char {
None = ' ',
Japan = 'J',
Americas = 'U',
Europe = 'E'
};
fn formatTerminatedString(str string) {
u8 index;
while (index < std::string::length(string)) {
if (std::mem::read_string($+index, 2) == " ")
break;
index += 1;
}
return "\"" + std::string::substr(string, 0, index) + "\"";
};
struct Header {
char systemType[16] [[format("formatTerminatedString")]];
char copyright[16] [[format("formatTerminatedString")]];
char domesticTitle[48] [[format("formatTerminatedString")]];
char overseasTitle[48] [[format("formatTerminatedString")]];
Info info;
u16 checksum;
DeviceType deviceType[16];
u32 romAddressRange[2];
u32 ramAddressRange[2];
if ($[$] == 'R') ExtraMemory extraMemory; else padding[12];
if ($[$] == 'M') ModemSupport modemSupport; else padding[12];
padding[40];
RegionType regions[3];
};
Header header @ 0x100;

View File

@@ -3,6 +3,7 @@
#pragma description ggml GGUF v3
#pragma authors @leonjza, jessie @ imhex discord
#pragma magic [ 47 47 55 46 ] @ 0x00
#pragma pattern_limit 300000

View File

@@ -22,13 +22,18 @@
* SOFTWARE.
*/
#pragma author H. Utku Maden
#pragma author H. Utku Maden, xZise
#pragma description GL Transmission Format binary 3D model (.glb)
#pragma MIME model/gltf-binary
#pragma magic [67 6C 54 46] @ 0x00
import std.mem;
import std.io;
import type.magic;
import std.core;
#ifdef __IMHEX__
import hex.type.json;
#endif
/**
* @brief The glTF magic section.
@@ -53,7 +58,15 @@ enum gltf_chunk_type_t : u32 {
struct gltf_chunk_t {
u32 length; /**< Length of this chunk. */
gltf_chunk_type_t type [[format("gltf_format")]]; /**< Type of the chunk. JSON or BIN expected. */
u8 string[length]; /**< The chunk data. */
#ifndef __IMHEX__
u8 data[length]; /**< The chunk data. */
#endif
#ifdef __IMHEX__
match (type) {
(gltf_chunk_type_t::JSON): hex::type::Json<length> json;
(gltf_chunk_type_t::BIN): u8 data[length];
} /**< The chunk data. */
#endif
};
fn gltf_format(gltf_chunk_type_t x)
@@ -64,7 +77,162 @@ fn gltf_format(gltf_chunk_type_t x)
return "";
};
gltf_magic_t magic @ 0x00;
gltf_chunk_t chunks[while(!std::mem::eof())] @ $;
struct stride_type_t<InnerType, auto Stride> {
InnerType value [[inline]];
if (Stride > 0) {
padding[Stride - sizeof(value)];
}
};
std::assert_warn(std::mem::size() == magic.length, "file size mismatch");
enum component_types_t : u64 {
BYTE = 5120,
UNSIGNED_BYTE = 5121,
SHORT = 5122,
UNSIGNED_SHORT = 5123,
UNSIGNED_INT = 5125,
FLOAT = 5126,
};
fn component_type_format(component_types_t component_type)
{
if (component_type == component_types_t::BYTE) return "s8";
else if (component_type == component_types_t::UNSIGNED_BYTE) return "u8";
else if (component_type == component_types_t::SHORT) return "s16";
else if (component_type == component_types_t::UNSIGNED_SHORT) return "u16";
else if (component_type == component_types_t::UNSIGNED_INT) return "u32";
else if (component_type == component_types_t::FLOAT) return "float";
return std::format("{}", component_type);
};
struct component_type_t<auto component_type> {
match (component_type) {
(component_types_t::BYTE): s8 value;
(component_types_t::UNSIGNED_BYTE): u8 value;
(component_types_t::SHORT): s16 value;
(component_types_t::UNSIGNED_SHORT): u16 value;
(component_types_t::UNSIGNED_INT): u32 value;
(component_types_t::FLOAT): float value;
}
};
struct scalar_t<auto component_type> {
component_type_t<component_type> scalar [[inline]];
} [[static]];
struct vec2_t<auto component_type> {
component_type_t<component_type> x;
component_type_t<component_type> y;
} [[static]];
struct vec3_t<auto component_type> {
component_type_t<component_type> x;
component_type_t<component_type> y;
component_type_t<component_type> z;
} [[static]];
struct vec4_t<auto component_type> {
component_type_t<component_type> x;
component_type_t<component_type> y;
component_type_t<component_type> z;
component_type_t<component_type> w;
} [[static]];
struct mat2_t<auto component_type> {
component_type_t<component_type> a11, a21;
component_type_t<component_type> a12, a22;
} [[static]];
struct mat3_t<auto component_type> {
component_type_t<component_type> a11, a21, a31;
component_type_t<component_type> a12, a22, a32;
component_type_t<component_type> a13, a23, a33;
} [[static]];
struct mat4_t<auto component_type> {
component_type_t<component_type> a11, a21, a31, a41;
component_type_t<component_type> a12, a22, a32, a42;
component_type_t<component_type> a13, a23, a33, a43;
component_type_t<component_type> a14, a24, a34, a44;
} [[static]];
fn mem_cnt(auto value) {
return std::core::member_count(value);
};
fn has_mem(auto value, str member) {
return std::core::has_member(value, member);
};
struct accessor_t {
u64 accessor_index = std::core::array_index();
u64 view_index = glb.json_chunk.json.accessors[accessor_index].bufferView [[export]];
u64 view_offset = glb.json_chunk.json.bufferViews[view_index].byteOffset [[export]];
if (has_mem(glb.json_chunk.json.bufferViews[view_index], "byteStride")) {
u64 byte_stride = glb.json_chunk.json.bufferViews[view_index].byteStride [[export]];
} else {
u64 byte_stride = 0 [[export]];
}
if (has_mem(glb.json_chunk.json.accessors[accessor_index], "byteOffset")) {
u64 accessor_offset = glb.json_chunk.json.accessors[accessor_index].byteOffset [[export]];
} else {
u64 accessor_offset = 0 [[export]];
}
view_offset = view_offset + accessor_offset;
u64 count_elements = glb.json_chunk.json.accessors[accessor_index].count;
component_types_t component_type = glb.json_chunk.json.accessors[accessor_index].componentType [[export]];
str element_type = glb.json_chunk.json.accessors[accessor_index].type [[export]];
match (element_type) {
("SCALAR"): stride_type_t<scalar_t<parent.component_type>, byte_stride> content[count_elements] @ view_offset + addressof(glb.chunks[0].data);
("VEC2"): stride_type_t<vec2_t<parent.component_type>, byte_stride> content[count_elements] @ view_offset + addressof(glb.chunks[0].data);
("VEC3"): stride_type_t<vec3_t<parent.component_type>, byte_stride> content[count_elements] @ view_offset + addressof(glb.chunks[0].data);
("VEC4"): stride_type_t<vec4_t<parent.component_type>, byte_stride> content[count_elements] @ view_offset + addressof(glb.chunks[0].data);
("MAT2"): stride_type_t<mat2_t<parent.component_type>, byte_stride> content[count_elements] @ view_offset + addressof(glb.chunks[0].data);
("MAT3"): stride_type_t<mat3_t<parent.component_type>, byte_stride> content[count_elements] @ view_offset + addressof(glb.chunks[0].data);
("MAT4"): stride_type_t<mat4_t<parent.component_type>, byte_stride> content[count_elements] @ view_offset + addressof(glb.chunks[0].data);
}
} [[format("accessor_format")]];
fn accessor_format(accessor_t accessor) {
return std::format("{}<{}>[{}]", accessor.element_type, accessor.component_type, accessor.count_elements);
};
struct image_buffer_t {
u64 image_index = std::core::array_index();
u64 buffer_view_index = glb.json_chunk.json.images[image_index].bufferView;
u64 byte_offset = glb.json_chunk.json.bufferViews[buffer_view_index].byteOffset;
u64 byte_length = glb.json_chunk.json.bufferViews[buffer_view_index].byteLength;
u8 image[byte_length] @ addressof(glb.chunks[0].data) + byte_offset;
} [[hex::visualize("image", image)]];
struct buffer_view_t {
u64 buffer_view_index = std::core::array_index();
u64 byte_offset = glb.json_chunk.json.bufferViews[buffer_view_index].byteOffset;
u64 byte_length = glb.json_chunk.json.bufferViews[buffer_view_index].byteLength;
u8 data[byte_length] @ addressof(glb.chunks[0].data) + byte_offset;
};
struct glb_file_t {
gltf_magic_t magic;
gltf_chunk_t json_chunk;
gltf_chunk_t chunks[while(!std::mem::eof())];
std::assert_warn(std::mem::size() == magic.length, "file size mismatch");
};
glb_file_t glb @ 0x00;
#ifdef __IMHEX__
struct glb_objects_t {
if (std::core::member_count(glb.chunks) == 1) {
if (has_mem(glb.json_chunk.json, "images")) {
image_buffer_t images[mem_cnt(glb.json_chunk.json.images)];
}
buffer_view_t buffer_views[mem_cnt(glb.json_chunk.json.bufferViews)];
accessor_t accessors[mem_cnt(glb.json_chunk.json.accessors)];
}
};
glb_objects_t objects @ 0x00;
#endif

229
patterns/gmf.hexpat Normal file
View File

@@ -0,0 +1,229 @@
#pragma author DmitriLeon2000
#pragma description Game Maker 3.x data
#pragma endian little
import std.mem;
import std.io;
struct Colors {
u8 red [[color("FF0000")]];
u8 green [[color("00FF00")]];
u8 blue [[color("0000FF")]];
padding[1];
} [[static, color(std::format("{:02X}{:02X}{:02X}", red, green, blue)),
hex::inline_visualize("color", red, green, blue, 255)]];
struct PascalString {
u32 length;
char data[length];
};
struct BitmapData {
u8 type[2];
u32 size;
u8 data[size-6] [[sealed]];
};
enum BackgroundType : s32 {
Solid = 0,
Image = 1,
Gradient = 2,
None = 3
};
enum BackImageStyle : s32 {
Tile = 0,
Stretch = 1,
Scrolling = 2,
LeftTop = 3
};
enum Transition : u32 {
None = 0,
CreateFromLeft = 1,
CreateFromRight = 2,
CreateFromTop = 3,
CreateFromBottom = 4,
CreateFromCenter = 5,
ShiftFromLeft = 6,
ShiftFromRight = 7,
ShiftFromTop = 8,
ShiftFromBottom = 9,
PushFromLeft = 10,
PushFromRight = 11,
PushFromTop = 12,
PushFromBottom = 13
};
struct SpriteBoundingBox {
u32 left, right, bottom, top;
};
enum ActionID : s32 {
EnumerateActions = 0,
EndAction = 1,
MoveFixed = 101,
ReverseHorizontal = 102,
ReverseVertical = 103,
JumpPosition = 104,
JumpRandom = 105,
Bounce = 106,
SetSpeedHorizontal = 111,
SetSpeedVertical = 112,
SetGravity = 121,
SetFriction = 122,
MoveFree = 131,
SetAlarm = 201,
InstanceCreate = 311,
InstanceDestroy = 312,
InstanceChange = 313,
PositionDestroy = 321,
Sound = 401,
ShowMessage = 411,
SetScore = 421,
DisplayHighscore = 431,
GoToRoom = 501,
EndGame = 511,
Sleep = 521,
ExitEvent = 601,
CheckPlaceFree = 701,
CheckInstanceNumber = 702,
CheckPlaceObject = 703,
CheckPlaceCollision = 704,
CheckQuestion = 721,
Else = 751,
CheckExpression = 801,
ExecuteCode = 811,
SetVariable = 821,
BlockStart = 901,
BlockEnd = 902,
DrawImage = 1001,
DrawText = 1002,
SetFont = 1003
};
struct GameObjectAction {
s32 version_verify [[hidden]];
ActionID action_id;
s32 apply_to; // -1 - self; -2 - not available
bool relative;
padding[3];
u32 param_count;
PascalString params[param_count];
s32 action_group;
};
struct GameObjectSubEvent {
s32 subevent_number;
s32 version_verify [[hidden]];
u32 action_count;
GameObjectAction actions[action_count];
};
struct GameObjectEvent {
GameObjectSubEvent subevents[while(std::mem::read_unsigned($, 4) != 0xFFFFFFFF)];
padding[4];
};
struct GameSprite {
s32 version_verify [[hidden]];
s32 width, height;
SpriteBoundingBox bounding_box1;
u32 image_count;
BitmapData images[image_count];
SpriteBoundingBox bounding_box2;
};
struct GameObject {
s32 version_verify [[hidden]];
PascalString name;
bool solid;
padding[3];
bool active;
padding[3];
if (version_verify >= 320)
u32 parent_id;
GameObjectEvent events[13];
// Events: 0 - Create, 1 - Destroy, 2 - Alarm, 3 - Step, 4 - Collision,
// 5 - Meeting, 6 - Mouse, 7 - Keyboard, 8 - Other, 9 - Drawing
// 10 - Create duplicate, 11-13 - unused
s32 cap [[hidden]];
GameSprite sprite;
} [[name(name.data)]];
struct GameRoomView {
bool enabled;
padding[3];
if (parent.version_verify >= 320)
s32 left, top, left_cell, top_cell;
u32 width;
u32 height;
if (parent.version_verify >= 320) {
u32 border_horiz, border_vert;
} else
u32 border;
u32 object_to_follow;
};
struct GameRoomInstance {
s32 left, top, object_index;
};
struct GameRoom {
u32 version_verify [[hidden]];
PascalString name;
Colors back_color1;
if (version_verify >= 320) {
Colors back_color2;
bool vertical_gradient;
padding[3];
}
// specify the name of the external image file from the data folder
PascalString back_image_name;
BackgroundType back_type;
BackImageStyle back_image_style;
s32 back_scroll_speed_horizontal, back_scroll_speed_vertical;
s32 speed, width, height, cell_size;
if (version_verify >= 320) {
bool enable_views;
padding[3];
GameRoomView views[4];
} else
GameRoomView view;
if (version_verify >= 320) {
Transition transition;
u32 transition_time, transition_steps;
}
u32 instance_count;
GameRoomInstance instances[instance_count];
} [[name(name.data)]];
struct GameSound {
u32 version_verify [[hidden]];
PascalString name;
u32 reserved;
// specify the name of the external audio file from the data folder
PascalString filename;
bool allow_for_sound_effects;
padding[3];
u32 buffer_count;
} [[name(name.data)]];
struct GMF {
u32 version;
u32 verification[2];
u32 version_verify_options [[hidden]];
u32 option_count;
PascalString options[option_count];
u32 version_verify_objects [[hidden]];
u32 object_count;
GameObject objects[object_count];
u32 version_verify_rooms [[hidden]];
u32 room_count;
GameRoom rooms[room_count];
u32 version_verify_sounds [[hidden]];
u32 sound_count;
GameSound sounds[sound_count];
};
GMF gmf @ 0x0;

View File

@@ -1,5 +1,6 @@
#pragma author Surasia
#pragma description Halo Infinite HavokScript 5.1 "luas"
#pragma magic [ 75 63 73 68 ] @ 0x00
import std.io;
import std.mem;

View File

@@ -1,7 +1,8 @@
#pragma author Surasia
#pragma description Halo Infinite Module
#pragma array_limit 4294967295
#pragma pattern_limit 4294967295
#pragma array_limit 0
#pragma pattern_limit 0
#pragma magic [ 6D 6F 68 64 ] @ 0x00
import std.string;

View File

@@ -1,5 +1,6 @@
#pragma author Surasia
#pragma description Halo Infinite Tag
#pragma magic [ 75 63 73 68 ] @ 0x00
import std.string;
import type.guid;

362
patterns/hprof.hexpat Normal file
View File

@@ -0,0 +1,362 @@
#pragma author WerWolv
#pragma description Java HPROF Profiler Data Format
#pragma endian big
#pragma magic [ "JAVA PROFILE" ] @ 0x00
#pragma array_limit 0
#pragma pattern_limit 0
import std.mem;
import std.io;
import std.sys;
import std.core;
enum Tag : u8 {
STRING_IN_UTF8 = 0x01,
LOAD_CLASS = 0x02,
UNLOAD_CLASS = 0x03,
STACK_FRAME = 0x04,
STACK_TRACE = 0x05,
ALLOC_SITES = 0x06,
HEAP_SUMMARY = 0x07,
START_THREAD = 0x0A,
END_THREAD = 0x0B,
HEAP_DUMP = 0x0C,
HEAP_DUMP_SEGMENT = 0x1C,
HEAP_DUMP_END = 0x2C,
CPU_SAMPLES = 0x0D,
CONTROL_SETTINGS = 0x0E,
};
u32 id_size = 0;
struct ID {
match (id_size) {
(1): u8 value;
(2): u16 value;
(4): u32 value;
(8): u64 value;
(_): std::error("Invalid ID size");
}
} [[sealed, format("format_id")]];
fn format_id(ref auto id) {
return std::format("0x{:0{}X}", id.value, id_size * 2);
};
struct StringInUTF8 {
ID id;
char string[parent.length - sizeof(id)];
};
struct LoadClass {
u32 classSerialNumber;
ID classObjectId;
u32 stackTraceSerialNumber;
ID classNameStringID;
};
struct StackFrame {
ID stackFrameId;
ID methodNameStringId;
ID methodSignatureStringId;
ID sourceFileNameStringId;
u32 classSerialNumber;
u32 lineInformation;
};
struct StackTrace {
u32 stackTraceSerialNumber;
u32 threadSerialNumber;
u32 numberOfFrames;
ID stackFrameIds[while(!std::mem::reached(addressof(this) + parent.length))];
};
enum SubTag : u8 {
RootUnknown = 0xFF,
RootJNIGlobal = 0x01,
RootJNILocal = 0x02,
RootJavaFrame = 0x03,
RootNativeStack = 0x04,
RootStickyClass = 0x05,
RootThreadBlock = 0x06,
RootMonitorUsed = 0x07,
RootThreadObject = 0x08,
ClassDump = 0x20,
InstanceDump = 0x21,
ObjectArrayDump = 0x22,
PrimitiveArrayDump = 0x23
};
enum EntryType : u8 {
Object = 2,
Boolean = 4,
Char = 5,
Float = 6,
Double = 7,
Byte = 8,
Short = 9,
Int = 10,
Long = 11
};
struct BasicType<auto Tag> {
match (Tag) {
(EntryType::Object): ID value;
(EntryType::Boolean): bool value;
(EntryType::Char): { padding[1]; char value; }
(EntryType::Float): float value;
(EntryType::Double): double value;
(EntryType::Byte): u8 value;
(EntryType::Short): u16 value;
(EntryType::Int): u32 value;
(EntryType::Long): u64 value;
(_): std::error("Invalid BasicType type");
}
} [[sealed, format("format_basic_type")]];
fn format_basic_type(ref auto basicType) {
return std::format("{}", basicType.value);
};
struct ConstantPoolEntry {
u16 constantPoolIndex;
EntryType type;
BasicType<type> value;
};
struct ConstantPoolArray {
u16 size;
ConstantPoolEntry entries[size];
};
struct StaticFieldEntry {
ID staticFieldNameStringId;
EntryType type;
BasicType<type> value;
};
struct StaicFieldArray {
u16 size;
StaticFieldEntry entries[size];
};
struct InstanceField {
ID fieldNameStringId;
EntryType fieldType;
};
struct InstanceFieldsArray {
u16 size;
InstanceField instanceFields[size];
};
struct HeapDump {
SubTag subTag;
match (subTag) {
(SubTag::RootUnknown): {
ID objectId;
}
(SubTag::RootJNIGlobal): {
ID objectId;
ID jniGlobalRefId;
}
(SubTag::RootJNILocal): {
ID objectId;
u32 threadSerialNumber;
u32 frameNumberInStackTrace;
}
(SubTag::RootJavaFrame): {
ID objectId;
u32 threadSerialNumber;
u32 frameNumberInStackTrace;
}
(SubTag::RootNativeStack): {
ID objectId;
u32 threadSerialNumber;
}
(SubTag::RootStickyClass): {
ID objectId;
}
(SubTag::RootThreadBlock): {
ID objectId;
u32 threadSerialNumber;
}
(SubTag::RootMonitorUsed): {
ID objectId;
}
(SubTag::RootThreadObject): {
ID threadObjectId;
u32 threadSerialNumber;
u32 stackTraceSerialNumber;
}
(SubTag::ClassDump): {
ID classObjectId;
u32 stackTraceSerialNumber;
ID superClassObjectId;
ID classLoaderObjectId;
ID signersObjectId;
ID protectionDomainObjectId;
ID reserved[2];
u32 instanceSize;
ConstantPoolArray constantPool;
StaicFieldArray staticFields;
InstanceFieldsArray instanceFields;
}
(SubTag::InstanceDump): {
ID objectId;
u32 stackTraceSerialNumber;
ID classObjectId;
u32 numBytes;
std::mem::Bytes<numBytes> instanceFieldValues;
}
(SubTag::ObjectArrayDump): {
ID arrayObjectId;
u32 stackTraceSerialNumber;
u32 numberOfElements;
ID arrayClassObjectId;
ID elements[numberOfElements];
}
(SubTag::PrimitiveArrayDump): {
ID arrayObjectId;
u32 stackTraceSerialNumber;
u32 numberOfElements;
EntryType type;
BasicType<type> value[numberOfElements];
}
(_): std::error(std::format("Heap Dump Sub Tag {:02X} at 0x{:08X} {}", u32(subTag), $, std::core::array_index()));
}
if ($ - addressof(parent.length) + sizeof(parent.length) >= parent.length)
break;
u8 endTag [[no_unique_address, hidden]];
if (endTag == 0x2C) {
padding[1];
break;
}
};
struct UnloadClass {
u32 classSerialNumber;
};
bitfield AllocSitesFlags {
completeInsteadOfIncremental : 1;
sortedByLineInsteadOfAllocation : 1;
forceGc : 1;
padding : 13;
};
struct AllocSite {
bool arrayIndicator;
u32 classSerialNumber;
u32 stackTraceSerialNumber;
u32 numberOfLiveBytes;
u32 numberOfLiveInstances;
u32 numberOfBytesAllocated;
u32 numberOfInstancesAllocated;
};
struct AllocSites {
AllocSitesFlags flags;
float cutoffRatio;
u32 totalLiveBytes;
u32 totalLiveInstances;
u64 totalBytesAllocated;
u64 totalInstancesAllocated;
u32 numSites;
AllocSite sites[numSites];
};
struct HeapSummary {
u32 totalLiveBytes;
u32 totalLiveInstances;
u64 totalBytesAllocated;
u64 totalInstancesAllocated;
};
struct StartThread {
u32 threadSerialNumber;
ID threadObjectId;
u32 stackTraceSerialNumber;
ID threadNameStringId;
ID threadGroupNameId;
ID threadParentGroupNameId;
};
struct EndThread {
u32 threadSerialNumber;
};
struct Sample {
u32 numberOfSamples;
u32 stackTraceSerialNumber;
};
struct CpuSamples {
u32 numSamples;
Sample samples[numSamples];
};
bitfield ControlSettingsFlags {
allocTraces : 1;
cpuSampling : 1;
padding : 30;
};
struct ControlSettings {
ControlSettingsFlags flags;
u16 stackTraceDepth;
};
struct Record {
Tag tag;
u32 time;
u32 length;
match (tag) {
(Tag::STRING_IN_UTF8):
StringInUTF8 body;
(Tag::LOAD_CLASS):
LoadClass body;
(Tag::UNLOAD_CLASS):
UnloadClass body;
(Tag::STACK_FRAME):
StackFrame body;
(Tag::STACK_TRACE):
StackTrace body;
(Tag::ALLOC_SITES):
AllocSites body;
(Tag::HEAP_SUMMARY):
HeapSummary body;
(Tag::START_THREAD):
StartThread body;
(Tag::END_THREAD):
EndThread body;
(Tag::HEAP_DUMP | Tag::HEAP_DUMP_SEGMENT):
HeapDump heapDumps[while(true)];
(Tag::HEAP_DUMP_END):
std::error("HEAP_DUMP_END Tag without previous HEAP_DUMP or HEAP_DUMP_SEGMENT Tag");
(Tag::CPU_SAMPLES):
CpuSamples body;
(Tag::CONTROL_SETTINGS):
ControlSettings body;
(_):
std::error(std::format("Unknown record type {:02X} at address 0x{:08X}, index {}", u8(tag), addressof(tag), std::core::array_index()));
}
};
struct Header {
char format_name[];
u32 identifier_size;
id_size = identifier_size;
u32 timestamp_high;
u32 time_stamp_low;
};
struct HPROF {
Header header;
Record records[while(!std::mem::eof())];
};
HPROF hprof @ 0x00;

Some files were not shown because too many files have changed in this diff Show More