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.
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: