- build_debug.cmd / build_release.cmd: Windows batch files with MSVC setup - build_all_debug.sh / build_all_release.sh: Shell wrappers for Git Bash - deploy.sh: Automated release script for Gitea - Update CLAUDE.md with build instructions Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
9.0 KiB
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:
build_debug.cmd # Debug build (Windows CMD)
build_release.cmd # Release build (Windows CMD)
Or from Git 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
TypeRegistryloads and merges.xscriptfiles fromdefinitions/Lexertokenizes XScript sourceParserbuilds ASTInterpreterexecutes AST against binary streams- Results stored as
QVariantMapfor UI display
XScript Language Reference
Type Definition
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 bytescstring()- read null-terminated stringwstring()/wstring_be()- read UTF-16 LE/BE stringskip(n)- skip n bytesalign(n)- align to n-byte boundaryseek(pos)- seek to absolute positionpos()/size()- current position / file size
Random Access:
u8at(off),u16at(off),u32at(off),u64at(off),i32at(off)- read at offset without advancingbytesat(off, len)- read bytes at offsetwith_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 variableset_name(value)- set item name for tree displayset_display(value)- set display name
Decompression:
zlib(bytes)- decompress zlibxmem(bytes)- decompress Xbox xcompressdeflate(bytes)- decompress raw deflate
Conversion:
ascii(bytes)/utf8(bytes)/utf16le(bytes)/utf16be(bytes)- bytes to stringhex(value)- format as hex string
Collections:
make_list()/make_object()- create empty list/objectpush(listName, value)- append to listget(container, key)- get from list/objectset(varName, key, value)- set in list/objectlen(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 UIu32 field ui("Display Name", edit);- editable field shown in UIvar = expr ui("Display Name");- assignment with UI displayset_viewer("hex"|"text"|"image"|"audio")- set viewer typepreview(data)/set_preview(filename, data)- set preview data
Control:
match(value, case1, result1, case2, result2, ..., default)- switch expressionbit(value, bit)/bit(value, start, count)- extract bitscheck_criteria("typename")- test if type criteria matches current position
Control Flow
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
const PTR_INLINE = -1;
const MAGIC_HEADER = 0x12345678;
Array Declaration (simplifies repeat/push patterns)
// 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
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 functionslibs/dsl/parser.cpp- AST generationlibs/dsl/typeregistry.cpp- Type loading and file detectionapp/mainwindow.cpp- Main UI logicdefinitions/cod/fastfile.xscript- Primary COD format (good example)
Conventions
- Use
ctx_set()/ctx_get()for cross-type context (notset_global/get_global) - Use
skip(n)for padding, not_padding = read(n) - Pointer values of
-1indicate inline data follows - Use
-1consistently (not4294967295or0xFFFFFFFF)
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
- Root types must have explicit
byteorder(needed for file detection criteria) - Child types should omit
byteorderto inherit from parent - Only use explicit
byteorderon 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:
// 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:
// 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:
- Update the LaTeX source: Edit
docs/xscript-guide.texwith the new/changed syntax - Rebuild documentation: Run
docs/build-docs.cmd(Windows) ordocs/build-docs.sh(Linux/Mac)- This generates
xscript-guide.pdfandxscript-guide.md - Requires
pdflatexandpandocto be installed
- This generates
- Update this file: Keep the XScript Language Reference section in
CLAUDE.mdin sync with major changes