cbor-packed 0.1.5 → 0.2.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/cbor-packed.gemspec +1 -2
- data/lib/cbor-packed.rb +293 -60
- data/test/exa2r1.rb +58 -0
- data/test/test-packed.rb +5 -3
- metadata +5 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9306aa8a05d1747901cda5a72e3636199ce2dc403e09c8731c2fbd6c6be93623
|
4
|
+
data.tar.gz: 9ccd87f2b36818c1b71b7e946cdfe370c230f40ea9331fc407e925a0ff214824
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b35a19072f26120f7aa4e67c9f4b3af64f3aea70eeaa0203b3d7d0c228d8ab20ea006cebd09e62d26233ea10c8fbacad5b9024e75f180f9f9462c81fe1e5632a
|
7
|
+
data.tar.gz: 57a9c79818180b0433230c3666fdc5742d3b8fa22e9fd1deda8941a8a75eef05b0f933c249c1131afb5f615b23920cce16b5d81fc09d30b07d04ac0d233dd8f9
|
data/cbor-packed.gemspec
CHANGED
@@ -1,13 +1,12 @@
|
|
1
1
|
Gem::Specification.new do |s|
|
2
2
|
s.name = "cbor-packed"
|
3
|
-
s.version = "0.
|
3
|
+
s.version = "0.2.2"
|
4
4
|
s.summary = "CBOR (Concise Binary Object Representation) packer"
|
5
5
|
s.description = %q{cbor-packed implements packed encoding for CBOR, RFC 7049 Section 3.9}
|
6
6
|
s.author = "Carsten Bormann"
|
7
7
|
s.email = "cabo@tzi.org"
|
8
8
|
s.license = "Apache-2.0"
|
9
9
|
s.homepage = "http://cbor.io/"
|
10
|
-
s.has_rdoc = false
|
11
10
|
s.test_files = Dir['test/**/*.rb']
|
12
11
|
s.files = Dir['lib/**/*.rb'] + %w(cbor-packed.gemspec) + Dir['bin/**/*.rb']
|
13
12
|
s.executables = Dir['bin/**/*.rb'].map {|x| File.basename(x)}
|
data/lib/cbor-packed.rb
CHANGED
@@ -1,66 +1,220 @@
|
|
1
1
|
# -*- coding: utf-8 -*-
|
2
2
|
|
3
|
-
require "cbor" unless defined? CBOR
|
4
|
-
|
3
|
+
require "cbor-pure" unless defined? CBOR
|
4
|
+
require "pp"
|
5
5
|
|
6
6
|
$compression_hack = 0
|
7
7
|
|
8
|
+
# class String
|
9
|
+
# def xeh
|
10
|
+
# gsub(/\s/, "").chars.each_slice(2).map{ |x| Integer(x.join, 16).chr("BINARY") }.join
|
11
|
+
# end
|
12
|
+
# end
|
13
|
+
|
8
14
|
module CBOR
|
9
|
-
PACKED_TAG =
|
15
|
+
PACKED_TAG = 1113
|
16
|
+
MIXED_PACKED_TAG = 113
|
10
17
|
REF_TAG = 6
|
18
|
+
STRAIGHT_11_SIZE = 32 # How many 1+1 straight tags do we have
|
19
|
+
|
20
|
+
HEX_UC_TAG = 23
|
21
|
+
HEX_LC_TAG = 108 # 'l'.ord, SQUATTING, fix this
|
22
|
+
RECORD_TAG = 114 # 'r'.ord
|
23
|
+
UNDEFINED = CBOR::Simple.new(23)
|
11
24
|
|
25
|
+
# Use with || 4
|
26
|
+
# simple 6(1+0) 6(1+1)
|
12
27
|
REF_SIZE = [*Array.new(16, 1), *Array.new(48, 2), *Array.new(512-48, 3)]
|
13
28
|
|
14
29
|
class Packer
|
15
|
-
def self.
|
30
|
+
def self.build_match_array(item)
|
31
|
+
# Hash with all data items as keys and the number of times they occur as values:
|
16
32
|
count = Hash.new(0)
|
17
33
|
item.cbor_visit do |o|
|
18
34
|
(count[o] += 1) == 1
|
19
35
|
# if the count gets > 1, we can stop visiting, so we return false in the block
|
20
36
|
end
|
21
|
-
# pp count
|
22
|
-
# count is now a Hash with all data items as keys and the number of times they occur as values
|
23
37
|
|
24
38
|
# choose those matches that are occurring > 1, make first rough estimate of saving
|
25
|
-
good_count = count
|
26
|
-
|
27
|
-
|
39
|
+
good_count = count
|
40
|
+
.select {|k, v| v > 1}
|
41
|
+
.map {|k, v|
|
42
|
+
l = k.to_cbor.length
|
43
|
+
# v-1: We can only save space for the second etc.
|
44
|
+
# l-1: We'll need at least 1 byte for the reference
|
45
|
+
gain = (v-1)*(l-1)
|
46
|
+
[k, v, l] if gain > 0
|
47
|
+
}.compact
|
48
|
+
.sort_by {|a| -a[1]}
|
49
|
+
# good_count is now an array of [value, count, length] tuples that have potential gain,
|
50
|
+
# sorted by descending number of references we'll get
|
28
51
|
|
29
|
-
|
30
|
-
|
31
|
-
|
52
|
+
match_array = []
|
53
|
+
good_count.each {|a|
|
54
|
+
match_array << a[0] if (REF_SIZE[match_array.size] || 4) < a[2]
|
55
|
+
}
|
56
|
+
# pp match_array
|
57
|
+
[count, match_array]
|
58
|
+
end
|
32
59
|
|
33
|
-
|
60
|
+
def self.argref(n, casezero = 6)
|
61
|
+
case n
|
62
|
+
when 0
|
63
|
+
casezero
|
64
|
+
when 1..31
|
65
|
+
n + 224
|
66
|
+
when 32...0x1000
|
67
|
+
n + 0x7000
|
68
|
+
when 0x1000...0x10000000
|
69
|
+
n + 0x70000000
|
70
|
+
end
|
71
|
+
end
|
34
72
|
|
35
|
-
|
36
|
-
|
37
|
-
|
73
|
+
def self.sharedref(i)
|
74
|
+
if i < 16
|
75
|
+
CBOR::Simple.new(i)
|
76
|
+
else
|
77
|
+
i -= 16
|
78
|
+
CBOR::Tagged.new(REF_TAG, (i >> 1) ^ -(i & 1))
|
79
|
+
end
|
80
|
+
end
|
38
81
|
|
39
|
-
|
82
|
+
def self.build_bytes_from_hex(strings, count, match_array, item, translate, prefixes)
|
83
|
+
optimizable, others = strings.partition do |str|
|
84
|
+
if /(?:(?<lc>(?:[0-9a-f][0-9a-f]){4,})|(?<uc>(?:[0-9A-F][0-9A-F]){4,}))$/ =~ str
|
85
|
+
left = $`
|
86
|
+
# warn [:lc, left, lc, uc].inspect
|
87
|
+
bytes = [
|
88
|
+
if lc
|
89
|
+
tag = HEX_LC_TAG
|
90
|
+
fail if uc
|
91
|
+
lc
|
92
|
+
else
|
93
|
+
fail unless uc
|
94
|
+
tag = HEX_UC_TAG
|
95
|
+
uc
|
96
|
+
end].pack('H*').b
|
97
|
+
if outer = translate[str]
|
98
|
+
fail outer.inspect unless CBOR::Tagged === outer && left == outer.value # XXX
|
99
|
+
else
|
100
|
+
referto = bytes
|
101
|
+
if (count[bytes] += 1) == 2 # patch up match_array...
|
102
|
+
# translate[bytes] = sharedref(match_array.size) # happens later, too
|
103
|
+
match_array << bytes
|
104
|
+
referto = sharedref(match_array.size-1)
|
105
|
+
end
|
106
|
+
prefixes << left unless prefixes[-1] == left
|
107
|
+
translate[str] = CBOR::Tagged.new(argref(prefixes.size-1),
|
108
|
+
CBOR::Tagged.new(tag, referto)) unless count[bytes] > 2
|
109
|
+
# don't overwrite any entry made at == 2
|
110
|
+
end
|
111
|
+
true
|
112
|
+
end
|
113
|
+
end
|
114
|
+
others
|
115
|
+
end
|
40
116
|
|
41
|
-
|
42
|
-
|
117
|
+
def self.build_maps(count, match_array, translate, prefixes)
|
118
|
+
klcount = Hash.new(0)
|
119
|
+
mapvalues = Hash.new {|h, kl| # kl = key list
|
120
|
+
h.member?(kl) or h[kl] = Hash.new {|hv, kv|
|
121
|
+
hv.member?(kv) or hv[kv] = Hash.new(0)
|
122
|
+
}
|
43
123
|
}
|
44
|
-
# pp match_array
|
45
124
|
|
46
|
-
|
125
|
+
count.select {|o, _n| Hash === o}.each do |o, _n|
|
126
|
+
kl = o.keys.sort
|
127
|
+
klcount[kl] += 1
|
128
|
+
v = o.values_at(*kl)
|
129
|
+
z = kl.zip(v)
|
130
|
+
z.each do |k1, v1|
|
131
|
+
mapvalues[kl][k1][v1] += 1
|
132
|
+
end
|
133
|
+
end
|
134
|
+
repkl = klcount.select {|kl, n| n > 1}.sort_by {|kl, n| -n} # sort not needed
|
135
|
+
# fudge here -- ignore single children even in parent selection
|
136
|
+
|
137
|
+
# parent selection
|
138
|
+
|
139
|
+
klparents = {}
|
140
|
+
repkl.map do |kl, n|
|
141
|
+
klparent = {}
|
142
|
+
mapvalues[kl].each do |k1, v1|
|
143
|
+
repv = v1.to_a.select{|k2, v2| v2 > (n+3)/2} # low-hanging ->
|
144
|
+
if repv != [] # -> should be zero or one of them
|
145
|
+
# pp [k1, repv]
|
146
|
+
# The k1 values are those that go into the head arrays
|
147
|
+
# first .first: low-hanging, second .first: repeated member value
|
148
|
+
klparent[k1] = repv.first.first
|
149
|
+
end
|
150
|
+
end
|
151
|
+
# pp klparent
|
152
|
+
if klparent != {}
|
153
|
+
ix = prefixes.size
|
154
|
+
prefixes << klparent
|
155
|
+
constant_keys = Set[*klparent.keys]
|
156
|
+
variable_keys = Set[*kl] - constant_keys
|
157
|
+
klparents[kl] = [
|
158
|
+
klparent, argref(ix), constant_keys, variable_keys.to_a
|
159
|
+
]
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
klmatch = {}
|
164
|
+
|
165
|
+
count.select {|o, _n| Hash === o}.each do |o, _n|
|
166
|
+
kl = o.keys.sort
|
167
|
+
klp, ref, constant_keys, variable_kl = klparents[kl]
|
168
|
+
if klp # split off parent, return to common code then
|
169
|
+
oouter = o
|
170
|
+
o = o.reject {|k| constant_keys.include? k}
|
171
|
+
kl = variable_kl
|
172
|
+
end
|
173
|
+
if kl.size > 1 && (klp || klcount[kl] > 1) # TODO: tune
|
174
|
+
unless ix = klmatch[kl]
|
175
|
+
ix = prefixes.size
|
176
|
+
prefixes << CBOR::Tagged.new(RECORD_TAG, kl)
|
177
|
+
klmatch[kl] = ix
|
178
|
+
end
|
179
|
+
packed = translate[o] = CBOR::Tagged.new(argref(ix), o.values_at(*kl)) # needs packing
|
180
|
+
end
|
181
|
+
if packed && klp
|
182
|
+
translate[oouter] = CBOR::Tagged.new(ref, packed) # merge Hashes
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
end
|
187
|
+
|
188
|
+
CBOR_PACKED_HEX = ENV["CBOR_PACKED_HEX"]
|
189
|
+
CBOR_PACKED_MAPS = ENV["CBOR_PACKED_MAPS"]
|
190
|
+
|
191
|
+
def self.from_item(item)
|
192
|
+
count, match_array = build_match_array(item)
|
193
|
+
|
194
|
+
# TODO: the below needs to be done with arrays and (hard!) maps as well
|
47
195
|
# do this on the reverse to find common suffixes
|
196
|
+
|
197
|
+
translate = {} # map (sub)items to their arg-packed versions
|
198
|
+
prefixes = [] # provisional prefix table used in the above
|
199
|
+
|
48
200
|
# select all strings (ignoring reference counts) and sort them
|
49
201
|
strings = count.select {|k, v| String === k}.map(&:first).sort
|
50
202
|
if strings != []
|
51
|
-
|
52
|
-
|
53
|
-
[
|
54
|
-
|
203
|
+
strings = build_bytes_from_hex(strings, count, match_array, item, translate, prefixes) if CBOR_PACKED_HEX
|
204
|
+
if strings != []
|
205
|
+
string_common = strings[1..-1].zip(strings).map{ |y, x|
|
206
|
+
l = x.chars.zip(y.chars).take_while{|a, b| a == b}.length # should be bytes
|
207
|
+
[x, l]
|
208
|
+
} << [strings[-1], 0]
|
209
|
+
end
|
55
210
|
# string_common: list of strings/counts of number of /bytes/ matching with next
|
56
211
|
# pp string_common
|
57
212
|
end
|
58
|
-
translate = {}
|
59
|
-
prefixes = []
|
60
213
|
if string_common
|
214
|
+
|
61
215
|
prefix_stack = [[0, false]] # sentinel
|
62
216
|
pos = 0 # mirror prefix_stack[-1][0]
|
63
|
-
tag_no = REF_TAG
|
217
|
+
tag_no = argref(prefixes.size) # REF_TAG
|
64
218
|
string_common.each do |s, l|
|
65
219
|
if l > pos + 2 + $compression_hack
|
66
220
|
if t = prefix_stack[-1][1] # if we still have a prefix left
|
@@ -71,8 +225,9 @@ module CBOR
|
|
71
225
|
prefix_stack << [l, tag_no]
|
72
226
|
pos = l
|
73
227
|
tag_no += 1
|
74
|
-
tag_no = 225 if tag_no == REF_TAG+1
|
228
|
+
tag_no = 225 if tag_no == REF_TAG+1 # skip 224, as we always can use 6 here
|
75
229
|
tag_no = 28704 if tag_no == 256
|
230
|
+
tag_no = 1879052288 if tag_no == 32768
|
76
231
|
end
|
77
232
|
if t = prefix_stack[-1][1] # if we still have a viable prefix left
|
78
233
|
translate[s] = CBOR::Tagged.new(t, s[pos..-1])
|
@@ -87,8 +242,45 @@ module CBOR
|
|
87
242
|
end
|
88
243
|
|
89
244
|
end
|
90
|
-
# pp translate
|
91
|
-
#
|
245
|
+
# pp [:TRANSLATE, translate]
|
246
|
+
# pp [:PREFIXES, prefixes]
|
247
|
+
# Note that we didn't compute a suffix table to mix in
|
248
|
+
|
249
|
+
build_maps(count, match_array, translate, prefixes) if CBOR_PACKED_MAPS
|
250
|
+
|
251
|
+
match_array_size = match_array.size
|
252
|
+
mixed = match_array_size + prefixes.size <= STRAIGHT_11_SIZE
|
253
|
+
if mixed && match_array_size != 0
|
254
|
+
# We need to shift by match_array_size
|
255
|
+
translate = Hash[translate.map {|k, v|
|
256
|
+
PP.pp v, STDERR
|
257
|
+
newtag = v.tag
|
258
|
+
if newtag == REF_TAG
|
259
|
+
newtag = 224
|
260
|
+
end
|
261
|
+
# this works only if <= STRAIGHT_11_SIZE (above)
|
262
|
+
newtag += match_array_size
|
263
|
+
[k, CBOR::Tagged.new(newtag, v.value)]
|
264
|
+
}]
|
265
|
+
prefixes = prefixes.map {|p|
|
266
|
+
if CBOR::Tagged === p
|
267
|
+
case p.tag
|
268
|
+
when REF_TAG
|
269
|
+
CBOR::Tagged.new(224 + match_array_size, p.value)
|
270
|
+
when 224..255
|
271
|
+
CBOR::Tagged.new(p.tag + match_array_size, p.value)
|
272
|
+
else # this works only if <= STRAIGHT_11_SIZE (above)
|
273
|
+
p
|
274
|
+
end
|
275
|
+
else
|
276
|
+
p
|
277
|
+
end
|
278
|
+
}
|
279
|
+
# pp translate
|
280
|
+
# pp prefixes
|
281
|
+
end
|
282
|
+
|
283
|
+
# Check match_array for direct entries of an arg-packed string
|
92
284
|
match_array = match_array.map do |v|
|
93
285
|
if r = translate[v]
|
94
286
|
# puts "*** replacing #{v.inspect} by #{r.inspect}"
|
@@ -97,18 +289,18 @@ module CBOR
|
|
97
289
|
v
|
98
290
|
end
|
99
291
|
end
|
100
|
-
|
101
|
-
|
102
|
-
new(match_array, prefixes, [], translate)
|
292
|
+
|
293
|
+
new(match_array, prefixes, translate, mixed)
|
103
294
|
end
|
104
|
-
def initialize(match_array,
|
295
|
+
def initialize(match_array, argument_array, translate, mixed)
|
296
|
+
@mixed = mixed
|
105
297
|
@hit = translate
|
106
298
|
# XXX: make sure we don't overwrite the existing prefix compression values!
|
107
299
|
# (this should really be done downwards, ...) 16 x 1, 160 x 2, (512-48) x 3
|
108
300
|
match_array[0...16].each_with_index do |o, i|
|
109
301
|
@hit[o] = CBOR::Simple.new(i)
|
110
302
|
end
|
111
|
-
# if m = match_array[16...128]
|
303
|
+
# if m = match_array[16...128] # no allocation for simple(16...128)
|
112
304
|
# m.each_with_index do |o, i|
|
113
305
|
# @hit[o] = CBOR::Simple.new(i + 128)
|
114
306
|
# end
|
@@ -124,49 +316,48 @@ module CBOR
|
|
124
316
|
@hit[k] = r
|
125
317
|
end
|
126
318
|
end
|
127
|
-
#
|
319
|
+
# warn [:HIT, @hit['688921AF59455E4D35D2FFE5FD21CA0598D42374'.xeh]].inspect
|
128
320
|
@match_array = match_array
|
129
321
|
# @prefix = {} -- do that later
|
130
|
-
@
|
131
|
-
@suffix_array = suffix_array
|
322
|
+
@argument_array = argument_array
|
132
323
|
end
|
133
324
|
def has(o)
|
325
|
+
# warn [:HIT1].inspect if o == '688921AF59455E4D35D2FFE5FD21CA0598D42374'.xeh
|
134
326
|
@hit[o]
|
135
327
|
end
|
136
328
|
def pack(pa)
|
137
|
-
#
|
138
|
-
|
329
|
+
pa = pa.to_packed_cbor1(self) # should also sort by frequency...
|
330
|
+
if @mixed
|
331
|
+
mixed_array = @match_array + @argument_array
|
332
|
+
CBOR::Tagged.new(MIXED_PACKED_TAG, [mixed_array, pa])
|
333
|
+
else
|
334
|
+
CBOR::Tagged.new(PACKED_TAG, [@match_array, @argument_array, pa])
|
335
|
+
end
|
139
336
|
end
|
140
337
|
end
|
141
338
|
|
142
339
|
class Unpacker
|
143
|
-
def initialize(match_array,
|
340
|
+
def initialize(match_array, argument_array)
|
144
341
|
@simple_array = match_array[0...16]
|
145
342
|
@tagged_array = match_array[16..-1]
|
146
343
|
# index with 2i for i >= 0 or ~2i for i < 0
|
147
344
|
# no map as we need to populate in progress
|
148
|
-
# pp
|
149
|
-
@
|
150
|
-
|
151
|
-
@suffix_array = []
|
152
|
-
suffix_array.each {|x| @prefix_array << x.to_unpacked_cbor1(self)}
|
153
|
-
# XXX order? -- must do lazily!
|
345
|
+
# pp argument_array
|
346
|
+
@argument_array = []
|
347
|
+
@raw_argument_array = argument_array
|
154
348
|
end
|
155
349
|
def unsimple(sv)
|
156
|
-
@simple_array[sv]
|
350
|
+
@simple_array[sv].to_unpacked_cbor1(self)
|
157
351
|
end
|
158
352
|
def untag(i)
|
159
353
|
# @tagged_array[(i << 1) ^ (i >> 63)]
|
160
354
|
ix = (i << 1) ^ (i >> 63)
|
161
355
|
ret = @tagged_array[ix]
|
162
356
|
# warn "** UNTAG i=#{i} ix=#{ix} ret=#{ret}"
|
163
|
-
ret
|
357
|
+
ret.to_unpacked_cbor1(self)
|
164
358
|
end
|
165
359
|
def unprefix(n)
|
166
|
-
@
|
167
|
-
end
|
168
|
-
def unsuffix(n)
|
169
|
-
@suffix_array[n]
|
360
|
+
@argument_array[n] ||= @raw_argument_array[n].to_unpacked_cbor1(self)
|
170
361
|
end
|
171
362
|
end
|
172
363
|
|
@@ -209,6 +400,16 @@ module CBOR
|
|
209
400
|
# add checks
|
210
401
|
lhs = to_unpacked_cbor1(unpacker)
|
211
402
|
rhs = other.to_unpacked_cbor1(unpacker)
|
403
|
+
if CBOR::Tagged === rhs
|
404
|
+
case rhs.tag
|
405
|
+
when HEX_LC_TAG
|
406
|
+
rhs = rhs.value.unpack("H*").first
|
407
|
+
when HEX_UC_TAG
|
408
|
+
rhs = rhs.value.unpack("H*").first.upcase
|
409
|
+
else
|
410
|
+
fail ArgumentError, "*** String#packed_merge: unknown tag #{rhs.tag} on rhs"
|
411
|
+
end
|
412
|
+
end
|
212
413
|
begin
|
213
414
|
lhs + rhs
|
214
415
|
rescue => detail
|
@@ -268,8 +469,13 @@ module CBOR
|
|
268
469
|
end
|
269
470
|
end
|
270
471
|
def packed_merge(other, unpacker)
|
271
|
-
|
272
|
-
|
472
|
+
rhs = other
|
473
|
+
until Hash === rhs
|
474
|
+
rhso = rhs
|
475
|
+
rhs = rhs.to_unpacked_cbor1(unpacker)
|
476
|
+
fail ArgumentError, "*** In #{self.inspect}, cannot further unpack #{rhs.inspect}" unless rhso != rhs
|
477
|
+
end
|
478
|
+
to_unpacked_cbor1(unpacker).merge rhs
|
273
479
|
end
|
274
480
|
end
|
275
481
|
Hash.send(:include, Hash_Packed_CBOR)
|
@@ -284,11 +490,17 @@ module CBOR
|
|
284
490
|
if tag == PACKED_TAG
|
285
491
|
# check that this really is an array
|
286
492
|
# warn value.to_yaml
|
287
|
-
ma,
|
288
|
-
unpacker = Unpacker.new(ma,
|
493
|
+
ma, aa, pv = value
|
494
|
+
unpacker = Unpacker.new(ma, aa)
|
495
|
+
pv.to_unpacked_cbor1(unpacker)
|
496
|
+
elsif tag == MIXED_PACKED_TAG
|
497
|
+
# check that this really is an array
|
498
|
+
# warn value.to_yaml
|
499
|
+
args, pv = value
|
500
|
+
unpacker = Unpacker.new(args, args)
|
289
501
|
pv.to_unpacked_cbor1(unpacker)
|
290
502
|
else
|
291
|
-
fail "
|
503
|
+
fail "*** Don't know how to unpack tag #{tag}"
|
292
504
|
end
|
293
505
|
end
|
294
506
|
def to_unpacked_cbor1(unpacker)
|
@@ -319,9 +531,30 @@ module CBOR
|
|
319
531
|
CBOR::Tagged.new(tag, value.to_unpacked_cbor1(unpacker))
|
320
532
|
end
|
321
533
|
end
|
534
|
+
def packed_merge(other, unpacker)
|
535
|
+
# tag must be a function tag -- TODO add standin tag decoder for lhs (value)
|
536
|
+
case tag
|
537
|
+
when RECORD_TAG
|
538
|
+
rhs = other.to_unpacked_cbor1(unpacker)
|
539
|
+
raise ArgumentError, "*** need arrays for record tag (#{
|
540
|
+
value.inspect}, #{rhs.inspect})" unless Array === value && Array === rhs
|
541
|
+
n = value.size - rhs.size
|
542
|
+
if n > 0
|
543
|
+
rhs += [UNDEFINED] * n
|
544
|
+
elsif n < 0
|
545
|
+
raise ArgumentError, "*** too many values (#{rhs.inspect
|
546
|
+
}) for record tag keys (#{value.inspect
|
547
|
+
})" unless Array === value && Array === rhs
|
548
|
+
end
|
549
|
+
Hash[value.zip(rhs).select{|k, v| v != UNDEFINED}]
|
550
|
+
else
|
551
|
+
raise ArgumentError, "*** function tag #{tag} not implemented"
|
552
|
+
end
|
553
|
+
end
|
554
|
+
|
322
555
|
def to_packed_cbor1(packer = Packer.from_item(self))
|
323
556
|
if c = packer.has(self)
|
324
|
-
c
|
557
|
+
c.to_packed_cbor1(packer)
|
325
558
|
else
|
326
559
|
CBOR::Tagged.new(tag, value.to_packed_cbor1(packer))
|
327
560
|
end
|
data/test/exa2r1.rb
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
require 'cbor-pure'
|
2
|
+
require 'cbor-packed'
|
3
|
+
require 'treetop'
|
4
|
+
require 'cbor-diag-parser'
|
5
|
+
require 'cbor-diagnostic'
|
6
|
+
require 'json'
|
7
|
+
require 'yaml'
|
8
|
+
|
9
|
+
input = DATA.read
|
10
|
+
|
11
|
+
|
12
|
+
parser = CBOR_DIAGParser.new
|
13
|
+
if result = parser.parse(input)
|
14
|
+
o = result.to_rb.to_unpacked_cbor
|
15
|
+
puts o.cbor_diagnostic
|
16
|
+
else
|
17
|
+
puts "*** can't parse #{i}"
|
18
|
+
puts "*** #{parser.failure_reason}"
|
19
|
+
end
|
20
|
+
|
21
|
+
# ruby -I ../lib exa2r.rb | jq > .out1
|
22
|
+
# jq < ~/big/wot-thing-description/test-bed/data/plugfest/2017-05-osaka/MyLED_f.jsonld > .out2
|
23
|
+
# ruby .check
|
24
|
+
# => true
|
25
|
+
|
26
|
+
|
27
|
+
__END__
|
28
|
+
|
29
|
+
1113([/shared/["name", "@type", "links", "href", "mediaType",
|
30
|
+
/ 0 1 2 3 4 /
|
31
|
+
"application/json", "outputData", {"valueType": {"type":
|
32
|
+
/ 5 6 7 /
|
33
|
+
"number"}}, ["Property"], "writable", "valueType", "type"],
|
34
|
+
/ 8 9 10 11 /
|
35
|
+
/prefix/ ["http://192.168.1.10", 6("3:8445/wot/thing"),
|
36
|
+
/ 6 225 /
|
37
|
+
225("/MyLED/"), 226("rgbValue"), "rgbValue",
|
38
|
+
/ 226 227 228 /
|
39
|
+
{simple(6): simple(7), simple(9): true, simple(1): simple(8)}],
|
40
|
+
/ 229 /
|
41
|
+
/rump/ {simple(0): "MyLED",
|
42
|
+
"interactions": [
|
43
|
+
229({simple(2): [{simple(3): 227("Red"), simple(4): simple(5)}],
|
44
|
+
simple(0): 228("Red")}),
|
45
|
+
229({simple(2): [{simple(3): 227("Green"), simple(4): simple(5)}],
|
46
|
+
simple(0): 228("Green")}),
|
47
|
+
229({simple(2): [{simple(3): 227("Blue"), simple(4): simple(5)}],
|
48
|
+
simple(0): 228("Blue")}),
|
49
|
+
229({simple(2): [{simple(3): 227("White"), simple(4): simple(5)}],
|
50
|
+
simple(0): "rgbValueWhite"}),
|
51
|
+
{simple(2): [{simple(3): 226("ledOnOff"), simple(4): simple(5)}],
|
52
|
+
simple(6): {simple(10): {simple(11): "boolean"}}, simple(0):
|
53
|
+
"ledOnOff", simple(9): true, simple(1): simple(8)},
|
54
|
+
{simple(2): [{simple(3): 226("colorTemperatureChanged"),
|
55
|
+
simple(4): simple(5)}], simple(6): simple(7), simple(0):
|
56
|
+
"colorTemperatureChanged", simple(1): ["Event"]}],
|
57
|
+
simple(1): "Lamp", "id": "0", "base": 225(""),
|
58
|
+
"@context": 6("2:8444/wot/w3c-wot-td-context.jsonld")}])
|
data/test/test-packed.rb
CHANGED
@@ -35,16 +35,18 @@ puts "CBOR packed: #{cbp.length}"
|
|
35
35
|
File.write("/tmp/cbp", cbp)
|
36
36
|
File.write("/tmp/cbu", cb)
|
37
37
|
pad = CBOR.decode(cbp)
|
38
|
-
|
38
|
+
puts "--- packed decoded ---"
|
39
|
+
puts pad.to_yaml
|
39
40
|
up = pad.to_unpacked_cbor
|
40
|
-
pp up == jo
|
41
|
+
pp [:EQUAL, up == jo]
|
41
42
|
if up != jo
|
43
|
+
puts "--- not equal ---"
|
42
44
|
puts up.to_yaml
|
43
45
|
puts pad.to_yaml # get rid of unwanted sharing...
|
44
46
|
end
|
45
47
|
|
46
48
|
# puts "#{pa.value.map {|x| x.to_cbor.length}}"
|
47
|
-
puts pa.value[1].to_json
|
49
|
+
puts "pa.value[1].to_json: ", pa.value[1].to_json
|
48
50
|
|
49
51
|
exin = JSON.load(DATA)
|
50
52
|
exout = exin.to_packed_cbor
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cbor-packed
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Carsten Bormann
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2025-01-03 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: cbor-packed implements packed encoding for CBOR, RFC 7049 Section 3.9
|
14
14
|
email: cabo@tzi.org
|
@@ -20,6 +20,7 @@ files:
|
|
20
20
|
- lib/cbor-packed.rb
|
21
21
|
- test/exa2.rb
|
22
22
|
- test/exa2r.rb
|
23
|
+
- test/exa2r1.rb
|
23
24
|
- test/test-packed.rb
|
24
25
|
homepage: http://cbor.io/
|
25
26
|
licenses:
|
@@ -40,11 +41,12 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
40
41
|
- !ruby/object:Gem::Version
|
41
42
|
version: '0'
|
42
43
|
requirements: []
|
43
|
-
rubygems_version: 3.
|
44
|
+
rubygems_version: 3.5.14
|
44
45
|
signing_key:
|
45
46
|
specification_version: 4
|
46
47
|
summary: CBOR (Concise Binary Object Representation) packer
|
47
48
|
test_files:
|
48
49
|
- test/exa2.rb
|
49
50
|
- test/exa2r.rb
|
51
|
+
- test/exa2r1.rb
|
50
52
|
- test/test-packed.rb
|