# SDF File Editor & Hex Viewer
A small, Windows-friendly Tkinter GUI for inspecting and editing **binary `.sdf` suspension files**.
It scans a file for known element “signatures”, decodes fields using embedded encoding markers, presents everything in a tree view, and shows a synchronized **hex dump** with highlighting for the selected element/field/value. You can edit values inline and save a modified binary back to disk.
---
## Features
- **Open / view / edit `.sdf` (or any binary file)**
- **Tree view of decoded elements**
- Body elements: `BODY`, `GENERIC`
- Suspension elements: `JOINT&HINGE`, `BAR`
- **Inline editing**
- Click a value → edit in place (bytes, ints, floats)
- Modified values are shown in **blue**
- **Hex viewer**
- Full hex dump with ASCII side
- Selecting an element/field/value highlights the corresponding bytes
- **Auto-naming**
- Attempts to infer human-meaningful names for body parts from mass/inertia/position patterns
- Suspension parts are auto-named by detected order (corners and arms)
- **Persistent labels**
- Rename elements and store labels in `yourfile.sdf.labels.json`
- Import labels from another `.labels.json`
- **Reporting / Export**
- View a structured report (body + suspension)
- Copy report to clipboard
- Save report to a `.txt`
---
## Requirements
- Python **3.10+** recommended (uses modern typing like `X | None`)
- Standard library only:
- `tkinter`, `ttk`
- `struct`, `json`, `dataclasses`, `pathlib`
> On Windows the app also attempts to set DPI awareness via `ctypes` for sharper UI.
---
## Install / Run
### Run directly
```bash
python sdf_viewer_final.pyYou can package with PyInstaller if you want a single EXE:
pyinstaller --onefile --windowed sdf_viewer_final.py-
File → Open… and pick an
.sdffile -
Browse elements in the tree
-
Click a value in the right-most column to edit it
- Press Enter to confirm
- Esc cancels
-
Use the hex panel to verify byte-level alignment:
- Selecting an element highlights its full byte range
- Selecting a field/value highlights only the relevant bytes
-
File → Save or Save As… to write the updated binary
The scanner produces Element objects, each containing one or more Fields:
-
Elementkind: e.g.BODY,GENERIC,JOINT&HINGE,BARstart,end: byte offsets in the filefields: list of decoded fieldsdisplay_name: user-visible name (editable)auto_name: best-guess name (body elements)identifier: raw bytes used to identify certain suspension elements
-
Fieldname: e.g.mass,inertia,position,orientation,axis,pos,negat: byte offset of the field’s datafmt: tuple of type codes (b,i,f)values: decoded valuesencoding_suffix: the encoding marker bytes found in the file (when applicable)
The file uses small byte sequences (1–2 bytes) to indicate how the next values are encoded.
These are mapped in ENCODING_RULES, e.g.:
0xA3 0x02→Float, Float, Float0x03 0x00→Byte×30x21→Float×1
The parser:
- Finds a known signature (sequence of bytes)
- Looks immediately after the signature for an encoding suffix
- Uses that suffix to decide the struct format (byte/int/float)
- Reads values and records offsets
Body elements are parsed in sequence across the file:
-
BODY
- mass is read as a byte (after
SIG_BODY_MASS) - inertia/position/orientation are found by scanning ahead for signatures (
SIG_INERT,SIG_POS,SIG_ORI)
- mass is read as a byte (after
-
GENERIC
- mass is a float (after
SIG_GEN_MASS) - then inertia/position/orientation similarly
- mass is a float (after
Auto-naming (auto_name_element) uses patterns like:
- mass ranges
- encoding types used for inertia/position
- wheel vs spindle guess from inertia magnitude and Z position
Suspension scanning starts after the last body element.
-
JOINT&HINGE
- signature match
SIG_JOINT_HINGE - includes a 1-byte identifier immediately before the signature
- reads
('f','b','b')as axis info - first four are auto-named by order:
fl,fr,rl,rr→*_wheel_hinge?
- signature match
-
BAR
- position signature
SIG_BAR_POS - includes a 2-byte identifier immediately before the signature
- reads
postriple-float then searches forSIG_BAR_NEGand readsneg - auto-named by order (5 per corner):
forward_upper,rearward_upper,forward_lower,rearward_lower,tie_rod
- position signature
When you rename an element (double-click an element row), the name is stored in:
yourfile.sdf.labels.json
Keys are:
body:<index>for body elementssusp:<index>for suspension elements
You can also import labels from another labels file via Tools → Import labels…
The Export menu generates a text report including:
-
Element number, kind, name, offsets
-
Field details:
- encoding marker bytes
- type tuple
- formatted values
Options:
- View Report…
- Copy to Clipboard
- Save Report…
- This tool is signature-based: it only parses elements it recognizes via hard-coded signatures.
- Parsing uses a bounded lookahead (
MAX_LOOKAHEAD = 16384) when searching for the next signature. - No checksum/CRC validation is performed—changes are written directly at recorded offsets.
- The “auto names” include
?intentionally to indicate best-guess, not certainty.
If you want to support additional structures:
-
Add new encoding suffixes to
ENCODING_RULES -
Add new signatures (
SIG_*) -
Write a new
parse_*_at()function that:- matches the signature
- detects encoding
- reads values
- returns an
Element
-
Hook it into
scan()(phase 1 or 2 depending on where it appears)
