binary_parser 1.1.0 → 1.1.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 +4 -4
- data/.gitignore +1 -0
- data/lib/binary_parser/version.rb +1 -1
- data/lib/binary_parser.rb +5 -3
- data/lib/general_class/abstract_binary.rb +103 -39
- data/lib/general_class/binary_manipulate_function.rb +54 -0
- data/lib/general_class/buffered_stream.rb +21 -0
- data/lib/loop_list.rb +4 -5
- data/lib/nameless_template_maker.rb +9 -0
- data/lib/scope.rb +0 -5
- data/lib/stream_template_base.rb +63 -35
- data/lib/structure_definition.rb +34 -19
- data/lib/template_base.rb +27 -12
- data/unit_test/general_class/test_abstract_binary.rb +48 -3
- data/unit_test/general_class/test_binary_manipulate_function.rb +64 -0
- data/unit_test/general_class/test_bit_position.rb +1 -1
- data/unit_test/general_class/test_condition.rb +1 -1
- data/unit_test/general_class/test_expression.rb +1 -1
- data/unit_test/test_structure_definition.rb +26 -2
- data/unit_test/test_template_base.rb +10 -0
- metadata +6 -3
- data/lib/nameless_template.rb +0 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f00ee4cb710d229fe1bd23f7d2dd5b9d2e63fe17
|
4
|
+
data.tar.gz: 50a4f28986bdc26f158531dcbda7040cdd16cd9a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f24c616c42e6a4b2866c18d28764f2885758a566d1df136118a0c9fcfb91dece7ec573e5a560a3f6655551e29641dd2bee5e8bc8a6da527660db30521a83e100
|
7
|
+
data.tar.gz: 666608cd8a53767641515c5164a9916cb537db71244e148da052831ed265920be5925d343c924ddb5703d297dd88601ac4453d0ac72e26446fa320d30f23c34a
|
data/.gitignore
CHANGED
data/lib/binary_parser.rb
CHANGED
@@ -7,10 +7,12 @@ module BinaryParser
|
|
7
7
|
# load general class file
|
8
8
|
GENERAL_CLASS_DIR = '/lib/general_class/'
|
9
9
|
GENERAL_CLASS_FILES =
|
10
|
-
['
|
10
|
+
['binary_manipulate_function.rb',
|
11
|
+
'abstract_binary',
|
11
12
|
'expression.rb',
|
12
13
|
'bit_position.rb',
|
13
|
-
'condition.rb'
|
14
|
+
'condition.rb',
|
15
|
+
'buffered_stream.rb'
|
14
16
|
]
|
15
17
|
|
16
18
|
GENERAL_CLASS_FILES.each do |path|
|
@@ -40,7 +42,7 @@ module BinaryParser
|
|
40
42
|
'structure_definition.rb',
|
41
43
|
'template_base.rb',
|
42
44
|
'stream_template_base.rb',
|
43
|
-
'
|
45
|
+
'nameless_template_maker.rb',
|
44
46
|
'error.rb'
|
45
47
|
]
|
46
48
|
|
@@ -4,65 +4,129 @@ module BinaryParser
|
|
4
4
|
attr_reader :bit_length
|
5
5
|
|
6
6
|
def initialize(binary_string, bit_index=nil, bit_length=nil)
|
7
|
-
unless binary_string.encoding == Encoding::BINARY
|
8
|
-
raise BadBinaryManipulationError, "binary_string's encoding should be" +
|
9
|
-
"ASCII_8BIT(BINARY). This is #{binary_string.encoding}."
|
10
|
-
end
|
11
7
|
@bin_str = binary_string
|
12
8
|
@bit_index = bit_index || 0
|
13
|
-
@bit_length = bit_length || binary_string.length * 8
|
9
|
+
@bit_length = bit_length || binary_string.length * 8 - @bit_index
|
14
10
|
end
|
15
11
|
|
16
12
|
def sub(spec)
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
13
|
+
new_bit_index, new_bit_length = decode_spec(spec)
|
14
|
+
check_invalid_sub_position(new_bit_index, new_bit_length)
|
15
|
+
return self.class.new(@bin_str, new_bit_index, new_bit_length)
|
16
|
+
end
|
17
|
+
|
18
|
+
def to_i
|
19
|
+
if @bit_length == 0
|
20
|
+
raise BadBinaryManipulationError, "Cannot convert empty binary into integer."
|
21
21
|
end
|
22
|
+
str, ml, mr = BinaryManipulateFunction.needed_sub_string(@bin_str,
|
23
|
+
@bit_index,
|
24
|
+
@bit_index + @bit_length - 1)
|
25
|
+
return BinaryManipulateFunction.to_unsigned_int(str, ml, mr)
|
26
|
+
end
|
27
|
+
|
28
|
+
def to_chars
|
29
|
+
check_non_byte_position(@bit_index, @bit_length)
|
30
|
+
return @bin_str[@bit_index / 8, @bit_length / 8].unpack("C*")
|
31
|
+
end
|
22
32
|
|
23
|
-
|
24
|
-
|
33
|
+
def to_s
|
34
|
+
check_non_byte_position(@bit_index, @bit_length)
|
35
|
+
return @bin_str[@bit_index / 8, @bit_length / 8]
|
36
|
+
end
|
37
|
+
|
38
|
+
def byte_position?
|
39
|
+
@bit_index % 8 == 0 && @bit_length % 8 == 0
|
40
|
+
end
|
41
|
+
|
42
|
+
|
43
|
+
# Methods for generating modified binary.
|
44
|
+
def alt(binary_or_uint)
|
45
|
+
case binary_or_uint
|
46
|
+
when Integer
|
47
|
+
alt_uint(binary_or_uint)
|
48
|
+
when String
|
49
|
+
alt_binary(binary_or_uint)
|
25
50
|
else
|
26
|
-
|
51
|
+
raise BadManipulationError, "Argument shouled be Integer or binary-encoded String."
|
27
52
|
end
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
53
|
+
end
|
54
|
+
|
55
|
+
def alt_uint(uint)
|
56
|
+
unless uint.is_a?(Integer) && uint >= 0
|
57
|
+
raise BadManipulationError, "Specified arg #{uint} is not number of unsigned int."
|
32
58
|
end
|
59
|
+
unless uint < 2 ** @bit_length
|
60
|
+
raise BadBinaryManipulationError, "Specified arg #{uint} is too big to " +
|
61
|
+
"express by #{@bit_length} bit."
|
62
|
+
end
|
63
|
+
alt_binary = BinaryManipulateFunction.convert_uint_into_binary(uint, @bit_length)
|
64
|
+
alt_shift = 7 - ((@bit_length - 1) % 8)
|
65
|
+
return self.class.new(alt_binary, alt_shift)
|
66
|
+
end
|
33
67
|
|
34
|
-
|
68
|
+
def alt_binary(binary)
|
69
|
+
unless binary.length * 8 == @bit_length
|
70
|
+
raise BadBinaryManipulationError, "Given binary'length doesn't match self."
|
71
|
+
end
|
72
|
+
return self.class.new(binary)
|
35
73
|
end
|
36
74
|
|
37
|
-
def
|
38
|
-
|
39
|
-
|
75
|
+
def naive_concat(other)
|
76
|
+
left_shift = 7 - ((self.bit_length - 1) % 8)
|
77
|
+
left_binary = BinaryManipulateFunction.convert_uint_into_binary(self.to_i, self.bit_length)
|
78
|
+
|
79
|
+
right_shift = 7 - ((other.bit_length - 1) % 8)
|
80
|
+
right_binary = BinaryManipulateFunction.convert_uint_into_binary(other.to_i << right_shift,
|
81
|
+
other.bit_length)
|
82
|
+
|
83
|
+
return self.class.new(left_binary + right_binary,
|
84
|
+
left_shift,
|
85
|
+
self.bit_length + other.bit_length)
|
86
|
+
end
|
87
|
+
|
88
|
+
def binary_concat(other)
|
89
|
+
self.class.new(self.to_s + other.to_s)
|
90
|
+
end
|
91
|
+
|
92
|
+
def +(other)
|
93
|
+
if self.byte_position? && other.byte_position?
|
94
|
+
binary_concat(other)
|
95
|
+
else
|
96
|
+
naive_concat(other)
|
40
97
|
end
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
98
|
+
end
|
99
|
+
|
100
|
+
|
101
|
+
# Sub methods (helpers)
|
102
|
+
|
103
|
+
def decode_spec(spec)
|
104
|
+
new_bit_index = @bit_index + spec[:bit_index].to_i + spec[:byte_index].to_i * 8
|
105
|
+
|
106
|
+
if !spec[:bit_length] && !spec[:byte_length]
|
107
|
+
new_bit_length = @bit_length - (new_bit_index - @bit_index)
|
108
|
+
else
|
109
|
+
new_bit_length = spec[:bit_length].to_i + spec[:byte_length].to_i * 8
|
48
110
|
end
|
49
|
-
|
111
|
+
|
112
|
+
return new_bit_index, new_bit_length
|
50
113
|
end
|
51
|
-
|
52
|
-
def
|
53
|
-
|
54
|
-
raise BadBinaryManipulationError, "
|
55
|
-
|
114
|
+
|
115
|
+
def check_invalid_sub_position(new_bit_index, new_bit_length)
|
116
|
+
if new_bit_length < 0
|
117
|
+
raise BadBinaryManipulationError, "Specified new bit length is negative (#{new_bit_length})."
|
118
|
+
end
|
119
|
+
unless @bit_index <= new_bit_index && new_bit_index + new_bit_length <= @bit_index + @bit_length
|
120
|
+
raise BadBinaryManipulationError, "Specified new bit index #{new_bit_index} is " +
|
121
|
+
"out of current binary bit_index=#{@bit_index}, bit_length=#{@bit_length}."
|
56
122
|
end
|
57
|
-
return @bin_str[@bit_index / 8, @bit_length / 8].unpack("C*")
|
58
123
|
end
|
59
124
|
|
60
|
-
def
|
61
|
-
unless
|
62
|
-
raise BadBinaryManipulationError, "
|
63
|
-
"
|
125
|
+
def check_non_byte_position(bit_index, bit_length)
|
126
|
+
unless bit_index % 8 == 0 && bit_length % 8 == 0
|
127
|
+
raise BadBinaryManipulationError, "Position {bit_index=#{bit_index}, " +
|
128
|
+
"bit_length=#{bit_length}} is not byte-position."
|
64
129
|
end
|
65
|
-
return @bin_str[@bit_index / 8, @bit_length / 8]
|
66
130
|
end
|
67
131
|
end
|
68
132
|
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
module BinaryParser
|
2
|
+
module BinaryManipulateFunction
|
3
|
+
extend self
|
4
|
+
|
5
|
+
MASK = [0b11111111,
|
6
|
+
0b01111111,
|
7
|
+
0b00111111,
|
8
|
+
0b00011111,
|
9
|
+
0b00001111,
|
10
|
+
0b00000111,
|
11
|
+
0b00000011,
|
12
|
+
0b00000001]
|
13
|
+
|
14
|
+
def needed_sub_string(str, bit_first_pos, bit_last_pos)
|
15
|
+
return str[(bit_first_pos / 8)..(bit_last_pos / 8)], bit_first_pos % 8, 7 - (bit_last_pos % 8)
|
16
|
+
end
|
17
|
+
|
18
|
+
def needed_sub_string_in_domain_of_definition?(str, bfp, blp)
|
19
|
+
bfp < blp && blp / 8 < str.length
|
20
|
+
end
|
21
|
+
|
22
|
+
def to_unsigned_int(binary_string, margin_left=0, margin_right=0)
|
23
|
+
chars = binary_string.unpack("C*")
|
24
|
+
converted = chars.shift & MASK[margin_left]
|
25
|
+
chars.each do |char|
|
26
|
+
converted = (converted << 8) + char
|
27
|
+
end
|
28
|
+
return converted >> margin_right
|
29
|
+
end
|
30
|
+
|
31
|
+
def to_unsigned_int_in_domain_of_definition?(str, ml, mr)
|
32
|
+
[ str.length >= 1,
|
33
|
+
0 <= ml && ml <= 7,
|
34
|
+
0 <= mr && mr <= 7,
|
35
|
+
str.length != 1 || ml + mr <= 7 ].all?
|
36
|
+
end
|
37
|
+
|
38
|
+
def convert_uint_into_binary(uint, bit_length)
|
39
|
+
if uint == 0
|
40
|
+
if bit_length > 0
|
41
|
+
convert_uint_into_binary(0, bit_length - 8) + [0].pack("C1")
|
42
|
+
else
|
43
|
+
[].pack("C0")
|
44
|
+
end
|
45
|
+
else
|
46
|
+
convert_uint_into_binary(uint / 256, bit_length - 8) + [uint % 256].pack("C1")
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def convert_uint_into_binary_in_domain_of_definition?(uint, bit_length)
|
51
|
+
bit_length >= 0 && 0 <= uint && uint < 2 ** bit_length
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module BinaryParser
|
2
|
+
class BufferedStream
|
3
|
+
require 'stringio'
|
4
|
+
|
5
|
+
def initialize(stream, buffer_size)
|
6
|
+
@stream, @buffer_size = stream, buffer_size
|
7
|
+
end
|
8
|
+
|
9
|
+
def read(length)
|
10
|
+
if !@buffer || @buffer.eof?
|
11
|
+
return nil unless next_buffer = @stream.read(@buffer_size)
|
12
|
+
@buffer = StringIO.new(next_buffer)
|
13
|
+
end
|
14
|
+
return @buffer.read(length)
|
15
|
+
end
|
16
|
+
|
17
|
+
def close
|
18
|
+
@stream.close
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
data/lib/loop_list.rb
CHANGED
@@ -5,12 +5,12 @@ module BinaryParser
|
|
5
5
|
def initialize(definition, abstract_binary, parent_scope)
|
6
6
|
list, rest_binary = [], abstract_binary
|
7
7
|
while rest_binary.bit_length > 0
|
8
|
-
|
9
|
-
if
|
8
|
+
template = definition.klass.new(rest_binary, parent_scope)
|
9
|
+
if template.structure_bit_length == 0
|
10
10
|
raise ParsingError, "0 bit-length repetition happens. This means infinite loop."
|
11
11
|
end
|
12
|
-
rest_binary = rest_binary.sub(:bit_index =>
|
13
|
-
list <<
|
12
|
+
rest_binary = rest_binary.sub(:bit_index => template.structure_bit_length)
|
13
|
+
list << template
|
14
14
|
end
|
15
15
|
@list = list
|
16
16
|
end
|
@@ -41,7 +41,6 @@ module BinaryParser
|
|
41
41
|
# recursively => Whether print recursively or not. Default is false.
|
42
42
|
# out => Print target. Default is STDOUT.
|
43
43
|
def show(recursively=false, out=STDOUT, depth=0)
|
44
|
-
#out.puts " " * (depth * 2) + "*** LIST with #{size} elements ***"
|
45
44
|
@list.each_with_index do |element, i|
|
46
45
|
out.puts sprintf(" " * (depth * 2) + "%-5s", "[#{i}]")
|
47
46
|
element.show(true, out, depth + 1) if recursively
|
data/lib/scope.rb
CHANGED
data/lib/stream_template_base.rb
CHANGED
@@ -2,21 +2,38 @@ module BinaryParser
|
|
2
2
|
class StreamTemplateBase
|
3
3
|
include BuiltInTemplate
|
4
4
|
|
5
|
-
def self.def_stream(byte_length, &definition_proc)
|
5
|
+
def self.def_stream(byte_length, buffer_num=10000, &definition_proc)
|
6
6
|
@byte_length = byte_length
|
7
|
-
|
8
|
-
@
|
7
|
+
@buffer_size = buffer_num * byte_length
|
8
|
+
@template = NamelessTemplateMaker.new(definition_proc)
|
9
9
|
end
|
10
10
|
|
11
|
-
def self.Def(byte_length,
|
11
|
+
def self.Def(byte_length, buffer_num=10000, &definition_proc)
|
12
|
+
def_stream(byte_length, buffer_num, &definition_proc)
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.get_template
|
16
|
+
raise BadManipulationError, "Structure is undefined." unless @template
|
17
|
+
return @template
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.get_byte_length
|
21
|
+
raise BadManipulationError, "Byte-length is undefined." unless @byte_length
|
22
|
+
return @byte_length
|
23
|
+
end
|
12
24
|
|
13
|
-
def self.
|
14
|
-
raise BadManipulationError, "
|
15
|
-
return @
|
25
|
+
def self.get_buffer_size
|
26
|
+
raise BadManipulationError, "Buffer-size is undefined." unless @buffer_size
|
27
|
+
return @buffer_size
|
16
28
|
end
|
17
29
|
|
18
30
|
def initialize(binary_stream, filters=[])
|
19
|
-
|
31
|
+
case binary_stream
|
32
|
+
when BufferedStream
|
33
|
+
@buffered_binary_stream = binary_stream
|
34
|
+
else
|
35
|
+
@buffered_binary_stream = BufferedStream.new(binary_stream, self.class.get_buffer_size)
|
36
|
+
end
|
20
37
|
@filters = filters
|
21
38
|
end
|
22
39
|
|
@@ -24,7 +41,7 @@ module BinaryParser
|
|
24
41
|
# return: new instance which has filter
|
25
42
|
def filter(&filter_proc)
|
26
43
|
raise BadManipulationError, "Filter Proc isn't given." unless filter_proc
|
27
|
-
return self.class.new(@
|
44
|
+
return self.class.new(@buffered_binary_stream, @filters + [filter_proc])
|
28
45
|
end
|
29
46
|
|
30
47
|
# Get next element from binary-stream.
|
@@ -33,24 +50,40 @@ module BinaryParser
|
|
33
50
|
# Special cases:
|
34
51
|
# (1) If rest of binary-stream's length is 0, this method returns nil.
|
35
52
|
# (2) If rest of binary-stream's length is shorter than required,
|
36
|
-
# this method throws
|
53
|
+
# this method throws ParsingError.
|
37
54
|
def get_next
|
55
|
+
return take_lookahead || filtered_simply_get_next(@filters)
|
56
|
+
end
|
57
|
+
|
58
|
+
def non_proceed_get_next
|
59
|
+
@lookahead ||= get_next
|
60
|
+
end
|
61
|
+
|
62
|
+
def take_lookahead
|
63
|
+
res, @lookahead = @lookahead, nil
|
64
|
+
return res
|
65
|
+
end
|
66
|
+
|
67
|
+
def filtered_simply_get_next(filters)
|
38
68
|
begin
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
69
|
+
structure = simply_get_next
|
70
|
+
return nil unless structure
|
71
|
+
end until filters.all?{|filter| filter.call(structure)}
|
72
|
+
return structure
|
73
|
+
end
|
74
|
+
|
75
|
+
def simply_get_next
|
76
|
+
return nil unless binary = next_binary
|
77
|
+
self.class.get_template.new(binary)
|
78
|
+
end
|
79
|
+
|
80
|
+
def next_binary
|
81
|
+
binary = @buffered_binary_stream.read(self.class.get_byte_length)
|
82
|
+
if binary && binary.length < self.class.get_byte_length
|
83
|
+
raise ParsingError, "Stream's rest binary length" +
|
84
|
+
"(#{binary.length} byte) is shorter than required length (#{self.class.get_byte_length} byte)."
|
85
|
+
end
|
86
|
+
return binary
|
54
87
|
end
|
55
88
|
|
56
89
|
# Remove elements until finding element which fullfils proc-condition or reaching end of stream.
|
@@ -65,13 +98,8 @@ module BinaryParser
|
|
65
98
|
def seek_top(&cond_proc)
|
66
99
|
raise BadManipulationError, "Condition Proc isn't given." unless cond_proc
|
67
100
|
abandoned = []
|
68
|
-
until
|
69
|
-
|
70
|
-
abandoned << @lookahead
|
71
|
-
@lookahead = nil
|
72
|
-
end
|
73
|
-
return abandoned unless rest?
|
74
|
-
@lookahead = get_next
|
101
|
+
until !rest? || cond_proc.call(non_proceed_get_next)
|
102
|
+
abandoned << take_lookahead
|
75
103
|
end
|
76
104
|
return abandoned
|
77
105
|
end
|
@@ -118,12 +146,12 @@ module BinaryParser
|
|
118
146
|
|
119
147
|
# Check whether binary-stream remains or not.
|
120
148
|
def rest?
|
121
|
-
|
149
|
+
non_proceed_get_next
|
122
150
|
end
|
123
|
-
|
151
|
+
|
124
152
|
# Simply close binary-stream.
|
125
153
|
def close
|
126
|
-
@
|
154
|
+
@buffered_binary_stream.close
|
127
155
|
end
|
128
156
|
end
|
129
157
|
end
|
data/lib/structure_definition.rb
CHANGED
@@ -2,7 +2,7 @@ module BinaryParser
|
|
2
2
|
class StructureDefinition
|
3
3
|
|
4
4
|
DataDefinition = Struct.new(:bit_position, :bit_length, :conditions, :klass)
|
5
|
-
LoopDefinition = Struct.new(:bit_position, :bit_length, :conditions, :
|
5
|
+
LoopDefinition = Struct.new(:bit_position, :bit_length, :conditions, :klass)
|
6
6
|
|
7
7
|
attr_reader :parent_structure, :bit_at, :names
|
8
8
|
|
@@ -28,18 +28,18 @@ module BinaryParser
|
|
28
28
|
def SPEND(bit_length, name, &block)
|
29
29
|
check_new_def_name(name)
|
30
30
|
bit_at, bit_length = process_bit_length(bit_length, name)
|
31
|
-
|
32
|
-
|
33
|
-
@data_def[name] = LoopDefinition.new(bit_at, bit_length, @conditions.dup, structure)
|
31
|
+
klass = NamelessTemplateMaker.new(self, block)
|
32
|
+
@data_def[name] = LoopDefinition.new(bit_at, bit_length, @conditions.dup, klass)
|
34
33
|
@names << name
|
35
34
|
end
|
36
35
|
|
37
36
|
def TIMES(times, name, &block)
|
38
37
|
check_new_def_name(name)
|
39
|
-
|
38
|
+
klass = NamelessTemplateMaker.new(self, block)
|
39
|
+
structure = klass.structure
|
40
40
|
if structure.bit_at.names.empty?
|
41
41
|
bit_at, bit_length = process_bit_length(times * structure.bit_at.imm, name)
|
42
|
-
@data_def[name] = LoopDefinition.new(bit_at, bit_length, @conditions.dup,
|
42
|
+
@data_def[name] = LoopDefinition.new(bit_at, bit_length, @conditions.dup, klass)
|
43
43
|
else
|
44
44
|
bit_length = Expression.new([0])
|
45
45
|
structure.bit_at.names.each do |bit_at_depending_name|
|
@@ -54,7 +54,7 @@ module BinaryParser
|
|
54
54
|
bit_length += depending_length_exp
|
55
55
|
end
|
56
56
|
bit_at, bit_length = process_bit_length(bit_length * times, name)
|
57
|
-
@data_def[name] = LoopDefinition.new(bit_at, bit_length, @conditions.dup,
|
57
|
+
@data_def[name] = LoopDefinition.new(bit_at, bit_length, @conditions.dup, klass)
|
58
58
|
end
|
59
59
|
@names << name
|
60
60
|
end
|
@@ -85,24 +85,39 @@ module BinaryParser
|
|
85
85
|
end
|
86
86
|
|
87
87
|
def cond(*var_names, &condition_proc)
|
88
|
-
|
89
|
-
|
88
|
+
var_names.each do |var_name|
|
89
|
+
unless name_solvable?(var_name)
|
90
|
+
raise DefinitionError, "As condition variable, unsolvable variable #{var_name} is used."
|
91
|
+
end
|
90
92
|
end
|
91
93
|
return Condition.new(*var_names, &condition_proc)
|
92
94
|
end
|
93
95
|
|
94
|
-
def
|
95
|
-
|
96
|
-
|
96
|
+
def match(var_name, value)
|
97
|
+
case value
|
98
|
+
when Integer
|
99
|
+
return cond(var_name){|v| v.to_i == value}
|
100
|
+
when String
|
101
|
+
return cond(var_name){|v| v.to_s == value}
|
102
|
+
when Symbol
|
103
|
+
return cond(var_name, value){|v1, v2| v1.to_i == v2.to_i}
|
104
|
+
else
|
105
|
+
raise DefinitionError, "Unknown type of matching value(#{value}) '#{value.class}'."
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
def var(var_name)
|
110
|
+
unless name_solvable?(var_name)
|
111
|
+
raise DefinitionError, "Unsolvable variable #{var_name} is used."
|
97
112
|
end
|
98
|
-
return Expression.new([
|
113
|
+
return Expression.new([var_name])
|
99
114
|
end
|
100
115
|
|
101
|
-
def len(
|
102
|
-
unless name_solvable?(
|
103
|
-
raise DefinitionError, "Unsolvable variable #{
|
116
|
+
def len(var_name)
|
117
|
+
unless name_solvable?(var_name)
|
118
|
+
raise DefinitionError, "Unsolvable variable #{var_name} is used."
|
104
119
|
end
|
105
|
-
symbol = ("__LEN__" +
|
120
|
+
symbol = ("__LEN__" + var_name.to_s).to_sym
|
106
121
|
return Expression.new([symbol])
|
107
122
|
end
|
108
123
|
|
@@ -114,8 +129,8 @@ module BinaryParser
|
|
114
129
|
return Expression.new([:__rest])
|
115
130
|
end
|
116
131
|
|
117
|
-
def [](
|
118
|
-
return @data_def[
|
132
|
+
def [](var_name)
|
133
|
+
return @data_def[var_name]
|
119
134
|
end
|
120
135
|
|
121
136
|
private
|
data/lib/template_base.rb
CHANGED
@@ -2,19 +2,38 @@ module BinaryParser
|
|
2
2
|
class TemplateBase
|
3
3
|
include BuiltInTemplate
|
4
4
|
|
5
|
-
def self.def_structure(&definition_proc)
|
6
|
-
|
7
|
-
@structure_def
|
5
|
+
def self.def_structure(parent_structure=nil, &definition_proc)
|
6
|
+
@structure_def = StructureDefinition.new(instance_methods, parent_structure, &definition_proc)
|
7
|
+
@structure_def.names.each do |name|
|
8
|
+
def_var_method(name)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.def_var_method(name)
|
13
|
+
define_method(name){|&block|
|
14
|
+
if block
|
15
|
+
case block.arity
|
16
|
+
when 0
|
17
|
+
@scope.load_var(name).instance_eval(&block)
|
18
|
+
when 1
|
19
|
+
block.call(@scope.load_var(name))
|
20
|
+
end
|
21
|
+
else
|
22
|
+
@scope.load_var(name)
|
23
|
+
end
|
24
|
+
}
|
8
25
|
end
|
9
26
|
|
10
|
-
def self.Def(
|
27
|
+
def self.Def(parent_structure=nil, &definition_proc)
|
28
|
+
def_structure(parent_structure, &definition_proc)
|
29
|
+
end
|
11
30
|
|
12
31
|
def self.structure
|
13
32
|
return @structure_def ||= StructureDefinition.new
|
14
33
|
end
|
15
34
|
|
16
|
-
def initialize(binary)
|
17
|
-
@scope = Scope.new(self.class.structure, convert_into_abstract_binary(binary))
|
35
|
+
def initialize(binary, parent_scope=nil)
|
36
|
+
@scope = Scope.new(self.class.structure, convert_into_abstract_binary(binary), parent_scope)
|
18
37
|
end
|
19
38
|
|
20
39
|
def convert_into_abstract_binary(object)
|
@@ -25,16 +44,12 @@ module BinaryParser
|
|
25
44
|
raise BadManipulationError, "Argument should be AbstractBinary or BINAY String."
|
26
45
|
end
|
27
46
|
|
28
|
-
def method_missing(name, *args)
|
29
|
-
return @scope.method_missing(name, *args)
|
30
|
-
end
|
31
|
-
|
32
47
|
def [](name)
|
33
|
-
|
48
|
+
@scope.load_var(name)
|
34
49
|
end
|
35
50
|
|
36
51
|
def names
|
37
|
-
|
52
|
+
@scope.names
|
38
53
|
end
|
39
54
|
|
40
55
|
# Convert held binary into unsigned integer.
|
@@ -6,7 +6,7 @@ module BinaryParser
|
|
6
6
|
require 'test/unit'
|
7
7
|
|
8
8
|
# load testing target
|
9
|
-
require $LIBRARY_ROOT_PATH + '/lib/
|
9
|
+
require $LIBRARY_ROOT_PATH + '/lib/binary_parser.rb'
|
10
10
|
|
11
11
|
class AbstractBinaryTest < Test::Unit::TestCase
|
12
12
|
|
@@ -44,15 +44,60 @@ module BinaryParser
|
|
44
44
|
def test_sub_error
|
45
45
|
abin = AbstractBinary.new(gen_bin(0b11110000, 0b11111111))
|
46
46
|
assert_raise(BadBinaryManipulationError) do
|
47
|
-
abin.sub(:bit_index =>
|
47
|
+
abin.sub(:bit_index => 17)
|
48
48
|
end
|
49
49
|
assert_raise(BadBinaryManipulationError) do
|
50
50
|
abin.sub(:bit_length => 17)
|
51
51
|
end
|
52
52
|
end
|
53
53
|
|
54
|
+
def test_alt_binary
|
55
|
+
abin = AbstractBinary.new(gen_bin(0b00000000), 0, 8)
|
56
|
+
assert_equal(0, abin.to_i)
|
57
|
+
assert_equal(255, abin.alt([0b11111111].pack("C*")).to_i)
|
58
|
+
end
|
59
|
+
|
60
|
+
def test_alt_uint
|
61
|
+
abin = AbstractBinary.new(gen_bin(0b00000000), 1, 3)
|
62
|
+
assert_equal(0, abin.to_i)
|
63
|
+
assert_equal(2, abin.alt(2).to_i)
|
64
|
+
end
|
65
|
+
|
66
|
+
def test_naive_concat_CASE1
|
67
|
+
abin1 = AbstractBinary.new(gen_bin(0b11110000, 0b11110000), 3, 7)
|
68
|
+
assert_equal(0b1000011, abin1.to_i)
|
69
|
+
|
70
|
+
abin2 = AbstractBinary.new(gen_bin(0b11110000, 0b11110000), 7, 3)
|
71
|
+
assert_equal(0b011, abin2.to_i)
|
72
|
+
|
73
|
+
con_abin = abin1.naive_concat(abin2)
|
74
|
+
assert_equal(0b1000011011, con_abin.to_i)
|
75
|
+
assert_equal(10, con_abin.bit_length)
|
76
|
+
end
|
77
|
+
|
78
|
+
def test_naive_concat_CASE2
|
79
|
+
abin1 = AbstractBinary.new(gen_bin(0b00000000, 0b00001111), 2, 14)
|
80
|
+
assert_equal(0b00000000001111, abin1.to_i)
|
81
|
+
|
82
|
+
abin2 = AbstractBinary.new(gen_bin(0b11110000), 0, 1)
|
83
|
+
assert_equal(0b1, abin2.to_i)
|
84
|
+
|
85
|
+
con_abin = abin1.naive_concat(abin2)
|
86
|
+
assert_equal(0b000000000011111, con_abin.to_i)
|
87
|
+
assert_equal(15, con_abin.bit_length)
|
88
|
+
end
|
89
|
+
|
90
|
+
def test_binary_concat_CASE1
|
91
|
+
abin1 = AbstractBinary.new(gen_bin(0b10000000), 0, 8)
|
92
|
+
abin2 = AbstractBinary.new(gen_bin(0b00000000), 0, 8)
|
93
|
+
|
94
|
+
con_abin = abin1.binary_concat(abin2)
|
95
|
+
assert_equal(0b1000000000000000, con_abin.to_i)
|
96
|
+
assert_equal(16, con_abin.bit_length)
|
97
|
+
end
|
98
|
+
|
54
99
|
# helper for generating binary
|
55
|
-
|
100
|
+
def gen_bin(*chars)
|
56
101
|
return chars.pack("C*")
|
57
102
|
end
|
58
103
|
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
$LIBRARY_ROOT_PATH = File.dirname(File.dirname(File.expand_path(File.dirname(__FILE__))))
|
2
|
+
|
3
|
+
module BinaryParser
|
4
|
+
module UnitTest
|
5
|
+
require 'test/unit'
|
6
|
+
|
7
|
+
# load testing target
|
8
|
+
require $LIBRARY_ROOT_PATH + '/lib/binary_parser.rb'
|
9
|
+
|
10
|
+
class BinaryManipulateFunctionTest < Test::Unit::TestCase
|
11
|
+
|
12
|
+
def test_needed_sub_string
|
13
|
+
str = gen_bin(0, 0, 0)
|
14
|
+
|
15
|
+
assert_equal([str[0], 0, 0], nss(str, 0, 7))
|
16
|
+
assert_equal([str[0], 1, 2], nss(str, 1, 5))
|
17
|
+
assert_equal([str[0..1], 1, 7], nss(str, 1, 8))
|
18
|
+
assert_equal([str[0..2], 1, 3], nss(str, 1, 20))
|
19
|
+
assert_equal([str[1..2], 2, 3], nss(str, 10, 20))
|
20
|
+
assert_equal([str[1], 0, 0], nss(str, 8, 15))
|
21
|
+
end
|
22
|
+
|
23
|
+
def test_to_unsigned_int
|
24
|
+
str = gen_bin(0b11110000, 0b11110000)
|
25
|
+
|
26
|
+
assert_equal(0b01, tui(str, 7, 7))
|
27
|
+
assert_equal(0b00001111, tui(str, 4, 4))
|
28
|
+
assert_equal(0b1111000011110000, tui(str, 0, 0))
|
29
|
+
end
|
30
|
+
|
31
|
+
def test_convert_uint_into_binary
|
32
|
+
assert_equal([0x00], cuib(0, 8).unpack("C*"))
|
33
|
+
assert_equal([0x00, 0x00], cuib(0, 9).unpack("C*"))
|
34
|
+
assert_equal([0x00, 0x00, 0x00], cuib(0, 17).unpack("C*"))
|
35
|
+
|
36
|
+
assert_equal([0x01], cuib(1, 8).unpack("C*"))
|
37
|
+
assert_equal([0x00, 0x01], cuib(1, 9).unpack("C*"))
|
38
|
+
|
39
|
+
assert_equal([0xff], cuib(255, 8).unpack("C*"))
|
40
|
+
assert_equal([0x01, 0x00], cuib(256, 9).unpack("C*"))
|
41
|
+
|
42
|
+
assert_equal([0xff, 0xff], cuib(0xffff, 16).unpack("C*"))
|
43
|
+
assert_equal([0x00, 0xff, 0xff], cuib(0xffff, 17).unpack("C*"))
|
44
|
+
end
|
45
|
+
|
46
|
+
# helper for generating binary
|
47
|
+
def gen_bin(*chars)
|
48
|
+
return chars.pack("C*")
|
49
|
+
end
|
50
|
+
|
51
|
+
def nss(*args)
|
52
|
+
BinaryManipulateFunction.needed_sub_string(*args)
|
53
|
+
end
|
54
|
+
|
55
|
+
def tui(*args)
|
56
|
+
BinaryManipulateFunction.to_unsigned_int(*args)
|
57
|
+
end
|
58
|
+
|
59
|
+
def cuib(*args)
|
60
|
+
BinaryManipulateFunction.convert_uint_into_binary(*args)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -6,7 +6,7 @@ module BinaryParser
|
|
6
6
|
require 'test/unit'
|
7
7
|
|
8
8
|
# load testing target
|
9
|
-
require $LIBRARY_ROOT_PATH + '/lib/
|
9
|
+
require $LIBRARY_ROOT_PATH + '/lib/binary_parser.rb'
|
10
10
|
|
11
11
|
class ExpressionTest < Test::Unit::TestCase
|
12
12
|
VAL = {:hoge => 10, :fuga => 1000}
|
@@ -46,8 +46,8 @@ module BinaryParser
|
|
46
46
|
data :dat3, C3, 8
|
47
47
|
end
|
48
48
|
|
49
|
-
assert_equal(8, st[:lp].structure[:dat1].bit_length.eval{})
|
50
|
-
assert_equal(16, st[:lp].structure[:dat2].bit_length.eval{})
|
49
|
+
assert_equal(8, st[:lp].klass.structure[:dat1].bit_length.eval{})
|
50
|
+
assert_equal(16, st[:lp].klass.structure[:dat2].bit_length.eval{})
|
51
51
|
assert_equal(48, st[:dat3].bit_position.eval{})
|
52
52
|
end
|
53
53
|
|
@@ -83,6 +83,30 @@ module BinaryParser
|
|
83
83
|
assert_equal(0, st[:dat4].conditions.size)
|
84
84
|
end
|
85
85
|
|
86
|
+
def test_match
|
87
|
+
st = StructureDefinition.new do
|
88
|
+
data :hoge, C1, 1
|
89
|
+
data :fuga, C1, 1
|
90
|
+
end
|
91
|
+
|
92
|
+
eval_proc = Proc.new do |var_name|
|
93
|
+
{:hoge => 1, :fuga => 1}[var_name]
|
94
|
+
end
|
95
|
+
|
96
|
+
cond1 = st.match(:hoge, 1)
|
97
|
+
assert_equal(true, cond1.eval(&eval_proc))
|
98
|
+
|
99
|
+
cond2 = st.match(:hoge, "ABC")
|
100
|
+
assert_equal(false, cond2.eval(&eval_proc))
|
101
|
+
|
102
|
+
cond3 = st.match(:hoge, :fuga)
|
103
|
+
assert_equal(true, cond3.eval(&eval_proc))
|
104
|
+
|
105
|
+
assert_raise(DefinitionError) do
|
106
|
+
st.match(:hoge, Object.new)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
86
110
|
def test_VARIABLE_REFERENCE_ERROR
|
87
111
|
assert_raise(DefinitionError) do
|
88
112
|
st = StructureDefinition.new do
|
@@ -53,6 +53,16 @@ module BinaryParser
|
|
53
53
|
assert_equal(40, t.structure_bit_length)
|
54
54
|
end
|
55
55
|
|
56
|
+
def test_data_method_block_call
|
57
|
+
t = gen(0b10000001, 0, 0, 0, 0)
|
58
|
+
|
59
|
+
assert_equal(0b1000000, t.number.to_i)
|
60
|
+
assert_equal(0b1000000, t.number{ to_i })
|
61
|
+
t.number do |n|
|
62
|
+
assert_equal(0b1000000, n.to_i)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
56
66
|
# helper for generating binary
|
57
67
|
def gen(*chars)
|
58
68
|
return TestingTemplate.new(chars.pack("C*"))
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: binary_parser
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.1.
|
4
|
+
version: 1.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- rokugats(u)
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-04-
|
11
|
+
date: 2014-04-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -64,16 +64,19 @@ files:
|
|
64
64
|
- lib/built_in_template/uint.rb
|
65
65
|
- lib/error.rb
|
66
66
|
- lib/general_class/abstract_binary.rb
|
67
|
+
- lib/general_class/binary_manipulate_function.rb
|
67
68
|
- lib/general_class/bit_position.rb
|
69
|
+
- lib/general_class/buffered_stream.rb
|
68
70
|
- lib/general_class/condition.rb
|
69
71
|
- lib/general_class/expression.rb
|
70
72
|
- lib/loop_list.rb
|
71
|
-
- lib/
|
73
|
+
- lib/nameless_template_maker.rb
|
72
74
|
- lib/scope.rb
|
73
75
|
- lib/stream_template_base.rb
|
74
76
|
- lib/structure_definition.rb
|
75
77
|
- lib/template_base.rb
|
76
78
|
- unit_test/general_class/test_abstract_binary.rb
|
79
|
+
- unit_test/general_class/test_binary_manipulate_function.rb
|
77
80
|
- unit_test/general_class/test_bit_position.rb
|
78
81
|
- unit_test/general_class/test_condition.rb
|
79
82
|
- unit_test/general_class/test_expression.rb
|