26 return (c == (uint8_t)
' ') || (c == (uint8_t)
'\t') || (c == (uint8_t)
'\n') ||
32 return ((c >= (uint8_t)
'A') && (c <= (uint8_t)
'Z')) ||
33 ((c >= (uint8_t)
'a') && (c <= (uint8_t)
'z'));
44 (c == (uint8_t)
'.') || (c == (uint8_t)
'-');
52 size_t cursor = start + 1U;
53 bool saw_colon =
false;
54 while (cursor < end) {
55 const uint8_t
byte = source[cursor];
58 }
else if ((
byte == (uint8_t)
':') && !saw_colon && ((cursor + 1U) < end) &&
72 if ((event !=
nullptr) && (cursor !=
nullptr)) {
73 cursor->
position =
event->name.offset +
event->name.length;
100 uint32_t cursor = *position;
104 if ((cursor >= end) || (source[cursor] != (uint8_t)
'=')) {
111 if ((cursor >= end) || ((source[cursor] != (uint8_t)
'\'') && (source[cursor] != (uint8_t)
'"'))) {
114 const uint8_t quote = source[cursor];
116 const uint32_t value_start = cursor;
117 while ((cursor < end) && (source[cursor] != quote)) {
118 if (source[cursor] == (uint8_t)
'<') {
127 *position = cursor + 1U;
137 uint32_t position = cursor->
position;
141 const uint32_t name_start = position;
142 size_t name_end = 0U;
146 position = (uint32_t)name_end;
162 uint16_t prior_count)
166 const uint32_t end =
event->markup.offset +
event->markup.length - 1U;
167 for (uint16_t i = 0U; i < prior_count; ++i) {
188 if ((source ==
nullptr) || (event ==
nullptr) || (cursor ==
nullptr) ||
189 (out_attribute ==
nullptr) || (out_has_value ==
nullptr)) {
193 *out_has_value =
false;
200 const uint32_t end =
event->markup.offset +
event->markup.length - 1U;
210 for (
size_t i = start + 1U; i < length; ++i) {
211 const uint8_t
byte = source[i];
218 if ((
byte == (uint8_t)
'\'') || (
byte == (uint8_t)
'"')) {
222 if (
byte == (uint8_t)
'>') {
235 const uint32_t end =
event->markup.offset +
event->markup.length - 1U;
238 uint32_t position = cursor.
position;
242 if ((position >= end) || (source[position] == (uint8_t)
'/')) {
249 if ((err !=
k_ra8_ok) || (count == UINT16_MAX) ||
257 if ((cursor.
position >= end) || (source[cursor.
position] != (uint8_t)
'/')) {
268 event->attribute_count = count;
274 size_t cursor = reader->
position + 1U;
275 const size_t name_start = cursor;
283 event->name = (
xml_span_t){(uint32_t)name_start, (uint32_t)(cursor - name_start)};
289 event->self_closing = ((tail > cursor) && (reader->
source[tail - 1U] == (uint8_t)
'/')) ? 1U : 0U;
315 size_t cursor = reader->
position + 2U;
316 const size_t name_start = cursor;
320 const size_t name_end = cursor;
324 if ((cursor != end) || (reader->
stack_size == 0U)) {
328 const size_t name_length = name_end - name_start;
337 event->name = (
xml_span_t){(uint32_t)name_start, (uint32_t)name_length};
349 const char* terminator,
352 const size_t term_len =
strlen(terminator);
353 for (
size_t i = start; (i + term_len) <= length; ++i) {
364 const size_t content = reader->
position + 4U;
370 if ((term > content) && (reader->
source[term - 1U] == (uint8_t)
'-')) {
373 for (
size_t i = content; (i + 1U) < term; ++i) {
374 if ((reader->
source[i] == (uint8_t)
'-') && (reader->
source[i + 1U] == (uint8_t)
'-')) {
387 return ((end - start) == 3U) && ((source[start] | 0x20U) == (uint8_t)
'x') &&
388 ((source[start + 1U] | 0x20U) == (uint8_t)
'm') &&
389 ((source[start + 2U] | 0x20U) == (uint8_t)
'l');
404 bool* saw_standalone)
410 if (!*saw_encoding && !*saw_standalone &&
412 *saw_encoding =
true;
415 if (!*saw_standalone &&
xml_span_equal(source, source_len, attribute->
name,
"standalone")) {
416 *saw_standalone =
true;
426 const bool initial = (reader->
position == 0U) ||
434 bool saw_encoding =
false;
435 bool saw_standalone =
false;
467 const size_t target_start = reader->
position + 2U;
474 size_t target_end = 0U;
509 event->markup = (
xml_span_t){(uint32_t)content, (uint32_t)(term - content)};
517 const size_t pos = reader->
position;
518 *out_emitted =
false;
533 if (((pos + 2U) <= reader->
source_len) && (reader->
source[pos + 1U] == (uint8_t)
'?')) {
541 const size_t start = reader->
position;
552 for (
size_t i = start; (i + 2U) < reader->
position; ++i) {
553 if ((reader->
source[i] == (uint8_t)
']') && (reader->
source[i + 1U] == (uint8_t)
']') &&
554 (reader->
source[i + 2U] == (uint8_t)
'>')) {
559 for (
size_t i = start; i < reader->
position; ++i) {
567 event->markup = span;
572 const uint8_t* source,
576 if ((reader ==
nullptr) || (source ==
nullptr) || (workspace ==
nullptr)) {
579 if ((source_len == 0U) || (source_len > UINT32_MAX)) {
582 *reader = (
xml_reader_t){.source = source, .source_len = source_len, .workspace = workspace};
592 if ((reader ==
nullptr) || (out_event ==
nullptr)) {
604 if ((next == (uint8_t)
'!') || (next == (uint8_t)
'?')) {
605 bool emitted =
false;
618 if (next == (uint8_t)
'/') {
static ra8_err_t internal_space(void *ctx, fw_fs_space_t *out)
Annotation-attribute framework macros for ra8-firmware.
#define RA8_INTERNAL
Marker that a function is intended to be static (file-local).
@ 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.
@ k_ra8_err_invalid_size
Invalid size parameter (too large, too small, or misaligned).
ra8_err_codes_t ra8_err_t
Canonical error-return type used by every ra8-firmware API.
int memcmp(const void *a, const void *b, size_t n)
Compare bytes in two memory areas.
size_t strlen(const char *s)
Calculate string length.
Mutable cursor for one start event's attributes.
uint16_t emitted
Attributes already returned.
uint32_t position
Next scan position.
Source-order attribute view.
xml_span_t value
Quoted value excluding delimiters.
xml_span_t name
Attribute name.
uint16_t attribute_count
Source-order attributes on start.
xml_span_t markup
Complete markup span, or text payload.
uint8_t self_closing
One for an empty-element start.
xml_span_t name
Element name for start/end.
One open-element identity retained for close-tag validation.
uint16_t name_length
Element-name byte count.
uint32_t name_offset
Element-name offset in the source.
Pull-reader state; initialise before each pass.
uint8_t finished
End validation complete.
uint8_t root_count
Completed/started roots.
uint16_t stack_size
Open element count.
const uint8_t * source
Immutable source bytes.
xml_workspace_t * workspace
Caller-owned stack.
size_t source_len
Source byte count.
size_t position
Next scan position.
uint8_t declaration_seen
One after XML declaration.
uint8_t root_closed
One after root close.
Immutable byte span expressed relative to the source.
uint32_t length
Byte count.
uint32_t offset
First byte offset.
Exactly bounded caller-owned nesting storage.
xml_frame_t frames[k_xml_workspace_frames]
Open-element stack.
static ra8_err_t internal_pi(xml_reader_t *reader)
static bool internal_name_start(uint8_t c)
static bool internal_xml_target(const uint8_t *source, size_t start, size_t end)
static ra8_err_t internal_markup_end(const uint8_t *source, size_t length, size_t start, size_t *out_end)
void xml_attr_begin(const xml_event_t *event, xml_attr_cursor_t *cursor)
Initialise source-order attribute iteration for a start event.
static ra8_err_t internal_end(xml_reader_t *reader, size_t end, xml_event_t *event)
static bool internal_space(uint8_t c)
static ra8_err_t internal_comment(xml_reader_t *reader)
static ra8_err_t internal_attr_parse(const uint8_t *source, size_t source_len, uint32_t end, xml_attr_cursor_t *cursor, xml_attribute_t *out)
static ra8_err_t internal_terminator(const uint8_t *source, size_t length, size_t start, const char *terminator, size_t *out_start)
static ra8_err_t internal_start(xml_reader_t *reader, size_t end, xml_event_t *event)
ra8_err_t xml_attr_next(const uint8_t *source, size_t source_len, const xml_event_t *event, xml_attr_cursor_t *cursor, xml_attribute_t *out_attribute, bool *out_has_value)
Return the next source-order attribute.
static bool internal_ascii_letter(uint8_t c)
static bool internal_attr_duplicate(const uint8_t *source, size_t source_len, const xml_event_t *event, const xml_attribute_t *current, uint16_t prior_count)
ra8_err_t priv_xml_qname(const uint8_t *source, size_t end, size_t start, size_t *out_end)
Scan the supported QName subset over a bounded byte range.
static ra8_err_t internal_cdata(xml_reader_t *reader, xml_event_t *event)
ra8_err_t xml_validate(const uint8_t *source, size_t source_len, xml_workspace_t *workspace)
Validate a complete document before any consumer mutation.
static bool internal_declaration_attr(const uint8_t *source, size_t source_len, const xml_attribute_t *attribute, uint16_t ordinal, bool *saw_encoding, bool *saw_standalone)
static ra8_err_t internal_text(xml_reader_t *reader, xml_event_t *event)
static ra8_err_t internal_attributes(const uint8_t *source, size_t source_len, xml_event_t *event)
static bool internal_name_continue(uint8_t c)
static ra8_err_t internal_special(xml_reader_t *reader, xml_event_t *event, bool *out_emitted)
static ra8_err_t internal_attr_value(const uint8_t *source, uint32_t end, uint32_t *position, xml_attribute_t *out)
Parse the equals sign, quote, and value of one XML attribute.
static ra8_err_t internal_declaration(xml_reader_t *reader, size_t target_end, size_t term)
ra8_err_t xml_reader_init(xml_reader_t *reader, const uint8_t *source, size_t source_len, xml_workspace_t *workspace)
Initialise a pull pass over immutable bytes.
static bool internal_encoding(const uint8_t *source, xml_span_t value)
ra8_err_t xml_reader_next(xml_reader_t *reader, xml_event_t *out_event)
Return the next semantic event and validate syntax incrementally.
Bounded, caller-owned, no-heap XML pull reader.
@ k_xml_max_element_depth
Accepted element levels, including root.
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.
@ k_xml_event_cdata
CDATA payload.
@ k_xml_event_start
Element start.
@ k_xml_event_none
No event / end of source.
@ k_xml_event_text
Character-data run.
@ k_xml_event_end
Element end.
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.
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.
bool priv_xml_span_valid(size_t source_len, xml_span_t span)
Check that a source-relative span is in range.
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.
ra8_err_t priv_xml_doctype(xml_reader_t *reader)
Validate and skip one supported pre-root external DOCTYPE.
Private lexical seams shared by the bounded XML reader.
@ k_priv_xml_doctype_open_bytes
Bytes in the DOCTYPE opener.
@ k_priv_xml_encoding_bytes
Bytes in the UTF-8 encoding label.
@ k_priv_xml_cdata_open_bytes
Bytes in the CDATA opener.
@ k_priv_utf8_bom_second
Second UTF-8 BOM byte.
@ k_priv_utf8_bom_first
First UTF-8 BOM byte.
@ k_priv_utf8_bom_third
Third UTF-8 BOM byte.
Private contracts for the bounded XML reader implementation.