cbor-packed 0.1.5 → 0.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/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
|