gvariant 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (3) hide show
  1. checksums.yaml +7 -0
  2. data/lib/gvariant.rb +350 -0
  3. 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: