binary_parser 1.1.0 → 1.1.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|