Skip to content

UXRscV2

UXRscV2 reads the UXNB chunk (v2, and from 0.7 v3) out of a .rsc file, entirely in portable code. It reads the bytes in place; to load a form, use UXRsc.

#use <UXKit> // or #import "UXRscV2.xc"

v1’s chunk is read by libGEM’s C rscload, whose surface UXRscGem declares. That makes v1 rsc loading GEM-only.

v2 is parsed here, from the raw bytes, with no host dependency. Variant selection, logical-id resolution and validation therefore run, and are gated, on every backend, wasm32 included.

A resource format read by one platform’s C library cannot be used by the other six backends, which is why v2 exists.

The magics differ:

magic
UXNBv2 and v3 — invisible to the C v1 reader
XGNBv1 — this parser reports it as version 1

A v2 file cannot confuse the old reader. A v1 file handed to this parser is presented per the spec’s compatibility rule: every tree its own single-variant form of class any.

There is no migration step. Old resources keep working, new ones gain variants, and the same code path consumes both.

From 0.7 the chunk can be version 3. Three things change:

  • A connection carries a scope, the layout themes it binds in. connScope reads it, and every v2 connection reads as 0, all themes.
  • A top-level object carries a label, the name the designer shows.
  • The chunk can carry extension sections, {tag, size, body}, which a reader skips by size when it does not know the tag.

The classic body is unchanged, so a v3 file is still a plain .rsc to a GEM AES.

i32 tree = rsc.selectTree(formId, klass, &chosenClass);

A form can carry several variants (a phone layout, a tablet layout, a desktop one). selectTree picks the best available for a requested class by walking a fallback chain of up to four steps.

An rsc file that only ships a desktop variant still loads on a phone by falling back. An rsc file that ships both gets the right one with no if in the application.

chosenClass reports which variant was used. This matters when the answer was a fallback rather than the exact match: it separates “there is a phone layout” from “the desktop layout is in use on a phone”.

A form with no usable variant returns -1 rather than guessing.

A phone or tablet layout can also come in portrait and landscape trees. A rotation can re-nest a layout, not just stretch it, so each orientation gets a whole tree of its own, exactly as each form factor does.

i32 tree = rsc.selectTreeOriented(formId, gDriver.formFactorClass(),
gDriver.orientation(), &cls, &orient);

Within each class of the fallback chain the order is:

  1. a tree for the current orientation;
  2. a tree with no orientation, drawn to work both ways;
  3. the other orientation’s tree.

Only then does selection move on to the next class. A tablet held upright with only a landscape tablet layout therefore gets that layout, not the desktop’s.

The orientation rides in the top two bits of a variant’s class word (0 none, 1 portrait, 2 landscape). Files written before it existed have 0 there and read unchanged. selectTree masks those bits off, so code that ignores orientation keeps working.

i32 obj = rsc.objForLogical(tree, logicalId);
// -1 means the variant genuinely does not have that control

A control is referred to by a logical id instead of its index in a tree, so the same code binds to it in every variant even though the layouts differ.

-1 is a normal answer, not an error:

Borrowing keeps loading an rsc file cheap: a resource file with hundreds of names costs no allocations to parse.

All multi-byte fields are big-endian, matching the .rsc body. The parser is byte-order-independent, and a resource built on one machine loads on another.

open · parse · version · formCount · formAt · formOffById · formName · selectTree · selectTreeOriented · chainAt / chain · classOf · orientOf · objForLogical · resolveView · connScope · connInScope · themeBit · topObjectLabel · extCount · extTag / extSize / extBody · str

static UXRscV2* open(u8* rsc, u32 rscLen)

Finds the chunk in a resource file. The buffer is borrowed; see the caution.

bool parse(void)

Reads the header and the section offsets. Returns false on a malformed chunk. Check this before trusting anything else.

i32 version(void)

1 for a v1 file presented through the compatibility rule, otherwise the chunk’s own version, 2 or 3.

i32 formCount(void)
u32 formAt(i32 f)

The byte offset of the i-th form record.

u32 formOffById(i32 formId)

By id rather than by index. 0 when absent.

u8* formName(i32 formId)

Borrowed, like every string here.

i32 selectTree(i32 formId, i32 klass, i32* chosenClass)

The best variant for a form-factor class, ignoring orientation. See above.

i32 selectTreeOriented(i32 formId, i32 klass, i32 orient, i32* chosenClass, i32* chosenOrient)

The best variant for a class held at an orientation (UX_ORIENT_*). See Orientation is a second axis. chosenOrient reports the orientation of the tree that won.

i32 chainAt(i32 klass, i32 step)
static i32 chain(i32 klass, i32 step)

The form-factor class at step (0 to 3) of klass’s fallback chain.

static i32 classOf(u32 word)

The form-factor class in a variant’s class word: its low 14 bits.

static i32 orientOf(u32 word)

The orientation in a variant’s class word: its top two bits.

i32 objForLogical(i32 tree, i32 logicalId)

An object index within a tree, or -1.

i32 resolveView(u32 refAt, i32 tree)

Resolves a reference record to an object. References carry a space saying what they point at: a view by coordinate, a top-level object, the owner, or a view by logical id. This lets a connection survive a variant that moved things around.

u32 connScope(i32 i)

Connection i’s scope: bit class * 3 + orientation per theme, 0 for all.

bool connInScope(i32 i, i32 klass, i32 orient)

Whether connection i binds in a theme.

static u32 themeBit(i32 klass, i32 orient)
u8* topObjectLabel(i32 i)

The designer’s name for top-level object i; "" before v3.

i32 extCount(void)
u32 extTag(i32 i)
u32 extSize(i32 i)
u32 extBody(i32 i)

Extension section i: its tag, its size, and the offset of its body in the buffer.

u8* str(u32 off)

A string from the chunk’s table, borrowed.

  • UXRsc: loading a form on every backend
  • UXRscGem: v1, and the host surface that makes it GEM-only
  • UXViewDriver: formFactorClass, which supplies the class selectTree is asked for
  • UXViewTree: what a loaded rsc becomes