UXData
UXData is a growable byte buffer: append, read back, slice, compare, render as
hex. It has the shape of NSData/NSMutableData.
#use <UXKit> // or #import "UXData.xc"Overview
Section titled “Overview”UXData* d = UXData.fromString((u8*)"GEM");d.appendByte(0);d.appendByte(255);
d.length(); // 5d.toHex(); // "47454d00ff"d.subdata(0, 3); // "GEM"Binary pasteboard payloads, serialised structures and file contents travel in a
UXData. The string-only classes cannot carry them.
Bytes, not characters
Section titled “Bytes, not characters”A string stops at the first 0. A UXData has an explicit length, so a zero
byte is a byte like any other.
Anything with an embedded NUL (a length-prefixed record, a binary header, an
image) cannot travel as a u8* without losing its tail at the first zero. This
class exists to carry such data.
UXData.fromString(s); // takes the bytes up to the NULUXData.fromBytes(p, n); // takes exactly n bytes, zeros includedfromString is the bridge in; toHex is a readable bridge out. There is no
toString, because a buffer with a zero in the middle has no faithful string
form.
There is no string literal for an arbitrary byte
Section titled “There is no string literal for an arbitrary byte”Both candidate spellings mean something else:
"\xff" // not valid: \xNN is ASCII by definition, 00-7F only"\u00ff" // TWO bytes — 195 191 — \u is a CODE POINT, UTF-8 encodedA string literal is UTF-8 text, so it cannot spell the single byte 0xFF. This
is a property of the language. appendByte and
fromBytes are the intended way to build binary data.
A character literal is different: '\u00ff' is the code point as a u8,
which is 255, and it composes as expected:
d.appendByte('\u00ff'); // one byte, 255Capacity doubles
Section titled “Capacity doubles”Growth doubles the buffer, so a sequence of appends amortises to O(1) each instead of reallocating per byte.
withCapacity pre-sizes the buffer when you know roughly how
much is coming, which avoids the doubling. It sets capacity, not length: a
withCapacity(1024) still has length() == 0.
Slicing clamps
Section titled “Slicing clamps”d.subdata(2, 999).length(); // whatever is actually thereAn over-long range is clamped to the end instead of reading past it, so
subdata(start, veryLarge) is the idiom for “the rest from here”.
The result is a copy, independent of the original. Appending to the source afterwards does not change it.
Comparison is by content
Section titled “Comparison is by content”slice.isEqualTo(other); // same length, same bytesComparison does not use identity or pointers. Two buffers built separately from the same bytes are equal, which a pasteboard round-trip test needs.
Topics
Section titled “Topics”withCapacity · fromBytes · fromString · appendByte · appendBytes · appendData · subdata · isEqualTo · toHex · length · byteAt · bytes
withCapacity
Section titled “withCapacity”static UXData* withCapacity(i32 n)Empty, with room for n bytes.
fromBytes
Section titled “fromBytes”static UXData* fromBytes(u8* src, i32 n)n bytes, copied. Zeros included.
fromString
Section titled “fromString”static UXData* fromString(u8* s)The bytes up to the terminating NUL, not including it.
appendByte
Section titled “appendByte”void appendByte(u8 b)One byte. The clearest way to build a small binary blob, and it can carry every byte value.
appendBytes
Section titled “appendBytes”void appendBytes(u8* src, i32 n)appendData
Section titled “appendData”void appendData(UXData* o)Concatenate another buffer. The source is unchanged.
subdata
Section titled “subdata”UXData* subdata(i32 start, i32 n)A copy of a range, clamped to what exists.
isEqualTo
Section titled “isEqualTo”bool isEqualTo(UXData* o)u8* toHex(void)Lowercase hex, two characters per byte, no separators and no prefix. A fresh string each call.
It serves as both a debugging tool and a readable serialisation: you can paste a
UXData printed as hex into a test.
length
Section titled “length”i32 length(void)Bytes held, not capacity.
byteAt
Section titled “byteAt”u8 byteAt(i32 i)One byte, bounds-checked: an index outside the buffer reads as 0 instead
of faulting. A loop that runs one past the end gives a wrong answer instead of
a crash. That suits a format parser walking a buffer whose length it is still
working out.
u8* bytes(void)The live internal buffer, not a copy. Use it to hand the bytes to something that wants a plain pointer, such as a write syscall or a hash.
Read the caution above before storing it anywhere: an
append may reallocate and leave it dangling. bytes() is also not
NUL-terminated, so treat it as a pointer plus length, never as a
string.
Example
Section titled “Example”data: len=7 hex=47454d000102ffslice(0,3): len=3 hex=47454dequal=1 differs from whole=0joined hex=61626364 over-long slice len=547454d00 is GEM followed by a zero byte, which a u8* could not carry.
The program is website/site/examples/uxkit/toolbox.xc; the doc-examples
gate compiles it, and the output above is what it prints.
Conforms to
Section titled “Conforms to”- A plain class (not an
Objectsubclass)
See also
Section titled “See also”UXPasteboard: the main consumer of binary payloadsUXText: the string counterpartUXJSON: a text serialisation, when the payload does not have to be binary