Ignore CLAUDE.md

This commit is contained in:
njohnson 2026-01-11 16:56:03 -05:00
parent 92caed5f7e
commit 6fbb62a242

274
CLAUDE.md
View File

@ -1,274 +0,0 @@
# CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
## Build Instructions
To build the project, use the provided build scripts:
```cmd
build_debug.cmd # Debug build (Windows CMD)
build_release.cmd # Release build (Windows CMD)
```
Or from Git Bash:
```bash
./build_all_debug.sh # Debug build
./build_all_release.sh # Release build
```
This project uses Qt 6.10.0 with MSVC 2022 on Windows. The build scripts use jom (Qt's parallel make) and automatically run windeployqt. The .cmd files set up the MSVC environment via vcvars64.bat.
Build output locations:
- Debug: `build/Debug/app/debug/app.exe`
- Release: `build/Release/app/release/app.exe`
## Deployment
**NEVER run `deploy.sh` without explicit user consent.** Focus on building and testing only. The deploy script creates releases and uploads to Gitea - this should only be done when the user explicitly requests a release.
## Project Overview
XPlor is a Qt-based binary file format explorer for video game files. It uses **XScript**, a custom DSL for defining binary file structures, allowing new formats to be added without modifying core code.
## Architecture
```
XPlor/
├── app/ # Qt GUI application (MainWindow, previews, settings)
├── libs/
│ ├── dsl/ # XScript engine (lexer, parser, interpreter, typeregistry)
│ ├── core/ # Utilities, logging, syntax highlighters
│ ├── compression/ # LZO, zlib, Oodle, xcompress64 support
│ └── encryption/ # Salsa20, SHA1 support
├── definitions/ # XScript format definitions
│ ├── cod/ # Call of Duty formats (60+ files)
│ ├── asura/ # Sniper Elite V2 formats
│ └── [other engines]
└── third_party/ # External SDKs (DevIL, Xbox SDK, zlib)
```
## DSL Engine Flow
1. `TypeRegistry` loads and merges `.xscript` files from `definitions/`
2. `Lexer` tokenizes XScript source
3. `Parser` builds AST
4. `Interpreter` executes AST against binary streams
5. Results stored as `QVariantMap` for UI display
## XScript Language Reference
### Type Definition
```xscript
type typename ui("Display Name", root) byteorder LE
{
criteria { require _ext == "ff"; }
// Parse body with UI display
magic = ascii(read(4)) ui("Magic");
u32 version ui("Version");
// Fields without ui() suffix are not shown in UI
u32 internal_field;
}
```
### Scalar Types
`u8`, `i8`, `u16`, `i16`, `u32`, `i32`, `u64`, `i64`, `f32`, `f64`, `bool`
### Built-in Functions
**Reading:**
- `read(n)` - read n bytes
- `cstring()` - read null-terminated string
- `wstring()` / `wstring_be()` - read UTF-16 LE/BE string
- `skip(n)` - skip n bytes
- `align(n)` - align to n-byte boundary
- `seek(pos)` - seek to absolute position
- `pos()` / `size()` - current position / file size
**Random Access:**
- `u8at(off)`, `u16at(off)`, `u32at(off)`, `u64at(off)`, `i32at(off)` - read at offset without advancing
- `bytesat(off, len)` - read bytes at offset
- `with_seek(offset, expr)` - evaluate expression at offset, restore position
**Parsing:**
- `parse("typename", bytes)` - parse bytes as type (creates new stream)
- `parse_here("typename")` - parse type at current position (same stream, delegation pattern)
**Context:**
- `ctx_set(name, value)` - set global context variable (cross-type communication)
- `ctx_get(name)` - get global context variable
- `set_name(value)` - set item name for tree display
- `set_display(value)` - set display name
**Decompression:**
- `zlib(bytes)` - decompress zlib
- `xmem(bytes)` - decompress Xbox xcompress
- `deflate(bytes)` - decompress raw deflate
**Conversion:**
- `ascii(bytes)` / `utf8(bytes)` / `utf16le(bytes)` / `utf16be(bytes)` - bytes to string
- `hex(value)` - format as hex string
**Collections:**
- `make_list()` / `make_object()` - create empty list/object
- `push(listName, value)` - append to list
- `get(container, key)` - get from list/object
- `set(varName, key, value)` - set in list/object
- `len(value)` - length of string/bytes/list
**String:**
- `contains(str, sub)`, `starts_with(str, prefix)`, `ends_with(str, suffix)`
- `substr(str, start, len)`, `split(str, delim)`, `replace(str, old, new)`
- `trim(str)`, `to_lower(str)`, `clean(str)`, `basename(path)`
**UI Metadata (inline suffix syntax):**
- `u32 field ui("Display Name");` - readonly field shown in UI
- `u32 field ui("Display Name", edit);` - editable field shown in UI
- `var = expr ui("Display Name");` - assignment with UI display
- `set_viewer("hex"|"text"|"image"|"audio")` - set viewer type
- `preview(data)` / `set_preview(filename, data)` - set preview data
**Control:**
- `match(value, case1, result1, case2, result2, ..., default)` - switch expression
- `bit(value, bit)` / `bit(value, start, count)` - extract bits
- `check_criteria("typename")` - test if type criteria matches current position
### Control Flow
```xscript
if (condition) { ... } else { ... }
while (condition) { ... }
repeat count { ... } // provides _i index
for i in start..end { ... }
break;
// Match expression (replaces long if-else chains)
match(value) {
"pattern1" => { ... }
"pattern2" | "pattern3" => { ... } // multiple patterns
default => { ... }
}
```
### Constants
```xscript
const PTR_INLINE = -1;
const MAGIC_HEADER = 0x12345678;
```
### Array Declaration (simplifies repeat/push patterns)
```xscript
// Instead of: items = 0; repeat(count) { _x = parse_here("type"); items = push("items", _x); }
array[count] items: typename;
// With pointer condition:
array[count] items: typename when items_ptr;
```
### Pipeline Syntax
```xscript
zone = read(size) | zlib | parse("zone");
```
### File Variables
- `_path` - full file path
- `_name` - filename
- `_basename` - filename without extension
- `_ext` - file extension (lowercase)
## Key Files
- `libs/dsl/interpreter.cpp` - Runtime execution, all built-in functions
- `libs/dsl/parser.cpp` - AST generation
- `libs/dsl/typeregistry.cpp` - Type loading and file detection
- `app/mainwindow.cpp` - Main UI logic
- `definitions/cod/fastfile.xscript` - Primary COD format (good example)
## Conventions
- Use `ctx_set()`/`ctx_get()` for cross-type context (not `set_global`/`get_global`)
- Use `skip(n)` for padding, not `_padding = read(n)`
- Pointer values of `-1` indicate inline data follows
- Use `-1` consistently (not `4294967295` or `0xFFFFFFFF`)
## Byte Order Inheritance
Child types **automatically inherit byte order** from their parent when called via `parse_here()` or `parse()`. This eliminates the need for duplicate BE/LE type definitions in most cases.
### Rules
1. **Root types** must have explicit `byteorder` (needed for file detection criteria)
2. **Child types** should omit `byteorder` to inherit from parent
3. Only use explicit `byteorder` on child types when you need to **override** inherited order
### Pattern: Thin Dispatcher + Shared Implementation
For formats that exist in both BE and LE variants with identical structure:
```xscript
// Root dispatcher for BE files (Xbox 360, Wii)
type myformat ui("My Format", root) byteorder BE
{
criteria { require ascii(bytesat(0, 4)) == "MAGIC"; }
parse_here("myformat_impl");
}
// Root dispatcher for LE files (PC, original Xbox)
type myformat_le ui("My Format", root) byteorder LE
{
criteria { require ascii(bytesat(0, 4)) == "CIGAM"; }
parse_here("myformat_impl");
}
// Shared implementation - inherits byteorder from caller
type myformat_impl ui("My Format")
{
magic = ascii(read(4)) ui("Magic");
u32 version ui("Version");
// ... all parsing logic once ...
}
```
### Pattern: Runtime Detection with BE Wrapper
When a single root type detects endianness at runtime:
```xscript
// Root dispatcher - uses LE, delegates to BE wrapper when needed
type myformat ui("My Format", root) byteorder LE
{
criteria { require magic == 0xBEEFFEED || magic == 0xEDFEEFBE; }
if (u32at(0) == 0xEDFEEFBE) {
parse_here("myformat_be"); // BE wrapper overrides inherited LE
} else {
parse_here("myformat_impl"); // Inherits LE
}
}
// BE wrapper - explicit byteorder overrides inherited LE
type myformat_be ui("My Format BE") byteorder BE
{
parse_here("myformat_impl");
}
// Shared implementation - inherits byteorder from caller
type myformat_impl ui("My Format") { ... }
```
### When NOT to Consolidate
Keep separate BE/LE types when:
- Structures are **legitimately different** per platform (different header sizes, fields, etc.)
- Magic bytes differ in ways that indicate structural differences (not just reversed)
## Documentation Updates
**IMPORTANT**: After making changes to the XScript DSL (parser, interpreter, or language features), you MUST update the documentation:
1. **Update the LaTeX source**: Edit `docs/xscript-guide.tex` with the new/changed syntax
2. **Rebuild documentation**: Run `docs/build-docs.cmd` (Windows) or `docs/build-docs.sh` (Linux/Mac)
- This generates `xscript-guide.pdf` and `xscript-guide.md`
- Requires `pdflatex` and `pandoc` to be installed
3. **Update this file**: Keep the XScript Language Reference section in `CLAUDE.md` in sync with major changes