ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
xml.c
Go to the documentation of this file.
1
15#include "xml.h"
16
17#include <limits.h>
18#include <string.h>
19
20#include "ra8_attributes.h"
21#include "xml_internal.h"
22#include "xml_reader_internal.h"
23
24RA8_INTERNAL static bool internal_space(uint8_t c)
25{
26 return (c == (uint8_t)' ') || (c == (uint8_t)'\t') || (c == (uint8_t)'\n') ||
27 (c == (uint8_t)'\r');
28}
29
30RA8_INTERNAL static bool internal_ascii_letter(uint8_t c)
31{
32 return ((c >= (uint8_t)'A') && (c <= (uint8_t)'Z')) ||
33 ((c >= (uint8_t)'a') && (c <= (uint8_t)'z'));
34}
35
36RA8_INTERNAL static bool internal_name_start(uint8_t c)
37{
38 return internal_ascii_letter(c) || (c == (uint8_t)'_');
39}
40
42{
43 return internal_name_start(c) || ((c >= (uint8_t)'0') && (c <= (uint8_t)'9')) ||
44 (c == (uint8_t)'.') || (c == (uint8_t)'-');
45}
46
47ra8_err_t priv_xml_qname(const uint8_t* source, size_t end, size_t start, size_t* out_end)
48{
49 if ((start >= end) || !internal_name_start(source[start])) {
51 }
52 size_t cursor = start + 1U;
53 bool saw_colon = false;
54 while (cursor < end) {
55 const uint8_t byte = source[cursor];
56 if (internal_name_continue(byte)) {
57 ++cursor;
58 } else if ((byte == (uint8_t)':') && !saw_colon && ((cursor + 1U) < end) &&
59 internal_name_start(source[cursor + 1U])) {
60 saw_colon = true;
61 cursor += 2U;
62 } else {
63 break;
64 }
65 }
66 *out_end = cursor;
67 return k_ra8_ok;
68}
69
70void xml_attr_begin(const xml_event_t* event, xml_attr_cursor_t* cursor)
71{
72 if ((event != nullptr) && (cursor != nullptr)) {
73 cursor->position = event->name.offset + event->name.length;
74 cursor->emitted = 0U;
75 }
76}
77
98internal_attr_value(const uint8_t* source, uint32_t end, uint32_t* position, xml_attribute_t* out)
99{
100 uint32_t cursor = *position;
101 while ((cursor < end) && internal_space(source[cursor])) {
102 ++cursor;
103 }
104 if ((cursor >= end) || (source[cursor] != (uint8_t)'=')) {
106 }
107 ++cursor;
108 while ((cursor < end) && internal_space(source[cursor])) {
109 ++cursor;
110 }
111 if ((cursor >= end) || ((source[cursor] != (uint8_t)'\'') && (source[cursor] != (uint8_t)'"'))) {
113 }
114 const uint8_t quote = source[cursor];
115 ++cursor;
116 const uint32_t value_start = cursor;
117 while ((cursor < end) && (source[cursor] != quote)) {
118 if (source[cursor] == (uint8_t)'<') {
120 }
121 ++cursor;
122 }
123 if (cursor >= end) {
125 }
126 out->value = (xml_span_t){value_start, cursor - value_start};
127 *position = cursor + 1U;
128 return k_ra8_ok;
129}
130
131RA8_INTERNAL static ra8_err_t internal_attr_parse(const uint8_t* source,
132 size_t source_len,
133 uint32_t end,
134 xml_attr_cursor_t* cursor,
135 xml_attribute_t* out)
136{
137 uint32_t position = cursor->position;
138 while ((position < end) && internal_space(source[position])) {
139 ++position;
140 }
141 const uint32_t name_start = position;
142 size_t name_end = 0U;
143 if (priv_xml_qname(source, end, name_start, &name_end) != k_ra8_ok) {
145 }
146 position = (uint32_t)name_end;
147 out->name = (xml_span_t){name_start, position - name_start};
148 ra8_err_t err = internal_attr_value(source, end, &position, out);
149 if (err == k_ra8_ok) {
150 cursor->position = position;
151 ++cursor->emitted;
152 size_t decoded = 0U;
153 err = xml_decoded_size(source, source_len, out->value, &decoded);
154 }
155 return err;
156}
157
158RA8_INTERNAL static bool internal_attr_duplicate(const uint8_t* source,
159 size_t source_len,
160 const xml_event_t* event,
161 const xml_attribute_t* current,
162 uint16_t prior_count)
163{
164 xml_attr_cursor_t prior = {};
165 xml_attr_begin(event, &prior);
166 const uint32_t end = event->markup.offset + event->markup.length - 1U;
167 for (uint16_t i = 0U; i < prior_count; ++i) {
168 xml_attribute_t attribute = {};
169 if (internal_attr_parse(source, source_len, end, &prior, &attribute) != k_ra8_ok) {
170 return true;
171 }
172 if ((attribute.name.length == current->name.length) && (memcmp(&source[attribute.name.offset],
173 &source[current->name.offset],
174 current->name.length) == 0)) {
175 return true;
176 }
177 }
178 return false;
179}
180
181ra8_err_t xml_attr_next(const uint8_t* source,
182 size_t source_len,
183 const xml_event_t* event,
184 xml_attr_cursor_t* cursor,
185 xml_attribute_t* out_attribute,
186 bool* out_has_value)
187{
188 if ((source == nullptr) || (event == nullptr) || (cursor == nullptr) ||
189 (out_attribute == nullptr) || (out_has_value == nullptr)) {
190 return k_ra8_err_null_ptr;
191 }
192 if (cursor->emitted >= event->attribute_count) {
193 *out_has_value = false;
194 return k_ra8_ok;
195 }
196 if (!priv_xml_span_valid(source_len, event->markup) ||
197 !priv_xml_span_valid(source_len, event->name) || (event->markup.length == 0U)) {
199 }
200 const uint32_t end = event->markup.offset + event->markup.length - 1U;
201 const ra8_err_t err = internal_attr_parse(source, source_len, end, cursor, out_attribute);
202 *out_has_value = err == k_ra8_ok;
203 return err;
204}
205
207internal_markup_end(const uint8_t* source, size_t length, size_t start, size_t* out_end)
208{
209 uint8_t quote = 0U;
210 for (size_t i = start + 1U; i < length; ++i) {
211 const uint8_t byte = source[i];
212 if (quote != 0U) {
213 if (byte == quote) {
214 quote = 0U;
215 }
216 continue;
217 }
218 if ((byte == (uint8_t)'\'') || (byte == (uint8_t)'"')) {
219 quote = byte;
220 continue;
221 }
222 if (byte == (uint8_t)'>') {
223 *out_end = i;
224 return k_ra8_ok;
225 }
226 }
228}
229
231internal_attributes(const uint8_t* source, size_t source_len, xml_event_t* event)
232{
233 xml_attr_cursor_t cursor = {};
234 xml_attr_begin(event, &cursor);
235 const uint32_t end = event->markup.offset + event->markup.length - 1U;
236 uint16_t count = 0U;
237 for (;;) {
238 uint32_t position = cursor.position;
239 while ((position < end) && internal_space(source[position])) {
240 ++position;
241 }
242 if ((position >= end) || (source[position] == (uint8_t)'/')) {
243 cursor.position = position;
244 break;
245 }
246 xml_attribute_t attribute = {};
247 const ra8_err_t err = internal_attr_parse(source, source_len, end, &cursor, &attribute);
248 // mcdc-deactivated: internal_attributes attribute-count saturation guard; it exists to stop `count` wrapping the uint16_t event->attribute_count, and flipping it needs 65535 mutually distinct attributes on ONE element while internal_attr_duplicate re-parses every prior attribute per new one -- a quadratic ~2.1e9-parse input that no bounded unit test can drive.
249 if ((err != k_ra8_ok) || (count == UINT16_MAX) ||
250 internal_attr_duplicate(source, source_len, event, &attribute, count)) {
252 }
253 ++count;
254 }
255 if (event->self_closing != 0U) {
256 // mcdc-deactivated: internal_attributes self-closing slash recheck; the attribute loop above breaks only on `position >= end` or `source[position] == '/'`, and self_closing was set from a non-space '/' that lies inside the still-unscanned range, so the loop necessarily stopped on that slash -- both conditions are constant-false here.
257 if ((cursor.position >= end) || (source[cursor.position] != (uint8_t)'/')) {
259 }
260 ++cursor.position;
261 }
262 while ((cursor.position < end) && internal_space(source[cursor.position])) {
263 ++cursor.position;
264 }
265 if (cursor.position != end) {
267 }
268 event->attribute_count = count;
269 return k_ra8_ok;
270}
271
273{
274 size_t cursor = reader->position + 1U;
275 const size_t name_start = cursor;
276 if ((priv_xml_qname(reader->source, end, name_start, &cursor) != k_ra8_ok) ||
277 (reader->root_closed != 0U) ||
278 ((size_t)reader->stack_size >= (size_t)k_xml_max_element_depth)) {
280 }
281 event->kind = (uint8_t)k_xml_event_start;
282 event->depth = reader->stack_size;
283 event->name = (xml_span_t){(uint32_t)name_start, (uint32_t)(cursor - name_start)};
284 event->markup = (xml_span_t){(uint32_t)reader->position, (uint32_t)(end - reader->position + 1U)};
285 size_t tail = end;
286 while ((tail > cursor) && internal_space(reader->source[tail - 1U])) {
287 --tail;
288 }
289 event->self_closing = ((tail > cursor) && (reader->source[tail - 1U] == (uint8_t)'/')) ? 1U : 0U;
290 const ra8_err_t attr_err = internal_attributes(reader->source, reader->source_len, event);
291 if (attr_err != k_ra8_ok) {
292 return attr_err;
293 }
294 if (reader->stack_size == 0U) {
295 if (reader->root_count != 0U) {
297 }
298 reader->root_count = 1U;
299 }
300 if (event->self_closing != 0U) {
301 if (reader->stack_size == 0U) {
302 reader->root_closed = 1U;
303 }
304 } else {
305 xml_frame_t* frame = &reader->workspace->frames[reader->stack_size];
306 reader->stack_size += 1U;
307 *frame = (xml_frame_t){event->name.offset, (uint16_t)event->name.length, 0U};
308 }
309 reader->position = end + 1U;
310 return k_ra8_ok;
311}
312
313RA8_INTERNAL static ra8_err_t internal_end(xml_reader_t* reader, size_t end, xml_event_t* event)
314{
315 size_t cursor = reader->position + 2U;
316 const size_t name_start = cursor;
317 if (priv_xml_qname(reader->source, end, name_start, &cursor) != k_ra8_ok) {
319 }
320 const size_t name_end = cursor;
321 while ((cursor < end) && internal_space(reader->source[cursor])) {
322 ++cursor;
323 }
324 if ((cursor != end) || (reader->stack_size == 0U)) {
326 }
327 const xml_frame_t* frame = &reader->workspace->frames[reader->stack_size - 1U];
328 const size_t name_length = name_end - name_start;
329 if ((name_length != frame->name_length) ||
330 (memcmp(&reader->source[name_start], &reader->source[frame->name_offset], name_length) !=
331 0)) {
333 }
334 --reader->stack_size;
335 event->kind = (uint8_t)k_xml_event_end;
336 event->depth = reader->stack_size;
337 event->name = (xml_span_t){(uint32_t)name_start, (uint32_t)name_length};
338 event->markup = (xml_span_t){(uint32_t)reader->position, (uint32_t)(end - reader->position + 1U)};
339 if (reader->stack_size == 0U) {
340 reader->root_closed = 1U;
341 }
342 reader->position = end + 1U;
343 return k_ra8_ok;
344}
345
346RA8_INTERNAL static ra8_err_t internal_terminator(const uint8_t* source,
347 size_t length,
348 size_t start,
349 const char* terminator,
350 size_t* out_start)
351{
352 const size_t term_len = strlen(terminator);
353 for (size_t i = start; (i + term_len) <= length; ++i) {
354 if (priv_xml_bytes_equal(source, i, terminator, term_len)) {
355 *out_start = i;
356 return k_ra8_ok;
357 }
358 }
360}
361
363{
364 const size_t content = reader->position + 4U;
365 size_t term = 0U;
366 ra8_err_t err = internal_terminator(reader->source, reader->source_len, content, "-->", &term);
367 if (err != k_ra8_ok) {
368 return err;
369 }
370 if ((term > content) && (reader->source[term - 1U] == (uint8_t)'-')) {
372 }
373 for (size_t i = content; (i + 1U) < term; ++i) {
374 if ((reader->source[i] == (uint8_t)'-') && (reader->source[i + 1U] == (uint8_t)'-')) {
376 }
377 }
378 err = priv_xml_raw(reader->source, content, term);
379 if (err == k_ra8_ok) {
380 reader->position = term + 3U;
381 }
382 return err;
383}
384
385RA8_INTERNAL static bool internal_xml_target(const uint8_t* source, size_t start, size_t end)
386{
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');
390}
391
392RA8_INTERNAL static bool internal_encoding(const uint8_t* source, xml_span_t value)
393{
394 return (value.length == k_priv_xml_encoding_bytes) &&
395 (priv_xml_bytes_equal(source, value.offset, "UTF-8", k_priv_xml_encoding_bytes) ||
396 priv_xml_bytes_equal(source, value.offset, "utf-8", k_priv_xml_encoding_bytes));
397}
398
399RA8_INTERNAL static bool internal_declaration_attr(const uint8_t* source,
400 size_t source_len,
401 const xml_attribute_t* attribute,
402 uint16_t ordinal,
403 bool* saw_encoding,
404 bool* saw_standalone)
405{
406 if (ordinal == 0U) {
407 return xml_span_equal(source, source_len, attribute->name, "version") &&
408 xml_span_equal(source, source_len, attribute->value, "1.0");
409 }
410 if (!*saw_encoding && !*saw_standalone &&
411 xml_span_equal(source, source_len, attribute->name, "encoding")) {
412 *saw_encoding = true;
413 return internal_encoding(source, attribute->value);
414 }
415 if (!*saw_standalone && xml_span_equal(source, source_len, attribute->name, "standalone")) {
416 *saw_standalone = true;
417 return xml_span_equal(source, source_len, attribute->value, "yes") ||
418 xml_span_equal(source, source_len, attribute->value, "no");
419 }
420 return false;
421}
422
424internal_declaration(xml_reader_t* reader, size_t target_end, size_t term)
425{
426 const bool initial = (reader->position == 0U) ||
427 ((reader->position == 3U) && (reader->source[0] == k_priv_utf8_bom_first));
428 // mcdc-deactivated: internal_declaration placement gate; `initial` is only true at offset 0 or at offset 3 behind a BOM, and both declaration_seen and root_count are set by passes that leave reader->position beyond those offsets, so conditions 2 and 3 cannot be true while condition 1 is false. Condition 5 is likewise constant: internal_pi has already rejected `(target_end < term) && !internal_space(source[target_end])`, so reaching here with `target_end < term` implies the byte IS spacing. Only the `target_end >= term` condition varies.
429 if (!initial || (reader->declaration_seen != 0U) || (reader->root_count != 0U) ||
430 (target_end >= term) || !internal_space(reader->source[target_end])) {
432 }
433 xml_attr_cursor_t cursor = {.position = (uint32_t)target_end};
434 bool saw_encoding = false;
435 bool saw_standalone = false;
436 uint16_t count = 0U;
437 while (cursor.position < term) {
438 while ((cursor.position < term) && internal_space(reader->source[cursor.position])) {
439 ++cursor.position;
440 }
441 if (cursor.position == term) {
442 break;
443 }
444 xml_attribute_t attribute = {};
445 const ra8_err_t err =
446 internal_attr_parse(reader->source, reader->source_len, (uint32_t)term, &cursor, &attribute);
447 if ((err != k_ra8_ok) || !internal_declaration_attr(reader->source,
448 reader->source_len,
449 &attribute,
450 count,
451 &saw_encoding,
452 &saw_standalone)) {
454 }
455 ++count;
456 }
457 if (count == 0U) {
459 }
460 reader->declaration_seen = 1U;
461 reader->position = term + 2U;
462 return k_ra8_ok;
463}
464
466{
467 const size_t target_start = reader->position + 2U;
468 size_t term = 0U;
469 ra8_err_t err =
470 internal_terminator(reader->source, reader->source_len, target_start, "?>", &term);
471 if (err != k_ra8_ok) {
472 return err;
473 }
474 size_t target_end = 0U;
475 err = priv_xml_qname(reader->source, term, target_start, &target_end);
476 if ((err != k_ra8_ok) || ((target_end < term) && !internal_space(reader->source[target_end]))) {
478 }
479 if (internal_xml_target(reader->source, target_start, target_end)) {
480 if (!priv_xml_bytes_equal(reader->source, target_start, "xml", 3U)) {
482 }
483 return internal_declaration(reader, target_end, term);
484 }
485 err = priv_xml_raw(reader->source, target_end, term);
486 if (err == k_ra8_ok) {
487 reader->position = term + 2U;
488 }
489 return err;
490}
491
493{
494 if (reader->stack_size == 0U) {
496 }
497 const size_t content = reader->position + k_priv_xml_cdata_open_bytes;
498 size_t term = 0U;
499 ra8_err_t err = internal_terminator(reader->source, reader->source_len, content, "]]>", &term);
500 if (err != k_ra8_ok) {
501 return err;
502 }
503 err = priv_xml_raw(reader->source, content, term);
504 if (err != k_ra8_ok) {
505 return err;
506 }
507 event->kind = (uint8_t)k_xml_event_cdata;
508 event->depth = reader->stack_size;
509 event->markup = (xml_span_t){(uint32_t)content, (uint32_t)(term - content)};
510 reader->position = term + 3U;
511 return k_ra8_ok;
512}
513
515internal_special(xml_reader_t* reader, xml_event_t* event, bool* out_emitted)
516{
517 const size_t pos = reader->position;
518 *out_emitted = false;
519 if (((pos + 4U) <= reader->source_len) && priv_xml_bytes_equal(reader->source, pos, "<!--", 4U)) {
520 return internal_comment(reader);
521 }
522 if (((pos + k_priv_xml_cdata_open_bytes) <= reader->source_len) &&
523 priv_xml_bytes_equal(reader->source, pos, "<![CDATA[", k_priv_xml_cdata_open_bytes)) {
524 const ra8_err_t err = internal_cdata(reader, event);
525 *out_emitted = err == k_ra8_ok;
526 return err;
527 }
528 if (((pos + k_priv_xml_doctype_open_bytes) <= reader->source_len) &&
529 priv_xml_bytes_equal(reader->source, pos, "<!DOCTYPE", k_priv_xml_doctype_open_bytes)) {
530 return priv_xml_doctype(reader);
531 }
532 // mcdc-deactivated: internal_special processing-instruction probe; xml_reader_next rejects `(position + 1U) >= source_len` before dispatching here, so `(pos + 2U) <= source_len` holds on every reachable call and only the '?' byte test varies.
533 if (((pos + 2U) <= reader->source_len) && (reader->source[pos + 1U] == (uint8_t)'?')) {
534 return internal_pi(reader);
535 }
537}
538
540{
541 const size_t start = reader->position;
542 while ((reader->position < reader->source_len) &&
543 (reader->source[reader->position] != (uint8_t)'<')) {
544 ++reader->position;
545 }
546 const xml_span_t span = {(uint32_t)start, (uint32_t)(reader->position - start)};
547 size_t decoded = 0U;
548 const ra8_err_t err = xml_decoded_size(reader->source, reader->source_len, span, &decoded);
549 if (err != k_ra8_ok) {
550 return err;
551 }
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)'>')) {
556 }
557 }
558 if (reader->stack_size == 0U) {
559 for (size_t i = start; i < reader->position; ++i) {
560 if (!internal_space(reader->source[i])) {
562 }
563 }
564 }
565 event->kind = (uint8_t)k_xml_event_text;
566 event->depth = reader->stack_size;
567 event->markup = span;
568 return k_ra8_ok;
569}
570
572 const uint8_t* source,
573 size_t source_len,
574 xml_workspace_t* workspace)
575{
576 if ((reader == nullptr) || (source == nullptr) || (workspace == nullptr)) {
577 return k_ra8_err_null_ptr;
578 }
579 if ((source_len == 0U) || (source_len > UINT32_MAX)) {
581 }
582 *reader = (xml_reader_t){.source = source, .source_len = source_len, .workspace = workspace};
583 if ((source_len >= 3U) && (source[0] == k_priv_utf8_bom_first) &&
584 (source[1] == k_priv_utf8_bom_second) && (source[2] == k_priv_utf8_bom_third)) {
585 reader->position = 3U;
586 }
587 return k_ra8_ok;
588}
589
591{
592 if ((reader == nullptr) || (out_event == nullptr)) {
593 return k_ra8_err_null_ptr;
594 }
595 *out_event = (xml_event_t){};
596 while (reader->position < reader->source_len) {
597 if (reader->source[reader->position] != (uint8_t)'<') {
598 return internal_text(reader, out_event);
599 }
600 if ((reader->position + 1U) >= reader->source_len) {
602 }
603 const uint8_t next = reader->source[reader->position + 1U];
604 if ((next == (uint8_t)'!') || (next == (uint8_t)'?')) {
605 bool emitted = false;
606 const ra8_err_t err = internal_special(reader, out_event, &emitted);
607 if ((err != k_ra8_ok) || emitted) {
608 return err;
609 }
610 continue;
611 }
612 size_t end = 0U;
613 const ra8_err_t scan_err =
614 internal_markup_end(reader->source, reader->source_len, reader->position, &end);
615 if (scan_err != k_ra8_ok) {
616 return scan_err;
617 }
618 if (next == (uint8_t)'/') {
619 return internal_end(reader, end, out_event);
620 }
621 return internal_start(reader, end, out_event);
622 }
623 // mcdc-deactivated: xml_reader_next end-of-document completeness gate; root_closed is set by the only two ways the element stack can drain back to zero after a root was started (a self-closing root in internal_start, a matching end tag in internal_end), so `stack_size == 0 && root_count == 1 && root_closed == 0` is unreachable and the third condition cannot flip independently.
624 if ((reader->stack_size != 0U) || (reader->root_count != 1U) || (reader->root_closed == 0U)) {
626 }
627 reader->finished = 1U;
628 return k_ra8_ok;
629}
630
631ra8_err_t xml_validate(const uint8_t* source, size_t source_len, xml_workspace_t* workspace)
632{
633 xml_reader_t reader = {};
634 ra8_err_t err = xml_reader_init(&reader, source, source_len, workspace);
635 while (err == k_ra8_ok) {
636 xml_event_t event = {};
637 err = xml_reader_next(&reader, &event);
638 if ((err != k_ra8_ok) || (event.kind == (uint8_t)k_xml_event_none)) {
639 break;
640 }
641 }
642 return err;
643}
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).
Definition ra8_err.h:459
@ k_ra8_ok
Success – operation completed with all postconditions satisfied.
Definition ra8_err.h:119
@ k_ra8_err_null_ptr
Pointer was NULL where a valid pointer was required.
Definition ra8_err.h:478
@ k_ra8_err_invalid_size
Invalid size parameter (too large, too small, or misaligned).
Definition ra8_err.h:167
ra8_err_codes_t ra8_err_t
Canonical error-return type used by every ra8-firmware API.
Definition ra8_err.h:546
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.
Definition xml.h:87
uint16_t emitted
Attributes already returned.
Definition xml.h:89
uint32_t position
Next scan position.
Definition xml.h:88
Source-order attribute view.
Definition xml.h:81
xml_span_t value
Quoted value excluding delimiters.
Definition xml.h:83
xml_span_t name
Attribute name.
Definition xml.h:82
One XML pull event.
Definition xml.h:71
uint16_t attribute_count
Source-order attributes on start.
Definition xml.h:75
xml_span_t markup
Complete markup span, or text payload.
Definition xml.h:72
uint8_t self_closing
One for an empty-element start.
Definition xml.h:77
xml_span_t name
Element name for start/end.
Definition xml.h:73
One open-element identity retained for close-tag validation.
Definition xml.h:50
uint16_t name_length
Element-name byte count.
Definition xml.h:52
uint32_t name_offset
Element-name offset in the source.
Definition xml.h:51
Pull-reader state; initialise before each pass.
Definition xml.h:93
uint8_t finished
End validation complete.
Definition xml.h:103
uint8_t root_count
Completed/started roots.
Definition xml.h:99
uint16_t stack_size
Open element count.
Definition xml.h:98
const uint8_t * source
Immutable source bytes.
Definition xml.h:94
xml_workspace_t * workspace
Caller-owned stack.
Definition xml.h:97
size_t source_len
Source byte count.
Definition xml.h:95
size_t position
Next scan position.
Definition xml.h:96
uint8_t declaration_seen
One after XML declaration.
Definition xml.h:101
uint8_t root_closed
One after root close.
Definition xml.h:100
Immutable byte span expressed relative to the source.
Definition xml.h:44
uint32_t length
Byte count.
Definition xml.h:46
uint32_t offset
First byte offset.
Definition xml.h:45
Exactly bounded caller-owned nesting storage.
Definition xml.h:57
xml_frame_t frames[k_xml_workspace_frames]
Open-element stack.
Definition xml.h:58
static ra8_err_t internal_pi(xml_reader_t *reader)
Definition xml.c:465
static bool internal_name_start(uint8_t c)
Definition xml.c:36
static bool internal_xml_target(const uint8_t *source, size_t start, size_t end)
Definition xml.c:385
static ra8_err_t internal_markup_end(const uint8_t *source, size_t length, size_t start, size_t *out_end)
Definition xml.c:207
void xml_attr_begin(const xml_event_t *event, xml_attr_cursor_t *cursor)
Initialise source-order attribute iteration for a start event.
Definition xml.c:70
static ra8_err_t internal_end(xml_reader_t *reader, size_t end, xml_event_t *event)
Definition xml.c:313
static bool internal_space(uint8_t c)
Definition xml.c:24
static ra8_err_t internal_comment(xml_reader_t *reader)
Definition xml.c:362
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)
Definition xml.c:131
static ra8_err_t internal_terminator(const uint8_t *source, size_t length, size_t start, const char *terminator, size_t *out_start)
Definition xml.c:346
static ra8_err_t internal_start(xml_reader_t *reader, size_t end, xml_event_t *event)
Definition xml.c:272
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.
Definition xml.c:181
static bool internal_ascii_letter(uint8_t c)
Definition xml.c:30
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)
Definition xml.c:158
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.
Definition xml.c:47
static ra8_err_t internal_cdata(xml_reader_t *reader, xml_event_t *event)
Definition xml.c:492
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.
Definition xml.c:631
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)
Definition xml.c:399
static ra8_err_t internal_text(xml_reader_t *reader, xml_event_t *event)
Definition xml.c:539
static ra8_err_t internal_attributes(const uint8_t *source, size_t source_len, xml_event_t *event)
Definition xml.c:231
static bool internal_name_continue(uint8_t c)
Definition xml.c:41
static ra8_err_t internal_special(xml_reader_t *reader, xml_event_t *event, bool *out_emitted)
Definition xml.c:515
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.
Definition xml.c:98
static ra8_err_t internal_declaration(xml_reader_t *reader, size_t target_end, size_t term)
Definition xml.c:424
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.
Definition xml.c:571
static bool internal_encoding(const uint8_t *source, xml_span_t value)
Definition xml.c:392
ra8_err_t xml_reader_next(xml_reader_t *reader, xml_event_t *out_event)
Return the next semantic event and validate syntax incrementally.
Definition xml.c:590
Bounded, caller-owned, no-heap XML pull reader.
@ k_xml_max_element_depth
Accepted element levels, including root.
Definition xml.h:39
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.
Definition xml_decode.c:544
@ k_xml_event_cdata
CDATA payload.
Definition xml.h:67
@ k_xml_event_start
Element start.
Definition xml.h:64
@ k_xml_event_none
No event / end of source.
Definition xml.h:63
@ k_xml_event_text
Character-data run.
Definition xml.h:66
@ k_xml_event_end
Element end.
Definition xml.h:65
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.
Definition xml_decode.c:555
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.
Definition xml_decode.c:260
bool priv_xml_span_valid(size_t source_len, xml_span_t span)
Check that a source-relative span is in range.
Definition xml_decode.c:161
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.
Definition xml_decode.c:610
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.