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 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