yeptris 0.6.16.1 → 0.6.16.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/yeptris_native/yeptris_native.c +43 -0
- data/lib/yeptris/json.rb +8 -4
- data/lib/yeptris/psych/class_loader.rb +24 -0
- data/lib/yeptris/psych/scalar_scanner.rb +149 -0
- data/lib/yeptris/psych.rb +23 -5
- data/lib/yeptris.rb +1 -1
- data/vendor/libyeptris/src/include/yeptris/schema.h +4 -2
- data/vendor/libyeptris/src/yeptris/cbor/decode.c +310 -177
- data/vendor/libyeptris/src/yeptris/cbor/sink.h +58 -0
- metadata +5 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: f6b3f2406ea8b763cfa7bd0d0a36ea30ba7bb80c8322c6ebe5fd8300725e47d2
|
|
4
|
+
data.tar.gz: 9a500939ce7f65be9219acc0a44c62819ddd09f4f64486177065681b8490e686
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 6c4eeced42673cb9613462d239f6427bdb1190e14b0a733976e3bd9c17ee061a4fe7fb5f14ace52ea05242b186410570b8d44f1fc5bbc2ab2aacbcd65188d7ef
|
|
7
|
+
data.tar.gz: 5b84d8229ff419ab0c04fba154088775776ed5f70f4e6be5a9939e9b495e61ac82656a1bf0d7cbddbdf55ae9c1ba1912c44fc2af5b22e16d40a432e71009b185
|
|
@@ -423,8 +423,51 @@ static VALUE native_gc_mode_set(VALUE self, VALUE mode) {
|
|
|
423
423
|
return mode;
|
|
424
424
|
}
|
|
425
425
|
|
|
426
|
+
/* ABI-drift self-check (the #157-audit silent-nil class): the bundle
|
|
427
|
+
* is compiled against a specific yep_dom layout; engine drift makes
|
|
428
|
+
* the walkers read fields at stale offsets — cbor_load returned NIL
|
|
429
|
+
* on valid CBOR in the dev-checkout audit, with no error anywhere.
|
|
430
|
+
* Both walkers must round-trip a known document at load, or Init
|
|
431
|
+
* raises LoadError: lib/yeptris.rb's existing rescue falls back to
|
|
432
|
+
* the FFI ladder (loudly), and the stale bundle never answers with
|
|
433
|
+
* garbage. Runs inside rb_protect so a drifted walk raises instead of
|
|
434
|
+
* crashing the load. */
|
|
435
|
+
static VALUE native_self_check_body(VALUE unused) {
|
|
436
|
+
/* JSON: {"a"=>[1, 2.5, "x", true, nil]} */
|
|
437
|
+
const char* json = "{\"a\":[1,2.5,\"x\",true,null]}";
|
|
438
|
+
VALUE j = yep_rb_parse_json(json, strlen(json), 0);
|
|
439
|
+
if (j == Qundef || !RB_TYPE_P(j, T_HASH)) return Qfalse;
|
|
440
|
+
VALUE a = rb_hash_lookup(j, rb_str_new_cstr("a"));
|
|
441
|
+
if (!RB_TYPE_P(a, T_ARRAY) || RARRAY_LEN(a) != 5) return Qfalse;
|
|
442
|
+
if (!RB_INTEGER_TYPE_P(rb_ary_entry(a, 0))) return Qfalse;
|
|
443
|
+
if (!RB_FLOAT_TYPE_P(rb_ary_entry(a, 1))) return Qfalse;
|
|
444
|
+
if (!RB_TYPE_P(rb_ary_entry(a, 2), T_STRING)) return Qfalse;
|
|
445
|
+
if (rb_ary_entry(a, 3) != Qtrue || !NIL_P(rb_ary_entry(a, 4))) return Qfalse;
|
|
446
|
+
|
|
447
|
+
/* CBOR: A1 61 6B 01 = {"k" => 1} (canonical, hand-encoded) */
|
|
448
|
+
const char cbor[] = "\xA1\x61\x6B\x01";
|
|
449
|
+
VALUE c = yep_rb_cbor_load(cbor, sizeof(cbor) - 1, 0);
|
|
450
|
+
if (c == Qundef || !RB_TYPE_P(c, T_HASH)) return Qfalse;
|
|
451
|
+
VALUE one = rb_hash_lookup(c, rb_str_new_cstr("k"));
|
|
452
|
+
if (!RB_INTEGER_TYPE_P(one) || !rb_eql(one, INT2FIX(1))) return Qfalse;
|
|
453
|
+
return Qtrue;
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
static void native_self_check(void) {
|
|
457
|
+
int state = 0;
|
|
458
|
+
VALUE ok = rb_protect(native_self_check_body, Qnil, &state);
|
|
459
|
+
if (state != 0 || ok != Qtrue) {
|
|
460
|
+
if (state != 0) rb_set_errinfo(Qnil);
|
|
461
|
+
rb_raise(rb_eLoadError,
|
|
462
|
+
"yeptris: native materializer failed its ABI self-check "
|
|
463
|
+
"(stale build against a drifted engine?) — refusing to "
|
|
464
|
+
"register; the FFI ladder will carry the load");
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
|
|
426
468
|
RUBY_FUNC_EXPORTED void Init_native(void) {
|
|
427
469
|
utf8_enc = rb_utf8_encoding();
|
|
470
|
+
native_self_check();
|
|
428
471
|
VALUE mYep = rb_define_module("Yeptris");
|
|
429
472
|
VALUE mNat = rb_define_module_under(mYep, "Native");
|
|
430
473
|
rb_define_singleton_method(mNat, "load_json", native_load_json, -1);
|
data/lib/yeptris/json.rb
CHANGED
|
@@ -119,7 +119,7 @@ module Yeptris
|
|
|
119
119
|
end
|
|
120
120
|
end
|
|
121
121
|
|
|
122
|
-
def walk_tape(src, tape)
|
|
122
|
+
def walk_tape(src, tape, strict_dup = STRICT_DUPLICATE_KEYS)
|
|
123
123
|
n = tape[:count]
|
|
124
124
|
kinds = tape[:kinds].read_bytes(n).unpack("C*")
|
|
125
125
|
offs = tape[:offs].read_bytes(n * 4).unpack("V*")
|
|
@@ -139,7 +139,7 @@ module Yeptris
|
|
|
139
139
|
|
|
140
140
|
docs = [nil] # record 0 (DOC) pre-consumed — the root's slot
|
|
141
141
|
stack = []
|
|
142
|
-
key_sets =
|
|
142
|
+
key_sets = strict_dup ? [{}] : nil
|
|
143
143
|
pending_key = nil
|
|
144
144
|
i = 1
|
|
145
145
|
while i < n
|
|
@@ -152,8 +152,12 @@ module Yeptris
|
|
|
152
152
|
place(docs, stack, pending_key) { {} }
|
|
153
153
|
pending_key = nil
|
|
154
154
|
when T_CLOSE
|
|
155
|
+
# Key frames are pushed per MAP_OPEN — an ARRAY close must
|
|
156
|
+
# not pop the enclosing map's frame (issue found by ea's CI:
|
|
157
|
+
# {"a":[1],"b":[2],"c":[3]} exhausted the frames and the next
|
|
158
|
+
# map key hit key_sets.last.key? on nil under strict mode).
|
|
159
|
+
key_sets&.pop if stack.last.is_a?(Hash)
|
|
155
160
|
stack.pop
|
|
156
|
-
key_sets&.pop
|
|
157
161
|
when T_STR
|
|
158
162
|
# empty-string literals are frozen+shared since Ruby 3.4
|
|
159
163
|
# (and `+""` binds after the method chain anyway), so the
|
|
@@ -256,8 +260,8 @@ module Yeptris
|
|
|
256
260
|
place(docs, stack, pending_key) { {} }
|
|
257
261
|
pending_key = nil
|
|
258
262
|
when ValueML::CLOSE
|
|
263
|
+
key_sets&.pop if stack.last.is_a?(Hash)
|
|
259
264
|
stack.pop
|
|
260
|
-
key_sets&.pop
|
|
261
265
|
when ValueML::V_STR
|
|
262
266
|
text = arena.byteslice(offs[i], lens[i])
|
|
263
267
|
if ikeys[i] == 1 && !stack.empty? && stack.last.is_a?(Hash)
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "date"
|
|
4
|
+
|
|
5
|
+
module Yeptris
|
|
6
|
+
module Psych
|
|
7
|
+
# The minimal ClassLoader face the ScalarScanner port drives
|
|
8
|
+
# (stdlib's loader resolves through the class hierarchy; the
|
|
9
|
+
# scanner only needs the date class and symbolize).
|
|
10
|
+
class ClassLoader
|
|
11
|
+
def date
|
|
12
|
+
Date
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def symbolize str
|
|
16
|
+
str.to_sym
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def load name
|
|
20
|
+
Object.const_get(name)
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "date"
|
|
4
|
+
|
|
5
|
+
module Yeptris
|
|
6
|
+
module Psych
|
|
7
|
+
###
|
|
8
|
+
# Scan scalars for built in types — the stdlib Psych::ScalarScanner
|
|
9
|
+
# port (#179): same regexes, same precedence, same edge verdicts.
|
|
10
|
+
# The load path types through the C resolver; this class is the
|
|
11
|
+
# standalone API stdlib code (and Psych's own tests) drive directly.
|
|
12
|
+
class ScalarScanner
|
|
13
|
+
# Taken from http://yaml.org/type/timestamp.html
|
|
14
|
+
TIME = /^-?\d{4}-\d{1,2}-\d{1,2}(?:[Tt]|\s+)\d{1,2}:\d\d:\d\d(?:\.\d*)?(?:\s*(?:Z|[-+]\d{1,2}:?(?:\d\d)?))?$/
|
|
15
|
+
|
|
16
|
+
# Taken from http://yaml.org/type/float.html
|
|
17
|
+
# Base 60, [-+]inf and NaN are handled separately
|
|
18
|
+
FLOAT = /^(?:[-+]?([0-9][0-9_,]*)?\.[0-9]*([eE][-+][0-9]+)?(?# base 10))$/x
|
|
19
|
+
|
|
20
|
+
# Taken from http://yaml.org/type/int.html and modified to ensure at least one numerical symbol exists
|
|
21
|
+
INTEGER_STRICT = /^(?:[-+]?0b[_]*[0-1][0-1_]* (?# base 2)
|
|
22
|
+
|[-+]?0[_]*[0-7][0-7_]* (?# base 8)
|
|
23
|
+
|[-+]?(0|[1-9][0-9_]*) (?# base 10)
|
|
24
|
+
|[-+]?0x[_]*[0-9a-fA-F][0-9a-fA-F_]* (?# base 16))$/x
|
|
25
|
+
|
|
26
|
+
# Same as above, but allows commas.
|
|
27
|
+
# Not to YML spec, but kept for backwards compatibility
|
|
28
|
+
INTEGER_LEGACY = /^(?:[-+]?0b[_,]*[0-1][0-1_,]* (?# base 2)
|
|
29
|
+
|[-+]?0[_,]*[0-7][0-7_,]* (?# base 8)
|
|
30
|
+
|[-+]?(?:0|[1-9](?:[0-9]|,[0-9]|_[0-9])*) (?# base 10)
|
|
31
|
+
|[-+]?0x[_,]*[0-9a-fA-F][0-9a-fA-F_,]* (?# base 16))$/x
|
|
32
|
+
|
|
33
|
+
BOOLEAN_TRUE = /^(yes|true|on)$/i
|
|
34
|
+
BOOLEAN_FALSE = /^(no|false|off)$/i
|
|
35
|
+
|
|
36
|
+
attr_reader :class_loader
|
|
37
|
+
|
|
38
|
+
# Create a new scanner
|
|
39
|
+
def initialize class_loader = ClassLoader, strict_integer: false, parse_symbols: true
|
|
40
|
+
@symbol_cache = {}
|
|
41
|
+
@class_loader = class_loader
|
|
42
|
+
@strict_integer = strict_integer
|
|
43
|
+
@parse_symbols = parse_symbols
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# Tokenize +string+ returning the Ruby object
|
|
47
|
+
def tokenize string
|
|
48
|
+
return nil if string.empty?
|
|
49
|
+
return @symbol_cache[string] if @symbol_cache.key?(string)
|
|
50
|
+
integer_regex = @strict_integer ? INTEGER_STRICT : INTEGER_LEGACY
|
|
51
|
+
# Check for a String type, being careful not to get caught by hash keys, hex values, and
|
|
52
|
+
# special floats (e.g., -.inf).
|
|
53
|
+
if string.match?(%r{^[^\d.:-]?[[:alpha:]_\s!@#$%\^&*(){}<>|/\\~;=]+}) || string.match?(/\n/)
|
|
54
|
+
return string if string.length > 5
|
|
55
|
+
|
|
56
|
+
if string.match?(/^[^ytonf~]/i)
|
|
57
|
+
string
|
|
58
|
+
elsif string == '~' || string.match?(/^null$/i)
|
|
59
|
+
nil
|
|
60
|
+
elsif string.match?(BOOLEAN_TRUE)
|
|
61
|
+
true
|
|
62
|
+
elsif string.match?(BOOLEAN_FALSE)
|
|
63
|
+
false
|
|
64
|
+
else
|
|
65
|
+
string
|
|
66
|
+
end
|
|
67
|
+
elsif string.match?(TIME)
|
|
68
|
+
begin
|
|
69
|
+
parse_time string
|
|
70
|
+
rescue ArgumentError
|
|
71
|
+
string
|
|
72
|
+
end
|
|
73
|
+
elsif string.match?(/^\d{4}-(?:1[012]|0\d|\d)-(?:[12]\d|3[01]|0\d|\d)$/)
|
|
74
|
+
begin
|
|
75
|
+
class_loader.date.strptime(string, '%F', Date::GREGORIAN)
|
|
76
|
+
rescue ArgumentError
|
|
77
|
+
string
|
|
78
|
+
end
|
|
79
|
+
elsif string.match?(/^\+?\.inf$/i)
|
|
80
|
+
Float::INFINITY
|
|
81
|
+
elsif string.match?(/^-\.inf$/i)
|
|
82
|
+
-Float::INFINITY
|
|
83
|
+
elsif string.match?(/^\.nan$/i)
|
|
84
|
+
Float::NAN
|
|
85
|
+
elsif @parse_symbols && string.match?(/^:./)
|
|
86
|
+
if string =~ /^:(["'])(.*)\1/
|
|
87
|
+
@symbol_cache[string] = class_loader.symbolize($2.sub(/^:/, ''))
|
|
88
|
+
else
|
|
89
|
+
@symbol_cache[string] = class_loader.symbolize(string.sub(/^:/, ''))
|
|
90
|
+
end
|
|
91
|
+
elsif string.match?(/^[-+]?[0-9][0-9_]*(:[0-5]?[0-9]){1,2}$/)
|
|
92
|
+
i = 0
|
|
93
|
+
string.split(':').each_with_index do |n, e|
|
|
94
|
+
i += (n.to_i * 60**(e - 2).abs)
|
|
95
|
+
end
|
|
96
|
+
i
|
|
97
|
+
elsif string.match?(/^[-+]?[0-9][0-9_]*(:[0-5]?[0-9]){1,2}\.[0-9_]*$/)
|
|
98
|
+
i = 0
|
|
99
|
+
string.split(':').each_with_index do |n, e|
|
|
100
|
+
i += (n.to_f * 60**(e - 2).abs)
|
|
101
|
+
end
|
|
102
|
+
i
|
|
103
|
+
elsif string.match?(FLOAT)
|
|
104
|
+
if string.match?(/\A[-+]?\.\Z/)
|
|
105
|
+
string
|
|
106
|
+
else
|
|
107
|
+
Float(string.delete(',_').gsub(/\.([Ee]|$)/, '\1'))
|
|
108
|
+
end
|
|
109
|
+
elsif string.match?(integer_regex)
|
|
110
|
+
parse_int string
|
|
111
|
+
else
|
|
112
|
+
string
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
# Parse and return an int from +string+
|
|
117
|
+
def parse_int string
|
|
118
|
+
Integer(string.delete(',_'))
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
###
|
|
122
|
+
# Parse and return a Time from +string+
|
|
123
|
+
def parse_time string
|
|
124
|
+
date, time = *(string.split(/[Tt]|\s+/, 2))
|
|
125
|
+
(yy, m, dd) = date.match(/^(-?\d{4})-(\d{1,2})-(\d{1,2})/).captures.map { |x| x.to_i }
|
|
126
|
+
md = time.match(/(\d+:\d+:\d+)(?:\.(\d*))?\s*(Z|[-+]\d+(:\d\d)?)?/)
|
|
127
|
+
|
|
128
|
+
(hh, mm, ss) = md[1].split(':').map { |x| x.to_i }
|
|
129
|
+
us = (md[2] ? Rational("0.#{md[2]}") : 0) * 1_000_000
|
|
130
|
+
|
|
131
|
+
time = Time.utc(yy, m, dd, hh, mm, ss, us)
|
|
132
|
+
|
|
133
|
+
return time if 'Z' == md[3]
|
|
134
|
+
return Time.at(time.to_i, us) unless md[3]
|
|
135
|
+
|
|
136
|
+
tz = md[3].match(/^([+\-]?\d{1,2})\:?(\d{1,2})?$/)[1..-1].compact.map { |digit| Integer(digit, 10) }
|
|
137
|
+
offset = tz.first * 3600
|
|
138
|
+
|
|
139
|
+
if offset < 0
|
|
140
|
+
offset -= ((tz[1] || 0) * 60)
|
|
141
|
+
else
|
|
142
|
+
offset += ((tz[1] || 0) * 60)
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
Time.new(yy, m, dd, hh, mm, ss + us / 1_000_000r, offset)
|
|
146
|
+
end
|
|
147
|
+
end
|
|
148
|
+
end
|
|
149
|
+
end
|
data/lib/yeptris/psych.rb
CHANGED
|
@@ -22,6 +22,9 @@ require "yeptris"
|
|
|
22
22
|
# document without materializing.
|
|
23
23
|
module Yeptris
|
|
24
24
|
module Psych
|
|
25
|
+
autoload :ClassLoader, "yeptris/psych/class_loader"
|
|
26
|
+
autoload :ScalarScanner, "yeptris/psych/scalar_scanner"
|
|
27
|
+
|
|
25
28
|
# The tag registries (Psych's class-level API, #95 bug 4):
|
|
26
29
|
# load_tags maps a serialized tag to the Class that revives it;
|
|
27
30
|
# dump_tags overrides the emitted tag for a Class. Consulted by
|
|
@@ -258,18 +261,28 @@ module Yeptris
|
|
|
258
261
|
::Yeptris::Psych.dump(obj, io, options)
|
|
259
262
|
end
|
|
260
263
|
|
|
261
|
-
def load_stream(yaml, **kwargs)
|
|
264
|
+
def load_stream(yaml, **kwargs, &block)
|
|
262
265
|
# materialize each document's root directly — the stream
|
|
263
266
|
# children share one C document, so their handles would all
|
|
264
|
-
# resolve to the first document's tree
|
|
267
|
+
# resolve to the first document's tree. stdlib's block form
|
|
268
|
+
# yields each loaded document's object (#179 round 4).
|
|
265
269
|
doc = Yeptris::Document.parse(yaml, schema: :compat_11)
|
|
266
270
|
return nil if doc.nil? # the legal empty stream
|
|
267
271
|
|
|
268
272
|
begin
|
|
269
|
-
(0...doc.document_count).map { |i| doc.root(i).to_ruby }
|
|
273
|
+
docs = (0...doc.document_count).map { |i| doc.root(i).to_ruby }
|
|
270
274
|
ensure
|
|
271
275
|
doc.free
|
|
272
276
|
end
|
|
277
|
+
docs.each { |d| block.call(d) } if block
|
|
278
|
+
docs
|
|
279
|
+
end
|
|
280
|
+
|
|
281
|
+
# safe_load_stream: stdlib's surface — the stream form of
|
|
282
|
+
# safe_load. Our load_stream is already safe-by-default
|
|
283
|
+
# (Psych 5 semantics), so this is the yielding wrapper.
|
|
284
|
+
def safe_load_stream(yaml, **kwargs, &block)
|
|
285
|
+
load_stream(yaml, **kwargs, &block)
|
|
273
286
|
end
|
|
274
287
|
|
|
275
288
|
# The first document's node tree (no Ruby materialization).
|
|
@@ -299,13 +312,14 @@ module Yeptris
|
|
|
299
312
|
# handles GC-free. (The block-yielding form is tracked under
|
|
300
313
|
# #179: the current implementation materializes eagerly; the
|
|
301
314
|
# block is only honored as a no-op convenience.)
|
|
302
|
-
_ = block # reserved for the future yielding form (#179)
|
|
303
315
|
doc = Yeptris::Document.parse(yaml, schema: :compat_11)
|
|
304
316
|
return nil if doc.nil? || doc.document_count.zero?
|
|
305
317
|
|
|
306
318
|
stream = Nodes::Stream.new
|
|
307
319
|
(0...doc.document_count).each do |i|
|
|
308
|
-
|
|
320
|
+
child = Nodes::Builder.document_stream_child(doc, i)
|
|
321
|
+
stream.children << child
|
|
322
|
+
block.call(child) if block # stdlib's yielding form (#179 round 4)
|
|
309
323
|
end
|
|
310
324
|
# ownership: the DOCUMENT wrapper is the sole owner — its own
|
|
311
325
|
# finalizer (pointer-only closure) frees the C memory; the
|
|
@@ -450,6 +464,10 @@ module Yeptris
|
|
|
450
464
|
# tree stay valid while the tree is reachable; a GC finalizer
|
|
451
465
|
# releases the C memory when it is not.
|
|
452
466
|
class Document < Node
|
|
467
|
+
# The document's root as a Ruby object (the stream-yield face).
|
|
468
|
+
def to_ruby
|
|
469
|
+
children.first&.to_ruby
|
|
470
|
+
end
|
|
453
471
|
attr_reader :version, :tags
|
|
454
472
|
|
|
455
473
|
def initialize(version = [], tags = {})
|
data/lib/yeptris.rb
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
module Yeptris
|
|
4
4
|
# The gem's version lives in the parent namespace's file — the last
|
|
5
5
|
# internal require (yeptris/version) retired with it.
|
|
6
|
-
VERSION = "0.6.16.
|
|
6
|
+
VERSION = "0.6.16.2".freeze
|
|
7
7
|
# The error hierarchy lives in THIS file (the parent namespace's
|
|
8
8
|
# own file): nested constants do not trigger a parent-constant
|
|
9
9
|
# autoload, and the law forbids internal requires — defining the
|
|
@@ -65,7 +65,9 @@ enum {
|
|
|
65
65
|
(default: last, as at parse) */
|
|
66
66
|
};
|
|
67
67
|
|
|
68
|
-
/* One plan node.
|
|
68
|
+
/* One plan node. ABI-pinned: a pointer plus 16 fixed-width bytes —
|
|
69
|
+
* 24 on LP64, 20 on 32-bit (the hosts' FFI mirrors size :pointer
|
|
70
|
+
* per-process, so the layout contract is the POINTER plus the tail). */
|
|
69
71
|
typedef struct yeptris_desc_node {
|
|
70
72
|
const char* wire_name; /* mapping key to match (NULL: the root) */
|
|
71
73
|
uint8_t kind; /* YEP_SK_* */
|
|
@@ -77,7 +79,7 @@ typedef struct yeptris_desc_node {
|
|
|
77
79
|
uint32_t reserved; /* must be 0 (ABI headroom) */
|
|
78
80
|
} yeptris_desc_node;
|
|
79
81
|
|
|
80
|
-
YEPTRIS_CT_ASSERT(sizeof(yeptris_desc_node) ==
|
|
82
|
+
YEPTRIS_CT_ASSERT(sizeof(yeptris_desc_node) == sizeof(const char*) + 16);
|
|
81
83
|
|
|
82
84
|
/* One column's output. Caller allocates the payload array (sized by
|
|
83
85
|
* expectation); the call fills it and sets count. No per-value FFI:
|
|
@@ -27,6 +27,8 @@
|
|
|
27
27
|
#include <math.h>
|
|
28
28
|
#include <string.h>
|
|
29
29
|
|
|
30
|
+
#include <stdlib.h>
|
|
31
|
+
|
|
30
32
|
#include <yeptris/cbor.h>
|
|
31
33
|
#include <yeptris/resolve.h>
|
|
32
34
|
|
|
@@ -37,29 +39,41 @@
|
|
|
37
39
|
#include "../memory/allocator.h"
|
|
38
40
|
#include "../parse/events.h"
|
|
39
41
|
#include "doc.h"
|
|
42
|
+
#include "sink.h"
|
|
40
43
|
|
|
41
44
|
#define YEP_CBOR_INDEF UINT64_MAX
|
|
42
45
|
#define YEP_CBOR_MAX_ARG_BYTES 8
|
|
43
46
|
|
|
44
47
|
typedef struct {
|
|
45
|
-
uint64_t rem;
|
|
48
|
+
uint64_t rem; /* items left; maps count 2*pairs; INDEF = until break */
|
|
49
|
+
uint64_t consumed; /* items landed (the key/value parity) */
|
|
46
50
|
uint8_t is_map;
|
|
47
51
|
} yep_cframe;
|
|
48
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
|
+
|
|
49
58
|
typedef struct {
|
|
50
|
-
yep_dom* d;
|
|
59
|
+
yep_dom* d; /* the DOM sink's ctx (NULL for pure sinks) */
|
|
51
60
|
const unsigned char* p;
|
|
52
61
|
size_t len;
|
|
53
62
|
size_t i;
|
|
54
63
|
int strict;
|
|
55
64
|
YeptrisStatus status;
|
|
56
|
-
/* pending tag chain
|
|
57
|
-
*
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
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;
|
|
61
75
|
yep_cframe frame[YEP_DOM_MAX_DEPTH];
|
|
62
|
-
int depth;
|
|
76
|
+
int depth;
|
|
63
77
|
} yep_cdec;
|
|
64
78
|
|
|
65
79
|
static void cbor_fail(yep_cdec* c, yep_err_code code, const char* msg) {
|
|
@@ -146,116 +160,74 @@ static double cbor_half(uint16_t h) {
|
|
|
146
160
|
return (h & 0x8000u) != 0 ? -val : val;
|
|
147
161
|
}
|
|
148
162
|
|
|
149
|
-
/*
|
|
150
|
-
static
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
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;
|
|
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;
|
|
178
168
|
}
|
|
179
|
-
|
|
169
|
+
*len = c->taglen;
|
|
170
|
+
c->taglen = 0;
|
|
171
|
+
return c->tagbuf;
|
|
180
172
|
}
|
|
181
173
|
|
|
182
|
-
/*
|
|
183
|
-
static uint32_t
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
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) {
|
|
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)) {
|
|
194
180
|
c->status = YEPTRIS_ERROR_MEMORY;
|
|
195
181
|
return UINT32_MAX;
|
|
196
182
|
}
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
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) {
|
|
201
194
|
c->status = YEPTRIS_ERROR_MEMORY;
|
|
202
195
|
return UINT32_MAX;
|
|
203
196
|
}
|
|
204
|
-
return
|
|
197
|
+
return 0;
|
|
205
198
|
}
|
|
206
199
|
|
|
207
|
-
static int cbor_open(yep_cdec* c, int is_map) {
|
|
200
|
+
static int cbor_open(yep_cdec* c, int is_map, uint64_t cap) {
|
|
208
201
|
if (c->depth >= YEP_DOM_MAX_DEPTH) {
|
|
209
202
|
yep_error_set(yep_error_tls(), YEP_ERR_UNEXPECTED, 0, 0, c->i,
|
|
210
203
|
"CBOR nesting exceeds the depth guard at byte %zu", c->i);
|
|
211
204
|
c->status = YEPTRIS_ERROR_DEPTH;
|
|
212
205
|
return 0;
|
|
213
206
|
}
|
|
214
|
-
|
|
215
|
-
const
|
|
216
|
-
if (c->
|
|
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) {
|
|
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)) {
|
|
225
210
|
c->status = YEPTRIS_ERROR_MEMORY;
|
|
226
211
|
return 0;
|
|
227
212
|
}
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
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 */
|
|
213
|
+
/* a sibling at this depth may have left state behind */
|
|
214
|
+
c->frame[c->depth].consumed = 0;
|
|
215
|
+
c->depth++;
|
|
235
216
|
return 1;
|
|
236
217
|
}
|
|
237
218
|
|
|
238
219
|
static int cbor_note_tag(yep_cdec* c, uint64_t tag) {
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
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;
|
|
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;
|
|
248
225
|
return 0;
|
|
249
226
|
}
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
c->pending_tag = piece;
|
|
253
|
-
c->pending_tag.len = 0;
|
|
254
|
-
c->have_pending = 1;
|
|
227
|
+
if (c->taglen > 0) {
|
|
228
|
+
c->tagbuf[c->taglen++] = ' '; /* separator between chain links */
|
|
255
229
|
}
|
|
256
|
-
|
|
257
|
-
/* piece-by-piece commit keeps the chain contiguous in the arena */
|
|
258
|
-
c->pending_tag.len += n;
|
|
230
|
+
c->taglen += cbor_u64dec(tag, c->tagbuf + c->taglen);
|
|
259
231
|
return 1;
|
|
260
232
|
}
|
|
261
233
|
|
|
@@ -263,7 +235,6 @@ static int cbor_note_tag(yep_cdec* c, uint64_t tag) {
|
|
|
263
235
|
* arena; text chunks validate per chunk — RFC 8949 s3.2.3's code-point
|
|
264
236
|
* boundary rule makes per-chunk validity imply whole-string validity). */
|
|
265
237
|
static int cbor_indef_string(yep_cdec* c, int is_text) {
|
|
266
|
-
uint32_t first = 0;
|
|
267
238
|
uint32_t total = 0;
|
|
268
239
|
for (;;) {
|
|
269
240
|
if (c->i >= c->len) {
|
|
@@ -291,75 +262,55 @@ static int cbor_indef_string(yep_cdec* c, int is_text) {
|
|
|
291
262
|
return 0;
|
|
292
263
|
}
|
|
293
264
|
if (n > 0) { /* zero-length chunks are legal, just empty */
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
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;
|
|
303
277
|
}
|
|
278
|
+
memcpy(c->ibuf + total, c->p + c->i, (size_t)n);
|
|
304
279
|
total += (uint32_t)n;
|
|
305
280
|
}
|
|
306
281
|
c->i += (size_t)n;
|
|
307
282
|
}
|
|
308
|
-
/*
|
|
309
|
-
|
|
310
|
-
const
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
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) {
|
|
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) {
|
|
326
289
|
c->status = YEPTRIS_ERROR_MEMORY;
|
|
327
290
|
return 0;
|
|
328
291
|
}
|
|
329
292
|
return 1;
|
|
330
293
|
}
|
|
331
294
|
|
|
332
|
-
/*
|
|
333
|
-
static int cbor_int_node(yep_cdec* c, int negative, uint64_t mag) {
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
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;
|
|
339
302
|
}
|
|
340
|
-
|
|
341
|
-
tag_id = YEPTRIS_TAG_INT;
|
|
342
|
-
return cbor_text_node(c, buf, n, tag_id) != UINT32_MAX;
|
|
303
|
+
return 1;
|
|
343
304
|
}
|
|
344
305
|
|
|
345
|
-
static int cbor_float_node(yep_cdec* c, double dv) {
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
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);
|
|
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;
|
|
360
312
|
}
|
|
361
|
-
|
|
362
|
-
return cbor_text_node(c, buf, n, YEPTRIS_TAG_FLOAT) != UINT32_MAX;
|
|
313
|
+
return 1;
|
|
363
314
|
}
|
|
364
315
|
|
|
365
316
|
/* The diagnostic renderer for lenient-mode non-string SCALAR map keys
|
|
@@ -408,9 +359,9 @@ static int cbor_key_diag(yep_cdec* c, uint8_t mt, uint64_t val, double dv) {
|
|
|
408
359
|
}
|
|
409
360
|
break;
|
|
410
361
|
default:
|
|
411
|
-
return cbor_float_node(c, dv); /* floats: the shortest text */
|
|
362
|
+
return cbor_float_node(c, dv, 1); /* floats: the shortest text */
|
|
412
363
|
}
|
|
413
|
-
return cbor_text_node(c, buf, n, 0) != UINT32_MAX;
|
|
364
|
+
return cbor_text_node(c, buf, n, 0, 1) != UINT32_MAX;
|
|
414
365
|
}
|
|
415
366
|
|
|
416
367
|
/* Decodes ONE data item (scalar: creates+places the node; container:
|
|
@@ -425,9 +376,10 @@ static int cbor_item(yep_cdec* c) {
|
|
|
425
376
|
uint8_t ai = ib & 0x1F;
|
|
426
377
|
|
|
427
378
|
/* the map-key position decides representation before the item is
|
|
428
|
-
* built
|
|
379
|
+
* built: even items consumed = key, odd = value (the frame's own
|
|
380
|
+
* parity — the DOM's placement machine tracks its own copy) */
|
|
429
381
|
int key_slot = 0;
|
|
430
|
-
if (c->depth > 0 && c->frame[c->depth - 1].is_map &&
|
|
382
|
+
if (c->depth > 0 && c->frame[c->depth - 1].is_map && c->frame[c->depth - 1].consumed % 2 == 0) {
|
|
431
383
|
key_slot = 1;
|
|
432
384
|
}
|
|
433
385
|
|
|
@@ -444,7 +396,7 @@ static int cbor_item(yep_cdec* c) {
|
|
|
444
396
|
if (key_slot) {
|
|
445
397
|
CBOR_REJECT("structure as map key");
|
|
446
398
|
}
|
|
447
|
-
if (!cbor_open(c, 0)) {
|
|
399
|
+
if (!cbor_open(c, 0, YEP_CBOR_INDEF)) {
|
|
448
400
|
return 0;
|
|
449
401
|
}
|
|
450
402
|
c->frame[c->depth - 1].rem = YEP_CBOR_INDEF;
|
|
@@ -454,7 +406,7 @@ static int cbor_item(yep_cdec* c) {
|
|
|
454
406
|
if (key_slot) {
|
|
455
407
|
CBOR_REJECT("structure as map key");
|
|
456
408
|
}
|
|
457
|
-
if (!cbor_open(c, 1)) {
|
|
409
|
+
if (!cbor_open(c, 1, YEP_CBOR_INDEF)) {
|
|
458
410
|
return 0;
|
|
459
411
|
}
|
|
460
412
|
c->frame[c->depth - 1].rem = YEP_CBOR_INDEF;
|
|
@@ -482,9 +434,9 @@ static int cbor_item(yep_cdec* c) {
|
|
|
482
434
|
return cbor_key_diag(c, 0, arg, 0) ? 1 : 0;
|
|
483
435
|
}
|
|
484
436
|
if (arg <= (uint64_t)INT64_MAX) {
|
|
485
|
-
return cbor_int_node(c, 0, arg) ? 1 : 0;
|
|
437
|
+
return cbor_int_node(c, 0, arg, key_slot) ? 1 : 0;
|
|
486
438
|
}
|
|
487
|
-
return cbor_float_node(c, (double)arg) ? 1 : 0;
|
|
439
|
+
return cbor_float_node(c, (double)arg, key_slot) ? 1 : 0;
|
|
488
440
|
}
|
|
489
441
|
case 1: {
|
|
490
442
|
if (key_slot && c->strict) {
|
|
@@ -495,9 +447,9 @@ static int cbor_item(yep_cdec* c) {
|
|
|
495
447
|
}
|
|
496
448
|
if (arg <= (uint64_t)INT64_MAX + 1) { /* -1-2^63 == INT64_MIN */
|
|
497
449
|
uint64_t mag = arg + 1;
|
|
498
|
-
return cbor_int_node(c, 1, mag) ? 1 : 0;
|
|
450
|
+
return cbor_int_node(c, 1, mag, key_slot) ? 1 : 0;
|
|
499
451
|
}
|
|
500
|
-
return cbor_float_node(c, -((double)arg + 1.0)) ? 1 : 0;
|
|
452
|
+
return cbor_float_node(c, -((double)arg + 1.0), key_slot) ? 1 : 0;
|
|
501
453
|
}
|
|
502
454
|
case 2:
|
|
503
455
|
case 3: {
|
|
@@ -518,7 +470,7 @@ static int cbor_item(yep_cdec* c) {
|
|
|
518
470
|
c->i += (size_t)arg;
|
|
519
471
|
return ok ? 1 : 0;
|
|
520
472
|
}
|
|
521
|
-
uint32_t id = cbor_span_node(c, c->p + c->i, (uint32_t)arg);
|
|
473
|
+
uint32_t id = cbor_span_node(c, c->p + c->i, (uint32_t)arg, (uint8_t)mt, key_slot);
|
|
522
474
|
c->i += (size_t)arg;
|
|
523
475
|
return id != UINT32_MAX ? 1 : 0;
|
|
524
476
|
}
|
|
@@ -529,7 +481,7 @@ static int cbor_item(yep_cdec* c) {
|
|
|
529
481
|
if (arg > c->len - c->i) { /* every item consumes >= 1 byte */
|
|
530
482
|
CBOR_REJECT("array overruns the input");
|
|
531
483
|
}
|
|
532
|
-
if (!cbor_open(c, 0)) {
|
|
484
|
+
if (!cbor_open(c, 0, arg)) {
|
|
533
485
|
return 0;
|
|
534
486
|
}
|
|
535
487
|
c->frame[c->depth - 1].rem = arg;
|
|
@@ -543,7 +495,7 @@ static int cbor_item(yep_cdec* c) {
|
|
|
543
495
|
if (arg > (c->len - c->i) / 2) { /* pairs need 2 items each */
|
|
544
496
|
CBOR_REJECT("map overruns the input");
|
|
545
497
|
}
|
|
546
|
-
if (!cbor_open(c, 1)) {
|
|
498
|
+
if (!cbor_open(c, 1, arg * 2)) {
|
|
547
499
|
return 0;
|
|
548
500
|
}
|
|
549
501
|
c->frame[c->depth - 1].rem = arg * 2;
|
|
@@ -566,22 +518,22 @@ static int cbor_item(yep_cdec* c) {
|
|
|
566
518
|
if (key_slot) {
|
|
567
519
|
return cbor_key_diag(c, 7, 20, 0) ? 1 : 0;
|
|
568
520
|
}
|
|
569
|
-
return cbor_text_node(c, "false", 5, YEPTRIS_TAG_BOOL) != UINT32_MAX ? 1 : 0;
|
|
521
|
+
return cbor_text_node(c, "false", 5, YEPTRIS_TAG_BOOL, key_slot) != UINT32_MAX ? 1 : 0;
|
|
570
522
|
case 21:
|
|
571
523
|
if (key_slot) {
|
|
572
524
|
return cbor_key_diag(c, 7, 21, 0) ? 1 : 0;
|
|
573
525
|
}
|
|
574
|
-
return cbor_text_node(c, "true", 4, YEPTRIS_TAG_BOOL) != UINT32_MAX ? 1 : 0;
|
|
526
|
+
return cbor_text_node(c, "true", 4, YEPTRIS_TAG_BOOL, key_slot) != UINT32_MAX ? 1 : 0;
|
|
575
527
|
case 22:
|
|
576
528
|
if (key_slot) {
|
|
577
529
|
return cbor_key_diag(c, 7, 22, 0) ? 1 : 0;
|
|
578
530
|
}
|
|
579
|
-
return cbor_text_node(c, "null", 4, YEPTRIS_TAG_NULL) != UINT32_MAX ? 1 : 0;
|
|
531
|
+
return cbor_text_node(c, "null", 4, YEPTRIS_TAG_NULL, key_slot) != UINT32_MAX ? 1 : 0;
|
|
580
532
|
case 23:
|
|
581
533
|
if (key_slot) {
|
|
582
534
|
return cbor_key_diag(c, 7, 23, 0) ? 1 : 0;
|
|
583
535
|
}
|
|
584
|
-
return cbor_text_node(c, "undefined", 9, 0) != UINT32_MAX ? 1 : 0;
|
|
536
|
+
return cbor_text_node(c, "undefined", 9, 0, key_slot) != UINT32_MAX ? 1 : 0;
|
|
585
537
|
case 24: {
|
|
586
538
|
if (c->len - c->i < 1) {
|
|
587
539
|
CBOR_REJECT("truncated simple value");
|
|
@@ -597,7 +549,7 @@ static int cbor_item(yep_cdec* c) {
|
|
|
597
549
|
memcpy(buf, "simple(", 7);
|
|
598
550
|
uint32_t n = 7 + cbor_u64dec(v, buf + 7);
|
|
599
551
|
buf[n++] = ')';
|
|
600
|
-
return cbor_text_node(c, buf, n, 0) != UINT32_MAX ? 1 : 0;
|
|
552
|
+
return cbor_text_node(c, buf, n, 0, key_slot) != UINT32_MAX ? 1 : 0;
|
|
601
553
|
}
|
|
602
554
|
case 25: {
|
|
603
555
|
if (c->len - c->i < 2) {
|
|
@@ -641,7 +593,7 @@ static int cbor_item(yep_cdec* c) {
|
|
|
641
593
|
memcpy(buf, "simple(", 7);
|
|
642
594
|
uint32_t n = 7 + cbor_u64dec(ai, buf + 7);
|
|
643
595
|
buf[n++] = ')';
|
|
644
|
-
return cbor_text_node(c, buf, n, 0) != UINT32_MAX ? 1 : 0;
|
|
596
|
+
return cbor_text_node(c, buf, n, 0, key_slot) != UINT32_MAX ? 1 : 0;
|
|
645
597
|
}
|
|
646
598
|
CBOR_REJECT("reserved additional information");
|
|
647
599
|
}
|
|
@@ -652,34 +604,191 @@ static int cbor_item(yep_cdec* c) {
|
|
|
652
604
|
if (key_slot) {
|
|
653
605
|
return cbor_key_diag(c, 8, 0, dv) ? 1 : 0;
|
|
654
606
|
}
|
|
655
|
-
return cbor_float_node(c, dv) ? 1 : 0;
|
|
607
|
+
return cbor_float_node(c, dv, key_slot) ? 1 : 0;
|
|
656
608
|
}
|
|
657
609
|
|
|
658
|
-
|
|
659
|
-
|
|
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) {
|
|
660
765
|
yep_cdec c;
|
|
661
766
|
memset(&c, 0, sizeof(c));
|
|
662
|
-
c.
|
|
767
|
+
c.s = sink;
|
|
663
768
|
c.p = p;
|
|
664
769
|
c.len = len;
|
|
665
770
|
c.strict = strict;
|
|
666
771
|
c.status = YEPTRIS_OK;
|
|
667
772
|
int done_top = 0; /* the ONE top-level item is done (tags never count) */
|
|
773
|
+
int rc;
|
|
668
774
|
for (;;) {
|
|
669
775
|
if (c.depth == 0) {
|
|
670
776
|
if (done_top) { /* the root closed; one data item per call */
|
|
671
777
|
if (c.i != len && consumed == NULL) {
|
|
672
778
|
cbor_fail(&c, YEP_ERR_UNEXPECTED, "trailing bytes after the data item");
|
|
673
|
-
|
|
779
|
+
rc = YEPTRIS_ERROR_PARSE;
|
|
780
|
+
goto done;
|
|
674
781
|
}
|
|
675
782
|
if (consumed != NULL) {
|
|
676
783
|
*consumed = c.i;
|
|
677
784
|
}
|
|
678
|
-
|
|
785
|
+
rc = YEPTRIS_OK;
|
|
786
|
+
goto done;
|
|
679
787
|
}
|
|
680
788
|
int st = cbor_item(&c);
|
|
681
789
|
if (st == 0) {
|
|
682
|
-
|
|
790
|
+
rc = (int)c.status;
|
|
791
|
+
goto done;
|
|
683
792
|
}
|
|
684
793
|
if (st == 2) {
|
|
685
794
|
continue; /* tag chain: the content item follows */
|
|
@@ -689,19 +798,26 @@ int yep_cbor_decode_dom(yep_dom* d, const unsigned char* p, size_t len, int stri
|
|
|
689
798
|
}
|
|
690
799
|
yep_cframe* fr = &c.frame[c.depth - 1];
|
|
691
800
|
if (fr->rem == 0) { /* definite container complete */
|
|
692
|
-
c.
|
|
801
|
+
if (!c.s->close(c.s->ctx, fr->is_map)) {
|
|
802
|
+
rc = YEPTRIS_ERROR_MEMORY;
|
|
803
|
+
goto done;
|
|
804
|
+
}
|
|
693
805
|
c.depth--;
|
|
694
806
|
continue;
|
|
695
807
|
}
|
|
696
808
|
if (fr->rem == YEP_CBOR_INDEF) {
|
|
697
809
|
if (c.i < c.len && c.p[c.i] == 0xFF) {
|
|
698
|
-
if (fr->is_map &&
|
|
810
|
+
if (fr->is_map && fr->consumed % 2 == 1) {
|
|
699
811
|
cbor_fail(&c, YEP_ERR_UNEXPECTED,
|
|
700
812
|
"break in a map value position (odd item count)");
|
|
701
|
-
|
|
813
|
+
rc = YEPTRIS_ERROR_PARSE;
|
|
814
|
+
goto done;
|
|
702
815
|
}
|
|
703
816
|
c.i++;
|
|
704
|
-
c.
|
|
817
|
+
if (!c.s->close(c.s->ctx, fr->is_map)) {
|
|
818
|
+
rc = YEPTRIS_ERROR_MEMORY;
|
|
819
|
+
goto done;
|
|
820
|
+
}
|
|
705
821
|
c.depth--;
|
|
706
822
|
continue;
|
|
707
823
|
}
|
|
@@ -709,16 +825,33 @@ int yep_cbor_decode_dom(yep_dom* d, const unsigned char* p, size_t len, int stri
|
|
|
709
825
|
size_t parent = (size_t)(c.depth - 1);
|
|
710
826
|
int st = cbor_item(&c);
|
|
711
827
|
if (st == 0) {
|
|
712
|
-
|
|
828
|
+
rc = (int)c.status;
|
|
829
|
+
goto done;
|
|
713
830
|
}
|
|
714
831
|
if (st == 2) {
|
|
715
832
|
continue; /* tags never consume a container slot */
|
|
716
833
|
}
|
|
834
|
+
c.frame[parent].consumed++;
|
|
717
835
|
if (c.frame[parent].rem != YEP_CBOR_INDEF) {
|
|
718
836
|
c.frame[parent].rem--;
|
|
719
837
|
/* one item (scalar, or a container now open) consumed a parent slot */
|
|
720
838
|
}
|
|
721
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);
|
|
722
855
|
}
|
|
723
856
|
|
|
724
857
|
static YeptrisDocument cbor_wrap(yep_dom* dom, const void* buf, const yep_allocator* sys) {
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/* sink.h — the CBOR decode seam (#157).
|
|
2
|
+
*
|
|
3
|
+
* The grammar loop (decode.c's cbor_item machinery) is the single
|
|
4
|
+
* source of CBOR semantics; a sink implements the item constructors
|
|
5
|
+
* on top of it. Two sinks exist: the DOM builder (the default, the
|
|
6
|
+
* yeptris_cbor_decode public path) and the native ext's VALUE builder
|
|
7
|
+
* (one pass, no intermediate). Sinks receive the resolver's tag_id
|
|
8
|
+
* and the pending semantic-tag chain in its text form ("N N N",
|
|
9
|
+
* outermost first — NULL when the item carries no chain).
|
|
10
|
+
*/
|
|
11
|
+
#ifndef YEP_CBOR_SINK_H
|
|
12
|
+
#define YEP_CBOR_SINK_H
|
|
13
|
+
|
|
14
|
+
#include <stddef.h>
|
|
15
|
+
#include <stdint.h>
|
|
16
|
+
|
|
17
|
+
#include <yeptris/api.h> /* YEPTRIS_API (the ext links these) */
|
|
18
|
+
|
|
19
|
+
typedef struct yep_cbor_sink {
|
|
20
|
+
void* ctx;
|
|
21
|
+
/* All callbacks return 0 on sink failure (the decoder reports
|
|
22
|
+
* MEMORY). They may raise through host languages (longjmp): the
|
|
23
|
+
* decoder owns no host-managed state across them except the
|
|
24
|
+
* indefinite buffer, which its own exit paths free. */
|
|
25
|
+
/* is_key: 1 = the item lands in the enclosing map's key slot
|
|
26
|
+
* (sinks key-intern strings; the DOM ignores it). Rendered text:
|
|
27
|
+
* numbers-as-text, false/true/null/undefined, simple(N) — the
|
|
28
|
+
* exact bytes the DOM path stores. */
|
|
29
|
+
int (*text)(void* ctx, const char* s, uint32_t n, uint8_t tag_id, int is_key, const char* tag,
|
|
30
|
+
uint32_t tag_len);
|
|
31
|
+
/* Known integers: value = negative ? -(mag) : mag, mag <= 2^63. */
|
|
32
|
+
int (*int_val)(void* ctx, int negative, uint64_t mag, int is_key, const char* tag,
|
|
33
|
+
uint32_t tag_len);
|
|
34
|
+
int (*float_val)(void* ctx, double dv, int is_key, const char* tag, uint32_t tag_len);
|
|
35
|
+
/* Strings. borrowed: 1 = p is the input (a sink may record the
|
|
36
|
+
* offset), 0 = the decoder's scratch buffer (copy or take it). */
|
|
37
|
+
int (*str_val)(void* ctx, const unsigned char* p, uint32_t n, int borrowed, int is_key,
|
|
38
|
+
const char* tag, uint32_t tag_len);
|
|
39
|
+
int (*bytes_val)(void* ctx, const unsigned char* p, uint32_t n, int borrowed, int is_key,
|
|
40
|
+
const char* tag, uint32_t tag_len);
|
|
41
|
+
/* Containers. cap: expected item count (maps: pairs*2), UINT64_MAX
|
|
42
|
+
* for indefinite. close fires for BOTH the definite-complete and
|
|
43
|
+
* the break paths, after the last child. */
|
|
44
|
+
int (*open)(void* ctx, int is_map, uint64_t cap, const char* tag, uint32_t tag_len);
|
|
45
|
+
int (*close)(void* ctx, int is_map);
|
|
46
|
+
} yep_cbor_sink;
|
|
47
|
+
|
|
48
|
+
/* The generic engine: the grammar, driving `sink`. Same reject/
|
|
49
|
+
* encoding/depth semantics as the DOM entry. */
|
|
50
|
+
YEPTRIS_API int yep_cbor_decode_gen(const unsigned char* p, size_t len, int strict,
|
|
51
|
+
size_t* consumed, const yep_cbor_sink* sink);
|
|
52
|
+
|
|
53
|
+
/* The DOM sink: pairs yep_cbor_decode_gen with a yep_dom* (the
|
|
54
|
+
* yep_cbor_decode_dom public path's driver; d is a yep_dom*). */
|
|
55
|
+
YEPTRIS_API int yep_cbor_decode_dom_sink(void* d, const unsigned char* p, size_t len, int strict,
|
|
56
|
+
size_t* consumed);
|
|
57
|
+
|
|
58
|
+
#endif /* YEP_CBOR_SINK_H */
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: yeptris
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.6.16.
|
|
4
|
+
version: 0.6.16.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Ribose Inc.
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-09-
|
|
11
|
+
date: 2026-09-22 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: ffi
|
|
@@ -50,11 +50,13 @@ files:
|
|
|
50
50
|
- lib/yeptris/materializer.rb
|
|
51
51
|
- lib/yeptris/node.rb
|
|
52
52
|
- lib/yeptris/psych.rb
|
|
53
|
+
- lib/yeptris/psych/class_loader.rb
|
|
53
54
|
- lib/yeptris/psych/coder_shim.rb
|
|
54
55
|
- lib/yeptris/psych/drop_in.rb
|
|
55
56
|
- lib/yeptris/psych/encodable.rb
|
|
56
57
|
- lib/yeptris/psych/handler.rb
|
|
57
58
|
- lib/yeptris/psych/parser.rb
|
|
59
|
+
- lib/yeptris/psych/scalar_scanner.rb
|
|
58
60
|
- lib/yeptris/psych/visitors.rb
|
|
59
61
|
- lib/yeptris/schema.rb
|
|
60
62
|
- lib/yeptris/valueml.rb
|
|
@@ -89,6 +91,7 @@ files:
|
|
|
89
91
|
- vendor/libyeptris/src/yeptris/cbor/cbor.h
|
|
90
92
|
- vendor/libyeptris/src/yeptris/cbor/decode.c
|
|
91
93
|
- vendor/libyeptris/src/yeptris/cbor/encode.c
|
|
94
|
+
- vendor/libyeptris/src/yeptris/cbor/sink.h
|
|
92
95
|
- vendor/libyeptris/src/yeptris/common/chartype.c
|
|
93
96
|
- vendor/libyeptris/src/yeptris/common/chartype.h
|
|
94
97
|
- vendor/libyeptris/src/yeptris/common/cpu.c
|