mirror of
https://github.com/WerWolv/ImHex-Patterns.git
synced 2026-03-31 13:25:58 -05:00
Compare commits
182 Commits
ImHex-v1.3
...
dev
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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 | ||
|
|
17c200a92e | ||
|
|
384d4c7794 | ||
|
|
37a7e59c06 | ||
|
|
e8cea09477 | ||
|
|
883433b260 | ||
|
|
2db9993cb1 | ||
|
|
01ce565c9e | ||
|
|
b7b949ea27 | ||
|
|
e026ff187e | ||
|
|
63504f59a1 | ||
|
|
6113df643d | ||
|
|
3f42dddd19 | ||
|
|
2cc8868727 | ||
|
|
7f02510762 | ||
|
|
13c4168af0 | ||
|
|
1e69cd7fb2 | ||
|
|
16a87df2ac | ||
|
|
b7598405b5 | ||
|
|
d14f8de459 | ||
|
|
4c96bfbeb3 | ||
|
|
500a3fe26e | ||
|
|
5ffc583640 | ||
|
|
b9f5f1668b | ||
|
|
4c22f28a67 | ||
|
|
6f9b05b853 | ||
|
|
c533017d0b | ||
|
|
221fa70a67 | ||
|
|
661e5b7081 | ||
|
|
7d0bbd1e24 | ||
|
|
55aca93a18 | ||
|
|
255116a587 | ||
|
|
79e25fdb73 | ||
|
|
c8d9a8deb7 | ||
|
|
1d680fbf5e | ||
|
|
bc5a55affe | ||
|
|
85f5541350 | ||
|
|
61d3e110fb | ||
|
|
af957389c2 | ||
|
|
e85645897e | ||
|
|
abc78d1644 | ||
|
|
46e41db0a8 | ||
|
|
c67dc84911 | ||
|
|
323898d083 | ||
|
|
abbd25e7f6 | ||
|
|
c8ebb3eb8a | ||
|
|
bf94cb7243 | ||
|
|
6697fc23a4 | ||
|
|
8a6bb6612b | ||
|
|
1d66949375 | ||
|
|
7c65d51986 | ||
|
|
d961271c5d | ||
|
|
26d48df7dd | ||
|
|
8f1f4911a0 | ||
|
|
1d7cc537ed | ||
|
|
62ceaae09b | ||
|
|
4a8a6cba1b | ||
|
|
c3eb9e4126 | ||
|
|
a263347414 | ||
|
|
204599a70b | ||
|
|
bf6ee6d02f | ||
|
|
0125ec2c57 | ||
|
|
c5aaac25dd | ||
|
|
196011ead9 | ||
|
|
5b15136ea4 | ||
|
|
59c954ae28 | ||
|
|
8a5cb1061b | ||
|
|
120bc84548 | ||
|
|
0e17355db0 | ||
|
|
6aee524d1a | ||
|
|
b42c571d4d | ||
|
|
71e1ad8df7 | ||
|
|
5c7d77b50f | ||
|
|
a746ecb164 | ||
|
|
569e5c4c1a | ||
|
|
0316f2b667 | ||
|
|
196695e37b | ||
|
|
bced518508 | ||
|
|
2f795fc23c | ||
|
|
5ff783d571 |
@@ -9,4 +9,4 @@
|
||||
- [ ] The pattern was associated with all relevant MIME types (using `#pragma MIME mime-type` in the source code)
|
||||
- Make sure to never use `application/octet-stream` here as that means "Unidentifiable binary data"
|
||||
- [ ] A test file for this pattern has been added to [/tests/patterns/test_data](/tests/patterns/test_data)
|
||||
- Try to keep this file below ~ 1 MB
|
||||
- Try to keep this file below ~ 1 MB
|
||||
|
||||
10
.github/workflows/dispatch.yml
vendored
10
.github/workflows/dispatch.yml
vendored
@@ -8,7 +8,7 @@ on:
|
||||
repository_dispatch:
|
||||
types: [run_tests]
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
inputs:
|
||||
generate_docs:
|
||||
description: "Regenerate docs"
|
||||
required: false
|
||||
@@ -17,7 +17,7 @@ on:
|
||||
jobs:
|
||||
tests:
|
||||
name: 🎯 Dispatch changes
|
||||
runs-on: ubuntu-22.04
|
||||
runs-on: ubuntu-24.04
|
||||
env:
|
||||
DISPATCH_TOKEN: ${{ secrets.DISPATCH_TOKEN }}
|
||||
permissions:
|
||||
@@ -27,13 +27,13 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: 🧰 Checkout
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
- name: 📄 Check changed include files
|
||||
id: changed-includes
|
||||
uses: tj-actions/changed-files@v35
|
||||
uses: tj-actions/changed-files@v45
|
||||
with:
|
||||
files: includes/**/*.pat
|
||||
|
||||
@@ -45,7 +45,7 @@ jobs:
|
||||
repo: Documentation
|
||||
owner: WerWolv
|
||||
event_type: update_pl_docs
|
||||
|
||||
|
||||
- name: ✉️ Update PatternLanguage Website
|
||||
if: ${{ env.DISPATCH_TOKEN != '' }}
|
||||
uses: mvasigh/dispatch-action@main
|
||||
|
||||
25
.github/workflows/tests.yml
vendored
25
.github/workflows/tests.yml
vendored
@@ -7,11 +7,12 @@ on:
|
||||
branches: [ '*' ]
|
||||
repository_dispatch:
|
||||
types: [run_tests]
|
||||
workflow_call:
|
||||
|
||||
jobs:
|
||||
tests:
|
||||
name: 🧪 Unit Tests
|
||||
runs-on: ubuntu-22.04
|
||||
runs-on: ubuntu-24.04
|
||||
permissions:
|
||||
actions: read
|
||||
contents: read
|
||||
@@ -19,8 +20,9 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: 🧰 Checkout
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
repository: ${{ github.repository_owner }}/ImHex-Patterns
|
||||
submodules: recursive
|
||||
|
||||
- name: ⬇️ Install dependencies
|
||||
@@ -29,17 +31,17 @@ jobs:
|
||||
sudo apt install -y \
|
||||
build-essential \
|
||||
ccache \
|
||||
gcc-12 \
|
||||
g++-12 \
|
||||
gcc-14 \
|
||||
g++-14 \
|
||||
lld \
|
||||
${PKGCONF:-} \
|
||||
cmake \
|
||||
make \
|
||||
ninja-build \
|
||||
python3 \
|
||||
python3-pip \
|
||||
libmagic-dev \
|
||||
lcov
|
||||
|
||||
|
||||
sudo pip install jsonschema
|
||||
|
||||
- name: 📜 Setup ccache
|
||||
@@ -51,22 +53,23 @@ jobs:
|
||||
|
||||
- name: 🛠️ Build
|
||||
run: |
|
||||
cd tests
|
||||
mkdir -p build
|
||||
cd build
|
||||
CC=gcc-12 CXX=g++-12 cmake \
|
||||
CC=gcc-14 CXX=g++-14 cmake \
|
||||
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
|
||||
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
|
||||
-DCMAKE_C_FLAGS="-fuse-ld=lld --coverage" \
|
||||
-DCMAKE_CXX_FLAGS="-fuse-ld=lld --coverage" \
|
||||
-DIMHEX_PATTERNS_ENABLE_UNIT_TESTS=ON \
|
||||
-DLIBPL_ENABLE_TESTS=OFF \
|
||||
-DLIBPL_ENABLE_CLI=OFF \
|
||||
-G Ninja \
|
||||
..
|
||||
make -j4
|
||||
ninja unit_tests
|
||||
|
||||
- name: 🧪 Perform Unit Tests
|
||||
run: |
|
||||
cd tests/build
|
||||
cd build
|
||||
ctest --output-on-failure -j 4
|
||||
|
||||
- name: 📎 Validate JSON Files
|
||||
@@ -74,7 +77,7 @@ jobs:
|
||||
cd constants
|
||||
for file in ./[!_schema.json]*; do jsonschema -i $file _schema.json; done
|
||||
cd ..
|
||||
|
||||
|
||||
cd tips
|
||||
for file in ./[!_schema.json]*; do jsonschema -i $file _schema.json; done
|
||||
cd ..
|
||||
|
||||
9
.gitignore
vendored
9
.gitignore
vendored
@@ -1,6 +1,13 @@
|
||||
|
||||
tests/cmake*/
|
||||
tests/build*/
|
||||
build/
|
||||
cmake-build-*/
|
||||
|
||||
.vscode/
|
||||
.devcontainer/
|
||||
.cache/
|
||||
.idea/
|
||||
.DS_Store
|
||||
.DS_Store
|
||||
|
||||
compile_commands.json
|
||||
30
CMakeLists.txt
Normal file
30
CMakeLists.txt
Normal file
@@ -0,0 +1,30 @@
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
project(ImHex-Patterns)
|
||||
|
||||
option(IMHEX_PATTERNS_ENABLE_UNIT_TESTS "Enable building unit tests for ImHex-Patterns" OFF)
|
||||
|
||||
# if enabled, add a unit_test custom target for all the unit tests to be registered against
|
||||
if(IMHEX_PATTERNS_ENABLE_UNIT_TESTS)
|
||||
if(NOT TARGET unit_tests)
|
||||
enable_testing()
|
||||
add_custom_target(unit_tests)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# If this has been manually cloned into another project, libpl may already have been set up
|
||||
if(NOT TARGET libpl)
|
||||
include(FetchContent)
|
||||
|
||||
FetchContent_Declare(
|
||||
pattern_language
|
||||
GIT_REPOSITORY https://github.com/WerWolv/PatternLanguage
|
||||
GIT_TAG master
|
||||
)
|
||||
|
||||
FetchContent_MakeAvailable(pattern_language)
|
||||
endif()
|
||||
|
||||
if(IMHEX_PATTERNS_ENABLE_UNIT_TESTS)
|
||||
add_subdirectory(tests)
|
||||
endif()
|
||||
@@ -8,5 +8,5 @@ Thanks a lot for any additions or improvements :)
|
||||
## Adding new Patterns
|
||||
|
||||
When adding new patterns, if possible, please also add a test file named `<pattern_name>.hexpat.<extension>` to the `/tests/patterns/test_data` directory. This allows our Unit Tests to be run against your code so we can make sure it stays up-to-date and doesn't break when changes are made to the PatternLanguage.
|
||||
Please try to keep these files as small as possible (~100kiB at most) so cloning stays fast.
|
||||
Please try to keep these files as small as possible (~100kiB at most) so cloning stays fast.
|
||||
Please also make sure to not submit any test files that are under copyright such as game files, ROMs or files extracted from other programs. We don't want a DMCA takedown on this repo.
|
||||
|
||||
121
README.md
121
README.md
@@ -25,113 +25,189 @@ 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 |
|
||||
| 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 |
|
||||
| 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 |
|
||||
| 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 |
|
||||
| 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) | 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 |
|
||||
| DICOM | `application/dicom` | [`patterns/dicom.hexpat`](patterns/dicom.hexpat) | DICOM image format |
|
||||
| DMG | | [`patterns/dmg.hexpat`](patterns/dmg.hexpat) | Apple Disk Image Trailer (DMG) |
|
||||
| DMP | | [`patterns/dmp64.hexpat`](patterns/dmp64.hexpat) | Windows Kernel Dump(DMP64) |
|
||||
| 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 |
|
||||
| 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) |
|
||||
| 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 |
|
||||
| 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 |
|
||||
| GB | `application/x-gameboy-rom` | [`patterns/gb.hexpat`](patterns/gb.hexpat) | Gameboy ROM |
|
||||
| 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 |
|
||||
| GGUF | | [`patterns/gguf.hexpat`](patterns/gguf.hexpat) | GGML Inference Models |
|
||||
| GIF | `image/gif` | [`patterns/gif.hexpat`](patterns/gif.hexpat) | GIF image files |
|
||||
| GLTF | `model/gltf-binary` | [`patterns/gltf.hexpat`](patterns/gltf.hexpat) | GL Transmission Format binary 3D model file |
|
||||
| GZIP | `application/gzip` | [`patterns/gzip.hexpat`](patterns/gzip.hexpat) | GZip compressed data format |
|
||||
| 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 |
|
||||
| LOC | | [`patterns/loc.hexpat`](patterns/loc.hexpat) | Minecraft Legacy Console Edition Language file |
|
||||
| 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 |
|
||||
| Lua 5.4 | | [`patterns/lua54.hexpat`](patterns/lua54.hexpat) | Lua 5.4 bytecode |
|
||||
| LCE Savefile | | [`patterns/lcesave.hexpat`](patterns/lcesave.hexpat) | Minecraft Legacy Console Edition save file |
|
||||
| LZNT1 | | [`patterns/lznt1.hexpat`](patterns/lznt1.hexpat) | LZNT1 compressed data format |
|
||||
| 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 |
|
||||
| NotepadWindowState | | [`patterns/notepad-windowstate.hexpat`](patterns/notepad-windowstate.hexpat) | Windows 11 Notepad - Window State .bin file |
|
||||
| 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) | .nes file format |
|
||||
| NotepadCache | | [`patterns/notepad-cache.hexpat`](patterns/notepad-cache.hexpat) | Windows Notepad Cache |
|
||||
| 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) |
|
||||
| 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) |
|
||||
| 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 |
|
||||
| PRODINFO | | [`patterns/prodinfo.hexpat`](patterns/prodinfo.hexpat) | Nintendo Switch PRODINFO |
|
||||
| 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 |
|
||||
| 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 |
|
||||
| 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 |
|
||||
| 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 |
|
||||
| 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) |
|
||||
| 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 |
|
||||
|
||||
### Scripts
|
||||
|
||||
@@ -209,7 +285,6 @@ Everything will immediately show up in ImHex's Content Store and gets bundled wi
|
||||
| Turkish Windows | [`encodings/turkish_windows.tbl`](encodings/turkish_windows.tbl) | Turkish Windows encoding |
|
||||
| UTF-8 | [`encodings/utf8.tbl`](encodings/utf8.tbl) | UTF-8 encoding |
|
||||
| Vietnamese | [`encodings/vietnamese.tbl`](encodings/vietnamese.tbl) | Vietnamese character encoding |
|
||||
> import custom encoding from File -> Import... -> Custome Encoding File
|
||||
|
||||
### Data Processor Nodes
|
||||
|
||||
@@ -228,3 +303,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 |
|
||||
|
||||
@@ -775,6 +775,6 @@
|
||||
"name": "ENOTRECOVERABLE",
|
||||
"desc": "State not recoverable"
|
||||
}
|
||||
|
||||
|
||||
]
|
||||
}
|
||||
730
disassemblers/8051.json
Normal file
730
disassemblers/8051.json
Normal file
@@ -0,0 +1,730 @@
|
||||
{
|
||||
"name": "Intel 8051",
|
||||
"includes": [],
|
||||
"options": [],
|
||||
"opcodes": [
|
||||
{
|
||||
"mask": "0000'0000",
|
||||
"mnemonic": "NOP",
|
||||
"format": ""
|
||||
},
|
||||
{
|
||||
"mask": "0000'0010 AAAA'AAAA AAAA'AAAA",
|
||||
"mnemonic": "LJMP",
|
||||
"format": "#0x{A:04X}",
|
||||
"metadata": [
|
||||
{
|
||||
"type": "jump",
|
||||
"data": {
|
||||
"destination": "A"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"mask": "1000'0000 AAAA'AAAA",
|
||||
"mnemonic": "SJMP",
|
||||
"format": "#0x{A:02X}",
|
||||
"metadata": [
|
||||
{
|
||||
"type": "jump",
|
||||
"data": {
|
||||
"destination": "A"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"mask": "0111'0011",
|
||||
"mnemonic": "JMP",
|
||||
"format": "@A+DPTR"
|
||||
},
|
||||
{
|
||||
"mask": "0100'0000 AAAA'AAAA",
|
||||
"mnemonic": "JC",
|
||||
"format": "PC + 0x{A:02X}",
|
||||
"metadata": [
|
||||
{
|
||||
"type": "jump",
|
||||
"data": {
|
||||
"destination": "offset + 2 + A"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"mask": "0011'0000 BBBB'BBBB AAAA'AAAA",
|
||||
"mnemonic": "JNB",
|
||||
"format": "BIT[0x{B:02X}], PC + 0x{A:02X}",
|
||||
"metadata": [
|
||||
{
|
||||
"type": "jump",
|
||||
"data": {
|
||||
"destination": "offset + 3 + A"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"mask": "0001'0000 BBBB'BBBB AAAA'AAAA",
|
||||
"mnemonic": "JBC",
|
||||
"format": "BIT[0x{B:02X}], PC + 0x{A:02X}",
|
||||
"metadata": [
|
||||
{
|
||||
"type": "jump",
|
||||
"data": {
|
||||
"destination": "offset + 3 + A"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"mask": "0010'0000 AAAA'AAAA RRRR'RRRR",
|
||||
"mnemonic": "JB",
|
||||
"format": "BIT[0x{A:02X}], PC + 0x{R:02X}",
|
||||
"metadata": [
|
||||
{
|
||||
"type": "jump",
|
||||
"data": {
|
||||
"destination": "offset + 3 + A"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"mask": "0001'0010 AAAA'AAAA AAAA'AAAA",
|
||||
"mnemonic": "LCALL",
|
||||
"format": "#0x{A:04X}",
|
||||
"metadata": [
|
||||
{
|
||||
"type": "jump",
|
||||
"data": {
|
||||
"destination": "A"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"mask": "PPP1'0001 AAAA'AAAA",
|
||||
"mnemonic": "ACALL",
|
||||
"format": "page{P} #0x{A:04X}",
|
||||
"metadata": [
|
||||
{
|
||||
"type": "jump",
|
||||
"data": {
|
||||
"destination": "P * 256 + A"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"mask": "PPP0'0001 AAAA'AAAA",
|
||||
"mnemonic": "AJMP",
|
||||
"format": "page{P} #0x{A:04X}",
|
||||
"metadata": [
|
||||
{
|
||||
"type": "jump",
|
||||
"data": {
|
||||
"destination": "P * 256 + A"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"mask": "0000'0011",
|
||||
"mnemonic": "RR",
|
||||
"format": "A"
|
||||
},
|
||||
{
|
||||
"mask": "0001'0011",
|
||||
"mnemonic": "RRC",
|
||||
"format": "A"
|
||||
},
|
||||
{
|
||||
"mask": "0010'0011",
|
||||
"mnemonic": "RL",
|
||||
"format": "A"
|
||||
},
|
||||
{
|
||||
"mask": "0011'0011",
|
||||
"mnemonic": "RLC",
|
||||
"format": "A"
|
||||
},
|
||||
{
|
||||
"mask": "0000'0100",
|
||||
"mnemonic": "INC",
|
||||
"format": "A"
|
||||
},
|
||||
{
|
||||
"mask": "0000'0101 AAAA'AAAA",
|
||||
"mnemonic": "INC",
|
||||
"format": "IRAM[0x{A:02X}]"
|
||||
},
|
||||
{
|
||||
"mask": "0000'011R",
|
||||
"mnemonic": "INC",
|
||||
"format": "@R{R}"
|
||||
},
|
||||
{
|
||||
"mask": "0000'1RRR",
|
||||
"mnemonic": "INC",
|
||||
"format": "R{R}"
|
||||
},
|
||||
{
|
||||
"mask": "1010'0011",
|
||||
"mnemonic": "INC",
|
||||
"format": "DPTR"
|
||||
},
|
||||
{
|
||||
"mask": "0001'0100",
|
||||
"mnemonic": "DEC",
|
||||
"format": "A"
|
||||
},
|
||||
{
|
||||
"mask": "0001'0101 AAAA'AAAA",
|
||||
"mnemonic": "DEC",
|
||||
"format": "IRAM[0x{A:02X}]"
|
||||
},
|
||||
{
|
||||
"mask": "0001'0110",
|
||||
"mnemonic": "DEC",
|
||||
"format": "@R0"
|
||||
},
|
||||
{
|
||||
"mask": "0001'0111",
|
||||
"mnemonic": "DEC",
|
||||
"format": "@R1"
|
||||
},
|
||||
{
|
||||
"mask": "0001'1RRR",
|
||||
"mnemonic": "DEC",
|
||||
"format": "R{R}"
|
||||
},
|
||||
{
|
||||
"mask": "1110'0100",
|
||||
"mnemonic": "CLR",
|
||||
"format": "A"
|
||||
},
|
||||
{
|
||||
"mask": "1100'0010 AAAA'AAAA",
|
||||
"mnemonic": "CLR",
|
||||
"format": "BIT[0x{A:02X}]"
|
||||
},
|
||||
{
|
||||
"mask": "1100'0011",
|
||||
"mnemonic": "CLR",
|
||||
"format": "C"
|
||||
},
|
||||
{
|
||||
"mask": "1111'0000",
|
||||
"mnemonic": "MOVX",
|
||||
"format": "@DPTR, A"
|
||||
},
|
||||
{
|
||||
"mask": "1110'0000",
|
||||
"mnemonic": "MOVX",
|
||||
"format": "A, @DPTR"
|
||||
},
|
||||
{
|
||||
"mask": "1111'001R",
|
||||
"mnemonic": "MOVX",
|
||||
"format": "@R{R}, A"
|
||||
},
|
||||
{
|
||||
"mask": "1110'001R",
|
||||
"mnemonic": "MOVX",
|
||||
"format": "A, @R{R}"
|
||||
},
|
||||
{
|
||||
"mask": "0111'011R AAAA'AAAA",
|
||||
"mnemonic": "MOV",
|
||||
"format": "@R{R}, #0x{A:02X}"
|
||||
},
|
||||
{
|
||||
"mask": "0111'1RRR AAAA'AAAA",
|
||||
"mnemonic": "MOV",
|
||||
"format": "R{R}, #0x{A:02X}"
|
||||
},
|
||||
{
|
||||
"mask": "1111'1RRR",
|
||||
"mnemonic": "MOV",
|
||||
"format": "R{R}, A"
|
||||
},
|
||||
{
|
||||
"mask": "1110'011R",
|
||||
"mnemonic": "MOV",
|
||||
"format": "A, @R{R}"
|
||||
},
|
||||
{
|
||||
"mask": "1111'011R",
|
||||
"mnemonic": "MOV",
|
||||
"format": "@R{R}, A"
|
||||
},
|
||||
{
|
||||
"mask": "1110'1RRR",
|
||||
"mnemonic": "MOV",
|
||||
"format": "A, R{R}"
|
||||
},
|
||||
{
|
||||
"mask": "1001'0010 AAAA'AAAA",
|
||||
"mnemonic": "MOV",
|
||||
"format": "BIT[0x{A:02X}], C"
|
||||
},
|
||||
{
|
||||
"mask": "1010'0010 AAAA'AAAA",
|
||||
"mnemonic": "MOV",
|
||||
"format": "C, BIT[0x{A:02X}]"
|
||||
},
|
||||
{
|
||||
"mask": "1001'0000 DDDD'DDDD DDDD'DDDD",
|
||||
"mnemonic": "MOV",
|
||||
"format": "DPTR, #0x{D:04X}"
|
||||
},
|
||||
{
|
||||
"mask": "1110'0101 AAAA'AAAA",
|
||||
"mnemonic": "MOV",
|
||||
"format": "A, IRAM[0x{A:02X}]"
|
||||
},
|
||||
{
|
||||
"mask": "1111'0101 AAAA'AAAA",
|
||||
"mnemonic": "MOV",
|
||||
"format": "IRAM[#0x{A:02X}], A"
|
||||
},
|
||||
{
|
||||
"mask": "0111'0101 AAAA'AAAA DDDD'DDDD",
|
||||
"mnemonic": "MOV",
|
||||
"format": "IRAM[0x{A:02X}], #0x{D:02X}"
|
||||
},
|
||||
{
|
||||
"mask": "1000'0101 AAAA'AAAA BBBB'BBBB",
|
||||
"mnemonic": "MOV",
|
||||
"format": "IRAM[0x{A:02X}], IRAM[0x{B:02X}]"
|
||||
},
|
||||
{
|
||||
"mask": "0111'0100 DDDD'DDDD",
|
||||
"mnemonic": "MOV",
|
||||
"format": "A, #0x{D:02X}"
|
||||
},
|
||||
{
|
||||
"mask": "1000'011R AAAA'AAAA",
|
||||
"mnemonic": "MOV",
|
||||
"format": "IRAM[0x{A:02X}], @R{R}"
|
||||
},
|
||||
{
|
||||
"mask": "1000'1RRR AAAA'AAAA",
|
||||
"mnemonic": "MOV",
|
||||
"format": "IRAM[0x{A:02X}], R{R}"
|
||||
},
|
||||
{
|
||||
"mask": "1010'011R AAAA'AAAA",
|
||||
"mnemonic": "MOV",
|
||||
"format": "@R{R}, IRAM[0x{A:02X}]"
|
||||
},
|
||||
{
|
||||
"mask": "1010'1RRR AAAA'AAAA",
|
||||
"mnemonic": "MOV",
|
||||
"format": "R{R}, IRAM[0x{A:02X}]"
|
||||
},
|
||||
{
|
||||
"mask": "0110'0000 AAAA'AAAA",
|
||||
"mnemonic": "JZ",
|
||||
"format": "PC + 0x{A:02X}",
|
||||
"metadata": [
|
||||
{
|
||||
"type": "jump",
|
||||
"data": {
|
||||
"destination": "offset + 2 + A"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"mask": "0111'0000 AAAA'AAAA",
|
||||
"mnemonic": "JNZ",
|
||||
"format": "PC + 0x{A:02X}",
|
||||
"metadata": [
|
||||
{
|
||||
"type": "jump",
|
||||
"data": {
|
||||
"destination": "offset + 2 + A"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"mask": "1001'0011",
|
||||
"mnemonic": "MOVC",
|
||||
"format": "A, @A+DPTR"
|
||||
},
|
||||
{
|
||||
"mask": "1000'0011",
|
||||
"mnemonic": "MOVC",
|
||||
"format": "A, @A+PC"
|
||||
},
|
||||
{
|
||||
"mask": "1101'011R",
|
||||
"mnemonic": "XCHD",
|
||||
"format": "A, @R{R}"
|
||||
},
|
||||
{
|
||||
"mask": "1100'011R",
|
||||
"mnemonic": "XCH",
|
||||
"format": "A, @R{R}"
|
||||
},
|
||||
{
|
||||
"mask": "1100'1RRR",
|
||||
"mnemonic": "XCH",
|
||||
"format": "A, R{R}"
|
||||
},
|
||||
{
|
||||
"mask": "1100'0101 AAAA'AAAA",
|
||||
"mnemonic": "XCH",
|
||||
"format": "A, IRAM[0x{A:02X}]"
|
||||
},
|
||||
{
|
||||
"mask": "0010'0010",
|
||||
"mnemonic": "RET",
|
||||
"format": ""
|
||||
},
|
||||
{
|
||||
"mask": "0011'0010",
|
||||
"mnemonic": "RETI",
|
||||
"format": ""
|
||||
},
|
||||
{
|
||||
"mask": "1101'0010 AAAA'AAAA",
|
||||
"mnemonic": "SETB",
|
||||
"format": "BIT[0x{A:02X}]"
|
||||
},
|
||||
{
|
||||
"mask": "1101'0011",
|
||||
"mnemonic": "SETB",
|
||||
"format": "C"
|
||||
},
|
||||
{
|
||||
"mask": "0101'0010 AAAA'AAAA",
|
||||
"mnemonic": "ANL",
|
||||
"format": "IRAM[0x{A:02X}], A"
|
||||
},
|
||||
{
|
||||
"mask": "0101'0101 AAAA'AAAA",
|
||||
"mnemonic": "ANL",
|
||||
"format": "A, IRAM[0x{A:02X}]"
|
||||
},
|
||||
{
|
||||
"mask": "0101'0011 AAAA'AAAA DDDD'DDDD",
|
||||
"mnemonic": "ANL",
|
||||
"format": "A, IRAM[0x{A:02X}], #0x{D:02X}"
|
||||
},
|
||||
{
|
||||
"mask": "0101'0100 AAAA'AAAA",
|
||||
"mnemonic": "ANL",
|
||||
"format": "A, #0x{A:02X}"
|
||||
},
|
||||
{
|
||||
"mask": "0101'011R",
|
||||
"mnemonic": "ANL",
|
||||
"format": "A, @R{R}"
|
||||
},
|
||||
{
|
||||
"mask": "0101'1RRR",
|
||||
"mnemonic": "ANL",
|
||||
"format": "A, R{R}"
|
||||
},
|
||||
{
|
||||
"mask": "1000'0010 AAAA'AAAA",
|
||||
"mnemonic": "ANL",
|
||||
"format": "C, BIT[0x{A:02X}]"
|
||||
},
|
||||
{
|
||||
"mask": "1011'0000 AAAA'AAAA",
|
||||
"mnemonic": "ANL",
|
||||
"format": "C, /BIT[0x{A:02X}]"
|
||||
},
|
||||
{
|
||||
"mask": "0100'0010 AAAA'AAAA",
|
||||
"mnemonic": "ORL",
|
||||
"format": "IRAM[0x{A:02X}], A"
|
||||
},
|
||||
{
|
||||
"mask": "0100'0011 AAAA'AAAA DDDD'DDDD",
|
||||
"mnemonic": "ORL",
|
||||
"format": "IRAM[0x{A:02X}], #0x{D:02X}"
|
||||
},
|
||||
{
|
||||
"mask": "0100'0100 DDDD'DDDD",
|
||||
"mnemonic": "ORL",
|
||||
"format": "A, #0x{D:02X}"
|
||||
},
|
||||
{
|
||||
"mask": "0100'011R",
|
||||
"mnemonic": "ORL",
|
||||
"format": "A, @R{R}"
|
||||
},
|
||||
{
|
||||
"mask": "0100'1RRR",
|
||||
"mnemonic": "ORL",
|
||||
"format": "A, R{R}"
|
||||
},
|
||||
{
|
||||
"mask": "0100'0101 AAAA'AAAA",
|
||||
"mnemonic": "ORL",
|
||||
"format": "A, IRAM[0x{A:02X}]"
|
||||
},
|
||||
{
|
||||
"mask": "0111'0010 AAAA'AAAA",
|
||||
"mnemonic": "ORL",
|
||||
"format": "C, BIT[0x{A:02X}]"
|
||||
},
|
||||
{
|
||||
"mask": "1010'0000 AAAA'AAAA",
|
||||
"mnemonic": "ORL",
|
||||
"format": "C, /BIT[0x{A:02X}]"
|
||||
},
|
||||
{
|
||||
"mask": "0110'0010 AAAA'AAAA",
|
||||
"mnemonic": "XRL",
|
||||
"format": "IRAM[0x{A:02X}], A"
|
||||
},
|
||||
{
|
||||
"mask": "0110'0011 AAAA'AAAA DDDD'DDDD",
|
||||
"mnemonic": "XRL",
|
||||
"format": "IRAM[0x{A:02X}], #0x{D:02X}"
|
||||
},
|
||||
{
|
||||
"mask": "0110'0100 DDDD'DDDD",
|
||||
"mnemonic": "XRL",
|
||||
"format": "A, #0x{D:02X}"
|
||||
},
|
||||
{
|
||||
"mask": "0110'011R",
|
||||
"mnemonic": "XRL",
|
||||
"format": "A, @R{R}"
|
||||
},
|
||||
{
|
||||
"mask": "0110'1RRR",
|
||||
"mnemonic": "XRL",
|
||||
"format": "A, R{R}"
|
||||
},
|
||||
{
|
||||
"mask": "0110'0101 AAAA'AAAA",
|
||||
"mnemonic": "XRL",
|
||||
"format": "A, IRAM[0x{A:02X}]"
|
||||
},
|
||||
{
|
||||
"mask": "0010'0100 DDDD'DDDD",
|
||||
"mnemonic": "ADD",
|
||||
"format": "A, #0x{D:02X}"
|
||||
},
|
||||
{
|
||||
"mask": "0010'011R",
|
||||
"mnemonic": "ADD",
|
||||
"format": "A, @R{R}"
|
||||
},
|
||||
{
|
||||
"mask": "0010'0101 AAAA'AAAA",
|
||||
"mnemonic": "ADD",
|
||||
"format": "A, IRAM[0x{A:02X}]"
|
||||
},
|
||||
{
|
||||
"mask": "0011'0100 DDDD'DDDD",
|
||||
"mnemonic": "ADDC",
|
||||
"format": "A, #0x{D:02X}"
|
||||
},
|
||||
{
|
||||
"mask": "0011'011R",
|
||||
"mnemonic": "ADDC",
|
||||
"format": "A, @R{R}"
|
||||
},
|
||||
{
|
||||
"mask": "0011'0101 AAAA'AAAA",
|
||||
"mnemonic": "ADDC",
|
||||
"format": "A, IRAM[0x{A:02X}]"
|
||||
},
|
||||
{
|
||||
"mask": "0011'1RRR",
|
||||
"mnemonic": "ADDC",
|
||||
"format": "A, R{R}"
|
||||
},
|
||||
{
|
||||
"mask": "1001'0100 DDDD'DDDD",
|
||||
"mnemonic": "SUBB",
|
||||
"format": "A, #0x{D:02X}"
|
||||
},
|
||||
{
|
||||
"mask": "1001'0101 IIII'IIII",
|
||||
"mnemonic": "SUBB",
|
||||
"format": "A, IRAM[0x{I:02X}]"
|
||||
},
|
||||
{
|
||||
"mask": "1001'011R",
|
||||
"mnemonic": "SUBB",
|
||||
"format": "A, @R{R}"
|
||||
},
|
||||
{
|
||||
"mask": "1001'1RRR",
|
||||
"mnemonic": "SUBB",
|
||||
"format": "A, R{R}"
|
||||
},
|
||||
{
|
||||
"mask": "1010'0100",
|
||||
"mnemonic": "MUL",
|
||||
"format": "AB"
|
||||
},
|
||||
{
|
||||
"mask": "1000'0100",
|
||||
"mnemonic": "DIV",
|
||||
"format": "AB"
|
||||
},
|
||||
{
|
||||
"mask": "0010'1RRR",
|
||||
"mnemonic": "ORL",
|
||||
"format": "A, R{R}"
|
||||
},
|
||||
{
|
||||
"mask": "1011'0101 IIII'IIII AAAA'AAAA",
|
||||
"mnemonic": "CJNE",
|
||||
"format": "A, IRAM[0x{I:02X}], PC + 0x{A:02X}",
|
||||
"metadata": [
|
||||
{
|
||||
"type": "jump",
|
||||
"data": {
|
||||
"destination": "offset + 3 + A"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"mask": "1011'0100 DDDD'DDDD AAAA'AAAA",
|
||||
"mnemonic": "CJNE",
|
||||
"format": "A, #0x{D:02X}, PC + 0x{A:02X}",
|
||||
"metadata": [
|
||||
{
|
||||
"type": "jump",
|
||||
"data": {
|
||||
"destination": "offset + 3 + A"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"mask": "1011'011R DDDD'DDDD AAAA'AAAA",
|
||||
"mnemonic": "CJNE",
|
||||
"format": "@R{R}, #0x{D:02X}, PC + 0x{A:02X}",
|
||||
"metadata": [
|
||||
{
|
||||
"type": "jump",
|
||||
"data": {
|
||||
"destination": "offset + 3 + A"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"mask": "1011'1RRR DDDD'DDDD AAAA'AAAA",
|
||||
"mnemonic": "CJNE",
|
||||
"format": "R{R}, #0x{D:02X}, PC + 0x{A:02X}",
|
||||
"metadata": [
|
||||
{
|
||||
"type": "jump",
|
||||
"data": {
|
||||
"destination": "offset + 3 + A"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"mask": "1101'0101 IIII'IIII AAAA'AAAA",
|
||||
"mnemonic": "DJNZ",
|
||||
"format": "IRAM[0x{I:02X}], PC + 0x{A:02X}",
|
||||
"metadata": [
|
||||
{
|
||||
"type": "jump",
|
||||
"data": {
|
||||
"destination": "offset + 3 + A"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"mask": "1101'1RRR AAAA'AAAA",
|
||||
"mnemonic": "DJNZ",
|
||||
"format": "R{R}, PC + 0x{R:02X}",
|
||||
"metadata": [
|
||||
{
|
||||
"type": "jump",
|
||||
"data": {
|
||||
"destination": "offset + 2 + A"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"mask": "0101'0000 AAAA'AAAA",
|
||||
"mnemonic": "JNC",
|
||||
"format": "PC + 0x{A:02X}",
|
||||
"metadata": [
|
||||
{
|
||||
"type": "jump",
|
||||
"data": {
|
||||
"destination": "offset + 2 + A"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"mask": "1101'0000 AAAA'AAAA",
|
||||
"mnemonic": "POP",
|
||||
"format": "IRAM[0x{A:02X}]"
|
||||
},
|
||||
{
|
||||
"mask": "1100'0000 AAAA'AAAA",
|
||||
"mnemonic": "PUSH",
|
||||
"format": "IRAM[0x{A:02X}]"
|
||||
},
|
||||
{
|
||||
"mask": "1101'0100",
|
||||
"mnemonic": "DA",
|
||||
"format": ""
|
||||
},
|
||||
{
|
||||
"mask": "1100'0100",
|
||||
"mnemonic": "SWAP",
|
||||
"format": "A"
|
||||
},
|
||||
{
|
||||
"mask": "1111'0100",
|
||||
"mnemonic": "CPL",
|
||||
"format": "A"
|
||||
},
|
||||
{
|
||||
"mask": "1011'0011",
|
||||
"mnemonic": "CPL",
|
||||
"format": "C"
|
||||
},
|
||||
{
|
||||
"mask": "1011'0010 BBBB'BBBB",
|
||||
"mnemonic": "CPL",
|
||||
"format": "BIT[0x{B:02X}]"
|
||||
},
|
||||
{
|
||||
"mask": "1010'0101",
|
||||
"mnemonic": "INVALID",
|
||||
"format": ""
|
||||
},
|
||||
{
|
||||
"mask": "XXXX'XXXX",
|
||||
"mnemonic": "DB",
|
||||
"format": "#0x{X:02X}",
|
||||
"metadata": [
|
||||
{
|
||||
"type": "data",
|
||||
"data": {
|
||||
"value": "X"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
]
|
||||
}
|
||||
1045
disassemblers/jvm.json
Normal file
1045
disassemblers/jvm.json
Normal file
File diff suppressed because it is too large
Load Diff
21921
encodings/gbk.tbl
Normal file
21921
encodings/gbk.tbl
Normal file
File diff suppressed because it is too large
Load Diff
@@ -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);
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
@@ -7,11 +7,11 @@ import hex.impl.imhex_check;
|
||||
*/
|
||||
|
||||
namespace auto hex::prv {
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
Queries information from the currently loaded provider. The kind of information that's available depends on the provider that's loaded
|
||||
|
||||
|
||||
> **Available information**
|
||||
> - File Provider
|
||||
> - `file_path() -> str`
|
||||
@@ -32,12 +32,12 @@ namespace auto hex::prv {
|
||||
> - `region_size(regionName) -> u64`
|
||||
> - `process_id() -> u32`
|
||||
> - `process_name() -> str`
|
||||
|
||||
|
||||
@param category Information category
|
||||
@param argument Extra argument to pass along
|
||||
*/
|
||||
fn get_information(str category, str argument = "") {
|
||||
return builtin::hex::prv::get_information(category, argument);
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
28
includes/hex/type/encstr.pat
Normal file
28
includes/hex/type/encstr.pat
Normal file
@@ -0,0 +1,28 @@
|
||||
#pragma once
|
||||
|
||||
import hex.impl.imhex_check;
|
||||
|
||||
/*!
|
||||
Types to work with custom encoded strings using Thiny encoding definitions
|
||||
*/
|
||||
|
||||
namespace auto hex::type {
|
||||
|
||||
/**
|
||||
A string that was encoded using a custom encoding
|
||||
@tparam Data Pattern whose bytes are used in the decoding process
|
||||
@tparam EncodingDefinition A string containing a Thingy encoding definition as used by ImHex's custom encoding feature
|
||||
*/
|
||||
struct EncodedString<auto Data, auto EncodingDefinition> {
|
||||
builtin::hex::dec::EncodedString<Data, EncodingDefinition> string;
|
||||
} [[sealed, format("hex::type::impl::format_encoded_string")]];
|
||||
|
||||
namespace impl {
|
||||
|
||||
fn format_encoded_string(ref auto string) {
|
||||
return string.string;
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
143
includes/hex/type/instruction.pat
Normal file
143
includes/hex/type/instruction.pat
Normal file
@@ -0,0 +1,143 @@
|
||||
#pragma once
|
||||
|
||||
import hex.impl.imhex_check;
|
||||
|
||||
/*!
|
||||
Types to work with machine code
|
||||
*/
|
||||
|
||||
namespace auto hex::type {
|
||||
|
||||
/**
|
||||
A machine code instruction which will get disassembled
|
||||
@tparam DisassemblerSetting A string containing the config for the disassembler in the form of "architecture; setting1, setting2, no-setting3"
|
||||
@tparam SyntaxType Syntax used in the disassembly. Possible values are "intel", "at&t", "masm" and "motorola"
|
||||
@tparam ImageBaseAddress Start address of the instruction region in the data
|
||||
@tparam ImageLoadAddress Address where the instructions will be loaded into memory
|
||||
|
||||
Possible Values for DisassemblerSetting:
|
||||
- Architecture, all may be suffixed with le or be to specify endianess (e.g armbe or mipsle)
|
||||
- arm
|
||||
- thumb
|
||||
- aarch64
|
||||
- arm64
|
||||
- mips
|
||||
- x86
|
||||
- x86_64
|
||||
- x64
|
||||
- ppc
|
||||
- powerpc
|
||||
- sparc
|
||||
- sysz
|
||||
- xcore
|
||||
- m68k
|
||||
- m680x
|
||||
- tms320c64x
|
||||
- evm
|
||||
- wasm
|
||||
- riscv
|
||||
- mos65xx
|
||||
- bpf
|
||||
- sh
|
||||
- tricore
|
||||
|
||||
- Settings, not all settings make sense for each architecture. Prefixing settings with no- will remove them instead
|
||||
- 16bit
|
||||
- 32bit
|
||||
- 64bit
|
||||
- cortex-m
|
||||
- armv8
|
||||
- micromips
|
||||
- mips2
|
||||
- mips3
|
||||
- mips32r6
|
||||
- sparcv9
|
||||
- qpx
|
||||
- spe
|
||||
- ps
|
||||
- 68000
|
||||
- 68010
|
||||
- 68020
|
||||
- 68030
|
||||
- 68040
|
||||
- 68060
|
||||
- 6301
|
||||
- 6309
|
||||
- 6800
|
||||
- 6801
|
||||
- 6805
|
||||
- 6808
|
||||
- 6809
|
||||
- 6811
|
||||
- cpu12
|
||||
- hcs08
|
||||
- bpfe
|
||||
- rv32g
|
||||
- rv64g
|
||||
- riscvc
|
||||
- 6502
|
||||
- 65c02
|
||||
- w65c02
|
||||
- 65816
|
||||
- long-m
|
||||
- long-x
|
||||
- sh2
|
||||
- sh2a
|
||||
- sh3
|
||||
- sh4
|
||||
- sh4a
|
||||
- shfpu
|
||||
- shdsp
|
||||
- 1.1
|
||||
- 1.2
|
||||
- 1.3
|
||||
- 1.3.1
|
||||
- 1.6
|
||||
- 1.6.1
|
||||
- 1.6.2
|
||||
*/
|
||||
struct Instruction<auto DisassemblerSetting, auto SyntaxType, auto ImageBaseAddress, auto ImageLoadAddress> {
|
||||
builtin::hex::dec::Instruction<DisassemblerSetting, SyntaxType, ImageBaseAddress, ImageLoadAddress> instruction;
|
||||
} [[sealed, format("hex::type::impl::format_instruction")]];
|
||||
|
||||
/**
|
||||
A machine code instruction which will get disassembled using Intel syntax
|
||||
@tparam DisassemblerSetting A string containing the config for the disassembler in the form of "architecture; setting1, setting2, no-setting3"
|
||||
@tparam ImageBaseAddress Start address of the instruction region in the data
|
||||
@tparam ImageLoadAddress Address where the instructions will be loaded into memory
|
||||
*/
|
||||
using InstructionIntel<auto DisassemblerSetting, auto ImageBaseAddress, auto ImageLoadAddress> = Instruction<DisassemblerSetting, "intel", ImageBaseAddress, ImageLoadAddress>;
|
||||
|
||||
/**
|
||||
A machine code instruction which will get disassembled using AT&T syntax
|
||||
@tparam DisassemblerSetting A string containing the config for the disassembler in the form of "architecture; setting1, setting2, no-setting3"
|
||||
@tparam ImageBaseAddress Start address of the instruction region in the data
|
||||
@tparam ImageLoadAddress Address where the instructions will be loaded into memory
|
||||
*/
|
||||
using InstructionATNT<auto DisassemblerSetting, auto ImageBaseAddress, auto ImageLoadAddress> = Instruction<DisassemblerSetting, "at&t", ImageBaseAddress, ImageLoadAddress>;
|
||||
|
||||
/**
|
||||
A machine code instruction which will get disassembled using MASM syntax
|
||||
@tparam DisassemblerSetting A string containing the config for the disassembler in the form of "architecture; setting1, setting2, no-setting3"
|
||||
@tparam ImageBaseAddress Start address of the instruction region in the data
|
||||
@tparam ImageLoadAddress Address where the instructions will be loaded into memory
|
||||
*/
|
||||
using InstructionMASM<auto DisassemblerSetting, auto ImageBaseAddress, auto ImageLoadAddress> = Instruction<DisassemblerSetting, "masm", ImageBaseAddress, ImageLoadAddress>;
|
||||
|
||||
/**
|
||||
A machine code instruction which will get disassembled using Motorola syntax
|
||||
@tparam DisassemblerSetting A string containing the config for the disassembler in the form of "architecture; setting1, setting2, no-setting3"
|
||||
@tparam ImageBaseAddress Start address of the instruction region in the data
|
||||
@tparam ImageLoadAddress Address where the instructions will be loaded into memory
|
||||
*/
|
||||
using InstructionMotorola<auto DisassemblerSetting, auto ImageBaseAddress, auto ImageLoadAddress> = Instruction<DisassemblerSetting, "motorola", ImageBaseAddress, ImageLoadAddress>;
|
||||
|
||||
namespace impl {
|
||||
|
||||
fn format_instruction(ref auto instruction) {
|
||||
return instruction.instruction;
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
66
includes/hex/type/json.pat
Normal file
66
includes/hex/type/json.pat
Normal file
@@ -0,0 +1,66 @@
|
||||
#pragma once
|
||||
|
||||
import hex.impl.imhex_check;
|
||||
|
||||
/*!
|
||||
Types to decode JSON and JSON-like file formats into a pattern tree
|
||||
*/
|
||||
|
||||
namespace auto hex::type {
|
||||
|
||||
/**
|
||||
Type representing a JSON string
|
||||
@tparam Size size of the string
|
||||
*/
|
||||
struct Json<auto Size> {
|
||||
char __data[Size] [[hidden, no_unique_address]];
|
||||
builtin::hex::dec::Json<__data> json [[merge]];
|
||||
};
|
||||
|
||||
/**
|
||||
Type representing Bson data
|
||||
@tparam Size size of the data
|
||||
*/
|
||||
struct Bson<auto Size> {
|
||||
u8 __data[Size] [[hidden, no_unique_address]];
|
||||
builtin::hex::dec::Bson<__data> bson [[merge]];
|
||||
};
|
||||
|
||||
/**
|
||||
Type representing Cbor data
|
||||
@tparam Size size of the data
|
||||
*/
|
||||
struct Cbor<auto Size> {
|
||||
u8 __data[Size] [[hidden, no_unique_address]];
|
||||
builtin::hex::dec::Cbor<__data> cbor [[merge]];
|
||||
};
|
||||
|
||||
/**
|
||||
Type representing Bjdata data
|
||||
@tparam Size size of the data
|
||||
*/
|
||||
struct Bjdata<auto Size> {
|
||||
u8 __data[Size] [[hidden, no_unique_address]];
|
||||
builtin::hex::dec::Bjdata<__data> bjdata [[merge]];
|
||||
};
|
||||
|
||||
/**
|
||||
Type representing Msgpack data
|
||||
@tparam Size size of the data
|
||||
*/
|
||||
struct Msgpack<auto Size> {
|
||||
u8 __data[Size] [[hidden, no_unique_address]];
|
||||
builtin::hex::dec::Msgpack<__data> msgpack [[merge]];
|
||||
};
|
||||
|
||||
/**
|
||||
Type representing Ubjson data
|
||||
@tparam Size size of the data
|
||||
*/
|
||||
struct Ubjson<auto 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")]];
|
||||
|
||||
|
||||
70
includes/std/attrs.pat
Normal file
70
includes/std/attrs.pat
Normal file
@@ -0,0 +1,70 @@
|
||||
import std.io;
|
||||
import std.core;
|
||||
|
||||
/*!
|
||||
The attributes library contains a set of attributes that can be used to annotate types with certain properties.
|
||||
To use an attribute, simply make your custom type inherit from the attribute type you want to use.
|
||||
|
||||
For example, to make a type hidden, you can use the `Hidden` attribute like this:
|
||||
|
||||
```rust
|
||||
struct MyType : std::attr::Hidden {
|
||||
// ...
|
||||
};
|
||||
```
|
||||
*/
|
||||
|
||||
namespace auto std::attr {
|
||||
|
||||
/**
|
||||
Attribute that marks a type as a literal type.
|
||||
This means the type behaves like a built-in type in the sense that it doesn't show its internal state and its display value is determined by a format function.
|
||||
It can also be transformed into a different built-in literal when used in an expression.
|
||||
@tparam FormatFunction The format function to use. The return value of this function is used to display the value of the literal and also determines the value returned when the literal is used in an expression.
|
||||
*/
|
||||
struct Literal<auto FormatFunction> { }
|
||||
[[sealed, format_read(FormatFunction), transform(FormatFunction)]];
|
||||
|
||||
/**
|
||||
Attribute that changes the name of the variable created from a type.
|
||||
@tparam Name The name of the variable created
|
||||
*/
|
||||
struct Named<auto Name> { }
|
||||
[[name(Name)]];
|
||||
|
||||
/**
|
||||
Attribute that adds a comment to the variable created from a type.
|
||||
@tparam Comment The comment to add
|
||||
*/
|
||||
struct Commented<auto Comment> {}
|
||||
[[comment(Comment)]];
|
||||
|
||||
/**
|
||||
Attribute that marks a type as hidden.
|
||||
This means variables of this type are not displayed in the UI.
|
||||
*/
|
||||
struct Hidden {}
|
||||
[[hidden]];
|
||||
|
||||
/**
|
||||
Attribute that marks a type as hidden and also hides it from the highlighter.
|
||||
This means variables of this type are don't display any highlighting in the UI but are still visible.
|
||||
*/
|
||||
struct HighlightHidden {}
|
||||
[[highlight_hidden]];
|
||||
|
||||
/**
|
||||
Attribute that marks a type as inline.
|
||||
Creating a variable of this type will not create a new layer but instead dump the contents of the type directly into the current layer.
|
||||
*/
|
||||
struct Inlined {}
|
||||
[[inline]];
|
||||
|
||||
/**
|
||||
Attribute that marks a type as sealed.
|
||||
Sealed types don't display their internal state in the UI.
|
||||
*/
|
||||
struct Sealed {}
|
||||
[[sealed]];
|
||||
|
||||
}
|
||||
@@ -21,7 +21,7 @@ namespace auto std::bit {
|
||||
x = (x & a) + ((x >> 1) & a);
|
||||
x = (x & b) + ((x >> 2) & b);
|
||||
x = (x & c) + ((x >> 4) & c);
|
||||
|
||||
|
||||
return x % 0xFF;
|
||||
};
|
||||
|
||||
@@ -33,19 +33,19 @@ namespace auto std::bit {
|
||||
fn has_single_bit(u128 x) {
|
||||
return x != 0 && (x & (x - 1)) == 0;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
Rounds the given number up to the next bigger power of two
|
||||
@param x The number
|
||||
@return Next bigger power of two that can fit `x`
|
||||
*/
|
||||
fn bit_ceil(u128 x) {
|
||||
fn bit_ceil(u128 x) {
|
||||
if (x == 0) return 0;
|
||||
|
||||
|
||||
u8 i;
|
||||
while ((1 << i) < x)
|
||||
i = i + 1;
|
||||
|
||||
|
||||
return 1 << i;
|
||||
};
|
||||
|
||||
@@ -56,11 +56,11 @@ namespace auto std::bit {
|
||||
*/
|
||||
fn bit_floor(u128 x) {
|
||||
if (x == 0) return 0;
|
||||
|
||||
|
||||
u8 i;
|
||||
while ((x >> i) > 0)
|
||||
i = i + 1;
|
||||
|
||||
|
||||
return 1 << (i - 1);
|
||||
};
|
||||
|
||||
|
||||
@@ -56,17 +56,17 @@ namespace auto std::core {
|
||||
|
||||
|
||||
/**
|
||||
Sets the current default endianess.
|
||||
Any patterns created following this attribute will be created using the set endianess.
|
||||
@param endian The new default endianess
|
||||
Sets the current default endianness.
|
||||
Any patterns created following this attribute will be created using the set endianness.
|
||||
@param endian The new default endianness
|
||||
*/
|
||||
fn set_endian(std::mem::Endian endian) {
|
||||
builtin::std::core::set_endian(u32(endian));
|
||||
};
|
||||
|
||||
/**
|
||||
Gets the current default endianess.
|
||||
@return The currently set default endianess
|
||||
Gets the current default endianness.
|
||||
@return The currently set default endianness
|
||||
*/
|
||||
fn get_endian() {
|
||||
return builtin::std::core::get_endian();
|
||||
@@ -159,10 +159,10 @@ namespace auto std::core {
|
||||
/**
|
||||
Changes the comment attached to a pattern
|
||||
@param pattern The pattern to modify
|
||||
@param name The new comment of the pattern
|
||||
@param comment The new comment of the pattern
|
||||
*/
|
||||
fn set_pattern_comment(ref auto pattern, str comment) {
|
||||
builtin::std::core::set_pattern_comment(pattern, name);
|
||||
builtin::std::core::set_pattern_comment(pattern, comment);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -173,4 +173,20 @@ namespace auto std::core {
|
||||
fn execute_function(str function_name, auto ... args) {
|
||||
builtin::std::core::execute_function(function_name, args);
|
||||
};
|
||||
|
||||
/**
|
||||
Sets the pattern color palette for all future created patterns
|
||||
@param args RGBA8 colors as 32 bit integers (0xAABBGGRR)
|
||||
*/
|
||||
fn set_pattern_palette_colors(auto ... colors) {
|
||||
builtin::std::core::set_pattern_palette_colors(colors);
|
||||
};
|
||||
|
||||
/**
|
||||
Resets the current pattern palette progress back to zero.
|
||||
This can be useful to force all instances of a type to have the same coloring for its members
|
||||
*/
|
||||
fn reset_pattern_palette() {
|
||||
builtin::std::core::reset_pattern_palette();
|
||||
};
|
||||
}
|
||||
|
||||
@@ -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 <= '~';
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
/*!
|
||||
The File library allows reading and writing from/to external files using
|
||||
The File library allows reading and writing from/to external files using
|
||||
a C-like File IO API.
|
||||
|
||||
**These functions are considered dangerous and require the user to manually permit them**
|
||||
@@ -13,7 +13,7 @@ namespace auto std::file {
|
||||
A handle representing a file that has been opened
|
||||
*/
|
||||
using Handle = s32;
|
||||
|
||||
|
||||
/**
|
||||
The mode to open a file in.
|
||||
Read opens the file in read-only mode
|
||||
@@ -45,7 +45,7 @@ namespace auto std::file {
|
||||
builtin::std::file::close(handle);
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
Reads the content of a file into a string
|
||||
@param handle The file handle to read from
|
||||
@@ -85,14 +85,14 @@ namespace auto std::file {
|
||||
};
|
||||
|
||||
/**
|
||||
Resizes a file
|
||||
Resizes a file
|
||||
@param handle The handle of the file to resize
|
||||
*/
|
||||
fn resize(Handle handle, u64 size) {
|
||||
builtin::std::file::resize(handle, size);
|
||||
};
|
||||
|
||||
/**
|
||||
/**
|
||||
Flushes changes made to a file to disk
|
||||
@param handle The handle of the file to flush
|
||||
*/
|
||||
|
||||
@@ -20,7 +20,7 @@ namespace auto std::fxpt {
|
||||
fn to_float(fixed fxt, u32 precision) {
|
||||
return double(fxt) / double((1 << precision));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
Converts a floating point value into a fixed point value
|
||||
@param flt The floating point value to convert
|
||||
@@ -41,7 +41,7 @@ namespace auto std::fxpt {
|
||||
fn change_precision(fixed value, u32 start_precision, u32 end_precision) {
|
||||
return std::fxpt::to_fixed(std::fxpt::to_float(value, start_precision), end_precision);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
Adds two fixed point numbers with a given precision together
|
||||
@param a First fixed point number
|
||||
@@ -52,7 +52,7 @@ namespace auto std::fxpt {
|
||||
fn add(fixed a, fixed b, u32 precision) {
|
||||
return a + b;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
Subtracts two fixed point numbers with a given precision together
|
||||
@param a First fixed point number
|
||||
@@ -63,7 +63,7 @@ namespace auto std::fxpt {
|
||||
fn subtract(fixed a, fixed b, u32 precision) {
|
||||
return a - b;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
Multiplies two fixed point numbers with a given precision together
|
||||
@param a First fixed point number
|
||||
@@ -74,7 +74,7 @@ namespace auto std::fxpt {
|
||||
fn multiply(fixed a, fixed b, u32 precision) {
|
||||
return (a * b) / (1 << precision);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
Divides two fixed point numbers with a given precision together
|
||||
@param a First fixed point number
|
||||
|
||||
@@ -14,7 +14,7 @@ namespace auto std::hash {
|
||||
@param xorout The CRC8 XOR-Out value
|
||||
@param reflect_in Whether or not the input bytes should be reflected
|
||||
@param reflect_out Whether or not the output should be reflected
|
||||
@return Calculated CRC8 hash
|
||||
@return Calculated CRC8 hash
|
||||
*/
|
||||
fn crc8(ref auto pattern, u8 init, u8 poly, u8 xorout, bool reflect_in, bool reflect_out) {
|
||||
return builtin::std::hash::crc8(pattern, init, poly, xorout, reflect_in, reflect_out);
|
||||
@@ -28,7 +28,7 @@ namespace auto std::hash {
|
||||
@param xorout The CRC16 XOR-Out value
|
||||
@param reflect_in Whether or not the input bytes should be reflected
|
||||
@param reflect_out Whether or not the output should be reflected
|
||||
@return Calculated CRC16 hash
|
||||
@return Calculated CRC16 hash
|
||||
*/
|
||||
fn crc16(ref auto pattern, u16 init, u16 poly, u16 xorout, bool reflect_in, bool reflect_out) {
|
||||
return builtin::std::hash::crc16(pattern, init, poly, xorout, reflect_in, reflect_out);
|
||||
@@ -42,7 +42,7 @@ namespace auto std::hash {
|
||||
@param xorout The CRC32 XOR-Out value
|
||||
@param reflect_in Whether or not the input bytes should be reflected
|
||||
@param reflect_out Whether or not the output should be reflected
|
||||
@return Calculated CRC32 hash
|
||||
@return Calculated CRC32 hash
|
||||
*/
|
||||
fn crc32(ref auto pattern, u32 init, u32 poly, u32 xorout, bool reflect_in, bool reflect_out) {
|
||||
return builtin::std::hash::crc32(pattern, init, poly, xorout, reflect_in, reflect_out);
|
||||
@@ -56,7 +56,7 @@ namespace auto std::hash {
|
||||
@param xorout The CRC64 XOR-Out value
|
||||
@param reflect_in Whether or not the input bytes should be reflected
|
||||
@param reflect_out Whether or not the output should be reflected
|
||||
@return Calculated CRC64 hash
|
||||
@return Calculated CRC64 hash
|
||||
*/
|
||||
fn crc64(ref auto pattern, u64 init, u64 poly, u64 xorout, bool reflect_in, bool reflect_out) {
|
||||
return builtin::std::hash::crc64(pattern, init, poly, xorout, reflect_in, reflect_out);
|
||||
|
||||
@@ -9,21 +9,21 @@ namespace auto std {
|
||||
/**
|
||||
Formats the given arguments using the format string and prints the result to the console
|
||||
This function uses the C++20 `std::format` or libfmt's `fmt::format` syntax.
|
||||
@param fmt Format string
|
||||
@param fmt Format string or any other value that can be converted to a string
|
||||
@param args Values to use in the formatting
|
||||
*/
|
||||
fn print(str fmt, auto ... args) {
|
||||
fn print(auto fmt, auto ... args) {
|
||||
builtin::std::print(fmt, args);
|
||||
};
|
||||
|
||||
/**
|
||||
Formats the given arguments using the format string and returns the result as a string
|
||||
This function uses the C++20 `std::format` or libfmt's `fmt::format` syntax.
|
||||
@param fmt Format string
|
||||
@param fmt Format string or any other value that can be converted to a string
|
||||
@param args Values to use in the formatting
|
||||
@return The formatted string
|
||||
*/
|
||||
fn format(str fmt, auto ... args) {
|
||||
fn format(auto fmt, auto ... args) {
|
||||
return builtin::std::format(fmt, args);
|
||||
};
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
*/
|
||||
|
||||
namespace auto std::limits {
|
||||
|
||||
|
||||
/**
|
||||
Returns the minimum value that can be stored in a `u8`.
|
||||
@return Minimum value
|
||||
@@ -13,7 +13,7 @@ namespace auto std::limits {
|
||||
fn u8_min() {
|
||||
return u8(0);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
Returns the maximum value that can be stored in a `u8`.
|
||||
@return Maximum value
|
||||
@@ -29,7 +29,7 @@ namespace auto std::limits {
|
||||
fn s8_min() {
|
||||
return -s8((std::limits::u8_max() / 2)) - 1;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
Returns the maximum value that can be stored in a `s8`.
|
||||
@return Maximum value
|
||||
@@ -45,7 +45,7 @@ namespace auto std::limits {
|
||||
fn u16_min() {
|
||||
return u16(0);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
Returns the maximum value that can be stored in a `u16`.
|
||||
@return Maximum value
|
||||
@@ -53,7 +53,7 @@ namespace auto std::limits {
|
||||
fn u16_max() {
|
||||
return u16(-1);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
Returns the minimum value that can be stored in a `s16`.
|
||||
@return Minimum value
|
||||
@@ -61,7 +61,7 @@ namespace auto std::limits {
|
||||
fn s16_min() {
|
||||
return -s16((std::limits::u16_max() / 2)) - 1;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
Returns the maximum value that can be stored in a `s16`.
|
||||
@return Maximum value
|
||||
@@ -69,7 +69,7 @@ namespace auto std::limits {
|
||||
fn s16_max() {
|
||||
return s16((std::limits::u16_max() / 2));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
Returns the minimum value that can be stored in a `u32`.
|
||||
@return Minimum value
|
||||
@@ -77,7 +77,7 @@ namespace auto std::limits {
|
||||
fn u32_min() {
|
||||
return u32(0);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
Returns the maximum value that can be stored in a `u32`.
|
||||
@return Maximum value
|
||||
@@ -85,7 +85,7 @@ namespace auto std::limits {
|
||||
fn u32_max() {
|
||||
return u32(-1);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
Returns the minimum value that can be stored in a `s32`.
|
||||
@return Minimum value
|
||||
@@ -93,7 +93,7 @@ namespace auto std::limits {
|
||||
fn s32_min() {
|
||||
return -s32((std::limits::u32_max() / 2)) - 1;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
Returns the maximum value that can be stored in a `s32`.
|
||||
@return Maximum value
|
||||
@@ -101,7 +101,7 @@ namespace auto std::limits {
|
||||
fn s32_max() {
|
||||
return s32((std::limits::u32_max() / 2));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
Returns the minimum value that can be stored in a `u64`.
|
||||
@return Minimum value
|
||||
@@ -109,7 +109,7 @@ namespace auto std::limits {
|
||||
fn u64_min() {
|
||||
return u64(0);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
Returns the maximum value that can be stored in a `u64`.
|
||||
@return Maximum value
|
||||
@@ -117,7 +117,7 @@ namespace auto std::limits {
|
||||
fn u64_max() {
|
||||
return u64(-1);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
Returns the minimum value that can be stored in a `s64`.
|
||||
@return Minimum value
|
||||
@@ -125,7 +125,7 @@ namespace auto std::limits {
|
||||
fn s64_min() {
|
||||
return -s64((std::limits::u64_max() / 2)) - 1;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
Returns the maximum value that can be stored in a `s64`.
|
||||
@return Maximum value
|
||||
@@ -133,7 +133,7 @@ namespace auto std::limits {
|
||||
fn s64_max() {
|
||||
return s64((std::limits::u64_max() / 2));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
Returns the minimum value that can be stored in a `u128`.
|
||||
@return Minimum value
|
||||
@@ -141,7 +141,7 @@ namespace auto std::limits {
|
||||
fn u128_min() {
|
||||
return u128(0);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
Returns the maximum value that can be stored in a `u128`.
|
||||
@return Maximum value
|
||||
@@ -149,7 +149,7 @@ namespace auto std::limits {
|
||||
fn u128_max() {
|
||||
return u128(-1);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
Returns the minimum value that can be stored in a `s128`.
|
||||
@return Minimum value
|
||||
@@ -157,7 +157,7 @@ namespace auto std::limits {
|
||||
fn s128_min() {
|
||||
return -s128((std::limits::u128_max() / 2)) - 1;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
Returns the maximum value that can be stored in a `s128`.
|
||||
@return Maximum value
|
||||
@@ -165,5 +165,5 @@ namespace auto std::limits {
|
||||
fn s128_max() {
|
||||
return s128((std::limits::u128_max() / 2));
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ namespace auto std::math {
|
||||
else
|
||||
return b;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
Compares the values `a` and `b` with each other and returns the bigger of the two
|
||||
@param a First value
|
||||
@@ -56,9 +56,9 @@ namespace auto std::math {
|
||||
@return `x` if `x` is positive, `-x` otherwise
|
||||
*/
|
||||
fn abs(auto x) {
|
||||
if (x < 0)
|
||||
if (x < 0)
|
||||
return -x;
|
||||
else
|
||||
else
|
||||
return x;
|
||||
};
|
||||
|
||||
@@ -96,13 +96,13 @@ namespace auto std::math {
|
||||
*/
|
||||
fn factorial(u128 x) {
|
||||
u128 result;
|
||||
|
||||
|
||||
result = x;
|
||||
while (x > 1) {
|
||||
x = x - 1;
|
||||
result = result * x;
|
||||
}
|
||||
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
@@ -336,5 +336,5 @@ namespace auto std::math {
|
||||
fn accumulate(u128 start, u128 end, u128 valueSize, std::mem::Section section = 0, AccumulateOperation operation = AccumulateOperation::Add, std::mem::Endian endian = std::mem::Endian::Native) {
|
||||
return builtin::std::math::accumulate(start, end, valueSize, section, u128(operation), u128(endian));
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -6,30 +6,15 @@
|
||||
|
||||
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
|
||||
*/
|
||||
using Section = u128;
|
||||
const u64 SectionMain = 0;
|
||||
const u64 SectionCurrent = 0xFFFF'FFFF'FFFF'FFFF;
|
||||
|
||||
/**
|
||||
The Endianess of a value
|
||||
The endianness of a value
|
||||
*/
|
||||
enum Endian : u8 {
|
||||
Native = 0,
|
||||
@@ -46,6 +31,15 @@ namespace auto std::mem {
|
||||
return $ >= (std::mem::base_address() + std::mem::size());
|
||||
};
|
||||
|
||||
/**
|
||||
Function that returns true if the cursor position is at or beyond the given address
|
||||
@param address The address to compare against
|
||||
@return True if the cursor is at or beyond the given address
|
||||
*/
|
||||
fn reached(u128 address) {
|
||||
return $ >= address;
|
||||
};
|
||||
|
||||
/**
|
||||
Aligns the given value to the given alignment
|
||||
@param alignment The alignment to align to
|
||||
@@ -57,22 +51,22 @@ namespace auto std::mem {
|
||||
|
||||
return remainder != 0 ? value + (alignment - remainder) : value;
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
Gets the base address of the data
|
||||
@return The base address of the memory
|
||||
*/
|
||||
fn base_address() {
|
||||
return builtin::std::mem::base_address();
|
||||
fn base_address(u64 section = SectionCurrent) {
|
||||
return builtin::std::mem::base_address(section);
|
||||
};
|
||||
|
||||
/**
|
||||
Gets the size of the data
|
||||
@return The size of the memory
|
||||
*/
|
||||
fn size() {
|
||||
return builtin::std::mem::size();
|
||||
fn size(u64 section = SectionCurrent) {
|
||||
return builtin::std::mem::size(section);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -82,8 +76,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);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -106,8 +100,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);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -126,22 +120,22 @@ namespace auto std::mem {
|
||||
Reads a unsigned value from the memory
|
||||
@param address The address to read from
|
||||
@param size The size of the value to read
|
||||
@param [endian] The endianess of the value to read. Defaults to native
|
||||
@param [endian] The endianness of the value to read. Defaults to native
|
||||
@return The value read
|
||||
*/
|
||||
fn read_unsigned(u128 address, u8 size, Endian endian = Endian::Native) {
|
||||
return builtin::std::mem::read_unsigned(address, size, u32(endian));
|
||||
fn read_unsigned(u128 address, u8 size, Endian endian = Endian::Native, Section section = SectionCurrent) {
|
||||
return builtin::std::mem::read_unsigned(address, size, u32(endian), section);
|
||||
};
|
||||
|
||||
/**
|
||||
Reads a signed value from the memory
|
||||
@param address The address to read from
|
||||
@param size The size of the value to read
|
||||
@param [endian] The endianess of the value to read. Defaults to native
|
||||
@param [endian] The endianness of the value to read. Defaults to native
|
||||
@return The value read
|
||||
*/
|
||||
fn read_signed(u128 address, u8 size, Endian endian = Endian::Native) {
|
||||
return builtin::std::mem::read_signed(address, size, u32(endian));
|
||||
fn read_signed(u128 address, u8 size, Endian endian = Endian::Native, Section section = SectionCurrent) {
|
||||
return builtin::std::mem::read_signed(address, size, u32(endian), section);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -150,8 +144,8 @@ namespace auto std::mem {
|
||||
@param size The size of the value to read
|
||||
@return The value read
|
||||
*/
|
||||
fn read_string(u128 address, u128 size) {
|
||||
return builtin::std::mem::read_string(address, size);
|
||||
fn read_string(u128 address, u128 size, Section section = SectionCurrent) {
|
||||
return builtin::std::mem::read_string(address, size, section);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -233,26 +227,16 @@ 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
|
||||
@tparam To The type to reinterpret to
|
||||
*/
|
||||
union Reinterpreter<From, To> {
|
||||
From from;
|
||||
To to;
|
||||
From from_value;
|
||||
To to_value;
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
Aligns the cursor to the given alignment
|
||||
@@ -271,11 +255,33 @@ namespace auto std::mem {
|
||||
} [[sealed, format("std::mem::impl::format_bytes")]];
|
||||
|
||||
namespace impl {
|
||||
|
||||
|
||||
fn format_bytes(auto bytes) {
|
||||
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;
|
||||
}
|
||||
```
|
||||
*/
|
||||
@@ -57,7 +57,7 @@ namespace auto std::ptr {
|
||||
// `pointerValue` is `no_unique_address` because we don't want to advance
|
||||
// the current memory location after reading the value of the pointer itself;
|
||||
// we want to examine the value at this address to determine what should be
|
||||
// displayed. It's also `hidden` so the editor only displays either thee
|
||||
// displayed. It's also `hidden` so the editor only displays either thee
|
||||
// padding or the populated pointer/pointee field.
|
||||
PointerTy pointerValue [[no_unique_address, hidden]];
|
||||
if (pointerValue == 0x0) {
|
||||
|
||||
@@ -7,7 +7,7 @@ import std.limits;
|
||||
*/
|
||||
|
||||
namespace auto std::random {
|
||||
|
||||
|
||||
/**
|
||||
Represents the type of distribution to use to generate a random number
|
||||
*/
|
||||
@@ -68,7 +68,7 @@ namespace auto std::random {
|
||||
return builtin::std::random::generate(u32(distribution), param1, param2);
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
Generates a uniformly distributed random number between `min` and `max`
|
||||
@param [min] Minimum number. Defaults to 0
|
||||
@@ -77,5 +77,5 @@ namespace auto std::random {
|
||||
fn generate(u64 min = std::limits::u64_min(), u64 max = std::limits::u64_max()) {
|
||||
return std::random::generate_using(Distribution::Uniform, min, max);
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -4,13 +4,13 @@ import std.io;
|
||||
import std.mem;
|
||||
|
||||
/*!
|
||||
Libray to interact with strings.
|
||||
Library to interact with strings.
|
||||
*/
|
||||
|
||||
namespace auto std::string {
|
||||
|
||||
/**
|
||||
Base type for sized strings. Represents a string with its size preceeding it.
|
||||
Base type for sized strings. Represents a string with its size preceding it.
|
||||
@tparam SizeType The type of the size field.
|
||||
@tparam DataType The type of the characters.
|
||||
*/
|
||||
@@ -36,7 +36,7 @@ namespace auto std::string {
|
||||
@tparam DataType The type of the characters.
|
||||
*/
|
||||
struct NullStringBase<DataType> {
|
||||
DataType string[while(std::mem::read_unsigned($, sizeof(DataType)) != 0x00)];
|
||||
DataType data[while(std::mem::read_unsigned($, sizeof(DataType)) != 0x00)];
|
||||
DataType null_terminator;
|
||||
} [[sealed, format("std::string::impl::format_string"), transform("std::string::impl::format_string")]];
|
||||
|
||||
@@ -125,6 +125,8 @@ namespace auto std::string {
|
||||
@return True if the string starts with the substring, false otherwise.
|
||||
*/
|
||||
fn starts_with(str string, str part) {
|
||||
if (std::string::length(string) < std::string::length(part))
|
||||
return false;
|
||||
return std::string::substr(string, 0, std::string::length(part)) == part;
|
||||
};
|
||||
|
||||
@@ -135,6 +137,8 @@ namespace auto std::string {
|
||||
@return True if the string ends with the substring, false otherwise.
|
||||
*/
|
||||
fn ends_with(str string, str part) {
|
||||
if (std::string::length(string) < std::string::length(part))
|
||||
return false;
|
||||
return std::string::substr(string, std::string::length(string) - std::string::length(part), std::string::length(part)) == part;
|
||||
};
|
||||
|
||||
@@ -161,16 +165,16 @@ namespace auto std::string {
|
||||
@param string The string to reverse.
|
||||
@return The reversed string.
|
||||
*/
|
||||
fn reverse(str string) {
|
||||
fn reverse(str string) {
|
||||
str result;
|
||||
|
||||
|
||||
s32 i;
|
||||
i = std::string::length(string);
|
||||
while (i > 0) {
|
||||
i = i - 1;
|
||||
result = result + std::string::at(string, i);
|
||||
}
|
||||
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
@@ -181,23 +185,23 @@ namespace auto std::string {
|
||||
*/
|
||||
fn to_upper(str string) {
|
||||
str result;
|
||||
|
||||
|
||||
u32 i;
|
||||
char c;
|
||||
while (i < std::string::length(string)) {
|
||||
c = std::string::at(string, i);
|
||||
|
||||
|
||||
if (c >= 'a' && c <= 'z')
|
||||
result = result + char(c - 0x20);
|
||||
else
|
||||
result = result + c;
|
||||
|
||||
|
||||
i = i + 1;
|
||||
}
|
||||
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
Converts a string to lower case.
|
||||
@param string The string to convert.
|
||||
@@ -205,20 +209,20 @@ namespace auto std::string {
|
||||
*/
|
||||
fn to_lower(str string) {
|
||||
str result;
|
||||
|
||||
|
||||
u32 i;
|
||||
char c;
|
||||
while (i < std::string::length(string)) {
|
||||
c = std::string::at(string, i);
|
||||
|
||||
|
||||
if (c >= 'A' && c <= 'Z')
|
||||
result = result + char(c + 0x20);
|
||||
else
|
||||
result = result + c;
|
||||
|
||||
|
||||
i = i + 1;
|
||||
}
|
||||
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
|
||||
@@ -50,7 +50,7 @@ namespace auto std {
|
||||
};
|
||||
|
||||
/**
|
||||
Throws an error notifying the developer that the current codepath is not implemented currently.
|
||||
Throws an error notifying the developer that the current code path is not implemented currently.
|
||||
*/
|
||||
fn unimplemented() {
|
||||
std::error("Unimplemented code path reached!");
|
||||
|
||||
@@ -8,7 +8,7 @@ import std.core;
|
||||
*/
|
||||
|
||||
namespace auto type {
|
||||
|
||||
|
||||
/**
|
||||
Type visualizing the value of each individual bit
|
||||
*/
|
||||
@@ -22,7 +22,7 @@ namespace auto type {
|
||||
bit6 : 1;
|
||||
bit7 : 1;
|
||||
} [[format("type::impl::format_bits"), bitfield_order(std::core::BitfieldOrder::LeastToMostSignificant, 8)]];
|
||||
|
||||
|
||||
/**
|
||||
Type visualizing the value of the two nibbles
|
||||
*/
|
||||
@@ -30,9 +30,9 @@ namespace auto type {
|
||||
low : 4;
|
||||
high : 4;
|
||||
} [[format("type::impl::format_nibbles")]];
|
||||
|
||||
|
||||
/**
|
||||
Type representing a single Byte. Decodes the byte as it's hexadeicmal value, individual bits and nibbles
|
||||
Type representing a single Byte. Decodes the byte as it's hexadecimal value, individual bits and nibbles
|
||||
*/
|
||||
union Byte {
|
||||
u8 value;
|
||||
@@ -50,9 +50,9 @@ namespace auto type {
|
||||
byte.bits.bit0,
|
||||
byte.bits.bit7);
|
||||
};
|
||||
|
||||
|
||||
fn format_bits(Bits bits) {
|
||||
return std::format("0b{}{}{}{}{}{}{}{}",
|
||||
return std::format("0b{}{}{}{}{}{}{}{}",
|
||||
bits.bit7,
|
||||
bits.bit6,
|
||||
bits.bit5,
|
||||
@@ -62,7 +62,7 @@ namespace auto type {
|
||||
bits.bit1,
|
||||
bits.bit0);
|
||||
};
|
||||
|
||||
|
||||
fn format_nibbles(Nibbles nibbles) {
|
||||
return std::format("{{ {0:0X}, {1:0X} }}", nibbles.high, nibbles.low);
|
||||
};
|
||||
|
||||
@@ -14,15 +14,15 @@ namespace auto type {
|
||||
@tparam R Number of bits used for the red component
|
||||
@tparam G Number of bits used for the green component
|
||||
@tparam B Number of bits used for the blue component
|
||||
@tparam A Number of bits used for the alpha component
|
||||
@tparam A Number of bits used for the alpha component
|
||||
*/
|
||||
bitfield RGBA<auto R, auto G, auto B, auto A> {
|
||||
r : R;
|
||||
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
|
||||
@tparam R Number of bits used for the red component
|
||||
@@ -30,7 +30,7 @@ namespace auto type {
|
||||
@tparam B Number of bits used for the blue component
|
||||
*/
|
||||
using RGB<auto R, auto G, auto B> = RGBA<R,G,B,0>;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
Type representing a RGBA color with 8 bits for the red component, 8 bits for green, 8 bits for blue and 8 bits for alpha
|
||||
@@ -56,7 +56,7 @@ namespace auto type {
|
||||
Type representing a RGBA color with 5 bits for the red component, 5 bits for green, 5 bits for blue and 1 bits for alpha
|
||||
*/
|
||||
using RGBA5551 = RGBA<5,5,5,1>;
|
||||
|
||||
|
||||
|
||||
namespace impl {
|
||||
|
||||
@@ -76,5 +76,5 @@ namespace auto type {
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -9,14 +9,14 @@ import std.mem;
|
||||
*/
|
||||
|
||||
namespace auto type {
|
||||
|
||||
|
||||
/**
|
||||
Type representing a 16 bit half precision floating point number
|
||||
*/
|
||||
using float16 = u16 [[format("type::impl::format_float16")]];
|
||||
|
||||
namespace impl {
|
||||
|
||||
|
||||
union U32ToFloatConverter {
|
||||
u32 intValue;
|
||||
float floatValue;
|
||||
@@ -26,20 +26,20 @@ namespace auto type {
|
||||
u32 sign = value >> 15;
|
||||
u32 exponent = (value >> 10) & 0x1F;
|
||||
u32 mantissa = value & 0x3FF;
|
||||
|
||||
|
||||
u32 result = 0x00;
|
||||
|
||||
|
||||
if (exponent == 0) {
|
||||
if (mantissa == 0) {
|
||||
result = sign << 31;
|
||||
} else {
|
||||
exponent = 0x7F - 14;
|
||||
|
||||
|
||||
while ((mantissa & (1 << 10)) == 0) {
|
||||
exponent -= 1;
|
||||
mantissa <<= 1;
|
||||
}
|
||||
|
||||
|
||||
mantissa &= 0x3FF;
|
||||
result = (sign << 31) | (exponent << 23) | (mantissa << 13);
|
||||
}
|
||||
@@ -48,11 +48,11 @@ namespace auto type {
|
||||
} else {
|
||||
result = (sign << 31) | ((exponent + (0x7F - 15)) << 23) | (mantissa << 13);
|
||||
}
|
||||
|
||||
|
||||
std::mem::Reinterpreter<u32, float> converter;
|
||||
converter.from = result;
|
||||
|
||||
return std::format("{}", converter.to);
|
||||
converter.from_value = result;
|
||||
|
||||
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 {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ namespace auto type {
|
||||
|
||||
fn format_guid(GUID guid) {
|
||||
bool valid = ((le u16(guid.time_high_and_version) >> 12) <= 5) && (((guid.clock_seq_and_reserved >> 4) >= 8) || ((guid.clock_seq_and_reserved >> 4) == 0));
|
||||
|
||||
|
||||
return std::format("{}{{{:08X}-{:04X}-{:04X}-{:02X}{:02X}-{:02X}{:02X}{:02X}{:02X}{:02X}{:02X}}}",
|
||||
valid ? "" : "Invalid ",
|
||||
le u32(guid.time_low),
|
||||
|
||||
@@ -8,7 +8,7 @@ import std.mem;
|
||||
*/
|
||||
|
||||
namespace auto type {
|
||||
|
||||
|
||||
/**
|
||||
Base LEB128 type. Use `uLEB128` and `sLEB128` instead.
|
||||
*/
|
||||
@@ -30,9 +30,9 @@ namespace auto type {
|
||||
Legacy alias for uLEB128
|
||||
*/
|
||||
using LEB128 = uLEB128;
|
||||
|
||||
|
||||
namespace impl {
|
||||
|
||||
|
||||
fn transform_uleb128_array(ref auto array) {
|
||||
u128 res = array[0] & 0x7f;
|
||||
for(u8 i = 1, array[i-1] & 0x80 != 0, i+=1) {
|
||||
@@ -41,19 +41,19 @@ namespace auto type {
|
||||
return res;
|
||||
};
|
||||
|
||||
fn transform_sleb128_array(ref auto array) {
|
||||
fn transform_sleb128_array(ref auto array) {
|
||||
s128 res = type::impl::transform_uleb128_array(array);
|
||||
if (res & 0x40 != 0) {
|
||||
if (res & 1 << ((sizeof(array) / sizeof(u8)) * 7 - 1) != 0) {
|
||||
res |= ~0 << (sizeof(array) / sizeof(u8)) * 7;
|
||||
}
|
||||
return res;
|
||||
};
|
||||
|
||||
|
||||
fn format_uleb128(ref auto leb128) {
|
||||
u128 res = type::impl::transform_uleb128_array(leb128.array);
|
||||
return std::format("{} ({:#x})", res, res);
|
||||
};
|
||||
|
||||
|
||||
fn transform_uleb128(ref auto leb128) {
|
||||
return type::impl::transform_uleb128_array(leb128.array);
|
||||
};
|
||||
@@ -62,11 +62,11 @@ namespace auto type {
|
||||
s128 res = type::impl::transform_sleb128_array(leb128.array);
|
||||
return std::format("{} ({:#x})", res, res);
|
||||
};
|
||||
|
||||
|
||||
fn transform_sleb128(ref auto leb128) {
|
||||
return type::impl::transform_sleb128_array(leb128.array);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -9,8 +9,13 @@ import std.ctype;
|
||||
|
||||
namespace auto type
|
||||
{
|
||||
fn fm(ref auto value)
|
||||
{
|
||||
|
||||
/**
|
||||
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
|
||||
*/
|
||||
fn escape_bytes(ref auto value) {
|
||||
str result;
|
||||
for (u32 i = 0, i < sizeof(value), i += 1)
|
||||
{
|
||||
@@ -21,23 +26,20 @@ namespace auto type
|
||||
else
|
||||
result += std::format("\\x{:02X}", u8(c));
|
||||
}
|
||||
return std::format("\"{}\"", result);
|
||||
return result;
|
||||
};
|
||||
|
||||
/**
|
||||
A Magic number. Throws an error if the magic number does not match the expected value
|
||||
@tparam ExpectedValue A string representing the expected value
|
||||
*/
|
||||
struct Magic<auto ExpectedValue>
|
||||
{
|
||||
struct Magic<auto ExpectedValue> {
|
||||
char value[std::string::length(ExpectedValue)];
|
||||
std::assert_warn(value == ExpectedValue, std::format("Invalid magic value! Expected {}, got {} at position 0x{:X}", type::fm(ExpectedValue), type::fm(value), $ - std::string::length(ExpectedValue)));
|
||||
std::assert(value == ExpectedValue, std::format("Invalid magic value! Expected \"{}\", got \"{}\" at position 0x{:X}", type::escape_bytes(ExpectedValue), type::escape_bytes(value), $ - std::string::length(ExpectedValue)));
|
||||
} [[sealed, format("type::impl::format_magic")]];
|
||||
namespace impl
|
||||
{
|
||||
fn format_magic(ref auto magic)
|
||||
{
|
||||
return type::fm(magic.value);
|
||||
namespace impl {
|
||||
fn format_magic(ref auto magic) {
|
||||
return std::format("\"{}\"", type::escape_bytes(magic.value));
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -8,10 +8,10 @@ namespace auto type {
|
||||
|
||||
/**
|
||||
Type representing a single path segment. Use the `Path` type instead of using this on its own
|
||||
@tparam Delimeter The delimeter sequence used to separate two path segments
|
||||
@tparam Delimiter The delimiter sequence used to separate two path segments
|
||||
*/
|
||||
struct PathSegment<auto Delimeter> {
|
||||
char string[while(std::mem::read_string($, std::string::length(Delimeter)) != Delimeter && std::mem::read_unsigned($, 1) != 0x00)];
|
||||
struct PathSegment<auto Delimiter> {
|
||||
char string[while(std::mem::read_string($, std::string::length(Delimiter)) != Delimiter && std::mem::read_unsigned($, 1) != 0x00)];
|
||||
char separator [[hidden]];
|
||||
|
||||
if (separator == 0x00) {
|
||||
@@ -21,20 +21,20 @@ namespace auto type {
|
||||
} [[sealed, format("type::impl::format_path_segment")]];
|
||||
|
||||
/**
|
||||
A generic type representing a path with an arbitrary delimeter
|
||||
@tparam Delimeter The delimeter sequence used to separate two path segments
|
||||
A generic type representing a path with an arbitrary delimiter
|
||||
@tparam Delimiter The delimiter sequence used to separate two path segments
|
||||
*/
|
||||
struct Path<auto Delimeter> {
|
||||
PathSegment<Delimeter> segments[while(true)];
|
||||
struct Path<auto Delimiter> {
|
||||
PathSegment<Delimiter> segments[while(true)];
|
||||
} [[format("type::impl::format_path")]];
|
||||
|
||||
/**
|
||||
A type representing a Unix path using a '/' forwardslash as delimeter
|
||||
A type representing a Unix path using a '/' forward slash as delimiter
|
||||
*/
|
||||
using UnixPath = Path<"/">;
|
||||
|
||||
/**
|
||||
A type representing a DOS path using a '\\' backslash as delimeter
|
||||
A type representing a DOS path using a '\\' backslash as delimiter
|
||||
*/
|
||||
using DOSPath = Path<"\\">;
|
||||
|
||||
|
||||
@@ -13,9 +13,9 @@ namespace auto type {
|
||||
A 32 bit Unix time value
|
||||
*/
|
||||
using time32_t = u32 [[format("type::impl::format_time_t")]];
|
||||
|
||||
|
||||
/**
|
||||
Alias name for `time32_t`
|
||||
Alias name for `time32_t`
|
||||
*/
|
||||
using time_t = time32_t;
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#pragma author WerWolv
|
||||
#pragma description Autodesk 3DS Max Model file
|
||||
#pragma description Autodesk 3DS Max Model
|
||||
|
||||
import std.io;
|
||||
import type.base;
|
||||
@@ -7,7 +7,7 @@ import type.base;
|
||||
#pragma MIME image/x-3ds
|
||||
|
||||
// Heavily based off of ZiZi's 010 Editor 3DS Template
|
||||
enum ChunkIdentifier : u16 {
|
||||
enum ChunkIdentifier : u16 {
|
||||
NULL_CHUNK = 0x0000,
|
||||
ChunkType = 0x0995,
|
||||
ChunkUnique = 0x0996,
|
||||
@@ -40,10 +40,10 @@ enum ChunkIdentifier : u16 {
|
||||
COLOR_24 = 0x0011, // r,g,b: Byte
|
||||
LIN_COLOR_24 = 0x0012, // r,g,b: Byte (gamma corrected)
|
||||
LIN_COLOR_F = 0x0013, // r,g,b: Single precision float (gamma corrected)
|
||||
|
||||
|
||||
INT_PERCENTAGE = 0x0030, // u16 integer
|
||||
FLOAT_PERCENTAGE = 0x0031, // Single precision float
|
||||
|
||||
|
||||
M3DMAGIC = 0x4D4D,
|
||||
SMAGIC = 0x2D2D,
|
||||
LMAGIC = 0x2D3D,
|
||||
@@ -72,7 +72,7 @@ enum ChunkIdentifier : u16 {
|
||||
RAY_BIAS = 0x1460,
|
||||
USE_RAYTRACE = 0x1470,
|
||||
O_CONSTS = 0x1500,
|
||||
|
||||
|
||||
AMBIENT_LIGHT = 0x2100,
|
||||
|
||||
FOG = 0x2200,
|
||||
@@ -82,7 +82,7 @@ enum ChunkIdentifier : u16 {
|
||||
USE_DISTANCE_CUE = 0x2301,
|
||||
WORLD_LAYERED_FOG = 0x2302,
|
||||
WORLD_USE_LAYERED_FOG = 0x2303,
|
||||
|
||||
|
||||
DEFAULT_VIEW = 0x3000,
|
||||
VIEW_TOP = 0x3010,
|
||||
VIEW_BOTTOM = 0x3020,
|
||||
@@ -93,7 +93,7 @@ enum ChunkIdentifier : u16 {
|
||||
VIEW_USER = 0x3070,
|
||||
VIEW_CAMERA = 0x3080,
|
||||
VIEW_WINDOW = 0x3090,
|
||||
|
||||
|
||||
NAMED_OBJECT = 0x4000,
|
||||
OBJ_HIDDEN = 0x4010,
|
||||
OBJ_VIS_LOFTER = 0x4011,
|
||||
@@ -103,7 +103,7 @@ enum ChunkIdentifier : u16 {
|
||||
OBJ_PROCEDURAL = 0x4015,
|
||||
OBJ_FROZEN = 0x4016,
|
||||
OBJ_DONT_RCVSHADOW = 0x4017,
|
||||
|
||||
|
||||
N_TRI_OBJECT = 0x4100,
|
||||
POINT_ARRAY = 0x4110,
|
||||
POINT_FLAG_ARRAY = 0x4111,
|
||||
@@ -134,7 +134,7 @@ enum ChunkIdentifier : u16 {
|
||||
DL_SPOT_OVERSHOOT = 0x4652,
|
||||
DL_SPOT_PROJECTOR = 0x4653,
|
||||
DL_EXCLUDE = 0x4654,
|
||||
DL_RANGE = 0x4655, /* Not used in R3 */
|
||||
DL_RANGE = 0x4655, /* Not used in R3 */
|
||||
DL_SPOT_ROLL = 0x4656,
|
||||
DL_SPOT_ASPECT = 0x4657,
|
||||
DL_RAY_BIAS = 0x4658,
|
||||
@@ -143,22 +143,22 @@ enum ChunkIdentifier : u16 {
|
||||
DL_INNER_RANGE = 0x4659,
|
||||
DL_OUTER_RANGE = 0x465A,
|
||||
DL_MULTIPLIER = 0x465B,
|
||||
|
||||
|
||||
N_AMBIENT_LIGHT = 0x4680,
|
||||
|
||||
|
||||
N_CAMERA = 0x4700,
|
||||
CAM_SEE_CONE = 0x4710,
|
||||
CAM_RANGES = 0x4720,
|
||||
|
||||
|
||||
HIERARCHY = 0x4F00,
|
||||
PARENT_OBJECT = 0x4F10,
|
||||
PIVOT_OBJECT = 0x4F20,
|
||||
PIVOT_LIMITS = 0x4F30,
|
||||
PIVOT_ORDER = 0x4F40,
|
||||
XLATE_RANGE = 0x4F50,
|
||||
|
||||
|
||||
POLY_2D = 0x5000,
|
||||
|
||||
|
||||
/* Flags in shaper file that tell whether polys make up an ok shape */
|
||||
SHAPE_OK = 0x5010,
|
||||
SHAPE_NOT_OK = 0x5011,
|
||||
@@ -177,8 +177,8 @@ enum ChunkIdentifier : u16 {
|
||||
YZ_CURVE = 0x6080,
|
||||
INTERPCT = 0x6090,
|
||||
DEFORM_LIMIT = 0x60A0,
|
||||
|
||||
/* Flags for Modeler options */
|
||||
|
||||
/* Flags for Modeler options */
|
||||
USE_CONTOUR = 0x6100,
|
||||
USE_TWEEN = 0x6110,
|
||||
USE_SCALE = 0x6120,
|
||||
@@ -187,7 +187,7 @@ enum ChunkIdentifier : u16 {
|
||||
USE_FIT = 0x6150,
|
||||
USE_BEVEL = 0x6160,
|
||||
|
||||
/* Viewport description chunks */
|
||||
/* Viewport description chunks */
|
||||
VIEWPORT_LAYOUT_OLD = 0x7000,
|
||||
VIEWPORT_DATA_OLD = 0x7010,
|
||||
VIEWPORT_LAYOUT = 0x7001,
|
||||
@@ -196,7 +196,7 @@ enum ChunkIdentifier : u16 {
|
||||
VIEWPORT_SIZE = 0x7020,
|
||||
NETWORK_VIEW = 0x7030,
|
||||
|
||||
/* External Application Data */
|
||||
/* External Application Data */
|
||||
XDATA_SECTION = 0x8000,
|
||||
XDATA_ENTRY = 0x8001,
|
||||
XDATA_APPNAME = 0x8002,
|
||||
@@ -215,8 +215,8 @@ enum ChunkIdentifier : u16 {
|
||||
XDATA_RFU1 = 0x800F,
|
||||
|
||||
PARENT_NAME = 0x80F0,
|
||||
|
||||
/* Material Chunk IDs */
|
||||
|
||||
/* Material Chunk IDs */
|
||||
MAT_ENTRY = 0xAFFF,
|
||||
MAT_NAME = 0xA000,
|
||||
MAT_AMBIENT = 0xA010,
|
||||
@@ -228,7 +228,7 @@ enum ChunkIdentifier : u16 {
|
||||
MAT_TRANSPARENCY = 0xA050,
|
||||
MAT_XPFALL = 0xA052,
|
||||
MAT_REFBLUR = 0xA053,
|
||||
|
||||
|
||||
MAT_SELF_ILLUM = 0xA080,
|
||||
MAT_TWO_SIDE = 0xA081,
|
||||
MAT_DECAL = 0xA082,
|
||||
@@ -241,13 +241,13 @@ enum ChunkIdentifier : u16 {
|
||||
MAT_XPFALLIN = 0xA08A,
|
||||
MAT_PHONGSOFT = 0xA08C,
|
||||
MAT_WIREABS = 0xA08E,
|
||||
|
||||
|
||||
MAT_SHADING = 0xA100,
|
||||
|
||||
|
||||
MAT_TEXMAP = 0xA200,
|
||||
MAT_MAPNAME = 0xA300,
|
||||
MAT_ACUBIC = 0xA310,
|
||||
|
||||
|
||||
MAT_MAP_TILINGOLD = 0xA350,
|
||||
MAT_MAP_TILING = 0xA351,
|
||||
MAT_MAP_TEXBLUR_OLD = 0xA352,
|
||||
@@ -262,14 +262,14 @@ enum ChunkIdentifier : u16 {
|
||||
MAT_MAP_RCOL = 0xA364,
|
||||
MAT_MAP_GCOL = 0xA366,
|
||||
MAT_MAP_BCOL = 0xA368,
|
||||
|
||||
|
||||
MAT_SPECMAP = 0xA204,
|
||||
MAT_OPACMAP = 0xA210,
|
||||
MAT_REFLMAP = 0xA220,
|
||||
MAT_BUMPMAP = 0xA230,
|
||||
MAT_USE_REFBLUR = 0xA250,
|
||||
MAT_BUMP_PERCENT = 0xA252,
|
||||
|
||||
|
||||
MAT_SXP_TEXT_DATA = 0xA320,
|
||||
MAT_SXP_TEXT2_DATA = 0xA321,
|
||||
MAT_SXP_OPAC_DATA = 0xA322,
|
||||
@@ -285,7 +285,7 @@ enum ChunkIdentifier : u16 {
|
||||
MAT_SXP_SHIN_MASKDATA = 0xA334,
|
||||
MAT_SXP_SELFI_MASKDATA = 0xA336,
|
||||
MAT_SXP_REFL_MASKDATA = 0xA338,
|
||||
|
||||
|
||||
MAT_TEX2MAP = 0xA33A,
|
||||
MAT_SHINMAP = 0xA33C,
|
||||
MAT_SELFIMAP = 0xA33D,
|
||||
@@ -297,8 +297,8 @@ enum ChunkIdentifier : u16 {
|
||||
MAT_SPECMASK = 0xA348,
|
||||
MAT_SELFIMASK = 0xA34A,
|
||||
MAT_REFLMASK = 0xA34C,
|
||||
|
||||
/* Keyframe Chunk IDs */
|
||||
|
||||
/* Keyframe Chunk IDs */
|
||||
KFDATA = 0xB000,
|
||||
KFHDR = 0xB00A,
|
||||
AMBIENT_NODE_TAG = 0xB001,
|
||||
@@ -308,13 +308,13 @@ enum ChunkIdentifier : u16 {
|
||||
LIGHT_NODE_TAG = 0xB005,
|
||||
L_TARGET_NODE_TAG = 0xB006,
|
||||
SPOTLIGHT_NODE_TAG = 0xB007,
|
||||
|
||||
|
||||
KFSEG = 0xB008,
|
||||
KFCURTIME = 0xB009,
|
||||
|
||||
|
||||
NODE_HDR = 0xB010,
|
||||
INSTANCE_NAME = 0xB011,
|
||||
PRESCALE = 0xB012,
|
||||
PRESCALE = 0xB012,
|
||||
PIVOT = 0xB013,
|
||||
BOUNDBOX = 0xB014,
|
||||
MORPH_SMOOTH = 0xB015,
|
||||
@@ -329,10 +329,10 @@ enum ChunkIdentifier : u16 {
|
||||
FALL_TRACK_TAG = 0xB028,
|
||||
HIDE_TRACK_TAG = 0xB029,
|
||||
NODE_ID = 0xB030,
|
||||
|
||||
|
||||
|
||||
|
||||
CMAGIC = 0xC23D,
|
||||
|
||||
|
||||
C_MDRAWER = 0xC010,
|
||||
C_TDRAWER = 0xC020,
|
||||
C_SHPDRAWER = 0xC030,
|
||||
@@ -395,7 +395,7 @@ enum ChunkIdentifier : u16 {
|
||||
C_BITMAP_DRAWER = 0xC25B,
|
||||
C_RGB_FILE = 0xC260,
|
||||
C_RGB_OVASPECT = 0xC270,
|
||||
|
||||
|
||||
C_RGB_ANIMTYPE = 0xC271,
|
||||
C_RENDER_ALL = 0xC272,
|
||||
C_REND_FROM = 0xC273,
|
||||
@@ -513,16 +513,16 @@ enum ChunkIdentifier : u16 {
|
||||
C_VTR_IN = 0xC775,
|
||||
C_VTR_PK = 0xC780,
|
||||
C_VTR_SH = 0xC785,
|
||||
|
||||
/* Material chunks */
|
||||
C_WORK_MTLS = 0xC790, /* Old-style -- now ignored */
|
||||
C_WORK_MTLS_2 = 0xC792, /* Old-style -- now ignored */
|
||||
C_WORK_MTLS_3 = 0xC793, /* Old-style -- now ignored */
|
||||
C_WORK_MTLS_4 = 0xC794, /* Old-style -- now ignored */
|
||||
C_WORK_MTLS_5 = 0xCB00, /* Old-style -- now ignored */
|
||||
C_WORK_MTLS_6 = 0xCB01, /* Old-style -- now ignored */
|
||||
C_WORK_MTLS_7 = 0xCB02, /* Old-style -- now ignored */
|
||||
C_WORK_MTLS_8 = 0xCB03, /* Old-style -- now ignored */
|
||||
|
||||
/* Material chunks */
|
||||
C_WORK_MTLS = 0xC790, /* Old-style -- now ignored */
|
||||
C_WORK_MTLS_2 = 0xC792, /* Old-style -- now ignored */
|
||||
C_WORK_MTLS_3 = 0xC793, /* Old-style -- now ignored */
|
||||
C_WORK_MTLS_4 = 0xC794, /* Old-style -- now ignored */
|
||||
C_WORK_MTLS_5 = 0xCB00, /* Old-style -- now ignored */
|
||||
C_WORK_MTLS_6 = 0xCB01, /* Old-style -- now ignored */
|
||||
C_WORK_MTLS_7 = 0xCB02, /* Old-style -- now ignored */
|
||||
C_WORK_MTLS_8 = 0xCB03, /* Old-style -- now ignored */
|
||||
C_WORKMTL = 0xCB04,
|
||||
C_SXP_TEXT_DATA = 0xCB10,
|
||||
C_SXP_TEXT2_DATA = 0xCB20,
|
||||
@@ -542,15 +542,15 @@ enum ChunkIdentifier : u16 {
|
||||
|
||||
C_BGTYPE = 0xC7A1,
|
||||
C_MEDTILE = 0xC7B0,
|
||||
|
||||
|
||||
/* Contrast */
|
||||
C_LO_CONTRAST = 0xC7D0,
|
||||
C_HI_CONTRAST = 0xC7D1,
|
||||
|
||||
/* 3d frozen display */
|
||||
|
||||
/* 3d frozen display */
|
||||
C_FROZ_DISPLAY = 0xC7E0,
|
||||
|
||||
/* Booleans */
|
||||
|
||||
/* Booleans */
|
||||
C_BOOLWELD = 0xc7f0,
|
||||
C_BOOLTYPE = 0xc7f1,
|
||||
|
||||
@@ -569,8 +569,8 @@ enum ChunkIdentifier : u16 {
|
||||
C_MAPDRAWER8 = 0xCA08,
|
||||
C_MAPDRAWER9 = 0xCA09,
|
||||
C_MAPDRAWER_ENTRY = 0xCA10,
|
||||
|
||||
/* System Options */
|
||||
|
||||
/* System Options */
|
||||
C_BACKUP_FILE = 0xCA20,
|
||||
C_DITHER_256 = 0xCA21,
|
||||
C_SAVE_LAST = 0xCA22,
|
||||
@@ -596,8 +596,8 @@ enum ChunkIdentifier : u16 {
|
||||
C_AUTO_SMOOTH = 0xCA80,
|
||||
C_DXF_SMOOTH_ANG = 0xCA90,
|
||||
C_SMOOTH_ANG = 0xCAA0,
|
||||
|
||||
/* Special network-use chunks */
|
||||
|
||||
/* Special network-use chunks */
|
||||
C_NET_USE_VPOST = 0xCC00,
|
||||
C_NET_USE_GAMMA = 0xCC10,
|
||||
C_NET_FIELD_ORDER = 0xCC20,
|
||||
@@ -628,8 +628,8 @@ enum ChunkIdentifier : u16 {
|
||||
C_VIEW_PRES_RATIO = 0xCE50,
|
||||
C_BGND_PRES_RATIO = 0xCE60,
|
||||
C_NTH_SERIAL_NUM = 0xCE70,
|
||||
|
||||
/* Video Post */
|
||||
|
||||
/* Video Post */
|
||||
VPDATA = 0xd000,
|
||||
|
||||
P_QUEUE_ENTRY = 0xd100,
|
||||
@@ -648,7 +648,7 @@ enum ChunkIdentifier : u16 {
|
||||
P_QUEUE_ALIGN = 0xd190,
|
||||
|
||||
P_CUSTOM_SIZE = 0xd1a0,
|
||||
|
||||
|
||||
P_ALPH_NONE = 0xd210,
|
||||
P_ALPH_PSEUDO = 0xd220, /* Old chunk */
|
||||
P_ALPH_OP_PSEUDO = 0xd221, /* Old chunk */
|
||||
@@ -732,7 +732,7 @@ bitfield Spline {
|
||||
Use_Bias : 1;
|
||||
Use_Ease_To : 1;
|
||||
Use_Ease_From : 1;
|
||||
|
||||
|
||||
padding : 3;
|
||||
|
||||
if (Use_Tension == 1)
|
||||
@@ -745,7 +745,7 @@ bitfield Spline {
|
||||
float Ease_To;
|
||||
if (Use_Ease_From == 1)
|
||||
float Ease_From;
|
||||
|
||||
|
||||
padding : 8;
|
||||
};
|
||||
|
||||
@@ -795,7 +795,7 @@ struct Keys<auto identifier> {
|
||||
) : {
|
||||
RotationKey data[count];
|
||||
}
|
||||
|
||||
|
||||
(
|
||||
ChunkIdentifier::FOV_TRACK_TAG |
|
||||
ChunkIdentifier::ROLL_TRACK_TAG |
|
||||
@@ -804,13 +804,13 @@ struct Keys<auto identifier> {
|
||||
) : {
|
||||
AngleKey data[count];
|
||||
}
|
||||
|
||||
|
||||
(
|
||||
ChunkIdentifier::MORPH_TRACK_TAG
|
||||
) : {
|
||||
MorphKey data[count];
|
||||
}
|
||||
|
||||
|
||||
(
|
||||
ChunkIdentifier::HIDE_TRACK_TAG
|
||||
) : {
|
||||
@@ -842,7 +842,7 @@ struct Chunk {
|
||||
u32 chunkSize;
|
||||
u32 dataLength = chunkSize - 6 [[export]];
|
||||
u32 chunkEnd = $ + dataLength;
|
||||
|
||||
|
||||
if (chunkSize > 0) {
|
||||
std::print("{}", identifier);
|
||||
match (identifier) {
|
||||
@@ -894,14 +894,14 @@ struct Chunk {
|
||||
): {
|
||||
Chunk chunks[while($ < chunkEnd)];
|
||||
}
|
||||
|
||||
|
||||
(
|
||||
ChunkIdentifier::M3D_VERSION |
|
||||
ChunkIdentifier::MESH_VERSION
|
||||
): {
|
||||
u32 version;
|
||||
}
|
||||
|
||||
|
||||
(
|
||||
ChunkIdentifier::LO_SHADOW_BIAS |
|
||||
ChunkIdentifier::HI_SHADOW_BIAS |
|
||||
@@ -921,41 +921,41 @@ struct Chunk {
|
||||
): {
|
||||
float value;
|
||||
}
|
||||
|
||||
|
||||
(
|
||||
ChunkIdentifier::V_GRADIENT
|
||||
) : {
|
||||
float position;
|
||||
Chunk chunks[while($ < chunkEnd)];
|
||||
}
|
||||
|
||||
|
||||
(
|
||||
ChunkIdentifier::NAMED_OBJECT
|
||||
) : {
|
||||
char name[];
|
||||
Chunk chunks[while($ < chunkEnd)];
|
||||
}
|
||||
|
||||
|
||||
(
|
||||
ChunkIdentifier::POINT_ARRAY
|
||||
) : {
|
||||
u16 count;
|
||||
Vector3f vectices[count] [[hex::visualize("3d", this, null)]];
|
||||
}
|
||||
|
||||
|
||||
(
|
||||
ChunkIdentifier::TEX_VERTS
|
||||
) : {
|
||||
u16 count;
|
||||
Vector2f coords[count];
|
||||
}
|
||||
|
||||
|
||||
(
|
||||
ChunkIdentifier::MESH_MATRIX
|
||||
) : {
|
||||
Vector3f x, y, z, w;
|
||||
}
|
||||
|
||||
|
||||
(
|
||||
ChunkIdentifier::FACE_ARRAY
|
||||
) : {
|
||||
@@ -963,26 +963,26 @@ struct Chunk {
|
||||
Face faces[count];
|
||||
Chunk chunks[while($ < chunkEnd)];
|
||||
}
|
||||
|
||||
|
||||
(
|
||||
ChunkIdentifier::POINT_FLAG_ARRAY
|
||||
) : {
|
||||
u16 count;
|
||||
VertexFlags flags[count];
|
||||
}
|
||||
|
||||
|
||||
(
|
||||
ChunkIdentifier::SMOOTH_GROUP
|
||||
) : {
|
||||
u32 groups[dataLength / sizeof(u32)];
|
||||
}
|
||||
|
||||
|
||||
(
|
||||
ChunkIdentifier::MESH_COLOR
|
||||
) : {
|
||||
u8 value;
|
||||
}
|
||||
|
||||
|
||||
(
|
||||
ChunkIdentifier::MSH_MAT_GROUP
|
||||
) : {
|
||||
@@ -990,7 +990,7 @@ struct Chunk {
|
||||
u16 count;
|
||||
u16 groups[count];
|
||||
}
|
||||
|
||||
|
||||
(
|
||||
ChunkIdentifier::KFHDR
|
||||
) : {
|
||||
@@ -998,25 +998,25 @@ struct Chunk {
|
||||
char name[];
|
||||
u32 animationLength;
|
||||
}
|
||||
|
||||
|
||||
(
|
||||
ChunkIdentifier::KFSEG
|
||||
) : {
|
||||
u32 start, end;
|
||||
}
|
||||
|
||||
|
||||
(
|
||||
ChunkIdentifier::KFCURTIME
|
||||
) : {
|
||||
u32 frameIndex;
|
||||
}
|
||||
|
||||
|
||||
(
|
||||
ChunkIdentifier::NODE_ID
|
||||
) : {
|
||||
type::Hex<u16> id;
|
||||
}
|
||||
|
||||
|
||||
(
|
||||
ChunkIdentifier::NODE_HDR
|
||||
) : {
|
||||
@@ -1026,47 +1026,47 @@ struct Chunk {
|
||||
KeyFlags2 flags2;
|
||||
type::Hex<u16> parentId;
|
||||
}
|
||||
|
||||
|
||||
(
|
||||
ChunkIdentifier::PIVOT
|
||||
) : {
|
||||
Vector3f value;
|
||||
}
|
||||
|
||||
|
||||
(
|
||||
ChunkIdentifier::BOUNDBOX
|
||||
) : {
|
||||
Vector3f min, max;
|
||||
}
|
||||
|
||||
|
||||
(
|
||||
ChunkIdentifier::COLOR_24 |
|
||||
ChunkIdentifier::LIN_COLOR_24
|
||||
) : {
|
||||
RGB<u8> color;
|
||||
}
|
||||
|
||||
|
||||
(
|
||||
ChunkIdentifier::COLOR_F |
|
||||
ChunkIdentifier::LIN_COLOR_F
|
||||
) : {
|
||||
RGB<float> color;
|
||||
}
|
||||
|
||||
|
||||
(
|
||||
ChunkIdentifier::INT_PERCENTAGE |
|
||||
ChunkIdentifier::MAT_BUMP_PERCENT
|
||||
) : {
|
||||
u16 value;
|
||||
}
|
||||
|
||||
|
||||
(
|
||||
ChunkIdentifier::SHADOW_MAP_SIZE |
|
||||
ChunkIdentifier::MAT_SHADING
|
||||
) : {
|
||||
u16 value;
|
||||
}
|
||||
|
||||
|
||||
(
|
||||
ChunkIdentifier::POS_TRACK_TAG |
|
||||
ChunkIdentifier::ROT_TRACK_TAG |
|
||||
@@ -1077,13 +1077,13 @@ struct Chunk {
|
||||
ChunkIdentifier::MORPH_TRACK_TAG |
|
||||
ChunkIdentifier::HOT_TRACK_TAG |
|
||||
ChunkIdentifier::FALL_TRACK_TAG |
|
||||
ChunkIdentifier::HIDE_TRACK_TAG
|
||||
ChunkIdentifier::HIDE_TRACK_TAG
|
||||
) : {
|
||||
TrackFlags flags;
|
||||
u8 unknown[8];
|
||||
Keys<identifier> keys;
|
||||
}
|
||||
|
||||
|
||||
(
|
||||
ChunkIdentifier::INSTANCE_NAME |
|
||||
ChunkIdentifier::BIT_MAP |
|
||||
@@ -1093,26 +1093,26 @@ struct Chunk {
|
||||
) : {
|
||||
char name[];
|
||||
}
|
||||
|
||||
|
||||
(
|
||||
ChunkIdentifier::MAT_MAP_TILING
|
||||
) : {
|
||||
u16 tiling;
|
||||
}
|
||||
|
||||
|
||||
(
|
||||
ChunkIdentifier::WORLD_VIEWPORT_SIZE
|
||||
) : {
|
||||
u16 x, y, w, h;
|
||||
}
|
||||
|
||||
|
||||
(
|
||||
ChunkIdentifier::N_DIRECT_LIGHT
|
||||
) : {
|
||||
Vector3f position;
|
||||
Chunk chunks[while($ < chunkEnd)];
|
||||
}
|
||||
|
||||
|
||||
(
|
||||
ChunkIdentifier::DL_SPOTLIGHT
|
||||
) : {
|
||||
@@ -1120,16 +1120,16 @@ struct Chunk {
|
||||
float hotspot, falloff;
|
||||
Chunk chunks[while($ < chunkEnd)];
|
||||
}
|
||||
|
||||
|
||||
(
|
||||
ChunkIdentifier::N_CAMERA
|
||||
) : {
|
||||
Vector3f position, target;
|
||||
float roll, fov;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
(_) : {
|
||||
std::warning(std::format("Unhandled Chunk ID: {}, Skipping 0x{:04X} bytes", identifier, dataLength));
|
||||
$ += dataLength;
|
||||
|
||||
@@ -1,102 +1,93 @@
|
||||
#pragma description 7z File Format
|
||||
#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 std.io;
|
||||
import std.mem;
|
||||
import std.math;
|
||||
import type.magic;
|
||||
|
||||
|
||||
enum Type:u8{
|
||||
startPosition = 0x00, // Start position
|
||||
sizeStartHeader = 0x20, // Size of start Header
|
||||
};
|
||||
enum Type:u8{
|
||||
startPosition = 0x00, // Start position
|
||||
sizeStartHeader = 0x20, // Size of start Header
|
||||
};
|
||||
|
||||
enum TypeB:u48{
|
||||
sevenZipSignature = 0x1C27AFBC7A37, // Defining 7z signature
|
||||
};
|
||||
struct StartHeader {
|
||||
// File signature
|
||||
type::Magic<"7z\xBC\xAF\x27\x1C"> signature [[color("FF0000")] ];
|
||||
// Version format
|
||||
u16 formatVersion [[color("00FF00")]];
|
||||
// CRC start header
|
||||
u32 crcOfTheFollowing20Bytes [[color("0000FF")]];
|
||||
// Relative offset of End Header
|
||||
u64 relativeOffsetEndHeader [[color("FFFF00")]];
|
||||
// Length of End Header
|
||||
u64 theLengthOfEndHeader [[color("00FFFF")]];
|
||||
// CRC of End Ender
|
||||
u32 crcOftheEndHeader [[color("FF00FF")]];
|
||||
// File size calculation
|
||||
u64 fileSize = relativeOffsetEndHeader + theLengthOfEndHeader + Type::sizeStartHeader;
|
||||
// Absolute offset calculation End Header
|
||||
u64 startEndHeader = relativeOffsetEndHeader + Type::sizeStartHeader;
|
||||
};
|
||||
|
||||
struct StartHeader {
|
||||
// File signature
|
||||
u48 signature [[color("FF0000")] ];
|
||||
// Version format
|
||||
u16 formatVersion [[color("00FF00")]];
|
||||
// CRC start header
|
||||
u32 crcOfTheFollowing20Bytes [[color("0000FF")]];
|
||||
// Relative offset of End Header
|
||||
u64 relativeOffsetEndHeader [[color("FFFF00")]];
|
||||
// Length of End Header
|
||||
u64 theLengthOfEndHeader [[color("00FFFF")]];
|
||||
// CRC of End Ender
|
||||
u32 crcOftheEndHeader [[color("FF00FF")]];
|
||||
// File size calculation
|
||||
u64 fileSize = relativeOffsetEndHeader + theLengthOfEndHeader + Type::sizeStartHeader;
|
||||
// Absolute offset calculation End Header
|
||||
u64 startEndHeader = relativeOffsetEndHeader + Type::sizeStartHeader;
|
||||
};
|
||||
StartHeader startheader @ Type::startPosition;
|
||||
|
||||
StartHeader startheader @ Type::startPosition;
|
||||
|
||||
struct CompressedData {
|
||||
// Start of compressed data
|
||||
u8 startOfCompressedData[4] [[color("C0C0C0")]];
|
||||
};
|
||||
struct CompressedData {
|
||||
// Start of compressed data
|
||||
u8 startOfCompressedData[4] [[color("C0C0C0")]];
|
||||
};
|
||||
|
||||
CompressedData compresseddata @ Type::sizeStartHeader;
|
||||
CompressedData compresseddata @ Type::sizeStartHeader;
|
||||
|
||||
|
||||
struct EndHeader {
|
||||
// Set padding to place End Header in right position
|
||||
padding[startheader.relativeOffsetEndHeader];
|
||||
// Mark link to meta block
|
||||
u8 linkToMetaBlock [[color("FF0000")]];
|
||||
// Mark all End Header
|
||||
char fullEndHeader[startheader.theLengthOfEndHeader] [[color("63954A")]];
|
||||
// Detect LZMA signature
|
||||
u64 lzmaSignaturePosition = std::mem::find_sequence_in_range(0, addressof(fullEndHeader), addressof(fullEndHeader) + sizeof(fullEndHeader), 0x23, 0x03, 0x01, 0x01, 0x05, 0x5D);
|
||||
|
||||
// Mark positions if LZMA signature was detected
|
||||
if(lzmaSignaturePosition != 0xFFFFFFFFFFFFFFFF){
|
||||
u48 lzmaSignature @ lzmaSignaturePosition [[color("0000FF")]];
|
||||
}
|
||||
};
|
||||
|
||||
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");
|
||||
}
|
||||
struct EndHeader {
|
||||
// Set padding to place End Header in right position
|
||||
padding[startheader.relativeOffsetEndHeader];
|
||||
// Mark link to meta block
|
||||
u8 linkToMetaBlock [[color("FF0000")]];
|
||||
// Mark all End Header
|
||||
char fullEndHeader[startheader.theLengthOfEndHeader] [[color("63954A")]];
|
||||
// Detect LZMA signature
|
||||
u64 lzmaSignaturePosition = std::mem::find_sequence_in_range(0, addressof(fullEndHeader), addressof(fullEndHeader) + sizeof(fullEndHeader), 0x23, 0x03, 0x01, 0x01, 0x05, 0x5D);
|
||||
|
||||
std::print("Format Version {} ",startheader.formatVersion);
|
||||
// Mark positions if LZMA signature was detected
|
||||
if(lzmaSignaturePosition != 0xFFFFFFFFFFFFFFFF){
|
||||
u48 lzmaSignature @ lzmaSignaturePosition [[color("0000FF")]];
|
||||
}
|
||||
};
|
||||
|
||||
// Version verification
|
||||
if(startheader.formatVersion == 0x0400){
|
||||
std::print("Major Version 0x00 || 0 - Minor Version 0x04 || 4");
|
||||
}
|
||||
EndHeader endheader @ Type::sizeStartHeader;
|
||||
|
||||
// Verification of the compressed method is LZMA, Bzip2 or LZMA2
|
||||
if(compresseddata.startOfCompressedData[0] == Type::startPosition){
|
||||
std::print("Compressed Method LZMA");
|
||||
}else if(compresseddata.startOfCompressedData[0] == 0x42){
|
||||
std::print("Compressed Method Bzip2");
|
||||
}else{
|
||||
std::print("Compressed Method LZMA2");
|
||||
}
|
||||
std::print("Format Version {} ",startheader.formatVersion);
|
||||
|
||||
|
||||
// Version verification
|
||||
if(startheader.formatVersion == 0x0400){
|
||||
std::print("Major Version 0x00 || 0 - Minor Version 0x04 || 4");
|
||||
}
|
||||
|
||||
std::print("CRC Start Header 0x{:X}",startheader.crcOfTheFollowing20Bytes);
|
||||
// Verification of the compressed method is LZMA, Bzip2 or LZMA2
|
||||
if(compresseddata.startOfCompressedData[0] == Type::startPosition){
|
||||
std::print("Compressed Method LZMA");
|
||||
}else if(compresseddata.startOfCompressedData[0] == 0x42){
|
||||
std::print("Compressed Method Bzip2");
|
||||
}else{
|
||||
std::print("Compressed Method LZMA2");
|
||||
}
|
||||
|
||||
std::print("CRC End Header 0x{:X} ", startheader.crcOftheEndHeader);
|
||||
|
||||
std::print("CompressedData length 0x{:X} || {} bytes ",startheader.relativeOffsetEndHeader, startheader.relativeOffsetEndHeader);
|
||||
|
||||
std::print("Relative Offset of End Header 0x{:X} || {} bytes",startheader.relativeOffsetEndHeader, startheader.relativeOffsetEndHeader);
|
||||
std::print("CRC Start Header 0x{:X}",startheader.crcOfTheFollowing20Bytes);
|
||||
|
||||
std::print("Offset to start End Header 0x{:X} || {} bytes",startheader.startEndHeader,startheader.startEndHeader);
|
||||
std::print("CRC End Header 0x{:X} ", startheader.crcOftheEndHeader);
|
||||
|
||||
std::print("End Header length 0x{:X} || {} bytes",startheader.theLengthOfEndHeader,startheader.theLengthOfEndHeader);
|
||||
std::print("CompressedData length 0x{:X} || {} bytes ",startheader.relativeOffsetEndHeader, startheader.relativeOffsetEndHeader);
|
||||
|
||||
std::print("File size 0x{:X} || {} bytes",startheader.fileSize, startheader.fileSize);
|
||||
std::print("Relative Offset of End Header 0x{:X} || {} bytes",startheader.relativeOffsetEndHeader, startheader.relativeOffsetEndHeader);
|
||||
|
||||
std::print("Offset to start End Header 0x{:X} || {} bytes",startheader.startEndHeader,startheader.startEndHeader);
|
||||
|
||||
std::print("End Header length 0x{:X} || {} bytes",startheader.theLengthOfEndHeader,startheader.theLengthOfEndHeader);
|
||||
|
||||
std::print("File size 0x{:X} || {} bytes",startheader.fileSize, startheader.fileSize);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#pragma author AdventureT
|
||||
#pragma description Crash Bandicoot - Back in Time (fan game) User created level format
|
||||
#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
|
||||
@@ -353,7 +354,7 @@ struct Object {
|
||||
u16 numOfMetafields;
|
||||
u8 metafields[numOfMetafields];
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
u32 x;
|
||||
u32 y;
|
||||
|
||||
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,14 +1,13 @@
|
||||
#pragma authors: zhoubo
|
||||
#pragma version: 0.4
|
||||
#pragma description: Parse AAC's ADTS(Audio Data Transport Stream) audio files.
|
||||
#pragma category: Audio
|
||||
#pragma filemask: *.aac
|
||||
#pragma IDBytes: FF F //ADTS Syncword
|
||||
#pragma history:
|
||||
#pragma 0.4 2024-02-12 zhoubo: Porting from 010 Editor Templates.
|
||||
#pragma 0.3 2024-02-09 zhoubo: use BitfieldDisablePadding(Unpadded Bitfields) for odd header bytes(7,9 bytes) color, and remove FSeek.
|
||||
#pragma 0.2 2024-02-05 zhoubo: fix some comment & color.
|
||||
#pragma 0.1 2022-06-13 zhoubo: Init release. only ADTS, not support ADIF,LATM.
|
||||
#pragma author zhoubo
|
||||
#pragma description AAC ADTSn (Audio Data Transport Stream) Audio
|
||||
#pragma MIME audio/x-hx-aac-adts
|
||||
#pragma pattern_limit 0xFFFFFF
|
||||
|
||||
// History
|
||||
// 0.4 2024-02-12 zhoubo: Porting from 010 Editor Templates.
|
||||
// 0.3 2024-02-09 zhoubo: use BitfieldDisablePadding(Unpadded Bitfields) for odd header bytes(7,9 bytes) color, and remove FSeek.
|
||||
// 0.2 2024-02-05 zhoubo: fix some comment & color.
|
||||
// 0.1 2022-06-13 zhoubo: Init release. only ADTS, not support ADIF,LATM.
|
||||
|
||||
// More information available at:
|
||||
// 1. https://wiki.multimedia.cx/index.php?title=ADTS
|
||||
|
||||
@@ -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;
|
||||
@@ -52,8 +56,8 @@ std::assert(ctx.magic == ATMOSPHERE_REBOOT_TO_FATAL_MAGIC ||
|
||||
ctx.magic == ATMOSPHERE_REBOOT_TO_FATAL_MAGIC_1 ||
|
||||
ctx.magic == ATMOSPHERE_REBOOT_TO_FATAL_MAGIC_0,
|
||||
"File is not a valid Atmosphere fatal error binary!");
|
||||
|
||||
std::assert_warn(ctx.magic == ATMOSPHERE_REBOOT_TO_FATAL_MAGIC,
|
||||
|
||||
std::assert_warn(ctx.magic == ATMOSPHERE_REBOOT_TO_FATAL_MAGIC,
|
||||
"Atmosphere fatal error binary is for an older version!");
|
||||
|
||||
|
||||
|
||||
@@ -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;
|
||||
@@ -1,5 +1,5 @@
|
||||
#pragma author WerWolv
|
||||
#pragma description Static library archive files
|
||||
#pragma description GNU Static library archive
|
||||
|
||||
#pragma MIME application/x-archive
|
||||
|
||||
@@ -15,7 +15,7 @@ struct ARFile {
|
||||
char file_mode[8];
|
||||
char file_size[10];
|
||||
u16 end_marker;
|
||||
|
||||
|
||||
if (end_marker == 0x0A60) {
|
||||
u8 data[std::string::parse_int(this.file_size, 10)];
|
||||
padding[sizeof(data) & 1];
|
||||
@@ -23,6 +23,9 @@ struct ARFile {
|
||||
};
|
||||
|
||||
char signature[8] @ 0x00;
|
||||
if (signature == "!<arch>\r") {
|
||||
std::error("Archive file got corrupted due to CRLF line ending conversion!");
|
||||
}
|
||||
std::assert(signature == "!<arch>\n", "File is not a valid archive!");
|
||||
|
||||
ARFile files[while($ < std::mem::size())] @ $;
|
||||
|
||||
26
patterns/arc.hexpat
Normal file
26
patterns/arc.hexpat
Normal file
@@ -0,0 +1,26 @@
|
||||
#pragma author DexrnZacAttack
|
||||
#pragma description Minecraft LCE ARC File
|
||||
#pragma endian big
|
||||
|
||||
import std.string;
|
||||
#ifdef __IMHEX__
|
||||
import hex.core;
|
||||
#endif
|
||||
|
||||
struct Table {
|
||||
u16 nameSize;
|
||||
char fileName[nameSize];
|
||||
u32 offset;
|
||||
u32 size;
|
||||
u8 file[size] @ offset;
|
||||
#ifdef __IMHEX__
|
||||
hex::core::add_virtual_file(fileName, file);
|
||||
#endif
|
||||
} [[name(std::string::to_string(fileName))]];
|
||||
|
||||
struct ARC {
|
||||
u32 count;
|
||||
Table table[count];
|
||||
};
|
||||
|
||||
ARC arc @ 0x00;
|
||||
@@ -40,21 +40,21 @@ VectorTable vector_table @ VTOR;
|
||||
|
||||
fn main() {
|
||||
u32 table_size = sizeof(vector_table);
|
||||
|
||||
|
||||
u32 default_handler_address = 0x00;
|
||||
|
||||
|
||||
for (u32 i = 4, i < table_size, i = i + 4) {
|
||||
u32 occurrences = 0;
|
||||
for (u32 j = 4, j < table_size, j = j + 4) {
|
||||
if (std::mem::read_unsigned(i, 4) == std::mem::read_unsigned(j, 4)) {
|
||||
occurrences = occurrences + 1;
|
||||
|
||||
|
||||
if (occurrences > 1)
|
||||
default_handler_address = std::mem::read_unsigned(i, 4);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (default_handler_address != 0x00)
|
||||
std::print("Default Handler implementation at 0x{:08X}", default_handler_address);
|
||||
};
|
||||
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;
|
||||
@@ -1,5 +1,5 @@
|
||||
#pragma author WerWolv
|
||||
#pragma description Bencode encoding, used by Torrent files
|
||||
#pragma description Torrent data (Bencode)
|
||||
|
||||
#pragma MIME application/x-bittorrent
|
||||
|
||||
@@ -8,20 +8,20 @@ import std.mem;
|
||||
import std.string;
|
||||
|
||||
namespace bencode {
|
||||
|
||||
|
||||
struct ASCIIDecimal {
|
||||
char value[while(std::ctype::isdigit(std::mem::read_unsigned($, 1)))];
|
||||
} [[sealed, format("bencode::format_ascii_decimal"), transform("bencode::format_ascii_decimal")]];
|
||||
|
||||
|
||||
fn format_ascii_decimal(ASCIIDecimal adsasd) {
|
||||
return std::string::parse_int(adsasd.value, 10);
|
||||
};
|
||||
|
||||
|
||||
enum Type : u8 {
|
||||
Integer = 'i',
|
||||
Dictionary = 'd',
|
||||
List = 'l',
|
||||
|
||||
|
||||
String0 = '0',
|
||||
String1 = '1',
|
||||
String2 = '2',
|
||||
@@ -33,30 +33,39 @@ namespace bencode {
|
||||
String8 = '8',
|
||||
String9 = '9'
|
||||
};
|
||||
|
||||
|
||||
struct String {
|
||||
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;
|
||||
using Value;
|
||||
|
||||
|
||||
struct DictionaryEntry {
|
||||
String key;
|
||||
Value value;
|
||||
};
|
||||
|
||||
|
||||
struct Value {
|
||||
Type type;
|
||||
|
||||
|
||||
if (type == Type::Dictionary) {
|
||||
DictionaryEntry entry[while(std::mem::read_unsigned($, 1) != 'e')];
|
||||
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;
|
||||
@@ -65,12 +74,12 @@ namespace bencode {
|
||||
String value;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct Bencode {
|
||||
Value value[while(!std::mem::eof())] [[inline]];
|
||||
Value value[while(!std::mem::eof())] [[inline]];
|
||||
char end;
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
bencode::Bencode bencode @ 0x00;
|
||||
|
||||
@@ -1,80 +1,101 @@
|
||||
#pragma author Shadlock0133 (aka Aurora)
|
||||
#pragma description Binary G-Code from Prusa
|
||||
#pragma author Shadlock0133 (aka Aurora) / WerWolv
|
||||
#pragma description Prusa Binary G-Code
|
||||
#pragma magic [ 47 43 44 45 ] @ 0x00
|
||||
|
||||
#include <type/magic.pat>
|
||||
#include <std/mem.pat>
|
||||
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 {
|
||||
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
|
||||
};
|
||||
|
||||
struct GCode {
|
||||
GCodeEncoding encoding;
|
||||
|
||||
std::mem::Bytes<parent.header.dataSize> gcode;
|
||||
};
|
||||
|
||||
struct Block {
|
||||
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;
|
||||
};
|
||||
|
||||
struct BGCode {
|
||||
type::Magic<"GCDE"> magic;
|
||||
u32 version;
|
||||
ChecksumType checksum_type;
|
||||
};
|
||||
|
||||
Header header @ 0;
|
||||
std::assert(header.version == 1, "only version 1 supported");
|
||||
std::assert(version == 1, "Only Version 1 is supported");
|
||||
|
||||
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; }
|
||||
}
|
||||
ChecksumType checksumType;
|
||||
|
||||
Block blocks[while(!std::mem::eof())];
|
||||
};
|
||||
|
||||
Block blocks[while(!std::mem::eof())] @ $;
|
||||
BGCode bgcode @ 0x00;
|
||||
24
patterns/binka.hexpat
Normal file
24
patterns/binka.hexpat
Normal file
@@ -0,0 +1,24 @@
|
||||
#pragma author DexrnZacAttack
|
||||
#pragma description RAD Game Tools BINKA (Bink Audio)
|
||||
#pragma magic [31 46 43 42] @ 0x00
|
||||
|
||||
import std.string;
|
||||
import std.math;
|
||||
import type.magic;
|
||||
|
||||
fn getDuration(u32 duration_ts, u32 sample_rate) {
|
||||
return float(duration_ts) / float(sample_rate);
|
||||
};
|
||||
|
||||
struct Binka {
|
||||
type::Magic<"1FCB"> magic;
|
||||
u8; // can't get this to change anything when using ffprobe
|
||||
u8 channel_count [[name(std::format("Channel Count: {}", this))]];
|
||||
u16 sample_rate [[name(std::format("Sample Rate: {}", this))]];
|
||||
u32 duration_ts [[name(std::format("Duration: {}s", std::math::floor(getDuration(this, sample_rate))))]];
|
||||
u32;
|
||||
u32 size [[name(std::format("File Size: {} bytes", this))]];
|
||||
u8 data[size - 20];
|
||||
};
|
||||
|
||||
Binka binka @ 0x00;
|
||||
196
patterns/blend.hexpat
Normal file
196
patterns/blend.hexpat
Normal file
@@ -0,0 +1,196 @@
|
||||
#pragma description Blender file
|
||||
#pragma magic [42 4C 45 4E 44 45 52] @ 0x00
|
||||
|
||||
/*
|
||||
* References:
|
||||
* https://projects.blender.org/blender/blender
|
||||
* https://github.com/facebook/zstd/blob/master/contrib/seekable_format/zstd_seekable_compression_format.md
|
||||
*
|
||||
* Refer to the following files/structs:
|
||||
* source/blender/blenloader/intern/writefile.cc
|
||||
* source/blender/blenkernel/BKE_main.hh BlendThumbnail
|
||||
* source/blender/makesdna/DNA_sdna_types.h BHead
|
||||
*/
|
||||
|
||||
// Increased the pattern limit to be able to evaluate all pixels of the embedded thumbnail.
|
||||
#pragma pattern_limit 1000000
|
||||
|
||||
#ifdef __IMHEX__
|
||||
import hex.dec;
|
||||
#endif
|
||||
|
||||
import std.core;
|
||||
import std.io;
|
||||
import std.mem;
|
||||
import std.string;
|
||||
import std.sys;
|
||||
import type.color;
|
||||
import type.magic;
|
||||
|
||||
// Useful for extracting the thumbnail if the rest of the blend file is corrupted or truncated.
|
||||
bool quitAfterThumbnailIsParsed in;
|
||||
// Allow the pattern evaluator to skip the thumbnail e.g. if evaluation takes too long.
|
||||
bool skipThumbnail in;
|
||||
|
||||
struct BHead<Ptr> {
|
||||
char code[4];
|
||||
s32 len;
|
||||
Ptr old;
|
||||
s32 SDNAnr;
|
||||
s32 nr;
|
||||
|
||||
// ENDB marks the last data block in the file.
|
||||
if (code == "ENDB") {
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
struct ThumbnailLine<auto width> {
|
||||
type::RGBA8 pixels[width];
|
||||
};
|
||||
|
||||
fn copyThumbnail(u32 height, ref auto lines, std::mem::Section target) {
|
||||
for (s64 l = (height - 1), l >= 0, l = l - 1) {
|
||||
u64 currentSectionSize = std::mem::get_section_size(target);
|
||||
// Append the current line to section.
|
||||
std::mem::copy_value_to_section(lines[l], target, currentSectionSize);
|
||||
}
|
||||
};
|
||||
|
||||
struct Thumbnail {
|
||||
u32 width;
|
||||
u32 height;
|
||||
u128 size = width * height;
|
||||
ThumbnailLine<width> lines[height];
|
||||
|
||||
// Generate the thumbnail section.
|
||||
std::mem::Section thumbnailFlipped = std::mem::create_section("thumbnail");
|
||||
copyThumbnail(height, lines, thumbnailFlipped);
|
||||
type::RGBA8 image[size] @ 0x00 in thumbnailFlipped;
|
||||
}
|
||||
#ifdef __IMHEX__
|
||||
[[hex::visualize("bitmap", image, width, height)]]
|
||||
#endif
|
||||
;
|
||||
|
||||
struct DataBlock<Ptr> {
|
||||
BHead<Ptr> bHead;
|
||||
|
||||
if (bHead.SDNAnr == 0 && bHead.code == "TEST") {
|
||||
if (skipThumbnail) {
|
||||
u8 thumbnail[bHead.len]; // Interpret as raw binary data.
|
||||
} else {
|
||||
Thumbnail thumbnail;
|
||||
auto thumbnailSize = sizeof(thumbnail);
|
||||
std::assert(thumbnailSize == bHead.len,
|
||||
std::format("The thumbnail (size={:#x}) does not fit exactly into its DataBlock (len={:#x})!",
|
||||
thumbnailSize, bHead.len));
|
||||
}
|
||||
|
||||
if (quitAfterThumbnailIsParsed) {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
u8 data[bHead.len]; // Unknown. Interpret as raw binary data.
|
||||
}
|
||||
};
|
||||
|
||||
enum PointerSize : char {
|
||||
POINTER_4BYTE = '_',
|
||||
POINTER_8BYTE = '-'
|
||||
};
|
||||
|
||||
enum Endianness : char {
|
||||
BIG_ENDIAN = 'V',
|
||||
LITTLE_ENDIAN = 'v'
|
||||
};
|
||||
|
||||
struct Blend<auto inputSize> {
|
||||
type::Magic<"BLENDER"> magic;
|
||||
PointerSize pointerSize;
|
||||
Endianness endianness;
|
||||
char version[3];
|
||||
|
||||
match (endianness) {
|
||||
(Endianness::LITTLE_ENDIAN): std::core::set_endian(std::mem::Endian::Little);
|
||||
(Endianness::BIG_ENDIAN): std::core::set_endian(std::mem::Endian::Big);
|
||||
(_): std::error("Invalid value for endianness!");
|
||||
}
|
||||
|
||||
match (pointerSize) {
|
||||
(PointerSize::POINTER_4BYTE): DataBlock<u32> dataBlock[while($ < inputSize)];
|
||||
(PointerSize::POINTER_8BYTE): DataBlock<u64> dataBlock[while($ < inputSize)];
|
||||
(_): std::error("Invalid pointer size!");
|
||||
}
|
||||
};
|
||||
|
||||
struct BlendWrapper {
|
||||
u128 currentPos = $;
|
||||
char magic[4] @ currentPos [[hidden]];
|
||||
|
||||
if (magic != "\x28\xB5\x2F\xFD") { // ZSTD magic
|
||||
// Assume the blend file is uncompressed.
|
||||
Blend<sizeof($)> blend @ currentPos;
|
||||
return;
|
||||
}
|
||||
} [[inline]];
|
||||
|
||||
BlendWrapper blendWrapper @ 0x00;
|
||||
|
||||
// Assume the blend file is ZSTD compressed.
|
||||
|
||||
struct SeekTableFooter {
|
||||
u32 numFrames;
|
||||
char flag;
|
||||
type::Magic<"\xB1\xEA\x92\x8F"> footerMagic;
|
||||
};
|
||||
|
||||
u128 seekTableFooterSize = 9;
|
||||
SeekTableFooter seekTableFooter @ (sizeof($) - seekTableFooterSize);
|
||||
|
||||
struct SeekTableEntry {
|
||||
u32 compressedSize;
|
||||
u32 uncompressedSize;
|
||||
};
|
||||
|
||||
u128 seekTableEntrySize = 8;
|
||||
SeekTableEntry seekTableEntries[seekTableFooter.numFrames]
|
||||
@ (addressof(seekTableFooter) - seekTableFooter.numFrames * seekTableEntrySize);
|
||||
|
||||
struct SeekTableHeader {
|
||||
type::Magic<"\x5E\x2A\x4D\x18"> magic;
|
||||
u32 frameSize;
|
||||
};
|
||||
|
||||
u128 seekTableHeaderSize = 8;
|
||||
std::assert(seekTableFooter.numFrames > 0, "The seek table must contain entries!");
|
||||
SeekTableHeader seekTableHeader @ (addressof(seekTableEntries[0]) - seekTableHeaderSize);
|
||||
|
||||
u32 frameIndex = 0;
|
||||
|
||||
struct ZSTDFrame {
|
||||
u8 data[seekTableEntries[frameIndex].compressedSize];
|
||||
frameIndex = frameIndex + 1;
|
||||
};
|
||||
|
||||
ZSTDFrame zstdFrames[seekTableFooter.numFrames] @ 0x00;
|
||||
|
||||
#ifdef __IMHEX__
|
||||
std::mem::Section decompressedSection = std::mem::create_section("decompressedBlend");
|
||||
u128 previousSectionSize = 0;
|
||||
|
||||
for (u32 i = 0, i < seekTableFooter.numFrames, i = i + 1) {
|
||||
std::assert(hex::dec::zstd_decompress(zstdFrames[i].data, decompressedSection),
|
||||
"Decompression failed!");
|
||||
u32 uncompressedSize = seekTableEntries[i].uncompressedSize;
|
||||
u128 currentSectionSize = std::mem::get_section_size(decompressedSection)
|
||||
- previousSectionSize;
|
||||
std::assert_warn(uncompressedSize == currentSectionSize,
|
||||
std::format("The uncompressedSize {} for ZSTDFrame #{} "
|
||||
+ "must be equal to its actual decompressed size{}!",
|
||||
uncompressedSize, i, currentSectionSize));
|
||||
previousSectionSize += currentSectionSize;
|
||||
};
|
||||
|
||||
Blend<previousSectionSize> blend @ 0x00 in decompressedSection;
|
||||
#endif
|
||||
@@ -1,4 +1,4 @@
|
||||
#pragma description OS2/Windows Bitmap files
|
||||
#pragma description OS2/Windows Bitmap
|
||||
|
||||
#pragma MIME image/bmp
|
||||
#pragma endian little
|
||||
@@ -97,7 +97,7 @@ struct Bitmap {
|
||||
(_): BitmapInfoHeaderV1 bmih;
|
||||
}
|
||||
padding[bmih.biSize - sizeof(bmih)];
|
||||
|
||||
|
||||
if (bmih.biBitCount <= 8)
|
||||
{
|
||||
if (bmih.biClrUsed > 0 )
|
||||
@@ -105,7 +105,7 @@ struct Bitmap {
|
||||
else
|
||||
Colors rgbq[1 << bmih.biBitCount];
|
||||
}
|
||||
|
||||
|
||||
if (bmih.biSizeImage > 0 )
|
||||
u8 lineData[bmih.biSizeImage];
|
||||
else
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#pragma description TODO
|
||||
#pragma description Apple binary property list
|
||||
#pragma MIME application/x-bplist
|
||||
|
||||
import std.math;
|
||||
import std.core;
|
||||
@@ -29,14 +30,14 @@ enum Marker : u8 {
|
||||
UNK_0xF0 = 0xF0
|
||||
};
|
||||
|
||||
fn get_marker_name(u8 marker) {
|
||||
fn get_marker_name(u8 marker) {
|
||||
if (marker == Marker::Null){// null 0000 0000
|
||||
return "Null ";
|
||||
}else if (marker == Marker::False){ //bool 0000 1000 // false
|
||||
return "False";
|
||||
}else if (marker == Marker::True){//bool 0000 1001 // true
|
||||
return "True";
|
||||
}else if (marker == Marker::Fill){ //fill 0000 1111 // fill byte
|
||||
}else if (marker == Marker::Fill){ //fill 0000 1111 // fill byte
|
||||
return "Fill";
|
||||
}else if (marker & 0xF0 == Marker::Int){ //int 0001 nnnn ... // # of bytes is 2^nnnn, big-endian bytes
|
||||
return "Int";
|
||||
@@ -45,10 +46,10 @@ fn get_marker_name(u8 marker) {
|
||||
}else if (marker == Marker::Date){ //date 0011 0011 ... // 8 byte float follows, big-endian bytes
|
||||
return "Date";
|
||||
}else if (marker & 0xF0 == Marker::Data){ //data 0100 nnnn [int] ... // nnnn is number of bytes unless 1111 then int count follows, followed by bytes
|
||||
return "Data";
|
||||
return "Data";
|
||||
}else if (marker & 0xF0 == Marker::ASCIIString){ //string 0101 nnnn [int] ... // ASCII string, nnnn is # of chars, else 1111 then int count, then bytes
|
||||
return "ASCIIString";
|
||||
}else if (marker & 0xF0 == Marker::Unicode16String){ //string 0110 nnnn [int] ... // Unicode string, nnnn is # of chars, else 1111 then int count, then big-endian 2-byte
|
||||
}else if (marker & 0xF0 == Marker::Unicode16String){ //string 0110 nnnn [int] ... // Unicode string, nnnn is # of chars, else 1111 then int count, then big-endian 2-byte
|
||||
return "Unicode16String";
|
||||
}else if (marker & 0xF0 == Marker::UNK_0x70){ //0111 xxxx // unused
|
||||
return "UNK_0x70";
|
||||
@@ -56,19 +57,19 @@ fn get_marker_name(u8 marker) {
|
||||
return "UID";
|
||||
}else if (marker & 0xF0 == Marker::UNK_0x90){ // 1001 xxxx // unused
|
||||
return "UNK_0x90";
|
||||
}else if (marker & 0xF0 == Marker::Array){ //array 1010 nnnn [int] objref* // nnnn is count, unless '1111', then int count follows
|
||||
}else if (marker & 0xF0 == Marker::Array){ //array 1010 nnnn [int] objref* // nnnn is count, unless '1111', then int count follows
|
||||
return "Array";
|
||||
}else if (marker & 0xF0 == Marker::UNK_0xB0){ //1011 xxxx // unused
|
||||
return "UNK_0xB0";
|
||||
}else if (marker & 0xF0 == Marker::Set){ //set 1100 nnnn [int] objref* // nnnn is count, unless '1111', then int count follows
|
||||
return "Set";
|
||||
}else if (marker & 0xF0 == Marker::Dict){ //dict 1101 nnnn [int] keyref* objref* // nnnn is count, unless '1111', then int count follows
|
||||
}else if (marker & 0xF0 == Marker::Dict){ //dict 1101 nnnn [int] keyref* objref* // nnnn is count, unless '1111', then int count follows
|
||||
return "Dict";
|
||||
}else if (marker & 0xF0 == Marker::UNK_0xE0){ // 1110 xxxx // unused
|
||||
return "UNK_0xE0";
|
||||
}else if (marker & 0xF0 == Marker::UNK_0xF0){ //1111 xxxx // unused
|
||||
return "UNK_0xF0";
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
fn format_tag(u8 marker) {
|
||||
@@ -79,12 +80,12 @@ fn coredata_to_date (double val){
|
||||
return type::impl::format_time_t(978307200 + val);
|
||||
};
|
||||
|
||||
struct DictElement {
|
||||
struct DictElement {
|
||||
CFBinaryPlistObject key @ offsetTable[parent.objReference.key_refs[std::core::array_index()]].offset;
|
||||
CFBinaryPlistObject value @ offsetTable[parent.objReference.value_refs[std::core::array_index()]].offset;
|
||||
};
|
||||
|
||||
struct ArrayElement {
|
||||
struct ArrayElement {
|
||||
CFBinaryPlistObject value @ offsetTable[parent.objReference.value_refs[std::core::array_index()]].offset;
|
||||
};
|
||||
|
||||
@@ -142,23 +143,23 @@ struct CFBinaryPlistOffset{
|
||||
|
||||
struct CFBinaryPlistObject{
|
||||
u8 marker [[format("get_marker_name")]];
|
||||
|
||||
|
||||
u8 marker_msb = marker & 0xF0;
|
||||
u8 marker_lsb = marker & 0x0F;
|
||||
|
||||
match (marker_msb){
|
||||
match (marker_msb){
|
||||
(0x0): {
|
||||
match (marker_lsb){
|
||||
(Marker::Null): {
|
||||
u8 value = 0x00 [[export]];
|
||||
}
|
||||
(Marker::False): {
|
||||
(Marker::False): {
|
||||
bool value = false [[export]];
|
||||
}
|
||||
(Marker::True): {
|
||||
bool value = true [[export]];
|
||||
}
|
||||
(Marker::Fill): {
|
||||
(Marker::Fill): {
|
||||
//I think the correct implementation is to do nothing here. The marker will be used as padding (Fill) ???
|
||||
}
|
||||
(_): {
|
||||
@@ -167,7 +168,7 @@ struct CFBinaryPlistObject{
|
||||
}
|
||||
}
|
||||
(Marker::Int): {
|
||||
be u8 size = std::math::pow(2, marker_lsb);
|
||||
be u8 size = std::math::pow(2, marker_lsb);
|
||||
// in format version '00', 1, 2, and 4-byte integers have to be interpreted as unsigned,
|
||||
// whereas 8-byte integers are signed (and 16-byte when available)
|
||||
// negative 1, 2, 4-byte integers are always emitted as 8 bytes in format '00'
|
||||
@@ -181,10 +182,10 @@ struct CFBinaryPlistObject{
|
||||
(8): be s64 value;
|
||||
(16): be s128 value;
|
||||
(_): std::error(std::format("Invalid size detected for 'Int' marker. Got size: {}.", size));
|
||||
}
|
||||
}
|
||||
}
|
||||
(Marker::Real): {
|
||||
be u8 size = std::math::pow(2, marker_lsb);
|
||||
be u8 size = std::math::pow(2, marker_lsb);
|
||||
match (size){
|
||||
(4): be float value;
|
||||
(8): be double value;
|
||||
@@ -196,7 +197,7 @@ struct CFBinaryPlistObject{
|
||||
}
|
||||
(Marker::Data): {
|
||||
ObjectLen ObjectLen;
|
||||
u8 value[ObjectLen.size];
|
||||
u8 value[ObjectLen.size];
|
||||
}
|
||||
(Marker::ASCIIString): {
|
||||
ObjectLen ObjectLen;
|
||||
@@ -216,7 +217,7 @@ struct CFBinaryPlistObject{
|
||||
(8): be u64 value;
|
||||
(16): be u128 value;
|
||||
(_): std::error(std::format("Invalid size detected for 'UID' marker. Got size: {}.", size));
|
||||
}
|
||||
}
|
||||
}
|
||||
(Marker::Set | Marker::Array): {
|
||||
ObjectLen ObjectLen;
|
||||
@@ -226,7 +227,7 @@ struct CFBinaryPlistObject{
|
||||
}
|
||||
(Marker::Dict): {
|
||||
ObjectLen ObjectLen;
|
||||
|
||||
|
||||
ObjectReference objReference;
|
||||
DictElement value[ObjectLen.size];
|
||||
}
|
||||
@@ -235,7 +236,7 @@ struct CFBinaryPlistObject{
|
||||
}
|
||||
(_): {
|
||||
std::error(std::format("Got unknown marker 0x{:x}", marker));
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -249,13 +250,13 @@ struct CFBinaryPlistHeader{
|
||||
|
||||
struct CFBinaryPlistTrailer {
|
||||
u8 unused[5];
|
||||
u8 sortVersion;
|
||||
u8 sortVersion;
|
||||
be u8 offsetIntSize;
|
||||
match (offsetIntSize){
|
||||
(1|2|4|8): {}
|
||||
(_): {std::error("Invalid offsetIntSize.");}
|
||||
}
|
||||
be u8 objectRefSize;
|
||||
be u8 objectRefSize;
|
||||
match (objectRefSize){
|
||||
(1|2|4|8): {}
|
||||
(_): {std::error("Invalid objectRefSize.");}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#pragma author WerWolv
|
||||
#pragma description BSON (Binary JSON) format
|
||||
#pragma description BSON (Binary JSON)
|
||||
|
||||
#pragma MIME application/bson
|
||||
|
||||
@@ -26,8 +26,8 @@ enum Type : u8 {
|
||||
Timestamp = 0x11,
|
||||
Int64 = 0x12,
|
||||
Decimal128 = 0x13,
|
||||
|
||||
MinKey = 0xFF,
|
||||
|
||||
MinKey = 0xFF,
|
||||
MaxKey = 0x7F
|
||||
};
|
||||
|
||||
@@ -78,9 +78,9 @@ using Document;
|
||||
|
||||
struct Element {
|
||||
Type type;
|
||||
|
||||
|
||||
CString name;
|
||||
|
||||
|
||||
if (type == Type::Double) {
|
||||
double value;
|
||||
} else if (type == Type::String) {
|
||||
@@ -93,9 +93,9 @@ struct Element {
|
||||
Binary value;
|
||||
} else if (type == Type::Undefined) {
|
||||
/* undefined */
|
||||
} else if (type == Type::ObjectId) {
|
||||
} else if (type == Type::ObjectId) {
|
||||
ObjectId value;
|
||||
} else if (type == Type::Boolean) {
|
||||
} else if (type == Type::Boolean) {
|
||||
bool value;
|
||||
} else if (type == Type::UTCDatetime) {
|
||||
type::time64_t value;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#pragma description GoldSrc engine maps format (used in Half-Life 1)
|
||||
#pragma description GoldSrc engine map (Half-Life 1)
|
||||
|
||||
import std.ptr;
|
||||
import std.mem;
|
||||
@@ -163,7 +163,7 @@ struct dmiptexlump_t
|
||||
MiptexPointer dataofs[nummiptex];
|
||||
};
|
||||
|
||||
struct VisibilityData
|
||||
struct VisibilityData
|
||||
{
|
||||
u8 data[file_header.lumps[LumpIndex::Visibility].filelen];
|
||||
u8 pad[std::mem::align_to(4, sizeof(this)) - sizeof(this)];
|
||||
|
||||
64
patterns/bzip3.hexpat
Normal file
64
patterns/bzip3.hexpat
Normal file
@@ -0,0 +1,64 @@
|
||||
#pragma author Sewer56
|
||||
#pragma description Parses BZip3 compression (file format) by Kamila Szewczyk
|
||||
#pragma MIME application/x-bzip3
|
||||
#pragma endian little
|
||||
#pragma magic [42 5A 33 76 31] @ 0x00
|
||||
import std.mem;
|
||||
|
||||
// Helper function for bit counting
|
||||
fn popcount(u8 b) {
|
||||
u32 count = 0;
|
||||
while (b != 0) {
|
||||
count = count + (b & 1);
|
||||
b = b >> 1;
|
||||
}
|
||||
return count;
|
||||
};
|
||||
|
||||
// Frame header structure
|
||||
struct FrameHeader {
|
||||
char magic[5]; // "BZ3v1"
|
||||
u32 blockSize; // Maximum block size
|
||||
};
|
||||
|
||||
// Small block header (for blocks < 64 bytes)
|
||||
struct SmallBlock {
|
||||
u32 crc32; // CRC32 checksum
|
||||
u32 literal; // Always 0xFFFFFFFF for small blocks
|
||||
u8 data[parent.compressedSize - 8]; // Uncompressed data
|
||||
};
|
||||
|
||||
// Regular block (blocks > 64 bytes)
|
||||
struct Block {
|
||||
u32 crc32; // CRC32 checksum of uncompressed data
|
||||
u32 bwtIndex; // Burrows-Wheeler transform index
|
||||
u8 model; // Compression model flags
|
||||
|
||||
if ((model & 0x02) != 0)
|
||||
u32 lzpSize; // Size after LZP compression
|
||||
if ((model & 0x04) != 0)
|
||||
u32 rleSize; // Size after RLE compression
|
||||
|
||||
u8 data[parent.compressedSize - (popcount(model) * 4 + 9)];
|
||||
};
|
||||
|
||||
// Main block structure
|
||||
struct Chunk {
|
||||
u32 compressedSize; // Size of compressed block
|
||||
u32 origSize; // Original uncompressed size
|
||||
|
||||
if (origSize < 64) {
|
||||
SmallBlock block;
|
||||
} else {
|
||||
Block block;
|
||||
}
|
||||
};
|
||||
|
||||
// Main parsing structure
|
||||
struct BZip3File {
|
||||
FrameHeader header;
|
||||
// Read blocks until end of file
|
||||
Chunk chunks[while(!std::mem::eof())];
|
||||
};
|
||||
|
||||
BZip3File file @ 0x0;
|
||||
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;
|
||||
@@ -285,26 +286,26 @@ struct DirectoryIndexEntry {
|
||||
|
||||
struct ListingChunk {
|
||||
char magic[4];
|
||||
|
||||
|
||||
if (magic == "PMGL") {
|
||||
type::Size<u32> freeSpaceLength;
|
||||
u32;
|
||||
u32 prevChunkNumber, nextChunkNumber;
|
||||
|
||||
|
||||
u16 directoryListingEntryCount @ addressof(this) + parent.directoryChunkSize - 2;
|
||||
u16 offsets[(freeSpaceLength - 2) / 2] @ addressof(directoryListingEntryCount) - (freeSpaceLength - 2);
|
||||
|
||||
|
||||
DirectoryListingEntry directories[directoryListingEntryCount];
|
||||
|
||||
|
||||
$ = addressof(directoryListingEntryCount) + sizeof(directoryListingEntryCount);
|
||||
} else if (magic == "PMGI") {
|
||||
type::Size<u32> freeSpaceLength;
|
||||
|
||||
|
||||
u16 directoryIndexEntryCount @ addressof(this) + parent.directoryChunkSize - 2;
|
||||
u16 offsets[(freeSpaceLength - 2) / 2] @ addressof(directoryIndexEntryCount) - (freeSpaceLength - 2);
|
||||
|
||||
|
||||
DirectoryIndexEntry indexes[directoryIndexEntryCount];
|
||||
|
||||
|
||||
$ = addressof(directoryIndexEntryCount) + sizeof(directoryIndexEntryCount);
|
||||
} else {
|
||||
std::error("Invalid chunk magic!");
|
||||
@@ -313,7 +314,7 @@ struct ListingChunk {
|
||||
|
||||
struct HeaderSection {
|
||||
char magic[4];
|
||||
|
||||
|
||||
if (magic == "\xFE\x01\x00\x00") {
|
||||
u32;
|
||||
type::Size<u64> fileSize;
|
||||
@@ -337,7 +338,7 @@ struct HeaderSection {
|
||||
u32;
|
||||
u32;
|
||||
u32;
|
||||
|
||||
|
||||
ListingChunk chunk[directoryChunkCount];
|
||||
} else {
|
||||
std::error("Invalid header section magic!");
|
||||
@@ -347,22 +348,22 @@ struct HeaderSection {
|
||||
struct HeaderSectionTableEntry {
|
||||
u64 offset;
|
||||
type::Size<u64> size;
|
||||
|
||||
|
||||
HeaderSection headerSection @ offset;
|
||||
};
|
||||
|
||||
struct NameListEntry {
|
||||
type::Size<u16> nameLength;
|
||||
char16 name[nameLength];
|
||||
char16 name[nameLength];
|
||||
padding[2];
|
||||
};
|
||||
|
||||
struct NameListFile {
|
||||
u16 fileLengthWords;
|
||||
u16 entriesInFile;
|
||||
|
||||
|
||||
NameListEntry nameList[entriesInFile];
|
||||
|
||||
|
||||
padding[0x2E];
|
||||
};
|
||||
|
||||
@@ -376,7 +377,7 @@ struct SectionData {
|
||||
u32;
|
||||
};
|
||||
|
||||
struct Content {
|
||||
struct Content {
|
||||
NameListFile nameListFile;
|
||||
SectionData sectionData;
|
||||
};
|
||||
@@ -389,9 +390,9 @@ struct CHM {
|
||||
be u32 timeStamp;
|
||||
WindowsLanguageId languageId;
|
||||
type::GUID guids[2];
|
||||
|
||||
|
||||
HeaderSectionTableEntry headerSectionTable[2];
|
||||
|
||||
|
||||
Content *dataOffset : u64;
|
||||
};
|
||||
|
||||
|
||||
@@ -116,11 +116,11 @@ struct SymbolTable {
|
||||
Type type;
|
||||
StorageClass storageClass;
|
||||
u8 numberOfAuxSymbols;
|
||||
|
||||
|
||||
countedSymbols += 1 + numberOfAuxSymbols;
|
||||
|
||||
|
||||
AuxSymbol auxSymbols[numberOfAuxSymbols];
|
||||
|
||||
|
||||
if (countedSymbols >= parent.header.numberOfSymbols)
|
||||
break;
|
||||
};
|
||||
@@ -164,7 +164,10 @@ bitfield SectionFlags {
|
||||
};
|
||||
|
||||
fn format_alignment(u8 alignment) {
|
||||
return 1 << alignment;
|
||||
if(alignment > 0) {
|
||||
return 1 << (alignment - 1);
|
||||
}
|
||||
return alignment;
|
||||
};
|
||||
|
||||
struct Relocations {
|
||||
@@ -184,7 +187,7 @@ struct Section {
|
||||
u16 numberOfRelocations;
|
||||
u16 numberOfLineNumbers;
|
||||
SectionFlags characteristics;
|
||||
|
||||
|
||||
u8 rawData[sizeOfRawData] @ pointerToRawData [[sealed]];
|
||||
Relocations relocations[numberOfRelocations] @ pointerToRelocations;
|
||||
};
|
||||
@@ -202,9 +205,9 @@ struct Header {
|
||||
|
||||
struct COFF {
|
||||
Header header;
|
||||
|
||||
|
||||
Section sectionTable[header.numberOfSections];
|
||||
|
||||
|
||||
SymbolTable symbolTable[header.numberOfSymbols] @ header.pointerToSymbolTable;
|
||||
StringTable stringTable @ addressof(symbolTable) + sizeof(symbolTable);
|
||||
};
|
||||
|
||||
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;
|
||||
@@ -1,5 +1,5 @@
|
||||
#pragma author WerWolv
|
||||
#pragma description Old Binary CPIO Format
|
||||
#pragma description Old Binary CPIO
|
||||
|
||||
import type.base;
|
||||
|
||||
@@ -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")]];
|
||||
@@ -42,7 +42,7 @@ namespace old_binary {
|
||||
std::core::set_endian(std::mem::Endian::Little);
|
||||
else
|
||||
std::error("Invalid CPIO Magic!");
|
||||
|
||||
|
||||
u16 dev;
|
||||
u16 ino;
|
||||
Mode mode;
|
||||
@@ -59,7 +59,7 @@ namespace old_binary {
|
||||
CpioHeader header;
|
||||
char pathname[header.namesize % 2 == 0 ? header.namesize : header.namesize + 1];
|
||||
u8 data[header.filesize % 2 == 0 ? header.filesize : header.filesize + 1];
|
||||
|
||||
|
||||
if (pathname == "TRAILER!!!\x00\x00")
|
||||
break;
|
||||
};
|
||||
|
||||
99
patterns/credhist.hexpat
Normal file
99
patterns/credhist.hexpat
Normal file
@@ -0,0 +1,99 @@
|
||||
#pragma description "CREDHIST"
|
||||
|
||||
/*
|
||||
FilePath: C:\Users\<USER>\AppData\Roaming\Microsoft\Protect\
|
||||
The files/folders are hidden.
|
||||
|
||||
To unhide it
|
||||
1. Open Command Prompt (cmd.exe).
|
||||
2. Run the following command:
|
||||
=> attrib -h -s
|
||||
|
||||
*/
|
||||
|
||||
import type.guid;
|
||||
import std.mem;
|
||||
|
||||
// https://learn.microsoft.com/en-us/windows/win32/seccrypto/alg-id
|
||||
enum ALG_ID : u32 {
|
||||
CALG_DH_EPHEM = 0x0000aa02, // Diffie-Hellman ephemeral key exchange algorithm.
|
||||
CALG_DH_SF = 0x0000aa01, // Diffie-Hellman store and forward key exchange algorithm.
|
||||
CALG_DSS_SIGN = 0x00002200, // DSA public key signature algorithm.
|
||||
CALG_ECDH = 0x0000aa05, // Elliptic curve Diffie-Hellman key exchange algorithm.
|
||||
CALG_ECDH_EPHEM = 0x0000ae06, // Ephemeral elliptic curve Diffie-Hellman key exchange algorithm.
|
||||
CALG_ECDSA = 0x00002203, // Elliptic curve digital signature algorithm.
|
||||
CALG_ECMQV = 0x0000a001, // Elliptic curve Menezes, Qu, and Vanstone (MQV) key exchange algorithm.
|
||||
CALG_HASH_REPLACE_OWF = 0x0000800b, // One way function hashing algorithm.
|
||||
CALG_HUGHES_MD5 = 0x0000a003, // Hughes MD5 hashing algorithm.
|
||||
CALG_HMAC = 0x00008009, // HMAC keyed hash algorithm.
|
||||
CALG_KEA_KEYX = 0x0000aa04, // KEA key exchange algorithm (FORTEZZA).
|
||||
CALG_MAC = 0x00008005, // MAC keyed hash algorithm.
|
||||
CALG_MD2 = 0x00008001, // MD2 hashing algorithm.
|
||||
CALG_MD4 = 0x00008002, // MD4 hashing algorithm.
|
||||
CALG_MD5 = 0x00008003, // MD5 hashing algorithm.
|
||||
CALG_NO_SIGN = 0x00002000, // No signature algorithm.
|
||||
CALG_OID_INFO_CNG_ONLY = 0xffffffff, // Algorithm is only implemented in CNG.
|
||||
CALG_OID_INFO_PARAMETERS = 0xfffffffe, // Algorithm is defined in the encoded parameters.
|
||||
CALG_PCT1_MASTER = 0x00004c04, // Used by the Schannel.dll operations system.
|
||||
CALG_RC2 = 0x00006602, // RC2 block encryption algorithm.
|
||||
CALG_RC4 = 0x00006801, // RC4 stream encryption algorithm.
|
||||
CALG_RC5 = 0x0000660d, // RC5 block encryption algorithm.
|
||||
CALG_RSA_KEYX = 0x0000a400, // RSA public key exchange algorithm.
|
||||
CALG_RSA_SIGN = 0x00002400, // RSA public key signature algorithm.
|
||||
CALG_SCHANNEL_ENC_KEY = 0x00004c07, // Used by the Schannel.dll operations system.
|
||||
CALG_SCHANNEL_MAC_KEY = 0x00004c03, // Used by the Schannel.dll operations system.
|
||||
CALG_SCHANNEL_MASTER_HASH = 0x00004c02, // Used by the Schannel.dll operations system.
|
||||
CALG_SEAL = 0x00006802, // SEAL encryption algorithm.
|
||||
CALG_SHA = 0x00008004, // SHA hashing algorithm.
|
||||
CALG_SHA1 = 0x00008004, // Same as CALG_SHA.
|
||||
CALG_SHA_256 = 0x0000800c, // 256-bit SHA hashing algorithm.
|
||||
CALG_SHA_384 = 0x0000800d, // 384-bit SHA hashing algorithm.
|
||||
CALG_SHA_512 = 0x0000800e, // 512-bit SHA hashing algorithm.
|
||||
CALG_SKIPJACK = 0x0000660a, // Skipjack block encryption algorithm (FORTEZZA).
|
||||
CALG_SSL2_MASTER = 0x00004c05, // Used by the Schannel.dll operations system.
|
||||
CALG_SSL3_MASTER = 0x00004c01, // Used by the Schannel.dll operations system.
|
||||
CALG_SSL3_SHAMD5 = 0x00008008, // Used by the Schannel.dll operations system.
|
||||
CALG_TEK = 0x0000660b, // TEK (FORTEZZA).
|
||||
CALG_TLS1_MASTER = 0x00004c06, // Used by the Schannel.dll operations system.
|
||||
CALG_TLS1PRF = 0x0000800a // Used by the Schannel.dll operations system.
|
||||
};
|
||||
|
||||
// https://devblogs.microsoft.com/oldnewthing/20040315-00/?p=40253
|
||||
struct SID {
|
||||
u8 revisionlvl[[name("RevisionLevel"), comment("SID_REVISION")]];
|
||||
u8 dashes[[name("NoOfDashes"), comment("number of dashes minus two")]]; // dashes = actualdashes - 0x2
|
||||
char ntauth[0x6][[name("NtAuthority"), comment("SECURITY_NT_AUTHORITY")]];
|
||||
u32 subatuh1[[name("SubAuthority1"), comment("SECURITY_NT_NON_UNIQUE")]];
|
||||
u32 subatuh2[[name("SubAuthority2"), comment("these identify the machine that issued the SID")]];
|
||||
u32 subatuh3[[name("SubAuthority3"), comment("these identify the machine that issued the SID")]];
|
||||
u32 subatuh4[[name("SubAuthority4"), comment("these identify the machine that issued the SID")]];
|
||||
u32 rid[[name("RID"), comment("unique user id on the machine")]];
|
||||
};
|
||||
|
||||
|
||||
struct CREDHIST_HEADER{
|
||||
u32 version[[name("Version")]];
|
||||
type::GUID guid[[name("GUID")]];
|
||||
u32 nextlen[[name("NextCredSize")]];
|
||||
};
|
||||
|
||||
struct CREDHIST {
|
||||
CREDHIST_HEADER credheader[[name("CredHistHeader")]];
|
||||
if (std::mem::eof()){
|
||||
break;
|
||||
}
|
||||
u32 flgas [[name("Flags")]];
|
||||
ALG_ID alghashid[[name("AlgorithmHashId")]];
|
||||
u32 rounds [[name("Rounds")]];
|
||||
u32 sidlen [[name("SIDLen")]];
|
||||
ALG_ID algcryptid[[name("AlgorithmCryptId")]];
|
||||
u32 sha1len[[name("SHA1Len")]];
|
||||
u32 md4len[[name("ntlmlen")]];
|
||||
char salt[0x10][[name("Salt")]];
|
||||
SID sid[[name("SID")]];
|
||||
char sha1hash[sha1len][[name("SHA1Hash")]];
|
||||
char md4hash[md4len][[name("NTLMHash")]];
|
||||
u64 unk1[[name("Unknown")]];
|
||||
};
|
||||
|
||||
CREDHIST credhist [while(!std::mem::eof())] @ 0x0[[name("CredHist")]];
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma description DirectDraw Surface
|
||||
|
||||
#pragma MIME image/vnd-ms.dds
|
||||
#pragma MIME image/x-dds
|
||||
#pragma endian little
|
||||
|
||||
enum DXGI_FORMAT : u32 {
|
||||
@@ -202,7 +203,7 @@ enum DX10AlphaMode : u32 {
|
||||
Straight,
|
||||
PreMultiplied,
|
||||
Opaque,
|
||||
Custom,
|
||||
Custom,
|
||||
};
|
||||
|
||||
bitfield DX10MiscFlags {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#pragma description Dalvik EXecutable Format
|
||||
#pragma description Dalvik EXecutable
|
||||
#pragma magic [ 64 65 78 0A ?? ?? ?? 00 ]
|
||||
|
||||
import type.leb128;
|
||||
|
||||
@@ -99,7 +100,7 @@ enum access_flag : type::uLEB128{
|
||||
static = 0x8,
|
||||
final = 0x10,
|
||||
synchronized = 0x20,
|
||||
volatile = 0x40
|
||||
volatile = 0x40
|
||||
};
|
||||
|
||||
struct encoded_field {
|
||||
@@ -134,7 +135,7 @@ struct class_def_item {
|
||||
u32 class_data_off;
|
||||
//class_data_item *class_data_off:u32;
|
||||
u32 static_values_off;
|
||||
char class_name[] @ addressof(parent.type_ids[class_idx].type_name);
|
||||
char class_name[] @ addressof(parent.type_ids[class_idx].type_name);
|
||||
}[[name(class_name)]];
|
||||
|
||||
struct type_item {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#pragma description DICOM file
|
||||
#pragma description DICOM Digital Imaging and Communications in Medicine
|
||||
|
||||
#pragma MIME application/dicom
|
||||
#pragma endian little
|
||||
|
||||
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
|
||||
|
||||
@@ -11,41 +12,41 @@ import std.mem;
|
||||
//
|
||||
// UDIFResourceFile starts at size(file) - 512
|
||||
struct UDIFResourceFile {
|
||||
type::Magic<"koly"> Signature; // Magic ('koly')
|
||||
u32 Version; // Current version is 4
|
||||
type::Size<u32> HeaderSize; // sizeof(this), always 512
|
||||
type::Magic<"koly"> Signature; // Magic ('koly')
|
||||
u32 Version; // Current version is 4
|
||||
type::Size<u32> HeaderSize; // sizeof(this), always 512
|
||||
u32 Flags;
|
||||
u64 RunningDataForkOffset; //
|
||||
u64 DataForkOffset; // Data fork offset (usually 0, beginning of file)
|
||||
type::Size<u64> DataForkLength; // Size of data fork (usually up to the XMLOffset, below)
|
||||
u64 RsrcForkOffset; // Resource fork offset, if any
|
||||
type::Size<u64> RsrcForkLength; // Resource fork length, if any
|
||||
u32 SegmentNumber; // Usually 1, may be 0
|
||||
u32 SegmentCount; // Usually 1, may be 0
|
||||
type::GUID SegmentID; // 128-bit GUID identifier of segment (if SegmentNumber !=0)
|
||||
|
||||
u64 RunningDataForkOffset; //
|
||||
u64 DataForkOffset; // Data fork offset (usually 0, beginning of file)
|
||||
type::Size<u64> DataForkLength; // Size of data fork (usually up to the XMLOffset, below)
|
||||
u64 RsrcForkOffset; // Resource fork offset, if any
|
||||
type::Size<u64> RsrcForkLength; // Resource fork length, if any
|
||||
u32 SegmentNumber; // Usually 1, may be 0
|
||||
u32 SegmentCount; // Usually 1, may be 0
|
||||
|
||||
u32 DataChecksumType; // Data fork
|
||||
type::GUID SegmentID; // 128-bit GUID identifier of segment (if SegmentNumber !=0)
|
||||
|
||||
u32 DataChecksumType; // Data fork
|
||||
type::Size<u32> DataChecksumSize; // Checksum Information
|
||||
u32 DataChecksum[DataChecksumSize]; // Up to 128-bytes (32 x 4) of checksum
|
||||
u32 DataChecksum[32]; // Up to 128-bytes (32 x 4) of checksum
|
||||
|
||||
u64 XMLOffset; // Offset of property list in DMG, from beginning
|
||||
type::Size<u64> XMLLength; // Length of property list
|
||||
u8 Reserved1[120]; // 120 reserved bytes - zeroed
|
||||
u64 XMLOffset; // Offset of property list in DMG, from beginning
|
||||
type::Size<u64> XMLLength; // Length of property list
|
||||
u8 Reserved1[120]; // 120 reserved bytes - zeroed
|
||||
|
||||
u32 ChecksumType; // Master
|
||||
type::Size<u32> ChecksumSize; // Checksum information
|
||||
u32 Checksum[ChecksumSize]; // Up to 128-bytes (32 x 4) of checksum
|
||||
u32 ChecksumType; // Master
|
||||
type::Size<u32> ChecksumSize; // Checksum information
|
||||
u32 Checksum[32]; // Up to 128-bytes (32 x 4) of checksum
|
||||
|
||||
u32 ImageVariant; // Commonly 1
|
||||
u64 SectorCount; // Size of DMG when expanded, in sectors
|
||||
u32 ImageVariant; // Commonly 1
|
||||
u64 SectorCount; // Size of DMG when expanded, in sectors
|
||||
|
||||
u32 reserved2; // 0
|
||||
u32 reserved3; // 0
|
||||
u32 reserved4; // 0
|
||||
u32 reserved2; // 0
|
||||
u32 reserved3; // 0
|
||||
u32 reserved4; // 0
|
||||
};
|
||||
|
||||
|
||||
UDIFResourceFile trailer @ std::mem::size() - 512;
|
||||
|
||||
char metadata_plist[trailer.XMLLength] @ trailer.XMLOffset;
|
||||
char metadata_plist[trailer.XMLLength] @ trailer.XMLOffset;
|
||||
102
patterns/dmp64.hexpat
Normal file
102
patterns/dmp64.hexpat
Normal file
@@ -0,0 +1,102 @@
|
||||
#pragma magic [ 50 41 47 45 ] @ 0x00 // PAGE
|
||||
#pragma author "5h4rrK"
|
||||
#pragma description "KERNEL DUMP"
|
||||
|
||||
import std.core;
|
||||
import std.io;
|
||||
import std.array;
|
||||
|
||||
#define COMMENT_SIZE 0x80
|
||||
|
||||
fn format_values(auto val){
|
||||
return std::format("{:#x}", val);
|
||||
};
|
||||
|
||||
fn format_size_values(auto val){
|
||||
return std::format(
|
||||
"{:#x} ({}) ",
|
||||
val,
|
||||
std::format("{:#x}",val * 0x1000)
|
||||
);
|
||||
|
||||
};
|
||||
|
||||
union DUMP_FILE_ATTRIBUTES {
|
||||
u32 bitfields[[name("BitFields")]];
|
||||
u32 attributes[[name("Attributes")]];
|
||||
};
|
||||
|
||||
enum DUMP_TYPE : u32 {
|
||||
FULL_DUMP = 0x01,
|
||||
BITMAP_DUMP = 0x05
|
||||
};
|
||||
|
||||
struct EXCEPTION_RECORD64
|
||||
{
|
||||
u32 exception_code[[name("ExceptionCode"), format("format_values")]];
|
||||
u32 exception_flags[[name("ExceptionFlags"), format("format_values")]];
|
||||
u64 exception_record[[name("ExceptionRecord"), format("format_values")]];
|
||||
u64 exception_address[[name("ExceptionAddress"), format("format_values")]];
|
||||
u32 number_parameters[[name("NumberParameters"), format("format_values")]];
|
||||
u32 unused_alignment[[name("Alignment"), format("format_values")]];
|
||||
u64 exception_information[15][[name("ExceptionInformation")]];
|
||||
};
|
||||
|
||||
struct PHYSICAL_MEMORY_RUN64 {
|
||||
u64 base_page [[ name("BasePage"), format("format_size_values"), comment("StartOffset = BasePage * PageSize")]];
|
||||
u64 page_count[[ name("PageCount"),format("format_size_values"), comment("Length = PageCount * PageSize")]];
|
||||
}[[name("PHYSICAL_MEMORY_RUN_ENTRY")]];
|
||||
|
||||
struct PHYSICAL_MEMORY_DESCRIPTOR64 {
|
||||
u32 no_of_runs [[name("NumberOfRuns")]];
|
||||
char description[4][[name("Description")]];
|
||||
u64 no_of_pages[[name("NumberOfPages"),format("format_values")]];
|
||||
// PHYSICAL_MEMORY_RUN64 pmr64[no_of_runs] [[name("PHYSICAL_MEMORY_RUN64")]];
|
||||
std::Array<PHYSICAL_MEMORY_RUN64, no_of_runs> pmrObjs[[name("PHYSICAL_MEMORY_RUN64")]];
|
||||
|
||||
};
|
||||
|
||||
struct DUMP_HEADER64 {
|
||||
char signature[4][[name("Signature")]];
|
||||
char validdump[4][[name("ValidDump")]];
|
||||
u32 major_version[[name("MajorVersion")]];
|
||||
u32 minor_version[[name("MinorVersion")]];
|
||||
u64 dtb [[name("DirectoryBaseTable"),format("format_values")]];
|
||||
u64 pfn [[name("PfnDataBase"), format("format_values")]];
|
||||
u64 ploadedmodulelist [[name("PsLoadedModuleList"), format("format_values")]];
|
||||
u64 pactiveprocesshead [[name("PsActiveProcessHead"), format("format_values")]];
|
||||
u32 machine_type [[name("MachineImageType"), format("format_values")]];
|
||||
u32 processor_counts [[name("ProcessorsCount")]];
|
||||
u32 bug_check [[name("BugCheckCode"), format("format_values")]];
|
||||
u32 bug_check_code_desc[[name("BugCheckCodeDescription"), format("format_values")]];
|
||||
u64 bug_check_param1[[name("BugCheckCodeParameter1"), format("format_values")]];
|
||||
u64 bug_check_param2[[name("BugCheckCodeParameter2"), format("format_values")]];
|
||||
u64 bug_check_param3[[name("BugCheckCodeParameter3"), format("format_values")]];
|
||||
u64 bug_check_param4[[name("BugCheckCodeParameter4"), format("format_values")]];
|
||||
char version_user[0x20][[name("VersionUser")]];
|
||||
u64 kdbg[[name("KdDebuggerDataBlock"), format("format_values")]];
|
||||
PHYSICAL_MEMORY_DESCRIPTOR64 phys_mem_desc[[name("PHYSICAL_MEMORY_DESCRIPTOR64")]];
|
||||
char mem_block_buffer[0x260][[name("PhysicalMemoryBlockBuffer")]];
|
||||
char context_record[0xbb8][[name("ContextRecord")]];
|
||||
EXCEPTION_RECORD64 excr[[name("EXCEPTION_RECORD64")]];
|
||||
DUMP_TYPE dmp_type[[name("DumpType")]];
|
||||
char desc1[4][[name("Description")]];
|
||||
u64 req_dump_space[[name("RequiredDumpSpace"), format("format_values")]];
|
||||
u64 sys_time[[name("SystemTime"), format("format_values")]];
|
||||
char comment[COMMENT_SIZE][[name("Comment")]];
|
||||
u64 sys_up_time[[name("SystemUpTime"), format("format_values")]];
|
||||
u32 min_dmp_fields[[name("MiniDumpFields"), format("format_values")]];
|
||||
u32 sec_data_state[[name("SecondaryDataState"), format("format_values")]];
|
||||
u32 product_type[[name("ProductType"), format("format_values")]];
|
||||
u32 suite_mask[[name("SuiteMask"), format("format_values")]];
|
||||
u32 writer_status[[name("WriterStatus"), format("format_values")]];
|
||||
char unused1[[name("Unused1")]];
|
||||
char secondary_version[[name("KdSecondaryVersion")]];
|
||||
char unused2[2][[name("Unused2")]];
|
||||
DUMP_FILE_ATTRIBUTES dfa[[name("DUMP_FILE_ATTRIBUTES")]];
|
||||
u32 boot_id[[name("BootId")]];
|
||||
char reserved[0xfa8][[name("Reserved")]];
|
||||
|
||||
};
|
||||
|
||||
DUMP_HEADER64 dmp @ 0x00 [[name("DumpHeader")]];
|
||||
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;
|
||||
73
patterns/dpapiblob.hexpat
Normal file
73
patterns/dpapiblob.hexpat
Normal file
@@ -0,0 +1,73 @@
|
||||
#pragma description "DPAPI Blob"
|
||||
|
||||
import type.guid;
|
||||
import std.mem;
|
||||
|
||||
enum ALG_ID : u32 {
|
||||
CALG_DH_EPHEM = 0x0000aa02,
|
||||
CALG_DH_SF = 0x0000aa01,
|
||||
CALG_DSS_SIGN = 0x00002200,
|
||||
CALG_ECDH = 0x0000aa05,
|
||||
CALG_ECDH_EPHEM = 0x0000ae06,
|
||||
CALG_ECDSA = 0x00002203,
|
||||
CALG_ECMQV = 0x0000a001,
|
||||
CALG_HASH_REPLACE_OWF = 0x0000800b,
|
||||
CALG_HUGHES_MD5 = 0x0000a003,
|
||||
CALG_HMAC = 0x00008009,
|
||||
CALG_KEA_KEYX = 0x0000aa04,
|
||||
CALG_MAC = 0x00008005,
|
||||
CALG_MD2 = 0x00008001,
|
||||
CALG_MD4 = 0x00008002,
|
||||
CALG_MD5 = 0x00008003,
|
||||
CALG_NO_SIGN = 0x00002000,
|
||||
CALG_OID_INFO_CNG_ONLY = 0xffffffff,
|
||||
CALG_OID_INFO_PARAMETERS = 0xfffffffe,
|
||||
CALG_PCT1_MASTER = 0x00004c04,
|
||||
CALG_RC2 = 0x00006602,
|
||||
CALG_RC4 = 0x00006801,
|
||||
CALG_RC5 = 0x0000660d,
|
||||
CALG_RSA_KEYX = 0x0000a400,
|
||||
CALG_RSA_SIGN = 0x00002400,
|
||||
CALG_SCHANNEL_ENC_KEY = 0x00004c07,
|
||||
CALG_SCHANNEL_MAC_KEY = 0x00004c03,
|
||||
CALG_SCHANNEL_MASTER_HASH = 0x00004c02,
|
||||
CALG_SEAL = 0x00006802,
|
||||
CALG_SHA = 0x00008004,
|
||||
CALG_SHA1 = 0x00008004,
|
||||
CALG_SHA_256 = 0x0000800c,
|
||||
CALG_SHA_384 = 0x0000800d,
|
||||
CALG_SHA_512 = 0x0000800e,
|
||||
CALG_SKIPJACK = 0x0000660a,
|
||||
CALG_SSL2_MASTER = 0x00004c05,
|
||||
CALG_SSL3_MASTER = 0x00004c01,
|
||||
CALG_SSL3_SHAMD5 = 0x00008008,
|
||||
CALG_TEK = 0x0000660b,
|
||||
CALG_TLS1_MASTER = 0x00004c06,
|
||||
CALG_TLS1PRF = 0x0000800a
|
||||
};
|
||||
|
||||
struct DPAPI_BLOB{
|
||||
u32 version[[name("Version")]];
|
||||
type::GUID providerguid[[name("ProviderGUID")]];
|
||||
u32 masterguid[[name("MasterKeyVersion")]];
|
||||
type::GUID guid[[name("MasterKeyGUID")]];
|
||||
u32 flags[[name("Flags")]];
|
||||
u32 desclen [[name("DescriptionLen")]];
|
||||
char16 desc[desclen / 0x02 ] [[name("Description")]];
|
||||
ALG_ID cryptid [[name("AlgCryptId")]];
|
||||
u32 algcryptlen[[name("AlgCryptLen")]];
|
||||
u32 saltlen [[name("SaltLen")]];
|
||||
char salt[saltlen][[name("Salt")]];
|
||||
u32 hmackeylen[[name("HMACKeyLen")]];
|
||||
char hmackey[hmackeylen][[name("HMACKey")]];
|
||||
ALG_ID algid[[name("AlgHashId")]];
|
||||
u32 alghashkeylen[[name("AlgHashKeyLen")]];
|
||||
u32 hmac2keylen[[name("HMAC2keylen")]];
|
||||
char hmac2[hmac2keylen][[name("HMAC2Key")]];
|
||||
u32 datalen[[name("DataLen")]];
|
||||
char data[datalen][[name("Data")]];
|
||||
u32 signlen[[name("signlen")]];
|
||||
char signhash[signlen][[name("SignHash")]];
|
||||
};
|
||||
|
||||
DPAPI_BLOB dpapiblob @0x00 [[name("DPAPIBlob")]];
|
||||
124
patterns/dpapimasterkey.hexpat
Normal file
124
patterns/dpapimasterkey.hexpat
Normal file
@@ -0,0 +1,124 @@
|
||||
#pragma description "DPAPIMasterKey"
|
||||
|
||||
/*
|
||||
FilePath: C:\Users\<USER>\AppData\Roaming\Microsoft\Protect\<SID>
|
||||
This files are hidden.
|
||||
To unhide it,
|
||||
1. Open Command Prompt (cmd.exe).
|
||||
2. Run the following command:
|
||||
- attrib -h -s
|
||||
|
||||
*/
|
||||
|
||||
import type.guid;
|
||||
|
||||
// https://learn.microsoft.com/en-us/windows/win32/seccrypto/alg-id
|
||||
enum ALG_ID : u32 {
|
||||
CALG_DH_EPHEM = 0x0000aa02,
|
||||
CALG_DH_SF = 0x0000aa01,
|
||||
CALG_DSS_SIGN = 0x00002200,
|
||||
CALG_ECDH = 0x0000aa05,
|
||||
CALG_ECDH_EPHEM = 0x0000ae06,
|
||||
CALG_ECDSA = 0x00002203,
|
||||
CALG_ECMQV = 0x0000a001,
|
||||
CALG_HASH_REPLACE_OWF = 0x0000800b,
|
||||
CALG_HUGHES_MD5 = 0x0000a003,
|
||||
CALG_HMAC = 0x00008009,
|
||||
CALG_KEA_KEYX = 0x0000aa04,
|
||||
CALG_MAC = 0x00008005,
|
||||
CALG_MD2 = 0x00008001,
|
||||
CALG_MD4 = 0x00008002,
|
||||
CALG_MD5 = 0x00008003,
|
||||
CALG_NO_SIGN = 0x00002000,
|
||||
CALG_OID_INFO_CNG_ONLY = 0xffffffff,
|
||||
CALG_OID_INFO_PARAMETERS = 0xfffffffe,
|
||||
CALG_PCT1_MASTER = 0x00004c04,
|
||||
CALG_RC2 = 0x00006602,
|
||||
CALG_RC4 = 0x00006801,
|
||||
CALG_RC5 = 0x0000660d,
|
||||
CALG_RSA_KEYX = 0x0000a400,
|
||||
CALG_RSA_SIGN = 0x00002400,
|
||||
CALG_SCHANNEL_ENC_KEY = 0x00004c07,
|
||||
CALG_SCHANNEL_MAC_KEY = 0x00004c03,
|
||||
CALG_SCHANNEL_MASTER_HASH = 0x00004c02,
|
||||
CALG_SEAL = 0x00006802,
|
||||
CALG_SHA = 0x00008004,
|
||||
CALG_SHA1 = 0x00008004,
|
||||
CALG_SHA_256 = 0x0000800c,
|
||||
CALG_SHA_384 = 0x0000800d,
|
||||
CALG_SHA_512 = 0x0000800e,
|
||||
CALG_SKIPJACK = 0x0000660a,
|
||||
CALG_SSL2_MASTER = 0x00004c05,
|
||||
CALG_SSL3_MASTER = 0x00004c01,
|
||||
CALG_SSL3_SHAMD5 = 0x00008008,
|
||||
CALG_TEK = 0x0000660b,
|
||||
CALG_TLS1_MASTER = 0x00004c06,
|
||||
CALG_TLS1PRF = 0x0000800a
|
||||
};
|
||||
|
||||
|
||||
struct CREDHIST_MASTERKEY {
|
||||
u32 version[[name("Version")]];
|
||||
type::GUID guid[[name("GUID")]];
|
||||
|
||||
};
|
||||
|
||||
struct DOMAINKEY_MASTERKEY {
|
||||
u32 version[[name("Version")]];
|
||||
u32 seclen[[name("SecretLen")]];
|
||||
u32 accesschklen[[name("AccessCheckLen")]];
|
||||
type::GUID backupguid_[[name("BackupKeyGUID")]];
|
||||
char blob[seclen][[name("Secret")]];
|
||||
char accesschk[accesschklen][[name("AccessCheck")]];
|
||||
|
||||
};
|
||||
|
||||
struct BACKUP_MASTERKEY {
|
||||
u32 start = $;
|
||||
u32 version[[name("Version")]];
|
||||
char salt[16][[name("Salt")]];
|
||||
u32 rounds [[name("PBKDF2IterationCount")]];
|
||||
ALG_ID alghashid[[name("HMACAlgId")]];
|
||||
ALG_ID algcryptid[[name("CryptAlgId")]];
|
||||
u32 meta = $ - start;
|
||||
char key[parent.backupkeylen - meta][[name("Key")]];
|
||||
};
|
||||
|
||||
struct PASSWORD_MASTERKEY {
|
||||
u32 start = $;
|
||||
u32 version[[name("Version")]];
|
||||
char salt[16][[name("Salt")]];
|
||||
u32 rounds [[name("PBKDF2IterationCount")]];
|
||||
ALG_ID alghashid[[name("HMACAlgId")]];
|
||||
ALG_ID algcryptid[[name("CryptAlgId")]];
|
||||
u32 meta = $ - start;
|
||||
char key[parent.masterkeylen - meta][[name("Key")]];
|
||||
};
|
||||
|
||||
struct DPAPIMasterKey {
|
||||
u32 version[[name("Version")]];
|
||||
u32 unk1[[name("Unknown1")]];
|
||||
u32 unk2[[name("Unknown2")]];
|
||||
char16 guid[0x24][[name("GUID"), comment("This GUID is the fileName itself")]];
|
||||
u32 unk3[[name("Unknown3")]];
|
||||
u32 unk4[[name("Unknown4")]];
|
||||
u32 policy[[name("Policy")]];
|
||||
u64 masterkeylen [[name("MasterKeyLen")]];
|
||||
u64 backupkeylen [[name("BackupKeyLen")]];
|
||||
u64 credhistlen [[name("CredHistoryLen")]];
|
||||
u64 domainkeylen [[name("DomainKeyLen")]];
|
||||
if (masterkeylen > 0){
|
||||
PASSWORD_MASTERKEY masterkey[[name("MasterKey")]];
|
||||
}
|
||||
if (backupkeylen > 0){
|
||||
BACKUP_MASTERKEY backupkey[[name("BackupKey")]];
|
||||
}
|
||||
if (credhistlen > 0){
|
||||
CREDHIST_MASTERKEY credhistkey[[name("CredHistoryKey")]];
|
||||
}
|
||||
if (domainkeylen > 0){
|
||||
DOMAINKEY_MASTERKEY domainkey[[name("DomainKey")]];
|
||||
}
|
||||
};
|
||||
|
||||
DPAPIMasterKey masterkey @0x00[[name("DPAPIMasterKey")]];
|
||||
@@ -1,4 +1,5 @@
|
||||
#pragma description .DS_Store file format
|
||||
#pragma description macOS .DS_Store
|
||||
#pragma magic [ 42 75 64 31 ] @ 0x04
|
||||
|
||||
// Apple macOS .DS_Store format
|
||||
#pragma endian big
|
||||
@@ -7,11 +8,11 @@ import std.io;
|
||||
struct RecordEntry {
|
||||
u32 length;
|
||||
char16 filename[length];
|
||||
|
||||
|
||||
char id[4];
|
||||
// either blob or length
|
||||
char type[4];
|
||||
|
||||
|
||||
if (type == "blob") {
|
||||
u32 blobCount;
|
||||
u8 blobData[blobCount];
|
||||
@@ -67,15 +68,15 @@ struct BuddyBlock {
|
||||
u8 reserved[4];
|
||||
// padding for next multiple of 256 entries (1024 bytes)
|
||||
u32 addresses[blockCount];
|
||||
|
||||
|
||||
// u8 padding[paddingCount];
|
||||
u32 directoryCount;
|
||||
|
||||
|
||||
// directory entries
|
||||
u8 count;
|
||||
u8 name[count];
|
||||
u32 blockNumber;
|
||||
|
||||
|
||||
// free lists
|
||||
// 32 free lists
|
||||
BuddyRootBlockOffsets off[32];
|
||||
@@ -96,7 +97,7 @@ struct BuddyAllocator {
|
||||
u32 offsetBookkeeping2;
|
||||
u32 offsetData;
|
||||
u8 reserved[12];
|
||||
|
||||
|
||||
BuddyRootBlock root @ offsetBookkeeping + 4;
|
||||
|
||||
std::print("TOC {} address 0x{:08x}",
|
||||
@@ -104,7 +105,7 @@ struct BuddyAllocator {
|
||||
root.offsets.addresses[root.toc.toc[0].value] >> 0x5 << 0x5);
|
||||
|
||||
BlocksList blocks @ (root.offsets.addresses[root.toc.toc[0].value] >> 0x5 << 0x5) + 4;
|
||||
|
||||
|
||||
std::print("Blocks start at address 0x{:08x}, size 0x{:04x}",
|
||||
root.offsets.addresses[blocks.blockId] >> 0x5 << 0x5,
|
||||
1 << (root.offsets.addresses[blocks.blockId] & 0x1f));
|
||||
|
||||
@@ -1,17 +1,19 @@
|
||||
#pragma description Digital Terrain Elevation Data
|
||||
#pragma endian big
|
||||
|
||||
#pragma magic [ 4C 48 55 ] @ 0x00
|
||||
|
||||
import std.core;
|
||||
import std.io;
|
||||
import std.mem;
|
||||
import std.string;
|
||||
|
||||
|
||||
enum Magic:u24 {
|
||||
enum Magic:u24 {
|
||||
UHL = 0x55484C,
|
||||
DSI = 0x445349,
|
||||
ACC = 0x414343,
|
||||
};
|
||||
};
|
||||
|
||||
struct UHL {
|
||||
Magic magic;
|
||||
@@ -95,7 +97,7 @@ struct ACC {
|
||||
ACCSub subs[9];
|
||||
char reserved4[18];
|
||||
char reserved5[69];
|
||||
|
||||
|
||||
};
|
||||
|
||||
struct DataRecords {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#pragma author WerWolv
|
||||
#pragma description ELF header in elf binaries
|
||||
#pragma description Executable and Linkable Format executable (ELF)
|
||||
|
||||
#pragma MIME application/x-executable
|
||||
#pragma MIME application/x-elf
|
||||
@@ -10,6 +10,7 @@
|
||||
import std.core;
|
||||
import std.io;
|
||||
import std.mem;
|
||||
import type.magic;
|
||||
|
||||
using BitfieldOrder = std::core::BitfieldOrder;
|
||||
|
||||
@@ -496,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;
|
||||
@@ -515,7 +517,7 @@ bitfield PF {
|
||||
};
|
||||
|
||||
struct E_IDENT {
|
||||
char EI_MAG[4];
|
||||
type::Magic<"\x7fELF"> EI_MAG;
|
||||
EI_CLASS EI_CLASS;
|
||||
EI_DATA EI_DATA;
|
||||
EI_VERSION EI_VERSION;
|
||||
@@ -565,7 +567,7 @@ struct Elf32_Phdr {
|
||||
Elf32_Word p_memsz;
|
||||
PF p_flags;
|
||||
Elf32_Word p_align;
|
||||
|
||||
|
||||
if (p_offset >= 0 && p_filesz > 0 && (p_offset + p_filesz) <= std::mem::size() && p_filesz <= std::mem::size())
|
||||
u8 p_data[p_filesz] @ p_offset [[sealed]];
|
||||
};
|
||||
@@ -579,7 +581,7 @@ struct Elf64_Phdr {
|
||||
Elf64_Xword p_filesz;
|
||||
Elf64_Xword p_memsz;
|
||||
Elf64_Xword p_align;
|
||||
|
||||
|
||||
if (p_offset >= 0 && p_filesz > 0 && (p_offset + p_filesz) <= std::mem::size() && p_filesz <= std::mem::size())
|
||||
u8 p_data[p_filesz] @ p_offset [[sealed]];
|
||||
};
|
||||
@@ -636,22 +638,25 @@ struct Elf32_Shdr {
|
||||
Elf32_Word sh_info;
|
||||
Elf32_Word sh_addralign;
|
||||
Elf32_Word sh_entsize;
|
||||
|
||||
|
||||
if (sh_size > 0 && sh_offset + sh_size < std::mem::size()) {
|
||||
if (sh_type == SHT::NOBITS || sh_type == SHT::NULL) {
|
||||
// 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 {
|
||||
u8 data[sh_size] @ sh_offset [[sealed]];
|
||||
}
|
||||
}
|
||||
} [[format("format_section_header")]];;
|
||||
} [[format("format_section_header")]];
|
||||
|
||||
struct Elf64_Chdr {
|
||||
u32 ch_type;
|
||||
@@ -696,15 +701,18 @@ struct Elf64_Shdr {
|
||||
Elf64_Word sh_info;
|
||||
Elf64_Xword sh_addralign;
|
||||
Elf64_Xword sh_entsize;
|
||||
|
||||
|
||||
if (sh_size > 0 && sh_offset + sh_size < std::mem::size()) {
|
||||
if (sh_type == SHT::NOBITS || sh_type == SHT::NULL) {
|
||||
// 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 {
|
||||
@@ -715,7 +723,7 @@ struct Elf64_Shdr {
|
||||
|
||||
fn format_section_header(auto shdr) {
|
||||
u32 i = 0;
|
||||
|
||||
|
||||
u32 nameAddress = addressof(elf.shdr[stringTableIndex].stringTable) + shdr.sh_name;
|
||||
String string @ nameAddress;
|
||||
|
||||
@@ -725,25 +733,32 @@ fn format_section_header(auto shdr) {
|
||||
|
||||
struct ELF {
|
||||
E_IDENT e_ident;
|
||||
|
||||
|
||||
if (e_ident.EI_DATA == EI_DATA::ELFDATA2LSB)
|
||||
std::core::set_endian(std::mem::Endian::Little);
|
||||
else
|
||||
std::core::set_endian(std::mem::Endian::Big);
|
||||
|
||||
|
||||
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(
|
||||
|
||||
@@ -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] @ $;
|
||||
|
||||
193
patterns/fbx.hexpat
Normal file
193
patterns/fbx.hexpat
Normal file
@@ -0,0 +1,193 @@
|
||||
#pragma description Kaydara FBX Binary
|
||||
#pragma magic [4B 61 79 64 61 72 61 20 46 42 58 20 42 69 6E 61 72 79 20 20 00 1A 00] @ 0x00
|
||||
|
||||
/*
|
||||
* Based on Blenders implementation of FBX import/export, see:
|
||||
* (incomplete) https://code.blender.org/2013/08/fbx-binary-file-format-specification/
|
||||
* https://projects.blender.org/blender/blender/src/branch/main/scripts/addons_core/io_scene_fbx/parse_fbx.py
|
||||
* https://projects.blender.org/blender/blender/src/branch/main/scripts/addons_core/io_scene_fbx/encode_bin.py
|
||||
*/
|
||||
|
||||
#pragma endian little
|
||||
|
||||
#ifdef __IMHEX__
|
||||
import hex.dec;
|
||||
#endif
|
||||
|
||||
import std.mem;
|
||||
import std.string;
|
||||
import std.sys;
|
||||
import type.magic;
|
||||
|
||||
struct Array<E> {
|
||||
u32 arrayLength;
|
||||
u32 encoding;
|
||||
u32 compressedLength;
|
||||
|
||||
std::assert(encoding < 2, "Invalid array encoding!");
|
||||
|
||||
if (encoding == 0) {
|
||||
// Uncompressed
|
||||
E contents[arrayLength];
|
||||
} else {
|
||||
// Compressed (zlib)
|
||||
u128 pos = $;
|
||||
u8 compressedContents[compressedLength];
|
||||
|
||||
#ifdef __IMHEX__
|
||||
std::mem::Section contentsSection = std::mem::create_section(std::format("contentsSection @ {:#x}", pos));
|
||||
hex::dec::zlib_decompress(compressedContents, contentsSection, 15);
|
||||
auto contentsSectionSize = std::mem::get_section_size(contentsSection);
|
||||
auto contentsElementSize = sizeof(E);
|
||||
std::assert_warn((contentsSectionSize % contentsElementSize) == 0,
|
||||
"The size of the contentsSection must be an integer multiple of sizeof(E) !");
|
||||
E contents[contentsSectionSize / contentsElementSize] @ 0x00 in contentsSection;
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
enum PropertyTypeCode : char {
|
||||
BYTE = 'Z',
|
||||
SHORT = 'Y',
|
||||
BOOL = 'B',
|
||||
CHAR = 'C',
|
||||
INT = 'I',
|
||||
FLOAT = 'F',
|
||||
DOUBLE = 'D',
|
||||
LONG = 'L',
|
||||
BINARY = 'R',
|
||||
STRING = 'S',
|
||||
ARRAY_BOOL = 'b',
|
||||
ARRAY_UBYTE = 'c',
|
||||
ARRAY_INT = 'i',
|
||||
ARRAY_LONG = 'l',
|
||||
ARRAY_FLOAT = 'f',
|
||||
ARRAY_DOUBLE = 'd'
|
||||
};
|
||||
|
||||
struct PropertyRecord {
|
||||
PropertyTypeCode typeCode;
|
||||
|
||||
match (typeCode) {
|
||||
(PropertyTypeCode::BYTE): s8 data;
|
||||
(PropertyTypeCode::SHORT): s16 data;
|
||||
(PropertyTypeCode::BOOL): bool data;
|
||||
(PropertyTypeCode::CHAR): char data;
|
||||
(PropertyTypeCode::INT): s32 data;
|
||||
(PropertyTypeCode::FLOAT): float data;
|
||||
(PropertyTypeCode::DOUBLE): double data;
|
||||
(PropertyTypeCode::LONG): s64 data;
|
||||
(PropertyTypeCode::BINARY): {
|
||||
u32 dataLength;
|
||||
u8 data[dataLength];
|
||||
}
|
||||
(PropertyTypeCode::STRING): {
|
||||
u32 stringLength;
|
||||
char string[stringLength];
|
||||
}
|
||||
(PropertyTypeCode::ARRAY_BOOL): Array<bool> data;
|
||||
(PropertyTypeCode::ARRAY_UBYTE): Array<u8> data;
|
||||
(PropertyTypeCode::ARRAY_INT): Array<s32> data;
|
||||
(PropertyTypeCode::ARRAY_LONG): Array<s64> data;
|
||||
(PropertyTypeCode::ARRAY_FLOAT): Array<float> data;
|
||||
(PropertyTypeCode::ARRAY_DOUBLE): Array<double> data;
|
||||
(_): std::error("Invalid property type code!");
|
||||
}
|
||||
};
|
||||
|
||||
struct NodeRecord32 {
|
||||
u32 endOffset;
|
||||
u32 numProperties;
|
||||
u32 propertyListLen;
|
||||
u8 nameLen;
|
||||
|
||||
// Detect sentinel record which marks the end of a list of node records
|
||||
if (endOffset == 0
|
||||
&& numProperties == 0
|
||||
&& propertyListLen == 0
|
||||
&& nameLen == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
char name[nameLen];
|
||||
auto posBeforePropertyRecords = $;
|
||||
auto posAfterPropertyRecords = posBeforePropertyRecords + propertyListLen;
|
||||
PropertyRecord propertyRecords[numProperties];
|
||||
std::assert($ == posAfterPropertyRecords, std::format("Invalid size of propertyRecords @ {:#x} !", posBeforePropertyRecords));
|
||||
NodeRecord32 nestedList[while($ < endOffset)];
|
||||
std::assert($ == endOffset, std::format("Invalid size of nestedList @ {:#x} !", posAfterPropertyRecords));
|
||||
};
|
||||
|
||||
struct NodeRecord64 {
|
||||
u64 endOffset;
|
||||
u64 numProperties;
|
||||
u64 propertyListLen;
|
||||
u8 nameLen;
|
||||
|
||||
// Detect sentinel record which marks the end of a list of node records
|
||||
if (endOffset == 0
|
||||
&& numProperties == 0
|
||||
&& propertyListLen == 0
|
||||
&& nameLen == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
char name[nameLen];
|
||||
auto posBeforePropertyRecords = $;
|
||||
auto posAfterPropertyRecords = posBeforePropertyRecords + propertyListLen;
|
||||
PropertyRecord propertyRecords[numProperties];
|
||||
std::assert($ == posAfterPropertyRecords, std::format("Invalid size of propertyRecords @ {:#x} !", posBeforePropertyRecords));
|
||||
NodeRecord64 nestedList[while($ < endOffset)];
|
||||
std::assert($ == endOffset, std::format("Invalid size of nestedList @ {:#x} !", posAfterPropertyRecords));
|
||||
};
|
||||
|
||||
fn assertZero (auto array, u128 size, auto message) {
|
||||
bool nonzeroPadding = false;
|
||||
|
||||
for (u8 i = 0, i < size, i = i + 1) {
|
||||
if (array[i] != 0) {
|
||||
nonzeroPadding = true;
|
||||
}
|
||||
}
|
||||
|
||||
std::assert_warn(!nonzeroPadding, message);
|
||||
};
|
||||
|
||||
struct Footer {
|
||||
type::Magic<"\xFA\xBC\xAB\x09\xD0\xC8\xD4\x66\xB1\x76\xFB\x83\x1C\xF7\x26\x7E"> footerId;
|
||||
char zeroes[4];
|
||||
assertZero(zeroes, 4, "Found non-zero values in footer after footerId!");
|
||||
u128 ofs = $;
|
||||
u8 alignmentPaddingSize = ((ofs + 15) & ~15) - ofs;
|
||||
|
||||
if (alignmentPaddingSize == 0) {
|
||||
alignmentPaddingSize = 16;
|
||||
}
|
||||
|
||||
char alignmentPadding[alignmentPaddingSize];
|
||||
assertZero(alignmentPadding, alignmentPaddingSize, "Found non-zero bytes in alignmentPadding!");
|
||||
u32 version;
|
||||
char staticPadding[120];
|
||||
assertZero(staticPadding, 120, "Found non-zero bytes in staticPadding!");
|
||||
type::Magic<"\xF8\x5A\x8C\x6A\xDE\xF5\xD9\x7E\xEC\xE9\x0C\xE3\x75\x8F\x29\x0B"> footerMagic;
|
||||
};
|
||||
|
||||
struct Header {
|
||||
type::Magic<"Kaydara FBX Binary \x00\x1A\x00"> magic;
|
||||
u32 version;
|
||||
};
|
||||
|
||||
struct FBX {
|
||||
Header header;
|
||||
|
||||
if (header.version < 7500) {
|
||||
NodeRecord32 rootRecords[while(true)];
|
||||
} else {
|
||||
NodeRecord64 rootRecords[while(true)];
|
||||
}
|
||||
|
||||
Footer footer;
|
||||
std::assert_warn(header.version == footer.version, "Version numbers in header and footer do not match!");
|
||||
};
|
||||
|
||||
FBX fbx @ 0x00;
|
||||
@@ -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;
|
||||
@@ -22,7 +23,7 @@ enum BLOCK_TYPE : u8 {
|
||||
VORBIS_COMMENT = 4,
|
||||
CUESHEET = 5,
|
||||
PICTURE = 6,
|
||||
|
||||
|
||||
INVALID = 127
|
||||
};
|
||||
|
||||
@@ -48,7 +49,7 @@ struct METADATA_BLOCK_STREAMINFO {
|
||||
u24 minFrameSize, maxFrameSize;
|
||||
STREAMINFO_FLAGS flags;
|
||||
u128 md5Signature;
|
||||
|
||||
|
||||
bitsPerSample = flags.bitsPerSample;
|
||||
};
|
||||
|
||||
@@ -79,7 +80,7 @@ struct VORBIS_USER_COMMENT {
|
||||
struct METADATA_BLOCK_VORBIS_COMMENT {
|
||||
le u32 vendorLength;
|
||||
u8 vendor[vendorLength];
|
||||
|
||||
|
||||
le u32 userCommentListLength;
|
||||
VORBIS_USER_COMMENT userCommentList[userCommentListLength];
|
||||
};
|
||||
@@ -168,24 +169,24 @@ bitfield FRAME_HEADER_FLAGS {
|
||||
|
||||
struct FRAME_HEADER {
|
||||
FRAME_HEADER_FLAGS flags;
|
||||
|
||||
|
||||
sampleSize = flags.sampleSize;
|
||||
|
||||
|
||||
if (flags.blockingStrategy)
|
||||
char16 sampleNumber[7];
|
||||
else
|
||||
char16 frameNumber[6];
|
||||
|
||||
|
||||
if (flags.blockSize == 0b0110)
|
||||
u8 blockSize;
|
||||
else if (flags.blockSize == 0b0111)
|
||||
u16 blockSize;
|
||||
|
||||
|
||||
if (flags.sampleRate == 0b1100)
|
||||
u8 sampleRate;
|
||||
else if (flags.sampleRate == 0b1101 || flags.sampleRate == 0b1110)
|
||||
u16 sampleRate;
|
||||
|
||||
|
||||
u8 crc8;
|
||||
};
|
||||
|
||||
@@ -248,8 +249,8 @@ struct RESIDUAL {
|
||||
RESIDUAL_CODING_METHOD_PARTITIONED_RICE rice;
|
||||
else if (parent.value.codingMethod == 0b01)
|
||||
RESIDUAL_CODING_METHOD_PARTITIONED_RICE2 rice;
|
||||
|
||||
|
||||
|
||||
|
||||
if ((parent.parent.header.type & 0b111) == 0b000)
|
||||
u8 samples[(getBitsPerSample() * (parent.parent.parent.header.flags.blockSize - (parent.parent.header.type & 0b111))) / 8];
|
||||
else if (std::core::array_index() != 0)
|
||||
@@ -278,7 +279,7 @@ struct SUBFRAME_LPC {
|
||||
|
||||
struct SUBFRAME {
|
||||
SUBFRAME_HEADER header;
|
||||
|
||||
|
||||
if (header.type == 0b00000)
|
||||
SUBFRAME_CONSTANT constant;
|
||||
else if (header.type == 0b000001)
|
||||
@@ -300,7 +301,7 @@ struct METADATA_BLOCK {
|
||||
METADATA_BLOCK_HEADER header;
|
||||
if (header.lastMetadataBlock)
|
||||
break;
|
||||
|
||||
|
||||
if (header.blockType == BLOCK_TYPE::STREAMINFO)
|
||||
METADATA_BLOCK_STREAMINFO data;
|
||||
else if (header.blockType == BLOCK_TYPE::PADDING)
|
||||
|
||||
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())] @ $;
|
||||
258
patterns/flipper_settings.hexpat
Normal file
258
patterns/flipper_settings.hexpat
Normal file
@@ -0,0 +1,258 @@
|
||||
/*!
|
||||
This pattern can be used to parse Flipper Zero settings.
|
||||
It supports SavedStructure based settings and Notification settings.
|
||||
*/
|
||||
|
||||
#pragma author Jan Wiesemann
|
||||
#pragma description Flipper Zero Settings
|
||||
|
||||
/**
|
||||
Infrared
|
||||
@source https://github.com/flipperdevices/flipperzero-firmware/blob/a403e5f543a5423e39ac1700ae4711e9e489445e/applications/main/infrared/infrared_app.c#L17
|
||||
*/
|
||||
#define MAGIC_IR 0x1F
|
||||
|
||||
/**
|
||||
Expansion/UART
|
||||
@source https://github.com/flipperdevices/flipperzero-firmware/blob/a403e5f543a5423e39ac1700ae4711e9e489445e/applications/services/expansion/expansion_settings.c#L10
|
||||
*/
|
||||
#define MAGIC_UART 0xEA
|
||||
|
||||
/**
|
||||
Bluetooth
|
||||
@source https://github.com/flipperdevices/flipperzero-firmware/blob/a403e5f543a5423e39ac1700ae4711e9e489445e/applications/services/bt/bt_settings.c#L9
|
||||
*/
|
||||
#define MAGIC_BT 0x19
|
||||
|
||||
/**
|
||||
Dolphin
|
||||
@source https://github.com/DarkFlippers/unleashed-firmware/blob/b2305ce5c7a6ab36babc30243a589eccfa9edcb6/applications/services/dolphin/helpers/dolphin_state.c#L14
|
||||
*/
|
||||
#define MAGIC_DOLPHIN 0xD0
|
||||
|
||||
/**
|
||||
Desktop
|
||||
@source https://github.com/flipperdevices/flipperzero-firmware/blob/a403e5f543a5423e39ac1700ae4711e9e489445e/applications/services/desktop/desktop_settings.h#L14
|
||||
*/
|
||||
#define MAGIC_DEKTOP 0x17
|
||||
|
||||
/* ======= Common structures =======
|
||||
|
||||
Flipper datatype aliases
|
||||
They are added for easyer translatiom from the Flipper soruce into ImHex
|
||||
*/
|
||||
using int8_t = u8;
|
||||
using uint8_t = u8;
|
||||
|
||||
using int16_t = u16;
|
||||
using uint16_t = u16;
|
||||
|
||||
using int32_t = s32;
|
||||
using uint32_t = u32;
|
||||
|
||||
using int64_t = s64;
|
||||
using uint64_t = u64;
|
||||
|
||||
/* ======= Common structures ======= */
|
||||
|
||||
/**
|
||||
Header for a saved structure file
|
||||
@source https://github.com/flipperdevices/flipperzero-firmware/blob/a403e5f543a5423e39ac1700ae4711e9e489445e/lib/toolbox/saved_struct.c#L14
|
||||
*/
|
||||
struct SavedStructHeader {
|
||||
uint8_t magic;
|
||||
uint8_t version;
|
||||
uint8_t checksum; //Sum of data-bytes
|
||||
uint8_t flags; //Not used always 0
|
||||
uint32_t timestamp; //Not used alwas 0
|
||||
};
|
||||
|
||||
/* ======= Infrared settings '.infrared.settings' ======= */
|
||||
|
||||
/*
|
||||
Lists all avalible outputs for the Infrared appication
|
||||
@source https://github.com/flipperdevices/flipperzero-firmware/blob/a403e5f543a5423e39ac1700ae4711e9e489445e/targets/furi_hal_include/furi_hal_infrared.h#L23
|
||||
*/
|
||||
enum FuriHalInfraredTxPin : uint8_t {
|
||||
FuriHalInfraredTxPinInternal,
|
||||
FuriHalInfraredTxPinExtPA7,
|
||||
FuriHalInfraredTxPinMax
|
||||
};
|
||||
|
||||
/*
|
||||
Infrared Settings
|
||||
@source https://github.com/flipperdevices/flipperzero-firmware/blob/a403e5f543a5423e39ac1700ae4711e9e489445e/applications/main/infrared/infrared_app.c#L22
|
||||
*/
|
||||
struct InfraredSettings {
|
||||
FuriHalInfraredTxPin tx_pin;
|
||||
bool otg_enabled;
|
||||
};
|
||||
|
||||
/* ======= Expansion settings '.expansion.settings' ======= */
|
||||
|
||||
/**
|
||||
???
|
||||
@source https://github.com/flipperdevices/flipperzero-firmware/blob/a403e5f543a5423e39ac1700ae4711e9e489445e/applications/services/expansion/expansion_settings.h#L23
|
||||
*/
|
||||
struct ExpansionSettings {
|
||||
uint8_t uart_index;
|
||||
};
|
||||
|
||||
/* ======= Bluetooth settings '.bt.settings' ======= */
|
||||
|
||||
/**
|
||||
Bluetooth Settings
|
||||
@source https://github.com/flipperdevices/flipperzero-firmware/blob/a403e5f543a5423e39ac1700ae4711e9e489445e/applications/services/bt/bt_settings.h#L14
|
||||
*/
|
||||
struct BtSettings {
|
||||
bool enabled;
|
||||
};
|
||||
|
||||
/* ======= Dolphin state '.dolphin.state' ======= */
|
||||
|
||||
/**
|
||||
Lists all avalible Apps, that grand you points
|
||||
@source https://github.com/flipperdevices/flipperzero-firmware/blob/a403e5f543a5423e39ac1700ae4711e9e489445e/applications/services/dolphin/helpers/dolphin_deed.h#L18
|
||||
*/
|
||||
enum DolphinApp : uint16_t {
|
||||
DolphinAppSubGhz,
|
||||
DolphinAppRfid,
|
||||
DolphinAppNfc,
|
||||
DolphinAppIr,
|
||||
DolphinAppIbutton,
|
||||
DolphinAppBadusb,
|
||||
DolphinAppPlugin,
|
||||
DolphinAppMAX
|
||||
};
|
||||
|
||||
/**
|
||||
States for the Dolphin
|
||||
@source https://github.com/flipperdevices/flipperzero-firmware/blob/a403e5f543a5423e39ac1700ae4711e9e489445e/applications/services/dolphin/helpers/dolphin_state.h#L17
|
||||
*/
|
||||
struct DolphinStoreData{
|
||||
uint8_t icounter_daily_limit[DolphinApp::DolphinAppMAX];
|
||||
uint8_t butthurt_daily_limit;
|
||||
uint32_t flags; // Not used always 0
|
||||
uint32_t icounter;
|
||||
int32_t butthurt;
|
||||
uint64_t timestamp;
|
||||
padding[4];
|
||||
};
|
||||
|
||||
/* ======= Desktop settings '.dektop.settings' ======= */
|
||||
|
||||
#define MAX_PIN_SIZE 10
|
||||
#define MIN_PIN_SIZE 4
|
||||
#define MAX_APP_LENGTH 128
|
||||
|
||||
/**
|
||||
Represents a Input Key
|
||||
@source https://github.com/flipperdevices/flipperzero-firmware/blob/a403e5f543a5423e39ac1700ae4711e9e489445e/targets/f7/furi_hal/furi_hal_resources.h#L22
|
||||
*/
|
||||
enum InputKey : uint8_t{
|
||||
InputKeyUp,
|
||||
InputKeyDown,
|
||||
InputKeyRight,
|
||||
InputKeyLeft,
|
||||
InputKeyOk,
|
||||
InputKeyBack,
|
||||
InputKeyMAX, /**< Special value */
|
||||
};
|
||||
|
||||
/**
|
||||
Stores the Pin-Code
|
||||
@source https://github.com/flipperdevices/flipperzero-firmware/blob/a403e5f543a5423e39ac1700ae4711e9e489445e/applications/services/desktop/desktop_settings.h#L58
|
||||
*/
|
||||
struct PinCode{
|
||||
InputKey data[MAX_PIN_SIZE];
|
||||
uint8_t length;
|
||||
};
|
||||
|
||||
/**
|
||||
Possible buttons for the Shortcut menu
|
||||
@source https://github.com/flipperdevices/flipperzero-firmware/blob/a403e5f543a5423e39ac1700ae4711e9e489445e/applications/services/desktop/desktop_settings.h#L45
|
||||
*/
|
||||
enum FavoriteAppShortcut : uint32_t {
|
||||
FavoriteAppLeftShort,
|
||||
FavoriteAppLeftLong,
|
||||
FavoriteAppRightShort,
|
||||
FavoriteAppRightLong,
|
||||
FavoriteAppNumber
|
||||
};
|
||||
/**
|
||||
Possible buttons for the Shortcut menu while using the dummy mode
|
||||
@source https://github.com/flipperdevices/flipperzero-firmware/blob/a403e5f543a5423e39ac1700ae4711e9e489445e/applications/services/desktop/desktop_settings.h#L53
|
||||
*/
|
||||
enum DummyAppShortcut : uint32_t{
|
||||
DummyAppLeft = 0,
|
||||
DummyAppRight,
|
||||
DummyAppDown,
|
||||
DummyAppOk,
|
||||
DummyAppNumber,
|
||||
};
|
||||
|
||||
/**
|
||||
Path or Appname for a Shortcut
|
||||
@source https://github.com/flipperdevices/flipperzero-firmware/blob/a403e5f543a5423e39ac1700ae4711e9e489445e/applications/services/desktop/desktop_settings.h#L62
|
||||
*/
|
||||
struct FavoriteApp {
|
||||
char name_or_path[MAX_APP_LENGTH];
|
||||
};
|
||||
/**
|
||||
Settings for the Desktop
|
||||
@source https://github.com/flipperdevices/flipperzero-firmware/blob/a403e5f543a5423e39ac1700ae4711e9e489445e/applications/services/desktop/desktop_settings.h#L71
|
||||
*/
|
||||
struct DesktopSettings {
|
||||
PinCode pin_code;
|
||||
padding[1];
|
||||
uint32_t auto_lock_delay_ms;
|
||||
uint8_t dummy_mode;
|
||||
uint8_t display_clock;
|
||||
FavoriteApp favorite_apps[FavoriteAppShortcut::FavoriteAppNumber];
|
||||
FavoriteApp dummy_apps[DummyAppShortcut::DummyAppNumber];
|
||||
padding[2];
|
||||
};
|
||||
|
||||
/* ======= Helper======= */
|
||||
|
||||
/**
|
||||
Container for SavedStruct based settings
|
||||
*/
|
||||
struct SavedStructure {
|
||||
SavedStructHeader header;
|
||||
|
||||
match(header.magic, sizeof($) - sizeof(SavedStructHeader)) {
|
||||
(MAGIC_IR, sizeof(InfraredSettings)): InfraredSettings infraredSettings;
|
||||
(MAGIC_UART, sizeof(ExpansionSettings)): ExpansionSettings expansionSettings;
|
||||
(MAGIC_BT, sizeof(BtSettings)): BtSettings btSettings;
|
||||
(MAGIC_DOLPHIN, sizeof(DolphinStoreData)): DolphinStoreData dolphinStoreData;
|
||||
(MAGIC_DEKTOP, sizeof(DesktopSettings)): DesktopSettings desktopSettings;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
Settings for the LCD and Notifications
|
||||
@source https://github.com/flipperdevices/flipperzero-firmware/blob/a403e5f543a5423e39ac1700ae4711e9e489445e/applications/services/notification/notification_app.h#L46
|
||||
*/
|
||||
struct NotificationSettings {
|
||||
uint8_t version;
|
||||
padding[3];
|
||||
float display_brightness;
|
||||
float led_brightness;
|
||||
float speaker_volume;
|
||||
uint32_t display_off_delay_ms;
|
||||
int8_t contrast;
|
||||
bool vibro_on;
|
||||
padding[2];
|
||||
};
|
||||
|
||||
/**
|
||||
Wrapper for SavedStructure or Notificaition settings
|
||||
*/
|
||||
struct FlipperSettings {
|
||||
if(sizeof($) == sizeof(NotificationSettings))
|
||||
NotificationSettings notificationSettings;
|
||||
else
|
||||
SavedStructure savedStructure;
|
||||
};
|
||||
FlipperSettings flipperSettings @ 0x00;
|
||||
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,7 +1,9 @@
|
||||
#pragma author WerWolv
|
||||
#pragma description Drive File System
|
||||
#pragma MIME application/x-ima
|
||||
|
||||
import std.io;
|
||||
import std.core;
|
||||
|
||||
struct DiskTimeStamp {
|
||||
u8 seconds, minutes, hours;
|
||||
@@ -46,25 +48,25 @@ namespace fat32 {
|
||||
padding[12];
|
||||
u32 trailSignature;
|
||||
};
|
||||
|
||||
|
||||
bitfield SequenceNumber {
|
||||
padding : 1;
|
||||
lastLogical : 1;
|
||||
padding : 1;
|
||||
number : 5;
|
||||
} [[bitfield_order(BitfieldOrder::MostToLeastSignificant, 8)]];
|
||||
|
||||
} [[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;
|
||||
@@ -73,8 +75,8 @@ namespace fat32 {
|
||||
subdirectory : 1;
|
||||
archive : 1;
|
||||
padding : 2;
|
||||
} [[bitfield_order(BitfieldOrder::LeastToMostSignificant, 8)]];
|
||||
|
||||
} [[bitfield_order(std::core::BitfieldOrder::LeastToMostSignificant, 8)]];
|
||||
|
||||
struct DirEntry {
|
||||
char fileName[8];
|
||||
char extension[3];
|
||||
@@ -83,10 +85,10 @@ namespace fat32 {
|
||||
u16 time, date;
|
||||
u16 startingCluster;
|
||||
u32 fileSize;
|
||||
|
||||
|
||||
u8 data[fileSize] @ startingCluster * bytesPerCluster;
|
||||
};
|
||||
|
||||
|
||||
struct VFATDirEntry {
|
||||
EntryStatusOrSequenceNumber entryStatusOrSequenceNumber;
|
||||
char16 name1[5];
|
||||
@@ -96,7 +98,7 @@ namespace fat32 {
|
||||
char16 name2[6];
|
||||
u16 startingCluster;
|
||||
char16 name3[2];
|
||||
|
||||
|
||||
if (entryStatusOrSequenceNumber.sequenceNumber.number > 1)
|
||||
VFATDirEntry nextLogicalEntry;
|
||||
else
|
||||
@@ -133,9 +135,9 @@ namespace fat32 {
|
||||
char fsType[8];
|
||||
u8 bootstrapCode[420];
|
||||
u16 signature;
|
||||
|
||||
|
||||
bytesPerCluster = (sectorsPerCluster * 1024) * bytesPerSector;
|
||||
|
||||
|
||||
FSInfo fsInfo @ addressof(this) + fsInfoSector * bytesPerSector;
|
||||
VFATDirEntry rootDirEntry @ addressof(this) + rootCluster * bytesPerCluster;
|
||||
};
|
||||
@@ -143,13 +145,13 @@ namespace fat32 {
|
||||
}
|
||||
|
||||
struct PartitionEntry {
|
||||
PartitionStatus status;
|
||||
PartitionStatus status;
|
||||
CHS chsFirstSectorAddress;
|
||||
PartitionType type;
|
||||
CHS chsLastSectorAddress;
|
||||
u32 lbaFirstSectorAddress;
|
||||
u32 numSectors;
|
||||
|
||||
|
||||
if (type == PartitionType::EmptyPartitionEntry)
|
||||
continue;
|
||||
else if (type == PartitionType::FAT32_CHS || type == PartitionType::FAT32_LBA)
|
||||
|
||||
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;
|
||||
543
patterns/fs/ext4.hexpat
Normal file
543
patterns/fs/ext4.hexpat
Normal file
@@ -0,0 +1,543 @@
|
||||
#pragma author endes
|
||||
#pragma description ext4 volume layout parser (until inodes)
|
||||
|
||||
// Decodes the ext4 superblock, group descriptors and inodes.
|
||||
// Does not decode the directory entries, inode data, jornal or superblock backups.
|
||||
// Heavily based on the linux kernel documentation:
|
||||
// https://www.kernel.org/doc/html/latest/filesystems/ext4/
|
||||
|
||||
#pragma endian little
|
||||
#pragma magic [53 EF] @ 0x438
|
||||
#pragma pattern_limit 0x90000
|
||||
|
||||
import type.time;
|
||||
import type.size;
|
||||
import type.magic;
|
||||
import std.core;
|
||||
import std.mem;
|
||||
import std.math;
|
||||
|
||||
|
||||
enum ext4_super_state : u16 {
|
||||
Cleanlyumounted = 0x01,
|
||||
Errorsdetected = 0x02,
|
||||
Orphansbeingrecovered = 0x03
|
||||
};
|
||||
|
||||
enum ext4_super_errors : u16 {
|
||||
Continue = 0x01,
|
||||
RemountReadOnly = 0x02,
|
||||
Panic = 0x03
|
||||
};
|
||||
|
||||
enum ext4_super_creator : u32 {
|
||||
Linux = 0x00,
|
||||
Hurd = 0x01,
|
||||
Masix = 0x02,
|
||||
FreeBSD = 0x03,
|
||||
Lites = 0x04
|
||||
};
|
||||
|
||||
enum ext4_super_revision : u32 {
|
||||
ORIGINAL = 0x00,
|
||||
V2_DYNAMIC_REV = 0x01
|
||||
};
|
||||
|
||||
bitfield ext4_super_compat {
|
||||
COMPAT_DIR_PREALLOC : 1 [[comment("Directory preallocation.")]];
|
||||
COMPAT_IMAGIC_INODES : 1 [[comment("“imagic inodes”. Not clear from the code what this does.")]];
|
||||
COMPAT_HAS_JOURNAL : 1 [[comment("Has a journal.")]];
|
||||
COMPAT_EXT_ATTR : 1 [[comment("Supports extended attributes.")]];
|
||||
COMPAT_RESIZE_INODE : 1 [[comment("Has reserved GDT blocks for filesystem expansion.")]];
|
||||
COMPAT_DIR_INDEX : 1 [[comment("Has directory indices.")]];
|
||||
COMPAT_LAZY_BG : 1 [[comment("“Lazy BG”. Not in Linux kernel, seems to have been for uninitialized block groups?.")]];
|
||||
COMPAT_EXCLUDE_INODE : 1 [[comment("“Exclude inode”. Not used.")]];
|
||||
COMPAT_EXCLUDE_BITMAP : 1 [[comment("“Exclude bitmap”. Seems to be used to indicate the presence of snapshot-related exclude bitmaps? Not defined in linux kernel or used in e2fsprogs.")]];
|
||||
COMPAT_SPARSE_SUPER2 : 1 [[comment("Sparse Super Block, v2. If this flag is set, the SB field s_backup_bgs points to the two block groups that contain backup superblocks.")]];
|
||||
COMPAT_FAST_COMMIT : 1 [[comment("Journal fast commits supported.")]];
|
||||
padding : 1;
|
||||
RO_COMPAT_ORPHAN_PRESENT : 1 [[comment("Orphan file allocated. This is the special file for more efficient tracking of unlinked but still open inodes.")]];
|
||||
};
|
||||
|
||||
bitfield ext4_super_incompat {
|
||||
INCOMPAT_COMPRESSION : 1;
|
||||
INCOMPAT_FILETYPE : 1 [[comment("Directory entries record the file type.")]];
|
||||
INCOMPAT_RECOVER : 1 [[comment("Filesystem needs recovery.")]];
|
||||
INCOMPAT_JOURNAL_DEV : 1 [[comment("Filesystem has a separate journal device.")]];
|
||||
INCOMPAT_META_BG : 1 [[comment("Meta block groups.")]];
|
||||
padding : 1;
|
||||
INCOMPAT_EXTENTS : 1 [[comment("Files in this filesystem use extents.")]];
|
||||
INCOMPAT_64BIT : 1 [[comment("Enable a filesystem size of 2^64 blocks.")]];
|
||||
INCOMPAT_MMP : 1 [[comment("Multiple mount protection.")]];
|
||||
INCOMPAT_FLEX_BG : 1 [[comment("Flexible block groups.")]];
|
||||
INCOMPAT_EA_INODE : 1 [[comment("Inodes can be used to store large extended attribute values.")]];
|
||||
padding : 1 [[comment("Data in directory entry.")]];
|
||||
INCOMPAT_DIRDATA : 1;
|
||||
INCOMPAT_CSUM_SEED : 1 [[comment("Metadata checksum seed is stored in the superblock.")]];
|
||||
INCOMPAT_LARGEDIR : 1 [[comment("Large directory >2GB or 3-level htree.")]];
|
||||
INCOMPAT_INLINE_DATA : 1 [[comment("Data in inode.")]];
|
||||
INCOMPAT_ENCRYPT : 1 [[comment("Encrypted inodes are present on the filesystem.")]];
|
||||
};
|
||||
|
||||
bitfield ext4_super_compat_ro {
|
||||
RO_COMPAT_SPARSE_SUPER : 1 [[comment("Sparse superblocks.")]];
|
||||
RO_COMPAT_LARGE_FILE : 1 [[comment("This filesystem has been used to store a file greater than 2GiB.")]];
|
||||
RO_COMPAT_BTREE_DIR : 1 [[comment("Not used in linux kernel or e2fsprogs.")]];
|
||||
RO_COMPAT_HUGE_FILE : 1 [[comment("This filesystem has files whose sizes are represented in units of logical blocks, not 512-byte sectors. This implies a very large file indeed!.")]];
|
||||
RO_COMPAT_GDT_CSUM : 1 [[comment("Group descriptors have checksums.")]];
|
||||
RO_COMPAT_DIR_NLINK : 1 [[comment("Indicates that the old ext3 32,000 subdirectory limit no longer applies.")]];
|
||||
RO_COMPAT_EXTRA_ISIZE : 1 [[comment("Indicates that large inodes exist on this filesystem.")]];
|
||||
RO_COMPAT_HAS_SNAPSHOT : 1 [[comment("This filesystem has a snapshot.")]];
|
||||
RO_COMPAT_QUOTA : 1;
|
||||
RO_COMPAT_BIGALLOC : 1 [[comment("This filesystem supports “bigalloc”, which means that file extents are tracked in units of clusters (of blocks) instead of blocks.")]];
|
||||
RO_COMPAT_METADATA_CSUM : 1 [[comment("This filesystem supports metadata checksumming.")]];
|
||||
RO_COMPAT_REPLICA : 1 [[comment("Filesystem supports replicas. This feature is neither in the kernel nor e2fsprogs.")]];
|
||||
RO_COMPAT_READONLY : 1 [[comment("Read-only filesystem image.")]];
|
||||
RO_COMPAT_PROJECT : 1 [[comment("Filesystem tracks project quotas.")]];
|
||||
padding : 1;
|
||||
RO_COMPAT_VERITY : 1 [[comment("Verity inodes may be present on the filesystem.")]];
|
||||
RO_COMPAT_ORPHAN_PRESENT : 1 [[comment("Indicates orphan file may have valid orphan entries and thus we need to clean them up when mounting the filesystem.")]];
|
||||
};
|
||||
|
||||
enum ext4_super_def_hash : u8 {
|
||||
LEGACY = 0x00,
|
||||
HALF_MD4 = 0x01,
|
||||
TEA = 0x02,
|
||||
LEGACY_UNSIGNED = 0x03,
|
||||
HALF_MD4_UNSIGNED = 0x04,
|
||||
TEA_UNSIGNED = 0x05
|
||||
};
|
||||
|
||||
bitfield ext4_super_mountopts {
|
||||
EXT4_DEFM_DEBUG : 1 [[comment("Print debugging info upon (re)mount.")]];
|
||||
EXT4_DEFM_BSDGROUPS : 1 [[comment("New files take the gid of the containing directory (instead of the fsgid of the current process).")]];
|
||||
EXT4_DEFM_XATTR_USER : 1 [[comment("Support userspace-provided extended attributes.")]];
|
||||
EXT4_DEFM_ACL : 1 [[comment("Support POSIX access control lists (ACLs).")]];
|
||||
EXT4_DEFM_UID16 : 1 [[comment("Do not support 32-bit UIDs.")]];
|
||||
EXT4_DEFM_JMODE_DATA : 1 [[comment("All data and metadata are committed to the journal.")]];
|
||||
EXT4_DEFM_JMODE_ORDER : 1 [[comment("All data are flushed to the disk before metadata are committed to the journal.")]];
|
||||
padding : 1;
|
||||
EXT4_DEFM_NOBARRIER : 1 [[comment("Disable write flushes.")]];
|
||||
EXT4_DEFM_BLOCK_VALIDITY : 1 [[comment("Track which blocks in a filesystem are metadata and therefore should not be used as data blocks.")]];
|
||||
EXT4_DEFM_DISCARD : 1 [[comment("Enable DISCARD support, where the storage device is told about blocks becoming unused.")]];
|
||||
EXT4_DEFM_NODELALLOC : 1 [[comment("Disable delayed allocation.")]];
|
||||
};
|
||||
|
||||
bitfield ext4_super_flags {
|
||||
SIGNED_HASH_DIRECTORY : 1;
|
||||
UNSIGNED_HASH_DIRECTORY : 1;
|
||||
TEST_DEV_CODE : 1;
|
||||
};
|
||||
|
||||
enum ext4_super_encrypt_algos : u8 {
|
||||
ENCRYPTION_MODE_INVALID = 0x00,
|
||||
ENCRYPTION_MODE_AES_256_XTS = 0x01,
|
||||
ENCRYPTION_MODE_AES_256_GCM = 0x02,
|
||||
ENCRYPTION_MODE_AES_256_CBC = 0x03,
|
||||
};
|
||||
|
||||
|
||||
struct ext4_super_block {
|
||||
u32 s_inodes_count [[comment("Total inode count.")]];
|
||||
u32 s_blocks_count_lo [[comment("Total block count.")]];
|
||||
u32 s_r_blocks_count_lo [[comment("This number of blocks can only be allocated by the super-user.")]];
|
||||
u32 s_free_blocks_count_lo [[comment("Free block count.")]];
|
||||
u32 s_free_inodes_count [[comment("Free inode count.")]];
|
||||
u32 s_first_data_block [[comment("First data block. This must be at least 1 for 1k-block filesystems and is typically 0 for all other block sizes.")]];
|
||||
u32 s_log_block_size;
|
||||
u32 s_log_cluster_size;
|
||||
u64 block_size = std::math::pow(2, 10+s_log_block_size);
|
||||
u64 cluster_size = std::math::pow(2, 10+s_log_cluster_size);
|
||||
u32 s_blocks_per_group [[comment("Blocks per group.")]];
|
||||
u32 s_clusters_per_group [[comment("Clusters per group, if bigalloc is enabled. Otherwise s_clusters_per_group must equal s_blocks_per_group.")]];
|
||||
u32 s_inodes_per_group [[comment("Inodes per group.")]];
|
||||
|
||||
type::time32_t s_mtime [[comment("Last mount time, in seconds since the epoch.")]];
|
||||
type::time32_t s_wtime [[comment("Last write time, in seconds since the epoch.")]];
|
||||
u16 s_mnt_count [[comment("Number of mounts since the last fsck.")]];
|
||||
u16 s_max_mnt_count [[comment("Number of mounts beyond which a fsck is needed.")]];
|
||||
|
||||
type::Magic<"\x53\xEF"> s_magic;
|
||||
|
||||
ext4_super_state s_state [[comment("File system state.")]];
|
||||
ext4_super_errors s_errors [[comment("Behaviour when detecting errors.")]];
|
||||
u16 s_minor_rev_level [[comment("Minor revision level.")]];
|
||||
type::time32_t s_lastcheck [[comment("Time of last check, in seconds since the epoch.")]];
|
||||
u32 s_checkinterval [[comment("Maximum time between checks, in seconds.")]];
|
||||
ext4_super_creator s_creator_os [[comment("Creator OS.")]];
|
||||
ext4_super_revision s_rev_level [[comment("Revision level.")]];
|
||||
|
||||
u16 s_def_resuid [[comment("Default uid for reserved blocks.")]];
|
||||
u16 s_def_resgid [[comment("Default gid for reserved blocks.")]];
|
||||
|
||||
// EXT2_DYNAMIC_REV superblock
|
||||
if (s_rev_level >= ext4_super_revision::V2_DYNAMIC_REV) {
|
||||
u32 s_first_ino [[comment("First non-reserved inode.")]];
|
||||
u16 s_inode_size [[comment("Size of inode structure, in bytes.")]];
|
||||
u16 s_block_group_nr [[comment("Block group number of this superblock.")]];
|
||||
|
||||
ext4_super_compat s_feature_compat [[comment("Compatible feature set flags. Kernel can still read/write this fs even if it doesn’t understand a flag; fsck should not do that.")]];
|
||||
padding[2];
|
||||
ext4_super_incompat s_feature_incompat [[comment("Incompatible feature set. If the kernel or fsck doesn’t understand one of these bits, it should stop.")]];
|
||||
padding[1];
|
||||
ext4_super_compat_ro s_feature_ro_compat [[comment("Readonly-compatible feature set. If the kernel doesn’t understand one of these bits, it can still mount read-only.")]];
|
||||
padding[1];
|
||||
|
||||
u8 s_uuid[16] [[comment("128-bit UUID for volume.")]];
|
||||
char s_volume_name[16] [[comment("Volume label.")]];
|
||||
char s_last_mounted[64] [[comment("Directory where filesystem was last mounted.")]];
|
||||
|
||||
if (s_feature_incompat.INCOMPAT_COMPRESSION) {
|
||||
u32 s_algorithm_usage_bitmap;
|
||||
} else {
|
||||
padding[4];
|
||||
}
|
||||
|
||||
// Performance hints
|
||||
if (s_feature_compat.COMPAT_DIR_PREALLOC) {
|
||||
u8 s_prealloc_blocks [[comment("Number of blocks to try to preallocate for ... files? (Not used in e2fsprogs/Linux).")]];
|
||||
u8 s_prealloc_dir_blocks [[comment("Number of blocks to preallocate for directories. (Not used in e2fsprogs/Linux).")]];
|
||||
} else {
|
||||
padding[2];
|
||||
}
|
||||
|
||||
u16 s_reserved_gdt_blocks [[comment("Number of reserved GDT entries for future filesystem expansion.")]];
|
||||
|
||||
// Journaling support
|
||||
if (s_feature_compat.COMPAT_HAS_JOURNAL) {
|
||||
u8 s_journal_uuid[16] [[comment("UUID of journal superblock.")]];
|
||||
u32 s_journal_inum [[comment("Inode number of journal file.")]];
|
||||
if (s_feature_incompat.INCOMPAT_JOURNAL_DEV) {
|
||||
u32 s_journal_dev [[comment("Device number of journal file.")]];
|
||||
} else {
|
||||
padding[4];
|
||||
}
|
||||
} else {
|
||||
padding[24];
|
||||
}
|
||||
|
||||
u32 s_last_orphan [[comment("Inode start of list of orphaned inodes to delete.")]];
|
||||
|
||||
u32 s_hash_seed[4] [[comment("HTREE hash seed.")]];
|
||||
ext4_super_def_hash s_def_hash_version [[comment("Default hash algorithm to use for directory hashes.")]];
|
||||
|
||||
u8 s_jnl_backup_type [[comment("If this value is 0 or EXT3_JNL_BACKUP_BLOCKS (1), then the s_jnl_blocks field contains a duplicate copy of the inode’s i_block[] array and i_size.")]];
|
||||
|
||||
if (s_feature_incompat.INCOMPAT_64BIT) {
|
||||
u16 s_desc_size [[comment("Size of group descriptors, in bytes, if the 64bit incompat feature flag is set.")]];
|
||||
} else {
|
||||
padding[2];
|
||||
}
|
||||
ext4_super_mountopts s_default_mount_opts [[comment("Default mount options.")]];
|
||||
padding[2];
|
||||
|
||||
if (s_feature_incompat.INCOMPAT_META_BG) {
|
||||
u32 s_first_meta_bg [[comment("First metablock block group, if the meta_bg feature is enabled.")]];
|
||||
} else {
|
||||
padding[4];
|
||||
}
|
||||
|
||||
type::time32_t s_mkfs_time [[comment("When the filesystem was created, in seconds since the epoch.")]];
|
||||
|
||||
u32 s_jnl_blocks[17] [[comment("Backup copy of the journal inode’s i_block[] array in the first 15 elements and i_size_high and i_size in the 16th and 17th elements, respectively.")]];
|
||||
|
||||
if (s_feature_incompat.INCOMPAT_64BIT) {
|
||||
u32 s_blocks_count_hi [[comment("High 32-bits of the block count.")]];
|
||||
u32 s_r_blocks_count_hi [[comment("High 32-bits of the reserved block count.")]];
|
||||
u32 s_free_blocks_count_hi [[comment("High 32-bits of the free block count.")]];
|
||||
|
||||
u64 s_blocks_count = (u64(s_blocks_count_hi) << 32) + s_blocks_count_lo;
|
||||
u64 s_r_blocks_count = (u64(s_r_blocks_count_hi) << 32) + s_r_blocks_count_lo;
|
||||
u64 s_free_blocks_count = (u64(s_free_blocks_count_hi) << 32) + s_free_blocks_count_lo;
|
||||
u64 groups_count = std::math::ceil(s_blocks_count/float(s_blocks_per_group));
|
||||
} else {
|
||||
padding[12];
|
||||
|
||||
u64 s_blocks_count = s_blocks_count_lo;
|
||||
u64 s_r_blocks_count = s_r_blocks_count_lo;
|
||||
u64 s_free_blocks_count = s_free_blocks_count_lo;
|
||||
u64 groups_count = std::math::ceil(s_blocks_count/float(s_blocks_per_group));
|
||||
}
|
||||
|
||||
if (s_feature_ro_compat.RO_COMPAT_EXTRA_ISIZE) {
|
||||
u16 s_min_extra_isize [[comment("All inodes have at least # bytes.")]];
|
||||
u16 s_want_extra_isize [[comment("New inodes should reserve # bytes.")]];
|
||||
} else {
|
||||
padding[4];
|
||||
}
|
||||
|
||||
ext4_super_flags s_flags [[comment("Miscellaneous flags.")]];
|
||||
padding[3];
|
||||
|
||||
u16 s_raid_stride [[comment("RAID stride. This is the number of logical blocks read from or written to the disk before moving to the next disk. This affects the placement of filesystem metadata.")]];
|
||||
|
||||
if (s_feature_incompat.INCOMPAT_MMP) {
|
||||
u16 s_mmp_interval [[comment("Number of seconds to wait in multi-mount prevention (MMP) checking.")]];
|
||||
u64 s_mmp_block [[comment("Block number for multi-mount protection data.")]];
|
||||
} else {
|
||||
padding[10];
|
||||
}
|
||||
|
||||
u32 s_raid_stripe_width [[comment("RAID stripe width. This is the number of logical blocks read from or written to the disk before coming back to the current disk.")]];
|
||||
|
||||
if (s_feature_incompat.INCOMPAT_FLEX_BG) {
|
||||
u8 s_log_groups_per_flex;
|
||||
u64 groups_per_flex = std::math::pow(2, s_log_groups_per_flex);
|
||||
} else {
|
||||
padding[1];
|
||||
}
|
||||
|
||||
if (s_feature_ro_compat.RO_COMPAT_METADATA_CSUM) {
|
||||
u8 s_checksum_type [[comment("Metadata checksum algorithm type.")]];
|
||||
} else {
|
||||
padding[1];
|
||||
}
|
||||
padding[2];
|
||||
|
||||
u64 s_kbytes_written [[comment("Number of KiB written to this filesystem over its lifetime.")]];
|
||||
|
||||
if (s_feature_ro_compat.RO_COMPAT_HAS_SNAPSHOT) {
|
||||
u32 s_snapshot_inum [[comment("inode number of active snapshot. (Not used in e2fsprogs/Linux.)")]];
|
||||
u32 s_snapshot_id [[comment("Sequential ID of active snapshot. (Not used in e2fsprogs/Linux.)")]];
|
||||
u64 s_snapshot_r_blocks_count [[comment("Number of blocks reserved for active snapshot’s future use. (Not used in e2fsprogs/Linux.)")]];
|
||||
u32 s_snapshot_list [[comment("inode number of the head of the on-disk snapshot list. (Not used in e2fsprogs/Linux.)")]];
|
||||
} else {
|
||||
padding[20];
|
||||
}
|
||||
|
||||
u32 s_error_count [[comment("Number of errors seen.")]];
|
||||
if (s_error_count > 0) {
|
||||
type::time32_t s_first_error_time [[comment("First time an error happened.")]];
|
||||
u32 s_first_error_ino [[comment("inode involved in first error.")]];
|
||||
u64 s_first_error_block [[comment("Number of block involved of first error.")]];
|
||||
char s_first_error_func[32] [[comment("Name of function where the error happened.")]];
|
||||
u32 s_first_error_line [[comment("Line number where error happened.")]];
|
||||
type::time32_t s_last_error_time [[comment("Last time an error happened.")]];
|
||||
u32 s_last_error_ino [[comment("inode involved in most recent error.")]];
|
||||
u32 s_last_error_line [[comment("Line number where most recent error happened.")]];
|
||||
u64 s_last_error_block [[comment("Number of block involved in most recent error.")]];
|
||||
char s_last_error_func[32] [[comment("Name of function where the most recent error happened.")]];
|
||||
} else {
|
||||
padding[104];
|
||||
}
|
||||
|
||||
char s_mount_opts[64] [[comment("ASCIIZ string of mount options.")]];
|
||||
|
||||
if (s_feature_ro_compat.RO_COMPAT_QUOTA) {
|
||||
u32 s_usr_quota_inum [[comment("Inode number of user quota file.")]];
|
||||
u32 s_grp_quota_inum [[comment("Inode number of group quota file.")]];
|
||||
} else {
|
||||
padding[8];
|
||||
}
|
||||
|
||||
u32 s_overhead_blocks [[comment("Overhead blocks/clusters in fs. (Huh? This field is always zero, which means that the linux kernel calculates it dynamically.)")]];
|
||||
|
||||
if (s_feature_compat.COMPAT_SPARSE_SUPER2) {
|
||||
u32 s_backup_bgs[2] [[comment("Block groups containing superblock backups.")]];
|
||||
} else {
|
||||
padding[8];
|
||||
}
|
||||
|
||||
if (s_feature_incompat.INCOMPAT_ENCRYPT) {
|
||||
ext4_super_encrypt_algos s_encrypt_algos[4] [[comment("Encryption algorithms in use. There can be up to four algorithms in use at any time.")]];
|
||||
u8 s_encrypt_pw_salt[16] [[comment("Salt for the string2key algorithm for encryption.")]];
|
||||
} else {
|
||||
padding[20];
|
||||
}
|
||||
|
||||
u32 s_lpf_ino [[comment("Inode number of lost+found.")]];
|
||||
|
||||
if (s_feature_ro_compat.RO_COMPAT_PROJECT) {
|
||||
u32 s_prj_quota_inum [[comment("Inode that tracks project quotas.")]];
|
||||
} else {
|
||||
padding[4];
|
||||
}
|
||||
|
||||
if (s_feature_ro_compat.RO_COMPAT_METADATA_CSUM) {
|
||||
u32 s_checksum_seed [[comment("Checksum seed used for metadata_csum calculations. This value is crc32c(~0, $orig_fs_uuid).")]];
|
||||
} else {
|
||||
padding[4];
|
||||
}
|
||||
|
||||
u8 s_wtime_hi [[comment("Upper 8 bits of the s_wtime field.")]];
|
||||
u8 s_mtime_hi [[comment("Upper 8 bits of the s_mtime field.")]];
|
||||
u8 s_mkfs_time_hi [[comment("Upper 8 bits of the s_mkfs_time field.")]];
|
||||
u8 s_lastcheck_hi [[comment("Upper 8 bits of the s_lastcheck field.")]];
|
||||
u8 s_first_error_time_hi [[comment("Upper 8 bits of the s_first_error_time field.")]];
|
||||
u8 s_last_error_time_hi [[comment("Upper 8 bits of the s_last_error_time field.")]];
|
||||
|
||||
padding[2];
|
||||
|
||||
u16 s_encoding [[comment("Filename charset encoding.")]];
|
||||
u16 s_encoding_flags [[comment("Filename charset encoding flags.")]];
|
||||
|
||||
if (s_feature_compat.RO_COMPAT_ORPHAN_PRESENT) {
|
||||
u32 s_orphan_file_inum [[comment("Orphan file inode number.")]];
|
||||
} else {
|
||||
padding[4];
|
||||
}
|
||||
|
||||
padding[376];
|
||||
if (s_feature_ro_compat.RO_COMPAT_METADATA_CSUM) {
|
||||
u32 s_checksum [[comment("Superblock checksum.")]];
|
||||
} else {
|
||||
padding[4];
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
ext4_super_block super_block @ 0x400;
|
||||
|
||||
fn block_to_address(u32 block) {
|
||||
return super_block.block_size * block;
|
||||
};
|
||||
|
||||
fn block_pointer_to_address(u32 block) {
|
||||
return block_to_address(block) - block;
|
||||
};
|
||||
|
||||
struct ext4_bitmap {
|
||||
u8 data[super_block.block_size];
|
||||
};
|
||||
|
||||
bitfield ext4_i_mode {
|
||||
S_IXOTH : 1 [[comment("Others may execute.")]];
|
||||
S_IWOTH : 1 [[comment("Others may write.")]];
|
||||
S_IROTH : 1 [[comment("Others may read.")]];
|
||||
S_IXGRP : 1 [[comment("Group members may execute.")]];
|
||||
S_IWGRP : 1 [[comment("Group members may write.")]];
|
||||
S_IRGRP : 1 [[comment("Group members may read.")]];
|
||||
S_IXUSR : 1 [[comment("Owner may execute.")]];
|
||||
S_IWUSR : 1 [[comment("Owner may write.")]];
|
||||
S_IRUSR : 1 [[comment("Owner may read.")]];
|
||||
S_ISVTX : 1 [[comment("Sticky bit.")]];
|
||||
S_ISGID : 1 [[comment("Set GID.")]];
|
||||
S_ISUID : 1 [[comment("Set UID.")]];
|
||||
S_IFIFO : 1 [[comment("FIFO.")]];
|
||||
S_IFCHR : 1 [[comment("Character device.")]];
|
||||
S_IFDIR : 1 [[comment("Directory.")]];
|
||||
S_IFREG : 1 [[comment("Regular file.")]];
|
||||
};
|
||||
|
||||
bitfield ext4_i_flags {
|
||||
EXT4_SECRM_FL : 1 [[comment("This file requires secure deletion.")]];
|
||||
EXT4_UNRM_FL : 1 [[comment("This file should be preserved, should undeletion be desired.")]];
|
||||
EXT4_COMPR_FL : 1 [[comment("File is compressed.")]];
|
||||
EXT4_SYNC_FL : 1 [[comment("All writes to the file must be synchronous.")]];
|
||||
EXT4_IMMUTABLE_FL : 1 [[comment("File is immutable.")]];
|
||||
EXT4_APPEND_FL : 1 [[comment("File can only be appended.")]];
|
||||
EXT4_NODUMP_FL : 1 [[comment("The dump utility should not dump this file.")]];
|
||||
EXT4_NOATIME_FL : 1 [[comment("Do not update access time.")]];
|
||||
EXT4_DIRTY_FL : 1 [[comment("Dirty compressed file.")]];
|
||||
EXT4_COMPRBLK_FL : 1 [[comment("File has one or more compressed clusters.")]];
|
||||
EXT4_NOCOMPR_FL : 1 [[comment("Do not compress file.")]];
|
||||
EXT4_ENCRYPT_FL : 1 [[comment("Encrypted inode.")]];
|
||||
EXT4_INDEX_FL : 1 [[comment("Directory has hashed indexes.")]];
|
||||
EXT4_IMAGIC_FL : 1 [[comment("AFS magic directory.")]];
|
||||
EXT4_JOURNAL_DATA_FL : 1 [[comment("File data must always be written through the journal.")]];
|
||||
EXT4_NOTAIL_FL : 1 [[comment("File tail should not be merged.")]];
|
||||
EXT4_DIRSYNC_FL : 1 [[comment("All directory entry data should be written synchronously.")]];
|
||||
EXT4_TOPDIR_FL : 1 [[comment("Top of directory hierarchy.")]];
|
||||
EXT4_HUGE_FILE_FL : 1 [[comment("This is a huge file.")]];
|
||||
EXT4_EXTENTS_FL : 1 [[comment("Inode uses extents.")]];
|
||||
EXT4_VERITY_FL : 1 [[comment("Verity protected file.")]];
|
||||
EXT4_EA_INODE_FL : 1 [[comment("Inode stores a large extended attribute value in its data blocks.")]];
|
||||
EXT4_EOFBLOCKS_FL : 1 [[comment("This file has blocks allocated past EOF.")]];
|
||||
padding : 1;
|
||||
EXT4_SNAPFILE_FL : 1 [[comment("Inode is a snapshot.")]];
|
||||
padding : 1;
|
||||
EXT4_SNAPFILE_DELETED_FL : 1 [[comment("Snapshot is being deleted.")]];
|
||||
EXT4_SNAPFILE_SHRUNK_FL : 1 [[comment("Snapshot shrink has completed.")]];
|
||||
EXT4_INLINE_DATA_FL : 1 [[comment("Inode has inline data.")]];
|
||||
EXT4_PROJINHERIT_FL : 1 [[comment("Create children with the same project ID.")]];
|
||||
padding : 1;
|
||||
EXT4_RESERVED_FL : 1 [[comment("Reserved for ext4 library.")]];
|
||||
};
|
||||
|
||||
struct ext4_inode {
|
||||
ext4_i_mode i_mode [[comment("File mode.")]];
|
||||
u16 i_uid [[comment("Lower 16-bits of Owner UID.")]];
|
||||
u32 i_size [[comment("Lower 32-bits of size in bytes.")]];
|
||||
type::time32_t i_atime [[comment("Last access time.")]];
|
||||
type::time32_t i_ctime [[comment("Last inode change time.")]];
|
||||
type::time32_t i_mtime [[comment("Last data modification time.")]];
|
||||
type::time32_t i_dtime [[comment("Deletion Time.")]];
|
||||
u16 i_gid [[comment("Lower 16-bits of GID.")]];
|
||||
u16 i_links_count [[comment("Hard link count.")]];
|
||||
u32 i_blocks_lo [[comment("Lower 32-bits of “block” count.")]];
|
||||
ext4_i_flags i_flags [[comment("Inode flags.")]];
|
||||
u32 i_osd1 [[comment("Depends of the OS.")]];
|
||||
u32 i_block[15] [[comment("Block map or extent tree.")]];
|
||||
u32 i_generation [[comment("File version (for NFS).")]];
|
||||
u32 i_file_acl [[comment("Lower 32-bits of extended attribute block.")]];
|
||||
u32 i_dir_acl [[comment("Upper 32-bits of file/directory size.")]];
|
||||
u32 i_faddr [[comment("Fragment address.")]];
|
||||
u8 i_osd2[12] [[comment("Depends of the OS.")]];
|
||||
if (super_block.s_rev_level >= ext4_super_revision::V2_DYNAMIC_REV && super_block.s_inode_size > 0x80) {
|
||||
u16 i_extra_isize [[comment("Size of this inode - 128.")]];
|
||||
u16 i_checksum_hi [[comment("Upper 16-bits of the inode checksum.")]];
|
||||
if (super_block.s_inode_size > 0x84) {
|
||||
u32 i_ctime_extra [[comment("Extra change time bits.")]];
|
||||
u32 i_mtime_extra [[comment("Extra modification time bits.")]];
|
||||
u32 i_atime_extra [[comment("Extra access time bits.")]];
|
||||
u32 i_crtime [[comment("File creation time.")]];
|
||||
u32 i_crtime_extra [[comment("Extra file creation time bits.")]];
|
||||
if (super_block.s_inode_size > 0x98) {
|
||||
u32 i_version_hi [[comment("Upper 32-bits for version number.")]];
|
||||
if (super_block.s_inode_size > 0x9C) {
|
||||
u32 i_projid [[comment("Project ID.")]];
|
||||
if (super_block.s_inode_size > 0xA0) {
|
||||
padding[super_block.s_inode_size - 0xA0];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
bitfield ext4_bg_flags {
|
||||
EXT4_BG_INODE_UNINIT : 1 [[comment("Inode table and bitmap are not initialized.")]];
|
||||
EXT4_BG_BLOCK_UNINIT : 1 [[comment("Block bitmap is not initialized.")]];
|
||||
EXT4_BG_INODE_ZEROED : 1 [[comment("Inode table is zeroed.")]];
|
||||
};
|
||||
|
||||
struct ext4_group_desc {
|
||||
ext4_bitmap *bg_block_bitmap : u32 [[pointer_base("block_pointer_to_address"), comment("Lower 32-bits of location of block bitmap.")]];
|
||||
ext4_bitmap *bg_inode_bitmap : u32 [[pointer_base("block_pointer_to_address"), comment("Lower 32-bits of location of inode bitmap.")]];
|
||||
ext4_inode *bg_inode_table[super_block.s_inodes_per_group] : u32 [[pointer_base("block_pointer_to_address"), comment("Lower 32-bits of location of inode table.")]];
|
||||
u16 bg_free_blocks_count [[comment("Lower 16-bits of free block count.")]];
|
||||
u16 bg_free_inodes_count [[comment("Lower 16-bits of free inode count.")]];
|
||||
u16 bg_used_dirs_count [[comment("Lower 16-bits of directory count.")]];
|
||||
ext4_bg_flags bg_flags [[comment("Block group flags.")]];
|
||||
padding[1];
|
||||
u32 bg_exclude_bitmap_lo [[comment("Lower 32-bits of location of snapshot exclusion bitmap.")]];
|
||||
u16 bg_block_bitmap_csum_lo [[comment("Lower 16-bits of the block bitmap checksum.")]];
|
||||
u16 bg_inode_bitmap_csum_lo [[comment("Lower 16-bits of the inode bitmap checksum.")]];
|
||||
u16 bg_itable_unused_lo [[comment("Lower 16-bits of unused inode count.")]];
|
||||
u16 bg_checksum [[comment("Group descriptor checksum.")]];
|
||||
|
||||
};
|
||||
|
||||
struct ext4_group_desc_64_bit : ext4_group_desc {
|
||||
u32 bg_block_bitmap_hi [[comment("Upper 32-bits of location of block bitmap.")]];
|
||||
u32 bg_inode_bitmap_hi [[comment("Upper 32-bits of location of inodes bitmap.")]];
|
||||
u32 bg_inode_table_hi [[comment("Upper 32-bits of location of inodes table.")]];
|
||||
u16 bg_free_blocks_count_hi [[comment("Upper 16-bits of free block count.")]];
|
||||
u16 bg_free_inodes_count_hi [[comment("Upper 16-bits of free inode count.")]];
|
||||
u16 bg_used_dirs_count_hi [[comment("Upper 16-bits of directory count.")]];
|
||||
u16 bg_itable_unused_hi [[comment("Upper 16-bits of unused inode count.")]];
|
||||
u32 bg_exclude_bitmap_hi [[comment("Upper 32-bits of location of snapshot exclusion bitmap.")]];
|
||||
u16 bg_block_bitmap_csum_hi [[comment("Upper 16-bits of the block bitmap checksum.")]];
|
||||
u16 bg_inode_bitmap_csum_hi [[comment("Upper 16-bits of the inode bitmap checksum.")]];
|
||||
padding[4];
|
||||
};
|
||||
|
||||
struct ext4_group_descriptors {
|
||||
if (super_block.s_rev_level >= ext4_super_revision::V2_DYNAMIC_REV && super_block.s_feature_incompat.INCOMPAT_64BIT) {
|
||||
ext4_group_desc_64_bit group_desc[super_block.groups_count];
|
||||
} else {
|
||||
ext4_group_desc group_desc[super_block.groups_count];
|
||||
}
|
||||
};
|
||||
|
||||
ext4_group_descriptors group_descs @ block_to_address(2);
|
||||
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;
|
||||
@@ -1,6 +1,6 @@
|
||||
#pragma author 5h4rrK // https://www.github.com/5h4rrK
|
||||
#pragma organization temabi0s // (https://bi0s.in)
|
||||
#pragma description ReFS-File-System
|
||||
#pragma description ReFS-File-System
|
||||
|
||||
#pragma array_limit 10000
|
||||
|
||||
@@ -97,7 +97,7 @@ struct INDEX_HEADER {
|
||||
u64 unused2[[name("UnUsed")]];
|
||||
u32 end[[name("KeyIndexEnd")]];
|
||||
u32 align[[name("Alignment")]];
|
||||
$ = this.parent.start_pos + 0x50 + this.parent.rootsize + keyindxoff;
|
||||
$ = this.parent.start_pos + 0x50 + this.parent.rootsize + keyindxoff;
|
||||
OFFSET_ENTRIES entries[keycount][[name("KeyEntries")]];
|
||||
|
||||
};
|
||||
@@ -142,7 +142,7 @@ struct ROOT_NODE{
|
||||
char comps[rootsize - ($ - start_pos) + 0x50][[name("Components")]];
|
||||
$ = (start_pos + 0x50 + rootsize);
|
||||
INDEX_HEADER indxhdr[[name("IndexHeader")]];
|
||||
// $ = start_pos + 0x50 + rootsize + indxhdr.keyindxoff;
|
||||
// $ = start_pos + 0x50 + rootsize + indxhdr.keyindxoff;
|
||||
$ = (start_pos + 0x50 + rootsize + indxhdr.size);
|
||||
INDEX_ENTRY_STRUCTURE indxentrystruct[indxhdr.keycount][[name("IndexEntry")]];
|
||||
};
|
||||
@@ -214,7 +214,7 @@ struct CHECKPOINT {
|
||||
u32 lenselfdescriptor[[comment("Self Descriptor Size"),name("SelfDescriptorSz")]];
|
||||
u64 blockno[[comment("Most Recent CheckPoint") , name("BlockNumber")]];
|
||||
u32 prev_pos = $;
|
||||
$ = ($ / clustersz) *clustersz + offsetselfdescriptor;
|
||||
$ = ($ / clustersz) *clustersz + offsetselfdescriptor;
|
||||
SELF_DESCRIPTOR selfdes[[name("SelfDescriptor")]];
|
||||
$ = prev_pos;
|
||||
$ += (0x28);
|
||||
@@ -238,7 +238,7 @@ struct SUPERBLOCK {
|
||||
};
|
||||
|
||||
struct VOLUME_BOOT_RECORD {
|
||||
BYTE jmpInstruction[3] [[comment("Jump Instruction"), name("JumpInstruction")]];;
|
||||
BYTE jmpInstruction[3] [[comment("Jump Instruction"), name("JumpInstruction")]];
|
||||
FILESYSTEM FileSystem[[comment("FileSystemName"), name("FileSystem")]];
|
||||
BYTE UnKnown[5];
|
||||
char Identifier[4][[comment("File System Recognition Structure, allows OS to recognise the structure"), name("FSRSIdentifier")]];
|
||||
@@ -7,6 +7,9 @@ import type.size;
|
||||
import std.string;
|
||||
import std.mem;
|
||||
|
||||
const u16 ROMBANKSIZE_16K = 0x4000;
|
||||
const u16 ROMBANKSIZE_32K = 0x8000;
|
||||
|
||||
bool uppercaseROMFeatures in;
|
||||
bool brandedROMFeatures in;
|
||||
|
||||
@@ -30,9 +33,13 @@ namespace format {
|
||||
romSize = 1258291;
|
||||
romBanks = 80;
|
||||
}
|
||||
if (cartSizeType == 0x54) {
|
||||
romSize = 1572864;
|
||||
romBanks = 96;
|
||||
}
|
||||
return std::format("size: {}, banks: {}", type::impl::size_formatter(romSize), romBanks);
|
||||
};
|
||||
|
||||
|
||||
fn ram_type(u8 ramType) {
|
||||
u16 ramSize;
|
||||
u16 ramBanks;
|
||||
@@ -54,7 +61,7 @@ namespace format {
|
||||
}
|
||||
return std::format("size: {}, banks: {}", type::impl::size_formatter(ramSize), ramBanks);
|
||||
};
|
||||
|
||||
|
||||
fn rom_features(u8 type) {
|
||||
str result = "( ";
|
||||
if (brandedROMFeatures) match(type) {
|
||||
@@ -64,37 +71,37 @@ namespace format {
|
||||
match(type) {
|
||||
(0x00): result += "no_mbc";
|
||||
(0x01): result += "mbc1";
|
||||
(0x02): result += "mbc1 | ram";
|
||||
(0x02): result += "mbc1 | ram";
|
||||
(0x03): result += "mbc1 | ram | battery";
|
||||
(0x05): result += "mbc2";
|
||||
(0x05): result += "mbc2";
|
||||
(0x06): result += "mbc2 | battery";
|
||||
(0x08): result += "no_mbc | ram";
|
||||
(0x08): result += "no_mbc | ram";
|
||||
(0x09): result += "no_mbc | ram | battery";
|
||||
(0x0B): result += "mmm01";
|
||||
(0x0B): result += "mmm01";
|
||||
(0x0C): result += "mmm01 | ram";
|
||||
(0x0D): result += "mmm01 | ram | battery";
|
||||
(0x0D): result += "mmm01 | ram | battery";
|
||||
(0x0F): result += "mbc3 | timer | battery";
|
||||
(0x10): result += "mbc3 | timer | ram | battery";
|
||||
(0x10): result += "mbc3 | timer | ram | battery";
|
||||
(0x11): result += "mbc3";
|
||||
(0x12): result += "mbc3 | ram";
|
||||
(0x12): result += "mbc3 | ram";
|
||||
(0x13): result += "mbc3 | ram | battery";
|
||||
(0x19): result += "mbc5";
|
||||
(0x19): result += "mbc5";
|
||||
(0x1A): result += "mbc5 | ram";
|
||||
(0x1B): result += "mbc5 | ram | battery";
|
||||
(0x1B): result += "mbc5 | ram | battery";
|
||||
(0x1C): result += "mbc5 | rumble";
|
||||
(0x1D): result += "mbc5 | rumble | ram";
|
||||
(0x1D): result += "mbc5 | rumble | ram";
|
||||
(0x1E): result += "mbc5 | rumble | ram | battery";
|
||||
(0x20): result += "mbc6";
|
||||
(0x20): result += "mbc6";
|
||||
(0x22): result += "mbc7 | sensor | rumble";
|
||||
(0xFC): result += "camera";
|
||||
(0xFC): result += "camera";
|
||||
(0xFD): result += "tama5";
|
||||
(0xFE): result += "huc3";
|
||||
(0xFE): result += "huc3";
|
||||
(0xFF): result += "huc1 | ram | battery";
|
||||
}
|
||||
if (uppercaseROMFeatures) result = std::string::to_upper(result);
|
||||
return result + " )";
|
||||
return result + " )";
|
||||
};
|
||||
|
||||
|
||||
fn licensee_code(u8 code) {
|
||||
match(code) {
|
||||
(0x00): return "None";
|
||||
@@ -128,6 +135,7 @@ namespace format {
|
||||
(0x46 | 0xCF): return "Angel";
|
||||
(0x47): return "Spectrum Holoby";
|
||||
(0x49): return "Irem";
|
||||
(0x4F): return "U.S. Gold";
|
||||
(0x50): return "Absolute";
|
||||
(0x51 | 0xB0): return "Acclaim";
|
||||
(0x52): return "Activision";
|
||||
@@ -196,7 +204,7 @@ namespace format {
|
||||
(0xCA): return "Ultra";
|
||||
(0xCB): return "Vap";
|
||||
(0xCC): return "Use Corporation";
|
||||
(0xCD): return "Meldac";
|
||||
(0xCD): return "Meldac";
|
||||
(0xD1): return "Sofel";
|
||||
(0xD2): return "Quest";
|
||||
(0xD3): return "Sigma Enterprises";
|
||||
@@ -214,6 +222,7 @@ namespace format {
|
||||
(0xE8): return "Asmik";
|
||||
(0xE9): return "Natsume";
|
||||
(0xEA): return "King Records";
|
||||
(0xEC): return "Epic/Sony Records";
|
||||
(0xEE): return "IGS";
|
||||
(0xF0): return "A Wave";
|
||||
(0xF3): return "Extreme Entertainment";
|
||||
@@ -221,7 +230,7 @@ namespace format {
|
||||
return "Unknown Licensee";
|
||||
};
|
||||
|
||||
fn new_licensee_code(str a) {
|
||||
fn new_licensee_code(str a) {
|
||||
if (std::mem::read_unsigned(0x14B, 1) != 0x33) return "See old licensee code";
|
||||
match(a) {
|
||||
("00"): return "None";
|
||||
@@ -284,13 +293,16 @@ namespace format {
|
||||
("96"): return "Yonezawa/s’pal";
|
||||
("97"): return "Kaneko";
|
||||
("99"): return "Pack in soft";
|
||||
("9H"): return "Bottom Up";
|
||||
("A4"): return "Konami (Yu-Gi-Oh!)";
|
||||
("BL"): return "MTO";
|
||||
("DK"): return "Kodansha";
|
||||
}
|
||||
return "Unknown";
|
||||
};
|
||||
|
||||
using CGB;
|
||||
|
||||
|
||||
fn null_cgb_flags(CGB flags) {
|
||||
return "NO_CGB";
|
||||
};
|
||||
@@ -357,5 +369,15 @@ struct JumpVectors {
|
||||
u8 int5[8] [[comment("joypad")]];
|
||||
};
|
||||
|
||||
struct romBank16K {
|
||||
u8 Bank[ROMBANKSIZE_16K];
|
||||
};
|
||||
struct romBank32K {
|
||||
u8 Bank[ROMBANKSIZE_32K];
|
||||
};
|
||||
|
||||
romBank16K romBanks16K[std::mem::size() / ROMBANKSIZE_16K] @ 0x00;
|
||||
romBank32K romBanks32K[std::mem::size() / ROMBANKSIZE_32K] @ 0x00;
|
||||
|
||||
JumpVectors jumpVectors @ 0x00 [[comment("Instructions called on interrupts or RST instructions")]];
|
||||
CartridgeStart cartridgeStart @ 0x100;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user