gvariant 0.0.1
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 +7 -0
- data/lib/gvariant.rb +350 -0
- metadata +45 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 474158feb1e3e77fa47defab829eb37de58133ef
|
4
|
+
data.tar.gz: 54927059812535d1b6f5da8106ff777860a2b047
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: e96e389ed9f1417987e59a8983a2764612a669628c7518c9a7f8d919fbd81593aca23b59e522240a1a16859c5aa9025ed467f8cbb74703dfa036c64c681535eb
|
7
|
+
data.tar.gz: 93c4b94b1ad02d59edd8682713b380721928396a63d53fdc4d710c71be48bc5650a2040f0e1df4a5e9a0f767ef437d3c8ae385b46d4d0dd336c9f61708ebcf75
|
data/lib/gvariant.rb
ADDED
@@ -0,0 +1,350 @@
|
|
1
|
+
class GVariantBasicType
|
2
|
+
attr_reader :id, :fixed_size, :default_value, :alignment
|
3
|
+
|
4
|
+
def initialize(id, unpack, alignment, fixed_size, default_value)
|
5
|
+
@id, @unpack, @alignment, @fixed_size, @default_value =
|
6
|
+
id, unpack, alignment, fixed_size, default_value
|
7
|
+
end
|
8
|
+
|
9
|
+
def align(i)
|
10
|
+
(i + @alignment - 1) & ~(@alignment - 1)
|
11
|
+
end
|
12
|
+
|
13
|
+
def read(buf)
|
14
|
+
return @default_value if @fixed_size && buf.length != @fixed_size
|
15
|
+
buf.unpack("#{@unpack}").first
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
class GVariantByteType < GVariantBasicType
|
20
|
+
def initialize
|
21
|
+
super('y', 'C', 1, 1, 0)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
class GVariantSignedShortType < GVariantBasicType
|
26
|
+
def initialize
|
27
|
+
super('n', 's', 2, 2, 0)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
class GVariantUnsignedShortType < GVariantBasicType
|
32
|
+
def initialize
|
33
|
+
super('q', 'S', 2, 2, 0)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
class GVariantSignedIntType < GVariantBasicType
|
38
|
+
def initialize
|
39
|
+
super('i', 'l', 4, 4, 0)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
class GVariantUnsignedIntType < GVariantBasicType
|
44
|
+
def initialize
|
45
|
+
super('u', 'L', 4, 4, 0)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
class GVariantSignedLongType < GVariantBasicType
|
50
|
+
def initialize
|
51
|
+
super('x', 'q', 8, 8, 0)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
class GVariantUnsignedLongType < GVariantBasicType
|
56
|
+
def initialize
|
57
|
+
super('t', 'Q', 8, 8, 0)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
class GVariantDoubleType < GVariantBasicType
|
62
|
+
def initialize
|
63
|
+
super('d', 'd', 8, 8, 0.0)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
class GVariantBooleanType < GVariantBasicType
|
68
|
+
def initialize
|
69
|
+
super('b', 'C', 1, 1, false)
|
70
|
+
end
|
71
|
+
|
72
|
+
def read(buf)
|
73
|
+
b = super(buf)
|
74
|
+
b != false && b != 0
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
class GVariantStringType < GVariantBasicType
|
79
|
+
def initialize(id)
|
80
|
+
super(id, 'Z*', 1, nil, '')
|
81
|
+
end
|
82
|
+
|
83
|
+
def read(buf)
|
84
|
+
return @default_value if (buf.length == 0 || buf[buf.length - 1] != "\x00")
|
85
|
+
buf.unpack("Z*").first
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
class GVariantMaybeType < GVariantBasicType
|
90
|
+
def initialize(id, maybe_element)
|
91
|
+
super(id, nil, maybe_element.alignment, nil, nil)
|
92
|
+
@element = maybe_element
|
93
|
+
end
|
94
|
+
|
95
|
+
def read(buf)
|
96
|
+
l = buf.length
|
97
|
+
|
98
|
+
# Nothing
|
99
|
+
return nil if l == 0
|
100
|
+
|
101
|
+
# Just
|
102
|
+
if (@element.fixed_size)
|
103
|
+
return nil if l != @element.fixed_size
|
104
|
+
@element.read(buf)
|
105
|
+
else
|
106
|
+
@element.read(buf[0..l - 1])
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
class GVariantVariantType < GVariantBasicType
|
112
|
+
def initialize
|
113
|
+
super('v', nil, 8, nil, { type: '()', value: {} })
|
114
|
+
end
|
115
|
+
|
116
|
+
def read(buf)
|
117
|
+
value, sep, type = buf[0..buf.length - 1].rpartition("\x00")
|
118
|
+
{ type: type, value: GVariant.read(type, value) }
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
class GVariantOffsetType < GVariantBasicType
|
123
|
+
|
124
|
+
def initialize(id, alignment, default_value)
|
125
|
+
@offset_size = nil
|
126
|
+
super(id, nil, alignment, nil, default_value)
|
127
|
+
end
|
128
|
+
|
129
|
+
def read_offset(buf, n)
|
130
|
+
l = buf.length
|
131
|
+
|
132
|
+
if @offset_size.nil?
|
133
|
+
if (l < 0xff)
|
134
|
+
@offset_size = 1
|
135
|
+
@offset_unpack = 'C'
|
136
|
+
elsif (l <= 0xffff)
|
137
|
+
@offset_size = 2
|
138
|
+
@offset_unpack = 'S'
|
139
|
+
elsif (l < 0xffffffff)
|
140
|
+
@offset_size = 4
|
141
|
+
@offset_unpack = 'L'
|
142
|
+
else
|
143
|
+
raise ArgumentError.new("Offset range too big.")
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
buf.unpack("@#{l + @offset_size * n}#{@offset_unpack}")[0]
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
class GVariantDictionaryType < GVariantOffsetType
|
152
|
+
def initialize(id, key_element, value_element)
|
153
|
+
super(id, [ key_element.alignment, value_element.alignment ].max,
|
154
|
+
[ key_element.default_value, value_element.default_value ])
|
155
|
+
|
156
|
+
@key_element = key_element
|
157
|
+
@value_element = value_element
|
158
|
+
|
159
|
+
if key_element.fixed_size && value_element.fixed_size
|
160
|
+
@fixed_size = value_element.align(key_element.fixed_size) + value_element.fixed_size
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
def read(buf)
|
165
|
+
return @default_value if @fixed_size && buf.length != @fixed_size
|
166
|
+
|
167
|
+
if @key_element.fixed_size
|
168
|
+
key_end = @key_element.fixed_size
|
169
|
+
value_end = buf.length
|
170
|
+
else
|
171
|
+
key_end = read_offset(buf, -1)
|
172
|
+
value_end = buf.length - @offset_size
|
173
|
+
end
|
174
|
+
|
175
|
+
key = @key_element.read(buf[0..key_end - 1]).to_sym
|
176
|
+
value = @value_element.read(buf[@value_element.align(key_end)..value_end - 1])
|
177
|
+
|
178
|
+
Hash[key, value]
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
class GVariantArrayType < GVariantOffsetType
|
183
|
+
def initialize(id, array_element)
|
184
|
+
super(id, array_element.alignment, [])
|
185
|
+
@element = array_element
|
186
|
+
end
|
187
|
+
|
188
|
+
def read(buf)
|
189
|
+
size = buf.length
|
190
|
+
|
191
|
+
if size == 0
|
192
|
+
return @element.is_a?(GVariantDictionaryType) ? {} : @default_value
|
193
|
+
end
|
194
|
+
|
195
|
+
values = []
|
196
|
+
c = 0
|
197
|
+
|
198
|
+
if (@element.fixed_size)
|
199
|
+
return [] if (size % @element.fixed_size != 0)
|
200
|
+
n = size / @element.fixed_size
|
201
|
+
|
202
|
+
n.times do
|
203
|
+
values << @element.read(buf[c, @element.fixed_size])
|
204
|
+
c += @element.fixed_size
|
205
|
+
end
|
206
|
+
else
|
207
|
+
n = (size - read_offset(buf, -1)) / @offset_size
|
208
|
+
|
209
|
+
n.times do |i|
|
210
|
+
o = read_offset(buf, -n + i)
|
211
|
+
values << @element.read(buf[c..o - 1])
|
212
|
+
c = @element.align(o)
|
213
|
+
end
|
214
|
+
end
|
215
|
+
|
216
|
+
values
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
220
|
+
class GVariantTupleType < GVariantOffsetType
|
221
|
+
def initialize(id, elements)
|
222
|
+
super(id, 1, [])
|
223
|
+
@elements = elements
|
224
|
+
@fixed_size = 0
|
225
|
+
|
226
|
+
elements.each do |element|
|
227
|
+
if element.fixed_size
|
228
|
+
unless @fixed_size.nil?
|
229
|
+
@fixed_size = element.align(@fixed_size + element.fixed_size)
|
230
|
+
end
|
231
|
+
else
|
232
|
+
@fixed_size = nil
|
233
|
+
end
|
234
|
+
|
235
|
+
if element.alignment > @alignment
|
236
|
+
@alignment = element.alignment
|
237
|
+
end
|
238
|
+
|
239
|
+
@default_value << element.default_value
|
240
|
+
end
|
241
|
+
|
242
|
+
@fixed_size = 1 if @fixed_size == 0
|
243
|
+
|
244
|
+
if @fixed_size
|
245
|
+
@fixed_size = align(@fixed_size)
|
246
|
+
end
|
247
|
+
end
|
248
|
+
|
249
|
+
def read(buf)
|
250
|
+
return @default_value if @fixed_size && buf.length != @fixed_size
|
251
|
+
|
252
|
+
cur_offset = 0
|
253
|
+
c = 0
|
254
|
+
|
255
|
+
@elements.map do |element|
|
256
|
+
c = element.align(c)
|
257
|
+
|
258
|
+
if element.fixed_size
|
259
|
+
n = c + element.fixed_size
|
260
|
+
elsif element != @elements.last
|
261
|
+
cur_offset -= 1
|
262
|
+
n = read_offset(buf, cur_offset)
|
263
|
+
else
|
264
|
+
read_offset(buf, 0)
|
265
|
+
n = buf.length - @offset_size * -cur_offset
|
266
|
+
end
|
267
|
+
|
268
|
+
v = element.read(buf[c..n - 1])
|
269
|
+
c = n
|
270
|
+
v
|
271
|
+
end
|
272
|
+
end
|
273
|
+
end
|
274
|
+
|
275
|
+
class GVariant
|
276
|
+
|
277
|
+
def initialize(typestr, buffer)
|
278
|
+
@typestr, @buffer = typestr, buffer
|
279
|
+
end
|
280
|
+
|
281
|
+
def self.next_type(signature, index)
|
282
|
+
|
283
|
+
case signature[index]
|
284
|
+
when 'y'
|
285
|
+
GVariantByteType.new
|
286
|
+
when 'n'
|
287
|
+
GVariantSignedShortType.new
|
288
|
+
when 'q'
|
289
|
+
GVariantUnsignedShortType.new
|
290
|
+
when 'i'
|
291
|
+
GVariantSignedIntType.new
|
292
|
+
when 'u'
|
293
|
+
GVariantUnsignedIntType.new
|
294
|
+
when 'x'
|
295
|
+
GVariantSignedLongType.new
|
296
|
+
when 't'
|
297
|
+
GVariantUnsignedLongType.new
|
298
|
+
when 'd'
|
299
|
+
GVariantDoubleType.new
|
300
|
+
when 'b'
|
301
|
+
GVariantBooleanType.new
|
302
|
+
when 's', 'g', 'o'
|
303
|
+
GVariantStringType.new(signature[index])
|
304
|
+
when 'v'
|
305
|
+
GVariantVariantType.new
|
306
|
+
when 'm'
|
307
|
+
maybe_element = next_type(signature, index + 1)
|
308
|
+
raise ArgumentError.new("Invalid type string") unless maybe_element
|
309
|
+
GVariantMaybeType.new(signature[index, maybe_element.id.length + 1], maybe_element)
|
310
|
+
when 'a'
|
311
|
+
array_element = next_type(signature, index + 1)
|
312
|
+
raise ArgumentError.new("Invalid type string") unless array_element
|
313
|
+
GVariantArrayType.new(signature[index, array_element.id.length + 1], array_element)
|
314
|
+
when '{'
|
315
|
+
key_element = next_type(signature, index + 1)
|
316
|
+
value_element = next_type(signature, index + 1 + key_element.id.length)
|
317
|
+
raise ArgumentError.new("Invalid type string") unless key_element && value_element
|
318
|
+
GVariantDictionaryType.new(signature[index, key_element.id.length + value_element.id.length + 2], key_element, value_element)
|
319
|
+
when '('
|
320
|
+
sig_end = index + 1
|
321
|
+
elements = []
|
322
|
+
|
323
|
+
while signature[sig_end] != ')' do
|
324
|
+
e = next_type(signature, sig_end)
|
325
|
+
sig_end += e.id.length
|
326
|
+
elements << e
|
327
|
+
end
|
328
|
+
|
329
|
+
GVariantTupleType.new(signature[index..sig_end], elements)
|
330
|
+
end
|
331
|
+
end
|
332
|
+
|
333
|
+
def self.parse_type(str)
|
334
|
+
type = next_type(str, 0)
|
335
|
+
|
336
|
+
if type.nil? || type.id.length != str.length
|
337
|
+
raise ArgumentError.new("Invalid type string: #{str}")
|
338
|
+
end
|
339
|
+
|
340
|
+
type
|
341
|
+
end
|
342
|
+
|
343
|
+
def self.read(typestr, buffer)
|
344
|
+
buffer = buffer.pack("C*") if buffer.is_a? Array
|
345
|
+
buffer.freeze if RUBY_VERSION >= '2.1.0'
|
346
|
+
type = parse_type(typestr)
|
347
|
+
type.read(buffer)
|
348
|
+
end
|
349
|
+
|
350
|
+
end
|
metadata
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: gvariant
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Daniel Mack
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2016-06-10 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description: A simple reader and writer for the GVariant serialization format
|
14
|
+
email: github@zonque.org
|
15
|
+
executables: []
|
16
|
+
extensions: []
|
17
|
+
extra_rdoc_files: []
|
18
|
+
files:
|
19
|
+
- lib/gvariant.rb
|
20
|
+
homepage: http://rubygems.org/gems/gvariant
|
21
|
+
licenses:
|
22
|
+
- LGPL-3.0
|
23
|
+
metadata: {}
|
24
|
+
post_install_message:
|
25
|
+
rdoc_options: []
|
26
|
+
require_paths:
|
27
|
+
- lib
|
28
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
29
|
+
requirements:
|
30
|
+
- - ">="
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '0'
|
33
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
34
|
+
requirements:
|
35
|
+
- - ">="
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
requirements: []
|
39
|
+
rubyforge_project:
|
40
|
+
rubygems_version: 2.5.1
|
41
|
+
signing_key:
|
42
|
+
specification_version: 4
|
43
|
+
summary: GVariant reader and writer
|
44
|
+
test_files: []
|
45
|
+
has_rdoc:
|