mirror of
https://github.com/WerWolv/ImHex-Patterns.git
synced 2026-04-02 05:27:40 -05:00
Compare commits
135 Commits
ImHex-v1.3
...
ImHex-v1.3
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4646e4b965 | ||
|
|
9143996589 | ||
|
|
7c3dcc1fcc | ||
|
|
ea8b381ac5 | ||
|
|
998655f74a | ||
|
|
681b208aab | ||
|
|
64d86cbdd1 | ||
|
|
285a2fc7d1 | ||
|
|
2a9676238f | ||
|
|
ee340409db | ||
|
|
84dff0c886 | ||
|
|
28a297582b | ||
|
|
681b1a1ded | ||
|
|
0a09efdd20 | ||
|
|
0d8bd76c2c | ||
|
|
a525160243 | ||
|
|
c3946d33a7 | ||
|
|
cc7eb7d764 | ||
|
|
53384a4a54 | ||
|
|
da005f0172 | ||
|
|
b2f126d22f | ||
|
|
7ea863269e | ||
|
|
faff9e0364 | ||
|
|
a35004665f | ||
|
|
4fc11f1b91 | ||
|
|
7a9a5097a2 | ||
|
|
0e67ee102b | ||
|
|
69077b919d | ||
|
|
297f611fed | ||
|
|
b24ae36638 | ||
|
|
50d776f497 | ||
|
|
7dfacc4139 | ||
|
|
5359e385ea | ||
|
|
75bcb487ee | ||
|
|
fb214600ec | ||
|
|
d95390ea42 | ||
|
|
284ca8d325 | ||
|
|
6630180276 | ||
|
|
ff68d1e23d | ||
|
|
70dd55aa6b | ||
|
|
76f850c543 | ||
|
|
74c06b74f7 | ||
|
|
f13d9d3894 | ||
|
|
c4c75a9ab2 | ||
|
|
7278a22eb2 | ||
|
|
91fd36097c | ||
|
|
afffd7eced | ||
|
|
7fd79ec9fd | ||
|
|
6b9f39cc21 | ||
|
|
9207282bcf | ||
|
|
5ed64f9f08 | ||
|
|
a75a7a5b98 | ||
|
|
60c8d93449 | ||
|
|
d3b05fd753 | ||
|
|
3b2f098b09 | ||
|
|
f4f004f0eb | ||
|
|
5c6cb9dccc | ||
|
|
44717e9b19 | ||
|
|
bc35349e0f | ||
|
|
fed5db4109 | ||
|
|
1d41392215 | ||
|
|
0b75336638 | ||
|
|
e3edbd5a6f | ||
|
|
b10a37af67 | ||
|
|
103d434cc5 | ||
|
|
7716b9d6e7 | ||
|
|
ad1e300674 | ||
|
|
e918ce52b9 | ||
|
|
db4d62aa20 | ||
|
|
d96bfbb942 | ||
|
|
2070c95f58 | ||
|
|
877895741d | ||
|
|
6b279b8375 | ||
|
|
a692b22ecc | ||
|
|
2ae0499293 | ||
|
|
bd06987e8e | ||
|
|
74e08623f1 | ||
|
|
a860c396fa | ||
|
|
da934e2045 | ||
|
|
394ef80611 | ||
|
|
2ce182b1b3 | ||
|
|
6cadad3d1f | ||
|
|
7ad9cd4f41 | ||
|
|
bcaeef31d7 | ||
|
|
ee8d2f50b7 | ||
|
|
5b8dde19a9 | ||
|
|
0b0eff0cb6 | ||
|
|
3185503be1 | ||
|
|
3a64207e58 | ||
|
|
c94d42d5c0 | ||
|
|
45c4c1d35b | ||
|
|
f93be1ea06 | ||
|
|
5ed9c0fd4d | ||
|
|
11d373319f | ||
|
|
e7d366571d | ||
|
|
b6df1742b6 | ||
|
|
0b9e83ff8a | ||
|
|
c0fc748de6 | ||
|
|
89307ba8a5 | ||
|
|
a12b5ba406 | ||
|
|
537ce67895 | ||
|
|
1771c1f077 | ||
|
|
cef20e24a7 | ||
|
|
8e7cfd9442 | ||
|
|
d0ba754dc2 | ||
|
|
9f92c38ecf | ||
|
|
0844e07056 | ||
|
|
66fc006b08 | ||
|
|
5bc66df14f | ||
|
|
7310a10214 | ||
|
|
34ee3107e2 | ||
|
|
c4378ffb14 | ||
|
|
5ad7f0c1e7 | ||
|
|
df97fc7257 | ||
|
|
3ad263783d | ||
|
|
5ccd431320 | ||
|
|
fb8e5e3f77 | ||
|
|
375145e759 | ||
|
|
71eeed981d | ||
|
|
e779b88a58 | ||
|
|
aef3d3451f | ||
|
|
c5fa53dcea | ||
|
|
9a6cbdfe28 | ||
|
|
083042632d | ||
|
|
4d172cebc3 | ||
|
|
53ff0a5d62 | ||
|
|
b3b730c6e9 | ||
|
|
8db011b6e5 | ||
|
|
b936c04d21 | ||
|
|
bf56d4ff49 | ||
|
|
fdc4a87389 | ||
|
|
1f6c701348 | ||
|
|
4092dad428 | ||
|
|
559faebec3 | ||
|
|
cde46e1f15 |
13
.github/workflows/tests.yml
vendored
13
.github/workflows/tests.yml
vendored
@@ -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
1
.gitignore
vendored
@@ -2,6 +2,7 @@
|
||||
tests/cmake*/
|
||||
tests/build*/
|
||||
build/
|
||||
cmake-build-*/
|
||||
|
||||
.vscode/
|
||||
.devcontainer/
|
||||
|
||||
@@ -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()
|
||||
|
||||
108
README.md
108
README.md
@@ -25,52 +25,72 @@ 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 |
|
||||
| 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) |
|
||||
| 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 |
|
||||
| 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 |
|
||||
@@ -81,16 +101,22 @@ 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.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 +126,39 @@ 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 |
|
||||
| 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 +166,72 @@ 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 |
|
||||
| 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
|
||||
|
||||
@@ -261,9 +327,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 |
|
||||
| 8051 | [`disassemblers/8051.json`](disassemblers/8051.json) | Intel 8051 Architecture |
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
]
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
]
|
||||
|
||||
@@ -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)"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -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"
|
||||
}
|
||||
|
||||
]
|
||||
}
|
||||
@@ -49,8 +49,8 @@
|
||||
"format": "#{I}"
|
||||
},
|
||||
{
|
||||
"mask": "areturn",
|
||||
"mnemonic": "1011'0000",
|
||||
"mask": "1011'0000",
|
||||
"mnemonic": "areturn",
|
||||
"format": ""
|
||||
},
|
||||
{
|
||||
@@ -84,8 +84,8 @@
|
||||
"format": ""
|
||||
},
|
||||
{
|
||||
"mask": "athrow",
|
||||
"mnemonic": "1011'1111",
|
||||
"mask": "1011'1111",
|
||||
"mnemonic": "athrow",
|
||||
"format": ""
|
||||
},
|
||||
{
|
||||
@@ -1042,4 +1042,4 @@
|
||||
"format": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
@@ -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]];
|
||||
};
|
||||
|
||||
|
||||
@@ -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")]];
|
||||
|
||||
|
||||
@@ -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 <= '~';
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -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]];
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
```
|
||||
*/
|
||||
|
||||
@@ -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 {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,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
|
||||
*/
|
||||
|
||||
@@ -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
|
||||
|
||||
47
patterns/AC Unity/acu_data_compressed.hexpat
Normal file
47
patterns/AC Unity/acu_data_compressed.hexpat
Normal 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;
|
||||
93
patterns/AC Unity/acu_data_decompressed.hexpat
Normal file
93
patterns/AC Unity/acu_data_decompressed.hexpat
Normal 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;
|
||||
64
patterns/AC Unity/acu_forge.hexpat
Normal file
64
patterns/AC Unity/acu_forge.hexpat
Normal 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;
|
||||
@@ -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
|
||||
|
||||
81
patterns/DFIR/DFIR_README.md
Normal file
81
patterns/DFIR/DFIR_README.md
Normal 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)
|
||||
|
||||
|
||||
677
patterns/DFIR/DISK_PARSER.hexpat
Normal file
677
patterns/DFIR/DISK_PARSER.hexpat
Normal 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 3–47: Reserved for UEFI")]];
|
||||
reserved_MS : 12 [[comment("Bits 48–59: 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
789
patterns/DFIR/FAT32.hexpat
Normal 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
1571
patterns/DFIR/NTFS.hexpat
Normal file
File diff suppressed because it is too large
Load Diff
616
patterns/DFIR/exFAT.hexpat
Normal file
616
patterns/DFIR/exFAT.hexpat
Normal 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(" ");
|
||||
}
|
||||
165
patterns/Devil May Cry HD Collection/dmc3_hd_mod.hexpat
Normal file
165
patterns/Devil May Cry HD Collection/dmc3_hd_mod.hexpat
Normal 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
189
patterns/SHR.hexpat
Normal 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 there’s 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;
|
||||
176
patterns/adtfdat.hexpat
Normal file
176
patterns/adtfdat.hexpat
Normal 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;
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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") {
|
||||
|
||||
50
patterns/apple_single_double.hexpat
Normal file
50
patterns/apple_single_double.hexpat
Normal 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
168
patterns/bcss.hexpat
Normal 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;
|
||||
@@ -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;
|
||||
|
||||
@@ -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
533
patterns/blf.hexpat
Normal 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");
|
||||
|
||||
@@ -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
110
patterns/cab.hexpat
Normal 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] @ $;
|
||||
@@ -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
105
patterns/chd.hexpat
Normal 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;
|
||||
@@ -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;
|
||||
|
||||
158
patterns/commodore_basic.hexpat
Normal file
158
patterns/commodore_basic.hexpat
Normal 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;
|
||||
@@ -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")]];
|
||||
|
||||
@@ -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
165
patterns/dmc3_hd_mod.hexpat
Normal 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);
|
||||
@@ -1,4 +1,5 @@
|
||||
#pragma description Apple Disk Image Trailer (DMG)
|
||||
#pragma magic [ 6B 6F 6C 79 ] @ -512
|
||||
|
||||
#pragma endian big
|
||||
|
||||
|
||||
@@ -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
242
patterns/dos.hexpat
Normal 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.0–3.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; there’s some extra data
|
||||
* the CPU can see before the data in the EXE. What confused me for a bit was why
|
||||
* it’s 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;;
|
||||
921
patterns/dotnet_binaryformatter.hexpat
Normal file
921
patterns/dotnet_binaryformatter.hexpat
Normal 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;
|
||||
@@ -1,4 +1,5 @@
|
||||
#pragma description macOS .DS_Store
|
||||
#pragma magic [ 42 75 64 31 ] @ 0x04
|
||||
|
||||
// Apple macOS .DS_Store format
|
||||
#pragma endian big
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -497,14 +497,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 +644,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 +707,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 +741,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
119
patterns/esp32_image.hexpat
Normal 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;
|
||||
@@ -1,5 +1,5 @@
|
||||
#pragma description MS Windows Vista Event Log
|
||||
|
||||
#pragma MIME application/x-ms-evtx
|
||||
#pragma endian little
|
||||
|
||||
struct Header {
|
||||
|
||||
@@ -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] @ $;
|
||||
@@ -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] @ $;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#pragma author WerWolv
|
||||
#pragma description Flat Linux Device Tree blob
|
||||
#pragma magic [ D0 0D FE ED ] @ 0x00
|
||||
|
||||
#pragma endian big
|
||||
|
||||
|
||||
@@ -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
268
patterns/flc.hexpat
Normal 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
224
patterns/flv.hexpat
Normal 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]];
|
||||
@@ -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
1479
patterns/fs/apfs.hexpat
Normal file
File diff suppressed because it is too large
Load Diff
311
patterns/fs/exfat.hexpat
Normal file
311
patterns/fs/exfat.hexpat
Normal 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;
|
||||
@@ -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
108
patterns/fs/fat32.hexpat
Normal 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
997
patterns/fs/ntfs.hexpat
Normal 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
231
patterns/fs/pattern.hexpat
Normal 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;
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
229
patterns/gmf.hexpat
Normal 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;
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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
362
patterns/hprof.hexpat
Normal 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;
|
||||
@@ -2,9 +2,11 @@
|
||||
#pragma author xtex
|
||||
|
||||
#pragma description HiSilicon HSDT device-tree table
|
||||
#pragma endian little
|
||||
#pragma magic [ 48 53 44 54 ] @ 0x00
|
||||
|
||||
import std.sys;
|
||||
import std.mem;
|
||||
#pragma endian little
|
||||
|
||||
u32 dt_hdr_offset;
|
||||
if (std::mem::read_unsigned(4096, 4, std::mem::Endian::Little) == 0x54445348) {
|
||||
|
||||
@@ -4,6 +4,10 @@
|
||||
#pragma endian little
|
||||
|
||||
import std.sys;
|
||||
import std.mem;
|
||||
import std.string;
|
||||
import * from bmp as BMP;
|
||||
import * from png as PNG;
|
||||
|
||||
#pragma MIME image/vnd.microsoft.icon
|
||||
#pragma MIME image/x-icon
|
||||
@@ -13,38 +17,65 @@ import std.sys;
|
||||
#pragma MIME application/ico
|
||||
|
||||
enum ImageType : u16 {
|
||||
Icon = 1,
|
||||
Cursor = 2
|
||||
Icon = 1,
|
||||
Cursor = 2
|
||||
};
|
||||
|
||||
struct ICONDIR {
|
||||
u16 reserved [[hidden]];
|
||||
ImageType type;
|
||||
u16 num_images;
|
||||
u16 reserved [[hidden]];
|
||||
ImageType type;
|
||||
u16 num_images;
|
||||
};
|
||||
|
||||
struct BMPData {
|
||||
u8 data[sizeof(parent.raw_data)] [[hidden, no_unique_address]];
|
||||
std::mem::Section section = std::mem::create_section("BMP Image " + std::string::to_string(addressof(this)));
|
||||
std::mem::set_section_size(section, sizeof(data) + 14);
|
||||
u8 headerData[14] @ 0x00 in section [[hidden]];
|
||||
headerData[0x00] = 0x42;
|
||||
headerData[0x01] = 0x4D;
|
||||
u32 size @ 0x02 in section [[hidden]];
|
||||
size = std::mem::get_section_size(section);
|
||||
std::mem::copy_value_to_section(data, section, 0x0E);
|
||||
BMP image @ 0x00 in section;
|
||||
u32 offset @ 0x0D in section [[hidden]];
|
||||
offset = addressof(image.lineData);
|
||||
};
|
||||
|
||||
struct ImageData {
|
||||
u8 data[parent.image_data_size] [[inline]];
|
||||
std::mem::Bytes<parent.image_data_size> raw_data [[no_unique_address]];
|
||||
be u64 png_magic [[hidden, no_unique_address]];
|
||||
if (png_magic == 0x89504e470d0a1a0a) {
|
||||
PNG png_image @ $ [[inline, highlight_hidden]];
|
||||
}
|
||||
|
||||
// TODO: Sections currently can't be properly accessed accross imported types
|
||||
// TODO: Uncomment this again once that's been fixed
|
||||
/*else {
|
||||
BMPData data [[hidden]];
|
||||
BMP bmp_image @ addressof(this) - 14 [[inline, highlight_hidden]];
|
||||
}*/
|
||||
};
|
||||
|
||||
struct ICONDIRENTRY {
|
||||
u8 width, height;
|
||||
u8 num_colors;
|
||||
u8 reserved [[hidden]];
|
||||
u8 width, height;
|
||||
u8 num_colors;
|
||||
u8 reserved [[hidden]];
|
||||
|
||||
if (header.type == ImageType::Icon) {
|
||||
u16 color_planes;
|
||||
u16 bits_per_pixel;
|
||||
} else if (header.type == ImageType::Cursor) {
|
||||
u16 horizontal_hotspot_coordinate;
|
||||
u16 vertical_hotspot_coordinate;
|
||||
}
|
||||
if (header.type == ImageType::Icon) {
|
||||
u16 color_planes;
|
||||
u16 bits_per_pixel;
|
||||
} else if (header.type == ImageType::Cursor) {
|
||||
u16 horizontal_hotspot_coordinate;
|
||||
u16 vertical_hotspot_coordinate;
|
||||
}
|
||||
|
||||
u32 image_data_size;
|
||||
ImageData *image_data : u32;
|
||||
u32 image_data_size;
|
||||
u32 image_data_offset;
|
||||
ImageData image_data @ image_data_offset;
|
||||
};
|
||||
|
||||
ICONDIR header @ 0x00;
|
||||
ICONDIRENTRY images[header.num_images] @ $;
|
||||
|
||||
std::assert(header.reserved == 0x00, "Invalid ICO header");
|
||||
std::assert(header.reserved == 0x00, "Invalid ICO header");
|
||||
|
||||
52
patterns/imah.hexpat
Normal file
52
patterns/imah.hexpat
Normal file
@@ -0,0 +1,52 @@
|
||||
#pragma author Hrant (0xZ3R0)
|
||||
#pragma description DJI Encrypted/Signed Firmware (IM*H)
|
||||
#pragma endian little
|
||||
|
||||
// refs:
|
||||
// - "Challenges in Dynamic Analysis of Drone Firmware and Its Solutions" (DOI: 10.1109/ACCESS.2024.3425604)
|
||||
// - "Drone Security and the Mysterious Case of DJI’s DroneID" (DOI: 10.14722/ndss.2023.24217)
|
||||
// - https://github.com/o-gs/dji-firmware-tools
|
||||
|
||||
struct imah_chunk_header {
|
||||
s8 id[4];
|
||||
u32 offset;
|
||||
u32 size;
|
||||
u32 attrib;
|
||||
u64 address;
|
||||
u8 reserved[8];
|
||||
};
|
||||
|
||||
struct imah_header {
|
||||
s8 magic[4];
|
||||
u32 header_version;
|
||||
u32 size;
|
||||
u8 reserved[4];
|
||||
u32 header_size;
|
||||
u32 signature_size;
|
||||
u32 payload_size;
|
||||
u32 target_size;
|
||||
u8 os;
|
||||
u8 arch;
|
||||
u8 compression;
|
||||
u8 anti_version;
|
||||
u32 auth_alg;
|
||||
u8 auth_key[4];
|
||||
u8 enc_key[4];
|
||||
u8 scram_key[16];
|
||||
s8 name[32];
|
||||
u8 type[4];
|
||||
u32 version;
|
||||
u32 date;
|
||||
u32 encr_cksum;
|
||||
u8 reserved2[16];
|
||||
s8 userdata[16];
|
||||
u8 entry[8];
|
||||
u32 plain_cksum;
|
||||
u32 chunk_num;
|
||||
u8 payload_digest[32];
|
||||
};
|
||||
|
||||
imah_header header @ 0x00;
|
||||
imah_chunk_header chunks[header.chunk_num] @ addressof (header) + sizeof (header);
|
||||
u8 signature[header.signature_size] @ addressof (chunks) + sizeof (chunks);
|
||||
u8 payload_start @ addressof (signature) + sizeof (signature);
|
||||
@@ -7,6 +7,7 @@
|
||||
* values
|
||||
*/
|
||||
#pragma endian big
|
||||
#pragma MIME text/x-hex
|
||||
|
||||
import std.mem;
|
||||
|
||||
|
||||
@@ -1,28 +1,28 @@
|
||||
#pragma author gmestanley
|
||||
#pragma description IPS (International Patching System)
|
||||
#pragma magic [ 50 41 54 43 48 ] @ 0x00
|
||||
|
||||
#pragma endian big
|
||||
|
||||
import std.mem;
|
||||
import std.string;
|
||||
|
||||
struct Hunk {
|
||||
u24 offset;
|
||||
u16 length;
|
||||
if (!length) {
|
||||
u16 runCount;
|
||||
u8 payload;
|
||||
}
|
||||
else {
|
||||
u8 payload[length];
|
||||
}
|
||||
u24 offset;
|
||||
u16 length;
|
||||
if (!length) {
|
||||
u16 runCount;
|
||||
u8 payload;
|
||||
}
|
||||
else {
|
||||
u8 payload[length];
|
||||
}
|
||||
};
|
||||
|
||||
struct IPS {
|
||||
char signature[5];
|
||||
Hunk hunks[while($ < std::mem::size() - (3 + 3 * (std::mem::read_string(std::mem::size()-3, 3) != "EOF")))];
|
||||
char eof[3];
|
||||
u24 truncatedSize[3+(std::mem::read_string(std::mem::size()-3, 3) != "EOF")>3];
|
||||
char signature[5];
|
||||
Hunk hunks[while($ < std::mem::size() - (3 + 3 * (std::mem::read_string(std::mem::size()-3, 3) != "EOF")))];
|
||||
char eof[3];
|
||||
u24 truncatedSize[std::mem::read_string(std::mem::size()-3, 3) != "EOF"];
|
||||
};
|
||||
|
||||
IPS ips @ 0x00;
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
#pragma description ISO 9660 file system
|
||||
#pragma MIME application/x-iso9660-image
|
||||
|
||||
#pragma endian little
|
||||
|
||||
import std.io;
|
||||
import std.mem;
|
||||
|
||||
enum VolumeDescriptorTypes : u8 {
|
||||
BootRecord,
|
||||
@@ -95,6 +97,19 @@ struct DirectoryRecord {
|
||||
u8 fileNameLen;
|
||||
char fileName[fileNameLen];
|
||||
padding[$ % 2];
|
||||
u8 remainingSize = $ - addressof(this);
|
||||
if (recordSize > remainingSize) {
|
||||
u8 systemUse[recordSize - remainingSize];
|
||||
}
|
||||
};
|
||||
|
||||
fn GetSupplementaryEncoding() {
|
||||
const u128 escapeSequencesOffset = 89 - 8;
|
||||
|
||||
str encoding = std::mem::read_string($ + escapeSequencesOffset, 0x20);
|
||||
return encoding == "%/@\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
|
||||
|| encoding == "%/C\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
|
||||
|| encoding == "%/E\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
|
||||
};
|
||||
|
||||
struct VolumeDescriptor {
|
||||
@@ -127,8 +142,37 @@ struct VolumeDescriptor {
|
||||
StrDateFormat expirationTime[[format("FormatStrDate")]];
|
||||
StrDateFormat effectiveTime[[format("FormatStrDate")]];
|
||||
u8 fileStructVersion;
|
||||
padding[0x200 + 0x28E];
|
||||
} else if (type == VolumeDescriptorTypes::SupplementaryVolume && GetSupplementaryEncoding()) {
|
||||
u8 flags;
|
||||
be char16 systemId[0x10];
|
||||
be char16 volumeId[0x10];
|
||||
padding[8];
|
||||
di32 spaceSize;
|
||||
u8 escapeSequences[0x20];
|
||||
di16 setSize;
|
||||
di16 sequenceNumber;
|
||||
di16 logicalBlockSize;
|
||||
di32 pathTableSize;
|
||||
PathTablePtr pathTableOffset;
|
||||
DirectoryRecord rootDir;
|
||||
be char16 setId[0x40];
|
||||
be char16 publisherId[0x40];
|
||||
be char16 preparerId[0x40];
|
||||
be char16 applicationId[0x40];
|
||||
be char16 copyrightFileId[0x12];
|
||||
padding[1];
|
||||
be char16 abstractFileId[0x12];
|
||||
padding[1];
|
||||
be char16 bibliographicFileId[0x12];
|
||||
padding[1];
|
||||
StrDateFormat creationTime[[format("FormatStrDate")]];
|
||||
StrDateFormat modificationTime[[format("FormatStrDate")]];
|
||||
StrDateFormat expirationTime[[format("FormatStrDate")]];
|
||||
StrDateFormat effectiveTime[[format("FormatStrDate")]];
|
||||
u8 fileStructVersion;
|
||||
}
|
||||
padding[0x800 - $ % 0x800];
|
||||
};
|
||||
|
||||
VolumeDescriptor data @ 0x8000;
|
||||
VolumeDescriptor descriptors[while(std::mem::read_unsigned($, 1) != 0xFF)] @ 0x8000;
|
||||
VolumeDescriptor terminator @ $;
|
||||
@@ -117,7 +117,10 @@ namespace fmt {
|
||||
};
|
||||
|
||||
fn const_ref(u2 index) {
|
||||
cp_info info = file.constant_pool[index-1];
|
||||
return fmt::format_info_const_ref(index, file.constant_pool[index-1]);
|
||||
};
|
||||
|
||||
fn format_info_const_ref(u2 index, ref auto info) {
|
||||
match(info.tag) {
|
||||
(1): return info.bytes;
|
||||
(3): return std::format("{:d} [{:d}]", index, info.bytes);
|
||||
@@ -140,7 +143,10 @@ namespace fmt {
|
||||
};
|
||||
|
||||
fn const_ref_top(u2 index) {
|
||||
cp_info info = file.constant_pool[index-1];
|
||||
return fmt::format_info_const_ref_top(index, file.constant_pool[index-1]);
|
||||
};
|
||||
|
||||
fn format_info_const_ref_top(u2 index, ref auto info) {
|
||||
match(info.tag) {
|
||||
(1): return std::format("{:d} [{:s}]", index, info.bytes);
|
||||
(_): return fmt::const_ref(index);
|
||||
@@ -444,6 +450,15 @@ enum major_version : u2 {
|
||||
Java_SE_15 = 59,
|
||||
Java_SE_16 = 60,
|
||||
Java_SE_17 = 61,
|
||||
Java_SE_18 = 62,
|
||||
Java_SE_19 = 63,
|
||||
Java_SE_20 = 64,
|
||||
Java_SE_21 = 65,
|
||||
Java_SE_22 = 66,
|
||||
Java_SE_23 = 67,
|
||||
Java_SE_24 = 68,
|
||||
Java_SE_25 = 69,
|
||||
Java_SE_26 = 70,
|
||||
};
|
||||
|
||||
bitfield access_flags_method {
|
||||
|
||||
@@ -145,6 +145,7 @@ struct Segment {
|
||||
u16 length;
|
||||
if (marker == Marker::APP0) {
|
||||
APP0 data;
|
||||
u8 xtra_data[length - sizeof(length) - sizeof(data)];
|
||||
} else if (marker == Marker::APP14) {
|
||||
APP14 data;
|
||||
} else if (marker == Marker::COM) {
|
||||
|
||||
363
patterns/kindle_update.hexpat
Normal file
363
patterns/kindle_update.hexpat
Normal file
@@ -0,0 +1,363 @@
|
||||
#pragma author ptrpaws
|
||||
#pragma description Kindle Update Package
|
||||
#pragma magic [ 53 50 30 31 ] @ 0x00 // "SP01"
|
||||
#pragma endian little
|
||||
|
||||
// enums and structs are based on KindleTool source code by Yifan Lu & NiLuJe
|
||||
|
||||
enum Magic : u32 {
|
||||
SP01 = 0x31305053,
|
||||
FB01 = 0x31304246,
|
||||
FB02 = 0x32304246,
|
||||
FB03 = 0x33304246,
|
||||
FC02 = 0x32304346,
|
||||
FC04 = 0x34304346,
|
||||
FD03 = 0x33304446,
|
||||
FD04 = 0x34304446,
|
||||
FL01 = 0x31304C46,
|
||||
GZIP = 0x00088B1F,
|
||||
ZIP = 0x04034B50,
|
||||
CB01 = 0x31304243,
|
||||
};
|
||||
|
||||
enum Device : u16 {
|
||||
KindleUnknown = 0x00,
|
||||
Kindle1 = 0x01,
|
||||
Kindle2US = 0x02,
|
||||
Kindle2International = 0x03,
|
||||
KindleDXUS = 0x04,
|
||||
KindleDXInternational = 0x05,
|
||||
Kindle3WiFi3G = 0x06,
|
||||
ValidKindleUnknown_0x07 = 0x07,
|
||||
Kindle3WiFi = 0x08,
|
||||
KindleDXGraphite = 0x09,
|
||||
Kindle3WiFi3GEurope = 0x0A,
|
||||
ValidKindleUnknown_0x0B = 0x0B,
|
||||
ValidKindleUnknown_0x0C = 0x0C,
|
||||
ValidKindleUnknown_0x0D = 0x0D,
|
||||
Kindle4NonTouch = 0x0E,
|
||||
Kindle5TouchWiFi3G = 0x0F,
|
||||
Kindle5TouchWiFi3GEurope = 0x10,
|
||||
Kindle5TouchWiFi = 0x11,
|
||||
Kindle5TouchUnknown = 0x12,
|
||||
KindleVoyageWiFi = 0x13,
|
||||
ValidKindleUnknown_0x16 = 0x16,
|
||||
KindlePaperWhite2WiFi4GBInternational = 0x17,
|
||||
KindlePaperWhiteWiFi3G = 0x1B,
|
||||
KindlePaperWhiteWiFi3GCanada = 0x1C,
|
||||
KindlePaperWhiteWiFi3GEurope = 0x1D,
|
||||
KindlePaperWhiteWiFi3GJapan = 0x1F,
|
||||
KindlePaperWhiteWiFi3GBrazil = 0x20,
|
||||
ValidKindleUnknown_0x21 = 0x21,
|
||||
Kindle4NonTouchBlack = 0x23,
|
||||
KindlePaperWhiteWiFi = 0x24,
|
||||
KindleVoyageWiFi3GJapan = 0x2A,
|
||||
KindleVoyageWiFi3G_0x4F = 0x4F,
|
||||
KindleVoyageWiFi3GMexico = 0x52,
|
||||
KindleVoyageWiFi3GEurope = 0x53,
|
||||
KindleVoyageWiFi3G = 0x54,
|
||||
KindlePaperWhite2WiFiJapan = 0x5A,
|
||||
KindlePaperWhite2WiFi3G4GBCanada = 0x5F,
|
||||
KindlePaperWhite2WiFi3G4GBEurope = 0x60,
|
||||
KindlePaperWhite2WiFi3G4GBBrazil = 0x61,
|
||||
KindlePaperWhite2WiFi3G4GB = 0x62,
|
||||
ValidKindleUnknown_0x99 = 0x99,
|
||||
KindleBasic = 0xC6,
|
||||
KindlePaperWhite2WiFi = 0xD4,
|
||||
KindlePaperWhite2WiFi3G = 0xD5,
|
||||
KindlePaperWhite2WiFi3GCanada = 0xD6,
|
||||
KindlePaperWhite2WiFi3GEurope = 0xD7,
|
||||
KindlePaperWhite2WiFi3GRussia = 0xD8,
|
||||
KindleBasicKiwi = 0xDD,
|
||||
KindlePaperWhite2WiFi3GJapan = 0xF2,
|
||||
KindlePaperWhite2Unknown_0xF4 = 0xF4,
|
||||
KindlePaperWhite2Unknown_0xF9 = 0xF9,
|
||||
KindleBasic2Unknown_0DU = 0x1BC,
|
||||
KindlePaperWhite3WiFi = 0x201,
|
||||
KindlePaperWhite3WiFi3G = 0x202,
|
||||
KindlePaperWhite3WiFi3GMexico = 0x204,
|
||||
KindlePaperWhite3WiFi3GEurope = 0x205,
|
||||
KindlePaperWhite3WiFi3GCanada = 0x206,
|
||||
KindlePaperWhite3WiFi3GJapan = 0x207,
|
||||
KindleOasisWiFi = 0x20C,
|
||||
KindleOasisWiFi3G = 0x20D,
|
||||
KindleOasisWiFi3GInternational = 0x219,
|
||||
KindleOasisUnknown_0GS = 0x21A,
|
||||
KindleOasisWiFi3GChina = 0x21B,
|
||||
KindleOasisWiFi3GEurope = 0x21C,
|
||||
KindleBasic2 = 0x269,
|
||||
KindleBasic2White = 0x26A,
|
||||
KindlePaperWhite3WhiteWiFi = 0x26B,
|
||||
KindlePaperWhite3WhiteWiFi3GJapan = 0x26C,
|
||||
KindlePW3WhiteUnknown_0KD = 0x26D,
|
||||
KindlePaperWhite3WhiteWiFi3GInternational = 0x26E,
|
||||
KindlePaperWhite3WhiteWiFi3GInternationalBis = 0x26F,
|
||||
KindlePW3WhiteUnknown_0KG = 0x270,
|
||||
KindlePaperWhite3BlackWiFi32GBJapan = 0x293,
|
||||
KindlePaperWhite3WhiteWiFi32GBJapan = 0x294,
|
||||
KindleOasis2Unknown_0LM = 0x295,
|
||||
KindleOasis2Unknown_0LN = 0x296,
|
||||
KindleOasis2Unknown_0LP = 0x297,
|
||||
KindleOasis2Unknown_0LQ = 0x298,
|
||||
KindleOasis2WiFi32GBChampagne = 0x2E1,
|
||||
KindleOasis2Unknown_0P2 = 0x2E2,
|
||||
KindleOasis2Unknown_0P6 = 0x2E6,
|
||||
KindleOasis2Unknown_0P7 = 0x2E7,
|
||||
KindleOasis2WiFi8GB = 0x2E8,
|
||||
KindlePW4Unknown_0PL = 0x2F4,
|
||||
KindlePaperWhite4WiFi8GB = 0x2F7,
|
||||
KindleOasis2WiFi3G32GB = 0x341,
|
||||
KindleOasis2WiFi3G32GBEurope = 0x342,
|
||||
KindleOasis2Unknown_0S3 = 0x343,
|
||||
KindleOasis2Unknown_0S4 = 0x344,
|
||||
KindleOasis2Unknown_0S7 = 0x347,
|
||||
KindleOasis2WiFi32GB = 0x34A,
|
||||
KindlePaperWhite4WiFi4G32GB = 0x361,
|
||||
KindlePaperWhite4WiFi4G32GBEurope = 0x362,
|
||||
KindlePaperWhite4WiFi4G32GBJapan = 0x363,
|
||||
KindlePaperWhite4Unknown_0T4 = 0x364,
|
||||
KindlePaperWhite4Unknown_0T5 = 0x365,
|
||||
KindlePaperWhite4WiFi32GB = 0x366,
|
||||
KindlePaperWhite4Unknown_0T7 = 0x367,
|
||||
KindlePaperWhite4Unknown_0TJ = 0x372,
|
||||
KindlePaperWhite4Unknown_0TK = 0x373,
|
||||
KindlePaperWhite4Unknown_0TL = 0x374,
|
||||
KindlePaperWhite4Unknown_0TM = 0x375,
|
||||
KindlePaperWhite4Unknown_0TN = 0x376,
|
||||
KindleBasic3White8GB = 0x3CF,
|
||||
KindleBasic3Unknown_0WG = 0x3D0,
|
||||
KindleBasic3White = 0x3D1,
|
||||
KindleBasic3Unknown_0WJ = 0x3D2,
|
||||
KindleOasis3WiFi8GB = 0x3D4,
|
||||
KindleOasis3WiFi32GB = 0x3D5,
|
||||
KindleOasis3WiFi4G32GB = 0x3D6,
|
||||
KindleOasis3WiFi4G32GBIndia = 0x3D7,
|
||||
KindleOasis3WiFi4G32GBJapan = 0x3D8,
|
||||
KindleBasic3KidsEdition = 0x3AB,
|
||||
KindlePaperWhite4WiFi8GBIndia = 0x402,
|
||||
KindlePaperWhite4WiFi32GBIndia = 0x403,
|
||||
KindleBasic3 = 0x414,
|
||||
KindleOasis3WiFi32GBChampagne = 0x434,
|
||||
KindlePaperWhite4WiFi32GBBlue = 0x4D8,
|
||||
KindlePaperWhite4WiFi32GBPlum = 0x4D9,
|
||||
KindlePaperWhite4WiFi32GBSage = 0x4DA,
|
||||
KindlePaperWhite4WiFi8GBBlue = 0x4DB,
|
||||
KindlePaperWhite4WiFi8GBPlum = 0x4DC,
|
||||
KindlePaperWhite4WiFi8GBSage = 0x4DD,
|
||||
KindlePaperWhite5SignatureEdition = 0x690,
|
||||
KindlePaperWhite5 = 0x6FF,
|
||||
KindlePaperWhite5Unknown_1Q0 = 0x700,
|
||||
KindlePaperWhite5Unknown_1VD = 0x7AD,
|
||||
KindleBasic4Unknown_1XH = 0x7F1,
|
||||
KindlePaperWhite5SE_219 = 0x829,
|
||||
KindlePaperWhite5_21A = 0x82A,
|
||||
KindleScribe16GB_227 = 0x847,
|
||||
KindleBasic4Unknown_22C = 0x84C,
|
||||
KindleBasic4Unknown_22D = 0x84D,
|
||||
KindleBasic4Unknown_23A = 0x86A,
|
||||
KindleScribe_23L = 0x874,
|
||||
KindleScribe64GB_23M = 0x875,
|
||||
KindleBasic4Unknown_25T = 0x8BB,
|
||||
KindleScribeUnknown_263 = 0x8C3,
|
||||
KindleScribeUnknown_270 = 0x8E0,
|
||||
KindleScribeUnknown_27J = 0x8F2,
|
||||
KindleBasic4_2AP = 0x957,
|
||||
KindleBasic4_2AQ = 0x958,
|
||||
KindlePaperWhite5SE_2BH = 0x971,
|
||||
KindlePaperWhite5Unknown_2BJ = 0x972,
|
||||
KindleScribeUnknown_2BL = 0x974,
|
||||
KindleScribeUnknown_2BM = 0x975,
|
||||
KindlePaperWhite5_2DK = 0x9B3,
|
||||
KindlePaperWhite6Unknown_33W = 0xC7E,
|
||||
KindlePaperWhite6Unknown_33X = 0xC7F,
|
||||
KindlePaperWhite6Unknown_346 = 0xC86,
|
||||
KindlePaperWhite6Unknown_349 = 0xC89,
|
||||
KindleColorSoftUnknown_34X = 0xC9F,
|
||||
KindleColorSoftUnknown_3H2 = 0xE22,
|
||||
KindlePaperWhite6Unknown_3H3 = 0xE23,
|
||||
KindleColorSoftUnknown_3H4 = 0xE24,
|
||||
KindlePaperWhite6Unknown_3H5 = 0xE25,
|
||||
KindleColorSoftUnknown_3H6 = 0xE26,
|
||||
KindleColorSoftUnknown_3H7 = 0xE27,
|
||||
KindlePaperWhite6Unknown_3H8 = 0xE28,
|
||||
KindleColorSoftUnknown_3H9 = 0xE29,
|
||||
KindlePaperWhite6Unknown_3HA = 0xE2A,
|
||||
KindleColorSoftUnknown_3HB = 0xE2B,
|
||||
KindlePaperWhite6Unknown_3J5 = 0xE45,
|
||||
KindleColorSoftUnknown_3J6 = 0xE46,
|
||||
KindlePaperWhite6Unknown_3JS = 0xE5A,
|
||||
KindleColorSoftUnknown_3JT = 0xE5B,
|
||||
KindleBasic5Unknown_3KM = 0xE75,
|
||||
KindleBasic5Unknown_3L2 = 0xE82,
|
||||
KindleBasic5Unknown_3L3 = 0xE83,
|
||||
KindleBasic5Unknown_3L4 = 0xE84,
|
||||
KindleBasic5Unknown_3L5 = 0xE85,
|
||||
KindleBasic5Unknown_3L6 = 0xE86,
|
||||
KindleScribe2Unknown_3UV = 0xF9D,
|
||||
KindleScribe2Unknown_3V0 = 0xFA0,
|
||||
KindleScribe2Unknown_3V1 = 0xFA1,
|
||||
KindleScribe2Unknown_3X3 = 0xFE3,
|
||||
KindleScribe2Unknown_3X4 = 0xFE4,
|
||||
KindleScribe2Unknown_3X5 = 0xFE5,
|
||||
KindleScribe2Unknown_41D = 0x102D,
|
||||
KindleScribe2Unknown_41E = 0x102E,
|
||||
KindleColorSoftUnknown_455 = 0x10A5,
|
||||
KindleColorSoftUnknown_456 = 0x10A6,
|
||||
KindleColorSoftUnknown_4EP = 0x11D7,
|
||||
KindleBasic5Unknown_A89 = 0x2909,
|
||||
KindlePW3Unknown_TTT = 0x6F7B,
|
||||
};
|
||||
|
||||
enum Platform : u32 {
|
||||
Plat_Unspecified = 0x00, MarioDeprecated = 0x01, Luigi = 0x02,
|
||||
Banjo = 0x03, Yoshi = 0x04, YoshimeProto = 0x05,
|
||||
Yoshime = 0x06, Wario = 0x07, Duet = 0x08,
|
||||
Heisenberg = 0x09, Zelda = 0x0A, Rex = 0x0B,
|
||||
Bellatrix = 0x0C, Bellatrix3 = 0x0D, Bellatrix4 = 0x0E,
|
||||
};
|
||||
|
||||
enum Board : u32 {
|
||||
Board_Unspecified = 0x00,
|
||||
Tequila = 0x03,
|
||||
Whitney = 0x05,
|
||||
};
|
||||
|
||||
enum CertificateNumber : u32 {
|
||||
Developer = 0x00,
|
||||
Official_1K = 0x01,
|
||||
Official_2K = 0x02,
|
||||
};
|
||||
|
||||
const u8 gtop[256] = {
|
||||
0xa7, 0xb7, 0x87, 0x97, 0xe7, 0xf7, 0xc7, 0xd7, 0x27, 0x37, 0x07, 0x17, 0x67, 0x77, 0x47, 0x57, 0xa6, 0xb6, 0x86,
|
||||
0x96, 0xe6, 0xf6, 0xc6, 0xd6, 0x26, 0x36, 0x06, 0x16, 0x66, 0x76, 0x46, 0x56, 0xa5, 0xb5, 0x85, 0x95, 0xe5, 0xf5,
|
||||
0xc5, 0xd5, 0x25, 0x35, 0x05, 0x15, 0x65, 0x75, 0x45, 0x55, 0xa4, 0xb4, 0x84, 0x94, 0xe4, 0xf4, 0xc4, 0xd4, 0x24,
|
||||
0x34, 0x04, 0x14, 0x64, 0x74, 0x44, 0x54, 0xa3, 0xb3, 0x83, 0x93, 0xe3, 0xf3, 0xc3, 0xd3, 0x23, 0x33, 0x03, 0x13,
|
||||
0x63, 0x73, 0x43, 0x53, 0xa2, 0xb2, 0x82, 0x92, 0xe2, 0xf2, 0xc2, 0xd2, 0x22, 0x32, 0x02, 0x12, 0x62, 0x72, 0x42,
|
||||
0x52, 0xa1, 0xb1, 0x81, 0x91, 0xe1, 0xf1, 0xc1, 0xd1, 0x21, 0x31, 0x01, 0x11, 0x61, 0x71, 0x41, 0x51, 0xa0, 0xb0,
|
||||
0x80, 0x90, 0xe0, 0xf0, 0xc0, 0xd0, 0x20, 0x30, 0x00, 0x10, 0x60, 0x70, 0x40, 0x50, 0xaf, 0xbf, 0x8f, 0x9f, 0xef,
|
||||
0xff, 0xcf, 0xdf, 0x2f, 0x3f, 0x0f, 0x1f, 0x6f, 0x7f, 0x4f, 0x5f, 0xae, 0xbe, 0x8e, 0x9e, 0xee, 0xfe, 0xce, 0xde,
|
||||
0x2e, 0x3e, 0x0e, 0x1e, 0x6e, 0x7e, 0x4e, 0x5e, 0xad, 0xbd, 0x8d, 0x9d, 0xed, 0xfd, 0xcd, 0xdd, 0x2d, 0x3d, 0x0d,
|
||||
0x1d, 0x6d, 0x7d, 0x4d, 0x5d, 0xac, 0xbc, 0x8c, 0x9c, 0xec, 0xfc, 0xcc, 0xdc, 0x2c, 0x3c, 0x0c, 0x1c, 0x6c, 0x7c,
|
||||
0x4c, 0x5c, 0xab, 0xbb, 0x8b, 0x9b, 0xeb, 0xfb, 0xcb, 0xdb, 0x2b, 0x3b, 0x0b, 0x1b, 0x6b, 0x7b, 0x4b, 0x5b, 0xaa,
|
||||
0xba, 0x8a, 0x9a, 0xea, 0xfa, 0xca, 0xda, 0x2a, 0x3a, 0x0a, 0x1a, 0x6a, 0x7a, 0x4a, 0x5a, 0xa9, 0xb9, 0x89, 0x99,
|
||||
0xe9, 0xf9, 0xc9, 0xd9, 0x29, 0x39, 0x09, 0x19, 0x69, 0x79, 0x49, 0x59, 0xa8, 0xb8, 0x88, 0x98, 0xe8, 0xf8, 0xc8,
|
||||
0xd8, 0x28, 0x38, 0x08, 0x18, 0x68, 0x78, 0x48, 0x58
|
||||
};
|
||||
|
||||
fn format_md5(auto m) {
|
||||
str result = "";
|
||||
for(u8 i = 0, i < sizeof(m), i += 1) {
|
||||
result += char(gtop[m[i]]);
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
struct UpdateSignatureHeader {
|
||||
CertificateNumber certificate_number;
|
||||
u8 reserved[56] [[hidden]];
|
||||
};
|
||||
|
||||
struct UpdateSignaturePackage {
|
||||
UpdateSignatureHeader header;
|
||||
match (header.certificate_number) {
|
||||
(CertificateNumber::Developer) : u8 signature[128];
|
||||
(CertificateNumber::Official_1K) : u8 signature[128];
|
||||
(CertificateNumber::Official_2K) : u8 signature[256];
|
||||
(_) : {
|
||||
std::error("Unknown certificate type.");
|
||||
u8 signature[0];
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct RecoveryUpdateV2Package {
|
||||
padding[4];
|
||||
u64 target_revision;
|
||||
u8 md5_sum[32] [[format("format_md5")]];
|
||||
u32 magic_1;
|
||||
u32 magic_2;
|
||||
u32 minor;
|
||||
Platform platform;
|
||||
u32 header_rev;
|
||||
Board board;
|
||||
padding[7];
|
||||
u8 num_devices;
|
||||
Device devices[num_devices];
|
||||
};
|
||||
|
||||
struct OTAUpdatePackage {
|
||||
u32 source_revision;
|
||||
u32 target_revision;
|
||||
Device device;
|
||||
u8 optional;
|
||||
u8 unused;
|
||||
u8 md5_sum[32] [[format("format_md5")]];
|
||||
};
|
||||
|
||||
struct RecoveryUpdatePackage {
|
||||
u8 unused[12];
|
||||
u8 md5_sum[32] [[format("format_md5")]];
|
||||
u32 magic_1;
|
||||
u32 magic_2;
|
||||
u32 minor;
|
||||
Device device;
|
||||
};
|
||||
|
||||
struct MetaString {
|
||||
be u16 length;
|
||||
char value[length];
|
||||
};
|
||||
|
||||
struct OTAUpdateV2Package {
|
||||
u64 source_revision;
|
||||
u64 target_revision;
|
||||
u16 num_devices;
|
||||
Device devices[num_devices];
|
||||
u8 critical;
|
||||
u8 padding_byte;
|
||||
u8 md5_sum[32] [[format("format_md5")]];
|
||||
u16 num_metadata;
|
||||
MetaString metadata[num_metadata];
|
||||
};
|
||||
|
||||
struct GenericPayload {
|
||||
u8 data[];
|
||||
};
|
||||
|
||||
struct FirmwarePayload {
|
||||
Magic magic;
|
||||
|
||||
match (magic) {
|
||||
(Magic::FB03) : RecoveryUpdateV2Package recovery_v2 [[name("Recovery V2 Header (FB03)")]];
|
||||
(Magic::FC04) : OTAUpdateV2Package ota_v2 [[name("OTA V2 Header (FC04/FD04/FL01)")]];
|
||||
(Magic::FD04) : OTAUpdateV2Package ota_v2_fd04 [[name("OTA V2 Header (FC04/FD04/FL01)")]];
|
||||
(Magic::FL01) : OTAUpdateV2Package ota_v2_fl01 [[name("OTA V2 Header (FC04/FD04/FL01)")]];
|
||||
(Magic::FC02) : OTAUpdatePackage ota_v1 [[name("OTA V1 Header (FC02/FD03)")]];
|
||||
(Magic::FD03) : OTAUpdatePackage ota_v1_fd03 [[name("OTA V1 Header (FC02/FD03)")]];
|
||||
(Magic::FB01) : RecoveryUpdatePackage recovery_v1 [[name("Recovery V1 Header (FB01/FB02)")]];
|
||||
(Magic::FB02) : RecoveryUpdatePackage recovery_v1_fb02 [[name("Recovery V1 Header (FB01/FB02)")]];
|
||||
(Magic::GZIP) : GenericPayload userdata_gzip [[name("UserData Package (GZIP)")]];
|
||||
(Magic::ZIP) : GenericPayload android_zip [[name("Android Update (ZIP)")]];
|
||||
(Magic::CB01) : GenericPayload component_update [[name("Component Update (CB01)")]];
|
||||
(_) : {
|
||||
std::warning("Unsupported inner package type.");
|
||||
u8 unknown_payload_header[0];
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct KindleFirmware {
|
||||
Magic magic;
|
||||
|
||||
if (magic == Magic::SP01) {
|
||||
UpdateSignaturePackage signature_package [[name("Signature Wrapper (SP01)")]];
|
||||
FirmwarePayload payload;
|
||||
} else {
|
||||
// not a signed SP01 package
|
||||
$ -= sizeof(magic);
|
||||
FirmwarePayload payload;
|
||||
}
|
||||
};
|
||||
|
||||
KindleFirmware file @ 0x00;
|
||||
231
patterns/ktx.hexpat
Normal file
231
patterns/ktx.hexpat
Normal file
@@ -0,0 +1,231 @@
|
||||
#pragma author Lexi Mayfield
|
||||
#pragma description Khronos TeXture 1.0
|
||||
#pragma MIME image/ktx
|
||||
#pragma magic [ AB 4B 54 58 20 31 31 BB 0D 0A 1A 0A ] @ 0x00
|
||||
|
||||
import std.io;
|
||||
import std.mem;
|
||||
import type.magic;
|
||||
|
||||
enum GLType : u32 {
|
||||
compressed = 0x0,
|
||||
UNSIGNED_BYTE = 0x1401,
|
||||
BYTE = 0x1400,
|
||||
UNSIGNED_SHORT = 0x1403,
|
||||
SHORT = 0x1402,
|
||||
UNSIGNED_INT = 0x1405,
|
||||
INT = 0x1404,
|
||||
HALF_FLOAT = 0x140B,
|
||||
FLOAT = 0x1406,
|
||||
UNSIGNED_BYTE_3_3_2 = 0x8032,
|
||||
UNSIGNED_BYTE_2_3_3_REV = 0x8362,
|
||||
UNSIGNED_SHORT_5_6_5 = 0x8363,
|
||||
UNSIGNED_SHORT_5_6_5_REV = 0x8364,
|
||||
UNSIGNED_SHORT_4_4_4_4 = 0x8033,
|
||||
UNSIGNED_SHORT_4_4_4_4_REV = 0x8365,
|
||||
UNSIGNED_SHORT_5_5_5_1 = 0x8034,
|
||||
UNSIGNED_SHORT_1_5_5_5_REV = 0x8366,
|
||||
UNSIGNED_INT_8_8_8_8 = 0x8035,
|
||||
UNSIGNED_INT_8_8_8_8_REV = 0x8367,
|
||||
UNSIGNED_INT_10_10_10_2 = 0x8036,
|
||||
UNSIGNED_INT_2_10_10_10_REV = 0x8368,
|
||||
UNSIGNED_INT_24_8 = 0x84FA,
|
||||
UNSIGNED_INT_10F_11F_11F_REV = 0x8C3B,
|
||||
UNSIGNED_INT_5_9_9_9_REV = 0x8C3E,
|
||||
FLOAT_32_UNSIGNED_INT_24_8_REV = 0x8DAD,
|
||||
};
|
||||
|
||||
enum GLFormat : u32 {
|
||||
compressed = 0x0,
|
||||
RED = 0x1903,
|
||||
RG = 0x8227,
|
||||
RGB = 0x1907,
|
||||
BGR = 0x80E0,
|
||||
RGBA = 0x1908,
|
||||
BGRA = 0x80E1,
|
||||
RED_INTEGER = 0x8D94,
|
||||
RG_INTEGER = 0x8228,
|
||||
RGB_INTEGER = 0x8D98,
|
||||
BGR_INTEGER = 0x8D9A,
|
||||
RGBA_INTEGER = 0x8D99,
|
||||
BGRA_INTEGER = 0x8D9B,
|
||||
STENCIL_INDEX = 0x1901,
|
||||
DEPTH_COMPONENT = 0x1902,
|
||||
DEPTH_STENCIL = 0x84F9,
|
||||
};
|
||||
|
||||
enum GLInternalFormat : u32 {
|
||||
R8 = 0x8229,
|
||||
R8_SNORM = 0x8F94,
|
||||
R16 = 0x822A,
|
||||
R16_SNORM = 0x8F98,
|
||||
RG8 = 0x822B,
|
||||
RG8_SNORM = 0x8F95,
|
||||
RG16 = 0x822C,
|
||||
RG16_SNORM = 0x8F99,
|
||||
R3_G3_B2 = 0x2A10,
|
||||
RGB4 = 0x804F,
|
||||
RGB5 = 0x8050,
|
||||
RGB8 = 0x8051,
|
||||
RGB8_SNORM = 0x8F96,
|
||||
RGB10 = 0x8052,
|
||||
RGB12 = 0x8053,
|
||||
RGB16_SNORM = 0x8F9A,
|
||||
RGBA2 = 0x8055,
|
||||
RGBA4 = 0x8056,
|
||||
RGB5_A1 = 0x8057,
|
||||
RGBA8 = 0x8058,
|
||||
RGBA8_SNORM = 0x8F97,
|
||||
RGB10_A2 = 0x8059,
|
||||
RGB10_A2UI = 0x906F,
|
||||
RGBA12 = 0x805A,
|
||||
RGBA16 = 0x805B,
|
||||
SRGB8 = 0x8C41,
|
||||
SRGB8_ALPHA8 = 0x8C43,
|
||||
R16F = 0x822D,
|
||||
RG16F = 0x822F,
|
||||
RGB16F = 0x881B,
|
||||
RGBA16F = 0x881A,
|
||||
R32F = 0x822E,
|
||||
RG32F = 0x8230,
|
||||
RGB32F = 0x8815,
|
||||
RGBA32F = 0x8814,
|
||||
R11F_G11F_B10F = 0x8C3A,
|
||||
RGB9_E5 = 0x8C3D,
|
||||
R8I = 0x8231,
|
||||
R8UI = 0x8232,
|
||||
R16I = 0x8233,
|
||||
R16UI = 0x8234,
|
||||
R32I = 0x8235,
|
||||
R32UI = 0x8236,
|
||||
RG8I = 0x8237,
|
||||
RG8UI = 0x8238,
|
||||
RG16I = 0x8239,
|
||||
RG16UI = 0x823A,
|
||||
RG32I = 0x823B,
|
||||
RG32UI = 0x823C,
|
||||
RGB8I = 0x8D8F,
|
||||
RGB8UI = 0x8D7D,
|
||||
RGB16I = 0x8D89,
|
||||
RGB16UI = 0x8D77,
|
||||
RGB32I = 0x8D83,
|
||||
RGB32UI = 0x8D71,
|
||||
RGBA8I = 0x8D8E,
|
||||
RGBA8UI = 0x8D7C,
|
||||
RGBA16I = 0x8D88,
|
||||
RGBA16UI = 0x8D76,
|
||||
RGBA32I = 0x8D82,
|
||||
RGBA32UI = 0x8D70,
|
||||
COMPRESSED_RGB_S3TC_DXT1_EXT = 0x83F0, // BC1
|
||||
COMPRESSED_RGBA_S3TC_DXT1_EXT = 0x83F1, // BC1
|
||||
COMPRESSED_RGBA_S3TC_DXT3_EXT = 0x83F2, // BC2
|
||||
COMPRESSED_RGBA_S3TC_DXT5_EXT = 0x83F3, // BC3
|
||||
COMPRESSED_SRGB_S3TC_DXT1_EXT = 0x8C4C, // BC1
|
||||
COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT = 0x8C4D, // BC1
|
||||
COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT = 0x8C4E, // BC2
|
||||
COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT = 0x8C4F, // BC3
|
||||
COMPRESSED_RED_RGTC1 = 0x8DBB, // BC4
|
||||
COMPRESSED_SIGNED_RED_RGTC1 = 0x8DBC, // BC4
|
||||
COMPRESSED_RG_RGTC2 = 0x8DBD, // BC5
|
||||
COMPRESSED_SIGNED_RG_RGTC2 = 0x8DBE, // BC5
|
||||
COMPRESSED_RGBA_BPTC_UNORM = 0x8E8C, // BC7
|
||||
COMPRESSED_SRGB_ALPHA_BPTC_UNORM = 0x8E8D, // BC7
|
||||
COMPRESSED_RGB_BPTC_SIGNED_FLOAT = 0x8E8E, // BC6H
|
||||
COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT = 0x8E8F, // BC6H
|
||||
ETC1_RGB8_OES = 0x8D64, // ETC1
|
||||
COMPRESSED_R11_EAC = 0x9270, // EAC
|
||||
COMPRESSED_SIGNED_R11_EAC = 0x9271, // EAC
|
||||
COMPRESSED_RG11_EAC = 0x9272, // EAC
|
||||
COMPRESSED_SIGNED_RG11_EAC = 0x9273, // EAC
|
||||
COMPRESSED_RGB8_ETC2 = 0x9274, // ETC2
|
||||
COMPRESSED_SRGB8_ETC2 = 0x9275, // ETC2
|
||||
COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2 = 0x9276, // ETC2
|
||||
COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2 = 0x9277, // ETC2
|
||||
COMPRESSED_RGBA8_ETC2_EAC = 0x9278, // ETC2
|
||||
COMPRESSED_SRGB8_ALPHA8_ETC2_EAC = 0x9279, // ETC2
|
||||
COMPRESSED_RGBA_ASTC_4x4_KHR = 0x93B0, // ASTC...
|
||||
COMPRESSED_RGBA_ASTC_5x4_KHR = 0x93B1,
|
||||
COMPRESSED_RGBA_ASTC_5x5_KHR = 0x93B2,
|
||||
COMPRESSED_RGBA_ASTC_6x5_KHR = 0x93B3,
|
||||
COMPRESSED_RGBA_ASTC_6x6_KHR = 0x93B4,
|
||||
COMPRESSED_RGBA_ASTC_8x5_KHR = 0x93B5,
|
||||
COMPRESSED_RGBA_ASTC_8x6_KHR = 0x93B6,
|
||||
COMPRESSED_RGBA_ASTC_8x8_KHR = 0x93B7,
|
||||
COMPRESSED_RGBA_ASTC_10x5_KHR = 0x93B8,
|
||||
COMPRESSED_RGBA_ASTC_10x6_KHR = 0x93B9,
|
||||
COMPRESSED_RGBA_ASTC_10x8_KHR = 0x93BA,
|
||||
COMPRESSED_RGBA_ASTC_10x10_KHR = 0x93BB,
|
||||
COMPRESSED_RGBA_ASTC_12x10_KHR = 0x93BC,
|
||||
COMPRESSED_RGBA_ASTC_12x12_KHR = 0x93BD,
|
||||
COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR = 0x93D0,
|
||||
COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR = 0x93D1,
|
||||
COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR = 0x93D2,
|
||||
COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR = 0x93D3,
|
||||
COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR = 0x93D4,
|
||||
COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR = 0x93D5,
|
||||
COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR = 0x93D6,
|
||||
COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR = 0x93D7,
|
||||
COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR = 0x93D8,
|
||||
COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR = 0x93D9,
|
||||
COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR = 0x93DA,
|
||||
COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR = 0x93DB,
|
||||
COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR = 0x93DC,
|
||||
COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR = 0x93DD,
|
||||
};
|
||||
|
||||
enum GLBaseInternalFormat : u32 {
|
||||
RED = 0x1903,
|
||||
RG = 0x8227,
|
||||
RGB = 0x1907,
|
||||
BGR = 0x80E0,
|
||||
RGBA = 0x1908,
|
||||
BGRA = 0x80E1,
|
||||
RED_INTEGER = 0x8D94,
|
||||
RG_INTEGER = 0x8228,
|
||||
RGB_INTEGER = 0x8D98,
|
||||
BGR_INTEGER = 0x8D9A,
|
||||
RGBA_INTEGER = 0x8D99,
|
||||
BGRA_INTEGER = 0x8D9B,
|
||||
SRGB = 0x8C40,
|
||||
SRGB8 = 0x8C41,
|
||||
SRGB_ALPHA = 0x8C42,
|
||||
SRGB8_ALPHA8 = 0x8C43,
|
||||
};
|
||||
|
||||
struct KeyValue {
|
||||
u32 keyAndValueByteSize;
|
||||
char keyAndValue[keyAndValueByteSize];
|
||||
std::mem::AlignTo<4>;
|
||||
};
|
||||
|
||||
struct Header {
|
||||
u32 endianness;
|
||||
GLType glType;
|
||||
u32 glTypeSize;
|
||||
GLFormat glFormat;
|
||||
GLInternalFormat glInternalFormat;
|
||||
GLBaseInternalFormat glBaseInternalFormat;
|
||||
u32 pixelWidth;
|
||||
u32 pixelHeight;
|
||||
u32 pixelDepth;
|
||||
u32 numberOfArrayElements;
|
||||
u32 numberOfFaces;
|
||||
u32 numberOfMipmapLevels;
|
||||
u32 bytesOfKeyValueData;
|
||||
};
|
||||
|
||||
struct MipLevel {
|
||||
u32 imageSize;
|
||||
u8 imageData[imageSize];
|
||||
std::mem::AlignTo<4>;
|
||||
};
|
||||
|
||||
struct KhronosTexture {
|
||||
type::Magic<"\xABKTX 11\xBB\x0D\x0A\x1A\x0A"> identifier;
|
||||
Header header;
|
||||
u32 keyValueEnd = $ + header.bytesOfKeyValueData;
|
||||
KeyValue kv[while($ < keyValueEnd)];
|
||||
MipLevel mipLevels[header.numberOfMipmapLevels];
|
||||
};
|
||||
|
||||
KhronosTexture khronosTexture @ 0x00;
|
||||
@@ -2,8 +2,8 @@
|
||||
#pragma description Minecraft LCE LOC file
|
||||
|
||||
#pragma endian big
|
||||
#pragma array_limit 739845729834
|
||||
#pragma pattern_limit 34893726894
|
||||
#pragma array_limit 0
|
||||
#pragma pattern_limit 0
|
||||
|
||||
import std.string;
|
||||
|
||||
|
||||
133
patterns/lua40.hexpat
Normal file
133
patterns/lua40.hexpat
Normal file
@@ -0,0 +1,133 @@
|
||||
#pragma description Lua 4.0 bytecode
|
||||
#pragma magic [ 1B 4C 75 61 40 ] @ 0x00
|
||||
// based off of https://www.lua.org/source/4.0/dump.c.html
|
||||
|
||||
import std.io;
|
||||
|
||||
namespace impl {
|
||||
fn format_LuaString(auto string) {
|
||||
if (string.size == 0) {
|
||||
return "None";
|
||||
}
|
||||
return std::format("\"{}\"", string.data);
|
||||
};
|
||||
|
||||
fn format_Version(auto ver) {
|
||||
return std::format("Ver. {}.{}", ver.major, ver.minor);
|
||||
};
|
||||
}
|
||||
using LuaFunction;
|
||||
|
||||
bitfield Version {
|
||||
minor : 4;
|
||||
major : 4;
|
||||
} [[format("impl::format_Version")]];
|
||||
|
||||
struct LuaBinaryHeader {
|
||||
u8 id_chunk;
|
||||
char magic[3];
|
||||
Version version;
|
||||
u8 endianness;
|
||||
u8 size_of_int;
|
||||
u8 size_of_size_t;
|
||||
u8 size_of_instruction; // ???
|
||||
u8 size_INSTRUCTION; // SIZE_INSTRUCTION in Lua 4 source
|
||||
u8 size_OP; // SIZE_OP
|
||||
u8 size_B; // SIZE_B
|
||||
u8 size_number; // sizeof(Number)
|
||||
|
||||
if (size_number == 4) {
|
||||
u32 TEST_NUMBER;
|
||||
} else {
|
||||
u64 TEST_NUMBER;
|
||||
}
|
||||
};
|
||||
|
||||
LuaBinaryHeader header @ 0;
|
||||
|
||||
struct LuaString {
|
||||
if (header.size_of_size_t == 4) {
|
||||
u32 size;
|
||||
} else {
|
||||
u64 size;
|
||||
}
|
||||
|
||||
if (size > 0) {
|
||||
char data[size];
|
||||
}
|
||||
}[[format("impl::format_LuaString")]];
|
||||
|
||||
struct Vector<T> {
|
||||
if (header.size_of_int == 4) {
|
||||
u32 size;
|
||||
} else {
|
||||
u64 size;
|
||||
}
|
||||
if (size > 0) {
|
||||
T values[size];
|
||||
}
|
||||
};
|
||||
|
||||
struct LocalVar {
|
||||
LuaString varname;
|
||||
if (header.size_of_int == 4) {
|
||||
u32 startpc;
|
||||
u32 endpc;
|
||||
} else {
|
||||
u64 startpc;
|
||||
u64 endpc;
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
struct LuaDebugInfo {
|
||||
Vector<LocalVar> localVar;
|
||||
if (header.size_of_int == 4) {
|
||||
Vector<u32> lineInfo; // i think this is correct
|
||||
} else {
|
||||
Vector<u64> lineInfo;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
bitfield LuaNumber {
|
||||
raw : header.size_number;
|
||||
};
|
||||
|
||||
struct LuaConstants{
|
||||
Vector<LuaString> stringConstants;
|
||||
if (header.size_of_int == 4) {
|
||||
Vector<u32> intConstants;
|
||||
} else {
|
||||
Vector<u64> intConstants;
|
||||
}
|
||||
Vector<LuaFunction> protos;
|
||||
};
|
||||
|
||||
struct LuaFunction {
|
||||
LuaString source;
|
||||
if (header.size_of_int == 4) {
|
||||
u32 linedefined;
|
||||
u32 numparams;
|
||||
} else {
|
||||
u64 linedefined;
|
||||
u64 numparams;
|
||||
}
|
||||
u8 is_vararg;
|
||||
|
||||
if (header.size_of_int == 4) {
|
||||
u32 maxstacksize;
|
||||
} else {
|
||||
u64 maxstacksize;
|
||||
}
|
||||
|
||||
LuaDebugInfo debugInfo;
|
||||
LuaConstants luaConstants;
|
||||
if (header.size_of_int == 4) {
|
||||
Vector<u32> code;
|
||||
} else {
|
||||
Vector<u64> code;
|
||||
}
|
||||
};
|
||||
|
||||
LuaFunction toplevelFunction @ sizeof(header);; // Lua header size is not always the same
|
||||
@@ -1,4 +1,5 @@
|
||||
#pragma description Lua 5.1 bytecode
|
||||
#pragma magic [ 1B 4C 75 61 51 ] @ 0x00
|
||||
|
||||
import std.io;
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#pragma description Lua 5.2 bytecode
|
||||
#pragma magic [ 1B 4C 75 61 52 ] @ 0x00
|
||||
|
||||
import std.io;
|
||||
import std.mem;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#pragma description Lua 5.3 bytecode
|
||||
#pragma magic [ 1B 4C 75 61 53 ] @ 0x00
|
||||
|
||||
import std.io;
|
||||
import type.base;
|
||||
@@ -43,8 +44,15 @@ struct LuaBinaryHeader {
|
||||
struct LuaString {
|
||||
u8 size;
|
||||
if (size > 0) {
|
||||
char data[size-1];
|
||||
if (size == 0xff) {
|
||||
u64 sizeReal;
|
||||
char data[sizeReal-1];
|
||||
} else {
|
||||
char data[size-1];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}[[format("impl::format_LuaString")]];
|
||||
|
||||
struct LuaConstant {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#pragma description Lua 5.4 bytecode
|
||||
#pragma magic [ 1B 4C 75 61 54 ] @ 0x00
|
||||
|
||||
import std.io;
|
||||
import std.mem;
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#pragma MIME application/x-mach-binary
|
||||
|
||||
import type.size;
|
||||
import std.string;
|
||||
|
||||
enum Magic : u32 {
|
||||
_32BitMagic = 0xFEEDFACE,
|
||||
@@ -367,18 +368,44 @@ struct CommandSegment64 {
|
||||
u8 data[fileSize] @ fileOffset [[sealed]];
|
||||
};
|
||||
|
||||
struct lc_str { // NB: struct as opposed to it's union def in loader.h
|
||||
u32 offset;
|
||||
// It's important to note that the `ptr` field is not used in the Mach-O file itself.
|
||||
// It is only relevant at runtime when the Mach-O file is loaded into memory.
|
||||
// The Mach-O file uses the `offset` field to locate the string data within the file.
|
||||
};
|
||||
|
||||
struct Dylib {
|
||||
lc_str name; // always 24
|
||||
u32 timestamp;
|
||||
u32 current_version;
|
||||
u32 compatibility_version;
|
||||
};
|
||||
|
||||
struct LoadDyLib {
|
||||
Dylib dylib [[inline]];
|
||||
};
|
||||
|
||||
struct LoadCommand {
|
||||
Command command;
|
||||
type::Size<u32> commandSize;
|
||||
|
||||
if (command == Command::UUID)
|
||||
CommandUUID data;
|
||||
else if (command == Command::Segment)
|
||||
CommandSegment data;
|
||||
else if (command == Command::Segment64)
|
||||
CommandSegment64 data;
|
||||
else
|
||||
u8 data[commandSize - 8] [[sealed]];
|
||||
match (command) {
|
||||
(Command::UUID): CommandUUID data;
|
||||
(Command::Segment): CommandSegment data;
|
||||
(Command::Segment64): CommandSegment64 data;
|
||||
(Command::LoadDyLib | Command::IdDyLib | Command::LoadWeakDyLib): {
|
||||
LoadDyLib dylib;
|
||||
|
||||
// always 24 bytes in the struct
|
||||
std::string::NullString dylib_name;
|
||||
|
||||
// the 1 is the size of the string terminator
|
||||
// not using align here since according to the spec this is computed
|
||||
padding[commandSize - dylib.dylib.name.offset - 1 - std::string::length(dylib_name)];
|
||||
}
|
||||
(_): u8 data[commandSize - 8] [[sealed]];
|
||||
}
|
||||
};
|
||||
|
||||
struct MachO {
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
import std.sys;
|
||||
import std.mem;
|
||||
|
||||
#pragma array_limit 12544
|
||||
#pragma pattern_limit 2000000
|
||||
#pragma array_limit 0
|
||||
#pragma pattern_limit 0
|
||||
#pragma eval_depth 32
|
||||
|
||||
enum FileType : u8
|
||||
|
||||
37
patterns/mo.hexpat
Normal file
37
patterns/mo.hexpat
Normal file
@@ -0,0 +1,37 @@
|
||||
#pragma author dvob
|
||||
#pragma description GNU Machine Object (MO) files containing translations for gettext
|
||||
|
||||
// https://www.gnu.org/software/gettext/manual/html_node/MO-Files.html
|
||||
|
||||
import std.core;
|
||||
import std.io;
|
||||
|
||||
struct strPtr {
|
||||
u32 length;
|
||||
u32 offset;
|
||||
char string[length] @ offset;
|
||||
};
|
||||
|
||||
struct file {
|
||||
be u32 magic;
|
||||
if ( magic == 0x950412de )
|
||||
std::core::set_endian(std::mem::Endian::Big);
|
||||
else if ( magic == 0xde120495)
|
||||
std::core::set_endian(std::mem::Endian::Little);
|
||||
else
|
||||
std::error("Invalid MO Magic!");
|
||||
|
||||
u16 majorVersion;
|
||||
u16 minorVersion;
|
||||
u32 count;
|
||||
u32 msgIdOffset;
|
||||
u32 msgStrOffset;
|
||||
u32 hashSize;
|
||||
u32 hashOffset;
|
||||
|
||||
u32 hashTable[hashSize] @ hashOffset;
|
||||
strPtr msgIDTable[count] @ msgIdOffset;
|
||||
strPtr msgStrTable[count] @ msgStrOffset;
|
||||
};
|
||||
|
||||
file moFile @ 0x0;
|
||||
@@ -424,7 +424,7 @@ struct MovieBox : BaseBox {
|
||||
};
|
||||
|
||||
struct MediaDataBox : BaseBox {
|
||||
u8 data[while($ < endOffset)] [[sealed]];
|
||||
std::mem::Bytes<boxSize - sizeof(size) - sizeof(type)> data;
|
||||
};
|
||||
|
||||
struct Box {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user