cddl 0.8.9 → 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 +10 -7
- data/data/cddl.abnf +30 -13
- data/lib/cbor-pp-play.rb +1 -0
- data/lib/cddl.rb +719 -71
- 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/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/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/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/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 +142 -13
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)
|
|
@@ -371,9 +442,17 @@ module CDDL
|
|
|
371
442
|
when 3
|
|
372
443
|
gen_word
|
|
373
444
|
when 6
|
|
374
|
-
|
|
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]))
|
|
375
450
|
when 7
|
|
376
|
-
|
|
451
|
+
w2 = where[2]
|
|
452
|
+
if Array === w2
|
|
453
|
+
w2 = generate1(w2)
|
|
454
|
+
end
|
|
455
|
+
case w2
|
|
377
456
|
when nil
|
|
378
457
|
Math::PI
|
|
379
458
|
when 20
|
|
@@ -382,10 +461,22 @@ module CDDL
|
|
|
382
461
|
true
|
|
383
462
|
when 22
|
|
384
463
|
nil
|
|
385
|
-
when 23
|
|
386
|
-
|
|
387
|
-
when 25
|
|
388
|
-
|
|
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
|
|
389
480
|
end
|
|
390
481
|
else
|
|
391
482
|
fail "Can't generate prim #{where[1]}"
|
|
@@ -393,7 +484,7 @@ module CDDL
|
|
|
393
484
|
when :anno
|
|
394
485
|
target = where[2]
|
|
395
486
|
control = where[3]
|
|
396
|
-
case where[1]
|
|
487
|
+
case conop = where[1]
|
|
397
488
|
when :size
|
|
398
489
|
should_be_int = generate1(control)
|
|
399
490
|
unless (Array === target && target[0] == :prim && [0, 2, 3].include?(target[1])) && Integer === should_be_int && should_be_int >= 0
|
|
@@ -439,6 +530,40 @@ module CDDL
|
|
|
439
530
|
$default_warned = true
|
|
440
531
|
end
|
|
441
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
|
|
442
567
|
when :eq
|
|
443
568
|
content = generate1(control)
|
|
444
569
|
if validate1(content, where)
|
|
@@ -452,7 +577,7 @@ module CDDL
|
|
|
452
577
|
content = Integer(content)
|
|
453
578
|
case target[1]
|
|
454
579
|
when 0
|
|
455
|
-
case
|
|
580
|
+
case conop
|
|
456
581
|
when :lt
|
|
457
582
|
rand(0...content)
|
|
458
583
|
when :le
|
|
@@ -466,8 +591,7 @@ module CDDL
|
|
|
466
591
|
warn "HUH gen #{where.inspect} #{try.inspect}" unless try.nil?
|
|
467
592
|
end
|
|
468
593
|
end
|
|
469
|
-
|
|
470
|
-
content = generate1(target)
|
|
594
|
+
try_generate(target) do |content|
|
|
471
595
|
if validate1(content, where)
|
|
472
596
|
return content
|
|
473
597
|
end
|
|
@@ -479,30 +603,117 @@ module CDDL
|
|
|
479
603
|
fail "Don't know yet how to generate #{where}"
|
|
480
604
|
end
|
|
481
605
|
REGEXP_FOR_STRING[regexp].random_example(max_repeater_variance: 5)
|
|
482
|
-
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
|
|
483
621
|
unless target == [:prim, 2]
|
|
484
622
|
fail "Don't know yet how to generate #{where}"
|
|
485
623
|
end
|
|
486
|
-
|
|
487
|
-
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
|
|
488
630
|
# remove the first head
|
|
489
|
-
|
|
490
|
-
when 0..23; 1
|
|
491
|
-
when 24; 2
|
|
492
|
-
when 25; 3
|
|
493
|
-
when 26; 5
|
|
494
|
-
when 27; 9 # unlikely :-)
|
|
495
|
-
else fail "Generated .cborseq sequence for #{where} not an array"
|
|
496
|
-
end
|
|
497
|
-
content[0...n] = ''
|
|
631
|
+
content = unpack_array_to_sequence(content, where)
|
|
498
632
|
end
|
|
499
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}"
|
|
500
711
|
when :within, :and
|
|
501
|
-
|
|
502
|
-
|
|
712
|
+
try_generate(target) do |content|
|
|
713
|
+
$features ||= Hash.new {|h, k| h[k] = {}}
|
|
503
714
|
if validate1(content, control)
|
|
504
715
|
return content
|
|
505
|
-
elsif
|
|
716
|
+
elsif conop == :within
|
|
506
717
|
warn "*** #{content.inspect} meets #{target.inspect} but not #{control.inspect}"
|
|
507
718
|
end
|
|
508
719
|
end
|
|
@@ -527,22 +738,102 @@ module CDDL
|
|
|
527
738
|
end
|
|
528
739
|
end
|
|
529
740
|
|
|
530
|
-
|
|
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}
|
|
531
749
|
SIMPLE_VALUE = {
|
|
532
750
|
[:prim, 7, 20] => [true, false, :bool],
|
|
533
751
|
[:prim, 7, 21] => [true, true, :bool],
|
|
534
752
|
[:prim, 7, 22] => [true, nil, :nil],
|
|
535
|
-
[:prim, 7, 23] => [true, :undefined, :undefined],
|
|
536
753
|
}
|
|
754
|
+
SIMPLE_VALUE_SIMPLE = Set[23] + (0..19) + (32..255)
|
|
537
755
|
|
|
538
756
|
def extract_value(t) # []
|
|
539
757
|
if vt = VALUE_TYPE[t[0]]
|
|
540
758
|
[true, t[1], vt]
|
|
541
|
-
elsif
|
|
542
|
-
|
|
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
|
|
543
826
|
else
|
|
544
|
-
|
|
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
|
|
545
835
|
end
|
|
836
|
+
[nm, det]
|
|
546
837
|
end
|
|
547
838
|
|
|
548
839
|
def validate_diag
|
|
@@ -551,11 +842,19 @@ module CDDL
|
|
|
551
842
|
|
|
552
843
|
def validate(d, warn=true)
|
|
553
844
|
@recursion = 0
|
|
845
|
+
$features = Hash.new {|h, k| h[k] = {}}
|
|
554
846
|
result = validate1a(d, rules)
|
|
555
|
-
|
|
556
|
-
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
|
|
557
855
|
warn "CDDL validation failure (#{result.inspect} for #{d.inspect}):"
|
|
558
856
|
PP::pp(validate_diag, STDERR)
|
|
857
|
+
puts(validate_diag.cbor_diagnostic)
|
|
559
858
|
end
|
|
560
859
|
end
|
|
561
860
|
result
|
|
@@ -563,7 +862,7 @@ module CDDL
|
|
|
563
862
|
|
|
564
863
|
def validate_result(check)
|
|
565
864
|
check || (
|
|
566
|
-
@last_message
|
|
865
|
+
@last_message << yield
|
|
567
866
|
false
|
|
568
867
|
)
|
|
569
868
|
end
|
|
@@ -596,7 +895,9 @@ module CDDL
|
|
|
596
895
|
ann.concat(ann2)
|
|
597
896
|
end
|
|
598
897
|
if occ < s
|
|
599
|
-
|
|
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}"
|
|
600
901
|
return [false, ann]
|
|
601
902
|
end
|
|
602
903
|
end
|
|
@@ -685,13 +986,17 @@ module CDDL
|
|
|
685
986
|
puts "COMPLEX: #{k.inspect} #{simple.inspect} #{simpleval.inspect}" if ENV["CDDL_TRACE"]
|
|
686
987
|
keys = d_check.keys
|
|
687
988
|
ta, keys = keys.partition{ |key| validate1(key, k)}
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
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}" }
|
|
695
1000
|
end
|
|
696
1001
|
end
|
|
697
1002
|
else
|
|
@@ -700,6 +1005,19 @@ module CDDL
|
|
|
700
1005
|
}
|
|
701
1006
|
end
|
|
702
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
|
+
|
|
703
1021
|
def validate1a(d, where)
|
|
704
1022
|
if ann = validate1(d, where)
|
|
705
1023
|
here = [d, where]
|
|
@@ -712,6 +1030,8 @@ module CDDL
|
|
|
712
1030
|
end
|
|
713
1031
|
|
|
714
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}
|
|
715
1035
|
|
|
716
1036
|
def validate1(d, where)
|
|
717
1037
|
if ENV["CDDL_TRACE"]
|
|
@@ -722,6 +1042,9 @@ module CDDL
|
|
|
722
1042
|
@last_data = d
|
|
723
1043
|
@last_rule = where
|
|
724
1044
|
ann = nil
|
|
1045
|
+
if CBOR::Tagged === d && d.tag === 888 && ENV["CDDL_888"]
|
|
1046
|
+
return []
|
|
1047
|
+
end
|
|
725
1048
|
case where[0]
|
|
726
1049
|
when :type1
|
|
727
1050
|
if where[1..-1].any? {|r| ann = validate1a(d, r)}
|
|
@@ -745,16 +1068,55 @@ module CDDL
|
|
|
745
1068
|
idx, ann = validate_forward(d, 0, where)
|
|
746
1069
|
ann if validate_result(idx == d.size) { "#{validate_diag.inspect} -- cannot complete (#{idx}, #{d.size}) array #{d} for #{where}" }
|
|
747
1070
|
end
|
|
748
|
-
when :
|
|
1071
|
+
when :int, :float
|
|
749
1072
|
_, v = extract_value(where)
|
|
750
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))
|
|
751
1077
|
when :range
|
|
752
1078
|
[] if where[2] === d && where[1].include?(d)
|
|
753
1079
|
when :anno
|
|
754
|
-
target = where
|
|
755
|
-
if
|
|
756
|
-
|
|
757
|
-
|
|
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
|
|
758
1120
|
when :size
|
|
759
1121
|
case d
|
|
760
1122
|
when Integer
|
|
@@ -793,11 +1155,20 @@ module CDDL
|
|
|
793
1155
|
$default_warned = true
|
|
794
1156
|
end
|
|
795
1157
|
ann
|
|
1158
|
+
when :feature
|
|
1159
|
+
nm, det = extract_feature(control, d)
|
|
1160
|
+
$features[nm][det] = true
|
|
1161
|
+
ann if !CDDL_FEATURE_REJECT[nm]
|
|
796
1162
|
when :lt, :le, :gt, :ge, :eq, :ne
|
|
797
|
-
op = OPERATORS[
|
|
1163
|
+
op = OPERATORS[conop]
|
|
798
1164
|
ok, v, _vt = extract_value(control)
|
|
799
1165
|
if ok
|
|
800
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
|
|
801
1172
|
end
|
|
802
1173
|
when :regexp
|
|
803
1174
|
ann if (
|
|
@@ -810,10 +1181,181 @@ module CDDL
|
|
|
810
1181
|
end
|
|
811
1182
|
end
|
|
812
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
|
+
)
|
|
813
1202
|
when :cbor
|
|
814
1203
|
ann if validate1((CBOR::decode(d) rescue :BAD_CBOR), control)
|
|
815
1204
|
when :cborseq
|
|
816
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
|
+
)
|
|
817
1359
|
when :within
|
|
818
1360
|
if validate1(d, control)
|
|
819
1361
|
ann
|
|
@@ -841,20 +1383,43 @@ module CDDL
|
|
|
841
1383
|
when 3
|
|
842
1384
|
String === d && d.encoding != Encoding::BINARY # cheat
|
|
843
1385
|
when 6
|
|
844
|
-
|
|
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])
|
|
845
1397
|
when 7
|
|
846
1398
|
t, v = extract_value(where)
|
|
847
1399
|
if t
|
|
848
1400
|
v.eql? d
|
|
849
1401
|
else
|
|
850
|
-
case where[2]
|
|
1402
|
+
case w2 = where[2]
|
|
851
1403
|
when nil
|
|
852
|
-
|
|
853
|
-
|
|
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)
|
|
854
1419
|
when 25, 26, 27
|
|
855
|
-
Float === d
|
|
1420
|
+
Float === d && FLOAT_AI_FROM_SIZE[d.to_cbor.size] == w2
|
|
856
1421
|
else
|
|
857
|
-
fail
|
|
1422
|
+
fail [:val7, d, where].inspect
|
|
858
1423
|
end
|
|
859
1424
|
end
|
|
860
1425
|
else
|
|
@@ -904,6 +1469,10 @@ module CDDL
|
|
|
904
1469
|
else
|
|
905
1470
|
[:type1]
|
|
906
1471
|
end
|
|
1472
|
+
elsif s = ENV["CDDL_INVENT"]
|
|
1473
|
+
s = "_" if s == ""
|
|
1474
|
+
r = [:type1, [:text, "#{s}-#{name}"]]
|
|
1475
|
+
return r
|
|
907
1476
|
end
|
|
908
1477
|
end
|
|
909
1478
|
if r
|
|
@@ -949,29 +1518,69 @@ module CDDL
|
|
|
949
1518
|
end
|
|
950
1519
|
end
|
|
951
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
|
+
|
|
952
1533
|
def value(n)
|
|
953
1534
|
# cheat:
|
|
954
1535
|
# warn n
|
|
955
1536
|
s = n.to_s
|
|
956
1537
|
if s[-1] == "'"
|
|
957
|
-
parts = s.split("'",
|
|
958
|
-
if parts[
|
|
959
|
-
warn "***
|
|
1538
|
+
bsqual, *parts = s.split("'", -1)
|
|
1539
|
+
if parts[-1] != ""
|
|
1540
|
+
warn "*** Problem decoding byte string #{s.inspect}"
|
|
960
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
|
+
}
|
|
961
1556
|
[:bytes,
|
|
962
|
-
case
|
|
1557
|
+
case bsqual
|
|
963
1558
|
when ""
|
|
964
|
-
|
|
1559
|
+
bsval.b
|
|
965
1560
|
when "h"
|
|
966
|
-
|
|
1561
|
+
bsval.gsub(/\s/, "").chars.each_slice(2).map{ |x| Integer(x.join, 16).chr("BINARY") }.join.b
|
|
967
1562
|
when "b64"
|
|
968
|
-
Base64.urlsafe_decode64(
|
|
1563
|
+
Base64.urlsafe_decode64(bsval)
|
|
969
1564
|
else
|
|
970
|
-
warn "*** Can't handle byte string type #{
|
|
1565
|
+
warn "*** Can't handle byte string type #{bsqual.inspect} yet"
|
|
971
1566
|
end
|
|
972
1567
|
]
|
|
973
1568
|
else
|
|
974
|
-
|
|
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
|
|
975
1584
|
# warn val
|
|
976
1585
|
case val
|
|
977
1586
|
when Integer; [:int, val]
|
|
@@ -1077,9 +1686,13 @@ module CDDL
|
|
|
1077
1686
|
def g_process(name, g, genericargs)
|
|
1078
1687
|
r, ids = g
|
|
1079
1688
|
args = genericargs.children(:type1).map {|x| type1(x, true)}
|
|
1689
|
+
# warn "** args #{args.inspect}"
|
|
1080
1690
|
fail "number of args #{name} #{ids.size} #{args.size}" if ids.size != args.size
|
|
1081
1691
|
bindings = Hash[ids.zip(args)]
|
|
1082
|
-
|
|
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)
|
|
1083
1696
|
end
|
|
1084
1697
|
|
|
1085
1698
|
def type_recall(name, canbegroup, genericargs)
|
|
@@ -1155,8 +1768,16 @@ module CDDL
|
|
|
1155
1768
|
|
|
1156
1769
|
BRACE = {"{" => :map, "[" => :array}
|
|
1157
1770
|
RANGE_EXCLUDE_END = {".." => false, "..." => true}
|
|
1158
|
-
SUPPORTED_ANNOTATIONS = [:bits, :size, :regexp,
|
|
1159
|
-
:
|
|
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
|
+
]
|
|
1160
1781
|
|
|
1161
1782
|
def type1(n, canbegroup = false)
|
|
1162
1783
|
# puts "NVALUE #{n.value.inspect}"
|
|
@@ -1188,6 +1809,13 @@ module CDDL
|
|
|
1188
1809
|
when /\A#(\d+)/
|
|
1189
1810
|
maj = $1.to_i
|
|
1190
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
|
|
1191
1819
|
if tagged_type = n.type
|
|
1192
1820
|
s << type(tagged_type)
|
|
1193
1821
|
end
|
|
@@ -1218,6 +1846,26 @@ module CDDL
|
|
|
1218
1846
|
v
|
|
1219
1847
|
}
|
|
1220
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
|
|
1221
1869
|
else
|
|
1222
1870
|
"unimplemented #{n}"
|
|
1223
1871
|
end
|