libbin 0.9.0

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: c632bd10fef318615e63edccbebd3b161ce7c9e3ccb5a2efec3b43bda3565cde
4
+ data.tar.gz: cd8853a5ca548a3221710d6388ecbd54f46cf9e3721410af7a1f581d115c738d
5
+ SHA512:
6
+ metadata.gz: bf807641924427087c89d3f3d89fc91c41a91cf2a6729bba0185592752d071fca322c3655b90912c288c7b3ce98a1a46db6d5471e5e4fd403f7a8570980547e9
7
+ data.tar.gz: acd847eb8f52ff55c7c1c92fe86fa6bf11cd20845189f6cd13957333b32feeda29bc620d9e8152d835aba2ba9ff45313357f7f75d54a7de126eb7c3d781ab9e9
data/LICENSE ADDED
@@ -0,0 +1,25 @@
1
+ BSD 2-Clause License
2
+
3
+ Copyright (c) 2018, Brice Videau
4
+ All rights reserved.
5
+
6
+ Redistribution and use in source and binary forms, with or without
7
+ modification, are permitted provided that the following conditions are met:
8
+
9
+ * Redistributions of source code must retain the above copyright notice, this
10
+ list of conditions and the following disclaimer.
11
+
12
+ * Redistributions in binary form must reproduce the above copyright notice,
13
+ this list of conditions and the following disclaimer in the documentation
14
+ and/or other materials provided with the distribution.
15
+
16
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
20
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
23
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
data/lib/libbin.rb ADDED
@@ -0,0 +1,358 @@
1
+ warn_level = $VERBOSE
2
+ $VERBOSE = nil
3
+ require 'float-formats'
4
+ $VERBOSE = warn_level
5
+
6
+ Flt::IEEE.binary :IEEE_binary16_pg, significand: 9, exponent: 6, bias: 47
7
+ Flt::IEEE.binary :IEEE_binary16_pg_BE, significand: 9, exponent: 6, bias: 47, endianness: :big_endian
8
+
9
+ require_relative 'libbin/alignment'
10
+ require_relative 'libbin/data_types'
11
+
12
+ module LibBin
13
+
14
+ @__big_architecture = [0x12345678].pack("i") == "\x12\x34\x56\x78"
15
+ @__big = nil
16
+
17
+ def self.default_big?
18
+ if @__big.nil?
19
+ @__big_architecture
20
+ else
21
+ @__big
22
+ end
23
+ end
24
+
25
+ class DataConverter
26
+ include Alignment
27
+
28
+ def inspect
29
+ to_s
30
+ end
31
+
32
+ attr_reader :__parent
33
+ attr_reader :__index
34
+ attr_reader :__iterator
35
+ attr_reader :__position
36
+ def __set_convert_type(input, output, input_big, output_big, parent, index)
37
+ @__input_big = input_big
38
+ @__output_big = output_big
39
+ @__input = input
40
+ @__output = output
41
+ @__parent = parent
42
+ @__index = index
43
+ @__position = input.tell
44
+ @__cur_position = @__position
45
+ end
46
+
47
+ def __set_size_type(position, parent, index)
48
+ @__parent = parent
49
+ @__index = index
50
+ @__position = position
51
+ @__cur_position = @__position
52
+ end
53
+
54
+ def __set_load_type(input, input_big, parent, index)
55
+ @__input_big = input_big
56
+ @__input = input
57
+ @__parent = parent
58
+ @__index = index
59
+ @__position = input.tell
60
+ @__cur_position = @__position
61
+ end
62
+
63
+ def __set_dump_type(output, output_big, parent, index)
64
+ @__output_big = output_big
65
+ @__output = output
66
+ @__parent = parent
67
+ @__index = index
68
+ @__position = output.tell
69
+ @__cur_position = @__position
70
+ end
71
+
72
+ def __unset_convert_type
73
+ @__input_big = nil
74
+ @__output_big = nil
75
+ @__input = nil
76
+ @__output = nil
77
+ @__parent = nil
78
+ @__index = nil
79
+ @__position = nil
80
+ @__cur_position = nil
81
+ end
82
+
83
+ def __unset_size_type
84
+ @__parent = nil
85
+ @__index = nil
86
+ @__position = nil
87
+ @__cur_position = nil
88
+ end
89
+
90
+ def __unset_load_type
91
+ @__input_big = nil
92
+ @__input = nil
93
+ @__parent = nil
94
+ @__index = nil
95
+ @__position = nil
96
+ @__cur_position = nil
97
+ end
98
+
99
+ def __unset_dump_type
100
+ @__output_big = nil
101
+ @__output = nil
102
+ @__parent = nil
103
+ @__index = nil
104
+ @__position = nil
105
+ @__cur_position = nil
106
+ end
107
+
108
+ def self.inherited(subclass)
109
+ subclass.instance_variable_set(:@fields, [])
110
+ end
111
+
112
+ def __decode_expression(sym)
113
+ case sym
114
+ when Proc
115
+ return sym.call
116
+ when String
117
+ exp = sym.gsub("..","__parent").gsub("\\",".")
118
+ return eval(exp)
119
+ else
120
+ return sym
121
+ end
122
+ end
123
+
124
+ def __decode_seek_offset(offset)
125
+ return nil unless offset
126
+ offset = __decode_expression(offset)
127
+ return false if offset == 0x0
128
+ @__cur_position = offset
129
+ @__input.seek(offset) if @__input
130
+ @__output.seek(offset) if @__output
131
+ offset
132
+ end
133
+
134
+ def __decode_condition(condition)
135
+ return true unless condition
136
+ __decode_expression(condition)
137
+ end
138
+
139
+ def __decode_count(count)
140
+ return 1 unless count
141
+ __decode_expression(count)
142
+ end
143
+
144
+ def __decode_type(type)
145
+ return __decode_expression(type)
146
+ end
147
+
148
+ def __decode_static_conditions(type, count, offset, sequence, condition)
149
+ @__offset = nil
150
+ @__condition = nil
151
+ @__type = nil
152
+ @__count = nil
153
+ unless sequence
154
+ @__offset = __decode_seek_offset(offset)
155
+ throw :ignored, nil if @__offset == false
156
+ @__condition = __decode_condition(condition)
157
+ throw :ignored, nil unless @__condition
158
+ @__type = __decode_type(type)
159
+ end
160
+ @__count = __decode_count(count)
161
+ end
162
+
163
+ def __decode_dynamic_conditions(type, offset, sequence, condition)
164
+ return true unless sequence
165
+ @__offset = nil
166
+ @__condition = nil
167
+ @__type = nil
168
+ @__offset = __decode_seek_offset(offset)
169
+ return false if @__offset == false
170
+ @__condition = __decode_condition(condition)
171
+ return false unless @__condition
172
+ @__type = __decode_type(type)
173
+ return true
174
+ end
175
+
176
+ def __restore_context
177
+ @__iterator = nil
178
+ @__type = nil
179
+ @__count = nil
180
+ @__offset = nil
181
+ @__condition = nil
182
+ end
183
+
184
+ def __convert_field(field, type, count, offset, sequence, condition)
185
+ __decode_static_conditions(type, count, offset, sequence, condition)
186
+ vs = @__count.times.collect do |it|
187
+ @__iterator = it
188
+ if __decode_dynamic_conditions(type, offset, sequence, condition)
189
+ @__type::convert(@__input, @__output, @__input_big, @__output_big, self, it)
190
+ else
191
+ nil
192
+ end
193
+ end
194
+ __restore_context
195
+ vs = vs.first unless count
196
+ vs
197
+ end
198
+
199
+ def __load_field(field, type, count, offset, sequence, condition)
200
+ __decode_static_conditions(type, count, offset, sequence, condition)
201
+ vs = @__count.times.collect do |it|
202
+ @__iterator = it
203
+ if __decode_dynamic_conditions(type, offset, sequence, condition)
204
+ @__type::load(@__input, @__input_big, self, it)
205
+ else
206
+ nil
207
+ end
208
+ end
209
+ __restore_context
210
+ vs = vs.first unless count
211
+ vs
212
+ end
213
+
214
+ def __dump_field(vs, field, type, count, offset, sequence, condition)
215
+ __decode_static_conditions(type, count, offset, sequence, condition)
216
+ vs = [vs] unless count
217
+ vs.each_with_index do |v, it|
218
+ @__iterator = it
219
+ if __decode_dynamic_conditions(type, offset, sequence, condition)
220
+ @__type::dump(v, @__output, @__output_big, self, it)
221
+ end
222
+ end
223
+ __restore_context
224
+ end
225
+
226
+ def __shape_field(vs, previous_offset, kind, field, type, count, offset, sequence, condition)
227
+ __decode_static_conditions(type, count, offset, sequence, condition)
228
+ vs = [vs] unless count
229
+ vs = vs.each_with_index.collect do |v, it|
230
+ @__iterator = it
231
+ if __decode_dynamic_conditions(type, offset, sequence, condition)
232
+ sh = @__type::shape(v, @__cur_position, self, it, kind)
233
+ @__cur_position = sh.last + 1 if sh.last && sh.last >= 0
234
+ sh
235
+ end
236
+ end
237
+ __restore_context
238
+ vs = vs.first unless count
239
+ vs
240
+ end
241
+
242
+ def __size(previous_offset = 0, parent = nil, index = nil)
243
+ __shape(previous_offset, parent, index, DataRange).size
244
+ end
245
+
246
+ def __shape(previous_offset = 0, parent = nil, index = nil, kind = DataShape)
247
+ __set_size_type(previous_offset, parent, index)
248
+ members = {}
249
+ self.class.instance_variable_get(:@fields).each { |name, type, *args|
250
+ begin
251
+ vs = send(name)
252
+ member = catch(:ignored) do
253
+ __shape_field(vs, previous_offset, kind, name, type, *args)
254
+ end
255
+ members[name] = member
256
+ rescue
257
+ STDERR.puts "#{self.class}: #{name}(#{type})"
258
+ raise
259
+ end
260
+ }
261
+ __unset_size_type
262
+ return nil if members.values.flatten.compact.size <= 0
263
+ kind::new(members)
264
+ end
265
+
266
+ def __convert_fields
267
+ self.class.instance_variable_get(:@fields).each { |name, type, *args|
268
+ begin
269
+ vs = catch(:ignored) do
270
+ __convert_field(name, type, *args)
271
+ end
272
+ send("#{name}=", vs)
273
+ rescue
274
+ STDERR.puts "#{self.class}: #{name}(#{type})"
275
+ raise
276
+ end
277
+ }
278
+ self
279
+ end
280
+
281
+ def __load_fields
282
+ self.class.instance_variable_get(:@fields).each { |name, type, *args|
283
+ begin
284
+ vs = catch(:ignored) do
285
+ __load_field(name, type, *args)
286
+ end
287
+ send("#{name}=", vs)
288
+ rescue
289
+ STDERR.puts "#{self.class}: #{name}(#{type})"
290
+ raise
291
+ end
292
+ }
293
+ self
294
+ end
295
+
296
+ def __dump_fields
297
+ self.class.instance_variable_get(:@fields).each { |name, type, *args|
298
+ begin
299
+ vs = send(name)
300
+ catch(:ignored) do
301
+ __dump_field(vs, name, type, *args)
302
+ end
303
+ rescue
304
+ STDERR.puts "#{self.class}: #{name}(#{type})"
305
+ raise
306
+ end
307
+ }
308
+ self
309
+ end
310
+
311
+ def __convert(input, output, input_big, output_big, parent = nil, index = nil)
312
+ __set_convert_type(input, output, input_big, output_big, parent, index)
313
+ __convert_fields
314
+ __unset_convert_type
315
+ self
316
+ end
317
+
318
+ def __load(input, input_big, parent = nil, index = nil)
319
+ __set_load_type(input, input_big, parent, index)
320
+ __load_fields
321
+ __unset_load_type
322
+ self
323
+ end
324
+
325
+ def __dump(output, output_big, parent = nil, index = nil)
326
+ __set_dump_type(output, output_big, parent, index)
327
+ __dump_fields
328
+ __unset_dump_type
329
+ self
330
+ end
331
+
332
+ def self.convert(input, output, input_big = LibBin::default_big?, output_big = !LibBin::default_big?, parent = nil, index = nil)
333
+ h = self::new
334
+ h.__convert(input, output, input_big, output_big, parent, index)
335
+ h
336
+ end
337
+
338
+ def self.load(input, input_big = LibBin::default_big?, parent = nil, index = nil)
339
+ h = self::new
340
+ h.__load(input, input_big, parent, index)
341
+ h
342
+ end
343
+
344
+ def self.dump(value, output, output_big = LibBin::default_big?, parent = nil, index = nil)
345
+ value.__dump(output, output_big, parent, index)
346
+ end
347
+
348
+ def self.size(value, previous_offset = 0, parent = nil, index = nil)
349
+ value.__shape(previous_offset, parent, index).size
350
+ end
351
+
352
+ def self.shape(value, previous_offset = 0, parent = nil, index = nil, kind = DataShape)
353
+ value.__shape(previous_offset, parent, index, kind = DataShape)
354
+ end
355
+
356
+ end
357
+
358
+ end
@@ -0,0 +1,14 @@
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
@@ -0,0 +1,416 @@
1
+ module LibBin
2
+
3
+ module RangeRefinement
4
+ refine Range do
5
+ def +(other)
6
+ Range::new(first <= other.first ? first : other.first,
7
+ last >= other.last ? last : other.last,
8
+ exclude_end?)
9
+ end
10
+ end
11
+ end
12
+
13
+ class DataShape
14
+ using RangeRefinement
15
+ attr_reader :range
16
+ attr_reader :members
17
+
18
+ def method_missing(m, *arg, &block)
19
+ return @members[m] if @members && @members[m]
20
+ super
21
+ end
22
+
23
+ def initialize(*args)
24
+ if args.length == 2
25
+ @range = Range::new(args[0], args[1])
26
+ @members = nil
27
+ else
28
+ @members = args[0]
29
+ @range = @members.values.flatten.compact.collect(&:range).reduce { |memo, obj| memo + obj }
30
+ end
31
+ end
32
+
33
+ def first
34
+ @range.first
35
+ end
36
+
37
+ def last
38
+ @range.last
39
+ end
40
+
41
+ def size
42
+ @range.size
43
+ end
44
+
45
+ end
46
+
47
+ class DataRange
48
+ using RangeRefinement
49
+ attr_reader :range
50
+
51
+ def initialize(*args)
52
+ if args.length == 2
53
+ @range = Range::new(args[0], args[1])
54
+ else
55
+ @range = args[0].values.flatten.compact.collect(&:range).reduce { |memo, obj| memo + obj }
56
+ end
57
+ end
58
+
59
+ def first
60
+ @range.first
61
+ end
62
+
63
+ def last
64
+ @range.last
65
+ end
66
+
67
+ def size
68
+ @range.size
69
+ end
70
+
71
+ end
72
+
73
+ class DataConverter
74
+
75
+ rl = lambda { |type, str|
76
+ str.unpack(type.to_s).first
77
+ }
78
+
79
+ sl = lambda { |type, value|
80
+ [value].pack(type.to_s)
81
+ }
82
+
83
+ l = lambda { |type|
84
+ [rl.curry[type], sl.curry[type]]
85
+ }
86
+
87
+ SCALAR_TYPES = {
88
+ :c => [:Int8, :int8],
89
+ :C => [:UInt8, :uint8],
90
+ :s => [:Int16, :int16],
91
+ :"s<" => [:Int16_LE, :int16_le],
92
+ :"s>" => [:Int16_BE, :int16_be],
93
+ :S => [:UInt16, :uint16],
94
+ :"S<" => [:UInt16_LE, :uint16_le],
95
+ :"S>" => [:UInt16_BE, :uint16_be],
96
+ :v => [:UInt16_LE, :uint16_le],
97
+ :n => [:UInt16_BE, :uint16_be],
98
+ :l => [:Int32, :int32],
99
+ :"l<" => [:Int32_LE, :int32_le],
100
+ :"l>" => [:Int32_BE, :int32_be],
101
+ :L => [:UInt32, :uint32],
102
+ :"L<" => [:UInt32_LE, :uint32_le],
103
+ :"L>" => [:UInt32_BE, :uint32_be],
104
+ :V => [:UInt32_LE, :uint32_le],
105
+ :N => [:UInt32_BE, :uint32_be],
106
+ :q => [:Int64, :int64],
107
+ :"q<" => [:Int64_LE, :int64_le],
108
+ :"q>" => [:Int64_BE, :int64_be],
109
+ :Q => [:UInt64, :uint64],
110
+ :"Q<" => [:UInt64_LE, :uint64_le],
111
+ :"Q>" => [:UInt64_BE, :uint64_be],
112
+ :F => [:Flt, :float],
113
+ :e => [:Flt_LE, :float_le],
114
+ :g => [:Flt_BE, :float_be],
115
+ :D => [:Double, :double],
116
+ :E => [:Double_LE, :double_le],
117
+ :G => [:Double_BE, :double_be],
118
+ :half => [:Half, :half],
119
+ :half_le => [:Half_LE, :half_le],
120
+ :half_be => [:Half_BE, :half_be],
121
+ :pghalf => [:PGHalf, :pghalf],
122
+ :pghalf_le => [:PGHalf_LE, :pghalf_le],
123
+ :pghalf_be => [:PGHalf_BE, :pghalf_be]
124
+ }
125
+
126
+ DATA_SIZES = Hash::new { |h,k|
127
+ if k.kind_of?(Symbol) && m = k.match(/a(\d+)/)
128
+ m[1].to_i
129
+ else
130
+ nil
131
+ end
132
+ }
133
+ DATA_SIZES.merge!( {
134
+ :c => 1,
135
+ :C => 1,
136
+ :s => 2,
137
+ :"s<" => 2,
138
+ :"s>" => 2,
139
+ :S => 2,
140
+ :"S<" => 2,
141
+ :"S>" => 2,
142
+ :v => 2,
143
+ :n => 2,
144
+ :l => 4,
145
+ :"l<" => 4,
146
+ :"l>" => 4,
147
+ :L => 4,
148
+ :"L<" => 4,
149
+ :"L>" => 4,
150
+ :V => 4,
151
+ :N => 4,
152
+ :q => 8,
153
+ :"q<" => 8,
154
+ :"q>" => 8,
155
+ :Q => 8,
156
+ :"Q<" => 8,
157
+ :"Q>" => 8,
158
+ :F => 4,
159
+ :e => 4,
160
+ :g => 4,
161
+ :D => 8,
162
+ :E => 8,
163
+ :G => 8,
164
+ :"a*" => -1,
165
+ :half => 2,
166
+ :half_le => 2,
167
+ :half_be => 2,
168
+ :pghalf => 2,
169
+ :pghalf_le => 2,
170
+ :pghalf_be => 2
171
+ } )
172
+ DATA_ENDIAN = {
173
+ true => Hash::new { |h,k|
174
+ if k.kind_of?(Symbol) && m = k.match(/a(\d+)/)
175
+ l[k]
176
+ else
177
+ nil
178
+ end
179
+ },
180
+ false => Hash::new { |h,k|
181
+ if k.kind_of?(Symbol) && m = k.match(/a(\d+)/)
182
+ l[k]
183
+ else
184
+ nil
185
+ end
186
+ }
187
+ }
188
+
189
+ DATA_ENDIAN[true].merge!( {
190
+ :c => l["c"],
191
+ :C => l["C"],
192
+ :s => l["s>"],
193
+ :"s<" => l["s<"],
194
+ :"s>" => l["s>"],
195
+ :S => l["S>"],
196
+ :"S<" => l["S<"],
197
+ :"S>" => l["S>"],
198
+ :v => l["v"],
199
+ :n => l["n"],
200
+ :l => l["l>"],
201
+ :"l<" => l["l<"],
202
+ :"l>" => l["l>"],
203
+ :L => l["L>"],
204
+ :"L<" => l["L<"],
205
+ :"L>" => l["L>"],
206
+ :V => l["V"],
207
+ :N => l["N"],
208
+ :q => l["q>"],
209
+ :"q<" => l["q<"],
210
+ :"q>" => l["q>"],
211
+ :Q => l["Q>"],
212
+ :"Q<" => l["Q<"],
213
+ :"Q>" => l["Q>"],
214
+ :F => l["g"],
215
+ :e => l["e"],
216
+ :g => l["g"],
217
+ :D => l["G"],
218
+ :E => l["E"],
219
+ :G => l["G"],
220
+ :"a*" => l["a*"],
221
+ :half => [ lambda { |str| Flt::IEEE_binary16_BE::from_bytes(str).to(Float) },
222
+ lambda { |v| Flt::IEEE_binary16_BE::new(v).to_bytes } ],
223
+ :half_le => [ lambda { |str| Flt::IEEE_binary16_LE::from_bytes(str).to(Float) },
224
+ lambda { |v| Flt::IEEE_binary16_LE::new(v).to_bytes } ],
225
+ :half_be => [ lambda { |str| Flt::IEEE_binary16_BE::from_bytes(str).to(Float) },
226
+ lambda { |v| Flt::IEEE_binary16_BE::new(v).to_bytes } ],
227
+ :pghalf => [ lambda { |str| Flt::IEEE_binary16_pg_BE::from_bytes(str).to(Float) },
228
+ lambda { |v| Flt::IEEE_binary16_pg_BE::new(v).to_bytes } ],
229
+ :pghalf_le => [ lambda { |str| Flt::IEEE_binary16_pg_LE::from_bytes(str).to(Float) },
230
+ lambda { |v| Flt::IEEE_binary16_pg_LE::new(v).to_bytes } ],
231
+ :pghalf_be => [ lambda { |str| Flt::IEEE_binary16_pg_BE::from_bytes(str).to(Float) },
232
+ lambda { |v| Flt::IEEE_binary16_pg_BE::new(v).to_bytes } ]
233
+ } )
234
+ DATA_ENDIAN[false].merge!( {
235
+ :c => l["c"],
236
+ :C => l["C"],
237
+ :s => l["s<"],
238
+ :"s<" => l["s<"],
239
+ :"s>" => l["s>"],
240
+ :S => l["S<"],
241
+ :"S<" => l["S<"],
242
+ :"S>" => l["S>"],
243
+ :v => l["v"],
244
+ :n => l["n"],
245
+ :l => l["l<"],
246
+ :"l<" => l["l<"],
247
+ :"l>" => l["l>"],
248
+ :L => l["L<"],
249
+ :"L<" => l["L<"],
250
+ :"L>" => l["L>"],
251
+ :V => l["V"],
252
+ :N => l["N"],
253
+ :q => l["q<"],
254
+ :"q<" => l["q<"],
255
+ :"q>" => l["q>"],
256
+ :Q => l["Q<"],
257
+ :"Q<" => l["Q<"],
258
+ :"Q>" => l["Q>"],
259
+ :F => l["e"],
260
+ :e => l["e"],
261
+ :g => l["g"],
262
+ :D => l["E"],
263
+ :E => l["E"],
264
+ :G => l["G"],
265
+ :"a*" => l["a*"],
266
+ :half => [ lambda { |str| Flt::IEEE_binary16::from_bytes(str).to(Float) },
267
+ lambda { |v| Flt::IEEE_binary16::new(v).to_bytes } ],
268
+ :half_le => [ lambda { |str| Flt::IEEE_binary16_LE::from_bytes(str).to(Float) },
269
+ lambda { |v| Flt::IEEE_binary16_LE::new(v).to_bytes } ],
270
+ :half_be => [ lambda { |str| Flt::IEEE_binary16_BE::from_bytes(str).to(Float) },
271
+ lambda { |v| Flt::IEEE_binary16_BE::new(v).to_bytes } ],
272
+ :pghalf => [ lambda { |str| Flt::IEEE_binary16_pg::from_bytes(str).to(Float) },
273
+ lambda { |v| Flt::IEEE_binary16_pg::new(v).to_bytes } ],
274
+ :pghalf_le => [ lambda { |str| Flt::IEEE_binary16_pg_LE::from_bytes(str).to(Float) },
275
+ lambda { |v| Flt::IEEE_binary16_pg_LE::new(v).to_bytes } ],
276
+ :pghalf_be => [ lambda { |str| Flt::IEEE_binary16_pg_BE::from_bytes(str).to(Float) },
277
+ lambda { |v| Flt::IEEE_binary16_pg_BE::new(v).to_bytes } ]
278
+ } )
279
+
280
+
281
+ class Scalar
282
+
283
+ def self.size(*args)
284
+ @size
285
+ end
286
+
287
+ def self.shape(value, previous_offset = 0, _ = nil, _ = nil, kind = DataShape)
288
+ kind::new(previous_offset, previous_offset + @size - 1)
289
+ end
290
+
291
+ def self.init(symbol)
292
+ @symbol = symbol
293
+ @size = DATA_SIZES[symbol]
294
+ @rl_be, @sl_be = DATA_ENDIAN[true][symbol]
295
+ @rl_le, @sl_be = DATA_ENDIAN[false][symbol]
296
+ end
297
+
298
+ def self.load(input, input_big = LibBin::default_big?, _ = nil, _ = nil)
299
+ str = input.read(@size)
300
+ input_big ? @rl_be[str] : @rl_le[str]
301
+ end
302
+
303
+ def self.dump(value, output, output_big = LibBin::default_big?, _ = nil, _ = nil)
304
+ str = (output_big ? @sl_be[value] : @sl_le[value])
305
+ output.write(str)
306
+ end
307
+
308
+ def self.convert(input, output, input_big = LibBin::default_big?, output_big = !LibBin::default_big, _ = nil, _ = nil)
309
+ str = input.read(@size)
310
+ value = (input_big ? @rl_be[str] : @rl_le[str])
311
+ str = (output_big ? @sl_be[value] : @sl_le[value])
312
+ output.write(str)
313
+ value
314
+ end
315
+
316
+ end
317
+
318
+ class Str < Scalar
319
+
320
+ def self.load(input, input_big = LibBin::default_big?, _ = nil, _ = nil)
321
+ str = (@size < 0 ? input.readline("\x00") : input.read(@size))
322
+ input_big ? @rl_be[str] : @rl_le[str]
323
+ end
324
+
325
+ def self.convert(input, output, input_big = LibBin::default_big?, output_big = !LibBin::default_big, _ = nil, _ = nil)
326
+ str = (@size < 0 ? input.readline("\x00") : input.read(@size))
327
+ value = (input_big ? @rl_be[str] : @rl_le[str])
328
+ str = (output_big ? @sl_be[value] : @sl_le[value])
329
+ output.write(str)
330
+ value
331
+ end
332
+
333
+ def self.shape(value, previous_offset = 0, _ = nil, _ = nil, kind = DataShape)
334
+ if @size < 0
335
+ kind::new(previous_offset, previous_offset + value.size - 1)
336
+ else
337
+ kind::new(previous_offset, previous_offset + @size - 1)
338
+ end
339
+ end
340
+
341
+ end
342
+
343
+ def self.register_field(field, type, count: nil, offset: nil, sequence: false, condition: nil)
344
+ if type.kind_of?(Symbol)
345
+ if type[0] == 'a'
346
+ c = Class::new(Str) do init(sym) end
347
+ @fields.push([field, c, count, offset, sequence, condition])
348
+ else
349
+ @fields.push([field, const_get(SCALAR_TYPES[type][0]), count, offset, sequence, condition])
350
+ end
351
+ else
352
+ @fields.push([field, type, count, offset, sequence, condition])
353
+ end
354
+ attr_accessor field
355
+ end
356
+
357
+ def self.create_scalar_type(symbol)
358
+ klassname, name = SCALAR_TYPES[symbol]
359
+ eval <<EOF
360
+ class #{klassname} < Scalar
361
+ init(#{symbol.inspect})
362
+ end
363
+
364
+ def self.#{name}(field, count: nil, offset: nil, sequence: false, condition: nil)
365
+ @fields.push([field, #{klassname}, count, offset, sequence, condition])
366
+ attr_accessor field
367
+ end
368
+ EOF
369
+ end
370
+
371
+ create_scalar_type(:c)
372
+ create_scalar_type(:C)
373
+ create_scalar_type(:s)
374
+ create_scalar_type(:"s<")
375
+ create_scalar_type(:"s>")
376
+ create_scalar_type(:S)
377
+ create_scalar_type(:"S<")
378
+ create_scalar_type(:"S>")
379
+ create_scalar_type(:l)
380
+ create_scalar_type(:"l<")
381
+ create_scalar_type(:"l>")
382
+ create_scalar_type(:L)
383
+ create_scalar_type(:"L<")
384
+ create_scalar_type(:"L>")
385
+ create_scalar_type(:q)
386
+ create_scalar_type(:"q<")
387
+ create_scalar_type(:"q>")
388
+ create_scalar_type(:Q)
389
+ create_scalar_type(:"Q<")
390
+ create_scalar_type(:"Q>")
391
+ create_scalar_type(:F)
392
+ create_scalar_type(:e)
393
+ create_scalar_type(:g)
394
+ create_scalar_type(:D)
395
+ create_scalar_type(:E)
396
+ create_scalar_type(:G)
397
+ create_scalar_type(:half)
398
+ create_scalar_type(:half_le)
399
+ create_scalar_type(:half_be)
400
+ create_scalar_type(:pghalf)
401
+ create_scalar_type(:pghalf_le)
402
+ create_scalar_type(:pghalf_be)
403
+
404
+ def self.string( field, length = nil, count: nil, offset: nil, sequence: false, condition: nil)
405
+ sym = (length ? :"a#{length}" : :"a*")
406
+ c = Class::new(Str) do
407
+ init(sym)
408
+ end
409
+ @fields.push([field, c, count, offset, sequence, condition])
410
+ attr_accessor field
411
+ end
412
+
413
+
414
+ end
415
+
416
+ end
data/libbin.gemspec ADDED
@@ -0,0 +1,14 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = 'libbin'
3
+ s.version = "0.9.0"
4
+ s.author = "Brice Videau"
5
+ s.email = "brice.videau@imag.fr"
6
+ s.homepage = "https://github.com/kerilk/libbin"
7
+ s.summary = "Library for loading and converting binary files"
8
+ s.description = "Read, write and convert Binary data in Ruby."
9
+ s.files = Dir[ 'libbin.gemspec', 'LICENSE', 'lib/**/*.rb' ]
10
+ s.has_rdoc = false
11
+ s.license = 'BSD-2-Clause'
12
+ s.required_ruby_version = '>= 2.0.0'
13
+ s.add_dependency 'float-formats', '~> 0.3', '>=0.3.0'
14
+ end
metadata ADDED
@@ -0,0 +1,68 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: libbin
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.9.0
5
+ platform: ruby
6
+ authors:
7
+ - Brice Videau
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2018-12-12 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: float-formats
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '0.3'
20
+ - - ">="
21
+ - !ruby/object:Gem::Version
22
+ version: 0.3.0
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - "~>"
28
+ - !ruby/object:Gem::Version
29
+ version: '0.3'
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: 0.3.0
33
+ description: Read, write and convert Binary data in Ruby.
34
+ email: brice.videau@imag.fr
35
+ executables: []
36
+ extensions: []
37
+ extra_rdoc_files: []
38
+ files:
39
+ - LICENSE
40
+ - lib/libbin.rb
41
+ - lib/libbin/alignment.rb
42
+ - lib/libbin/data_types.rb
43
+ - libbin.gemspec
44
+ homepage: https://github.com/kerilk/libbin
45
+ licenses:
46
+ - BSD-2-Clause
47
+ metadata: {}
48
+ post_install_message:
49
+ rdoc_options: []
50
+ require_paths:
51
+ - lib
52
+ required_ruby_version: !ruby/object:Gem::Requirement
53
+ requirements:
54
+ - - ">="
55
+ - !ruby/object:Gem::Version
56
+ version: 2.0.0
57
+ required_rubygems_version: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ requirements: []
63
+ rubyforge_project:
64
+ rubygems_version: 2.7.6
65
+ signing_key:
66
+ specification_version: 4
67
+ summary: Library for loading and converting binary files
68
+ test_files: []