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,835 @@
|
|
|
1
|
+
/* encode.c — CBOR (RFC 8949) encode over the shared DOM (TODO.cbor/02).
|
|
2
|
+
*
|
|
3
|
+
* DOM -> bytes, one data item for the document's first root (CBOR
|
|
4
|
+
* Sequences are item 03). The item-13 discipline: one exact-sizing
|
|
5
|
+
* walk, one allocation, linear writes. Every argument is minimal
|
|
6
|
+
* (shortest form, s4.2.1); floats use the preferred width (s4.2.2:
|
|
7
|
+
* smallest of half/single/double that round-trips; NaN canonicalizes
|
|
8
|
+
* to f9 7e00).
|
|
9
|
+
*
|
|
10
|
+
* Canonical mode (YEPTRIS_CBOR_CANONICAL): the core deterministic
|
|
11
|
+
* profile — minimal lengths, definite lengths, map keys sorted by the
|
|
12
|
+
* bytewise lexicographic order of their full encoded items. Stability:
|
|
13
|
+
* encode(decode(x)) is byte-identical across repeated encodes.
|
|
14
|
+
*
|
|
15
|
+
* Mapping ledger (mirrors decode.c's; pinned by tests):
|
|
16
|
+
* - tag-INT/FLOAT text re-converts through the number kernel (SSOT);
|
|
17
|
+
* beyond-int64 shapes encode as preferred floats (the 01 ledger
|
|
18
|
+
* widened them — the integer width does not survive the DOM)
|
|
19
|
+
* - tag-STR scalars encode as TEXT strings (major type 3): a byte
|
|
20
|
+
* string that decoded through the DOM re-encodes as text; both
|
|
21
|
+
* sides compare equal as DOM trees
|
|
22
|
+
* - the node's tag chain ("2 55799", outermost first) splits back
|
|
23
|
+
* into tag heads verbatim; any other tag shape (a YAML !tag) is
|
|
24
|
+
* YEPTRIS_ERROR_UNSUPPORTED — CBOR tag numbers are decimal
|
|
25
|
+
* - aliases (YAML input) are UNSUPPORTED: the CBOR model has none
|
|
26
|
+
*/
|
|
27
|
+
#include "cbor.h"
|
|
28
|
+
|
|
29
|
+
#include <math.h>
|
|
30
|
+
#include <stdlib.h>
|
|
31
|
+
#include <string.h>
|
|
32
|
+
|
|
33
|
+
#include <yeptris/cbor.h>
|
|
34
|
+
#include <yeptris/resolve.h>
|
|
35
|
+
|
|
36
|
+
#include "../common/error.h"
|
|
37
|
+
#include "../doc.h"
|
|
38
|
+
#include "../encoding/encoding.h"
|
|
39
|
+
#include "../scan/json.h"
|
|
40
|
+
|
|
41
|
+
/* ---- heads: minimal argument encoding (RFC 8949 s3) ----------------- */
|
|
42
|
+
|
|
43
|
+
static size_t cbor_arg_bytes(uint64_t arg) {
|
|
44
|
+
if (arg < 24)
|
|
45
|
+
return 1;
|
|
46
|
+
if (arg <= 0xFFull)
|
|
47
|
+
return 2;
|
|
48
|
+
if (arg <= 0xFFFFull)
|
|
49
|
+
return 3;
|
|
50
|
+
if (arg <= 0xFFFFFFFFull)
|
|
51
|
+
return 5;
|
|
52
|
+
return 9;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
static void cbor_put_head(uint8_t* out, size_t* pos, uint8_t mt, uint64_t arg) {
|
|
56
|
+
/* payload bytes -> additional info: 1->24, 2->25, 4->26, 8->27 */
|
|
57
|
+
static const uint8_t ai_of[9] = {0, 24, 25, 25, 26, 26, 26, 26, 27};
|
|
58
|
+
size_t n = cbor_arg_bytes(arg) - 1;
|
|
59
|
+
out[(*pos)++] = (uint8_t)((mt << 5) | (n == 0 ? (uint8_t)arg : ai_of[n]));
|
|
60
|
+
for (size_t k = 0; k < n; k++) { /* network byte order */
|
|
61
|
+
out[(*pos)++] = (uint8_t)(arg >> (8 * (n - 1 - k)));
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/* ---- half floats, both directions ----------------------------------- */
|
|
66
|
+
|
|
67
|
+
static double cbor_h2d(uint16_t h) {
|
|
68
|
+
unsigned exp = (h >> 10) & 0x1fu;
|
|
69
|
+
unsigned mant = h & 0x3ffu;
|
|
70
|
+
double val;
|
|
71
|
+
if (exp == 0) {
|
|
72
|
+
val = (double)mant;
|
|
73
|
+
for (int k = 0; k < 24; k++) {
|
|
74
|
+
val *= 0.5;
|
|
75
|
+
}
|
|
76
|
+
} else if (exp != 31) {
|
|
77
|
+
val = (double)(mant + 1024);
|
|
78
|
+
for (int k = 0; k < (int)exp - 25; k++) { /* halves above 2048 */
|
|
79
|
+
val *= 2.0;
|
|
80
|
+
}
|
|
81
|
+
for (int k = 0; k < 25 - (int)exp; k++) {
|
|
82
|
+
val *= 0.5;
|
|
83
|
+
}
|
|
84
|
+
} else {
|
|
85
|
+
val = mant == 0 ? (double)INFINITY : (double)NAN;
|
|
86
|
+
}
|
|
87
|
+
if (h & 0x8000u) {
|
|
88
|
+
val = -val;
|
|
89
|
+
}
|
|
90
|
+
return val;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/* Round-to-nearest-even double -> half. */
|
|
94
|
+
static uint16_t cbor_d2h(double d) {
|
|
95
|
+
uint64_t bits;
|
|
96
|
+
memcpy(&bits, &d, sizeof(bits));
|
|
97
|
+
uint32_t sign = (uint32_t)((bits >> 48) & 0x8000u);
|
|
98
|
+
uint32_t exp = (uint32_t)((bits >> 52) & 0x7ffu);
|
|
99
|
+
uint64_t man = bits & 0xfffffffffffffull;
|
|
100
|
+
if (exp == 0x7ffu) {
|
|
101
|
+
/* canonical NaN: f9 7e00, sign DROPPED — NaN sign is not
|
|
102
|
+
* meaningful (and (double)NAN carries a SET sign bit on
|
|
103
|
+
* arm64-MSVC, which turned the "canonical" form negative) */
|
|
104
|
+
return man ? 0x7e00u : (uint16_t)(sign | 0x7c00u); /* inf keeps sign */
|
|
105
|
+
}
|
|
106
|
+
int e2 = (int)exp - 1023 + 15;
|
|
107
|
+
if (e2 >= 0x1f) {
|
|
108
|
+
return (uint16_t)(sign | 0x7c00u); /* overflow -> infinity */
|
|
109
|
+
}
|
|
110
|
+
if (e2 > 0) {
|
|
111
|
+
uint32_t m10 = (uint32_t)(man >> 42);
|
|
112
|
+
uint64_t round = (man >> 41) & 1;
|
|
113
|
+
uint64_t sticky = man & ((1ull << 41) - 1);
|
|
114
|
+
if (round && (sticky || (m10 & 1))) {
|
|
115
|
+
m10++;
|
|
116
|
+
if (m10 == 0x400u) {
|
|
117
|
+
m10 = 0;
|
|
118
|
+
e2++;
|
|
119
|
+
if (e2 >= 0x1f) {
|
|
120
|
+
return (uint16_t)(sign | 0x7c00u);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
return (uint16_t)(sign | ((uint32_t)e2 << 10) | m10);
|
|
125
|
+
}
|
|
126
|
+
if (e2 < -10) {
|
|
127
|
+
return (uint16_t)sign; /* underflow to signed zero */
|
|
128
|
+
}
|
|
129
|
+
/* subnormal half: m10 = round_even((2^52+man) / 2^shift) with the
|
|
130
|
+
* result carrying the implicit one (values 0x200..0x3ff here) */
|
|
131
|
+
uint64_t full = man | (1ull << 52);
|
|
132
|
+
uint32_t shift = (uint32_t)(43 - e2); /* m10 = full / 2^(43-e2): e2=0
|
|
133
|
+
-> shift 43 (subnormal MSB) */
|
|
134
|
+
uint32_t m10 = (uint32_t)(full >> shift);
|
|
135
|
+
uint32_t round = (uint32_t)((full >> (shift - 1)) & 1);
|
|
136
|
+
uint64_t sticky = full & ((1ull << (shift - 1)) - 1);
|
|
137
|
+
if (round && (sticky || (m10 & 1))) {
|
|
138
|
+
m10++;
|
|
139
|
+
if (m10 == 0x400u) {
|
|
140
|
+
return (uint16_t)(sign | (1u << 10)); /* promoted to min normal */
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
return (uint16_t)(sign | m10);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
static uint8_t cbor_float_width(double d) {
|
|
147
|
+
if (d != d) {
|
|
148
|
+
return 2; /* NaN: the canonical f9 7e00 (s4.2.2) */
|
|
149
|
+
}
|
|
150
|
+
if (cbor_h2d(cbor_d2h(d)) == d) {
|
|
151
|
+
return 2;
|
|
152
|
+
}
|
|
153
|
+
float f = (float)d;
|
|
154
|
+
if ((double)f == d) {
|
|
155
|
+
return 4;
|
|
156
|
+
}
|
|
157
|
+
return 8;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
static void cbor_put_float(uint8_t* out, size_t* pos, double d, uint8_t width) {
|
|
161
|
+
out[(*pos)++] = (uint8_t)((7 << 5) | (width == 2 ? 25 : width == 4 ? 26 : 27));
|
|
162
|
+
uint64_t bits = 0;
|
|
163
|
+
if (width == 2) {
|
|
164
|
+
bits = (uint64_t)cbor_d2h(d) << 48;
|
|
165
|
+
} else if (width == 4) {
|
|
166
|
+
float f = (float)d;
|
|
167
|
+
uint32_t w;
|
|
168
|
+
memcpy(&w, &f, sizeof(w));
|
|
169
|
+
bits = (uint64_t)w << 32;
|
|
170
|
+
} else {
|
|
171
|
+
memcpy(&bits, &d, sizeof(bits));
|
|
172
|
+
}
|
|
173
|
+
for (uint8_t k = 0; k < width; k++) { /* bits holds the value top-aligned */
|
|
174
|
+
out[(*pos)++] = (uint8_t)(bits >> (8 * (7 - k)));
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/* ---- scalar decoding of node text (the number-kernel SSOT) ---------- */
|
|
179
|
+
|
|
180
|
+
typedef struct {
|
|
181
|
+
uint8_t mt; /* 0/1 integers, 7 floats */
|
|
182
|
+
uint64_t uval;
|
|
183
|
+
double dval;
|
|
184
|
+
uint8_t fwidth;
|
|
185
|
+
} cbor_num;
|
|
186
|
+
|
|
187
|
+
static int cbor_scalar_number(const yep_view* v, cbor_num* out) {
|
|
188
|
+
size_t i = 0;
|
|
189
|
+
int shape = 0;
|
|
190
|
+
int64_t iv = 0;
|
|
191
|
+
double dv = 0;
|
|
192
|
+
if (v->len == 0 || v->len > 32) { /* shortest text needed; d2s maxes ~24 */
|
|
193
|
+
return 0;
|
|
194
|
+
}
|
|
195
|
+
/* non-finite words (the decode ledger's rendering) */
|
|
196
|
+
if (v->len == 3 && memcmp(v->p, "NaN", 3) == 0) {
|
|
197
|
+
out->mt = 7;
|
|
198
|
+
out->dval = (double)NAN;
|
|
199
|
+
out->fwidth = 2;
|
|
200
|
+
return 1;
|
|
201
|
+
}
|
|
202
|
+
if ((v->len == 8 && memcmp(v->p, "Infinity", 8) == 0) ||
|
|
203
|
+
(v->len == 9 && memcmp(v->p, "-Infinity", 9) == 0)) {
|
|
204
|
+
out->mt = 7;
|
|
205
|
+
out->dval = v->p[0] == '-' ? -(double)INFINITY : (double)INFINITY;
|
|
206
|
+
out->fwidth = 2; /* half holds infinities exactly */
|
|
207
|
+
return 1;
|
|
208
|
+
}
|
|
209
|
+
if (!yep_json_number_scan(v->p, v->len, &i, &shape, &iv, &dv) || i != v->len) {
|
|
210
|
+
return 0;
|
|
211
|
+
}
|
|
212
|
+
if (shape == 0) {
|
|
213
|
+
if (iv < 0) {
|
|
214
|
+
out->mt = 1;
|
|
215
|
+
out->uval = (uint64_t)(-(iv + 1));
|
|
216
|
+
} else {
|
|
217
|
+
out->mt = 0;
|
|
218
|
+
out->uval = (uint64_t)iv;
|
|
219
|
+
}
|
|
220
|
+
return 1;
|
|
221
|
+
}
|
|
222
|
+
out->mt = 7;
|
|
223
|
+
out->dval = dv;
|
|
224
|
+
out->fwidth = cbor_float_width(dv);
|
|
225
|
+
return 1;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
static int cbor_bool_value(const yep_view* v) {
|
|
229
|
+
/* first byte decides: t/y/on-class true, f/n/off-class false
|
|
230
|
+
* (the YAML 1.1 resolver already typed the node as BOOL) */
|
|
231
|
+
if (v->len == 0) {
|
|
232
|
+
return 0;
|
|
233
|
+
}
|
|
234
|
+
switch (v->p[0]) {
|
|
235
|
+
case 't':
|
|
236
|
+
case 'T':
|
|
237
|
+
case 'y':
|
|
238
|
+
case 'Y':
|
|
239
|
+
case 'o':
|
|
240
|
+
case 'O':
|
|
241
|
+
return 1;
|
|
242
|
+
default:
|
|
243
|
+
return 0;
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
/* The diagnostic round-trip (the 01 ledger): decode renders
|
|
248
|
+
* undefined/simple(N) as text; encode recognizes them back. The words
|
|
249
|
+
* are reserved — a literal "undefined" string encodes as the simple. */
|
|
250
|
+
static int cbor_simple_of(const yep_view* v) {
|
|
251
|
+
if (v->len == 9 && memcmp(v->p, "undefined", 9) == 0) {
|
|
252
|
+
return 23;
|
|
253
|
+
}
|
|
254
|
+
if (v->len > 9 && memcmp(v->p, "simple(", 7) == 0 && v->p[v->len - 1] == ')') {
|
|
255
|
+
uint64_t val = 0;
|
|
256
|
+
for (size_t i = 7; i + 1 < v->len; i++) {
|
|
257
|
+
if (v->p[i] < '0' || v->p[i] > '9') {
|
|
258
|
+
return -1;
|
|
259
|
+
}
|
|
260
|
+
val = val * 10 + (uint64_t)(v->p[i] - '0');
|
|
261
|
+
if (val > 255) {
|
|
262
|
+
return -1;
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
if (val >= 24 && val < 32) {
|
|
266
|
+
return -1; /* 24..31 have no well-formed encoding */
|
|
267
|
+
}
|
|
268
|
+
return (int)val;
|
|
269
|
+
}
|
|
270
|
+
return -1;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
/* ---- tag chains: "2 55799" (outermost first) -> numbers -------------- */
|
|
274
|
+
|
|
275
|
+
static int cbor_tag_chain(const yep_dom* d, const yep_dnode* n, uint64_t* out, int max) {
|
|
276
|
+
if (n->tag.len == 0) {
|
|
277
|
+
return 0;
|
|
278
|
+
}
|
|
279
|
+
yep_view v = yep_dom_view(d, n->tag);
|
|
280
|
+
int count = 0;
|
|
281
|
+
size_t i = 0;
|
|
282
|
+
while (i < v.len) {
|
|
283
|
+
if (count >= max || v.p[i] < '0' || v.p[i] > '9') {
|
|
284
|
+
return -1;
|
|
285
|
+
}
|
|
286
|
+
uint64_t val = 0;
|
|
287
|
+
while (i < v.len && v.p[i] >= '0' && v.p[i] <= '9') {
|
|
288
|
+
if (val > (UINT64_MAX - (uint64_t)(v.p[i] - '0')) / 10) {
|
|
289
|
+
return -1;
|
|
290
|
+
}
|
|
291
|
+
val = val * 10 + (uint64_t)(v.p[i] - '0');
|
|
292
|
+
i++;
|
|
293
|
+
}
|
|
294
|
+
out[count++] = val;
|
|
295
|
+
if (i < v.len) {
|
|
296
|
+
if (v.p[i] != ' ' || i + 1 >= v.len) {
|
|
297
|
+
return -1; /* separators are single spaces, never trailing */
|
|
298
|
+
}
|
|
299
|
+
i++;
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
return count;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
/* ---- canonical map ordering (s4.2.1: bytewise on encoded keys) ------ */
|
|
306
|
+
|
|
307
|
+
typedef struct {
|
|
308
|
+
uint32_t map; /* map node id */
|
|
309
|
+
uint32_t pairs;
|
|
310
|
+
uint32_t* child; /* map children ids in chain order (k,v,k,v) */
|
|
311
|
+
uint32_t* order; /* pair emit order (indices into child) */
|
|
312
|
+
} cmap;
|
|
313
|
+
|
|
314
|
+
typedef struct {
|
|
315
|
+
const yep_dom* d;
|
|
316
|
+
int canonical;
|
|
317
|
+
int failed;
|
|
318
|
+
YeptrisStatus status;
|
|
319
|
+
cmap* maps;
|
|
320
|
+
size_t nmaps, maps_cap;
|
|
321
|
+
size_t next_map; /* write-order cursor: preps are consumed in the
|
|
322
|
+
same pre-order the sizing pass built them */
|
|
323
|
+
} cenc;
|
|
324
|
+
|
|
325
|
+
/* Encodes one KEY item (tags + scalar) into exactly-sized scratch. */
|
|
326
|
+
static uint8_t* cbor_encode_key(const yep_dom* d, const yep_dnode* key, size_t* out_len) {
|
|
327
|
+
yep_view v = yep_dom_view(d, key->value);
|
|
328
|
+
size_t cap = 16 * 9 + 9 + v.len; /* tags + head + text */
|
|
329
|
+
uint8_t* buf = malloc(cap);
|
|
330
|
+
if (buf == NULL) {
|
|
331
|
+
return NULL;
|
|
332
|
+
}
|
|
333
|
+
size_t pos = 0;
|
|
334
|
+
uint64_t tags[16];
|
|
335
|
+
int ntags = cbor_tag_chain(d, key, tags, 16);
|
|
336
|
+
if (ntags < 0) {
|
|
337
|
+
goto bad;
|
|
338
|
+
}
|
|
339
|
+
for (int t = 0; t < ntags; t++) {
|
|
340
|
+
cbor_put_head(buf, &pos, 6, tags[t]);
|
|
341
|
+
}
|
|
342
|
+
if (key->tag_id == YEPTRIS_TAG_INT || key->tag_id == YEPTRIS_TAG_FLOAT) {
|
|
343
|
+
cbor_num num;
|
|
344
|
+
if (!cbor_scalar_number(&v, &num)) {
|
|
345
|
+
goto bad;
|
|
346
|
+
}
|
|
347
|
+
if (num.mt != 7) {
|
|
348
|
+
cbor_put_head(buf, &pos, num.mt, num.uval);
|
|
349
|
+
} else {
|
|
350
|
+
cbor_put_float(buf, &pos, num.dval, num.fwidth);
|
|
351
|
+
}
|
|
352
|
+
} else { /* strings and diagnostics: a simple, else a text item */
|
|
353
|
+
if (key->tag.len == 0) {
|
|
354
|
+
int sv = cbor_simple_of(&v);
|
|
355
|
+
if (sv >= 0) {
|
|
356
|
+
if (sv < 24) {
|
|
357
|
+
buf[pos++] = (uint8_t)(0xE0 | (uint8_t)sv);
|
|
358
|
+
} else {
|
|
359
|
+
buf[pos++] = 0xF8;
|
|
360
|
+
buf[pos++] = (uint8_t)sv;
|
|
361
|
+
}
|
|
362
|
+
*out_len = pos;
|
|
363
|
+
return buf;
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
cbor_put_head(
|
|
367
|
+
buf, &pos,
|
|
368
|
+
v.len == 0 || yep_utf8_validate((const unsigned char*)v.p, v.len, NULL) ? 3 : 2, v.len);
|
|
369
|
+
if (v.len > 0) {
|
|
370
|
+
memcpy(buf + pos, v.p, v.len);
|
|
371
|
+
pos += v.len;
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
*out_len = pos;
|
|
375
|
+
return buf;
|
|
376
|
+
bad:
|
|
377
|
+
free(buf);
|
|
378
|
+
return NULL;
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
static void cenc_maps_free(cenc* e) {
|
|
382
|
+
for (size_t m = 0; m < e->nmaps; m++) {
|
|
383
|
+
free(e->maps[m].child);
|
|
384
|
+
free(e->maps[m].order);
|
|
385
|
+
}
|
|
386
|
+
free(e->maps);
|
|
387
|
+
e->maps = NULL;
|
|
388
|
+
e->nmaps = 0;
|
|
389
|
+
e->maps_cap = 0;
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
static cmap* cenc_map_add(cenc* e) {
|
|
393
|
+
if (e->nmaps >= e->maps_cap) {
|
|
394
|
+
size_t cap = e->maps_cap ? e->maps_cap * 2 : 16;
|
|
395
|
+
cmap* nm = realloc(e->maps, cap * sizeof(*nm));
|
|
396
|
+
if (nm == NULL) {
|
|
397
|
+
e->failed = 1;
|
|
398
|
+
e->status = YEPTRIS_ERROR_MEMORY;
|
|
399
|
+
return NULL;
|
|
400
|
+
}
|
|
401
|
+
e->maps = nm;
|
|
402
|
+
e->maps_cap = cap;
|
|
403
|
+
}
|
|
404
|
+
cmap* m = &e->maps[e->nmaps++];
|
|
405
|
+
m->map = 0;
|
|
406
|
+
m->pairs = 0;
|
|
407
|
+
m->child = NULL;
|
|
408
|
+
m->order = NULL;
|
|
409
|
+
return m;
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
/* Builds the canonical permutation for one map (stable bytewise sort
|
|
413
|
+
* of encoded keys). The child array also serves the write pass. */
|
|
414
|
+
static int cbor_canon_prepare(cenc* e, uint32_t id, uint32_t pairs) {
|
|
415
|
+
const yep_dom* d = e->d;
|
|
416
|
+
cmap* m = cenc_map_add(e);
|
|
417
|
+
if (m == NULL) {
|
|
418
|
+
return 0;
|
|
419
|
+
}
|
|
420
|
+
m->map = id;
|
|
421
|
+
m->pairs = pairs;
|
|
422
|
+
m->child = malloc((size_t)pairs * 2 * sizeof(uint32_t));
|
|
423
|
+
m->order = malloc((size_t)pairs * sizeof(uint32_t));
|
|
424
|
+
uint8_t** keys = malloc((size_t)pairs * sizeof(uint8_t*));
|
|
425
|
+
size_t* klen = malloc((size_t)pairs * sizeof(size_t));
|
|
426
|
+
if (m->child == NULL || m->order == NULL || keys == NULL || klen == NULL) {
|
|
427
|
+
free(keys);
|
|
428
|
+
free(klen);
|
|
429
|
+
e->failed = 1;
|
|
430
|
+
e->status = YEPTRIS_ERROR_MEMORY;
|
|
431
|
+
return 0;
|
|
432
|
+
}
|
|
433
|
+
uint32_t c = d->nodes[id].first_child;
|
|
434
|
+
for (uint32_t k = 0; k < pairs * 2; k++) {
|
|
435
|
+
m->child[k] = c;
|
|
436
|
+
c = d->nodes[c].next_sibling;
|
|
437
|
+
}
|
|
438
|
+
for (uint32_t p = 0; p < pairs; p++) {
|
|
439
|
+
keys[p] = NULL;
|
|
440
|
+
klen[p] = 0;
|
|
441
|
+
}
|
|
442
|
+
for (uint32_t p = 0; p < pairs; p++) {
|
|
443
|
+
keys[p] = cbor_encode_key(d, &d->nodes[m->child[p * 2]], &klen[p]);
|
|
444
|
+
if (keys[p] == NULL) {
|
|
445
|
+
e->failed = 1;
|
|
446
|
+
e->status = YEPTRIS_ERROR_UNSUPPORTED;
|
|
447
|
+
for (uint32_t q = 0; q < pairs; q++) {
|
|
448
|
+
free(keys[q]);
|
|
449
|
+
}
|
|
450
|
+
free(keys);
|
|
451
|
+
free(klen);
|
|
452
|
+
return 0;
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
for (uint32_t p = 0; p < pairs; p++) {
|
|
456
|
+
m->order[p] = p;
|
|
457
|
+
}
|
|
458
|
+
for (uint32_t p = 1; p < pairs; p++) { /* insertion sort: stable */
|
|
459
|
+
uint32_t cur = m->order[p];
|
|
460
|
+
size_t j = p;
|
|
461
|
+
while (j > 0) {
|
|
462
|
+
uint32_t other = m->order[j - 1];
|
|
463
|
+
const uint8_t* a = keys[cur];
|
|
464
|
+
const uint8_t* b = keys[other];
|
|
465
|
+
size_t la = klen[cur];
|
|
466
|
+
size_t lb = klen[other];
|
|
467
|
+
size_t min = la < lb ? la : lb;
|
|
468
|
+
int cmp = memcmp(a, b, min);
|
|
469
|
+
if (cmp < 0 || (cmp == 0 && la < lb)) {
|
|
470
|
+
m->order[j] = m->order[j - 1];
|
|
471
|
+
j--;
|
|
472
|
+
} else {
|
|
473
|
+
break;
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
m->order[j] = cur;
|
|
477
|
+
}
|
|
478
|
+
for (uint32_t p = 0; p < pairs; p++) {
|
|
479
|
+
free(keys[p]);
|
|
480
|
+
}
|
|
481
|
+
free(keys);
|
|
482
|
+
free(klen);
|
|
483
|
+
return 1;
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
/* ---- the two passes -------------------------------------------------- */
|
|
487
|
+
|
|
488
|
+
static size_t cbor_size_item(cenc* e, uint32_t id);
|
|
489
|
+
|
|
490
|
+
static size_t cbor_size_scalar(cenc* e, const yep_dnode* n) {
|
|
491
|
+
const yep_dom* d = e->d;
|
|
492
|
+
size_t sz = 0;
|
|
493
|
+
uint64_t tags[16];
|
|
494
|
+
int ntags = cbor_tag_chain(d, n, tags, 16);
|
|
495
|
+
if (ntags < 0) {
|
|
496
|
+
e->failed = 1;
|
|
497
|
+
e->status = YEPTRIS_ERROR_UNSUPPORTED;
|
|
498
|
+
return 0;
|
|
499
|
+
}
|
|
500
|
+
for (int t = 0; t < ntags; t++) {
|
|
501
|
+
sz += cbor_arg_bytes(tags[t]);
|
|
502
|
+
}
|
|
503
|
+
yep_view v = yep_dom_view(d, n->value);
|
|
504
|
+
switch (n->tag_id) {
|
|
505
|
+
case YEPTRIS_TAG_INT:
|
|
506
|
+
case YEPTRIS_TAG_FLOAT: {
|
|
507
|
+
cbor_num num;
|
|
508
|
+
if (!cbor_scalar_number(&v, &num)) {
|
|
509
|
+
e->failed = 1;
|
|
510
|
+
e->status = YEPTRIS_ERROR_UNSUPPORTED;
|
|
511
|
+
return 0;
|
|
512
|
+
}
|
|
513
|
+
return sz + (num.mt == 7 ? (size_t)(1 + num.fwidth) : cbor_arg_bytes(num.uval));
|
|
514
|
+
}
|
|
515
|
+
case YEPTRIS_TAG_BOOL:
|
|
516
|
+
case YEPTRIS_TAG_NULL:
|
|
517
|
+
return sz + 1;
|
|
518
|
+
default: /* str: a recognized diagnostic, else a text item */
|
|
519
|
+
if (n->tag.len == 0) {
|
|
520
|
+
int sv = cbor_simple_of(&v);
|
|
521
|
+
if (sv >= 0) {
|
|
522
|
+
return sz + ((uint32_t)sv < 24 ? 1 : 2);
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
return sz + cbor_arg_bytes(v.len) + v.len;
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
static size_t cbor_size_item(cenc* e, uint32_t id) {
|
|
530
|
+
const yep_dom* d = e->d;
|
|
531
|
+
const yep_dnode* n = &d->nodes[id];
|
|
532
|
+
if (n->kind == YEP_DOM_SCALAR) {
|
|
533
|
+
return cbor_size_scalar(e, n); /* includes the node's own tags */
|
|
534
|
+
}
|
|
535
|
+
size_t sz = 0;
|
|
536
|
+
uint64_t tags[16];
|
|
537
|
+
int ntags = cbor_tag_chain(d, n, tags, 16);
|
|
538
|
+
if (ntags < 0) {
|
|
539
|
+
e->failed = 1;
|
|
540
|
+
e->status = YEPTRIS_ERROR_UNSUPPORTED;
|
|
541
|
+
return 0;
|
|
542
|
+
}
|
|
543
|
+
for (int t = 0; t < ntags; t++) {
|
|
544
|
+
sz += cbor_arg_bytes(tags[t]);
|
|
545
|
+
}
|
|
546
|
+
if (n->kind == YEP_DOM_ALIAS) {
|
|
547
|
+
e->failed = 1;
|
|
548
|
+
e->status = YEPTRIS_ERROR_UNSUPPORTED;
|
|
549
|
+
return 0;
|
|
550
|
+
}
|
|
551
|
+
if (n->kind == YEP_DOM_SEQUENCE) {
|
|
552
|
+
sz += cbor_arg_bytes(n->count);
|
|
553
|
+
uint32_t c = n->first_child;
|
|
554
|
+
for (uint32_t k = 0; k < n->count && !e->failed; k++) {
|
|
555
|
+
sz += cbor_size_item(e, c);
|
|
556
|
+
c = d->nodes[c].next_sibling;
|
|
557
|
+
}
|
|
558
|
+
return e->failed ? 0 : sz;
|
|
559
|
+
}
|
|
560
|
+
/* mapping */
|
|
561
|
+
uint32_t pairs = n->count / 2;
|
|
562
|
+
sz += cbor_arg_bytes(pairs);
|
|
563
|
+
/* hold the INDEX, not the pointer: sizing a child recurses into
|
|
564
|
+
* nested maps whose preps REALLOC e->maps (#152 — a held cmap*
|
|
565
|
+
* dangled and the next pair read walked freed memory; n>=11 of
|
|
566
|
+
* the depth-3 users shape crossed the 16->32 growth) */
|
|
567
|
+
size_t canon_mi = 0;
|
|
568
|
+
int canon = 0;
|
|
569
|
+
if (e->canonical) {
|
|
570
|
+
if (!cbor_canon_prepare(e, id, pairs)) {
|
|
571
|
+
return 0;
|
|
572
|
+
}
|
|
573
|
+
canon_mi = e->nmaps - 1;
|
|
574
|
+
canon = 1;
|
|
575
|
+
}
|
|
576
|
+
if (canon) {
|
|
577
|
+
for (uint32_t p = 0; p < pairs && !e->failed; p++) {
|
|
578
|
+
const cmap* cm = &e->maps[canon_mi];
|
|
579
|
+
sz += cbor_size_item(e, cm->child[cm->order[p] * 2]);
|
|
580
|
+
if (!e->failed) {
|
|
581
|
+
cm = &e->maps[canon_mi];
|
|
582
|
+
sz += cbor_size_item(e, cm->child[cm->order[p] * 2 + 1]);
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
} else {
|
|
586
|
+
uint32_t c = n->first_child; /* the chain IS the pair order */
|
|
587
|
+
for (uint32_t p = 0; p < pairs && !e->failed; p++) {
|
|
588
|
+
sz += cbor_size_item(e, c);
|
|
589
|
+
c = d->nodes[c].next_sibling;
|
|
590
|
+
if (!e->failed && c != UINT32_MAX) {
|
|
591
|
+
sz += cbor_size_item(e, c);
|
|
592
|
+
c = d->nodes[c].next_sibling;
|
|
593
|
+
}
|
|
594
|
+
}
|
|
595
|
+
}
|
|
596
|
+
return e->failed ? 0 : sz;
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
static void cbor_write_item(cenc* e, uint32_t id, uint8_t* out, size_t* pos);
|
|
600
|
+
|
|
601
|
+
static void cbor_write_scalar(cenc* e, const yep_dnode* n, uint8_t* out, size_t* pos) {
|
|
602
|
+
/* the node's tag chain was already emitted by cbor_write_item */
|
|
603
|
+
const yep_dom* d = e->d;
|
|
604
|
+
yep_view v = yep_dom_view(d, n->value);
|
|
605
|
+
switch (n->tag_id) {
|
|
606
|
+
case YEPTRIS_TAG_INT:
|
|
607
|
+
case YEPTRIS_TAG_FLOAT: {
|
|
608
|
+
cbor_num num;
|
|
609
|
+
if (!cbor_scalar_number(&v, &num)) {
|
|
610
|
+
return; /* pass 1 already failed on this; unreachable */
|
|
611
|
+
}
|
|
612
|
+
if (num.mt == 7) {
|
|
613
|
+
cbor_put_float(out, pos, num.dval, num.fwidth);
|
|
614
|
+
} else {
|
|
615
|
+
cbor_put_head(out, pos, num.mt, num.uval);
|
|
616
|
+
}
|
|
617
|
+
return;
|
|
618
|
+
}
|
|
619
|
+
case YEPTRIS_TAG_BOOL:
|
|
620
|
+
out[(*pos)++] = cbor_bool_value(&v) ? 0xF5 : 0xF4;
|
|
621
|
+
return;
|
|
622
|
+
case YEPTRIS_TAG_NULL:
|
|
623
|
+
out[(*pos)++] = 0xF6;
|
|
624
|
+
return;
|
|
625
|
+
default:
|
|
626
|
+
if (n->tag.len == 0) {
|
|
627
|
+
int sv = cbor_simple_of(&v);
|
|
628
|
+
if (sv >= 0) {
|
|
629
|
+
if (sv < 24) {
|
|
630
|
+
out[(*pos)++] = (uint8_t)(0xE0 | (uint8_t)sv);
|
|
631
|
+
} else {
|
|
632
|
+
out[(*pos)++] = 0xF8;
|
|
633
|
+
out[(*pos)++] = (uint8_t)sv;
|
|
634
|
+
}
|
|
635
|
+
return;
|
|
636
|
+
}
|
|
637
|
+
}
|
|
638
|
+
/* invalid UTF-8 can only have been a byte string (the 01
|
|
639
|
+
* ledger: both decode to tag-str scalars) — emit mt2 so the
|
|
640
|
+
* roundtrip re-decodes to the same bytes */
|
|
641
|
+
cbor_put_head(
|
|
642
|
+
out, pos,
|
|
643
|
+
v.len == 0 || yep_utf8_validate((const unsigned char*)v.p, v.len, NULL) ? 3 : 2, v.len);
|
|
644
|
+
if (v.len > 0) { /* memcpy(_, NULL, 0) is UB (gcc UBSan) */
|
|
645
|
+
memcpy(out + *pos, v.p, v.len);
|
|
646
|
+
*pos += v.len;
|
|
647
|
+
}
|
|
648
|
+
return;
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
static void cbor_write_item(cenc* e, uint32_t id, uint8_t* out, size_t* pos) {
|
|
653
|
+
const yep_dom* d = e->d;
|
|
654
|
+
const yep_dnode* n = &d->nodes[id];
|
|
655
|
+
uint64_t tags[16];
|
|
656
|
+
int ntags = cbor_tag_chain(d, n, tags, 16);
|
|
657
|
+
for (int t = 0; t < ntags; t++) {
|
|
658
|
+
cbor_put_head(out, pos, 6, tags[t]);
|
|
659
|
+
}
|
|
660
|
+
if (n->kind == YEP_DOM_SCALAR) {
|
|
661
|
+
cbor_write_scalar(e, n, out, pos);
|
|
662
|
+
return;
|
|
663
|
+
}
|
|
664
|
+
if (n->kind == YEP_DOM_SEQUENCE) {
|
|
665
|
+
cbor_put_head(out, pos, 4, n->count);
|
|
666
|
+
uint32_t c = n->first_child;
|
|
667
|
+
for (uint32_t k = 0; k < n->count; k++) {
|
|
668
|
+
cbor_write_item(e, c, out, pos);
|
|
669
|
+
c = d->nodes[c].next_sibling;
|
|
670
|
+
}
|
|
671
|
+
return;
|
|
672
|
+
}
|
|
673
|
+
uint32_t pairs = n->count / 2;
|
|
674
|
+
cbor_put_head(out, pos, 5, pairs);
|
|
675
|
+
cmap* cm = NULL;
|
|
676
|
+
if (e->canonical && e->next_map < e->nmaps) {
|
|
677
|
+
cm = &e->maps[e->next_map++]; /* walk order == build order */
|
|
678
|
+
}
|
|
679
|
+
if (cm != NULL) {
|
|
680
|
+
for (uint32_t p = 0; p < pairs; p++) {
|
|
681
|
+
cbor_write_item(e, cm->child[cm->order[p] * 2], out, pos);
|
|
682
|
+
cbor_write_item(e, cm->child[cm->order[p] * 2 + 1], out, pos);
|
|
683
|
+
}
|
|
684
|
+
} else {
|
|
685
|
+
uint32_t c = n->first_child;
|
|
686
|
+
for (uint32_t p = 0; p < pairs && c != UINT32_MAX; p++) {
|
|
687
|
+
cbor_write_item(e, c, out, pos);
|
|
688
|
+
c = d->nodes[c].next_sibling;
|
|
689
|
+
if (c != UINT32_MAX) {
|
|
690
|
+
cbor_write_item(e, c, out, pos);
|
|
691
|
+
c = d->nodes[c].next_sibling;
|
|
692
|
+
}
|
|
693
|
+
}
|
|
694
|
+
}
|
|
695
|
+
}
|
|
696
|
+
|
|
697
|
+
/* the write pass consumes the canonical preps in walk order; drop each
|
|
698
|
+
* map's arrays after its last use is not tracked — freed once at exit */
|
|
699
|
+
|
|
700
|
+
/* ONE sizing walk (it also builds the canonical map preparations);
|
|
701
|
+
* writes only when out and cap allow — the needed size always comes
|
|
702
|
+
* back through *out_len. *written flags whether bytes went out. */
|
|
703
|
+
static int cbor_run(YeptrisDocument handle, uint32_t opts, uint8_t* out, size_t cap,
|
|
704
|
+
size_t* out_len, int* written) {
|
|
705
|
+
yeptris_document* doc = (yeptris_document*)handle;
|
|
706
|
+
yep_dom* d = yep_doc_dom(doc); /* #342 lazy: materialize on encode */
|
|
707
|
+
if (d == NULL) {
|
|
708
|
+
return YEPTRIS_ERROR_MEMORY;
|
|
709
|
+
}
|
|
710
|
+
if (d->dcount == 0) {
|
|
711
|
+
return YEPTRIS_ERROR_ARG;
|
|
712
|
+
}
|
|
713
|
+
cenc e = {d, (opts & YEPTRIS_CBOR_CANONICAL) != 0, 0, YEPTRIS_OK, NULL, 0, 0, 0};
|
|
714
|
+
size_t total = cbor_size_item(&e, d->docs[0]);
|
|
715
|
+
if (e.failed) {
|
|
716
|
+
cenc_maps_free(&e);
|
|
717
|
+
return (int)e.status;
|
|
718
|
+
}
|
|
719
|
+
*out_len = total;
|
|
720
|
+
if (out == NULL || cap < total) {
|
|
721
|
+
cenc_maps_free(&e);
|
|
722
|
+
*written = 0;
|
|
723
|
+
return YEPTRIS_OK;
|
|
724
|
+
}
|
|
725
|
+
size_t pos = 0;
|
|
726
|
+
cbor_write_item(&e, d->docs[0], out, &pos);
|
|
727
|
+
cenc_maps_free(&e);
|
|
728
|
+
if (pos != total) { /* the two passes diverged — a bug, refuse */
|
|
729
|
+
return YEPTRIS_ERROR_INTERNAL;
|
|
730
|
+
}
|
|
731
|
+
*out_len = pos;
|
|
732
|
+
*written = 1;
|
|
733
|
+
return YEPTRIS_OK;
|
|
734
|
+
}
|
|
735
|
+
|
|
736
|
+
YEPTRIS_API size_t yeptris_cbor_encode_into(YeptrisDocument doc, uint32_t opts, void* buf,
|
|
737
|
+
size_t cap) {
|
|
738
|
+
if (doc == NULL) {
|
|
739
|
+
return 0;
|
|
740
|
+
}
|
|
741
|
+
size_t out_len = 0;
|
|
742
|
+
int wrote = 0;
|
|
743
|
+
YeptrisStatus st = (YeptrisStatus)cbor_run(doc, opts, (uint8_t*)buf, cap, &out_len, &wrote);
|
|
744
|
+
if (st != YEPTRIS_OK) {
|
|
745
|
+
yep_error_set(yep_error_tls(), YEP_ERR_UNEXPECTED, 0, 0, 0,
|
|
746
|
+
"cbor encode failed (status %d)", (int)st);
|
|
747
|
+
return 0;
|
|
748
|
+
}
|
|
749
|
+
return out_len; /* the need when unwritten, the count when written */
|
|
750
|
+
}
|
|
751
|
+
|
|
752
|
+
YEPTRIS_API void* yeptris_cbor_encode(YeptrisDocument doc, uint32_t opts, size_t* len) {
|
|
753
|
+
size_t need = yeptris_cbor_encode_into(doc, opts, NULL, 0);
|
|
754
|
+
if (need == 0) {
|
|
755
|
+
return NULL;
|
|
756
|
+
}
|
|
757
|
+
uint8_t* buf = malloc(need);
|
|
758
|
+
if (buf == NULL) {
|
|
759
|
+
yep_error_set(yep_error_tls(), YEP_ERR_UNEXPECTED, 0, 0, 0, "cbor encode: out of memory");
|
|
760
|
+
return NULL;
|
|
761
|
+
}
|
|
762
|
+
size_t written = yeptris_cbor_encode_into(doc, opts, buf, need);
|
|
763
|
+
if (written != need) {
|
|
764
|
+
free(buf);
|
|
765
|
+
return NULL;
|
|
766
|
+
}
|
|
767
|
+
if (len != NULL) {
|
|
768
|
+
*len = written;
|
|
769
|
+
}
|
|
770
|
+
return buf;
|
|
771
|
+
}
|
|
772
|
+
|
|
773
|
+
YEPTRIS_API size_t yeptris_cbor_encode_sequence_into(YeptrisDocument* items, size_t n,
|
|
774
|
+
uint32_t opts, void* buf, size_t cap) {
|
|
775
|
+
if (items == NULL && n != 0) {
|
|
776
|
+
return 0;
|
|
777
|
+
}
|
|
778
|
+
size_t need = 0;
|
|
779
|
+
size_t* sizes = malloc(n * sizeof(size_t));
|
|
780
|
+
if (sizes == NULL) {
|
|
781
|
+
return 0;
|
|
782
|
+
}
|
|
783
|
+
for (size_t k = 0; k < n; k++) {
|
|
784
|
+
if (items[k] == NULL) {
|
|
785
|
+
free(sizes);
|
|
786
|
+
return 0;
|
|
787
|
+
}
|
|
788
|
+
size_t one = 0;
|
|
789
|
+
int wrote = 0;
|
|
790
|
+
if (cbor_run(items[k], opts, NULL, 0, &one, &wrote) != YEPTRIS_OK) {
|
|
791
|
+
free(sizes);
|
|
792
|
+
return 0;
|
|
793
|
+
}
|
|
794
|
+
sizes[k] = one;
|
|
795
|
+
need += one;
|
|
796
|
+
}
|
|
797
|
+
if (buf == NULL || cap < need) {
|
|
798
|
+
free(sizes);
|
|
799
|
+
return need;
|
|
800
|
+
}
|
|
801
|
+
size_t pos = 0;
|
|
802
|
+
for (size_t k = 0; k < n; k++) {
|
|
803
|
+
size_t one = 0;
|
|
804
|
+
int wrote = 0;
|
|
805
|
+
if (cbor_run(items[k], opts, (uint8_t*)buf + pos, sizes[k], &one, &wrote) != YEPTRIS_OK ||
|
|
806
|
+
!wrote || one != sizes[k]) {
|
|
807
|
+
free(sizes);
|
|
808
|
+
return 0;
|
|
809
|
+
}
|
|
810
|
+
pos += one;
|
|
811
|
+
}
|
|
812
|
+
free(sizes);
|
|
813
|
+
return pos;
|
|
814
|
+
}
|
|
815
|
+
|
|
816
|
+
YEPTRIS_API void* yeptris_cbor_encode_sequence(YeptrisDocument* items, size_t n, uint32_t opts,
|
|
817
|
+
size_t* len) {
|
|
818
|
+
size_t need = yeptris_cbor_encode_sequence_into(items, n, opts, NULL, 0);
|
|
819
|
+
if (need == 0) {
|
|
820
|
+
return NULL;
|
|
821
|
+
}
|
|
822
|
+
uint8_t* buf = malloc(need);
|
|
823
|
+
if (buf == NULL) {
|
|
824
|
+
return NULL;
|
|
825
|
+
}
|
|
826
|
+
size_t wrote = yeptris_cbor_encode_sequence_into(items, n, opts, buf, need);
|
|
827
|
+
if (wrote != need) {
|
|
828
|
+
free(buf);
|
|
829
|
+
return NULL;
|
|
830
|
+
}
|
|
831
|
+
if (len != NULL) {
|
|
832
|
+
*len = wrote;
|
|
833
|
+
}
|
|
834
|
+
return buf;
|
|
835
|
+
}
|