libbin 1.0.5 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/lib/libbin.rb CHANGED
@@ -1,391 +1,113 @@
1
- module LibBin
2
- end
3
1
  require "libbin_c.so"
4
2
 
5
- require_relative 'libbin/alignment'
6
3
  require_relative 'libbin/data_types'
7
4
 
5
+ # Container module, handles the global state default endianness and error output.
8
6
  module LibBin
9
7
 
10
- @__big_architecture = [0x12345678].pack("i") == "\x12\x34\x56\x78"
11
- @__big = nil
8
+ @big = [0x12345678].pack("i") == "\x12\x34\x56\x78"
9
+ @output = $stderr
12
10
 
13
- def self.default_big?
14
- if @__big.nil?
15
- @__big_architecture
16
- else
17
- @__big
18
- end
11
+ class << self
12
+ attr_accessor :big
13
+ attr_accessor :output
19
14
  end
20
15
 
21
- class DataConverter
22
- include Alignment
16
+ # Returns true the default endianness is big
17
+ def self.default_big?
18
+ @big
19
+ end
23
20
 
21
+ class Structure
22
+
23
+ # @!parse
24
+ # attr_accessor :__parent
25
+ # attr_accessor :__index
26
+ # attr_accessor :__position
27
+ # attr_accessor :__cur_position
28
+ # attr_accessor :__input
29
+ # attr_accessor :__output
30
+ # attr_accessor :__input_big
31
+ # attr_accessor :__output_big
32
+ #
33
+ # attr_accessor :__offset
34
+ # attr_accessor :__condition
35
+ # attr_accessor :__type
36
+ # attr_accessor :__length
37
+ # attr_accessor :__count
38
+ # attr_accessor :__iterator
39
+ # attr_accessor :__value
40
+ #
41
+ # # @method __dump_fields
42
+ # # Dump fields according to the internal state of +self+
43
+ # # @return [Structure] self
44
+
45
+ # @!visibility private
24
46
  def inspect
25
47
  to_s
26
48
  end
27
49
 
28
- attr_reader :__parent
29
- attr_reader :__index
30
- attr_reader :__iterator
31
- attr_reader :__position
32
- def __set_convert_type(input, output, input_big, output_big, parent, index)
33
- @__input_big = input_big
34
- @__output_big = output_big
35
- @__input = input
36
- @__output = output
37
- @__parent = parent
38
- @__index = index
39
- @__position = input.tell
40
- @__cur_position = @__position
41
- end
42
-
43
- def __set_size_type(position, parent, index)
44
- @__parent = parent
45
- @__index = index
46
- @__position = position
47
- @__cur_position = @__position
48
- end
49
-
50
- def __set_load_type(input, input_big, parent, index)
51
- @__input_big = input_big
52
- @__input = input
53
- @__parent = parent
54
- @__index = index
55
- @__position = input.tell
56
- @__cur_position = @__position
57
- end
58
-
59
- def __set_dump_type(output, output_big, parent, index)
60
- @__output_big = output_big
61
- @__output = output
62
- @__parent = parent
63
- @__index = index
64
- @__position = output.tell
65
- @__cur_position = @__position
66
- end
67
-
68
- def __unset_convert_type
69
- @__input_big = nil
70
- @__output_big = nil
71
- @__input = nil
72
- @__output = nil
73
- @__parent = nil
74
- @__index = nil
75
- @__position = nil
76
- @__cur_position = nil
77
- end
78
-
79
- def __unset_size_type
80
- @__parent = nil
81
- @__index = nil
82
- @__position = nil
83
- @__cur_position = nil
84
- end
85
-
86
- def __unset_load_type
87
- @__input_big = nil
88
- @__input = nil
89
- @__parent = nil
90
- @__index = nil
91
- @__position = nil
92
- @__cur_position = nil
93
- end
94
-
95
- def __unset_dump_type
96
- @__output_big = nil
97
- @__output = nil
98
- @__parent = nil
99
- @__index = nil
100
- @__position = nil
101
- @__cur_position = nil
102
- end
103
-
50
+ # @!visibility private
104
51
  def self.inherited(subclass)
105
52
  subclass.instance_variable_set(:@fields, [])
106
53
  end
107
54
 
108
- def __decode_expression(sym)
109
- case sym
110
- when Proc
111
- return sym.call
112
- when String
113
- exp = sym.gsub("..","__parent").gsub("\\",".")
114
- return eval(exp)
115
- else
116
- return sym
117
- end
118
- end
119
-
120
- def __decode_seek_offset(offset, relative_offset)
121
- return nil unless offset
122
- offset = __decode_expression(offset)
123
- return false if offset == 0x0
124
- offset += @__position if relative_offset
125
- @__cur_position = offset
126
- @__input.seek(offset) if @__input
127
- @__output.seek(offset) if @__output
128
- offset
129
- end
130
-
131
- def __decode_condition(condition)
132
- return true unless condition
133
- __decode_expression(condition)
134
- end
135
-
136
- def __decode_count(count)
137
- return 1 unless count
138
- __decode_expression(count)
139
- end
140
-
141
- def __decode_type(type)
142
- return __decode_expression(type)
143
- end
144
-
145
- def __decode_length(length)
146
- __decode_expression(length)
147
- end
148
-
149
- def __decode_static_conditions(field)
150
- @__offset = nil
151
- @__condition = nil
152
- @__type = nil
153
- @__length = nil
154
- @__count = nil
155
- unless field.sequence?
156
- @__offset = __decode_seek_offset(field.offset, field.relative_offset?)
157
- throw :ignored, nil if @__offset == false
158
- @__condition = __decode_condition(field.condition)
159
- throw :ignored, nil unless @__condition
160
- @__type = __decode_type(field.type)
161
- @__length = __decode_length(field.length)
162
- end
163
- @__count = __decode_count(field.count)
164
- end
165
-
166
- def __decode_dynamic_conditions(field)
167
- return true unless field.sequence?
168
- @__offset = nil
169
- @__condition = nil
170
- @__type = nil
171
- @__length = nil
172
- @__offset = __decode_seek_offset(field.offset, field.relative_offset?)
173
- return false if @__offset == false
174
- @__condition = __decode_condition(field.condition)
175
- return false unless @__condition
176
- @__type = __decode_type(field.type)
177
- @__length = __decode_length(field.length)
178
- return true
55
+ # Returns the size of the structure
56
+ # @param offset [Integer] position in the stream
57
+ # @param parent [Structure] if given, parent structure
58
+ # @param index [Integer] index if part of a repeated field inside parent
59
+ # @return [Integer] size of the structure
60
+ def __size(offset = 0, parent = nil, index = nil)
61
+ __shape(offset, parent, index, DataRange).size
179
62
  end
180
63
 
181
- def __restore_context
182
- @__iterator = nil
183
- @__type = nil
184
- @__length = nil
185
- @__count = nil
186
- @__offset = nil
187
- @__condition = nil
64
+ # Returns the alignement of the structure
65
+ # @return [Integer] alignment of the structure
66
+ def self.align
67
+ return @always_align if @always_align
68
+ align = @fields.collect(&:align).select { |v| v }.max
69
+ align = 0 unless align
70
+ align
188
71
  end
189
72
 
190
- def __convert_field(field)
191
- __decode_static_conditions(field)
192
- vs = @__count.times.collect do |it|
193
- @__iterator = it
194
- if __decode_dynamic_conditions(field)
195
- @__type::convert(@__input, @__output, @__input_big, @__output_big, self, it, @__length)
196
- else
197
- nil
198
- end
199
- end
200
- __restore_context
201
- vs = vs.first unless field.count
202
- vs
203
- end
204
-
205
- def __load_field(field)
206
- __decode_static_conditions(field)
207
- vs = @__count.times.collect do |it|
208
- @__iterator = it
209
- if __decode_dynamic_conditions(field)
210
- @__type::load(@__input, @__input_big, self, it, @__length)
211
- else
212
- nil
213
- end
214
- end
215
- __restore_context
216
- vs = vs.first unless field.count
217
- vs
218
- end
219
-
220
- def __dump_field(vs, field)
221
- __decode_static_conditions(field)
222
- vs = [vs] unless field.count
223
- vs.each_with_index do |v, it|
224
- @__iterator = it
225
- if __decode_dynamic_conditions(field)
226
- @__type::dump(v, @__output, @__output_big, self, it, @__length)
227
- end
228
- end
229
- __restore_context
230
- end
231
-
232
- def __shape_field(vs, previous_offset, kind, field)
233
- __decode_static_conditions(field)
234
- vs = [vs] unless field.count
235
- vs = vs.each_with_index.collect do |v, it|
236
- @__iterator = it
237
- if __decode_dynamic_conditions(field)
238
- sh = @__type::shape(v, @__cur_position, self, it, kind, @__length)
239
- @__cur_position = sh.last + 1 if sh.last && sh.last >= 0
240
- sh
241
- end
242
- end
243
- __restore_context
244
- vs = vs.first unless field.count
245
- vs
246
- end
247
-
248
- def __size(previous_offset = 0, parent = nil, index = nil)
249
- __shape(previous_offset, parent, index, DataRange).size
250
- end
251
-
252
- def __shape(previous_offset = 0, parent = nil, index = nil, kind = DataShape)
253
- __set_size_type(previous_offset, parent, index)
254
- members = {}
255
- self.class.instance_variable_get(:@fields).each { |field|
256
- begin
257
- vs = send(field.name)
258
- member = catch(:ignored) do
259
- __shape_field(vs, previous_offset, kind, field)
260
- end
261
- members[field.name] = member
262
- rescue
263
- STDERR.puts "#{self.class}: #{field.name}(#{field.type})"
264
- raise
265
- end
266
- }
267
- __unset_size_type
268
- return nil if members.values.flatten.compact.size <= 0
269
- kind::new(members)
270
- end
271
-
272
- def __convert_fields
273
- self.class.instance_variable_get(:@fields).each { |field|
274
- begin
275
- vs = catch(:ignored) do
276
- __convert_field(field)
277
- end
278
- send("#{field.name}=", vs)
279
- rescue
280
- STDERR.puts "#{self.class}: #{field.name}(#{field.type})"
281
- raise
282
- end
283
- }
284
- self
285
- end
286
-
287
- def __load_fields
288
- self.class.instance_variable_get(:@fields).each { |field|
289
- begin
290
- vs = catch(:ignored) do
291
- __load_field(field)
292
- end
293
- send("#{field.name}=", vs)
294
- rescue
295
- STDERR.puts "#{self.class}: #{field.name}(#{field.type})"
296
- raise
297
- end
298
- }
299
- self
300
- end
301
-
302
- def __dump_fields
303
- self.class.instance_variable_get(:@fields).each { |field|
304
- begin
305
- vs = send(field.name)
306
- catch(:ignored) do
307
- __dump_field(vs, field)
308
- end
309
- rescue
310
- STDERR.puts "#{self.class}: #{field.name}(#{field.type})"
311
- raise
312
- end
313
- }
314
- self
315
- end
316
-
317
- def __convert(input, output, input_big, output_big, parent = nil, index = nil)
318
- __set_convert_type(input, output, input_big, output_big, parent, index)
319
- __convert_fields
320
- __unset_convert_type
321
- self
322
- end
323
-
324
- def __load(input, input_big, parent = nil, index = nil)
325
- __set_load_type(input, input_big, parent, index)
326
- __load_fields
327
- __unset_load_type
328
- self
329
- end
330
-
331
- def __dump(output, output_big, parent = nil, index = nil)
332
- __set_dump_type(output, output_big, parent, index)
333
- __dump_fields
334
- __unset_dump_type
335
- self
336
- end
337
-
338
- def self.convert(input, output, input_big = LibBin::default_big?, output_big = !LibBin::default_big?, parent = nil, index = nil, length = nil)
339
- if length
340
- length.times.collect {
341
- h = self::new
342
- h.__load(input, input_big, parent, index)
343
- }
73
+ # Set the structure as needing to always be aligned
74
+ # @param align [true, Integer] if true use the fields' maximum alignment
75
+ # @return align
76
+ def self.set_always_align(align)
77
+ if align == true
78
+ @always_align = @fields.collect(&:align).select { |v| v }.max
79
+ @always_align = 0 unless align
344
80
  else
345
- h = self::new
346
- h.__convert(input, output, input_big, output_big, parent, index)
81
+ raise "alignement must be a power of 2" if align && (align - 1) & align != 0
82
+ @always_align = align
347
83
  end
84
+ align
348
85
  end
349
86
 
350
- def self.load(input, input_big = LibBin::default_big?, parent = nil, index = nil, length = nil)
351
- if length
352
- length.times.collect {
353
- h = self::new
354
- h.__load(input, input_big, parent, index)
355
- }
356
- else
357
- h = self::new
358
- h.__load(input, input_big, parent, index)
359
- end
87
+ class << self
88
+ alias always_align= set_always_align
89
+ attr_reader :always_align
90
+ attr_reader :fields
360
91
  end
361
92
 
362
- def self.dump(value, output, output_big = LibBin::default_big?, parent = nil, index = nil, length = nil)
93
+ # Returns the size of a structure
94
+ # @param value [Structure,Array<Structure>] field or array of field to get the size of
95
+ # @param offset [Integer] position in the stream
96
+ # @param parent [Structure] if given, parent structure
97
+ # @param index [Integer] index if part of a repeated field inside parent
98
+ # @param length [Integer] if given, the length of the vector
99
+ def self.size(value, offset = 0, parent = nil, index = nil, length = nil)
363
100
  if length
364
- length.times.collect { |i|
365
- value[i].__dump(output, output_big, parent, index)
366
- }
367
- value
101
+ shape(value, offset, parent, index, length).size
368
102
  else
369
- value.__dump(output, output_big, parent, index)
103
+ value.__shape(offset, parent, index).size
370
104
  end
371
105
  end
372
106
 
373
- def self.size(value, previous_offset = 0, parent = nil, index = nil, length = nil)
374
- if length
375
- shape(value, previous_offset, parent, index, length).size
376
- else
377
- value.__shape(previous_offset, parent, index).size
378
- end
379
- end
380
-
381
- def self.shape(value, previous_offset = 0, parent = nil, index = nil, kind = DataShape, length = nil)
382
- if length
383
- kind::new(length.times.collect { |i|
384
- value[i].__shape(previous_offset, parent, index, kind)
385
- })
386
- else
387
- value.__shape(previous_offset, parent, index, kind)
388
- end
107
+ # Return the structure class fields
108
+ # @return [Array<Field>]
109
+ def __fields
110
+ return self.class.fields
389
111
  end
390
112
 
391
113
  end
data/libbin.gemspec CHANGED
@@ -1,14 +1,13 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = 'libbin'
3
- s.version = "1.0.5"
3
+ s.version = "2.0.0"
4
4
  s.author = "Brice Videau"
5
- s.email = "brice.videau@imag.fr"
5
+ s.email = "brice.videau@gmail.com"
6
6
  s.homepage = "https://github.com/kerilk/libbin"
7
7
  s.summary = "Library for loading and converting binary files"
8
8
  s.description = "Read, write and convert Binary data in Ruby."
9
9
  s.files = Dir[ 'libbin.gemspec', 'LICENSE', 'lib/**/*.rb', 'ext/libbin/extconf.rb', 'ext/libbin/*.c', 'ext/libbin/*.h' ]
10
10
  s.extensions << 'ext/libbin/extconf.rb'
11
- s.has_rdoc = false
12
11
  s.license = 'BSD-2-Clause'
13
12
  s.required_ruby_version = '>= 2.0.0'
14
13
  s.add_dependency 'float-formats', '~> 0.3', '>=0.3.0'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: libbin
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.5
4
+ version: 2.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brice Videau
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-09-22 00:00:00.000000000 Z
11
+ date: 2021-11-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: float-formats
@@ -31,21 +31,24 @@ dependencies:
31
31
  - !ruby/object:Gem::Version
32
32
  version: 0.3.0
33
33
  description: Read, write and convert Binary data in Ruby.
34
- email: brice.videau@imag.fr
34
+ email: brice.videau@gmail.com
35
35
  executables: []
36
36
  extensions:
37
37
  - ext/libbin/extconf.rb
38
38
  extra_rdoc_files: []
39
39
  files:
40
40
  - LICENSE
41
+ - ext/libbin/data_types.c
42
+ - ext/libbin/data_types.h
41
43
  - ext/libbin/extconf.rb
42
44
  - ext/libbin/half.c
43
45
  - ext/libbin/half.h
44
46
  - ext/libbin/libbin_c.c
47
+ - ext/libbin/libbin_c.h
48
+ - ext/libbin/libbin_endian.h
45
49
  - ext/libbin/pghalf.c
46
50
  - ext/libbin/pghalf.h
47
51
  - lib/libbin.rb
48
- - lib/libbin/alignment.rb
49
52
  - lib/libbin/data_types.rb
50
53
  - libbin.gemspec
51
54
  homepage: https://github.com/kerilk/libbin
@@ -67,8 +70,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
67
70
  - !ruby/object:Gem::Version
68
71
  version: '0'
69
72
  requirements: []
70
- rubyforge_project:
71
- rubygems_version: 2.7.6
73
+ rubygems_version: 3.1.2
72
74
  signing_key:
73
75
  specification_version: 4
74
76
  summary: Library for loading and converting binary files
@@ -1,14 +0,0 @@
1
- module LibBin
2
-
3
- module Alignment
4
-
5
- def align(val, alignment)
6
- remainder = val % alignment
7
- val += alignment - remainder if remainder > 0
8
- val
9
- end
10
- private :align
11
-
12
- end
13
-
14
- end