yeptris 0.6.18.2-arm-linux-eabihf
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 +7 -0
- data/README.adoc +141 -0
- data/ext/build_windows_native.rb +41 -0
- data/ext/libyeptris/extconf.rb +57 -0
- data/ext/yeptris_native/cbor_ruby.c +193 -0
- data/ext/yeptris_native/extconf.rb +47 -0
- data/ext/yeptris_native/json_ruby.c +354 -0
- data/ext/yeptris_native/yeptris_native.c +497 -0
- data/lib/yeptris/cbor.rb +130 -0
- data/lib/yeptris/document.rb +255 -0
- data/lib/yeptris/ffi.rb +426 -0
- data/lib/yeptris/json/descriptor.rb +266 -0
- data/lib/yeptris/json.rb +394 -0
- data/lib/yeptris/materializer.rb +354 -0
- data/lib/yeptris/native-3.4.so +0 -0
- data/lib/yeptris/node.rb +453 -0
- data/lib/yeptris/psych/class_loader.rb +24 -0
- data/lib/yeptris/psych/coder_shim.rb +55 -0
- data/lib/yeptris/psych/drop_in.rb +63 -0
- data/lib/yeptris/psych/encodable.rb +14 -0
- data/lib/yeptris/psych/handler.rb +90 -0
- data/lib/yeptris/psych/parser.rb +105 -0
- data/lib/yeptris/psych/scalar_scanner.rb +149 -0
- data/lib/yeptris/psych/visitors.rb +545 -0
- data/lib/yeptris/psych.rb +622 -0
- data/lib/yeptris/schema.rb +253 -0
- data/lib/yeptris/valueml.rb +455 -0
- data/lib/yeptris/yaml/descriptor.rb +56 -0
- data/lib/yeptris/yaml.rb +422 -0
- data/lib/yeptris.rb +113 -0
- data/libyeptris.so +0 -0
- 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 +190 -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 +121 -0
- data/vendor/libyeptris/src/include/yeptris/tape.h +123 -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 +376 -0
- data/vendor/libyeptris/src/yeptris/cbor/cbor.h +25 -0
- data/vendor/libyeptris/src/yeptris/cbor/decode.c +981 -0
- data/vendor/libyeptris/src/yeptris/cbor/encode.c +835 -0
- data/vendor/libyeptris/src/yeptris/cbor/sink.h +58 -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 +56 -0
- data/vendor/libyeptris/src/yeptris/dom/dom.c +1192 -0
- data/vendor/libyeptris/src/yeptris/dom/dom.h +312 -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 +431 -0
- data/vendor/libyeptris/src/yeptris/emit/emit.c +434 -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 +231 -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 +816 -0
- data/vendor/libyeptris/src/yeptris/emit/writer.h +76 -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 +782 -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 +122 -0
- data/vendor/libyeptris/src/yeptris/memory/pool.h +36 -0
- data/vendor/libyeptris/src/yeptris/parse/engine.c +3698 -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 +737 -0
- data/vendor/libyeptris/src/yeptris/plan.c +824 -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 +308 -0
- data/vendor/libyeptris/src/yeptris/tape.c +1308 -0
- data/vendor/libyeptris/src/yeptris/tape_in.h +19 -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 +199 -0
|
@@ -0,0 +1,981 @@
|
|
|
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 <stdlib.h>
|
|
31
|
+
|
|
32
|
+
#include <yeptris/cbor.h>
|
|
33
|
+
#include <yeptris/resolve.h>
|
|
34
|
+
|
|
35
|
+
#include "../common/error.h"
|
|
36
|
+
#include "../doc.h"
|
|
37
|
+
#include "../emit/float/api.h"
|
|
38
|
+
#include "../encoding/encoding.h"
|
|
39
|
+
#include "../memory/allocator.h"
|
|
40
|
+
#include "../parse/events.h"
|
|
41
|
+
#include "doc.h"
|
|
42
|
+
#include "sink.h"
|
|
43
|
+
|
|
44
|
+
#define YEP_CBOR_INDEF UINT64_MAX
|
|
45
|
+
#define YEP_CBOR_MAX_ARG_BYTES 8
|
|
46
|
+
|
|
47
|
+
typedef struct {
|
|
48
|
+
uint64_t rem; /* items left; maps count 2*pairs; INDEF = until break */
|
|
49
|
+
uint64_t consumed; /* items landed (the key/value parity) */
|
|
50
|
+
uint8_t is_map;
|
|
51
|
+
} yep_cframe;
|
|
52
|
+
|
|
53
|
+
#define YEP_CBOR_TAGBUF \
|
|
54
|
+
512 /* a semantic-tag chain over ~23 links is \
|
|
55
|
+
* pathological; the arena form had no cap, \
|
|
56
|
+
* the stack form does (documented) */
|
|
57
|
+
|
|
58
|
+
typedef struct {
|
|
59
|
+
yep_dom* d; /* the DOM sink's ctx (NULL for pure sinks) */
|
|
60
|
+
const unsigned char* p;
|
|
61
|
+
size_t len;
|
|
62
|
+
size_t i;
|
|
63
|
+
int strict;
|
|
64
|
+
YeptrisStatus status;
|
|
65
|
+
/* the pending semantic-tag chain, text form ("N N N", outermost
|
|
66
|
+
* first — the next item's writer consumes it) */
|
|
67
|
+
char tagbuf[YEP_CBOR_TAGBUF];
|
|
68
|
+
uint32_t taglen;
|
|
69
|
+
/* indefinite-string accumulation (chunk framing is the grammar's;
|
|
70
|
+
* the finished span goes to one str/bytes callback) */
|
|
71
|
+
unsigned char* ibuf;
|
|
72
|
+
size_t icap;
|
|
73
|
+
uint32_t ilen;
|
|
74
|
+
const yep_cbor_sink* s;
|
|
75
|
+
yep_cframe frame[YEP_DOM_MAX_DEPTH];
|
|
76
|
+
int depth;
|
|
77
|
+
} yep_cdec;
|
|
78
|
+
|
|
79
|
+
static void cbor_fail(yep_cdec* c, yep_err_code code, const char* msg) {
|
|
80
|
+
yep_error_set(yep_error_tls(), code, 0, 0, c->i, "%s at byte %zu", msg, c->i);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
#define CBOR_REJECT(what) \
|
|
84
|
+
do { \
|
|
85
|
+
cbor_fail(c, YEP_ERR_UNEXPECTED, what); \
|
|
86
|
+
c->status = YEPTRIS_ERROR_PARSE; \
|
|
87
|
+
return 0; \
|
|
88
|
+
} while (0)
|
|
89
|
+
|
|
90
|
+
/* The head's argument: additional info 0-23 inline, 24-27 a 1/2/4/8-byte
|
|
91
|
+
* big-endian value; 28-30 are reserved (never well-formed). Strict mode
|
|
92
|
+
* also rejects non-minimal encodings (RFC 8949 s4.2.1's argument rule).
|
|
93
|
+
* ai 31 is the caller's (indefinite/break) — never reaches here. */
|
|
94
|
+
static int cbor_arg(yep_cdec* c, uint8_t ai, uint64_t* val) {
|
|
95
|
+
static const uint8_t nbytes[4] = {1, 2, 4, 8};
|
|
96
|
+
static const uint64_t minv[4] = {24, 0x100ull, 0x10000ull, 0x100000000ull};
|
|
97
|
+
if (ai >= 28) {
|
|
98
|
+
CBOR_REJECT("reserved additional information (28-30)");
|
|
99
|
+
}
|
|
100
|
+
uint64_t v = ai;
|
|
101
|
+
if (ai >= 24) {
|
|
102
|
+
size_t n = nbytes[ai - 24];
|
|
103
|
+
if (c->len - c->i < n) {
|
|
104
|
+
cbor_fail(c, YEP_ERR_UNEXPECTED, "truncated head");
|
|
105
|
+
c->status = YEPTRIS_ERROR_PARSE;
|
|
106
|
+
return 0;
|
|
107
|
+
}
|
|
108
|
+
v = 0;
|
|
109
|
+
for (size_t k = 0; k < n; k++) {
|
|
110
|
+
v = (v << 8) | c->p[c->i + k];
|
|
111
|
+
}
|
|
112
|
+
c->i += n;
|
|
113
|
+
if (c->strict && v < minv[ai - 24]) {
|
|
114
|
+
CBOR_REJECT("non-minimal length argument");
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
*val = v;
|
|
118
|
+
return 1;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
static uint32_t cbor_u64dec(uint64_t v, char* buf) {
|
|
122
|
+
char tmp[20];
|
|
123
|
+
uint32_t n = 0;
|
|
124
|
+
do {
|
|
125
|
+
tmp[n++] = (char)('0' + (v % 10));
|
|
126
|
+
v /= 10;
|
|
127
|
+
} while (v != 0);
|
|
128
|
+
for (uint32_t k = 0; k < n; k++) {
|
|
129
|
+
buf[k] = tmp[n - 1 - k];
|
|
130
|
+
}
|
|
131
|
+
return n;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/* ldexp without libm: the exponent range here is [-24, 5], so scaling
|
|
135
|
+
* by repeated doubling/halving is exact and bounded. */
|
|
136
|
+
static double cbor_pow2(double x, int e) {
|
|
137
|
+
while (e > 0) {
|
|
138
|
+
x *= 2.0;
|
|
139
|
+
e--;
|
|
140
|
+
}
|
|
141
|
+
while (e < 0) {
|
|
142
|
+
x *= 0.5;
|
|
143
|
+
e++;
|
|
144
|
+
}
|
|
145
|
+
return x;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/* The RFC 8949 Appendix D half-precision decoder, verbatim shape. */
|
|
149
|
+
static double cbor_half(uint16_t h) {
|
|
150
|
+
unsigned exp = (h >> 10) & 0x1fu;
|
|
151
|
+
unsigned mant = h & 0x3ffu;
|
|
152
|
+
double val;
|
|
153
|
+
if (exp == 0) {
|
|
154
|
+
val = cbor_pow2((double)mant, -24);
|
|
155
|
+
} else if (exp != 31) {
|
|
156
|
+
val = cbor_pow2((double)(mant + 1024), (int)exp - 25);
|
|
157
|
+
} else {
|
|
158
|
+
val = mant == 0 ? (double)INFINITY : (double)NAN;
|
|
159
|
+
}
|
|
160
|
+
return (h & 0x8000u) != 0 ? -val : val;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/* The pending semantic-tag chain, consumed by the next writer. */
|
|
164
|
+
static const char* cbor_take_tag(yep_cdec* c, uint32_t* len) {
|
|
165
|
+
if (c->taglen == 0) {
|
|
166
|
+
*len = 0;
|
|
167
|
+
return NULL;
|
|
168
|
+
}
|
|
169
|
+
*len = c->taglen;
|
|
170
|
+
c->taglen = 0;
|
|
171
|
+
return c->tagbuf;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/* Rendered text (numbers-as-text, literals, diagnostics). */
|
|
175
|
+
static uint32_t cbor_text_node(yep_cdec* c, const char* text, uint32_t n, uint8_t tag_id,
|
|
176
|
+
int is_key) {
|
|
177
|
+
uint32_t tag_len;
|
|
178
|
+
const char* tag = cbor_take_tag(c, &tag_len);
|
|
179
|
+
if (!c->s->text(c->s->ctx, text, n, tag_id, is_key, tag, tag_len)) {
|
|
180
|
+
c->status = YEPTRIS_ERROR_MEMORY;
|
|
181
|
+
return UINT32_MAX;
|
|
182
|
+
}
|
|
183
|
+
return 0; /* item identity is the sink's business */
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/* Definite string (mt2 -> bytes_val, mt3 -> str_val), borrowing the input. */
|
|
187
|
+
static uint32_t cbor_span_node(yep_cdec* c, const unsigned char* p, uint32_t n, uint8_t mt,
|
|
188
|
+
int is_key) {
|
|
189
|
+
uint32_t tag_len;
|
|
190
|
+
const char* tag = cbor_take_tag(c, &tag_len);
|
|
191
|
+
int ok = (mt == 2) ? c->s->bytes_val(c->s->ctx, p, n, 1, is_key, tag, tag_len)
|
|
192
|
+
: c->s->str_val(c->s->ctx, p, n, 1, is_key, tag, tag_len);
|
|
193
|
+
if (!ok) {
|
|
194
|
+
c->status = YEPTRIS_ERROR_MEMORY;
|
|
195
|
+
return UINT32_MAX;
|
|
196
|
+
}
|
|
197
|
+
return 0;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
static int cbor_open(yep_cdec* c, int is_map, uint64_t cap) {
|
|
201
|
+
if (c->depth >= YEP_DOM_MAX_DEPTH) {
|
|
202
|
+
yep_error_set(yep_error_tls(), YEP_ERR_UNEXPECTED, 0, 0, c->i,
|
|
203
|
+
"CBOR nesting exceeds the depth guard at byte %zu", c->i);
|
|
204
|
+
c->status = YEPTRIS_ERROR_DEPTH;
|
|
205
|
+
return 0;
|
|
206
|
+
}
|
|
207
|
+
uint32_t tag_len;
|
|
208
|
+
const char* tag = cbor_take_tag(c, &tag_len);
|
|
209
|
+
if (!c->s->open(c->s->ctx, is_map, cap, tag, tag_len)) {
|
|
210
|
+
c->status = YEPTRIS_ERROR_MEMORY;
|
|
211
|
+
return 0;
|
|
212
|
+
}
|
|
213
|
+
/* a sibling at this depth may have left state behind */
|
|
214
|
+
c->frame[c->depth].consumed = 0;
|
|
215
|
+
c->depth++;
|
|
216
|
+
return 1;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
static int cbor_note_tag(yep_cdec* c, uint64_t tag) {
|
|
220
|
+
if (c->taglen + 1 + 20 > sizeof c->tagbuf) {
|
|
221
|
+
yep_error_set(yep_error_tls(), YEP_ERR_UNEXPECTED, 0, 0, c->i,
|
|
222
|
+
"semantic-tag chain exceeds %u bytes at byte %zu", (unsigned)sizeof c->tagbuf,
|
|
223
|
+
c->i);
|
|
224
|
+
c->status = YEPTRIS_ERROR_PARSE;
|
|
225
|
+
return 0;
|
|
226
|
+
}
|
|
227
|
+
if (c->taglen > 0) {
|
|
228
|
+
c->tagbuf[c->taglen++] = ' '; /* separator between chain links */
|
|
229
|
+
}
|
|
230
|
+
c->taglen += cbor_u64dec(tag, c->tagbuf + c->taglen);
|
|
231
|
+
return 1;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
/* One complete indefinite-length string (chunks concatenate in the
|
|
235
|
+
* arena; text chunks validate per chunk — RFC 8949 s3.2.3's code-point
|
|
236
|
+
* boundary rule makes per-chunk validity imply whole-string validity). */
|
|
237
|
+
static int cbor_indef_string(yep_cdec* c, int is_text) {
|
|
238
|
+
uint32_t total = 0;
|
|
239
|
+
for (;;) {
|
|
240
|
+
if (c->i >= c->len) {
|
|
241
|
+
CBOR_REJECT("unterminated indefinite-length string");
|
|
242
|
+
}
|
|
243
|
+
uint8_t ib = c->p[c->i];
|
|
244
|
+
c->i++;
|
|
245
|
+
if (ib == 0xFF) {
|
|
246
|
+
break;
|
|
247
|
+
}
|
|
248
|
+
if ((ib >> 5) != (is_text ? 3 : 2) || (ib & 0x1F) == 31) {
|
|
249
|
+
CBOR_REJECT("indefinite-length string chunk must be definite, same major type");
|
|
250
|
+
}
|
|
251
|
+
uint64_t n = 0;
|
|
252
|
+
if (!cbor_arg(c, ib & 0x1F, &n)) {
|
|
253
|
+
return 0;
|
|
254
|
+
}
|
|
255
|
+
if (n > c->len - c->i) {
|
|
256
|
+
CBOR_REJECT("truncated string chunk");
|
|
257
|
+
}
|
|
258
|
+
if (is_text && !yep_utf8_validate(c->p + c->i, (size_t)n, NULL)) {
|
|
259
|
+
yep_error_set(yep_error_tls(), YEP_ERR_UNEXPECTED, 0, 0, c->i,
|
|
260
|
+
"ill-formed UTF-8 in text string at byte %zu", c->i);
|
|
261
|
+
c->status = YEPTRIS_ERROR_ENCODING;
|
|
262
|
+
return 0;
|
|
263
|
+
}
|
|
264
|
+
if (n > 0) { /* zero-length chunks are legal, just empty */
|
|
265
|
+
if (total + n > c->icap) {
|
|
266
|
+
size_t ncap = c->icap ? c->icap * 2 : 256;
|
|
267
|
+
while (ncap < total + n) {
|
|
268
|
+
ncap *= 2;
|
|
269
|
+
}
|
|
270
|
+
unsigned char* nib = realloc(c->ibuf, ncap);
|
|
271
|
+
if (nib == NULL) {
|
|
272
|
+
c->status = YEPTRIS_ERROR_MEMORY;
|
|
273
|
+
return 0;
|
|
274
|
+
}
|
|
275
|
+
c->ibuf = nib;
|
|
276
|
+
c->icap = ncap;
|
|
277
|
+
}
|
|
278
|
+
memcpy(c->ibuf + total, c->p + c->i, (size_t)n);
|
|
279
|
+
total += (uint32_t)n;
|
|
280
|
+
}
|
|
281
|
+
c->i += (size_t)n;
|
|
282
|
+
}
|
|
283
|
+
/* one value over the accumulated span */
|
|
284
|
+
uint32_t tag_len;
|
|
285
|
+
const char* tag = cbor_take_tag(c, &tag_len);
|
|
286
|
+
int ok =
|
|
287
|
+
(is_text ? c->s->str_val : c->s->bytes_val)(c->s->ctx, c->ibuf, total, 0, 0, tag, tag_len);
|
|
288
|
+
if (!ok) {
|
|
289
|
+
c->status = YEPTRIS_ERROR_MEMORY;
|
|
290
|
+
return 0;
|
|
291
|
+
}
|
|
292
|
+
return 1;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
/* Known integer: value = negative ? -mag : mag, mag <= 2^63. */
|
|
296
|
+
static int cbor_int_node(yep_cdec* c, int negative, uint64_t mag, int is_key) {
|
|
297
|
+
uint32_t tag_len;
|
|
298
|
+
const char* tag = cbor_take_tag(c, &tag_len);
|
|
299
|
+
if (!c->s->int_val(c->s->ctx, negative, mag, is_key, tag, tag_len)) {
|
|
300
|
+
c->status = YEPTRIS_ERROR_MEMORY;
|
|
301
|
+
return 0;
|
|
302
|
+
}
|
|
303
|
+
return 1;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
static int cbor_float_node(yep_cdec* c, double dv, int is_key) {
|
|
307
|
+
uint32_t tag_len;
|
|
308
|
+
const char* tag = cbor_take_tag(c, &tag_len);
|
|
309
|
+
if (!c->s->float_val(c->s->ctx, dv, is_key, tag, tag_len)) {
|
|
310
|
+
c->status = YEPTRIS_ERROR_MEMORY;
|
|
311
|
+
return 0;
|
|
312
|
+
}
|
|
313
|
+
return 1;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
/* The diagnostic renderer for lenient-mode non-string SCALAR map keys
|
|
317
|
+
* (the plan's policy: what the JSON path can round-trip). */
|
|
318
|
+
static int cbor_key_diag(yep_cdec* c, uint8_t mt, uint64_t val, double dv) {
|
|
319
|
+
char buf[48];
|
|
320
|
+
uint32_t n;
|
|
321
|
+
switch (mt) {
|
|
322
|
+
case 0:
|
|
323
|
+
n = cbor_u64dec(val, buf);
|
|
324
|
+
break;
|
|
325
|
+
case 1:
|
|
326
|
+
buf[0] = '-';
|
|
327
|
+
n = 1 + cbor_u64dec(val, buf + 1);
|
|
328
|
+
break;
|
|
329
|
+
case 2: { /* h'hex' */
|
|
330
|
+
buf[0] = 'h';
|
|
331
|
+
buf[1] = '\'';
|
|
332
|
+
static const char hexd[] = "0123456789abcdef";
|
|
333
|
+
n = 2;
|
|
334
|
+
for (uint64_t k = 0; k < val && n + 2 < sizeof(buf); k++) {
|
|
335
|
+
uint8_t b = c->p[c->i + k];
|
|
336
|
+
buf[n++] = hexd[b >> 4];
|
|
337
|
+
buf[n++] = hexd[b & 15];
|
|
338
|
+
}
|
|
339
|
+
buf[n++] = '\'';
|
|
340
|
+
break;
|
|
341
|
+
}
|
|
342
|
+
case 7:
|
|
343
|
+
if (val == 20) {
|
|
344
|
+
memcpy(buf, "false", 5);
|
|
345
|
+
n = 5;
|
|
346
|
+
} else if (val == 21) {
|
|
347
|
+
memcpy(buf, "true", 4);
|
|
348
|
+
n = 4;
|
|
349
|
+
} else if (val == 22) {
|
|
350
|
+
memcpy(buf, "null", 4);
|
|
351
|
+
n = 4;
|
|
352
|
+
} else if (val == 23) {
|
|
353
|
+
memcpy(buf, "undefined", 9);
|
|
354
|
+
n = 9;
|
|
355
|
+
} else {
|
|
356
|
+
memcpy(buf, "simple(", 7);
|
|
357
|
+
n = 7 + cbor_u64dec(val, buf + 7);
|
|
358
|
+
buf[n++] = ')';
|
|
359
|
+
}
|
|
360
|
+
break;
|
|
361
|
+
default:
|
|
362
|
+
return cbor_float_node(c, dv, 1); /* floats: the shortest text */
|
|
363
|
+
}
|
|
364
|
+
return cbor_text_node(c, buf, n, 0, 1) != UINT32_MAX;
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
/* Decodes ONE data item (scalar: creates+places the node; container:
|
|
368
|
+
* opens+pushes a frame; tag: notes the chain and reports "again").
|
|
369
|
+
* Returns 1 item consumed/started, 0 failure, 2 = tag (no slot). */
|
|
370
|
+
static int cbor_item(yep_cdec* c) {
|
|
371
|
+
if (c->i >= c->len) {
|
|
372
|
+
CBOR_REJECT("truncated head");
|
|
373
|
+
}
|
|
374
|
+
uint8_t ib = c->p[c->i++];
|
|
375
|
+
uint8_t mt = ib >> 5;
|
|
376
|
+
uint8_t ai = ib & 0x1F;
|
|
377
|
+
|
|
378
|
+
/* the map-key position decides representation before the item is
|
|
379
|
+
* built: even items consumed = key, odd = value (the frame's own
|
|
380
|
+
* parity — the DOM's placement machine tracks its own copy) */
|
|
381
|
+
int key_slot = 0;
|
|
382
|
+
if (c->depth > 0 && c->frame[c->depth - 1].is_map && c->frame[c->depth - 1].consumed % 2 == 0) {
|
|
383
|
+
key_slot = 1;
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
if (ai == 31) {
|
|
387
|
+
switch (mt) {
|
|
388
|
+
case 2:
|
|
389
|
+
case 3: {
|
|
390
|
+
if (key_slot) {
|
|
391
|
+
CBOR_REJECT("string key required");
|
|
392
|
+
}
|
|
393
|
+
return cbor_indef_string(c, mt == 3) ? 1 : 0;
|
|
394
|
+
}
|
|
395
|
+
case 4:
|
|
396
|
+
if (key_slot) {
|
|
397
|
+
CBOR_REJECT("structure as map key");
|
|
398
|
+
}
|
|
399
|
+
if (!cbor_open(c, 0, YEP_CBOR_INDEF)) {
|
|
400
|
+
return 0;
|
|
401
|
+
}
|
|
402
|
+
c->frame[c->depth - 1].rem = YEP_CBOR_INDEF;
|
|
403
|
+
c->frame[c->depth - 1].is_map = 0;
|
|
404
|
+
return 1;
|
|
405
|
+
case 5:
|
|
406
|
+
if (key_slot) {
|
|
407
|
+
CBOR_REJECT("structure as map key");
|
|
408
|
+
}
|
|
409
|
+
if (!cbor_open(c, 1, YEP_CBOR_INDEF)) {
|
|
410
|
+
return 0;
|
|
411
|
+
}
|
|
412
|
+
c->frame[c->depth - 1].rem = YEP_CBOR_INDEF;
|
|
413
|
+
c->frame[c->depth - 1].is_map = 1;
|
|
414
|
+
return 1;
|
|
415
|
+
default:
|
|
416
|
+
CBOR_REJECT("additional information 31 with major type 0, 1, 6, or as an item");
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
uint64_t arg = 0;
|
|
421
|
+
if (mt == 7) {
|
|
422
|
+
/* major type 7: ai is the payload shape, not an argument width */
|
|
423
|
+
arg = ai;
|
|
424
|
+
} else if (!cbor_arg(c, ai, &arg)) {
|
|
425
|
+
return 0;
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
switch (mt) {
|
|
429
|
+
case 0: {
|
|
430
|
+
if (key_slot && c->strict) {
|
|
431
|
+
CBOR_REJECT("string key required");
|
|
432
|
+
}
|
|
433
|
+
if (key_slot) {
|
|
434
|
+
return cbor_key_diag(c, 0, arg, 0) ? 1 : 0;
|
|
435
|
+
}
|
|
436
|
+
if (arg <= (uint64_t)INT64_MAX) {
|
|
437
|
+
return cbor_int_node(c, 0, arg, key_slot) ? 1 : 0;
|
|
438
|
+
}
|
|
439
|
+
return cbor_float_node(c, (double)arg, key_slot) ? 1 : 0;
|
|
440
|
+
}
|
|
441
|
+
case 1: {
|
|
442
|
+
if (key_slot && c->strict) {
|
|
443
|
+
CBOR_REJECT("string key required");
|
|
444
|
+
}
|
|
445
|
+
if (key_slot) {
|
|
446
|
+
return cbor_key_diag(c, 1, arg, 0) ? 1 : 0;
|
|
447
|
+
}
|
|
448
|
+
if (arg <= (uint64_t)INT64_MAX + 1) { /* -1-2^63 == INT64_MIN */
|
|
449
|
+
uint64_t mag = arg + 1;
|
|
450
|
+
return cbor_int_node(c, 1, mag, key_slot) ? 1 : 0;
|
|
451
|
+
}
|
|
452
|
+
return cbor_float_node(c, -((double)arg + 1.0), key_slot) ? 1 : 0;
|
|
453
|
+
}
|
|
454
|
+
case 2:
|
|
455
|
+
case 3: {
|
|
456
|
+
if (arg > c->len - c->i) {
|
|
457
|
+
CBOR_REJECT("truncated string");
|
|
458
|
+
}
|
|
459
|
+
if (mt == 3 && !yep_utf8_validate(c->p + c->i, (size_t)arg, NULL)) {
|
|
460
|
+
yep_error_set(yep_error_tls(), YEP_ERR_UNEXPECTED, 0, 0, c->i,
|
|
461
|
+
"ill-formed UTF-8 in text string at byte %zu", c->i);
|
|
462
|
+
c->status = YEPTRIS_ERROR_ENCODING;
|
|
463
|
+
return 0;
|
|
464
|
+
}
|
|
465
|
+
if (key_slot && mt == 2 && c->strict) {
|
|
466
|
+
CBOR_REJECT("string key required"); /* a byte string is not text */
|
|
467
|
+
}
|
|
468
|
+
if (key_slot && mt == 2) {
|
|
469
|
+
int ok = cbor_key_diag(c, 2, arg, 0);
|
|
470
|
+
c->i += (size_t)arg;
|
|
471
|
+
return ok ? 1 : 0;
|
|
472
|
+
}
|
|
473
|
+
uint32_t id = cbor_span_node(c, c->p + c->i, (uint32_t)arg, (uint8_t)mt, key_slot);
|
|
474
|
+
c->i += (size_t)arg;
|
|
475
|
+
return id != UINT32_MAX ? 1 : 0;
|
|
476
|
+
}
|
|
477
|
+
case 4: {
|
|
478
|
+
if (key_slot) {
|
|
479
|
+
CBOR_REJECT("structure as map key");
|
|
480
|
+
}
|
|
481
|
+
if (arg > c->len - c->i) { /* every item consumes >= 1 byte */
|
|
482
|
+
CBOR_REJECT("array overruns the input");
|
|
483
|
+
}
|
|
484
|
+
if (!cbor_open(c, 0, arg)) {
|
|
485
|
+
return 0;
|
|
486
|
+
}
|
|
487
|
+
c->frame[c->depth - 1].rem = arg;
|
|
488
|
+
c->frame[c->depth - 1].is_map = 0;
|
|
489
|
+
return 1;
|
|
490
|
+
}
|
|
491
|
+
case 5: {
|
|
492
|
+
if (key_slot) {
|
|
493
|
+
CBOR_REJECT("structure as map key");
|
|
494
|
+
}
|
|
495
|
+
if (arg > (c->len - c->i) / 2) { /* pairs need 2 items each */
|
|
496
|
+
CBOR_REJECT("map overruns the input");
|
|
497
|
+
}
|
|
498
|
+
if (!cbor_open(c, 1, arg * 2)) {
|
|
499
|
+
return 0;
|
|
500
|
+
}
|
|
501
|
+
c->frame[c->depth - 1].rem = arg * 2;
|
|
502
|
+
c->frame[c->depth - 1].is_map = 1;
|
|
503
|
+
return 1;
|
|
504
|
+
}
|
|
505
|
+
case 6:
|
|
506
|
+
if (!cbor_note_tag(c, arg)) {
|
|
507
|
+
return 0;
|
|
508
|
+
}
|
|
509
|
+
return 2; /* the chain needs its content item */
|
|
510
|
+
default: /* 7 */
|
|
511
|
+
break;
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
/* major type 7: simple values and floats */
|
|
515
|
+
double dv = 0;
|
|
516
|
+
switch (ai) {
|
|
517
|
+
case 20:
|
|
518
|
+
if (key_slot) {
|
|
519
|
+
return cbor_key_diag(c, 7, 20, 0) ? 1 : 0;
|
|
520
|
+
}
|
|
521
|
+
return cbor_text_node(c, "false", 5, YEPTRIS_TAG_BOOL, key_slot) != UINT32_MAX ? 1 : 0;
|
|
522
|
+
case 21:
|
|
523
|
+
if (key_slot) {
|
|
524
|
+
return cbor_key_diag(c, 7, 21, 0) ? 1 : 0;
|
|
525
|
+
}
|
|
526
|
+
return cbor_text_node(c, "true", 4, YEPTRIS_TAG_BOOL, key_slot) != UINT32_MAX ? 1 : 0;
|
|
527
|
+
case 22:
|
|
528
|
+
if (key_slot) {
|
|
529
|
+
return cbor_key_diag(c, 7, 22, 0) ? 1 : 0;
|
|
530
|
+
}
|
|
531
|
+
return cbor_text_node(c, "null", 4, YEPTRIS_TAG_NULL, key_slot) != UINT32_MAX ? 1 : 0;
|
|
532
|
+
case 23:
|
|
533
|
+
if (key_slot) {
|
|
534
|
+
return cbor_key_diag(c, 7, 23, 0) ? 1 : 0;
|
|
535
|
+
}
|
|
536
|
+
return cbor_text_node(c, "undefined", 9, 0, key_slot) != UINT32_MAX ? 1 : 0;
|
|
537
|
+
case 24: {
|
|
538
|
+
if (c->len - c->i < 1) {
|
|
539
|
+
CBOR_REJECT("truncated simple value");
|
|
540
|
+
}
|
|
541
|
+
uint64_t v = c->p[c->i++];
|
|
542
|
+
if (v < 32) {
|
|
543
|
+
CBOR_REJECT("two-byte simple value below 32");
|
|
544
|
+
}
|
|
545
|
+
if (key_slot) {
|
|
546
|
+
return cbor_key_diag(c, 7, v, 0) ? 1 : 0;
|
|
547
|
+
}
|
|
548
|
+
char buf[16];
|
|
549
|
+
memcpy(buf, "simple(", 7);
|
|
550
|
+
uint32_t n = 7 + cbor_u64dec(v, buf + 7);
|
|
551
|
+
buf[n++] = ')';
|
|
552
|
+
return cbor_text_node(c, buf, n, 0, key_slot) != UINT32_MAX ? 1 : 0;
|
|
553
|
+
}
|
|
554
|
+
case 25: {
|
|
555
|
+
if (c->len - c->i < 2) {
|
|
556
|
+
CBOR_REJECT("truncated half float");
|
|
557
|
+
}
|
|
558
|
+
uint16_t h = (uint16_t)((c->p[c->i] << 8) | c->p[c->i + 1]);
|
|
559
|
+
c->i += 2;
|
|
560
|
+
dv = cbor_half(h);
|
|
561
|
+
break;
|
|
562
|
+
}
|
|
563
|
+
case 26: {
|
|
564
|
+
if (c->len - c->i < 4) {
|
|
565
|
+
CBOR_REJECT("truncated single float");
|
|
566
|
+
}
|
|
567
|
+
uint32_t w = ((uint32_t)c->p[c->i] << 24) | ((uint32_t)c->p[c->i + 1] << 16) |
|
|
568
|
+
((uint32_t)c->p[c->i + 2] << 8) | (uint32_t)c->p[c->i + 3];
|
|
569
|
+
float f;
|
|
570
|
+
c->i += 4;
|
|
571
|
+
memcpy(&f, &w, sizeof(f)); /* the single's bit pattern, widened */
|
|
572
|
+
dv = (double)f;
|
|
573
|
+
break;
|
|
574
|
+
}
|
|
575
|
+
case 27: {
|
|
576
|
+
if (c->len - c->i < 8) {
|
|
577
|
+
CBOR_REJECT("truncated double float");
|
|
578
|
+
}
|
|
579
|
+
uint64_t w = 0;
|
|
580
|
+
for (int k = 0; k < 8; k++) {
|
|
581
|
+
w = (w << 8) | c->p[c->i + (size_t)k];
|
|
582
|
+
}
|
|
583
|
+
c->i += 8;
|
|
584
|
+
memcpy(&dv, &w, sizeof(dv));
|
|
585
|
+
break;
|
|
586
|
+
}
|
|
587
|
+
default:
|
|
588
|
+
if (ai < 20) { /* simple value 0..19 */
|
|
589
|
+
if (key_slot) {
|
|
590
|
+
return cbor_key_diag(c, 7, ai, 0) ? 1 : 0;
|
|
591
|
+
}
|
|
592
|
+
char buf[16];
|
|
593
|
+
memcpy(buf, "simple(", 7);
|
|
594
|
+
uint32_t n = 7 + cbor_u64dec(ai, buf + 7);
|
|
595
|
+
buf[n++] = ')';
|
|
596
|
+
return cbor_text_node(c, buf, n, 0, key_slot) != UINT32_MAX ? 1 : 0;
|
|
597
|
+
}
|
|
598
|
+
CBOR_REJECT("reserved additional information");
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
if (key_slot && c->strict) {
|
|
602
|
+
CBOR_REJECT("string key required");
|
|
603
|
+
}
|
|
604
|
+
if (key_slot) {
|
|
605
|
+
return cbor_key_diag(c, 8, 0, dv) ? 1 : 0;
|
|
606
|
+
}
|
|
607
|
+
return cbor_float_node(c, dv, key_slot) ? 1 : 0;
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
/* The DOM sink: the yeptris_cbor_decode public path. Each impl is the
|
|
611
|
+
* pre-sink writer, byte for byte (the differential suite pins it). */
|
|
612
|
+
|
|
613
|
+
static int dom_sink_text(void* dp, const char* s, uint32_t n, uint8_t tag_id, int is_key,
|
|
614
|
+
const char* tag, uint32_t tag_len) {
|
|
615
|
+
yep_dom* d = dp;
|
|
616
|
+
(void)is_key;
|
|
617
|
+
yep_view tag_v;
|
|
618
|
+
const yep_view* tagp = NULL;
|
|
619
|
+
if (tag != NULL) {
|
|
620
|
+
char* dst = yep_dom_str_tail(d, tag_len);
|
|
621
|
+
if (dst == NULL) {
|
|
622
|
+
return 0;
|
|
623
|
+
}
|
|
624
|
+
memcpy(dst, tag, tag_len);
|
|
625
|
+
yep_sview piece = yep_dom_str_commit(d, tag_len);
|
|
626
|
+
tag_v.p = d->str + (piece.off & YEP_SV_OFF);
|
|
627
|
+
tag_v.len = tag_len;
|
|
628
|
+
tagp = &tag_v;
|
|
629
|
+
}
|
|
630
|
+
uint32_t id = dom_open_node(d, YEP_DOM_SCALAR, tagp, NULL, 0, YEP_STYLE_PLAIN, 1, 0);
|
|
631
|
+
if (id == UINT32_MAX) {
|
|
632
|
+
return 0;
|
|
633
|
+
}
|
|
634
|
+
yep_dnode* node = &d->nodes[id];
|
|
635
|
+
char* dst = yep_dom_str_tail(d, n);
|
|
636
|
+
if (dst == NULL) {
|
|
637
|
+
return 0;
|
|
638
|
+
}
|
|
639
|
+
memcpy(dst, s, n);
|
|
640
|
+
node->value = yep_dom_str_commit(d, n);
|
|
641
|
+
node->tag_id = tag_id;
|
|
642
|
+
return dom_place(d, id) == 0;
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
static int dom_sink_span(void* dp, const unsigned char* p, uint32_t n, int borrowed, int is_key,
|
|
646
|
+
const char* tag, uint32_t tag_len) {
|
|
647
|
+
yep_dom* d = dp;
|
|
648
|
+
(void)is_key;
|
|
649
|
+
(void)borrowed; /* 0 rides the scratch buffer: still copied to the arena */
|
|
650
|
+
yep_view tag_v;
|
|
651
|
+
const yep_view* tagp = NULL;
|
|
652
|
+
if (tag != NULL) {
|
|
653
|
+
char* dst = yep_dom_str_tail(d, tag_len);
|
|
654
|
+
if (dst == NULL) {
|
|
655
|
+
return 0;
|
|
656
|
+
}
|
|
657
|
+
memcpy(dst, tag, tag_len);
|
|
658
|
+
yep_sview piece = yep_dom_str_commit(d, tag_len);
|
|
659
|
+
tag_v.p = d->str + (piece.off & YEP_SV_OFF);
|
|
660
|
+
tag_v.len = tag_len;
|
|
661
|
+
tagp = &tag_v;
|
|
662
|
+
}
|
|
663
|
+
uint32_t id = dom_open_node(d, YEP_DOM_SCALAR, tagp, NULL, 0, YEP_STYLE_DOUBLE_QUOTED, 0, 0);
|
|
664
|
+
if (id == UINT32_MAX) {
|
|
665
|
+
return 0;
|
|
666
|
+
}
|
|
667
|
+
yep_dnode* node = &d->nodes[id];
|
|
668
|
+
if (borrowed) {
|
|
669
|
+
node->value.off = (uint32_t)((const char*)p - d->input_base);
|
|
670
|
+
node->value.len = n;
|
|
671
|
+
} else if (n > 0) { /* the empty indefinite string needs no arena */
|
|
672
|
+
char* dst = yep_dom_str_tail(d, n);
|
|
673
|
+
if (dst == NULL) {
|
|
674
|
+
return 0;
|
|
675
|
+
}
|
|
676
|
+
memcpy(dst, p, n);
|
|
677
|
+
node->value = yep_dom_str_commit(d, n);
|
|
678
|
+
}
|
|
679
|
+
return dom_place(d, id) == 0;
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
static int dom_sink_str(void* dp, const unsigned char* p, uint32_t n, int borrowed, int is_key,
|
|
683
|
+
const char* tag, uint32_t tag_len) {
|
|
684
|
+
return dom_sink_span(dp, p, n, borrowed, is_key, tag, tag_len);
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
static int dom_sink_bytes(void* dp, const unsigned char* p, uint32_t n, int borrowed, int is_key,
|
|
688
|
+
const char* tag, uint32_t tag_len) {
|
|
689
|
+
return dom_sink_span(dp, p, n, borrowed, is_key, tag, tag_len);
|
|
690
|
+
}
|
|
691
|
+
|
|
692
|
+
static int dom_sink_open(void* dp, int is_map, uint64_t cap, const char* tag, uint32_t tag_len) {
|
|
693
|
+
yep_dom* d = dp;
|
|
694
|
+
(void)cap;
|
|
695
|
+
yep_view tag_v;
|
|
696
|
+
const yep_view* tagp = NULL;
|
|
697
|
+
if (tag != NULL) {
|
|
698
|
+
char* dst = yep_dom_str_tail(d, tag_len);
|
|
699
|
+
if (dst == NULL) {
|
|
700
|
+
return 0;
|
|
701
|
+
}
|
|
702
|
+
memcpy(dst, tag, tag_len);
|
|
703
|
+
yep_sview piece = yep_dom_str_commit(d, tag_len);
|
|
704
|
+
tag_v.p = d->str + (piece.off & YEP_SV_OFF);
|
|
705
|
+
tag_v.len = tag_len;
|
|
706
|
+
tagp = &tag_v;
|
|
707
|
+
}
|
|
708
|
+
uint32_t id =
|
|
709
|
+
dom_open_node(d, is_map ? YEP_DOM_MAPPING : YEP_DOM_SEQUENCE, tagp, NULL, 0, 0, 0, 1);
|
|
710
|
+
if (id == UINT32_MAX) {
|
|
711
|
+
return 0;
|
|
712
|
+
}
|
|
713
|
+
if (dom_place(d, id) != 0) {
|
|
714
|
+
return 0;
|
|
715
|
+
}
|
|
716
|
+
d->map_pending_key[d->depth] = 0;
|
|
717
|
+
d->stack[d->depth++] = id;
|
|
718
|
+
return 1;
|
|
719
|
+
}
|
|
720
|
+
|
|
721
|
+
static int dom_sink_close(void* dp, int is_map) {
|
|
722
|
+
yep_dom* d = dp;
|
|
723
|
+
(void)is_map;
|
|
724
|
+
d->depth--;
|
|
725
|
+
return 1;
|
|
726
|
+
}
|
|
727
|
+
|
|
728
|
+
static int dom_sink_int(void* dp, int negative, uint64_t mag, int is_key, const char* tag,
|
|
729
|
+
uint32_t tag_len) {
|
|
730
|
+
char buf[24];
|
|
731
|
+
uint32_t n = 0;
|
|
732
|
+
if (negative) {
|
|
733
|
+
buf[n++] = '-';
|
|
734
|
+
}
|
|
735
|
+
n += cbor_u64dec(mag, buf + n);
|
|
736
|
+
return dom_sink_text(dp, buf, n, YEPTRIS_TAG_INT, is_key, tag, tag_len);
|
|
737
|
+
}
|
|
738
|
+
|
|
739
|
+
static int dom_sink_float(void* dp, double dv, int is_key, const char* tag, uint32_t tag_len) {
|
|
740
|
+
char buf[48];
|
|
741
|
+
(void)is_key;
|
|
742
|
+
uint32_t n;
|
|
743
|
+
if (dv != dv) {
|
|
744
|
+
memcpy(buf, "NaN", 3);
|
|
745
|
+
n = 3;
|
|
746
|
+
} else if (dv > 1.7976931348623157e308) {
|
|
747
|
+
memcpy(buf, "Infinity", 8);
|
|
748
|
+
n = 8;
|
|
749
|
+
} else if (dv < -1.7976931348623157e308) {
|
|
750
|
+
memcpy(buf, "-Infinity", 9);
|
|
751
|
+
n = 9;
|
|
752
|
+
} else {
|
|
753
|
+
n = (uint32_t)yep_d2s_shortest(dv, buf);
|
|
754
|
+
}
|
|
755
|
+
return dom_sink_text(dp, buf, n, YEPTRIS_TAG_FLOAT, is_key, tag, tag_len);
|
|
756
|
+
}
|
|
757
|
+
|
|
758
|
+
static const yep_cbor_sink yep_cbor_dom_sink_impl = {
|
|
759
|
+
NULL, dom_sink_text, dom_sink_int, dom_sink_float,
|
|
760
|
+
dom_sink_str, dom_sink_bytes, dom_sink_open, dom_sink_close,
|
|
761
|
+
};
|
|
762
|
+
|
|
763
|
+
int yep_cbor_decode_gen(const unsigned char* p, size_t len, int strict, size_t* consumed,
|
|
764
|
+
const yep_cbor_sink* sink) {
|
|
765
|
+
yep_cdec c;
|
|
766
|
+
memset(&c, 0, sizeof(c));
|
|
767
|
+
c.s = sink;
|
|
768
|
+
c.p = p;
|
|
769
|
+
c.len = len;
|
|
770
|
+
c.strict = strict;
|
|
771
|
+
c.status = YEPTRIS_OK;
|
|
772
|
+
int done_top = 0; /* the ONE top-level item is done (tags never count) */
|
|
773
|
+
int rc;
|
|
774
|
+
for (;;) {
|
|
775
|
+
if (c.depth == 0) {
|
|
776
|
+
if (done_top) { /* the root closed; one data item per call */
|
|
777
|
+
if (c.i != len && consumed == NULL) {
|
|
778
|
+
cbor_fail(&c, YEP_ERR_UNEXPECTED, "trailing bytes after the data item");
|
|
779
|
+
rc = YEPTRIS_ERROR_PARSE;
|
|
780
|
+
goto done;
|
|
781
|
+
}
|
|
782
|
+
if (consumed != NULL) {
|
|
783
|
+
*consumed = c.i;
|
|
784
|
+
}
|
|
785
|
+
rc = YEPTRIS_OK;
|
|
786
|
+
goto done;
|
|
787
|
+
}
|
|
788
|
+
int st = cbor_item(&c);
|
|
789
|
+
if (st == 0) {
|
|
790
|
+
rc = (int)c.status;
|
|
791
|
+
goto done;
|
|
792
|
+
}
|
|
793
|
+
if (st == 2) {
|
|
794
|
+
continue; /* tag chain: the content item follows */
|
|
795
|
+
}
|
|
796
|
+
done_top = 1; /* scalar root finishes at the tail check above */
|
|
797
|
+
continue;
|
|
798
|
+
}
|
|
799
|
+
yep_cframe* fr = &c.frame[c.depth - 1];
|
|
800
|
+
if (fr->rem == 0) { /* definite container complete */
|
|
801
|
+
if (!c.s->close(c.s->ctx, fr->is_map)) {
|
|
802
|
+
rc = YEPTRIS_ERROR_MEMORY;
|
|
803
|
+
goto done;
|
|
804
|
+
}
|
|
805
|
+
c.depth--;
|
|
806
|
+
continue;
|
|
807
|
+
}
|
|
808
|
+
if (fr->rem == YEP_CBOR_INDEF) {
|
|
809
|
+
if (c.i < c.len && c.p[c.i] == 0xFF) {
|
|
810
|
+
if (fr->is_map && fr->consumed % 2 == 1) {
|
|
811
|
+
cbor_fail(&c, YEP_ERR_UNEXPECTED,
|
|
812
|
+
"break in a map value position (odd item count)");
|
|
813
|
+
rc = YEPTRIS_ERROR_PARSE;
|
|
814
|
+
goto done;
|
|
815
|
+
}
|
|
816
|
+
c.i++;
|
|
817
|
+
if (!c.s->close(c.s->ctx, fr->is_map)) {
|
|
818
|
+
rc = YEPTRIS_ERROR_MEMORY;
|
|
819
|
+
goto done;
|
|
820
|
+
}
|
|
821
|
+
c.depth--;
|
|
822
|
+
continue;
|
|
823
|
+
}
|
|
824
|
+
}
|
|
825
|
+
size_t parent = (size_t)(c.depth - 1);
|
|
826
|
+
int st = cbor_item(&c);
|
|
827
|
+
if (st == 0) {
|
|
828
|
+
rc = (int)c.status;
|
|
829
|
+
goto done;
|
|
830
|
+
}
|
|
831
|
+
if (st == 2) {
|
|
832
|
+
continue; /* tags never consume a container slot */
|
|
833
|
+
}
|
|
834
|
+
c.frame[parent].consumed++;
|
|
835
|
+
if (c.frame[parent].rem != YEP_CBOR_INDEF) {
|
|
836
|
+
c.frame[parent].rem--;
|
|
837
|
+
/* one item (scalar, or a container now open) consumed a parent slot */
|
|
838
|
+
}
|
|
839
|
+
}
|
|
840
|
+
done:
|
|
841
|
+
free(c.ibuf);
|
|
842
|
+
return rc;
|
|
843
|
+
}
|
|
844
|
+
|
|
845
|
+
int yep_cbor_decode_dom_sink(void* dp, const unsigned char* p, size_t len, int strict,
|
|
846
|
+
size_t* consumed) {
|
|
847
|
+
yep_cbor_sink s = yep_cbor_dom_sink_impl;
|
|
848
|
+
s.ctx = dp;
|
|
849
|
+
return yep_cbor_decode_gen(p, len, strict, consumed, &s);
|
|
850
|
+
}
|
|
851
|
+
|
|
852
|
+
int yep_cbor_decode_dom(yep_dom* d, const unsigned char* p, size_t len, int strict,
|
|
853
|
+
size_t* consumed) {
|
|
854
|
+
return yep_cbor_decode_dom_sink(d, p, len, strict, consumed);
|
|
855
|
+
}
|
|
856
|
+
|
|
857
|
+
static YeptrisDocument cbor_wrap(yep_dom* dom, const void* buf, const yep_allocator* sys) {
|
|
858
|
+
yeptris_document* d = yep_alloc(sys, sizeof(yeptris_document));
|
|
859
|
+
if (d == NULL) {
|
|
860
|
+
yep_dom_destroy(dom);
|
|
861
|
+
return NULL;
|
|
862
|
+
}
|
|
863
|
+
d->dom = dom;
|
|
864
|
+
d->sys = sys;
|
|
865
|
+
d->schema = YEPTRIS_SCHEMA_12_CORE;
|
|
866
|
+
d->transcoded = NULL;
|
|
867
|
+
d->transcoded_len = 0;
|
|
868
|
+
d->input = (const char*)buf;
|
|
869
|
+
d->finish_pool = NULL;
|
|
870
|
+
d->lazy_tape = NULL; /* field-by-field ctor: no garbage for free */
|
|
871
|
+
return (YeptrisDocument)d;
|
|
872
|
+
}
|
|
873
|
+
|
|
874
|
+
YEPTRIS_API size_t yeptris_cbor_decode_sequence(const void* buf, size_t len, uint32_t opts,
|
|
875
|
+
yeptris_cbor_item_cb cb, void* ctx,
|
|
876
|
+
YeptrisStatus* status) {
|
|
877
|
+
if ((buf == NULL && len != 0) || cb == NULL || (opts & ~YEPTRIS_CBOR_STRICT) != 0) {
|
|
878
|
+
if (status != NULL) {
|
|
879
|
+
*status = YEPTRIS_ERROR_ARG;
|
|
880
|
+
}
|
|
881
|
+
return 0;
|
|
882
|
+
}
|
|
883
|
+
int strict = (opts & YEPTRIS_CBOR_STRICT) != 0;
|
|
884
|
+
const yep_allocator* sys = yep_system_allocator();
|
|
885
|
+
const unsigned char* p = (const unsigned char*)buf;
|
|
886
|
+
size_t i = 0;
|
|
887
|
+
size_t count = 0;
|
|
888
|
+
for (;;) {
|
|
889
|
+
if (i >= len) {
|
|
890
|
+
if (status != NULL) {
|
|
891
|
+
*status = YEPTRIS_OK; /* RFC 8742: an empty sequence is valid */
|
|
892
|
+
}
|
|
893
|
+
return count;
|
|
894
|
+
}
|
|
895
|
+
yep_dom* dom = yep_dom_create(sys);
|
|
896
|
+
if (dom == NULL) {
|
|
897
|
+
if (status != NULL) {
|
|
898
|
+
*status = YEPTRIS_ERROR_MEMORY;
|
|
899
|
+
}
|
|
900
|
+
return count;
|
|
901
|
+
}
|
|
902
|
+
dom->input_base = (const char*)(p + i); /* item-relative borrows */
|
|
903
|
+
dom->input_len = len - i;
|
|
904
|
+
size_t used = 0;
|
|
905
|
+
YeptrisStatus st = (YeptrisStatus)yep_cbor_decode_dom(dom, p + i, len - i, strict, &used);
|
|
906
|
+
if (st != YEPTRIS_OK) {
|
|
907
|
+
yep_error_set(yep_error_tls(), YEP_ERR_UNEXPECTED, 0, 0, i,
|
|
908
|
+
"CBOR sequence item %zu at byte %zu is not well-formed", count, i);
|
|
909
|
+
yep_dom_destroy(dom);
|
|
910
|
+
if (status != NULL) {
|
|
911
|
+
*status = st == YEPTRIS_ERROR_MEMORY ? st : YEPTRIS_ERROR_PARSE;
|
|
912
|
+
}
|
|
913
|
+
return count;
|
|
914
|
+
}
|
|
915
|
+
YeptrisDocument doc = cbor_wrap(dom, p + i, sys);
|
|
916
|
+
if (doc == NULL) {
|
|
917
|
+
if (status != NULL) {
|
|
918
|
+
*status = YEPTRIS_ERROR_MEMORY;
|
|
919
|
+
}
|
|
920
|
+
return count;
|
|
921
|
+
}
|
|
922
|
+
if (cb(ctx, doc, count) != 0) { /* the callback owns each item;
|
|
923
|
+
nonzero aborts the iteration */
|
|
924
|
+
if (status != NULL) {
|
|
925
|
+
*status = YEPTRIS_OK;
|
|
926
|
+
}
|
|
927
|
+
return count;
|
|
928
|
+
}
|
|
929
|
+
i += used;
|
|
930
|
+
count++;
|
|
931
|
+
}
|
|
932
|
+
}
|
|
933
|
+
|
|
934
|
+
YEPTRIS_API YeptrisDocument yeptris_cbor_decode(const void* buf, size_t len, uint32_t opts,
|
|
935
|
+
YeptrisStatus* status) {
|
|
936
|
+
if ((buf == NULL && len != 0) || (opts & ~YEPTRIS_CBOR_STRICT) != 0) {
|
|
937
|
+
if (status != NULL) {
|
|
938
|
+
*status = YEPTRIS_ERROR_ARG;
|
|
939
|
+
}
|
|
940
|
+
return NULL;
|
|
941
|
+
}
|
|
942
|
+
const yep_allocator* sys = yep_system_allocator();
|
|
943
|
+
yep_dom* dom = yep_dom_create(sys);
|
|
944
|
+
if (dom == NULL) {
|
|
945
|
+
if (status != NULL) {
|
|
946
|
+
*status = YEPTRIS_ERROR_MEMORY;
|
|
947
|
+
}
|
|
948
|
+
return NULL;
|
|
949
|
+
}
|
|
950
|
+
dom->input_base = (const char*)buf;
|
|
951
|
+
dom->input_len = len;
|
|
952
|
+
YeptrisStatus st = (YeptrisStatus)yep_cbor_decode_dom(dom, (const unsigned char*)buf, len,
|
|
953
|
+
(opts & YEPTRIS_CBOR_STRICT) != 0, NULL);
|
|
954
|
+
if (st != YEPTRIS_OK) {
|
|
955
|
+
yep_dom_destroy(dom);
|
|
956
|
+
if (status != NULL) {
|
|
957
|
+
*status = st;
|
|
958
|
+
}
|
|
959
|
+
return NULL;
|
|
960
|
+
}
|
|
961
|
+
yeptris_document* doc = yep_alloc(sys, sizeof(yeptris_document));
|
|
962
|
+
if (doc == NULL) {
|
|
963
|
+
yep_dom_destroy(dom);
|
|
964
|
+
if (status != NULL) {
|
|
965
|
+
*status = YEPTRIS_ERROR_MEMORY;
|
|
966
|
+
}
|
|
967
|
+
return NULL;
|
|
968
|
+
}
|
|
969
|
+
doc->dom = dom;
|
|
970
|
+
doc->sys = sys;
|
|
971
|
+
doc->schema = YEPTRIS_SCHEMA_12_CORE; /* CBOR's model is the core schema */
|
|
972
|
+
doc->transcoded = NULL;
|
|
973
|
+
doc->transcoded_len = 0;
|
|
974
|
+
doc->input = (const char*)buf;
|
|
975
|
+
doc->finish_pool = NULL;
|
|
976
|
+
doc->lazy_tape = NULL; /* field-by-field ctor: no garbage for free */
|
|
977
|
+
if (status != NULL) {
|
|
978
|
+
*status = YEPTRIS_OK;
|
|
979
|
+
}
|
|
980
|
+
return (YeptrisDocument)doc;
|
|
981
|
+
}
|