cddl 0.8.8 → 0.10.3
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 +35 -15
- data/cddl.gemspec +5 -2
- data/data/cddl.abnf +2 -1
- data/lib/base45_lite.rb +71 -0
- data/lib/cbor-pp-play.rb +1 -0
- data/lib/cddl.rb +406 -50
- 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.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 +2 -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.cddl +1 -0
- data/test-data/decimal2.cddl +1 -0
- data/test-data/det1.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/json2.cddl +1 -0
- data/test-data/jsoniodef.cddl +719 -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/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/yangid.cddl +1 -0
- data/test-data/yaron1.cddl +95 -0
- metadata +100 -8
data/lib/cddl.rb
CHANGED
|
@@ -2,9 +2,13 @@ require 'abnc'
|
|
|
2
2
|
require 'pp'
|
|
3
3
|
require 'pathname'
|
|
4
4
|
require 'cbor-pure' unless defined?(CBOR::Tagged)
|
|
5
|
+
require 'cbor-deterministic'
|
|
5
6
|
require 'regexp-examples'
|
|
7
|
+
require 'abnftt'
|
|
6
8
|
require 'colorize'
|
|
7
9
|
require 'base64'
|
|
10
|
+
require 'base32'
|
|
11
|
+
require 'base45_lite'
|
|
8
12
|
|
|
9
13
|
module CDDL
|
|
10
14
|
|
|
@@ -21,6 +25,20 @@ module CDDL
|
|
|
21
25
|
|
|
22
26
|
class Parser
|
|
23
27
|
|
|
28
|
+
FEATURE_REJECT_RE = /\A\^/
|
|
29
|
+
# CDDL_FEATURE_OK=cbor,^json
|
|
30
|
+
CDDL_FEATURE_OK, CDDL_FEATURE_REJECT =
|
|
31
|
+
if ok = ENV["CDDL_FEATURE_OK"]
|
|
32
|
+
ok.split(/,\s*/)
|
|
33
|
+
.partition{|s| s[0] !~ FEATURE_REJECT_RE}
|
|
34
|
+
.map {|l| Hash[l.map {|feature|
|
|
35
|
+
[feature.sub(FEATURE_REJECT_RE, ''),
|
|
36
|
+
true]}]}
|
|
37
|
+
else
|
|
38
|
+
[{}, {}]
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
|
|
24
42
|
class BackTrack < Exception; end
|
|
25
43
|
|
|
26
44
|
def initialize(source_text)
|
|
@@ -55,6 +73,8 @@ module CDDL
|
|
|
55
73
|
@ast = @abnf.ast?
|
|
56
74
|
# our little argument stack for rule processing
|
|
57
75
|
@insides = []
|
|
76
|
+
# collect error information
|
|
77
|
+
@last_message = ""
|
|
58
78
|
end
|
|
59
79
|
|
|
60
80
|
def apr # for debugging
|
|
@@ -127,7 +147,7 @@ module CDDL
|
|
|
127
147
|
if subtree[0] == :type1 && subtree[1..-1].all? {|x| x[0] == :int}
|
|
128
148
|
if enumname = subtree.cbor_annotations rescue nil
|
|
129
149
|
enumname = cname(enumname.first)
|
|
130
|
-
subtree[1..-1].each do |x|
|
|
150
|
+
subtree[1..-1].each do |x|
|
|
131
151
|
if memname = x.cbor_annotations
|
|
132
152
|
memname = "#{enumname}_#{cname(memname.first)}"
|
|
133
153
|
add.(memname, x[1].to_s)
|
|
@@ -243,10 +263,41 @@ module CDDL
|
|
|
243
263
|
[rule[0], *rule[1]]
|
|
244
264
|
end
|
|
245
265
|
|
|
266
|
+
def remove_indentation(s)
|
|
267
|
+
l = s.lines
|
|
268
|
+
indent = l.grep(/\S/).map {|l| l[/^\s*/].size}.min
|
|
269
|
+
l.map {|l| l.sub(/^ {0,#{indent}}/, "")}.join
|
|
270
|
+
end
|
|
271
|
+
|
|
272
|
+
def unpack_array_to_sequence(content, where)
|
|
273
|
+
# remove the first head
|
|
274
|
+
n = case content.getbyte(0) - (4 << 5)
|
|
275
|
+
when 0..23; 1
|
|
276
|
+
when 24; 2
|
|
277
|
+
when 25; 3
|
|
278
|
+
when 26; 5
|
|
279
|
+
when 27; 9 # unlikely :-)
|
|
280
|
+
else fail ".cborseq sequence for #{where} not an array"
|
|
281
|
+
end
|
|
282
|
+
content[0...n] = ''
|
|
283
|
+
content
|
|
284
|
+
end
|
|
285
|
+
|
|
286
|
+
|
|
246
287
|
# Memoize a bit here
|
|
247
288
|
|
|
248
289
|
REGEXP_FOR_STRING = Hash.new {|h, k|
|
|
249
|
-
h[k] = Regexp.new("\\A
|
|
290
|
+
h[k] = Regexp.new("\\A(?:#{k})\\z")
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
ABNF_PARSER_FOR_STRING = Hash.new {|h, k|
|
|
294
|
+
grammar = "cddl-t0p--1eve1-f0r--abnf = " << k # XXX
|
|
295
|
+
h[k] = ABNF.from_abnf(grammar)
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
ABNF_ENCODING_FOR_CONOP = {
|
|
299
|
+
abnf: Encoding::UTF_8,
|
|
300
|
+
abnfb: Encoding::BINARY
|
|
250
301
|
}
|
|
251
302
|
|
|
252
303
|
def generate
|
|
@@ -329,8 +380,12 @@ module CDDL
|
|
|
329
380
|
unless kr
|
|
330
381
|
case vr[0]
|
|
331
382
|
when :grpent
|
|
332
|
-
fail "grpent in map #{vr.inspect}" unless vr.size == 2
|
|
333
|
-
g = Array.new(st) {
|
|
383
|
+
# fail "grpent in map #{vr.inspect}" unless vr.size == 2
|
|
384
|
+
g = Array.new(st) {
|
|
385
|
+
vr[1..-1].map{ |vrx|
|
|
386
|
+
generate1(vrx, true)
|
|
387
|
+
}.flatten(1)
|
|
388
|
+
}.flatten(1)
|
|
334
389
|
# warn "GGG #{g.inspect}"
|
|
335
390
|
return g
|
|
336
391
|
when :grpchoice
|
|
@@ -389,7 +444,7 @@ module CDDL
|
|
|
389
444
|
when :anno
|
|
390
445
|
target = where[2]
|
|
391
446
|
control = where[3]
|
|
392
|
-
case where[1]
|
|
447
|
+
case conop = where[1]
|
|
393
448
|
when :size
|
|
394
449
|
should_be_int = generate1(control)
|
|
395
450
|
unless (Array === target && target[0] == :prim && [0, 2, 3].include?(target[1])) && Integer === should_be_int && should_be_int >= 0
|
|
@@ -435,6 +490,40 @@ module CDDL
|
|
|
435
490
|
$default_warned = true
|
|
436
491
|
end
|
|
437
492
|
generate1(target, inmap)
|
|
493
|
+
when :feature
|
|
494
|
+
feature, = extract_feature(control, nil)
|
|
495
|
+
# warn "@@@ GENFEAT #{feature.inspect} #{CDDL_FEATURE_REJECT[feature].inspect}"
|
|
496
|
+
if CDDL_FEATURE_REJECT[feature]
|
|
497
|
+
fail BackTrack.new("Feature '#{feature}' rejected")
|
|
498
|
+
end
|
|
499
|
+
generate1(target, inmap)
|
|
500
|
+
when :cat, :det
|
|
501
|
+
lhs = generate1(target, inmap)
|
|
502
|
+
rhs = generate1(control)
|
|
503
|
+
if conop == :det
|
|
504
|
+
lhs = remove_indentation(lhs)
|
|
505
|
+
rhs = remove_indentation(rhs)
|
|
506
|
+
end
|
|
507
|
+
begin
|
|
508
|
+
lhs + rhs
|
|
509
|
+
rescue Exception => e
|
|
510
|
+
fail "Can't #{lhs.inspect} .cat #{rhs.inspect}: #{e.message}"
|
|
511
|
+
end
|
|
512
|
+
when :plus
|
|
513
|
+
lhs = generate1(target, inmap)
|
|
514
|
+
rhs = generate1(control)
|
|
515
|
+
begin
|
|
516
|
+
case lhs
|
|
517
|
+
when Integer
|
|
518
|
+
lhs + Integer(rhs)
|
|
519
|
+
when Numeric
|
|
520
|
+
lhs + rhs
|
|
521
|
+
else
|
|
522
|
+
fail "#{lhs.inspect}: Not a number"
|
|
523
|
+
end
|
|
524
|
+
rescue Exception => e
|
|
525
|
+
fail "Can't #{lhs.inspect} .plus #{rhs.inspect}: #{e.message}"
|
|
526
|
+
end
|
|
438
527
|
when :eq
|
|
439
528
|
content = generate1(control)
|
|
440
529
|
if validate1(content, where)
|
|
@@ -448,7 +537,7 @@ module CDDL
|
|
|
448
537
|
content = Integer(content)
|
|
449
538
|
case target[1]
|
|
450
539
|
when 0
|
|
451
|
-
case
|
|
540
|
+
case conop
|
|
452
541
|
when :lt
|
|
453
542
|
rand(0...content)
|
|
454
543
|
when :le
|
|
@@ -475,30 +564,88 @@ module CDDL
|
|
|
475
564
|
fail "Don't know yet how to generate #{where}"
|
|
476
565
|
end
|
|
477
566
|
REGEXP_FOR_STRING[regexp].random_example(max_repeater_variance: 5)
|
|
478
|
-
when :
|
|
567
|
+
when :abnf, :abnfb
|
|
568
|
+
grammar = generate1(control)
|
|
569
|
+
bytes = true if target == [:prim, 2]
|
|
570
|
+
bytes = false if target == [:prim, 3]
|
|
571
|
+
unless !bytes.nil? && String === grammar
|
|
572
|
+
fail "Don't know yet how to generate #{where}"
|
|
573
|
+
end
|
|
574
|
+
grammar << "\n" unless grammar =~ /\n\z/
|
|
575
|
+
out = ABNF_PARSER_FOR_STRING[grammar].generate
|
|
576
|
+
if conop == :abnfb
|
|
577
|
+
out = out.codepoints.pack("C*")
|
|
578
|
+
end
|
|
579
|
+
enc = bytes ? Encoding::BINARY : Encoding::UTF_8
|
|
580
|
+
out.force_encoding(enc)
|
|
581
|
+
when :cbor, :cborseq, :cbordet, :cborseqdet
|
|
479
582
|
unless target == [:prim, 2]
|
|
480
583
|
fail "Don't know yet how to generate #{where}"
|
|
481
584
|
end
|
|
482
|
-
|
|
483
|
-
if
|
|
585
|
+
input = generate1(control)
|
|
586
|
+
if conop == :cbordet || conop == :cborseqdet
|
|
587
|
+
input = input.cbor_prepare_deterministic
|
|
588
|
+
end
|
|
589
|
+
content = CBOR::encode(input)
|
|
590
|
+
if conop == :cborseq || conop == :cborseqdet
|
|
484
591
|
# remove the first head
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
else fail "Generated .cborseq sequence for #{where} not an array"
|
|
492
|
-
end
|
|
493
|
-
content[0...n] = ''
|
|
592
|
+
content = unpack_array_to_sequence(content, where)
|
|
593
|
+
end
|
|
594
|
+
content
|
|
595
|
+
when :json
|
|
596
|
+
unless target == [:prim, 3]
|
|
597
|
+
fail "Don't know yet how to generate #{where}"
|
|
494
598
|
end
|
|
599
|
+
content = JSON::dump(generate1(control))
|
|
600
|
+
content
|
|
601
|
+
when :decimal
|
|
602
|
+
unless target == [:prim, 3]
|
|
603
|
+
fail "Don't know yet how to generate #{where}"
|
|
604
|
+
end
|
|
605
|
+
content = Integer(generate1(control)).to_s
|
|
606
|
+
content
|
|
607
|
+
when :join
|
|
608
|
+
content = generate1(control)
|
|
609
|
+
unless Array === content &&
|
|
610
|
+
content.all? {|x| String === x &&
|
|
611
|
+
((target == [:prim, 2] && x.encoding == Encoding::BINARY) ||
|
|
612
|
+
(target == [:prim, 3] && x.encoding != Encoding::BINARY))}
|
|
613
|
+
fail "Don't know yet how to generate #{where}"
|
|
614
|
+
end
|
|
615
|
+
content = content.join
|
|
616
|
+
content
|
|
617
|
+
when :b64u, :"b64u-sloppy", :b64c, :"b64c-sloppy",
|
|
618
|
+
:b45, :b32, :h32, :hex, :hexlc, :hexuc
|
|
619
|
+
content = generate1(control)
|
|
620
|
+
unless String === content
|
|
621
|
+
fail "Don't know yet how to generate #{where}"
|
|
622
|
+
end
|
|
623
|
+
content = case conop
|
|
624
|
+
when :b64u, :"b64u-sloppy"
|
|
625
|
+
Base64.urlsafe_encode64(content, padding: false)
|
|
626
|
+
when :b64c, :"b64c-sloppy"
|
|
627
|
+
Base64.strict_encode64(content)
|
|
628
|
+
when :b45
|
|
629
|
+
Base45Lite.encode(content)
|
|
630
|
+
when :b32
|
|
631
|
+
Base32.table = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"
|
|
632
|
+
Base32.encode(content).gsub("=", "")
|
|
633
|
+
when :h32
|
|
634
|
+
Base32.table = "0123456789ABCDEFGHIJKLMNOPQRSTUV"
|
|
635
|
+
Base32.encode(content).gsub("=", "")
|
|
636
|
+
when :hex, :hexuc
|
|
637
|
+
content.unpack("H*")[0].upcase
|
|
638
|
+
when :hexlc
|
|
639
|
+
content.unpack("H*")[0]
|
|
640
|
+
else fail "Cannot happen"
|
|
641
|
+
end
|
|
495
642
|
content
|
|
496
643
|
when :within, :and
|
|
497
644
|
32.times do
|
|
498
645
|
content = generate1(target)
|
|
499
646
|
if validate1(content, control)
|
|
500
647
|
return content
|
|
501
|
-
elsif
|
|
648
|
+
elsif conop == :within
|
|
502
649
|
warn "*** #{content.inspect} meets #{target.inspect} but not #{control.inspect}"
|
|
503
650
|
end
|
|
504
651
|
end
|
|
@@ -523,7 +670,7 @@ module CDDL
|
|
|
523
670
|
end
|
|
524
671
|
end
|
|
525
672
|
|
|
526
|
-
VALUE_TYPE = {text: String, int: Integer, float: Float}
|
|
673
|
+
VALUE_TYPE = {text: String, bytes: String, int: Integer, float: Float}
|
|
527
674
|
SIMPLE_VALUE = {
|
|
528
675
|
[:prim, 7, 20] => [true, false, :bool],
|
|
529
676
|
[:prim, 7, 21] => [true, true, :bool],
|
|
@@ -536,9 +683,57 @@ module CDDL
|
|
|
536
683
|
[true, t[1], vt]
|
|
537
684
|
elsif v = SIMPLE_VALUE[t]
|
|
538
685
|
v
|
|
686
|
+
elsif t[0] == :anno
|
|
687
|
+
_, conop, target, control = t
|
|
688
|
+
# warn ["EXV0", conop, target, control].inspect
|
|
689
|
+
if conop == :cat || conop == :plus || conop == :det
|
|
690
|
+
ok1, v1, vt1 = extract_value(target)
|
|
691
|
+
ok2, v2, vt2 = extract_value(control)
|
|
692
|
+
# warn ["EXV", ok1, v1, vt1, ok2, v2, vt2].inspect
|
|
693
|
+
if ok1 && ok2
|
|
694
|
+
if vt1 == Integer
|
|
695
|
+
[true, v1 + Integer(v2), Integer] if vt2 == Integer || vt2 == Float
|
|
696
|
+
elsif vt1 == Float
|
|
697
|
+
[true, v1 + v2, vt1] if vt2 == Integer || vt2 == Float
|
|
698
|
+
else
|
|
699
|
+
if conop == :det
|
|
700
|
+
v1 = remove_indentation(v1)
|
|
701
|
+
v2 = remove_indentation(v2)
|
|
702
|
+
end
|
|
703
|
+
[true, v1 + v2, vt1] if vt1 == vt2
|
|
704
|
+
end
|
|
705
|
+
end rescue nil
|
|
706
|
+
end
|
|
707
|
+
end || [false]
|
|
708
|
+
end
|
|
709
|
+
|
|
710
|
+
def extract_array(t)
|
|
711
|
+
return [false] unless t[0] == :array
|
|
712
|
+
[true, *t[1..-1].map { |el|
|
|
713
|
+
return [false] unless el[0..3] == [:member, 1, 1, nil]
|
|
714
|
+
ok, v, vt = extract_value(el[4])
|
|
715
|
+
return [false] unless ok
|
|
716
|
+
[v, vt]
|
|
717
|
+
}]
|
|
718
|
+
end
|
|
719
|
+
|
|
720
|
+
def extract_feature(control, d)
|
|
721
|
+
ok, v, vt = extract_value(control)
|
|
722
|
+
if ok
|
|
723
|
+
nm = v
|
|
724
|
+
det = d
|
|
725
|
+
warn "*** feature controller should be a string: #{control.inspect}" unless String == vt
|
|
539
726
|
else
|
|
540
|
-
|
|
727
|
+
ok, *v = extract_array(control)
|
|
728
|
+
if ok && v.size == 2
|
|
729
|
+
nm = v[0][0]
|
|
730
|
+
det = v[1][0]
|
|
731
|
+
warn "*** first element of feature controller should be a string: #{control.inspect}" unless String === nm
|
|
732
|
+
else
|
|
733
|
+
warn "*** feature controller not implemented: #{control.inspect}"
|
|
734
|
+
end
|
|
541
735
|
end
|
|
736
|
+
[nm, det]
|
|
542
737
|
end
|
|
543
738
|
|
|
544
739
|
def validate_diag
|
|
@@ -547,11 +742,19 @@ module CDDL
|
|
|
547
742
|
|
|
548
743
|
def validate(d, warn=true)
|
|
549
744
|
@recursion = 0
|
|
745
|
+
$features = Hash.new {|h, k| h[k] = {}}
|
|
550
746
|
result = validate1a(d, rules)
|
|
551
|
-
|
|
552
|
-
if
|
|
747
|
+
if warn
|
|
748
|
+
if result
|
|
749
|
+
if $features != {}
|
|
750
|
+
features = $features.reject {|k, v| CDDL_FEATURE_OK[k.to_s] }
|
|
751
|
+
# warn "@@@ FEAT #{CDDL_FEATURE_OK.inspect} #{CDDL_FEATURE_REJECT.inspect}"
|
|
752
|
+
warn "** Features potentially used (#$fn): #{features.map {|k, v| "#{k}: #{v.keys}"}.join(", ")}" if features != {}
|
|
753
|
+
end
|
|
754
|
+
else
|
|
553
755
|
warn "CDDL validation failure (#{result.inspect} for #{d.inspect}):"
|
|
554
756
|
PP::pp(validate_diag, STDERR)
|
|
757
|
+
puts(validate_diag.cbor_diagnostic)
|
|
555
758
|
end
|
|
556
759
|
end
|
|
557
760
|
result
|
|
@@ -559,7 +762,7 @@ module CDDL
|
|
|
559
762
|
|
|
560
763
|
def validate_result(check)
|
|
561
764
|
check || (
|
|
562
|
-
@last_message
|
|
765
|
+
@last_message << yield
|
|
563
766
|
false
|
|
564
767
|
)
|
|
565
768
|
end
|
|
@@ -592,7 +795,9 @@ module CDDL
|
|
|
592
795
|
ann.concat(ann2)
|
|
593
796
|
end
|
|
594
797
|
if occ < s
|
|
595
|
-
|
|
798
|
+
# warn "*** lme #{@last_message.encoding} #{@last_message}"
|
|
799
|
+
# warn "*** #{"\noccur #{occ} < #{s}, not reached at #{i} in array #{d} for #{where}".encoding}"
|
|
800
|
+
@last_message << "\noccur #{occ} < #{s}, not reached at #{i} in array #{d} for #{where}"
|
|
596
801
|
return [false, ann]
|
|
597
802
|
end
|
|
598
803
|
end
|
|
@@ -681,13 +886,17 @@ module CDDL
|
|
|
681
886
|
puts "COMPLEX: #{k.inspect} #{simple.inspect} #{simpleval.inspect}" if ENV["CDDL_TRACE"]
|
|
682
887
|
keys = d_check.keys
|
|
683
888
|
ta, keys = keys.partition{ |key| validate1(key, k)}
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
889
|
+
count = 0
|
|
890
|
+
catch :enough do
|
|
891
|
+
ta.all? { |val|
|
|
892
|
+
if (ann2 = validate1a(d[val], v)) && # XXX check cut or not!
|
|
893
|
+
d_check.delete(val) {:not_found} != :not_found
|
|
894
|
+
anno.concat(ann2)
|
|
895
|
+
throw :enough, true if (count += 1) == e
|
|
896
|
+
true
|
|
897
|
+
end
|
|
898
|
+
}
|
|
899
|
+
end and validate_result(count >= s) { "not enough #{ta.inspect} for #{r.inspect}" }
|
|
691
900
|
end
|
|
692
901
|
end
|
|
693
902
|
else
|
|
@@ -741,16 +950,31 @@ module CDDL
|
|
|
741
950
|
idx, ann = validate_forward(d, 0, where)
|
|
742
951
|
ann if validate_result(idx == d.size) { "#{validate_diag.inspect} -- cannot complete (#{idx}, #{d.size}) array #{d} for #{where}" }
|
|
743
952
|
end
|
|
744
|
-
when :
|
|
953
|
+
when :int, :float
|
|
745
954
|
_, v = extract_value(where)
|
|
746
955
|
[] if d == v
|
|
956
|
+
when :text, :bytes
|
|
957
|
+
_, v = extract_value(where)
|
|
958
|
+
[] if d == v && ((d.encoding == Encoding::BINARY) == (v.encoding == Encoding::BINARY))
|
|
747
959
|
when :range
|
|
748
960
|
[] if where[2] === d && where[1].include?(d)
|
|
749
961
|
when :anno
|
|
750
|
-
target = where
|
|
751
|
-
if
|
|
752
|
-
|
|
753
|
-
|
|
962
|
+
_, conop, target, control = where
|
|
963
|
+
if conop == :cat || conop == :plus || conop == :det
|
|
964
|
+
ok1, v1, vt1 = extract_value(target)
|
|
965
|
+
ok2, v2, vt2 = extract_value(control)
|
|
966
|
+
# warn ["ANNO0", ok1, v1, vt1, ok2, v2, vt2, d].inspect
|
|
967
|
+
if ok1 && ok2
|
|
968
|
+
v2 = Integer(v2) if vt1 == Integer
|
|
969
|
+
if conop == :det
|
|
970
|
+
v1 = remove_indentation(v1)
|
|
971
|
+
v2 = remove_indentation(v2)
|
|
972
|
+
end
|
|
973
|
+
# warn ["ANNO", ok1, v1, vt1, ok2, v2, vt2, d].inspect
|
|
974
|
+
[] if d == v1 + v2 # XXX Focus ArgumentError
|
|
975
|
+
end
|
|
976
|
+
elsif ann = validate1a(d, target)
|
|
977
|
+
case conop
|
|
754
978
|
when :size
|
|
755
979
|
case d
|
|
756
980
|
when Integer
|
|
@@ -789,8 +1013,12 @@ module CDDL
|
|
|
789
1013
|
$default_warned = true
|
|
790
1014
|
end
|
|
791
1015
|
ann
|
|
1016
|
+
when :feature
|
|
1017
|
+
nm, det = extract_feature(control, d)
|
|
1018
|
+
$features[nm][det] = true
|
|
1019
|
+
ann if !CDDL_FEATURE_REJECT[nm]
|
|
792
1020
|
when :lt, :le, :gt, :ge, :eq, :ne
|
|
793
|
-
op = OPERATORS[
|
|
1021
|
+
op = OPERATORS[conop]
|
|
794
1022
|
ok, v, _vt = extract_value(control)
|
|
795
1023
|
if ok
|
|
796
1024
|
ann if d.send(op, v) rescue nil # XXX Focus ArgumentError
|
|
@@ -806,10 +1034,98 @@ module CDDL
|
|
|
806
1034
|
end
|
|
807
1035
|
end
|
|
808
1036
|
)
|
|
1037
|
+
when :abnf, :abnfb
|
|
1038
|
+
ann if (
|
|
1039
|
+
if String === d
|
|
1040
|
+
ok, v, vt = extract_value(control)
|
|
1041
|
+
if ok && vt == String
|
|
1042
|
+
begin
|
|
1043
|
+
ABNF_PARSER_FOR_STRING[v].validate(
|
|
1044
|
+
d.dup.force_encoding(ABNF_ENCODING_FOR_CONOP[conop]).codepoints.pack("U*")
|
|
1045
|
+
)
|
|
1046
|
+
true
|
|
1047
|
+
rescue => e
|
|
1048
|
+
# warn "*** #{e}" # XXX
|
|
1049
|
+
@last_message = e.to_s.force_encoding(Encoding::UTF_8)
|
|
1050
|
+
nil
|
|
1051
|
+
end
|
|
1052
|
+
end
|
|
1053
|
+
end
|
|
1054
|
+
)
|
|
809
1055
|
when :cbor
|
|
810
1056
|
ann if validate1((CBOR::decode(d) rescue :BAD_CBOR), control)
|
|
811
1057
|
when :cborseq
|
|
812
1058
|
ann if validate1((CBOR::decode("\x9f".b << d << "\xff".b) rescue :BAD_CBOR), control)
|
|
1059
|
+
when :cbordet
|
|
1060
|
+
decoded = CBOR::decode(d) rescue :BAD_CBOR
|
|
1061
|
+
if d != decoded.to_deterministic_cbor
|
|
1062
|
+
@last_message = "CBOR #{d.inspect} not deterministically encoded"
|
|
1063
|
+
nil
|
|
1064
|
+
else
|
|
1065
|
+
ann if validate1(decoded, control)
|
|
1066
|
+
end
|
|
1067
|
+
when :cborseqdet
|
|
1068
|
+
decoded = CBOR::decode("\x9f".b << d << "\xff".b) rescue :BAD_CBOR
|
|
1069
|
+
if d != unpack_array_to_sequence(decoded.to_deterministic_cbor, d.inspect)
|
|
1070
|
+
@last_message = "CBOR Sequence #{d.inspect} not deterministically encoded"
|
|
1071
|
+
nil
|
|
1072
|
+
else
|
|
1073
|
+
ann if validate1(decoded, control)
|
|
1074
|
+
end
|
|
1075
|
+
when :json
|
|
1076
|
+
ann if validate1((JSON::load(d) rescue :BAD_JSON), control)
|
|
1077
|
+
when :decimal
|
|
1078
|
+
ann if (
|
|
1079
|
+
if /\A0|-?[1-9][0-9]*\z/ === d
|
|
1080
|
+
validate1((d.to_i rescue :BAD_JSON), control)
|
|
1081
|
+
end
|
|
1082
|
+
)
|
|
1083
|
+
when :join
|
|
1084
|
+
ok, *v = extract_array(control)
|
|
1085
|
+
# warn "@@@JJJ@@@ #{ok.inspect} #{v.inspect}"
|
|
1086
|
+
if ok
|
|
1087
|
+
expected = v.map {|ve|
|
|
1088
|
+
fail "Not a string in #{where}" unless String === ve[0]
|
|
1089
|
+
ve[0]
|
|
1090
|
+
}.join
|
|
1091
|
+
ann if d == expected
|
|
1092
|
+
else
|
|
1093
|
+
fail "Don't know yet how to validate against #{where}"
|
|
1094
|
+
end
|
|
1095
|
+
when :b64u, :"b64u-sloppy", :b64c, :"b64c-sloppy", :b45, :b32, :h32, :hex, :hexlc, :hexuc
|
|
1096
|
+
ann if (
|
|
1097
|
+
String === d && (
|
|
1098
|
+
decoded = case conop
|
|
1099
|
+
when :b64u
|
|
1100
|
+
/=/ !~ d &&
|
|
1101
|
+
Base64.urlsafe_decode64(d)
|
|
1102
|
+
when :"b64u-sloppy"
|
|
1103
|
+
/[-_=]/ !~ d &&
|
|
1104
|
+
Base64.decode64(d.tr("+/", "-_"))
|
|
1105
|
+
when :b64c
|
|
1106
|
+
Base64.strict_decode64(d)
|
|
1107
|
+
when :"b64c-sloppy"
|
|
1108
|
+
Base64.decode64(d)
|
|
1109
|
+
when :b32
|
|
1110
|
+
/=/ !~ d &&
|
|
1111
|
+
(Base32.table = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567") &&
|
|
1112
|
+
Base32.decode(d)
|
|
1113
|
+
when :b45
|
|
1114
|
+
Base45Lite.decode(d)
|
|
1115
|
+
when :h32
|
|
1116
|
+
/=/ !~ d &&
|
|
1117
|
+
(Base32.table = "0123456789ABCDEFGHIJKLMNOPQRSTUV") &&
|
|
1118
|
+
Base32.decode(d)
|
|
1119
|
+
when :hex
|
|
1120
|
+
/\A[0-9a-fA-F]*\z/ =~ d && [d].pack("H*")
|
|
1121
|
+
when :hexuc
|
|
1122
|
+
/\A[0-9A-F]*\z/ =~ d && [d].pack("H*")
|
|
1123
|
+
when :hexlc
|
|
1124
|
+
/\A[0-9a-f]*\z/ =~ d && [d].pack("H*")
|
|
1125
|
+
else fail "Cannot happen"
|
|
1126
|
+
end
|
|
1127
|
+
) && validate1(decoded.b, control)
|
|
1128
|
+
)
|
|
813
1129
|
when :within
|
|
814
1130
|
if validate1(d, control)
|
|
815
1131
|
ann
|
|
@@ -837,6 +1153,14 @@ module CDDL
|
|
|
837
1153
|
when 3
|
|
838
1154
|
String === d && d.encoding != Encoding::BINARY # cheat
|
|
839
1155
|
when 6
|
|
1156
|
+
if Integer === d
|
|
1157
|
+
t = 2 # assuming only 2/3 match an Integer
|
|
1158
|
+
if d < 0
|
|
1159
|
+
d = ~d
|
|
1160
|
+
t = 3
|
|
1161
|
+
end
|
|
1162
|
+
d = CBOR::Tagged.new(t, d == 0 ? "".b : d.digits(256).reverse!.pack("C*"))
|
|
1163
|
+
end
|
|
840
1164
|
CBOR::Tagged === d && d.tag == where[2] && validate1a(d.data, where[3])
|
|
841
1165
|
when 7
|
|
842
1166
|
t, v = extract_value(where)
|
|
@@ -950,20 +1274,21 @@ module CDDL
|
|
|
950
1274
|
# warn n
|
|
951
1275
|
s = n.to_s
|
|
952
1276
|
if s[-1] == "'"
|
|
953
|
-
parts = s.split("'",
|
|
954
|
-
if parts[
|
|
955
|
-
warn "***
|
|
1277
|
+
bsqual, *parts = s.split("'", -1)
|
|
1278
|
+
if parts[-1] != ""
|
|
1279
|
+
warn "*** Problem decoding byte string #{s.inspect}"
|
|
956
1280
|
end
|
|
1281
|
+
bsval = parts[0...-1].join("'").gsub(/\\(.)/){$1}
|
|
957
1282
|
[:bytes,
|
|
958
|
-
case
|
|
1283
|
+
case bsqual
|
|
959
1284
|
when ""
|
|
960
|
-
|
|
1285
|
+
bsval.b
|
|
961
1286
|
when "h"
|
|
962
|
-
|
|
1287
|
+
bsval.gsub(/\s/, "").chars.each_slice(2).map{ |x| Integer(x.join, 16).chr("BINARY") }.join.b
|
|
963
1288
|
when "b64"
|
|
964
|
-
Base64.urlsafe_decode64(
|
|
1289
|
+
Base64.urlsafe_decode64(bsval)
|
|
965
1290
|
else
|
|
966
|
-
warn "*** Can't handle byte string type #{
|
|
1291
|
+
warn "*** Can't handle byte string type #{bsqual.inspect} yet"
|
|
967
1292
|
end
|
|
968
1293
|
]
|
|
969
1294
|
else
|
|
@@ -1073,9 +1398,13 @@ module CDDL
|
|
|
1073
1398
|
def g_process(name, g, genericargs)
|
|
1074
1399
|
r, ids = g
|
|
1075
1400
|
args = genericargs.children(:type1).map {|x| type1(x, true)}
|
|
1401
|
+
# warn "** args #{args.inspect}"
|
|
1076
1402
|
fail "number of args #{name} #{ids.size} #{args.size}" if ids.size != args.size
|
|
1077
1403
|
bindings = Hash[ids.zip(args)]
|
|
1078
|
-
|
|
1404
|
+
# warn "** bindings: #{bindings.inspect}"
|
|
1405
|
+
genname = "#{name}<#{args.inspect}>" # XXX this works up to a RECURSE...
|
|
1406
|
+
# warn "** genname #{genname}"
|
|
1407
|
+
r_process(genname, r, bindings)
|
|
1079
1408
|
end
|
|
1080
1409
|
|
|
1081
1410
|
def type_recall(name, canbegroup, genericargs)
|
|
@@ -1142,7 +1471,7 @@ module CDDL
|
|
|
1142
1471
|
end
|
|
1143
1472
|
when :recurse_grpent # XXX we don't have the entry yet
|
|
1144
1473
|
when :member
|
|
1145
|
-
fail "map entry without member key given: #{member}" unless member[3] || member[4][0] == :grpent || member[4][0] == :grpchoice
|
|
1474
|
+
fail "map entry #{member.inspect} without member key given: #{member}" unless member[3] || member[4][0] == :grpent || member[4][0] == :grpchoice
|
|
1146
1475
|
else
|
|
1147
1476
|
fail ["type1 member", member].inspect unless member[0] == :member
|
|
1148
1477
|
end
|
|
@@ -1151,8 +1480,15 @@ module CDDL
|
|
|
1151
1480
|
|
|
1152
1481
|
BRACE = {"{" => :map, "[" => :array}
|
|
1153
1482
|
RANGE_EXCLUDE_END = {".." => false, "..." => true}
|
|
1154
|
-
SUPPORTED_ANNOTATIONS = [:bits, :size, :regexp,
|
|
1155
|
-
:
|
|
1483
|
+
SUPPORTED_ANNOTATIONS = [:bits, :size, :regexp,
|
|
1484
|
+
:cbor, :cborseq, :cbordet, :cborseqdet,
|
|
1485
|
+
:within, :and,
|
|
1486
|
+
:default, :lt, :le, :gt, :ge, :eq, :ne,
|
|
1487
|
+
:feature, :abnf, :abnfb, :det, :cat, :plus,
|
|
1488
|
+
:json, :decimal, :join,
|
|
1489
|
+
:b64u, :"b64u-sloppy", :b64c, :"b64c-sloppy",
|
|
1490
|
+
:b45, :b32, :h32, :hex, :hexlc, :hexuc,
|
|
1491
|
+
]
|
|
1156
1492
|
|
|
1157
1493
|
def type1(n, canbegroup = false)
|
|
1158
1494
|
# puts "NVALUE #{n.value.inspect}"
|
|
@@ -1214,6 +1550,26 @@ module CDDL
|
|
|
1214
1550
|
v
|
|
1215
1551
|
}
|
|
1216
1552
|
]
|
|
1553
|
+
when /\A~/
|
|
1554
|
+
if tn = n.typename
|
|
1555
|
+
s = type_recall(tn.to_s, false, n.genericarg).flatten(1)
|
|
1556
|
+
else
|
|
1557
|
+
fail "No typename in unwrap #{n}"
|
|
1558
|
+
end
|
|
1559
|
+
if s[0] != :type1
|
|
1560
|
+
fail [:UNWRAPs0, s].inspect
|
|
1561
|
+
end
|
|
1562
|
+
case s[1]
|
|
1563
|
+
when :map, :array
|
|
1564
|
+
[:grpent, s[2..-1]]
|
|
1565
|
+
when :prim
|
|
1566
|
+
if s[2] != 6
|
|
1567
|
+
fail [:UNWRAPs2, s].inspect
|
|
1568
|
+
end
|
|
1569
|
+
s[4] # check :type1?
|
|
1570
|
+
else
|
|
1571
|
+
fail [:UNWRAPs1, s].inspect
|
|
1572
|
+
end
|
|
1217
1573
|
else
|
|
1218
1574
|
"unimplemented #{n}"
|
|
1219
1575
|
end
|