yeptris 0.6.5.4 → 0.6.7.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/ext/libyeptris/extconf.rb +57 -0
- data/lib/yeptris/ffi.rb +12 -15
- data/lib/yeptris/json.rb +5 -2
- data/lib/yeptris/psych.rb +76 -3
- data/lib/yeptris.rb +36 -14
- data/vendor/libyeptris/CMakeLists.txt +254 -0
- data/vendor/libyeptris/cmake/yeptris-config.cmake.in +5 -0
- data/vendor/libyeptris/cmake/yeptris.pc.in +11 -0
- data/vendor/libyeptris/src/CMakeLists.txt +167 -0
- data/vendor/libyeptris/src/include/yeptris/api.h +32 -0
- data/vendor/libyeptris/src/include/yeptris/cbor.h +101 -0
- data/vendor/libyeptris/src/include/yeptris/dom.h +181 -0
- data/vendor/libyeptris/src/include/yeptris/emit.h +81 -0
- data/vendor/libyeptris/src/include/yeptris/error.h +41 -0
- data/vendor/libyeptris/src/include/yeptris/events.h +157 -0
- data/vendor/libyeptris/src/include/yeptris/json.h +45 -0
- data/vendor/libyeptris/src/include/yeptris/json.hpp +258 -0
- data/vendor/libyeptris/src/include/yeptris/jsonc_compat.h +115 -0
- data/vendor/libyeptris/src/include/yeptris/marshal.h +52 -0
- data/vendor/libyeptris/src/include/yeptris/parse.h +48 -0
- data/vendor/libyeptris/src/include/yeptris/plan.h +100 -0
- data/vendor/libyeptris/src/include/yeptris/resolve.h +71 -0
- data/vendor/libyeptris/src/include/yeptris/schema.h +119 -0
- data/vendor/libyeptris/src/include/yeptris/tape.h +99 -0
- data/vendor/libyeptris/src/include/yeptris/types.h +38 -0
- data/vendor/libyeptris/src/include/yeptris/values.h +102 -0
- data/vendor/libyeptris/src/include/yeptris/version.h.in +29 -0
- data/vendor/libyeptris/src/include/yeptris/visit.h +77 -0
- data/vendor/libyeptris/src/include/yeptris/yajl_compat.h +135 -0
- data/vendor/libyeptris/src/include/yeptris.h +23 -0
- data/vendor/libyeptris/src/yeptris/build.c +371 -0
- data/vendor/libyeptris/src/yeptris/cbor/cbor.h +25 -0
- data/vendor/libyeptris/src/yeptris/cbor/decode.c +846 -0
- data/vendor/libyeptris/src/yeptris/cbor/encode.c +824 -0
- data/vendor/libyeptris/src/yeptris/common/chartype.c +41 -0
- data/vendor/libyeptris/src/yeptris/common/chartype.h +77 -0
- data/vendor/libyeptris/src/yeptris/common/cpu.c +81 -0
- data/vendor/libyeptris/src/yeptris/common/cpu.h +40 -0
- data/vendor/libyeptris/src/yeptris/common/error.c +65 -0
- data/vendor/libyeptris/src/yeptris/common/error.h +79 -0
- data/vendor/libyeptris/src/yeptris/common/mutex.h +45 -0
- data/vendor/libyeptris/src/yeptris/common/nametab.c +275 -0
- data/vendor/libyeptris/src/yeptris/common/nametab.h +68 -0
- data/vendor/libyeptris/src/yeptris/common/port.h +74 -0
- data/vendor/libyeptris/src/yeptris/common/simd_text.c +49 -0
- data/vendor/libyeptris/src/yeptris/common/simd_text.h +295 -0
- data/vendor/libyeptris/src/yeptris/common/simd_text_avx2.c +534 -0
- data/vendor/libyeptris/src/yeptris/common/simd_text_neon.c +662 -0
- data/vendor/libyeptris/src/yeptris/common/simd_text_scalar.c +298 -0
- data/vendor/libyeptris/src/yeptris/common/string_view.c +34 -0
- data/vendor/libyeptris/src/yeptris/common/string_view.h +93 -0
- data/vendor/libyeptris/src/yeptris/doc.h +37 -0
- data/vendor/libyeptris/src/yeptris/dom/dom.c +973 -0
- data/vendor/libyeptris/src/yeptris/dom/dom.h +290 -0
- data/vendor/libyeptris/src/yeptris/dom/hpool.c +107 -0
- data/vendor/libyeptris/src/yeptris/dom/mapindex.c +173 -0
- data/vendor/libyeptris/src/yeptris/dom/mapindex.h +61 -0
- data/vendor/libyeptris/src/yeptris/dom/mutate.c +429 -0
- data/vendor/libyeptris/src/yeptris/emit/emit.c +349 -0
- data/vendor/libyeptris/src/yeptris/emit/float/api.h +38 -0
- data/vendor/libyeptris/src/yeptris/emit/float/dragon.c +405 -0
- data/vendor/libyeptris/src/yeptris/emit/float/floatint.h +203 -0
- data/vendor/libyeptris/src/yeptris/emit/float/print.c +396 -0
- data/vendor/libyeptris/src/yeptris/emit/style.c +81 -0
- data/vendor/libyeptris/src/yeptris/emit/style.h +24 -0
- data/vendor/libyeptris/src/yeptris/emit/writer.c +746 -0
- data/vendor/libyeptris/src/yeptris/emit/writer.h +61 -0
- data/vendor/libyeptris/src/yeptris/encoding/bom.c +31 -0
- data/vendor/libyeptris/src/yeptris/encoding/encoding.h +63 -0
- data/vendor/libyeptris/src/yeptris/encoding/transcode.c +148 -0
- data/vendor/libyeptris/src/yeptris/encoding/utf8_validate.c +178 -0
- data/vendor/libyeptris/src/yeptris/events/capture.c +150 -0
- data/vendor/libyeptris/src/yeptris/events/capture.h +39 -0
- data/vendor/libyeptris/src/yeptris/events/iterparse.c +208 -0
- data/vendor/libyeptris/src/yeptris/events/pull.c +97 -0
- data/vendor/libyeptris/src/yeptris/events/push.c +104 -0
- data/vendor/libyeptris/src/yeptris/events/recorder.c +107 -0
- data/vendor/libyeptris/src/yeptris/events/values.c +527 -0
- data/vendor/libyeptris/src/yeptris/events/values_priv.h +51 -0
- data/vendor/libyeptris/src/yeptris/events/yaml_compat.c +86 -0
- data/vendor/libyeptris/src/yeptris/events/yaml_compat.h +90 -0
- data/vendor/libyeptris/src/yeptris/jsonapi/jsonc_compat.c +687 -0
- data/vendor/libyeptris/src/yeptris/jsonapi/yajl_compat.c +728 -0
- data/vendor/libyeptris/src/yeptris/marshal.c +744 -0
- data/vendor/libyeptris/src/yeptris/memory/allocator.c +20 -0
- data/vendor/libyeptris/src/yeptris/memory/allocator.h +43 -0
- data/vendor/libyeptris/src/yeptris/memory/arena.c +134 -0
- data/vendor/libyeptris/src/yeptris/memory/arena.h +52 -0
- data/vendor/libyeptris/src/yeptris/memory/pool.c +115 -0
- data/vendor/libyeptris/src/yeptris/memory/pool.h +36 -0
- data/vendor/libyeptris/src/yeptris/parse/engine.c +3689 -0
- data/vendor/libyeptris/src/yeptris/parse/engine.h +65 -0
- data/vendor/libyeptris/src/yeptris/parse/events.h +124 -0
- data/vendor/libyeptris/src/yeptris/parse/numbers.c +349 -0
- data/vendor/libyeptris/src/yeptris/parse/numbers.h +33 -0
- data/vendor/libyeptris/src/yeptris/parse/scalars.c +416 -0
- data/vendor/libyeptris/src/yeptris/parse/scalars.h +75 -0
- data/vendor/libyeptris/src/yeptris/parse.c +650 -0
- data/vendor/libyeptris/src/yeptris/plan.c +817 -0
- data/vendor/libyeptris/src/yeptris/resolve/compat11.c +334 -0
- data/vendor/libyeptris/src/yeptris/resolve/core12.c +143 -0
- data/vendor/libyeptris/src/yeptris/resolve/resolver.h +56 -0
- data/vendor/libyeptris/src/yeptris/resolve/tags.c +58 -0
- data/vendor/libyeptris/src/yeptris/scan/json.c +792 -0
- data/vendor/libyeptris/src/yeptris/scan/json.h +109 -0
- data/vendor/libyeptris/src/yeptris/scan/scan.c +463 -0
- data/vendor/libyeptris/src/yeptris/scan/scan.h +150 -0
- data/vendor/libyeptris/src/yeptris/schema.c +238 -0
- data/vendor/libyeptris/src/yeptris/tape.c +1292 -0
- data/vendor/libyeptris/src/yeptris/version.c +7 -0
- data/vendor/libyeptris/src/yeptris/visit/dom_visit.c +115 -0
- data/vendor/libyeptris/src/yeptris/visit/json_visit.c +293 -0
- data/vendor/libyeptris/src/yeptris/visit/yaml_visit.c +127 -0
- metadata +112 -2
|
@@ -0,0 +1,846 @@
|
|
|
1
|
+
/* decode.c — CBOR (RFC 8949) decode over the shared DOM (TODO.cbor/01).
|
|
2
|
+
*
|
|
3
|
+
* Bytes -> the same DOM JSON builds, one data item per call (trailing
|
|
4
|
+
* bytes are "too much data"; CBOR Sequences are item 03). The walk is
|
|
5
|
+
* iterative — the DOM's own builder stack hosts the nesting, so the
|
|
6
|
+
* C stack never rides the input depth.
|
|
7
|
+
*
|
|
8
|
+
* Representation ledger (documented divergences from CBOR's model,
|
|
9
|
+
* all pinned by the Appendix A + F suites):
|
|
10
|
+
* - integers beyond int64 materialize as shortest-double text (the
|
|
11
|
+
* number-kernel shape-2 contract); bignums stay tag+bytes (2/3)
|
|
12
|
+
* - byte strings and text strings are indistinguishable post-DOM
|
|
13
|
+
* (tag-str scalars, zero-copy spans); canonical re-encode (02)
|
|
14
|
+
* emits text strings
|
|
15
|
+
* - undefined is the scalar "undefined"; unassigned simple values
|
|
16
|
+
* are "simple(N)" diagnostic text (both modes)
|
|
17
|
+
* - tags ride the node's tag field as a decimal chain, outermost
|
|
18
|
+
* first ("2 55799"); never interpreted by the core
|
|
19
|
+
* - non-string map keys: strict rejects; lenient materializes the
|
|
20
|
+
* diagnostic text for SCALAR keys — structure keys reject in both
|
|
21
|
+
* - duplicate keys: last materialized wins, the JSON DOM path's rule
|
|
22
|
+
* - indefinite-length strings concatenate their chunks in the DOM's
|
|
23
|
+
* string arena (the only string copies; definite strings borrow)
|
|
24
|
+
*/
|
|
25
|
+
#include "cbor.h"
|
|
26
|
+
|
|
27
|
+
#include <math.h>
|
|
28
|
+
#include <string.h>
|
|
29
|
+
|
|
30
|
+
#include <yeptris/cbor.h>
|
|
31
|
+
#include <yeptris/resolve.h>
|
|
32
|
+
|
|
33
|
+
#include "../common/error.h"
|
|
34
|
+
#include "../doc.h"
|
|
35
|
+
#include "../emit/float/api.h"
|
|
36
|
+
#include "../encoding/encoding.h"
|
|
37
|
+
#include "../memory/allocator.h"
|
|
38
|
+
#include "../parse/events.h"
|
|
39
|
+
#include "doc.h"
|
|
40
|
+
|
|
41
|
+
#define YEP_CBOR_INDEF UINT64_MAX
|
|
42
|
+
#define YEP_CBOR_MAX_ARG_BYTES 8
|
|
43
|
+
|
|
44
|
+
typedef struct {
|
|
45
|
+
uint64_t rem; /* items left; maps count 2*pairs; INDEF = until break */
|
|
46
|
+
uint8_t is_map;
|
|
47
|
+
} yep_cframe;
|
|
48
|
+
|
|
49
|
+
typedef struct {
|
|
50
|
+
yep_dom* d;
|
|
51
|
+
const unsigned char* p;
|
|
52
|
+
size_t len;
|
|
53
|
+
size_t i;
|
|
54
|
+
int strict;
|
|
55
|
+
YeptrisStatus status;
|
|
56
|
+
/* pending tag chain: tag numbers arrive before their content and
|
|
57
|
+
* render into the arena as "N N N" (outermost first — the encoder
|
|
58
|
+
* splits it back); the span attaches to the next data item */
|
|
59
|
+
yep_sview pending_tag;
|
|
60
|
+
int have_pending;
|
|
61
|
+
yep_cframe frame[YEP_DOM_MAX_DEPTH];
|
|
62
|
+
int depth; /* == d->depth by construction */
|
|
63
|
+
} yep_cdec;
|
|
64
|
+
|
|
65
|
+
static void cbor_fail(yep_cdec* c, yep_err_code code, const char* msg) {
|
|
66
|
+
yep_error_set(yep_error_tls(), code, 0, 0, c->i, "%s at byte %zu", msg, c->i);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
#define CBOR_REJECT(what) \
|
|
70
|
+
do { \
|
|
71
|
+
cbor_fail(c, YEP_ERR_UNEXPECTED, what); \
|
|
72
|
+
c->status = YEPTRIS_ERROR_PARSE; \
|
|
73
|
+
return 0; \
|
|
74
|
+
} while (0)
|
|
75
|
+
|
|
76
|
+
/* The head's argument: additional info 0-23 inline, 24-27 a 1/2/4/8-byte
|
|
77
|
+
* big-endian value; 28-30 are reserved (never well-formed). Strict mode
|
|
78
|
+
* also rejects non-minimal encodings (RFC 8949 s4.2.1's argument rule).
|
|
79
|
+
* ai 31 is the caller's (indefinite/break) — never reaches here. */
|
|
80
|
+
static int cbor_arg(yep_cdec* c, uint8_t ai, uint64_t* val) {
|
|
81
|
+
static const uint8_t nbytes[4] = {1, 2, 4, 8};
|
|
82
|
+
static const uint64_t minv[4] = {24, 0x100ull, 0x10000ull, 0x100000000ull};
|
|
83
|
+
if (ai >= 28) {
|
|
84
|
+
CBOR_REJECT("reserved additional information (28-30)");
|
|
85
|
+
}
|
|
86
|
+
uint64_t v = ai;
|
|
87
|
+
if (ai >= 24) {
|
|
88
|
+
size_t n = nbytes[ai - 24];
|
|
89
|
+
if (c->len - c->i < n) {
|
|
90
|
+
cbor_fail(c, YEP_ERR_UNEXPECTED, "truncated head");
|
|
91
|
+
c->status = YEPTRIS_ERROR_PARSE;
|
|
92
|
+
return 0;
|
|
93
|
+
}
|
|
94
|
+
v = 0;
|
|
95
|
+
for (size_t k = 0; k < n; k++) {
|
|
96
|
+
v = (v << 8) | c->p[c->i + k];
|
|
97
|
+
}
|
|
98
|
+
c->i += n;
|
|
99
|
+
if (c->strict && v < minv[ai - 24]) {
|
|
100
|
+
CBOR_REJECT("non-minimal length argument");
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
*val = v;
|
|
104
|
+
return 1;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
static uint32_t cbor_u64dec(uint64_t v, char* buf) {
|
|
108
|
+
char tmp[20];
|
|
109
|
+
uint32_t n = 0;
|
|
110
|
+
do {
|
|
111
|
+
tmp[n++] = (char)('0' + (v % 10));
|
|
112
|
+
v /= 10;
|
|
113
|
+
} while (v != 0);
|
|
114
|
+
for (uint32_t k = 0; k < n; k++) {
|
|
115
|
+
buf[k] = tmp[n - 1 - k];
|
|
116
|
+
}
|
|
117
|
+
return n;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/* ldexp without libm: the exponent range here is [-24, 5], so scaling
|
|
121
|
+
* by repeated doubling/halving is exact and bounded. */
|
|
122
|
+
static double cbor_pow2(double x, int e) {
|
|
123
|
+
while (e > 0) {
|
|
124
|
+
x *= 2.0;
|
|
125
|
+
e--;
|
|
126
|
+
}
|
|
127
|
+
while (e < 0) {
|
|
128
|
+
x *= 0.5;
|
|
129
|
+
e++;
|
|
130
|
+
}
|
|
131
|
+
return x;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/* The RFC 8949 Appendix D half-precision decoder, verbatim shape. */
|
|
135
|
+
static double cbor_half(uint16_t h) {
|
|
136
|
+
unsigned exp = (h >> 10) & 0x1fu;
|
|
137
|
+
unsigned mant = h & 0x3ffu;
|
|
138
|
+
double val;
|
|
139
|
+
if (exp == 0) {
|
|
140
|
+
val = cbor_pow2((double)mant, -24);
|
|
141
|
+
} else if (exp != 31) {
|
|
142
|
+
val = cbor_pow2((double)(mant + 1024), (int)exp - 25);
|
|
143
|
+
} else {
|
|
144
|
+
val = mant == 0 ? (double)INFINITY : (double)NAN;
|
|
145
|
+
}
|
|
146
|
+
return (h & 0x8000u) != 0 ? -val : val;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/* Scalar from arena text (numbers, diagnostics, literals). */
|
|
150
|
+
static uint32_t cbor_text_node(yep_cdec* c, const char* text, uint32_t n, uint8_t tag_id) {
|
|
151
|
+
yep_view tag_v;
|
|
152
|
+
const yep_view* tag = NULL;
|
|
153
|
+
if (c->have_pending) {
|
|
154
|
+
/* the pending chain lives in the DOM arena (offsets, not
|
|
155
|
+
* pointers — the arena reallocs as it grows) */
|
|
156
|
+
tag_v.p = c->d->str + (c->pending_tag.off & YEP_SV_OFF);
|
|
157
|
+
tag_v.len = c->pending_tag.len;
|
|
158
|
+
tag = &tag_v;
|
|
159
|
+
c->have_pending = 0;
|
|
160
|
+
}
|
|
161
|
+
uint32_t id = dom_open_node(c->d, YEP_DOM_SCALAR, tag, NULL, 0, YEP_STYLE_PLAIN, 1, 0);
|
|
162
|
+
if (id == UINT32_MAX) {
|
|
163
|
+
c->status = YEPTRIS_ERROR_MEMORY;
|
|
164
|
+
return UINT32_MAX;
|
|
165
|
+
}
|
|
166
|
+
yep_dnode* node = &c->d->nodes[id];
|
|
167
|
+
char* dst = yep_dom_str_tail(c->d, n);
|
|
168
|
+
if (dst == NULL) {
|
|
169
|
+
c->status = YEPTRIS_ERROR_MEMORY;
|
|
170
|
+
return UINT32_MAX;
|
|
171
|
+
}
|
|
172
|
+
memcpy(dst, text, n);
|
|
173
|
+
node->value = yep_dom_str_commit(c->d, n);
|
|
174
|
+
node->tag_id = tag_id;
|
|
175
|
+
if (dom_place(c->d, id) != 0) {
|
|
176
|
+
c->status = YEPTRIS_ERROR_MEMORY;
|
|
177
|
+
return UINT32_MAX;
|
|
178
|
+
}
|
|
179
|
+
return id;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/* Scalar borrowing the input (definite strings, bignum byte strings). */
|
|
183
|
+
static uint32_t cbor_span_node(yep_cdec* c, const unsigned char* p, uint32_t n) {
|
|
184
|
+
yep_view tag_v;
|
|
185
|
+
const yep_view* tag = NULL;
|
|
186
|
+
if (c->have_pending) {
|
|
187
|
+
tag_v.p = c->d->str + (c->pending_tag.off & YEP_SV_OFF);
|
|
188
|
+
tag_v.len = c->pending_tag.len;
|
|
189
|
+
tag = &tag_v;
|
|
190
|
+
c->have_pending = 0;
|
|
191
|
+
}
|
|
192
|
+
uint32_t id = dom_open_node(c->d, YEP_DOM_SCALAR, tag, NULL, 0, YEP_STYLE_DOUBLE_QUOTED, 0, 0);
|
|
193
|
+
if (id == UINT32_MAX) {
|
|
194
|
+
c->status = YEPTRIS_ERROR_MEMORY;
|
|
195
|
+
return UINT32_MAX;
|
|
196
|
+
}
|
|
197
|
+
yep_dnode* node = &c->d->nodes[id];
|
|
198
|
+
node->value.off = (uint32_t)((const char*)p - c->d->input_base);
|
|
199
|
+
node->value.len = n;
|
|
200
|
+
if (dom_place(c->d, id) != 0) {
|
|
201
|
+
c->status = YEPTRIS_ERROR_MEMORY;
|
|
202
|
+
return UINT32_MAX;
|
|
203
|
+
}
|
|
204
|
+
return id;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
static int cbor_open(yep_cdec* c, int is_map) {
|
|
208
|
+
if (c->depth >= YEP_DOM_MAX_DEPTH) {
|
|
209
|
+
yep_error_set(yep_error_tls(), YEP_ERR_UNEXPECTED, 0, 0, c->i,
|
|
210
|
+
"CBOR nesting exceeds the depth guard at byte %zu", c->i);
|
|
211
|
+
c->status = YEPTRIS_ERROR_DEPTH;
|
|
212
|
+
return 0;
|
|
213
|
+
}
|
|
214
|
+
yep_view tag_v;
|
|
215
|
+
const yep_view* tag = NULL;
|
|
216
|
+
if (c->have_pending) {
|
|
217
|
+
tag_v.p = c->d->str + (c->pending_tag.off & YEP_SV_OFF);
|
|
218
|
+
tag_v.len = c->pending_tag.len;
|
|
219
|
+
tag = &tag_v;
|
|
220
|
+
c->have_pending = 0;
|
|
221
|
+
}
|
|
222
|
+
uint32_t id =
|
|
223
|
+
dom_open_node(c->d, is_map ? YEP_DOM_MAPPING : YEP_DOM_SEQUENCE, tag, NULL, 0, 0, 0, 1);
|
|
224
|
+
if (id == UINT32_MAX) {
|
|
225
|
+
c->status = YEPTRIS_ERROR_MEMORY;
|
|
226
|
+
return 0;
|
|
227
|
+
}
|
|
228
|
+
if (dom_place(c->d, id) != 0) {
|
|
229
|
+
c->status = YEPTRIS_ERROR_MEMORY;
|
|
230
|
+
return 0;
|
|
231
|
+
}
|
|
232
|
+
c->d->map_pending_key[c->d->depth] = 0;
|
|
233
|
+
c->d->stack[c->d->depth++] = id;
|
|
234
|
+
c->depth++; /* the frame mirrors the DOM's stack one-to-one */
|
|
235
|
+
return 1;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
static int cbor_note_tag(yep_cdec* c, uint64_t tag) {
|
|
239
|
+
char buf[24];
|
|
240
|
+
uint32_t n = 0;
|
|
241
|
+
if (c->have_pending) {
|
|
242
|
+
buf[n++] = ' '; /* separator between chain links */
|
|
243
|
+
}
|
|
244
|
+
n += cbor_u64dec(tag, buf + n);
|
|
245
|
+
char* dst = yep_dom_str_tail(c->d, n);
|
|
246
|
+
if (dst == NULL) {
|
|
247
|
+
c->status = YEPTRIS_ERROR_MEMORY;
|
|
248
|
+
return 0;
|
|
249
|
+
}
|
|
250
|
+
yep_sview piece = yep_dom_str_commit(c->d, n);
|
|
251
|
+
if (!c->have_pending) {
|
|
252
|
+
c->pending_tag = piece;
|
|
253
|
+
c->pending_tag.len = 0;
|
|
254
|
+
c->have_pending = 1;
|
|
255
|
+
}
|
|
256
|
+
memcpy(dst, buf, n);
|
|
257
|
+
/* piece-by-piece commit keeps the chain contiguous in the arena */
|
|
258
|
+
c->pending_tag.len += n;
|
|
259
|
+
return 1;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
/* One complete indefinite-length string (chunks concatenate in the
|
|
263
|
+
* arena; text chunks validate per chunk — RFC 8949 s3.2.3's code-point
|
|
264
|
+
* boundary rule makes per-chunk validity imply whole-string validity). */
|
|
265
|
+
static int cbor_indef_string(yep_cdec* c, int is_text) {
|
|
266
|
+
uint32_t first = 0;
|
|
267
|
+
uint32_t total = 0;
|
|
268
|
+
for (;;) {
|
|
269
|
+
if (c->i >= c->len) {
|
|
270
|
+
CBOR_REJECT("unterminated indefinite-length string");
|
|
271
|
+
}
|
|
272
|
+
uint8_t ib = c->p[c->i];
|
|
273
|
+
c->i++;
|
|
274
|
+
if (ib == 0xFF) {
|
|
275
|
+
break;
|
|
276
|
+
}
|
|
277
|
+
if ((ib >> 5) != (is_text ? 3 : 2) || (ib & 0x1F) == 31) {
|
|
278
|
+
CBOR_REJECT("indefinite-length string chunk must be definite, same major type");
|
|
279
|
+
}
|
|
280
|
+
uint64_t n = 0;
|
|
281
|
+
if (!cbor_arg(c, ib & 0x1F, &n)) {
|
|
282
|
+
return 0;
|
|
283
|
+
}
|
|
284
|
+
if (n > c->len - c->i) {
|
|
285
|
+
CBOR_REJECT("truncated string chunk");
|
|
286
|
+
}
|
|
287
|
+
if (is_text && !yep_utf8_validate(c->p + c->i, (size_t)n, NULL)) {
|
|
288
|
+
yep_error_set(yep_error_tls(), YEP_ERR_UNEXPECTED, 0, 0, c->i,
|
|
289
|
+
"ill-formed UTF-8 in text string at byte %zu", c->i);
|
|
290
|
+
c->status = YEPTRIS_ERROR_ENCODING;
|
|
291
|
+
return 0;
|
|
292
|
+
}
|
|
293
|
+
if (n > 0) { /* zero-length chunks are legal, just empty */
|
|
294
|
+
char* dst = yep_dom_str_tail(c->d, (uint32_t)n);
|
|
295
|
+
if (dst == NULL) {
|
|
296
|
+
c->status = YEPTRIS_ERROR_MEMORY;
|
|
297
|
+
return 0;
|
|
298
|
+
}
|
|
299
|
+
yep_sview piece = yep_dom_str_commit(c->d, (uint32_t)n);
|
|
300
|
+
memcpy(dst, c->p + c->i, (size_t)n);
|
|
301
|
+
if (total == 0) {
|
|
302
|
+
first = piece.off;
|
|
303
|
+
}
|
|
304
|
+
total += (uint32_t)n;
|
|
305
|
+
}
|
|
306
|
+
c->i += (size_t)n;
|
|
307
|
+
}
|
|
308
|
+
/* node over the concatenated arena span */
|
|
309
|
+
yep_view tag_v;
|
|
310
|
+
const yep_view* tag = NULL;
|
|
311
|
+
if (c->have_pending) {
|
|
312
|
+
tag_v.p = c->d->str + (c->pending_tag.off & YEP_SV_OFF);
|
|
313
|
+
tag_v.len = c->pending_tag.len;
|
|
314
|
+
tag = &tag_v;
|
|
315
|
+
c->have_pending = 0;
|
|
316
|
+
}
|
|
317
|
+
uint32_t id = dom_open_node(c->d, YEP_DOM_SCALAR, tag, NULL, 0, YEP_STYLE_DOUBLE_QUOTED, 0, 0);
|
|
318
|
+
if (id == UINT32_MAX) {
|
|
319
|
+
c->status = YEPTRIS_ERROR_MEMORY;
|
|
320
|
+
return 0;
|
|
321
|
+
}
|
|
322
|
+
yep_dnode* node = &c->d->nodes[id];
|
|
323
|
+
node->value.off = first;
|
|
324
|
+
node->value.len = total;
|
|
325
|
+
if (dom_place(c->d, id) != 0) {
|
|
326
|
+
c->status = YEPTRIS_ERROR_MEMORY;
|
|
327
|
+
return 0;
|
|
328
|
+
}
|
|
329
|
+
return 1;
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
/* yep_json_number-style inline render: one node for a known integer. */
|
|
333
|
+
static int cbor_int_node(yep_cdec* c, int negative, uint64_t mag) {
|
|
334
|
+
char buf[24];
|
|
335
|
+
uint32_t n = 0;
|
|
336
|
+
uint8_t tag_id;
|
|
337
|
+
if (negative) {
|
|
338
|
+
buf[n++] = '-';
|
|
339
|
+
}
|
|
340
|
+
n += cbor_u64dec(mag, buf + n);
|
|
341
|
+
tag_id = YEPTRIS_TAG_INT;
|
|
342
|
+
return cbor_text_node(c, buf, n, tag_id) != UINT32_MAX;
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
static int cbor_float_node(yep_cdec* c, double dv) {
|
|
346
|
+
char buf[48];
|
|
347
|
+
uint32_t n;
|
|
348
|
+
uint8_t tag_id = YEPTRIS_TAG_FLOAT;
|
|
349
|
+
if (dv != dv) {
|
|
350
|
+
memcpy(buf, "NaN", 3);
|
|
351
|
+
n = 3;
|
|
352
|
+
} else if (dv > 1.7976931348623157e308) {
|
|
353
|
+
memcpy(buf, "Infinity", 8);
|
|
354
|
+
n = 8;
|
|
355
|
+
} else if (dv < -1.7976931348623157e308) {
|
|
356
|
+
memcpy(buf, "-Infinity", 9);
|
|
357
|
+
n = 9;
|
|
358
|
+
} else {
|
|
359
|
+
n = (uint32_t)yep_d2s_shortest(dv, buf);
|
|
360
|
+
}
|
|
361
|
+
(void)tag_id;
|
|
362
|
+
return cbor_text_node(c, buf, n, YEPTRIS_TAG_FLOAT) != UINT32_MAX;
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
/* The diagnostic renderer for lenient-mode non-string SCALAR map keys
|
|
366
|
+
* (the plan's policy: what the JSON path can round-trip). */
|
|
367
|
+
static int cbor_key_diag(yep_cdec* c, uint8_t mt, uint64_t val, double dv) {
|
|
368
|
+
char buf[48];
|
|
369
|
+
uint32_t n;
|
|
370
|
+
switch (mt) {
|
|
371
|
+
case 0:
|
|
372
|
+
n = cbor_u64dec(val, buf);
|
|
373
|
+
break;
|
|
374
|
+
case 1:
|
|
375
|
+
buf[0] = '-';
|
|
376
|
+
n = 1 + cbor_u64dec(val, buf + 1);
|
|
377
|
+
break;
|
|
378
|
+
case 2: { /* h'hex' */
|
|
379
|
+
buf[0] = 'h';
|
|
380
|
+
buf[1] = '\'';
|
|
381
|
+
static const char hexd[] = "0123456789abcdef";
|
|
382
|
+
n = 2;
|
|
383
|
+
for (uint64_t k = 0; k < val && n + 2 < sizeof(buf); k++) {
|
|
384
|
+
uint8_t b = c->p[c->i + k];
|
|
385
|
+
buf[n++] = hexd[b >> 4];
|
|
386
|
+
buf[n++] = hexd[b & 15];
|
|
387
|
+
}
|
|
388
|
+
buf[n++] = '\'';
|
|
389
|
+
break;
|
|
390
|
+
}
|
|
391
|
+
case 7:
|
|
392
|
+
if (val == 20) {
|
|
393
|
+
memcpy(buf, "false", 5);
|
|
394
|
+
n = 5;
|
|
395
|
+
} else if (val == 21) {
|
|
396
|
+
memcpy(buf, "true", 4);
|
|
397
|
+
n = 4;
|
|
398
|
+
} else if (val == 22) {
|
|
399
|
+
memcpy(buf, "null", 4);
|
|
400
|
+
n = 4;
|
|
401
|
+
} else if (val == 23) {
|
|
402
|
+
memcpy(buf, "undefined", 9);
|
|
403
|
+
n = 9;
|
|
404
|
+
} else {
|
|
405
|
+
memcpy(buf, "simple(", 7);
|
|
406
|
+
n = 7 + cbor_u64dec(val, buf + 7);
|
|
407
|
+
buf[n++] = ')';
|
|
408
|
+
}
|
|
409
|
+
break;
|
|
410
|
+
default:
|
|
411
|
+
return cbor_float_node(c, dv); /* floats: the shortest text */
|
|
412
|
+
}
|
|
413
|
+
return cbor_text_node(c, buf, n, 0) != UINT32_MAX;
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
/* Decodes ONE data item (scalar: creates+places the node; container:
|
|
417
|
+
* opens+pushes a frame; tag: notes the chain and reports "again").
|
|
418
|
+
* Returns 1 item consumed/started, 0 failure, 2 = tag (no slot). */
|
|
419
|
+
static int cbor_item(yep_cdec* c) {
|
|
420
|
+
if (c->i >= c->len) {
|
|
421
|
+
CBOR_REJECT("truncated head");
|
|
422
|
+
}
|
|
423
|
+
uint8_t ib = c->p[c->i++];
|
|
424
|
+
uint8_t mt = ib >> 5;
|
|
425
|
+
uint8_t ai = ib & 0x1F;
|
|
426
|
+
|
|
427
|
+
/* the map-key position decides representation before the item is
|
|
428
|
+
* built (the DOM pairs whatever node lands there) */
|
|
429
|
+
int key_slot = 0;
|
|
430
|
+
if (c->depth > 0 && c->frame[c->depth - 1].is_map && !c->d->map_pending_key[c->d->depth - 1]) {
|
|
431
|
+
key_slot = 1;
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
if (ai == 31) {
|
|
435
|
+
switch (mt) {
|
|
436
|
+
case 2:
|
|
437
|
+
case 3: {
|
|
438
|
+
if (key_slot) {
|
|
439
|
+
CBOR_REJECT("string key required");
|
|
440
|
+
}
|
|
441
|
+
return cbor_indef_string(c, mt == 3) ? 1 : 0;
|
|
442
|
+
}
|
|
443
|
+
case 4:
|
|
444
|
+
if (key_slot) {
|
|
445
|
+
CBOR_REJECT("structure as map key");
|
|
446
|
+
}
|
|
447
|
+
if (!cbor_open(c, 0)) {
|
|
448
|
+
return 0;
|
|
449
|
+
}
|
|
450
|
+
c->frame[c->depth - 1].rem = YEP_CBOR_INDEF;
|
|
451
|
+
c->frame[c->depth - 1].is_map = 0;
|
|
452
|
+
return 1;
|
|
453
|
+
case 5:
|
|
454
|
+
if (key_slot) {
|
|
455
|
+
CBOR_REJECT("structure as map key");
|
|
456
|
+
}
|
|
457
|
+
if (!cbor_open(c, 1)) {
|
|
458
|
+
return 0;
|
|
459
|
+
}
|
|
460
|
+
c->frame[c->depth - 1].rem = YEP_CBOR_INDEF;
|
|
461
|
+
c->frame[c->depth - 1].is_map = 1;
|
|
462
|
+
return 1;
|
|
463
|
+
default:
|
|
464
|
+
CBOR_REJECT("additional information 31 with major type 0, 1, 6, or as an item");
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
uint64_t arg = 0;
|
|
469
|
+
if (mt == 7) {
|
|
470
|
+
/* major type 7: ai is the payload shape, not an argument width */
|
|
471
|
+
arg = ai;
|
|
472
|
+
} else if (!cbor_arg(c, ai, &arg)) {
|
|
473
|
+
return 0;
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
switch (mt) {
|
|
477
|
+
case 0: {
|
|
478
|
+
if (key_slot && c->strict) {
|
|
479
|
+
CBOR_REJECT("string key required");
|
|
480
|
+
}
|
|
481
|
+
if (key_slot) {
|
|
482
|
+
return cbor_key_diag(c, 0, arg, 0) ? 1 : 0;
|
|
483
|
+
}
|
|
484
|
+
if (arg <= (uint64_t)INT64_MAX) {
|
|
485
|
+
return cbor_int_node(c, 0, arg) ? 1 : 0;
|
|
486
|
+
}
|
|
487
|
+
return cbor_float_node(c, (double)arg) ? 1 : 0;
|
|
488
|
+
}
|
|
489
|
+
case 1: {
|
|
490
|
+
if (key_slot && c->strict) {
|
|
491
|
+
CBOR_REJECT("string key required");
|
|
492
|
+
}
|
|
493
|
+
if (key_slot) {
|
|
494
|
+
return cbor_key_diag(c, 1, arg, 0) ? 1 : 0;
|
|
495
|
+
}
|
|
496
|
+
if (arg <= (uint64_t)INT64_MAX + 1) { /* -1-2^63 == INT64_MIN */
|
|
497
|
+
uint64_t mag = arg + 1;
|
|
498
|
+
return cbor_int_node(c, 1, mag) ? 1 : 0;
|
|
499
|
+
}
|
|
500
|
+
return cbor_float_node(c, -((double)arg + 1.0)) ? 1 : 0;
|
|
501
|
+
}
|
|
502
|
+
case 2:
|
|
503
|
+
case 3: {
|
|
504
|
+
if (arg > c->len - c->i) {
|
|
505
|
+
CBOR_REJECT("truncated string");
|
|
506
|
+
}
|
|
507
|
+
if (mt == 3 && !yep_utf8_validate(c->p + c->i, (size_t)arg, NULL)) {
|
|
508
|
+
yep_error_set(yep_error_tls(), YEP_ERR_UNEXPECTED, 0, 0, c->i,
|
|
509
|
+
"ill-formed UTF-8 in text string at byte %zu", c->i);
|
|
510
|
+
c->status = YEPTRIS_ERROR_ENCODING;
|
|
511
|
+
return 0;
|
|
512
|
+
}
|
|
513
|
+
if (key_slot && mt == 2 && c->strict) {
|
|
514
|
+
CBOR_REJECT("string key required"); /* a byte string is not text */
|
|
515
|
+
}
|
|
516
|
+
if (key_slot && mt == 2) {
|
|
517
|
+
int ok = cbor_key_diag(c, 2, arg, 0);
|
|
518
|
+
c->i += (size_t)arg;
|
|
519
|
+
return ok ? 1 : 0;
|
|
520
|
+
}
|
|
521
|
+
uint32_t id = cbor_span_node(c, c->p + c->i, (uint32_t)arg);
|
|
522
|
+
c->i += (size_t)arg;
|
|
523
|
+
return id != UINT32_MAX ? 1 : 0;
|
|
524
|
+
}
|
|
525
|
+
case 4: {
|
|
526
|
+
if (key_slot) {
|
|
527
|
+
CBOR_REJECT("structure as map key");
|
|
528
|
+
}
|
|
529
|
+
if (arg > c->len - c->i) { /* every item consumes >= 1 byte */
|
|
530
|
+
CBOR_REJECT("array overruns the input");
|
|
531
|
+
}
|
|
532
|
+
if (!cbor_open(c, 0)) {
|
|
533
|
+
return 0;
|
|
534
|
+
}
|
|
535
|
+
c->frame[c->depth - 1].rem = arg;
|
|
536
|
+
c->frame[c->depth - 1].is_map = 0;
|
|
537
|
+
return 1;
|
|
538
|
+
}
|
|
539
|
+
case 5: {
|
|
540
|
+
if (key_slot) {
|
|
541
|
+
CBOR_REJECT("structure as map key");
|
|
542
|
+
}
|
|
543
|
+
if (arg > (c->len - c->i) / 2) { /* pairs need 2 items each */
|
|
544
|
+
CBOR_REJECT("map overruns the input");
|
|
545
|
+
}
|
|
546
|
+
if (!cbor_open(c, 1)) {
|
|
547
|
+
return 0;
|
|
548
|
+
}
|
|
549
|
+
c->frame[c->depth - 1].rem = arg * 2;
|
|
550
|
+
c->frame[c->depth - 1].is_map = 1;
|
|
551
|
+
return 1;
|
|
552
|
+
}
|
|
553
|
+
case 6:
|
|
554
|
+
if (!cbor_note_tag(c, arg)) {
|
|
555
|
+
return 0;
|
|
556
|
+
}
|
|
557
|
+
return 2; /* the chain needs its content item */
|
|
558
|
+
default: /* 7 */
|
|
559
|
+
break;
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
/* major type 7: simple values and floats */
|
|
563
|
+
double dv = 0;
|
|
564
|
+
switch (ai) {
|
|
565
|
+
case 20:
|
|
566
|
+
if (key_slot) {
|
|
567
|
+
return cbor_key_diag(c, 7, 20, 0) ? 1 : 0;
|
|
568
|
+
}
|
|
569
|
+
return cbor_text_node(c, "false", 5, YEPTRIS_TAG_BOOL) != UINT32_MAX ? 1 : 0;
|
|
570
|
+
case 21:
|
|
571
|
+
if (key_slot) {
|
|
572
|
+
return cbor_key_diag(c, 7, 21, 0) ? 1 : 0;
|
|
573
|
+
}
|
|
574
|
+
return cbor_text_node(c, "true", 4, YEPTRIS_TAG_BOOL) != UINT32_MAX ? 1 : 0;
|
|
575
|
+
case 22:
|
|
576
|
+
if (key_slot) {
|
|
577
|
+
return cbor_key_diag(c, 7, 22, 0) ? 1 : 0;
|
|
578
|
+
}
|
|
579
|
+
return cbor_text_node(c, "null", 4, YEPTRIS_TAG_NULL) != UINT32_MAX ? 1 : 0;
|
|
580
|
+
case 23:
|
|
581
|
+
if (key_slot) {
|
|
582
|
+
return cbor_key_diag(c, 7, 23, 0) ? 1 : 0;
|
|
583
|
+
}
|
|
584
|
+
return cbor_text_node(c, "undefined", 9, 0) != UINT32_MAX ? 1 : 0;
|
|
585
|
+
case 24: {
|
|
586
|
+
if (c->len - c->i < 1) {
|
|
587
|
+
CBOR_REJECT("truncated simple value");
|
|
588
|
+
}
|
|
589
|
+
uint64_t v = c->p[c->i++];
|
|
590
|
+
if (v < 32) {
|
|
591
|
+
CBOR_REJECT("two-byte simple value below 32");
|
|
592
|
+
}
|
|
593
|
+
if (key_slot) {
|
|
594
|
+
return cbor_key_diag(c, 7, v, 0) ? 1 : 0;
|
|
595
|
+
}
|
|
596
|
+
char buf[16];
|
|
597
|
+
memcpy(buf, "simple(", 7);
|
|
598
|
+
uint32_t n = 7 + cbor_u64dec(v, buf + 7);
|
|
599
|
+
buf[n++] = ')';
|
|
600
|
+
return cbor_text_node(c, buf, n, 0) != UINT32_MAX ? 1 : 0;
|
|
601
|
+
}
|
|
602
|
+
case 25: {
|
|
603
|
+
if (c->len - c->i < 2) {
|
|
604
|
+
CBOR_REJECT("truncated half float");
|
|
605
|
+
}
|
|
606
|
+
uint16_t h = (uint16_t)((c->p[c->i] << 8) | c->p[c->i + 1]);
|
|
607
|
+
c->i += 2;
|
|
608
|
+
dv = cbor_half(h);
|
|
609
|
+
break;
|
|
610
|
+
}
|
|
611
|
+
case 26: {
|
|
612
|
+
if (c->len - c->i < 4) {
|
|
613
|
+
CBOR_REJECT("truncated single float");
|
|
614
|
+
}
|
|
615
|
+
uint32_t w = ((uint32_t)c->p[c->i] << 24) | ((uint32_t)c->p[c->i + 1] << 16) |
|
|
616
|
+
((uint32_t)c->p[c->i + 2] << 8) | (uint32_t)c->p[c->i + 3];
|
|
617
|
+
float f;
|
|
618
|
+
c->i += 4;
|
|
619
|
+
memcpy(&f, &w, sizeof(f)); /* the single's bit pattern, widened */
|
|
620
|
+
dv = (double)f;
|
|
621
|
+
break;
|
|
622
|
+
}
|
|
623
|
+
case 27: {
|
|
624
|
+
if (c->len - c->i < 8) {
|
|
625
|
+
CBOR_REJECT("truncated double float");
|
|
626
|
+
}
|
|
627
|
+
uint64_t w = 0;
|
|
628
|
+
for (int k = 0; k < 8; k++) {
|
|
629
|
+
w = (w << 8) | c->p[c->i + (size_t)k];
|
|
630
|
+
}
|
|
631
|
+
c->i += 8;
|
|
632
|
+
memcpy(&dv, &w, sizeof(dv));
|
|
633
|
+
break;
|
|
634
|
+
}
|
|
635
|
+
default:
|
|
636
|
+
if (ai < 20) { /* simple value 0..19 */
|
|
637
|
+
if (key_slot) {
|
|
638
|
+
return cbor_key_diag(c, 7, ai, 0) ? 1 : 0;
|
|
639
|
+
}
|
|
640
|
+
char buf[16];
|
|
641
|
+
memcpy(buf, "simple(", 7);
|
|
642
|
+
uint32_t n = 7 + cbor_u64dec(ai, buf + 7);
|
|
643
|
+
buf[n++] = ')';
|
|
644
|
+
return cbor_text_node(c, buf, n, 0) != UINT32_MAX ? 1 : 0;
|
|
645
|
+
}
|
|
646
|
+
CBOR_REJECT("reserved additional information");
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
if (key_slot && c->strict) {
|
|
650
|
+
CBOR_REJECT("string key required");
|
|
651
|
+
}
|
|
652
|
+
if (key_slot) {
|
|
653
|
+
return cbor_key_diag(c, 8, 0, dv) ? 1 : 0;
|
|
654
|
+
}
|
|
655
|
+
return cbor_float_node(c, dv) ? 1 : 0;
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
int yep_cbor_decode_dom(yep_dom* d, const unsigned char* p, size_t len, int strict,
|
|
659
|
+
size_t* consumed) {
|
|
660
|
+
yep_cdec c;
|
|
661
|
+
memset(&c, 0, sizeof(c));
|
|
662
|
+
c.d = d;
|
|
663
|
+
c.p = p;
|
|
664
|
+
c.len = len;
|
|
665
|
+
c.strict = strict;
|
|
666
|
+
c.status = YEPTRIS_OK;
|
|
667
|
+
int done_top = 0; /* the ONE top-level item is done (tags never count) */
|
|
668
|
+
for (;;) {
|
|
669
|
+
if (c.depth == 0) {
|
|
670
|
+
if (done_top) { /* the root closed; one data item per call */
|
|
671
|
+
if (c.i != len && consumed == NULL) {
|
|
672
|
+
cbor_fail(&c, YEP_ERR_UNEXPECTED, "trailing bytes after the data item");
|
|
673
|
+
return YEPTRIS_ERROR_PARSE;
|
|
674
|
+
}
|
|
675
|
+
if (consumed != NULL) {
|
|
676
|
+
*consumed = c.i;
|
|
677
|
+
}
|
|
678
|
+
return YEPTRIS_OK;
|
|
679
|
+
}
|
|
680
|
+
int st = cbor_item(&c);
|
|
681
|
+
if (st == 0) {
|
|
682
|
+
return (int)c.status;
|
|
683
|
+
}
|
|
684
|
+
if (st == 2) {
|
|
685
|
+
continue; /* tag chain: the content item follows */
|
|
686
|
+
}
|
|
687
|
+
done_top = 1; /* scalar root finishes at the tail check above */
|
|
688
|
+
continue;
|
|
689
|
+
}
|
|
690
|
+
yep_cframe* fr = &c.frame[c.depth - 1];
|
|
691
|
+
if (fr->rem == 0) { /* definite container complete */
|
|
692
|
+
c.d->depth--;
|
|
693
|
+
c.depth--;
|
|
694
|
+
continue;
|
|
695
|
+
}
|
|
696
|
+
if (fr->rem == YEP_CBOR_INDEF) {
|
|
697
|
+
if (c.i < c.len && c.p[c.i] == 0xFF) {
|
|
698
|
+
if (fr->is_map && c.d->map_pending_key[c.d->depth - 1]) {
|
|
699
|
+
cbor_fail(&c, YEP_ERR_UNEXPECTED,
|
|
700
|
+
"break in a map value position (odd item count)");
|
|
701
|
+
return YEPTRIS_ERROR_PARSE;
|
|
702
|
+
}
|
|
703
|
+
c.i++;
|
|
704
|
+
c.d->depth--;
|
|
705
|
+
c.depth--;
|
|
706
|
+
continue;
|
|
707
|
+
}
|
|
708
|
+
}
|
|
709
|
+
size_t parent = (size_t)(c.depth - 1);
|
|
710
|
+
int st = cbor_item(&c);
|
|
711
|
+
if (st == 0) {
|
|
712
|
+
return (int)c.status;
|
|
713
|
+
}
|
|
714
|
+
if (st == 2) {
|
|
715
|
+
continue; /* tags never consume a container slot */
|
|
716
|
+
}
|
|
717
|
+
if (c.frame[parent].rem != YEP_CBOR_INDEF) {
|
|
718
|
+
c.frame[parent].rem--;
|
|
719
|
+
/* one item (scalar, or a container now open) consumed a parent slot */
|
|
720
|
+
}
|
|
721
|
+
}
|
|
722
|
+
}
|
|
723
|
+
|
|
724
|
+
static YeptrisDocument cbor_wrap(yep_dom* dom, const void* buf, const yep_allocator* sys) {
|
|
725
|
+
yeptris_document* d = yep_alloc(sys, sizeof(yeptris_document));
|
|
726
|
+
if (d == NULL) {
|
|
727
|
+
yep_dom_destroy(dom);
|
|
728
|
+
return NULL;
|
|
729
|
+
}
|
|
730
|
+
d->dom = dom;
|
|
731
|
+
d->sys = sys;
|
|
732
|
+
d->schema = YEPTRIS_SCHEMA_12_CORE;
|
|
733
|
+
d->transcoded = NULL;
|
|
734
|
+
d->transcoded_len = 0;
|
|
735
|
+
d->input = (const char*)buf;
|
|
736
|
+
d->finish_pool = NULL;
|
|
737
|
+
return (YeptrisDocument)d;
|
|
738
|
+
}
|
|
739
|
+
|
|
740
|
+
YEPTRIS_API size_t yeptris_cbor_decode_sequence(const void* buf, size_t len, uint32_t opts,
|
|
741
|
+
yeptris_cbor_item_cb cb, void* ctx,
|
|
742
|
+
YeptrisStatus* status) {
|
|
743
|
+
if ((buf == NULL && len != 0) || cb == NULL || (opts & ~YEPTRIS_CBOR_STRICT) != 0) {
|
|
744
|
+
if (status != NULL) {
|
|
745
|
+
*status = YEPTRIS_ERROR_ARG;
|
|
746
|
+
}
|
|
747
|
+
return 0;
|
|
748
|
+
}
|
|
749
|
+
int strict = (opts & YEPTRIS_CBOR_STRICT) != 0;
|
|
750
|
+
const yep_allocator* sys = yep_system_allocator();
|
|
751
|
+
const unsigned char* p = (const unsigned char*)buf;
|
|
752
|
+
size_t i = 0;
|
|
753
|
+
size_t count = 0;
|
|
754
|
+
for (;;) {
|
|
755
|
+
if (i >= len) {
|
|
756
|
+
if (status != NULL) {
|
|
757
|
+
*status = YEPTRIS_OK; /* RFC 8742: an empty sequence is valid */
|
|
758
|
+
}
|
|
759
|
+
return count;
|
|
760
|
+
}
|
|
761
|
+
yep_dom* dom = yep_dom_create(sys);
|
|
762
|
+
if (dom == NULL) {
|
|
763
|
+
if (status != NULL) {
|
|
764
|
+
*status = YEPTRIS_ERROR_MEMORY;
|
|
765
|
+
}
|
|
766
|
+
return count;
|
|
767
|
+
}
|
|
768
|
+
dom->input_base = (const char*)(p + i); /* item-relative borrows */
|
|
769
|
+
dom->input_len = len - i;
|
|
770
|
+
size_t used = 0;
|
|
771
|
+
YeptrisStatus st = (YeptrisStatus)yep_cbor_decode_dom(dom, p + i, len - i, strict, &used);
|
|
772
|
+
if (st != YEPTRIS_OK) {
|
|
773
|
+
yep_error_set(yep_error_tls(), YEP_ERR_UNEXPECTED, 0, 0, i,
|
|
774
|
+
"CBOR sequence item %zu at byte %zu is not well-formed", count, i);
|
|
775
|
+
yep_dom_destroy(dom);
|
|
776
|
+
if (status != NULL) {
|
|
777
|
+
*status = st == YEPTRIS_ERROR_MEMORY ? st : YEPTRIS_ERROR_PARSE;
|
|
778
|
+
}
|
|
779
|
+
return count;
|
|
780
|
+
}
|
|
781
|
+
YeptrisDocument doc = cbor_wrap(dom, p + i, sys);
|
|
782
|
+
if (doc == NULL) {
|
|
783
|
+
if (status != NULL) {
|
|
784
|
+
*status = YEPTRIS_ERROR_MEMORY;
|
|
785
|
+
}
|
|
786
|
+
return count;
|
|
787
|
+
}
|
|
788
|
+
if (cb(ctx, doc, count) != 0) { /* the callback owns each item;
|
|
789
|
+
nonzero aborts the iteration */
|
|
790
|
+
if (status != NULL) {
|
|
791
|
+
*status = YEPTRIS_OK;
|
|
792
|
+
}
|
|
793
|
+
return count;
|
|
794
|
+
}
|
|
795
|
+
i += used;
|
|
796
|
+
count++;
|
|
797
|
+
}
|
|
798
|
+
}
|
|
799
|
+
|
|
800
|
+
YEPTRIS_API YeptrisDocument yeptris_cbor_decode(const void* buf, size_t len, uint32_t opts,
|
|
801
|
+
YeptrisStatus* status) {
|
|
802
|
+
if ((buf == NULL && len != 0) || (opts & ~YEPTRIS_CBOR_STRICT) != 0) {
|
|
803
|
+
if (status != NULL) {
|
|
804
|
+
*status = YEPTRIS_ERROR_ARG;
|
|
805
|
+
}
|
|
806
|
+
return NULL;
|
|
807
|
+
}
|
|
808
|
+
const yep_allocator* sys = yep_system_allocator();
|
|
809
|
+
yep_dom* dom = yep_dom_create(sys);
|
|
810
|
+
if (dom == NULL) {
|
|
811
|
+
if (status != NULL) {
|
|
812
|
+
*status = YEPTRIS_ERROR_MEMORY;
|
|
813
|
+
}
|
|
814
|
+
return NULL;
|
|
815
|
+
}
|
|
816
|
+
dom->input_base = (const char*)buf;
|
|
817
|
+
dom->input_len = len;
|
|
818
|
+
YeptrisStatus st = (YeptrisStatus)yep_cbor_decode_dom(dom, (const unsigned char*)buf, len,
|
|
819
|
+
(opts & YEPTRIS_CBOR_STRICT) != 0, NULL);
|
|
820
|
+
if (st != YEPTRIS_OK) {
|
|
821
|
+
yep_dom_destroy(dom);
|
|
822
|
+
if (status != NULL) {
|
|
823
|
+
*status = st;
|
|
824
|
+
}
|
|
825
|
+
return NULL;
|
|
826
|
+
}
|
|
827
|
+
yeptris_document* doc = yep_alloc(sys, sizeof(yeptris_document));
|
|
828
|
+
if (doc == NULL) {
|
|
829
|
+
yep_dom_destroy(dom);
|
|
830
|
+
if (status != NULL) {
|
|
831
|
+
*status = YEPTRIS_ERROR_MEMORY;
|
|
832
|
+
}
|
|
833
|
+
return NULL;
|
|
834
|
+
}
|
|
835
|
+
doc->dom = dom;
|
|
836
|
+
doc->sys = sys;
|
|
837
|
+
doc->schema = YEPTRIS_SCHEMA_12_CORE; /* CBOR's model is the core schema */
|
|
838
|
+
doc->transcoded = NULL;
|
|
839
|
+
doc->transcoded_len = 0;
|
|
840
|
+
doc->input = (const char*)buf;
|
|
841
|
+
doc->finish_pool = NULL;
|
|
842
|
+
if (status != NULL) {
|
|
843
|
+
*status = YEPTRIS_OK;
|
|
844
|
+
}
|
|
845
|
+
return (YeptrisDocument)doc;
|
|
846
|
+
}
|