Py_sax2sab/README.md
arda.aydin@ontrol.com.tr 3e313f8223 First commit tekrar
Bu dosyalar Claude uzerinden olusturuldu
2026-08-12 20:49:31 +03:00

3.1 KiB

PySedonac

Pure-Python .sax -> .sab encoder. No Java, no JRE.

Ported from the Sedona 1.2 runtime library — sedona/src/sedona/src/sedona/offline/OfflineApp.java and friends, not from sedonac/ (that's the language compiler; app file conversion lives in the runtime lib).

Verified byte-identical to sedonac.exe on a 189-component / 217-link app across 18 kits.

Usage

python sab.py <app.sax> <sedona_home> <out.sab>

sedona_home is the directory holding manifests/ — kit manifests are required, since slot ids and types are resolved from them.

Verify

python verify.py [sedona_home]

Compares our output against the checked-in test_normal_sedonac.sab. Pass a sedona home containing bin/sedonac.exe and call check(sax) with no reference to diff against a live sedonac run instead.

Format

Big-endian. No padding, no alignmentBuf.bigEndian = true, checkAlignment = false. The align()/pad() helpers exist on Buf but the app encoder never calls them.

"sapp" (i4 0x73617070) | version (i4 0x0003)
schema:  u1 kitCount, then per kit: cstr name, i4 checksum
u2 maxId
components (ascending id, NOT tree order), each:
    u2 id | u1 kitId | u1 typeId
    cstr name | u2 parentId | u2 firstChildId | u2 nextSiblingId   (0xffff = none)
    config prop values in slot-id order, bare - no names, no ids
    u1 ';'
u2 0xffff
links: u2 fromComp | u1 fromSlot | u2 toComp | u1 toSlot
u2 0xffff
u1 '.'

Values: bool -> u1 (0/1, 2 = null) | byte -> u1 | short -> u2 | int -> i4 | long -> i8 | float -> f4 | double -> f8 | Buf -> u2 len + raw bytes | asStr -> u2 (len+1) + ASCII + NUL.

Slot flags (SlotManifest.flagsToString): a = action, c = config, s = asStr, o = operator.

Three things that will bite you

Kit order is normative. sys at index 0, everything else alphabetical (Schema.sortKits). Kit id is the position in that sorted list, and every component record references it. Document order of the <schema> block in the SAX is irrelevant.

Slot ids come from flattening. Type.resolveSlots inherits base slots then appends declared ones; the resulting index is the id written into links. An action override reuses the inherited id rather than appending (Type.addSlot) — get that wrong and every subsequent slot id shifts.

Missing prop is not null. When a <prop> is absent the value is the manifest's default attribute, or failing that Value.defaultForType -> zero. null (NaN, 0x7fc00000 for float) only when the SAX literally says val="null". This was the single bug between "same length" and "byte identical".

Not covered

Only what test_normal.sax exercises is proven. Untested: action overrides, Buf-typed props (base64 path is written but unexercised), non-ASCII strings (Sedona Str is ASCII-only and will raise), and apps whose component ids exceed the 256-entry lookup table.

Alternative

If a JRE is present, sedona/bin/sedonac.exe <file.sax|.sab> converts either direction off the file extension, and additionally validates the app (schema resolution, RAM/FLASH sizing) in a way this encoder does not.