85 uint32_t minimum = 0U;
105 *out_minimum = minimum;
133 if (position >= end) {
138 uint32_t minimum = 0U;
143 if ((position + used) > end) {
146 for (
size_t i = 1U; i < used; ++i) {
147 const uint8_t
byte = source[position + i];
163 return ((
size_t)span.
offset <= source_len) &&
164 ((size_t)span.
length <= (source_len - (size_t)span.
offset));
187 out[0] = (uint8_t)cp;
225 const uint32_t value = (uint32_t)c;
226 if ((c >= (uint8_t)
'0') && (c <= (uint8_t)
'9')) {
227 return value - (uint32_t)(uint8_t)
'0';
229 if ((base == 16U) && (c >= (uint8_t)
'a') && (c <= (uint8_t)
'f')) {
232 if ((base == 16U) && (c >= (uint8_t)
'A') && (c <= (uint8_t)
'F')) {
262 for (
size_t i = 0U; i < length; ++i) {
263 if (source[offset + i] != (uint8_t)literal[i]) {
294 static const char*
const names[] = {
"amp;",
"lt;",
"gt;",
"quot;",
"apos;"};
295 static const uint32_t cps[] = {
'&',
'<',
'>',
'"',
'\''};
296 if ((position + 2U) >= end) {
299 for (
size_t i = 0U; i < (
sizeof(names) /
sizeof(names[0])); ++i) {
300 const size_t length =
strlen(names[i]);
301 if (((position + 1U + length) <= end) &&
304 *out_used = length + 1U;
308 if (source[position + 1U] != (uint8_t)
'#') {
311 size_t cursor = position + 2U;
314 if ((cursor < end) && ((source[cursor] == (uint8_t)
'x') || (source[cursor] == (uint8_t)
'X'))) {
318 const size_t first_digit = cursor;
320 while ((cursor < end) && (source[cursor] != (uint8_t)
';')) {
325 cp = (cp * base) + digit;
332 *out_used = (cursor - position) + 1U;
374 uint8_t bytes[4] = {};
377 if (source[cursor] == (uint8_t)
'&') {
391 (void)
memcpy(bytes, &source[cursor], count);
393 if ((destination !=
nullptr) && !*clipped && ((*output + count) >= capacity)) {
398 destination[*output] =
'\0';
400 if ((destination !=
nullptr) && !*clipped) {
401 (void)
memcpy(&destination[*output], bytes, count);
403 if ((destination ==
nullptr) || !*clipped) {
438 bool clipped =
false;
439 const size_t end = (size_t)span.
offset + (
size_t)span.
length;
440 if ((destination !=
nullptr) && (capacity == 0U)) {
443 for (
size_t cursor = span.
offset; cursor < end;) {
459 if (destination !=
nullptr) {
460 destination[output] =
'\0';
462 *out_length = output;
493 if (source[cursor->
position] != (uint8_t)
'&') {
518 if ((source ==
nullptr) || (destination ==
nullptr) || (out_length ==
nullptr)) {
524 return internal_decode(source, span, destination, capacity,
false, out_length);
534 if ((source ==
nullptr) || (destination ==
nullptr) || (out_length ==
nullptr)) {
540 return internal_decode(source, span, destination, capacity,
true, out_length);
546 if ((source ==
nullptr) || (out_length ==
nullptr)) {
557 if ((source ==
nullptr) || (literal ==
nullptr) || !
priv_xml_span_valid(source_len, span)) {
560 const size_t length =
strlen(literal);
561 return ((
size_t)span.
length == length) &&
573 uint32_t offset = span.
offset;
574 uint32_t length = span.
length;
575 for (uint32_t i = 0U; i < span.
length; ++i) {
576 if (source[span.
offset + i] == (uint8_t)
':') {
577 offset = span.
offset + i + 1U;
578 length = span.
length - i - 1U;
586 if (source ==
nullptr) {
589 size_t left_size = 0U;
590 size_t right_size = 0U;
593 (left_size != right_size)) {
598 for (
size_t i = 0U; i < left_size; ++i) {
612 size_t cursor = start;
613 while (cursor < end) {
Annotation-attribute framework macros for ra8-firmware.
#define RA8_PRIV
Module-private helper: shared across TUs but only inside one library.
#define RA8_INTERNAL
Marker that a function is intended to be static (file-local).
@ k_ra8_err_no_mem
Static buffer exhausted (no dynamic memory on this project).
@ k_ra8_err_validation_failed
Validation rule failed (caller-supplied invariant not satisfied).
@ k_ra8_ok
Success – operation completed with all postconditions satisfied.
@ k_ra8_err_null_ptr
Pointer was NULL where a valid pointer was required.
ra8_err_codes_t ra8_err_t
Canonical error-return type used by every ra8-firmware API.
size_t strlen(const char *s)
Calculate string length.
void * memcpy(void *dst, const void *src, size_t n)
Copy memory area between non-overlapping regions.
Incremental decoded-byte cursor used for allocation-free comparison.
uint8_t pending_at
Next pending byte.
uint8_t pending[4]
UTF-8 bytes from the current entity.
uint8_t pending_len
Pending-byte count.
size_t end
One-past-last source byte.
size_t position
Next source byte.
Immutable byte span expressed relative to the source.
uint32_t length
Byte count.
uint32_t offset
First byte offset.
Bounded, caller-owned, no-heap XML pull reader.
ra8_err_t xml_decoded_size(const uint8_t *source, size_t source_len, xml_span_t span, size_t *out_length)
Measure the entity-decoded byte count of a bounded span.
bool xml_decoded_equal(const uint8_t *source, size_t source_len, xml_span_t left, xml_span_t right)
Compare two entity-decoded spans from the same immutable source.
static ra8_err_t internal_decode(const uint8_t *source, xml_span_t span, char *destination, size_t capacity, bool truncate, size_t *out_length)
Decode, prefix-decode, or measure one already-bounded span.
bool priv_xml_bytes_equal(const uint8_t *source, size_t offset, const char *literal, size_t length)
Compare bounded source bytes against a literal of known length.
static ra8_err_t internal_utf8_next(const uint8_t *source, size_t end, size_t position, uint32_t *out_cp, size_t *out_used)
Decode one canonical UTF-8 scalar.
static bool internal_xml_char(uint32_t cp)
Test whether a scalar is an XML 1.0 character.
bool xml_span_local_equal(const uint8_t *source, size_t source_len, xml_span_t span, const char *literal)
Compare the namespace-local tail of a bounded span with an ASCII literal.
bool priv_xml_span_valid(size_t source_len, xml_span_t span)
Check that a source-relative span is in range.
static size_t internal_utf8(uint32_t cp, uint8_t out[4])
Encode one valid Unicode scalar as UTF-8.
ra8_err_t priv_xml_raw(const uint8_t *source, size_t start, size_t end)
Validate canonical UTF-8 XML 1.0 characters over a byte range.
bool xml_span_equal(const uint8_t *source, size_t source_len, xml_span_t span, const char *literal)
Compare a bounded span with an exact ASCII literal.
static ra8_err_t internal_entity(const uint8_t *source, size_t end, size_t position, uint32_t *out_cp, size_t *out_used)
Decode one entity beginning at a bounded position.
static ra8_err_t internal_utf8_lead(uint8_t lead, uint32_t *out_cp, size_t *out_used, uint32_t *out_minimum)
Classify one UTF-8 lead byte into its scalar width and payload.
ra8_err_t xml_decode(const uint8_t *source, size_t source_len, xml_span_t span, char *destination, size_t capacity, size_t *out_length)
Entity-decode a source span into a bounded NUL-terminated buffer.
static ra8_err_t internal_decode_one(const uint8_t *source, size_t end, size_t cursor, char *destination, size_t capacity, bool truncate, size_t *output, bool *clipped, size_t *out_used)
Decode one character or entity and append it to the destination.
static uint32_t internal_digit(uint8_t c, uint32_t base)
Convert one numeric-reference digit.
static ra8_err_t internal_decoded_byte(const uint8_t *source, priv_decode_cursor_t *cursor, uint8_t *out)
Return one entity-decoded byte from a comparison cursor.
ra8_err_t xml_decode_prefix(const uint8_t *source, size_t source_len, xml_span_t span, char *destination, size_t capacity, size_t *out_length)
Decode the longest complete prefix that fits the destination.
Private lexical seams shared by the bounded XML reader.
@ k_priv_xml_decimal_base
Numeric-entity decimal radix.
@ k_priv_utf8_shift_second
Shift for the second payload group.
@ k_priv_xml_scalar_max
Last Unicode scalar.
@ k_priv_utf8_continuation_tag
Continuation tag and ASCII ceiling.
@ k_priv_utf8_two_lead_tag
Encoded two-byte lead tag.
@ k_priv_xml_bmp_second_min
First scalar after surrogates.
@ k_priv_utf8_scalar_mask
Scalar bits per continuation byte.
@ k_priv_utf8_three_lead_min
First three-byte lead.
@ k_priv_utf8_shift_third
Shift for the third payload group.
@ k_priv_xml_bmp_second_max
Last permitted BMP scalar.
@ k_priv_xml_line_feed
XML line-feed character.
@ k_priv_utf8_four_lead_min
First four-byte lead.
@ k_priv_xml_printable_min
First ordinary XML character.
@ k_priv_utf8_four_lead_tag
Encoded four-byte lead tag.
@ k_priv_utf8_two_lead_min
First canonical two-byte lead.
@ k_priv_xml_tab
XML tab character.
@ k_priv_utf8_four_lead_max
Last canonical four-byte lead.
@ k_priv_utf8_two_payload_mask
Payload bits in a two-byte lead.
@ k_priv_utf8_four_payload_mask
Payload bits in a four-byte lead.
@ k_priv_utf8_three_lead_tag
Encoded three-byte lead tag.
@ k_priv_utf8_three_payload_mask
Payload bits in a three-byte lead.
@ k_priv_utf8_three_lead_max
Last three-byte lead.
@ k_priv_utf8_three_scalar_min
First scalar needing three bytes.
@ k_priv_xml_bmp_first_max
Last scalar before surrogates.
@ k_priv_xml_carriage_return
XML carriage-return character.
@ k_priv_utf8_continuation_mask
Continuation tag mask.
@ k_priv_utf8_two_lead_max
Last two-byte lead.
@ k_priv_xml_supplementary_min
First supplementary scalar.