cddl 0.8.8 → 0.12.14
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/bin/cddl +51 -15
- data/cddl.gemspec +11 -7
- data/data/cddl.abnf +30 -13
- data/lib/cbor-pp-play.rb +1 -0
- data/lib/cddl.rb +726 -74
- data/test/test-cddl.rb +53 -2
- data/test-data/7807.cddl +14 -0
- data/test-data/abignum.cddl +1 -0
- data/test-data/abnf1.cddl +3 -0
- data/test-data/abnf2.cddl +37 -0
- data/test-data/abnf3.cddl +32 -0
- data/test-data/b64c-sloppy.cddl +1 -0
- data/test-data/b64c.cddl +1 -0
- data/test-data/b64u-strict.cddl +12 -0
- data/test-data/b64u.cddl +1 -0
- data/test-data/base32.cddl +1 -0
- data/test-data/base32hex.cddl +1 -0
- data/test-data/bat.cddl +16 -0
- data/test-data/bpv7.cddl +136 -0
- data/test-data/bpv7a.cddl +181 -0
- data/test-data/bpv7b.cddl +167 -0
- data/test-data/cat-re.cddl +4 -0
- data/test-data/catb64.cddl +8 -0
- data/test-data/complex-occ.cddl +11 -0
- data/test-data/coral.cddl +10 -0
- data/test-data/coral1.cddl +5 -0
- data/test-data/coral2.cddl +7 -0
- data/test-data/coral3.cddl +7 -0
- data/test-data/decimal-warn.cddl +1 -0
- data/test-data/decimal.cddl +1 -0
- data/test-data/decimal2.cddl +1 -0
- data/test-data/det1.cddl +12 -0
- data/test-data/dotplus1.cddl +3 -0
- data/test-data/dotplus2.cddl +3 -0
- data/test-data/dotplus3.cddl +3 -0
- data/test-data/dotplus4.cddl +3 -0
- data/test-data/enum.cddl +14 -0
- data/test-data/enum1.cddl +12 -0
- data/test-data/feat1.cddl +4 -0
- data/test-data/feature-controller.cddl +6 -0
- data/test-data/feature-detail.cddl +5 -0
- data/test-data/foo.cddl +1 -0
- data/test-data/hex.cddl +1 -0
- data/test-data/hexlc.cddl +1 -0
- data/test-data/hexuc.cddl +1 -0
- data/test-data/homenet-de.cddl +12 -0
- data/test-data/homenet-fe.cddl +12 -0
- data/test-data/jim-cut-2.cddl +11 -0
- data/test-data/jim-cut.cddl +12 -0
- data/test-data/join.cddl +1 -0
- data/test-data/joini.cddl +1 -0
- data/test-data/joinx.cddl +1 -0
- data/test-data/json.cddl +1 -0
- data/test-data/json1.cddl +15 -0
- data/test-data/json2.cddl +1 -0
- data/test-data/jsoniodef.cddl +719 -0
- data/test-data/jwt.cddl +15 -0
- data/test-data/lint1.cddl +9 -0
- data/test-data/mdl-ble.cddl +9 -0
- data/test-data/mdl-deve.cddl +54 -0
- data/test-data/mdl-dp.cddl +11 -0
- data/test-data/mdl-mso.cddl +20 -0
- data/test-data/mdl-request.cddl +26 -0
- data/test-data/mdl-response.cddl +66 -0
- data/test-data/mdl.cddl +11 -0
- data/test-data/mon-val.cddl +1 -0
- data/test-data/multipart-ct.cddl +2 -0
- data/test-data/named-group.cddl +7 -0
- data/test-data/non-empty.cddl +5 -0
- data/test-data/oid.cddl +8 -0
- data/test-data/oidbat.cddl +8 -0
- data/test-data/plus.cddl +3 -0
- data/test-data/prim.cddl +7 -0
- data/test-data/printf.cddl +2 -0
- data/test-data/printf0.cddl +1 -0
- data/test-data/printf1.cddl +2 -0
- data/test-data/printf2.cddl +2 -0
- data/test-data/printf3.cddl +2 -0
- data/test-data/sasl.cddl +24 -0
- data/test-data/sequence.cddl +1 -0
- data/test-data/sipos.cddl +8 -0
- data/test-data/star-edited.cddl +98 -0
- data/test-data/star.cddl +95 -0
- data/test-data/test-gen.cddl +3 -0
- data/test-data/time.cddl +11 -0
- data/test-data/valemb.cddl +16 -0
- data/test-data/yangid.cddl +1 -0
- data/test-data/yaron1.cddl +95 -0
- metadata +148 -14
data/lib/cddl.rb
CHANGED
|
@@ -2,9 +2,15 @@ require 'abnc'
|
|
|
2
2
|
require 'pp'
|
|
3
3
|
require 'pathname'
|
|
4
4
|
require 'cbor-pure' unless defined?(CBOR::Tagged)
|
|
5
|
+
require 'half'
|
|
6
|
+
require 'cbor-deterministic'
|
|
5
7
|
require 'regexp-examples'
|
|
8
|
+
require 'abnftt'
|
|
6
9
|
require 'colorize'
|
|
7
10
|
require 'base64'
|
|
11
|
+
require 'base32'
|
|
12
|
+
require 'base45_lite'
|
|
13
|
+
require 'scanf'
|
|
8
14
|
|
|
9
15
|
module CDDL
|
|
10
16
|
|
|
@@ -21,6 +27,21 @@ module CDDL
|
|
|
21
27
|
|
|
22
28
|
class Parser
|
|
23
29
|
|
|
30
|
+
FEATURE_REJECT_RE = /\A\^/
|
|
31
|
+
# CDDL_FEATURE_OK=cbor,^json
|
|
32
|
+
CDDL_FEATURE_OK, CDDL_FEATURE_REJECT =
|
|
33
|
+
if ok = ENV["CDDL_FEATURE_OK"]
|
|
34
|
+
ok.split(/,\s*/)
|
|
35
|
+
.partition{|s| s[0] !~ FEATURE_REJECT_RE}
|
|
36
|
+
.map {|l| Hash[l.map {|feature|
|
|
37
|
+
[feature.sub(FEATURE_REJECT_RE, ''),
|
|
38
|
+
true]}]}
|
|
39
|
+
else
|
|
40
|
+
[{}, {}]
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
CDDL_UNUSED_OK = ENV["CDDL_UNUSED_OK"]
|
|
44
|
+
|
|
24
45
|
class BackTrack < Exception; end
|
|
25
46
|
|
|
26
47
|
def initialize(source_text)
|
|
@@ -41,7 +62,7 @@ module CDDL
|
|
|
41
62
|
if upto - presult < 100
|
|
42
63
|
part2 = source_text[presult...upto]
|
|
43
64
|
else
|
|
44
|
-
part2 = source_text[presult, 50] + "......." + source_text[upto-50, 50]
|
|
65
|
+
part2 = source_text[presult, 50] + "......." + (source_text[upto-50, 50] || "")
|
|
45
66
|
end
|
|
46
67
|
warn "*** Look for syntax problems around the #{
|
|
47
68
|
"%%%".colorize(background: :light_yellow)} markers:\n#{
|
|
@@ -55,6 +76,8 @@ module CDDL
|
|
|
55
76
|
@ast = @abnf.ast?
|
|
56
77
|
# our little argument stack for rule processing
|
|
57
78
|
@insides = []
|
|
79
|
+
# collect error information
|
|
80
|
+
@last_message = ""
|
|
58
81
|
end
|
|
59
82
|
|
|
60
83
|
def apr # for debugging
|
|
@@ -96,6 +119,16 @@ module CDDL
|
|
|
96
119
|
r.compact
|
|
97
120
|
end
|
|
98
121
|
|
|
122
|
+
def longest_initial_match(old, now)
|
|
123
|
+
md = /\A(.*)(.*)\n\1(.*)\z/.match([old,now].join("\n"))
|
|
124
|
+
md[1..3]
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
def diff_message(old, now)
|
|
128
|
+
c, l, r = longest_initial_match(old, now)
|
|
129
|
+
"-- common: >#{c}< -- old: >#{l}< -- new: >#{r}<"
|
|
130
|
+
end
|
|
131
|
+
|
|
99
132
|
def cname(s)
|
|
100
133
|
s.to_s.gsub(/-/, "_")
|
|
101
134
|
end
|
|
@@ -127,7 +160,7 @@ module CDDL
|
|
|
127
160
|
if subtree[0] == :type1 && subtree[1..-1].all? {|x| x[0] == :int}
|
|
128
161
|
if enumname = subtree.cbor_annotations rescue nil
|
|
129
162
|
enumname = cname(enumname.first)
|
|
130
|
-
subtree[1..-1].each do |x|
|
|
163
|
+
subtree[1..-1].each do |x|
|
|
131
164
|
if memname = x.cbor_annotations
|
|
132
165
|
memname = "#{enumname}_#{cname(memname.first)}"
|
|
133
166
|
add.(memname, x[1].to_s)
|
|
@@ -182,7 +215,8 @@ module CDDL
|
|
|
182
215
|
ids = g.children(:id).map(&:to_s)
|
|
183
216
|
# puts ["ids", ids].inspect
|
|
184
217
|
if b = @generics[n]
|
|
185
|
-
fail "Duplicate generics definition #{n}
|
|
218
|
+
fail "Duplicate generics definition #{n} #{
|
|
219
|
+
diff_message(strip_nodes(b[0]).inspect, strip_nodes(rule_ast).inspect)}"
|
|
186
220
|
end
|
|
187
221
|
@generics[n] = [rule_ast, ids]
|
|
188
222
|
else
|
|
@@ -194,7 +228,7 @@ module CDDL
|
|
|
194
228
|
if a == b
|
|
195
229
|
warn "*** Warning: Identical redefinition of #{n} as #{a}"
|
|
196
230
|
else
|
|
197
|
-
fail "Duplicate rule definition #{n}
|
|
231
|
+
fail "Duplicate rule definition #{n} #{diff_message(b, a)}"
|
|
198
232
|
end
|
|
199
233
|
end
|
|
200
234
|
@rules[n] = rule_ast
|
|
@@ -226,7 +260,7 @@ module CDDL
|
|
|
226
260
|
r_process("used_in_cddl_prelude", @rules["used_in_cddl_prelude"])
|
|
227
261
|
@rules.each do |n, r|
|
|
228
262
|
# r_process(n, r) # debug only loop
|
|
229
|
-
warn "*** Unused rule #{n}" unless @stage1[n]
|
|
263
|
+
warn "*** Unused rule #{n}" unless @stage1[n] || CDDL_UNUSED_OK
|
|
230
264
|
end
|
|
231
265
|
if result[0] == :grpent
|
|
232
266
|
warn "Group at top -- first rule must be a type!"
|
|
@@ -243,12 +277,49 @@ module CDDL
|
|
|
243
277
|
[rule[0], *rule[1]]
|
|
244
278
|
end
|
|
245
279
|
|
|
280
|
+
def remove_indentation(s)
|
|
281
|
+
l = s.lines
|
|
282
|
+
indent = l.grep(/\S/).map {|l| l[/^\s*/].size}.min
|
|
283
|
+
l.map {|l| l.sub(/^ {0,#{indent}}/, "")}.join
|
|
284
|
+
end
|
|
285
|
+
|
|
286
|
+
def unpack_array_to_sequence(content, where)
|
|
287
|
+
# remove the first head
|
|
288
|
+
n = case content.getbyte(0) - (4 << 5)
|
|
289
|
+
when 0..23; 1
|
|
290
|
+
when 24; 2
|
|
291
|
+
when 25; 3
|
|
292
|
+
when 26; 5
|
|
293
|
+
when 27; 9 # unlikely :-)
|
|
294
|
+
else fail ".cborseq sequence for #{where} not an array"
|
|
295
|
+
end
|
|
296
|
+
content[0...n] = ''
|
|
297
|
+
content
|
|
298
|
+
end
|
|
299
|
+
|
|
300
|
+
|
|
246
301
|
# Memoize a bit here
|
|
247
302
|
|
|
248
303
|
REGEXP_FOR_STRING = Hash.new {|h, k|
|
|
249
|
-
h[k] = Regexp.new("\\A
|
|
304
|
+
h[k] = Regexp.new("\\A(?:#{k})\\z")
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
ABNF_PARSER_FOR_STRING = Hash.new {|h, k|
|
|
308
|
+
grammar = "cddl-t0p--1eve1-f0r--abnf = " << k # XXX
|
|
309
|
+
h[k] = ABNF.from_abnf(grammar)
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
ABNF_ENCODING_FOR_CONOP = {
|
|
313
|
+
abnf: Encoding::UTF_8,
|
|
314
|
+
abnfb: Encoding::BINARY
|
|
250
315
|
}
|
|
251
316
|
|
|
317
|
+
def myfrand(exp)
|
|
318
|
+
exprange = 1 << exp
|
|
319
|
+
expoffset= exprange >> 1
|
|
320
|
+
(rand(2)*2-1) * rand() * 2.0**(rand(exprange)-expoffset)
|
|
321
|
+
end
|
|
322
|
+
|
|
252
323
|
def generate
|
|
253
324
|
@recursion = 0
|
|
254
325
|
generate1(rules)
|
|
@@ -329,8 +400,12 @@ module CDDL
|
|
|
329
400
|
unless kr
|
|
330
401
|
case vr[0]
|
|
331
402
|
when :grpent
|
|
332
|
-
fail "grpent in map #{vr.inspect}" unless vr.size == 2
|
|
333
|
-
g = Array.new(st) {
|
|
403
|
+
# fail "grpent in map #{vr.inspect}" unless vr.size == 2
|
|
404
|
+
g = Array.new(st) {
|
|
405
|
+
vr[1..-1].map{ |vrx|
|
|
406
|
+
generate1(vrx, true)
|
|
407
|
+
}.flatten(1)
|
|
408
|
+
}.flatten(1)
|
|
334
409
|
# warn "GGG #{g.inspect}"
|
|
335
410
|
return g
|
|
336
411
|
when :grpchoice
|
|
@@ -367,9 +442,17 @@ module CDDL
|
|
|
367
442
|
when 3
|
|
368
443
|
gen_word
|
|
369
444
|
when 6
|
|
370
|
-
|
|
445
|
+
tn = Integer === where[2] ? where[2] : generate1(where[2])
|
|
446
|
+
unless Integer === tn && tn >= 0
|
|
447
|
+
fail "Can't generate a tag number out of #{where[2]}"
|
|
448
|
+
end
|
|
449
|
+
CBOR::Tagged.new(tn, generate1(where[3]))
|
|
371
450
|
when 7
|
|
372
|
-
|
|
451
|
+
w2 = where[2]
|
|
452
|
+
if Array === w2
|
|
453
|
+
w2 = generate1(w2)
|
|
454
|
+
end
|
|
455
|
+
case w2
|
|
373
456
|
when nil
|
|
374
457
|
Math::PI
|
|
375
458
|
when 20
|
|
@@ -378,10 +461,22 @@ module CDDL
|
|
|
378
461
|
true
|
|
379
462
|
when 22
|
|
380
463
|
nil
|
|
381
|
-
when 23
|
|
382
|
-
|
|
383
|
-
when 25
|
|
384
|
-
|
|
464
|
+
when 0..19, 23, 32..255
|
|
465
|
+
CBOR::Simple.new(w2)
|
|
466
|
+
when 25
|
|
467
|
+
while !(hs = Half.encode_from_single_bytes([myfrand(5)].pack("g")))
|
|
468
|
+
end
|
|
469
|
+
Half.decode(hs)
|
|
470
|
+
when 26
|
|
471
|
+
while (a = [myfrand(8)].pack("g").unpack("g").first).to_cbor.size != 5
|
|
472
|
+
end
|
|
473
|
+
a
|
|
474
|
+
when 27
|
|
475
|
+
while (a = myfrand(11)).to_cbor.size != 9
|
|
476
|
+
end
|
|
477
|
+
a
|
|
478
|
+
else
|
|
479
|
+
fail "Can't generate prim #7.#{where[2].inspect}" # XXX retry array generate
|
|
385
480
|
end
|
|
386
481
|
else
|
|
387
482
|
fail "Can't generate prim #{where[1]}"
|
|
@@ -389,7 +484,7 @@ module CDDL
|
|
|
389
484
|
when :anno
|
|
390
485
|
target = where[2]
|
|
391
486
|
control = where[3]
|
|
392
|
-
case where[1]
|
|
487
|
+
case conop = where[1]
|
|
393
488
|
when :size
|
|
394
489
|
should_be_int = generate1(control)
|
|
395
490
|
unless (Array === target && target[0] == :prim && [0, 2, 3].include?(target[1])) && Integer === should_be_int && should_be_int >= 0
|
|
@@ -435,6 +530,40 @@ module CDDL
|
|
|
435
530
|
$default_warned = true
|
|
436
531
|
end
|
|
437
532
|
generate1(target, inmap)
|
|
533
|
+
when :feature
|
|
534
|
+
feature, = extract_feature(control, nil)
|
|
535
|
+
# warn "@@@ GENFEAT #{feature.inspect} #{CDDL_FEATURE_REJECT[feature].inspect}"
|
|
536
|
+
if CDDL_FEATURE_REJECT[feature]
|
|
537
|
+
fail BackTrack.new("Feature '#{feature}' rejected")
|
|
538
|
+
end
|
|
539
|
+
generate1(target, inmap)
|
|
540
|
+
when :cat, :det
|
|
541
|
+
lhs = generate1(target, inmap)
|
|
542
|
+
rhs = generate1(control)
|
|
543
|
+
if conop == :det
|
|
544
|
+
lhs = remove_indentation(lhs)
|
|
545
|
+
rhs = remove_indentation(rhs)
|
|
546
|
+
end
|
|
547
|
+
begin
|
|
548
|
+
lhs + rhs
|
|
549
|
+
rescue Exception => e
|
|
550
|
+
fail "Can't #{lhs.inspect} .cat #{rhs.inspect}: #{e.message}"
|
|
551
|
+
end
|
|
552
|
+
when :plus
|
|
553
|
+
lhs = generate1(target, inmap)
|
|
554
|
+
rhs = generate1(control)
|
|
555
|
+
begin
|
|
556
|
+
case lhs
|
|
557
|
+
when Integer
|
|
558
|
+
lhs + Integer(rhs)
|
|
559
|
+
when Numeric
|
|
560
|
+
lhs + rhs
|
|
561
|
+
else
|
|
562
|
+
fail "#{lhs.inspect}: Not a number"
|
|
563
|
+
end
|
|
564
|
+
rescue Exception => e
|
|
565
|
+
fail "Can't #{lhs.inspect} .plus #{rhs.inspect}: #{e.message}"
|
|
566
|
+
end
|
|
438
567
|
when :eq
|
|
439
568
|
content = generate1(control)
|
|
440
569
|
if validate1(content, where)
|
|
@@ -448,7 +577,7 @@ module CDDL
|
|
|
448
577
|
content = Integer(content)
|
|
449
578
|
case target[1]
|
|
450
579
|
when 0
|
|
451
|
-
case
|
|
580
|
+
case conop
|
|
452
581
|
when :lt
|
|
453
582
|
rand(0...content)
|
|
454
583
|
when :le
|
|
@@ -462,8 +591,7 @@ module CDDL
|
|
|
462
591
|
warn "HUH gen #{where.inspect} #{try.inspect}" unless try.nil?
|
|
463
592
|
end
|
|
464
593
|
end
|
|
465
|
-
|
|
466
|
-
content = generate1(target)
|
|
594
|
+
try_generate(target) do |content|
|
|
467
595
|
if validate1(content, where)
|
|
468
596
|
return content
|
|
469
597
|
end
|
|
@@ -475,30 +603,117 @@ module CDDL
|
|
|
475
603
|
fail "Don't know yet how to generate #{where}"
|
|
476
604
|
end
|
|
477
605
|
REGEXP_FOR_STRING[regexp].random_example(max_repeater_variance: 5)
|
|
478
|
-
when :
|
|
606
|
+
when :abnf, :abnfb
|
|
607
|
+
grammar = generate1(control)
|
|
608
|
+
bytes = true if target == [:prim, 2]
|
|
609
|
+
bytes = false if target == [:prim, 3]
|
|
610
|
+
unless !bytes.nil? && String === grammar
|
|
611
|
+
fail "Don't know yet how to generate #{where}"
|
|
612
|
+
end
|
|
613
|
+
grammar << "\n" unless grammar =~ /\n\z/
|
|
614
|
+
out = ABNF_PARSER_FOR_STRING[grammar].generate
|
|
615
|
+
if conop == :abnfb
|
|
616
|
+
out = out.codepoints.pack("C*")
|
|
617
|
+
end
|
|
618
|
+
enc = bytes ? Encoding::BINARY : Encoding::UTF_8
|
|
619
|
+
out.force_encoding(enc)
|
|
620
|
+
when :cbor, :cborseq, :cbordet, :cborseqdet
|
|
479
621
|
unless target == [:prim, 2]
|
|
480
622
|
fail "Don't know yet how to generate #{where}"
|
|
481
623
|
end
|
|
482
|
-
|
|
483
|
-
if
|
|
624
|
+
input = generate1(control)
|
|
625
|
+
if conop == :cbordet || conop == :cborseqdet
|
|
626
|
+
input = input.cbor_prepare_deterministic
|
|
627
|
+
end
|
|
628
|
+
content = CBOR::encode(input)
|
|
629
|
+
if conop == :cborseq || conop == :cborseqdet
|
|
484
630
|
# remove the first head
|
|
485
|
-
|
|
486
|
-
when 0..23; 1
|
|
487
|
-
when 24; 2
|
|
488
|
-
when 25; 3
|
|
489
|
-
when 26; 5
|
|
490
|
-
when 27; 9 # unlikely :-)
|
|
491
|
-
else fail "Generated .cborseq sequence for #{where} not an array"
|
|
492
|
-
end
|
|
493
|
-
content[0...n] = ''
|
|
631
|
+
content = unpack_array_to_sequence(content, where)
|
|
494
632
|
end
|
|
495
633
|
content
|
|
634
|
+
when :json
|
|
635
|
+
unless target == [:prim, 3]
|
|
636
|
+
fail "Don't know yet how to generate #{where}"
|
|
637
|
+
end
|
|
638
|
+
content = JSON::dump(generate1(control))
|
|
639
|
+
content
|
|
640
|
+
when :decimal, :base10
|
|
641
|
+
if conop == :decimal
|
|
642
|
+
unless @decimal_warned
|
|
643
|
+
warn "** .decimal control operator is now called .base10"
|
|
644
|
+
@decimal_warned = true
|
|
645
|
+
end
|
|
646
|
+
end
|
|
647
|
+
unless target == [:prim, 3]
|
|
648
|
+
fail "Don't know yet how to generate #{where}"
|
|
649
|
+
end
|
|
650
|
+
content = Integer(generate1(control)).to_s
|
|
651
|
+
content
|
|
652
|
+
when :join
|
|
653
|
+
try_generate(control) do |content|
|
|
654
|
+
if Array === content &&
|
|
655
|
+
content.all? {|x| String === x} &&
|
|
656
|
+
Set[content.map {|x| x.encoding}].size == 1
|
|
657
|
+
content = content.join
|
|
658
|
+
if validate1(content, target)
|
|
659
|
+
return content
|
|
660
|
+
end
|
|
661
|
+
end
|
|
662
|
+
end
|
|
663
|
+
fail "Don't know yet how to generate #{where}"
|
|
664
|
+
when :b64u, :"b64u-sloppy", :b64c, :"b64c-sloppy",
|
|
665
|
+
:b45, :b32, :h32, :hex, :hexlc, :hexuc
|
|
666
|
+
try_generate(control) do |content|
|
|
667
|
+
if String === content
|
|
668
|
+
content = case conop
|
|
669
|
+
when :b64u, :"b64u-sloppy"
|
|
670
|
+
Base64.urlsafe_encode64(content, padding: false)
|
|
671
|
+
when :b64c, :"b64c-sloppy"
|
|
672
|
+
Base64.strict_encode64(content)
|
|
673
|
+
when :b45
|
|
674
|
+
Base45Lite.encode(content)
|
|
675
|
+
when :b32
|
|
676
|
+
Base32.table = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"
|
|
677
|
+
Base32.encode(content).gsub("=", "")
|
|
678
|
+
when :h32
|
|
679
|
+
Base32.table = "0123456789ABCDEFGHIJKLMNOPQRSTUV"
|
|
680
|
+
Base32.encode(content).gsub("=", "")
|
|
681
|
+
when :hex, :hexuc
|
|
682
|
+
content.unpack("H*")[0].upcase
|
|
683
|
+
when :hexlc
|
|
684
|
+
content.unpack("H*")[0]
|
|
685
|
+
else fail "Cannot happen"
|
|
686
|
+
end
|
|
687
|
+
if validate1(content, target)
|
|
688
|
+
return content
|
|
689
|
+
end
|
|
690
|
+
end
|
|
691
|
+
end
|
|
692
|
+
fail "Not smart enough to generate #{where}"
|
|
693
|
+
when :printf
|
|
694
|
+
try_generate(control) do |content|
|
|
695
|
+
if Array === content && content.size >= 1
|
|
696
|
+
fmt, *data = content
|
|
697
|
+
if String === fmt
|
|
698
|
+
begin
|
|
699
|
+
content = fmt % data
|
|
700
|
+
if validate1(content, target)
|
|
701
|
+
return content
|
|
702
|
+
end
|
|
703
|
+
rescue ArgumentError => e
|
|
704
|
+
# be verbose about mismatches here
|
|
705
|
+
@last_message << "\n** #{fmt.inspect} ArgumentError #{e}"
|
|
706
|
+
end
|
|
707
|
+
end
|
|
708
|
+
end
|
|
709
|
+
end
|
|
710
|
+
fail "Not smart enough to generate #{where}#{@last_message}"
|
|
496
711
|
when :within, :and
|
|
497
|
-
|
|
498
|
-
|
|
712
|
+
try_generate(target) do |content|
|
|
713
|
+
$features ||= Hash.new {|h, k| h[k] = {}}
|
|
499
714
|
if validate1(content, control)
|
|
500
715
|
return content
|
|
501
|
-
elsif
|
|
716
|
+
elsif conop == :within
|
|
502
717
|
warn "*** #{content.inspect} meets #{target.inspect} but not #{control.inspect}"
|
|
503
718
|
end
|
|
504
719
|
end
|
|
@@ -523,22 +738,102 @@ module CDDL
|
|
|
523
738
|
end
|
|
524
739
|
end
|
|
525
740
|
|
|
526
|
-
|
|
741
|
+
def try_generate(target)
|
|
742
|
+
32.times do
|
|
743
|
+
content = generate1(target)
|
|
744
|
+
yield content # should return if success
|
|
745
|
+
end
|
|
746
|
+
end
|
|
747
|
+
|
|
748
|
+
VALUE_TYPE = {text: String, bytes: String, int: Integer, float: Float}
|
|
527
749
|
SIMPLE_VALUE = {
|
|
528
750
|
[:prim, 7, 20] => [true, false, :bool],
|
|
529
751
|
[:prim, 7, 21] => [true, true, :bool],
|
|
530
752
|
[:prim, 7, 22] => [true, nil, :nil],
|
|
531
|
-
[:prim, 7, 23] => [true, :undefined, :undefined],
|
|
532
753
|
}
|
|
754
|
+
SIMPLE_VALUE_SIMPLE = Set[23] + (0..19) + (32..255)
|
|
533
755
|
|
|
534
756
|
def extract_value(t) # []
|
|
535
757
|
if vt = VALUE_TYPE[t[0]]
|
|
536
758
|
[true, t[1], vt]
|
|
537
|
-
elsif
|
|
538
|
-
|
|
759
|
+
elsif t[0] == :prim && t[1] == 7
|
|
760
|
+
case t2 = t[2]
|
|
761
|
+
when Integer
|
|
762
|
+
when Array
|
|
763
|
+
a, b, c = extract_value(t2)
|
|
764
|
+
if a && c == Integer
|
|
765
|
+
t2 = b
|
|
766
|
+
end
|
|
767
|
+
end
|
|
768
|
+
if v = SIMPLE_VALUE[[:prim, 7, t2]]
|
|
769
|
+
v
|
|
770
|
+
elsif SIMPLE_VALUE_SIMPLE === t2
|
|
771
|
+
[true, CBOR::Simple.new(t2), :simple]
|
|
772
|
+
end
|
|
773
|
+
elsif t[0] == :anno
|
|
774
|
+
_, conop, target, control = t
|
|
775
|
+
warn ["EXV0", conop, target, control].inspect if ENV["CDDL_TRACE"]
|
|
776
|
+
if conop == :cat || conop == :plus || conop == :det
|
|
777
|
+
ok1, v1, vt1 = extract_value(target)
|
|
778
|
+
ok2, v2, vt2 = extract_value(control)
|
|
779
|
+
# warn ["EXV", ok1, v1, vt1, ok2, v2, vt2].inspect
|
|
780
|
+
if ok1 && ok2
|
|
781
|
+
if vt1 == Integer
|
|
782
|
+
[true, v1 + Integer(v2), Integer] if vt2 == Integer || vt2 == Float
|
|
783
|
+
elsif vt1 == Float
|
|
784
|
+
[true, v1 + v2, vt1] if vt2 == Integer || vt2 == Float
|
|
785
|
+
else
|
|
786
|
+
if conop == :det
|
|
787
|
+
v1 = remove_indentation(v1)
|
|
788
|
+
v2 = remove_indentation(v2)
|
|
789
|
+
end
|
|
790
|
+
[true, v1 + v2, vt1] if vt1 == vt2
|
|
791
|
+
end
|
|
792
|
+
end rescue nil
|
|
793
|
+
end
|
|
794
|
+
end || [false]
|
|
795
|
+
end
|
|
796
|
+
|
|
797
|
+
def extract_array(t)
|
|
798
|
+
return [false] unless t[0] == :array
|
|
799
|
+
[true, *t[1..-1].map { |el|
|
|
800
|
+
return [false] unless el[0..3] == [:member, 1, 1, nil]
|
|
801
|
+
ok, v, vt = extract_value(el[4])
|
|
802
|
+
return [false] unless ok
|
|
803
|
+
[v, vt]
|
|
804
|
+
}]
|
|
805
|
+
end
|
|
806
|
+
|
|
807
|
+
|
|
808
|
+
def extract_arg0(t)
|
|
809
|
+
return [false] unless t[0] == :array
|
|
810
|
+
[true,
|
|
811
|
+
(el = t[1]
|
|
812
|
+
return [false] unless el[0..3] == [:member, 1, 1, nil]
|
|
813
|
+
ok, v, vt = extract_value(el[4])
|
|
814
|
+
return [false] unless ok
|
|
815
|
+
[v, vt]
|
|
816
|
+
),
|
|
817
|
+
*t[2..-1]]
|
|
818
|
+
end
|
|
819
|
+
|
|
820
|
+
def extract_feature(control, d)
|
|
821
|
+
ok, v, vt = extract_value(control)
|
|
822
|
+
if ok
|
|
823
|
+
nm = v
|
|
824
|
+
det = d
|
|
825
|
+
warn "*** feature controller should be a string: #{control.inspect}" unless String == vt
|
|
539
826
|
else
|
|
540
|
-
|
|
827
|
+
ok, *v = extract_array(control)
|
|
828
|
+
if ok && v.size == 2
|
|
829
|
+
nm = v[0][0]
|
|
830
|
+
det = v[1][0]
|
|
831
|
+
warn "*** first element of feature controller should be a string: #{control.inspect}" unless String === nm
|
|
832
|
+
else
|
|
833
|
+
warn "*** feature controller not implemented: #{control.inspect}"
|
|
834
|
+
end
|
|
541
835
|
end
|
|
836
|
+
[nm, det]
|
|
542
837
|
end
|
|
543
838
|
|
|
544
839
|
def validate_diag
|
|
@@ -547,11 +842,19 @@ module CDDL
|
|
|
547
842
|
|
|
548
843
|
def validate(d, warn=true)
|
|
549
844
|
@recursion = 0
|
|
845
|
+
$features = Hash.new {|h, k| h[k] = {}}
|
|
550
846
|
result = validate1a(d, rules)
|
|
551
|
-
|
|
552
|
-
if
|
|
847
|
+
if warn
|
|
848
|
+
if result
|
|
849
|
+
if $features != {}
|
|
850
|
+
features = $features.reject {|k, v| CDDL_FEATURE_OK[k.to_s] }
|
|
851
|
+
# warn "@@@ FEAT #{CDDL_FEATURE_OK.inspect} #{CDDL_FEATURE_REJECT.inspect}"
|
|
852
|
+
warn "** Features potentially used (#$fn): #{features.map {|k, v| "#{k}: #{v.keys}"}.join(", ")}" if features != {}
|
|
853
|
+
end
|
|
854
|
+
else
|
|
553
855
|
warn "CDDL validation failure (#{result.inspect} for #{d.inspect}):"
|
|
554
856
|
PP::pp(validate_diag, STDERR)
|
|
857
|
+
puts(validate_diag.cbor_diagnostic)
|
|
555
858
|
end
|
|
556
859
|
end
|
|
557
860
|
result
|
|
@@ -559,7 +862,7 @@ module CDDL
|
|
|
559
862
|
|
|
560
863
|
def validate_result(check)
|
|
561
864
|
check || (
|
|
562
|
-
@last_message
|
|
865
|
+
@last_message << yield
|
|
563
866
|
false
|
|
564
867
|
)
|
|
565
868
|
end
|
|
@@ -592,7 +895,9 @@ module CDDL
|
|
|
592
895
|
ann.concat(ann2)
|
|
593
896
|
end
|
|
594
897
|
if occ < s
|
|
595
|
-
|
|
898
|
+
# warn "*** lme #{@last_message.encoding} #{@last_message}"
|
|
899
|
+
# warn "*** #{"\noccur #{occ} < #{s}, not reached at #{i} in array #{d} for #{where}".encoding}"
|
|
900
|
+
@last_message << "\noccur #{occ} < #{s}, not reached at #{i} in array #{d} for #{where}"
|
|
596
901
|
return [false, ann]
|
|
597
902
|
end
|
|
598
903
|
end
|
|
@@ -681,13 +986,17 @@ module CDDL
|
|
|
681
986
|
puts "COMPLEX: #{k.inspect} #{simple.inspect} #{simpleval.inspect}" if ENV["CDDL_TRACE"]
|
|
682
987
|
keys = d_check.keys
|
|
683
988
|
ta, keys = keys.partition{ |key| validate1(key, k)}
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
989
|
+
count = 0
|
|
990
|
+
catch :enough do
|
|
991
|
+
ta.all? { |val|
|
|
992
|
+
if (ann2 = validate1a(d[val], v)) && # XXX check cut or not!
|
|
993
|
+
d_check.delete(val) {:not_found} != :not_found
|
|
994
|
+
anno.concat(ann2)
|
|
995
|
+
throw :enough, true if (count += 1) == e
|
|
996
|
+
true
|
|
997
|
+
end
|
|
998
|
+
}
|
|
999
|
+
end and validate_result(count >= s) { "not enough #{ta.inspect} for #{r.inspect}" }
|
|
691
1000
|
end
|
|
692
1001
|
end
|
|
693
1002
|
else
|
|
@@ -696,6 +1005,19 @@ module CDDL
|
|
|
696
1005
|
}
|
|
697
1006
|
end
|
|
698
1007
|
|
|
1008
|
+
def validate1a_ignore_encoding(d, where)
|
|
1009
|
+
if String === d
|
|
1010
|
+
validate1a(d.force_encoding(Encoding::BINARY), where) or (
|
|
1011
|
+
text = d.force_encoding(Encoding::UTF_8).scrub {
|
|
1012
|
+
fail "can't use bytes as text"
|
|
1013
|
+
} rescue :NOT_A_TEXT_STRING
|
|
1014
|
+
validate1a(text, where)
|
|
1015
|
+
)
|
|
1016
|
+
else
|
|
1017
|
+
validate1a(d, where)
|
|
1018
|
+
end
|
|
1019
|
+
end
|
|
1020
|
+
|
|
699
1021
|
def validate1a(d, where)
|
|
700
1022
|
if ann = validate1(d, where)
|
|
701
1023
|
here = [d, where]
|
|
@@ -708,6 +1030,8 @@ module CDDL
|
|
|
708
1030
|
end
|
|
709
1031
|
|
|
710
1032
|
OPERATORS = {lt: :<, le: :<=, gt: :>, ge: :>=, eq: :==, ne: :!=}
|
|
1033
|
+
OPERATORS_MATCH = {eq: true, ne: false}
|
|
1034
|
+
FLOAT_AI_FROM_SIZE = {3 => 25, 5 => 26, 9 => 27}
|
|
711
1035
|
|
|
712
1036
|
def validate1(d, where)
|
|
713
1037
|
if ENV["CDDL_TRACE"]
|
|
@@ -718,6 +1042,9 @@ module CDDL
|
|
|
718
1042
|
@last_data = d
|
|
719
1043
|
@last_rule = where
|
|
720
1044
|
ann = nil
|
|
1045
|
+
if CBOR::Tagged === d && d.tag === 888 && ENV["CDDL_888"]
|
|
1046
|
+
return []
|
|
1047
|
+
end
|
|
721
1048
|
case where[0]
|
|
722
1049
|
when :type1
|
|
723
1050
|
if where[1..-1].any? {|r| ann = validate1a(d, r)}
|
|
@@ -741,16 +1068,55 @@ module CDDL
|
|
|
741
1068
|
idx, ann = validate_forward(d, 0, where)
|
|
742
1069
|
ann if validate_result(idx == d.size) { "#{validate_diag.inspect} -- cannot complete (#{idx}, #{d.size}) array #{d} for #{where}" }
|
|
743
1070
|
end
|
|
744
|
-
when :
|
|
1071
|
+
when :int, :float
|
|
745
1072
|
_, v = extract_value(where)
|
|
746
1073
|
[] if d == v
|
|
1074
|
+
when :text, :bytes
|
|
1075
|
+
_, v = extract_value(where)
|
|
1076
|
+
[] if d == v && ((d.encoding == Encoding::BINARY) == (v.encoding == Encoding::BINARY))
|
|
747
1077
|
when :range
|
|
748
1078
|
[] if where[2] === d && where[1].include?(d)
|
|
749
1079
|
when :anno
|
|
750
|
-
target = where
|
|
751
|
-
if
|
|
752
|
-
|
|
753
|
-
|
|
1080
|
+
_, conop, target, control = where
|
|
1081
|
+
if conop == :cat || conop == :plus || conop == :det
|
|
1082
|
+
ok1, v1, vt1 = extract_value(target)
|
|
1083
|
+
ok2, v2, vt2 = extract_value(control)
|
|
1084
|
+
warn ["ANNO0", ok1, v1, vt1, ok2, v2, vt2, d].inspect if ENV["CDDL_TRACE"]
|
|
1085
|
+
if ok1 && ok2
|
|
1086
|
+
v2 = Integer(v2) if vt1 == Integer
|
|
1087
|
+
if conop == :det
|
|
1088
|
+
v1 = remove_indentation(v1)
|
|
1089
|
+
v2 = remove_indentation(v2)
|
|
1090
|
+
end
|
|
1091
|
+
# warn ["ANNO", ok1, v1, vt1, ok2, v2, vt2, d].inspect
|
|
1092
|
+
[] if d == v1 + v2 # XXX Focus ArgumentError
|
|
1093
|
+
elsif conop == :cat && String === d
|
|
1094
|
+
warn ["CAT-L", ok1, v1, vt1, ok2, v2, vt2, d].inspect if ENV["CDDL_TRACE"]
|
|
1095
|
+
if ok1 && vt1 == String
|
|
1096
|
+
# d and lhs (v1) need to agree in encoding
|
|
1097
|
+
if d.encoding == v1.encoding
|
|
1098
|
+
if d[0...v1.length] == v1
|
|
1099
|
+
d2 = d[v1.length..-1]
|
|
1100
|
+
warn ["CAT-L1", d2, d2.encoding, control].inspect if ENV["CDDL_TRACE"]
|
|
1101
|
+
validate1a_ignore_encoding(d2, control)
|
|
1102
|
+
end
|
|
1103
|
+
end
|
|
1104
|
+
elsif ok2 && vt2 == String
|
|
1105
|
+
warn ["CAT-R", ok1, v1, vt1, ok2, v2, vt2, d].inspect if ENV["CDDL_TRACE"]
|
|
1106
|
+
if d[-v2.length..-1] == v2
|
|
1107
|
+
d1 = d[0...-v2.length]
|
|
1108
|
+
validate1a(d1, control)
|
|
1109
|
+
end
|
|
1110
|
+
end
|
|
1111
|
+
elsif conop == :plus && Integer === d
|
|
1112
|
+
if ok1 && vt1 == Integer
|
|
1113
|
+
validate1a(d - Integer(v1), control)
|
|
1114
|
+
elsif ok2 && vt2 == Integer
|
|
1115
|
+
validate1a(d - Integer(v2), target)
|
|
1116
|
+
end
|
|
1117
|
+
end
|
|
1118
|
+
elsif ann = validate1a(d, target)
|
|
1119
|
+
case conop
|
|
754
1120
|
when :size
|
|
755
1121
|
case d
|
|
756
1122
|
when Integer
|
|
@@ -789,11 +1155,20 @@ module CDDL
|
|
|
789
1155
|
$default_warned = true
|
|
790
1156
|
end
|
|
791
1157
|
ann
|
|
1158
|
+
when :feature
|
|
1159
|
+
nm, det = extract_feature(control, d)
|
|
1160
|
+
$features[nm][det] = true
|
|
1161
|
+
ann if !CDDL_FEATURE_REJECT[nm]
|
|
792
1162
|
when :lt, :le, :gt, :ge, :eq, :ne
|
|
793
|
-
op = OPERATORS[
|
|
1163
|
+
op = OPERATORS[conop]
|
|
794
1164
|
ok, v, _vt = extract_value(control)
|
|
795
1165
|
if ok
|
|
796
1166
|
ann if d.send(op, v) rescue nil # XXX Focus ArgumentError
|
|
1167
|
+
else
|
|
1168
|
+
needs_to_match = OPERATORS_MATCH[conop]
|
|
1169
|
+
unless needs_to_match.nil?
|
|
1170
|
+
ann if !!validate1(d, control) == needs_to_match
|
|
1171
|
+
end
|
|
797
1172
|
end
|
|
798
1173
|
when :regexp
|
|
799
1174
|
ann if (
|
|
@@ -806,10 +1181,181 @@ module CDDL
|
|
|
806
1181
|
end
|
|
807
1182
|
end
|
|
808
1183
|
)
|
|
1184
|
+
when :abnf, :abnfb
|
|
1185
|
+
ann if (
|
|
1186
|
+
if String === d
|
|
1187
|
+
ok, v, vt = extract_value(control)
|
|
1188
|
+
if ok && vt == String
|
|
1189
|
+
begin
|
|
1190
|
+
ABNF_PARSER_FOR_STRING[v].validate(
|
|
1191
|
+
d.dup.force_encoding(ABNF_ENCODING_FOR_CONOP[conop]).codepoints.pack("U*")
|
|
1192
|
+
)
|
|
1193
|
+
true
|
|
1194
|
+
rescue => e
|
|
1195
|
+
# warn "*** #{e}" # XXX
|
|
1196
|
+
@last_message = e.to_s.force_encoding(Encoding::UTF_8)
|
|
1197
|
+
nil
|
|
1198
|
+
end
|
|
1199
|
+
end
|
|
1200
|
+
end
|
|
1201
|
+
)
|
|
809
1202
|
when :cbor
|
|
810
1203
|
ann if validate1((CBOR::decode(d) rescue :BAD_CBOR), control)
|
|
811
1204
|
when :cborseq
|
|
812
1205
|
ann if validate1((CBOR::decode("\x9f".b << d << "\xff".b) rescue :BAD_CBOR), control)
|
|
1206
|
+
when :cbordet
|
|
1207
|
+
decoded = CBOR::decode(d) rescue :BAD_CBOR
|
|
1208
|
+
if d != decoded.to_deterministic_cbor
|
|
1209
|
+
@last_message = "CBOR #{d.inspect} not deterministically encoded"
|
|
1210
|
+
nil
|
|
1211
|
+
else
|
|
1212
|
+
ann if validate1(decoded, control)
|
|
1213
|
+
end
|
|
1214
|
+
when :cborseqdet
|
|
1215
|
+
decoded = CBOR::decode("\x9f".b << d << "\xff".b) rescue :BAD_CBOR
|
|
1216
|
+
if d != unpack_array_to_sequence(decoded.to_deterministic_cbor, d.inspect)
|
|
1217
|
+
@last_message = "CBOR Sequence #{d.inspect} not deterministically encoded"
|
|
1218
|
+
nil
|
|
1219
|
+
else
|
|
1220
|
+
ann if validate1(decoded, control)
|
|
1221
|
+
end
|
|
1222
|
+
when :json
|
|
1223
|
+
ann if validate1((JSON::load(d) rescue :BAD_JSON), control)
|
|
1224
|
+
when :decimal, :base10
|
|
1225
|
+
if conop == :decimal
|
|
1226
|
+
unless @decimal_warned
|
|
1227
|
+
warn "** .decimal control operator is now called .base10"
|
|
1228
|
+
@decimal_warned = true
|
|
1229
|
+
end
|
|
1230
|
+
end
|
|
1231
|
+
|
|
1232
|
+
ann if (
|
|
1233
|
+
if /\A0|-?[1-9][0-9]*\z/ === d
|
|
1234
|
+
validate1((d.to_i rescue :BAD_JSON), control)
|
|
1235
|
+
end
|
|
1236
|
+
)
|
|
1237
|
+
when :join
|
|
1238
|
+
t = control
|
|
1239
|
+
v = if t[0] == :array
|
|
1240
|
+
t[1..-1].map { |el|
|
|
1241
|
+
if el[0..2] == [:member, 1, 1]
|
|
1242
|
+
ok, v, vt = extract_value(el[4])
|
|
1243
|
+
if ok
|
|
1244
|
+
[true, v, vt]
|
|
1245
|
+
else
|
|
1246
|
+
[false, el[4]]
|
|
1247
|
+
end
|
|
1248
|
+
end
|
|
1249
|
+
}
|
|
1250
|
+
end
|
|
1251
|
+
warn "@@@JOIN@@@ #{v.inspect}" if ENV["CDDL_TRACE"]
|
|
1252
|
+
ok = true
|
|
1253
|
+
if v
|
|
1254
|
+
ix = 0
|
|
1255
|
+
rest = d.dup
|
|
1256
|
+
while ix < v.length
|
|
1257
|
+
if left = v[ix]
|
|
1258
|
+
if left[0] # match constant value first
|
|
1259
|
+
fail "Not a string for #{left.inspect} in #{where}" unless String == left[2]
|
|
1260
|
+
want = left[1]
|
|
1261
|
+
have = rest[0...left[1].length]
|
|
1262
|
+
if want == have
|
|
1263
|
+
rest[0...left[1].length] = ''
|
|
1264
|
+
ix += 1
|
|
1265
|
+
next
|
|
1266
|
+
else
|
|
1267
|
+
fail ".join: want #{want.inspect}, have #{have.inspect}"
|
|
1268
|
+
end
|
|
1269
|
+
else
|
|
1270
|
+
ix += 1
|
|
1271
|
+
if ix == v.length # match remaining
|
|
1272
|
+
warn "@@@JOIN ok in #{ok.inspect} rest #{rest.inspect}" if ENV["CDDL_TRACE"]
|
|
1273
|
+
ok &&= validate1(rest, left[1])
|
|
1274
|
+
warn "@@@JOIN ok out #{ok.inspect}" if ENV["CDDL_TRACE"]
|
|
1275
|
+
# more diag
|
|
1276
|
+
rest = ''
|
|
1277
|
+
next
|
|
1278
|
+
else
|
|
1279
|
+
if mid = v[ix]
|
|
1280
|
+
if mid[0] # have constant value to split over
|
|
1281
|
+
fail "Not a string for #{mid} in #{where}" unless String == mid[2]
|
|
1282
|
+
rest1, rest2 = rest.split(mid[1], 2)
|
|
1283
|
+
if rest2
|
|
1284
|
+
warn "@@@JOIN ok in #{ok.inspect} rest1 #{rest1.inspect}" if ENV["CDDL_TRACE"]
|
|
1285
|
+
ok &&= validate1(rest1, left[1])
|
|
1286
|
+
warn "@@@JOIN ok out #{ok.inspect}" if ENV["CDDL_TRACE"]
|
|
1287
|
+
rest = rest2
|
|
1288
|
+
ix += 1
|
|
1289
|
+
next
|
|
1290
|
+
else
|
|
1291
|
+
fail "Can't find #{mid[1].inspect} in #{rest.inspect}"
|
|
1292
|
+
end
|
|
1293
|
+
else
|
|
1294
|
+
fail "Cannot validate consecutive non-constant members of .join in #{where}"
|
|
1295
|
+
end
|
|
1296
|
+
else
|
|
1297
|
+
fail "Cannot handle .join over #{t[ix+1]} in #{where}"
|
|
1298
|
+
end
|
|
1299
|
+
end
|
|
1300
|
+
end
|
|
1301
|
+
else
|
|
1302
|
+
fail "Cannot handle .join over #{t[ix+1]} in #{where}"
|
|
1303
|
+
end
|
|
1304
|
+
end
|
|
1305
|
+
fail "Can't match #{rest.inspect} for .join in #{where}" if rest != ''
|
|
1306
|
+
ann if ok
|
|
1307
|
+
else
|
|
1308
|
+
fail "Don't know yet how to validate against #{where}"
|
|
1309
|
+
end
|
|
1310
|
+
when :b64u, :"b64u-sloppy", :b64c, :"b64c-sloppy", :b45, :b32, :h32, :hex, :hexlc, :hexuc
|
|
1311
|
+
ann if (
|
|
1312
|
+
String === d && (
|
|
1313
|
+
decoded = case conop
|
|
1314
|
+
when :b64u
|
|
1315
|
+
/[+\/=]/ !~ d &&
|
|
1316
|
+
Base64.urlsafe_decode64(d)
|
|
1317
|
+
when :"b64u-sloppy"
|
|
1318
|
+
/[-_=]/ !~ d &&
|
|
1319
|
+
Base64.decode64(d.tr("+/", "-_"))
|
|
1320
|
+
when :b64c
|
|
1321
|
+
Base64.strict_decode64(d)
|
|
1322
|
+
when :"b64c-sloppy"
|
|
1323
|
+
Base64.decode64(d)
|
|
1324
|
+
when :b32
|
|
1325
|
+
/=/ !~ d &&
|
|
1326
|
+
(Base32.table = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567") &&
|
|
1327
|
+
Base32.decode(d)
|
|
1328
|
+
when :b45
|
|
1329
|
+
Base45Lite.decode(d)
|
|
1330
|
+
when :h32
|
|
1331
|
+
/=/ !~ d &&
|
|
1332
|
+
(Base32.table = "0123456789ABCDEFGHIJKLMNOPQRSTUV") &&
|
|
1333
|
+
Base32.decode(d)
|
|
1334
|
+
when :hex
|
|
1335
|
+
/\A[0-9a-fA-F]*\z/ =~ d && [d].pack("H*")
|
|
1336
|
+
when :hexuc
|
|
1337
|
+
/\A[0-9A-F]*\z/ =~ d && [d].pack("H*")
|
|
1338
|
+
when :hexlc
|
|
1339
|
+
/\A[0-9a-f]*\z/ =~ d && [d].pack("H*")
|
|
1340
|
+
else fail "Cannot happen"
|
|
1341
|
+
end
|
|
1342
|
+
) && validate1(decoded.b, control)
|
|
1343
|
+
)
|
|
1344
|
+
when :printf
|
|
1345
|
+
ann if String === d && (
|
|
1346
|
+
ok, fmt, *v = extract_arg0(control)
|
|
1347
|
+
if ok && String == fmt[1]
|
|
1348
|
+
fmt = fmt[0]
|
|
1349
|
+
# warn "** ok #{ok.inspect} fmt #{fmt.inspect} v #{v.inspect}"
|
|
1350
|
+
decoded = d.scanf(fmt) # this is a bit too lenient, so let's do:
|
|
1351
|
+
encode_again = fmt % decoded
|
|
1352
|
+
if encode_again != d
|
|
1353
|
+
warn "** fmt #{fmt.inspect} d #{d.inspect} decoded #{decoded.inspect} encode_again #{encode_again.inspect}"
|
|
1354
|
+
else
|
|
1355
|
+
validate1(decoded, [:array, *v])
|
|
1356
|
+
end
|
|
1357
|
+
end
|
|
1358
|
+
)
|
|
813
1359
|
when :within
|
|
814
1360
|
if validate1(d, control)
|
|
815
1361
|
ann
|
|
@@ -837,20 +1383,43 @@ module CDDL
|
|
|
837
1383
|
when 3
|
|
838
1384
|
String === d && d.encoding != Encoding::BINARY # cheat
|
|
839
1385
|
when 6
|
|
840
|
-
|
|
1386
|
+
if Integer === d
|
|
1387
|
+
t = 2 # assuming only 2/3 match an Integer
|
|
1388
|
+
if d < 0
|
|
1389
|
+
d = ~d
|
|
1390
|
+
t = 3
|
|
1391
|
+
end
|
|
1392
|
+
d = CBOR::Tagged.new(t, d == 0 ? "".b : d.digits(256).reverse!.pack("C*"))
|
|
1393
|
+
end
|
|
1394
|
+
CBOR::Tagged === d && (
|
|
1395
|
+
Integer === where[2] ? d.tag == where[2] : validate1a(d.tag, where[2])
|
|
1396
|
+
) && validate1a(d.data, where[3])
|
|
841
1397
|
when 7
|
|
842
1398
|
t, v = extract_value(where)
|
|
843
1399
|
if t
|
|
844
1400
|
v.eql? d
|
|
845
1401
|
else
|
|
846
|
-
case where[2]
|
|
1402
|
+
case w2 = where[2]
|
|
847
1403
|
when nil
|
|
848
|
-
|
|
849
|
-
|
|
1404
|
+
Float === d || CBOR::Simple === d || [false, true, nil].include?(d)
|
|
1405
|
+
when Array
|
|
1406
|
+
headnum = case d
|
|
1407
|
+
when Float
|
|
1408
|
+
FLOAT_AI_FROM_SIZE[d.to_cbor.size]
|
|
1409
|
+
when false
|
|
1410
|
+
20
|
|
1411
|
+
when true
|
|
1412
|
+
21
|
|
1413
|
+
when nil
|
|
1414
|
+
22
|
|
1415
|
+
when CBOR::Simple
|
|
1416
|
+
d.value
|
|
1417
|
+
end
|
|
1418
|
+
validate1a(headnum, w2)
|
|
850
1419
|
when 25, 26, 27
|
|
851
|
-
Float === d
|
|
1420
|
+
Float === d && FLOAT_AI_FROM_SIZE[d.to_cbor.size] == w2
|
|
852
1421
|
else
|
|
853
|
-
fail
|
|
1422
|
+
fail [:val7, d, where].inspect
|
|
854
1423
|
end
|
|
855
1424
|
end
|
|
856
1425
|
else
|
|
@@ -900,6 +1469,10 @@ module CDDL
|
|
|
900
1469
|
else
|
|
901
1470
|
[:type1]
|
|
902
1471
|
end
|
|
1472
|
+
elsif s = ENV["CDDL_INVENT"]
|
|
1473
|
+
s = "_" if s == ""
|
|
1474
|
+
r = [:type1, [:text, "#{s}-#{name}"]]
|
|
1475
|
+
return r
|
|
903
1476
|
end
|
|
904
1477
|
end
|
|
905
1478
|
if r
|
|
@@ -945,29 +1518,69 @@ module CDDL
|
|
|
945
1518
|
end
|
|
946
1519
|
end
|
|
947
1520
|
|
|
1521
|
+
STRING_ESCAPES = {
|
|
1522
|
+
"\"" => "\"",
|
|
1523
|
+
"/" => "/",
|
|
1524
|
+
"\\" => "\\",
|
|
1525
|
+
"'" => "'",
|
|
1526
|
+
"b" => "\b",
|
|
1527
|
+
"f" => "\f",
|
|
1528
|
+
"n" => "\n",
|
|
1529
|
+
"r" => "\r",
|
|
1530
|
+
"t" => "\t",
|
|
1531
|
+
}
|
|
1532
|
+
|
|
948
1533
|
def value(n)
|
|
949
1534
|
# cheat:
|
|
950
1535
|
# warn n
|
|
951
1536
|
s = n.to_s
|
|
952
1537
|
if s[-1] == "'"
|
|
953
|
-
parts = s.split("'",
|
|
954
|
-
if parts[
|
|
955
|
-
warn "***
|
|
1538
|
+
bsqual, *parts = s.split("'", -1)
|
|
1539
|
+
if parts[-1] != ""
|
|
1540
|
+
warn "*** Problem decoding byte string #{s.inspect}"
|
|
956
1541
|
end
|
|
1542
|
+
bsval = parts[0...-1].join("'").gsub(/\\u([Dd][89AaBb][0-9a-zA-Z]{2})\\u([Dd][CcDdEeFf][0-9a-zA-Z]{2})|\\u([0-9a-zA-Z]{4})|\\u\{([0-9a-zA-Z]+)\}|\r?(\n)|\\([^u])/) {
|
|
1543
|
+
if hex = $3 || $4
|
|
1544
|
+
hex.to_i(16).chr(Encoding::UTF_8)
|
|
1545
|
+
elsif lf = $5
|
|
1546
|
+
lf
|
|
1547
|
+
elsif escaped = $6
|
|
1548
|
+
STRING_ESCAPES[$6] or (
|
|
1549
|
+
fail "Invalid String Escape #{escaped.inspect} in #{s.inspect}"
|
|
1550
|
+
)
|
|
1551
|
+
else
|
|
1552
|
+
((($1.to_i(16) & 0x3ff) << 10) +
|
|
1553
|
+
($2.to_i(16) & 0x3ff) + 0x10000).chr(Encoding::UTF_8)
|
|
1554
|
+
end
|
|
1555
|
+
}
|
|
957
1556
|
[:bytes,
|
|
958
|
-
case
|
|
1557
|
+
case bsqual
|
|
959
1558
|
when ""
|
|
960
|
-
|
|
1559
|
+
bsval.b
|
|
961
1560
|
when "h"
|
|
962
|
-
|
|
1561
|
+
bsval.gsub(/\s/, "").chars.each_slice(2).map{ |x| Integer(x.join, 16).chr("BINARY") }.join.b
|
|
963
1562
|
when "b64"
|
|
964
|
-
Base64.urlsafe_decode64(
|
|
1563
|
+
Base64.urlsafe_decode64(bsval)
|
|
965
1564
|
else
|
|
966
|
-
warn "*** Can't handle byte string type #{
|
|
1565
|
+
warn "*** Can't handle byte string type #{bsqual.inspect} yet"
|
|
967
1566
|
end
|
|
968
1567
|
]
|
|
969
1568
|
else
|
|
970
|
-
|
|
1569
|
+
if s[-1] == '"'
|
|
1570
|
+
s.gsub!(/\\u([Dd][89AaBb][0-9a-zA-Z]{2})\\u([Dd][CcDdEeFf][0-9a-zA-Z]{2})|\\([^u]|u[0-9a-zA-Z]{4})/) {
|
|
1571
|
+
if $3
|
|
1572
|
+
"\\#$3" # skip this, use eval parser
|
|
1573
|
+
else
|
|
1574
|
+
((($1.to_i(16) & 0x3ff) << 10) +
|
|
1575
|
+
($2.to_i(16) & 0x3ff) + 0x10000).chr(Encoding::UTF_8)
|
|
1576
|
+
end
|
|
1577
|
+
}
|
|
1578
|
+
end
|
|
1579
|
+
if s =~ /p.*\d\z/ # hexfloat
|
|
1580
|
+
val = s.scanf("%a").first
|
|
1581
|
+
else
|
|
1582
|
+
val = eval(s)
|
|
1583
|
+
end
|
|
971
1584
|
# warn val
|
|
972
1585
|
case val
|
|
973
1586
|
when Integer; [:int, val]
|
|
@@ -1073,9 +1686,13 @@ module CDDL
|
|
|
1073
1686
|
def g_process(name, g, genericargs)
|
|
1074
1687
|
r, ids = g
|
|
1075
1688
|
args = genericargs.children(:type1).map {|x| type1(x, true)}
|
|
1689
|
+
# warn "** args #{args.inspect}"
|
|
1076
1690
|
fail "number of args #{name} #{ids.size} #{args.size}" if ids.size != args.size
|
|
1077
1691
|
bindings = Hash[ids.zip(args)]
|
|
1078
|
-
|
|
1692
|
+
# warn "** bindings: #{bindings.inspect}"
|
|
1693
|
+
genname = "#{name}<#{args.inspect}>" # XXX this works up to a RECURSE...
|
|
1694
|
+
# warn "** genname #{genname}"
|
|
1695
|
+
r_process(genname, r, bindings)
|
|
1079
1696
|
end
|
|
1080
1697
|
|
|
1081
1698
|
def type_recall(name, canbegroup, genericargs)
|
|
@@ -1142,7 +1759,7 @@ module CDDL
|
|
|
1142
1759
|
end
|
|
1143
1760
|
when :recurse_grpent # XXX we don't have the entry yet
|
|
1144
1761
|
when :member
|
|
1145
|
-
fail "map entry without member key given: #{member}" unless member[3] || member[4][0] == :grpent || member[4][0] == :grpchoice
|
|
1762
|
+
fail "map entry #{member.inspect} without member key given: #{member}" unless member[3] || member[4][0] == :grpent || member[4][0] == :grpchoice
|
|
1146
1763
|
else
|
|
1147
1764
|
fail ["type1 member", member].inspect unless member[0] == :member
|
|
1148
1765
|
end
|
|
@@ -1151,8 +1768,16 @@ module CDDL
|
|
|
1151
1768
|
|
|
1152
1769
|
BRACE = {"{" => :map, "[" => :array}
|
|
1153
1770
|
RANGE_EXCLUDE_END = {".." => false, "..." => true}
|
|
1154
|
-
SUPPORTED_ANNOTATIONS = [:bits, :size, :regexp,
|
|
1155
|
-
:
|
|
1771
|
+
SUPPORTED_ANNOTATIONS = [:bits, :size, :regexp,
|
|
1772
|
+
:cbor, :cborseq, :cbordet, :cborseqdet,
|
|
1773
|
+
:within, :and,
|
|
1774
|
+
:default, :lt, :le, :gt, :ge, :eq, :ne,
|
|
1775
|
+
:feature, :abnf, :abnfb, :det, :cat, :plus,
|
|
1776
|
+
:json, :decimal, :base10, :join,
|
|
1777
|
+
:b64u, :"b64u-sloppy", :b64c, :"b64c-sloppy",
|
|
1778
|
+
:b45, :b32, :h32, :hex, :hexlc, :hexuc,
|
|
1779
|
+
:printf,
|
|
1780
|
+
]
|
|
1156
1781
|
|
|
1157
1782
|
def type1(n, canbegroup = false)
|
|
1158
1783
|
# puts "NVALUE #{n.value.inspect}"
|
|
@@ -1184,6 +1809,13 @@ module CDDL
|
|
|
1184
1809
|
when /\A#(\d+)/
|
|
1185
1810
|
maj = $1.to_i
|
|
1186
1811
|
s = [:prim, maj, *n.children(:uint).map(&:to_s).map(&:to_i)]
|
|
1812
|
+
if tn = n.headnumber
|
|
1813
|
+
if ui = tn.uint
|
|
1814
|
+
s << ui.to_s.to_i
|
|
1815
|
+
elsif tt = tn.type
|
|
1816
|
+
s << type(tt)
|
|
1817
|
+
end
|
|
1818
|
+
end
|
|
1187
1819
|
if tagged_type = n.type
|
|
1188
1820
|
s << type(tagged_type)
|
|
1189
1821
|
end
|
|
@@ -1214,6 +1846,26 @@ module CDDL
|
|
|
1214
1846
|
v
|
|
1215
1847
|
}
|
|
1216
1848
|
]
|
|
1849
|
+
when /\A~/
|
|
1850
|
+
if tn = n.typename
|
|
1851
|
+
s = type_recall(tn.to_s, false, n.genericarg).flatten(1)
|
|
1852
|
+
else
|
|
1853
|
+
fail "No typename in unwrap #{n}"
|
|
1854
|
+
end
|
|
1855
|
+
if s[0] != :type1
|
|
1856
|
+
fail [:UNWRAPs0, s].inspect
|
|
1857
|
+
end
|
|
1858
|
+
case s[1]
|
|
1859
|
+
when :map, :array
|
|
1860
|
+
[:grpent, s[2..-1]]
|
|
1861
|
+
when :prim
|
|
1862
|
+
if s[2] != 6
|
|
1863
|
+
fail [:UNWRAPs2, s].inspect
|
|
1864
|
+
end
|
|
1865
|
+
s[4] # check :type1?
|
|
1866
|
+
else
|
|
1867
|
+
fail [:UNWRAPs1, s].inspect
|
|
1868
|
+
end
|
|
1217
1869
|
else
|
|
1218
1870
|
"unimplemented #{n}"
|
|
1219
1871
|
end
|