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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 329750cafce1313147ce33ce73a6ead4622c7463
4
- data.tar.gz: 810050523f1e4f013877ce96cca963424501b048
3
+ metadata.gz: f00ee4cb710d229fe1bd23f7d2dd5b9d2e63fe17
4
+ data.tar.gz: 50a4f28986bdc26f158531dcbda7040cdd16cd9a
5
5
  SHA512:
6
- metadata.gz: a1dd40df83f438b9ca90c6bc15ad056868d1f62d5523e0209a3b71d4122a9b661748bdba897f24a75c72edaf8b94e6894b983b56ff7117c213bfa928e8d9b55b
7
- data.tar.gz: 4f20fb77279fc8caac2d3512647dfefd17f597cc8a7e7b03886a982476fe24c6d4c23b85b0ca78a589f47a89161d1c6a5190d30c6c8c36876ad425f77f435a57
6
+ metadata.gz: f24c616c42e6a4b2866c18d28764f2885758a566d1df136118a0c9fcfb91dece7ec573e5a560a3f6655551e29641dd2bee5e8bc8a6da527660db30521a83e100
7
+ data.tar.gz: 666608cd8a53767641515c5164a9916cb537db71244e148da052831ed265920be5925d343c924ddb5703d297dd88601ac4453d0ac72e26446fa320d30f23c34a
data/.gitignore CHANGED
@@ -1,3 +1,4 @@
1
+ *.*~
1
2
  *.gem
2
3
  *.rbc
3
4
  .bundle
@@ -1,3 +1,3 @@
1
1
  module BinaryParser
2
- VERSION = "1.1.0"
2
+ VERSION = "1.1.1"
3
3
  end
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
- ['abstract_binary',
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
- 'nameless_template.rb',
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
- additional_bit_index = spec[:bit_index].to_i + spec[:byte_index].to_i * 8
18
- if additional_bit_index >= @bit_index + @bit_length
19
- raise BadBinaryManipulationError, "Impossible index specification of sub binary " +
20
- "(bit_index: #{additional_bit_index} on [#{@bit_index}, #{@bit_length}))"
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
- if spec[:bit_length] || spec[:byte_length]
24
- new_bit_length = spec[:bit_length].to_i + spec[:byte_length].to_i * 8
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
- new_bit_length = @bit_length - additional_bit_index
51
+ raise BadManipulationError, "Argument shouled be Integer or binary-encoded String."
27
52
  end
28
- if additional_bit_index + new_bit_length > @bit_length
29
- raise BadBinaryManipulationError, "Impossible length specification of" +
30
- "sub binary (bit_index: #{additional_bit_index}, " +
31
- "bit_length: #{new_bit_length} on [#{@bit_index}, #{@bit_length}])"
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
- return self.class.new(@bin_str, @bit_index + additional_bit_index, new_bit_length)
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 to_i
38
- if @bit_length == 0
39
- raise BadBinaryManipulationError, "Cannot convert empty binary into integer."
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
- res, rest_bit, char_pos = 0, @bit_length - 1, @bit_index % 8
42
- @bin_str[@bit_index / 8, (@bit_length + @bit_index % 8) / 8 + 1].unpack("C*").each do |char|
43
- (char_pos..7).each do |i|
44
- res += char[7 - i] * (1 << rest_bit)
45
- return res if (rest_bit -= 1) < 0
46
- end
47
- char_pos = 0
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
- raise ProgramAssertionError, "Failed to convert integer value."
111
+
112
+ return new_bit_index, new_bit_length
50
113
  end
51
-
52
- def to_chars
53
- unless @bit_index % 8 == 0 && @bit_length % 8 == 0
54
- raise BadBinaryManipulationError, "Invalid position(from #{@bit_index} bit)" +
55
- "and length(#{@bit_length} bit)."
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 to_s
61
- unless @bit_index % 8 == 0 && @bit_length % 8 == 0
62
- raise BadBinaryManipulationError, "Invalid position(from #{@bit_index} bit) " +
63
- "and length(#{@bit_length} bit)."
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
- scope = Scope.new(definition.structure, rest_binary, parent_scope)
9
- if scope.eval_entire_bit_length == 0
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 => scope.eval_entire_bit_length)
13
- list << NamelessTemplate.new(scope)
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
@@ -0,0 +1,9 @@
1
+ module BinaryParser
2
+ module NamelessTemplateMaker
3
+ def self.new(parent_structure=nil, structure_definition_proc)
4
+ Class.new(TemplateBase) do
5
+ Def(parent_structure, &structure_definition_proc)
6
+ end
7
+ end
8
+ end
9
+ end
data/lib/scope.rb CHANGED
@@ -10,11 +10,6 @@ module BinaryParser
10
10
  @data, @ebs, @ebl = {}, {}, {}
11
11
  end
12
12
 
13
- def method_missing(name, *args)
14
- return load_var(name) if @definition[name]
15
- super
16
- end
17
-
18
13
  def names
19
14
  @definition.names.dup
20
15
  end
@@ -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
- used_method_names = NamelessTemplate.instance_methods + Scope.instance_methods
8
- @structure = StructureDefinition.new(used_method_names, &definition_proc)
7
+ @buffer_size = buffer_num * byte_length
8
+ @template = NamelessTemplateMaker.new(definition_proc)
9
9
  end
10
10
 
11
- def self.Def(byte_length, &definition_proc) def_stream(byte_length, &definition_proc) end
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.get_stream_definition
14
- raise BadManipulationError, "Stream is undefined." unless @byte_length && @structure
15
- return @byte_length, @structure
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
- @binary_stream = binary_stream
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(@binary_stream, @filters + [filter_proc])
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 BadBinaryManipulationError.
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
- if @lookahead
40
- scope, @lookahead = @lookahead, nil
41
- else
42
- byte_length, structure = self.class.get_stream_definition
43
- binary = @binary_stream.read(byte_length)
44
- return nil unless binary
45
- if binary.length < byte_length
46
- raise ParsingError, "Stream's rest binary length" +
47
- "(#{binary.length} byte) is shorter than required length (#{byte_length} byte)."
48
- end
49
- abstract_binary = AbstractBinary.new(binary)
50
- scope = Scope.new(structure, abstract_binary)
51
- end
52
- end until @filters.all?{|filter| filter.call(scope)}
53
- return NamelessTemplate.new(scope)
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 @lookahead && cond_proc.call(@lookahead)
69
- if @lookahead
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
- return @lookahead || !@binary_stream.eof?
149
+ non_proceed_get_next
122
150
  end
123
-
151
+
124
152
  # Simply close binary-stream.
125
153
  def close
126
- @binary_stream.close
154
+ @buffered_binary_stream.close
127
155
  end
128
156
  end
129
157
  end
@@ -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, :structure)
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
- used_method_names = NamelessTemplate.instance_methods + Scope.instance_methods
32
- structure = StructureDefinition.new(used_method_names, self, &block)
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
- structure = StructureDefinition.new(Scope.instance_methods, self, &block)
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, structure)
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, structure)
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
- unless var_names.all?{|name| name_solvable?(name)}
89
- raise DefinitionError, "As condition variable, unsolvable variable #{symbol} is used."
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 var(name)
95
- unless name_solvable?(name)
96
- raise DefinitionError, "Unsolvable variable #{name} is used."
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([name])
113
+ return Expression.new([var_name])
99
114
  end
100
115
 
101
- def len(name)
102
- unless name_solvable?(name)
103
- raise DefinitionError, "Unsolvable variable #{name} is used."
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__" + name.to_s).to_sym
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 [](name)
118
- return @data_def[name]
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
- used_method_names = self.instance_methods + Scope.instance_methods
7
- @structure_def = StructureDefinition.new(used_method_names, &definition_proc)
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(&definition_proc) def_structure(&definition_proc) end
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
- return @scope.method_missing(name)
48
+ @scope.load_var(name)
34
49
  end
35
50
 
36
51
  def names
37
- return @scope.names
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/general_class/abstract_binary.rb'
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 => 16)
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
- def gen_bin(*chars)
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/general_class/bit_position.rb'
9
+ require $LIBRARY_ROOT_PATH + '/lib/binary_parser.rb'
10
10
 
11
11
  class BitPositionTest < Test::Unit::TestCase
12
12
 
@@ -6,7 +6,7 @@ module BinaryParser
6
6
  require 'test/unit'
7
7
 
8
8
  # load testing target
9
- require $LIBRARY_ROOT_PATH + '/lib/general_class/condition.rb'
9
+ require $LIBRARY_ROOT_PATH + '/lib/binary_parser.rb'
10
10
 
11
11
  class ConditionTest < Test::Unit::TestCase
12
12
 
@@ -6,7 +6,7 @@ module BinaryParser
6
6
  require 'test/unit'
7
7
 
8
8
  # load testing target
9
- require $LIBRARY_ROOT_PATH + '/lib/general_class/expression.rb'
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.0
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-10 00:00:00.000000000 Z
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/nameless_template.rb
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
@@ -1,7 +0,0 @@
1
- module BinaryParser
2
- class NamelessTemplate < TemplateBase
3
- def initialize(scope)
4
- @scope = scope
5
- end
6
- end
7
- end