codec 0.0.12 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore CHANGED
@@ -15,3 +15,4 @@ spec/reports
15
15
  test/tmp
16
16
  test/version_tmp
17
17
  tmp
18
+ rake_test.log
data/Rakefile CHANGED
@@ -3,6 +3,12 @@ require "bundler/gem_tasks"
3
3
 
4
4
  require 'rake/testtask'
5
5
 
6
+ desc "Open an irb session preloaded with this library"
7
+ task :console do
8
+ sh "irb -rubygems -I lib -r codec.rb"
9
+ end
10
+
11
+
6
12
  Rake::TestTask.new do |t|
7
13
  t.libs << 'lib/codec'
8
14
  t.test_files = FileList['test/lib/codec/*_test.rb']
@@ -17,7 +17,7 @@ Gem::Specification.new do |spec|
17
17
  spec.name = "codec"
18
18
  spec.require_paths = ["lib"]
19
19
  spec.version = Codec::VERSION
20
+ spec.add_dependency "log4r"
20
21
  spec.add_development_dependency "bundler", "~> 1.3"
21
22
  spec.add_development_dependency "rake"
22
- spec.add_development_dependency "log4r"
23
23
  end
@@ -14,4 +14,12 @@ require 'codec/tlv'
14
14
 
15
15
  module Codec
16
16
  # TODO : here implements Module constants and methods
17
+
18
+ # method use to log deprecation warning
19
+ def self.deprecated(msg)
20
+ stack = Kernel.caller
21
+ stack.shift
22
+ Logger.warn "DEPRECATED: #{msg} | Call stack :
23
+ #{stack.select{|l| l =~ /codec\/lib/}.each{|l| l}.join("\n")}"
24
+ end
17
25
  end
@@ -1,59 +1,20 @@
1
1
  module Codec
2
2
  class Base
3
- attr_reader :id
4
- def initialize(id,length)
5
- @length = length.to_i
6
- @id = id
7
- end
8
-
9
- def build_field(buf,length)
10
- f = Field.new(@id)
11
- f.set_value(buf[0,length])
12
- return f
13
- end
14
3
 
15
- def decode_with_length(buf,length)
16
- l = eval_length(buf,length)
17
- return build_field(buf,l),buf[l,buf.length]
18
- end
19
-
20
- def decode(buf)
21
- l = eval_length(buf,@length)
22
- return build_field(buf,l),buf[l,buf.length]
4
+ def decode(buf,field)
5
+ raise "Abstract Codec"
23
6
  end
24
7
 
25
- def encode(field)
26
- return field.get_value
27
- end
28
-
29
- def encode_with_length(field)
30
- buf = encode(field)
31
- return buf.length, buf
32
- end
33
-
34
- def get_length(field)
35
- field.get_value.length
8
+ def encode(buf,field)
9
+ raise "Abstract Codec"
36
10
  end
37
11
 
38
- def eval_length(buf,length)
39
- length = 0 if length.nil?
40
- if(length != 0)
41
- if buf.length < length
42
- raise BufferUnderflow, "Not enough data for parsing #{@id} (#{length}/#{buf.length})"
43
- end
44
- return length
45
- else
46
- return buf.length
47
- end
48
- end
49
-
50
- def add_sub_codec(id_field,codec)
12
+ def add_sub_codec(field_id,codec)
51
13
  if codec.nil?
52
- raise InitializeException, "Invalid codec reference in subcodec #{id_field} for codec #{@id}"
14
+ raise InitializeException, "Invalid codec reference in subcodec #{field_id} for codec #{@id}"
53
15
  end
54
- if @subCodecs.kind_of? Hash
55
- @subCodecs[id_field] = codec
56
- end
16
+ @subCodecs ||= {}
17
+ @subCodecs[field_id] = codec
57
18
  end
58
19
 
59
20
  def get_sub_codecs
@@ -1,8 +1,8 @@
1
1
  module Codec
2
2
  class Bitmap < Base
3
3
  NB_BITS_BY_BYTE = 8
4
- def initialize(id,length)
5
- super(id,length)
4
+ def initialize(length)
5
+ @length=length
6
6
  @num_extended_bitmaps=[]
7
7
  @subCodecs = {}
8
8
  end
@@ -10,71 +10,78 @@ module Codec
10
10
  def bitmap_length
11
11
  @length * NB_BITS_BY_BYTE
12
12
  end
13
+
13
14
  def add_extended_bitmap(num_extention)
14
15
  @num_extended_bitmaps << num_extention.to_i
15
16
  end
16
17
 
17
- def decodeBitmap(buffer,first_field_num)
18
- fieldsList = []
19
-
20
- bitmapBuffer = buffer[0,@length].unpack("B*").first
21
- buf = buffer[@length,buffer.length]
18
+ def decode_bitmap(buffer,first_field_num)
19
+ fields_ids = []
20
+ bitmap = buffer.slice!(0...@length).unpack("B*").first
22
21
  field_num = first_field_num
23
- while(bitmapBuffer.length > 0)
24
- fieldsList << field_num if bitmapBuffer.start_with?('1')
25
- bitmapBuffer.slice!(0)
22
+ until(bitmap.empty?)
23
+ fields_ids << field_num if bitmap.slice!(0) == "1"
26
24
  field_num += 1
27
25
  end
28
- return fieldsList, buf
26
+ return fields_ids
29
27
  end
30
28
 
31
- def encode_bitmap(fields_list,bitmap_index)
32
- offset = bitmap_index * bitmap_length
29
+ def encode_bitmap(buf,fields_list,bitmap_index)
30
+ offset_id = bitmap_index * bitmap_length + 1
33
31
  bitmap = ""
34
- ((offset + 1)..(offset + bitmap_length)).each do |i|
32
+ (offset_id...(offset_id + bitmap_length)).each do |i|
35
33
  if fields_list.include?(i)
36
- bitmap += "1"
34
+ bitmap << "1"
37
35
  else
38
- bitmap += "0"
36
+ bitmap << "0"
39
37
  end
40
38
  end
41
- return [bitmap].pack("B*")
39
+ Logger.debug { "Encoding bitmap #{bitmap_index}
40
+ form #{offset_id} to #{offset_id + bitmap_length - 1}
41
+ with #{fields_list.collect{|id| id.to_s}.join(',')}
42
+ result #{bitmap}" }
43
+ buf << [bitmap].pack("B*")
42
44
  end
43
45
 
44
- def encode(field)
46
+ def encode(buf, field)
47
+ Logger.debug { "Start bitmap encoding\n" }
48
+ initial_length = buf.length
45
49
  fields = field.get_value
46
50
  encoded_fields = []
47
51
  fields_list = fields.collect{|sf| sf.get_id.to_i}
48
- # Add field for bitmaps
49
- bitmap_fields = @num_extended_bitmaps[0,(fields_list.last - 1) / bitmap_length]
50
- fields_list += bitmap_fields
51
- fields += bitmap_fields.collect {|id| Field.new(id)}
52
+ fields_list.sort!
53
+ nb_additionnal_bitmaps = (fields_list.last - 1) / bitmap_length
54
+ @num_extended_bitmaps[0...nb_additionnal_bitmaps].each{ |bitmap_field_id|
55
+ Logger.debug{"adding bitmap = #{bitmap_field_id}\n"}
56
+ fields_list << bitmap_field_id
57
+ fields << Field.new(bitmap_field_id)
58
+ }
52
59
  fields.sort!{|a,b| a.get_id.to_i <=> b.get_id.to_i}
53
60
  # Encode first bitmap
54
- out = encode_bitmap(fields_list,0)
55
- bitmap_index = 1
61
+ bitmap_itt = 0
62
+ encode_bitmap(buf,fields_list,bitmap_itt)
56
63
  fields.each do |sf|
57
64
  codec = @subCodecs[sf.get_id]
58
65
  if @num_extended_bitmaps.include?(sf.get_id)
59
- out += encode_bitmap(fields_list,bitmap_index)
60
- bitmap_index += 1
66
+ bitmap_itt += 1
67
+ encode_bitmap(buf, fields_list, bitmap_itt)
61
68
  elsif codec.nil?
62
69
  raise EncodingException, "unknown codec for subfield #{sf.get_id}"
63
70
  elsif encoded_fields.include?(sf.get_id.to_i)
64
71
  raise EncodingException, "Multiple subfield #{sf.get_id} is invalid for Codec::Bitmap"
65
72
  else
66
- out += codec.encode(sf)
73
+ codec.encode(buf,sf)
67
74
  end
68
75
  encoded_fields << sf.get_id.to_i
69
76
  end
70
- return out
77
+ return buf.length - initial_length
71
78
  end
72
-
73
- def decode(buffer)
74
- msg = Field.new(@id)
79
+
80
+ def decode(buf,msg, length=nil)
81
+ buf = buf.slice!(0...length) if length && length > 0
75
82
  field_num = 1
76
83
  # 1. read bitmap
77
- fields_list,buf = decodeBitmap(buffer,field_num)
84
+ fields_list = decode_bitmap(buf,field_num)
78
85
  field_num += bitmap_length
79
86
  # 2. decode each field present
80
87
  while fields_list.length > 0
@@ -82,12 +89,12 @@ module Codec
82
89
  field_id = fields_list.slice!(0)
83
90
  field_tag = field_id.to_s
84
91
  if @num_extended_bitmaps.include?(field_id)
85
- nextFields,buf = decodeBitmap(buf,field_num)
92
+ nextFields = decode_bitmap(buf,field_num)
86
93
  fields_list = fields_list + nextFields
87
94
  elsif @subCodecs[field_tag].respond_to?(:decode)
88
95
  Logger.debug "Parsing bitmap field #{field_tag}"
89
- f,buf = @subCodecs[field_tag].decode(buf)
90
- f.set_id(field_tag)
96
+ f = Field.new(field_tag)
97
+ @subCodecs[field_tag].decode(buf,f)
91
98
  msg.add_sub_field(f)
92
99
  else
93
100
  f = Field.new("ERR")
@@ -96,7 +103,6 @@ module Codec
96
103
  raise ParsingException.new "#{msg}\nError unknown field #{field_tag} : "
97
104
  end
98
105
  end
99
- return msg,buf
100
106
  end
101
107
  end
102
108
  end
@@ -1,84 +1,57 @@
1
1
  module Codec
2
2
  class BaseComposed < Base
3
- def initialize(id)
4
- @id = id
5
- @subCodecs = []
3
+ def initialize(isComplete = false)
4
+ @is_complete = isComplete
5
+ @subCodecs = {}
6
6
  end
7
7
 
8
- def decode(buf)
9
- return build_each_field(buf,buf.length)
10
- end
11
-
12
- def encode(field)
13
- return "" if field.empty?
14
- subfields = field.get_value
15
- composed_encoder = subfields.zip(@subCodecs).collect {|sf,sc|
16
- if sf.get_id != sc.first
17
- raise EncodingException, "subfield #{sf.first} not correspond to subcodec #{sc.first}"
18
- end
19
- [sc.last,sf]
20
- }
21
- out = ""
22
- composed_encoder.each do |subcodec,subfield|
23
- out += subcodec.encode(subfield)
8
+ def decode(buf,msg, length = nil)
9
+ unless length.nil?
10
+ Logger.debug {"build composed for [#{buf.unpack("H*").first}] on #{length} bytes for #{msg.get_id} field"}
11
+ buf = buf.slice!(0...length)
24
12
  end
25
- return out
26
- end
27
-
28
- def build_each_field(buf,length)
29
- msg = Field.new(@id)
30
- working_buf = buf[0,length]
13
+
31
14
  @subCodecs.each{|id,codec|
32
- Logger.debug "Parsing struct field #{@id} : #{id}"
33
- if working_buf.length == 0
34
- Logger.debug "Not enough data to decode #{@id} : #{id}"
15
+ Logger.debug "Parsing struct field #{msg.get_id} - #{id} with [#{buf.unpack("H*").first}]"
16
+ if buf.empty?
17
+ Logger.debug "Not enough data to decode #{msg.get_id} : #{id}"
35
18
  else
36
- f,working_buf = codec.decode(working_buf)
37
- f.set_id(id)
19
+ f = Field.new(id)
20
+ codec.decode(buf,f)
38
21
  msg.add_sub_field(f)
39
22
  end
40
23
  }
41
- return msg,working_buf
42
- end
43
-
44
- def build_field(buf,length)
45
- msg,working_buf = build_each_field(buf,length)
46
-
47
- if working_buf.length > 0
48
- if @length_unknown
49
- @remain = working_buf
50
- else
51
- f = Field.new("PADDING")
52
- f.set_value(working_buf.unpack("H*").first)
53
- msg.add_sub_field(f)
54
- end
24
+ unless buf.empty? || length.nil?
25
+ f = Field.new("PADDING")
26
+ f.set_value(buf.unpack("H*").first)
27
+ msg.add_sub_field(f)
55
28
  end
56
- return msg
57
- end
58
-
59
- def add_sub_codec(id_field,codec)
60
- if codec.nil?
61
- raise InitializeException, "Invalid codec reference in subcodec #{id_field} for codec #{@id}"
62
- end
63
- @subCodecs << [id_field, codec]
64
- end
65
- end
66
-
67
- class CompleteComposed < BaseComposed
68
- def build_each_field(buf,length)
69
- f,r = super(buf,length)
29
+
70
30
  # Check if all struct's fields have been parsed
71
- if f.get_value.size < @subCodecs.size
72
- raise BufferUnderflow, "Not enough data for parsing Struct #{@id}"
73
- end
74
- return f,r
31
+ if @is_complete && msg.get_value.size < @subCodecs.size
32
+ raise BufferUnderflow, "Not enough data for parsing Struct #{msg.get_id}"
33
+ end
75
34
  end
76
35
 
77
- def encode(field)
78
- if @subCodecs.size != field.get_value.size
79
- raise EncodingException, "Not enough subfields to encode #{@id}"
36
+ def encode(buf, field)
37
+
38
+ if @is_complete && @subCodecs.size != field.get_value.size
39
+ raise EncodingException, "Not enough subfields to encode #{field.get_id}"
40
+ end
41
+
42
+ return if field.empty?
43
+ initial_length = buf.length
44
+ subfields = field.get_value
45
+ composed_encoder = subfields.zip(@subCodecs).collect {|sf,sc|
46
+ if sf.get_id != sc.first
47
+ raise EncodingException, "subfield #{sf.first} not correspond to subcodec #{sc.first}"
48
+ end
49
+ [sc.last,sf]
50
+ }
51
+ composed_encoder.each do |subcodec,subfield|
52
+ subcodec.encode(buf,subfield)
80
53
  end
81
- super(field)
54
+ return buf.length - initial_length
82
55
  end
83
56
  end
84
57
  end
@@ -63,7 +63,7 @@ module Codec
63
63
 
64
64
  def add_sub_field(sf)
65
65
  @value = [] if @value == ""
66
- raise "Add impossible on not Array valued field" unless @value.kind_of? Array
66
+ raise "Add sub field impossible on #{@value.class} value class" unless @value.kind_of? Array
67
67
  @value << [sf.id,sf.value]
68
68
  end
69
69
 
@@ -1,21 +1,48 @@
1
1
  module Codec
2
-
3
- class Numbin < Base
4
- def build_field(buf,length)
5
- f = Field.new(@id)
2
+ class Fix < Base
3
+
4
+ def initialize(length=nil)
5
+ @length = length || 0
6
+ end
7
+
8
+ def check_length(buf,length)
9
+ raise "Length is nil" if length.nil?
10
+ if(length != 0)
11
+ if buf.length < length
12
+ raise BufferUnderflow, "Not enough data for decoding (#{length}/#{buf.length})"
13
+ end
14
+ return length
15
+ else
16
+ return buf.length
17
+ end
18
+ end
19
+
20
+ def decode(buf,field,length=nil)
21
+ length ||= @length
22
+ l = check_length(buf,length)
23
+ wbuf = buf.slice!(0...l)
24
+ build_field(wbuf,field,l)
25
+ end
26
+
27
+ def build_field(w,f,l)
28
+ raise "Abstract Codec : build field not defined for #{self.class.name}"
29
+ end
30
+ end
31
+ class Numbin < Fix
32
+ def build_field(buf,f,length)
6
33
  res = 0
7
- buf[0,length].unpack("C*").each{ |ubyte|
34
+ buf.slice!(0...length).unpack("C*").each{ |ubyte|
8
35
  res *= 256
9
36
  res += ubyte
10
37
  }
11
38
  f.set_value(res)
12
- return f
13
39
  end
14
40
 
15
- def encode(field)
41
+ def encode(buf, field)
16
42
  val = field.get_value.to_i
17
43
  out = Numbin.numbin(val,@length)
18
- return out
44
+ buf << out
45
+ return out.length
19
46
  end
20
47
 
21
48
  def self.numbin(number,maxlength)
@@ -37,20 +64,19 @@ module Codec
37
64
  end
38
65
  end
39
66
 
40
- class Numstr < Base
41
- def build_field(buf,length)
42
- f = Field.new(@id)
43
- f.set_value(buf[0,length].to_i)
44
- return f
67
+ class Numstr < Fix
68
+ def build_field(buf, f, length)
69
+ f.set_value(buf.slice!(0...length).to_i)
45
70
  end
46
71
 
47
- def encode(field)
72
+ def encode(buf,field)
48
73
  out = field.get_value.to_s
49
74
  if @length > 0
50
75
  out = out.rjust(@length,"0")
51
76
  raise TooLongDataException if out.length > @length
52
77
  end
53
- return out
78
+ buf << out
79
+ return out.length
54
80
  end
55
81
  end
56
82
 
@@ -59,90 +85,85 @@ module Codec
59
85
  # have the same encoding for digits number
60
86
  end
61
87
 
62
- class Numebc < Base
63
- def build_field(buf,length)
64
- f = Field.new(@id)
65
- f.set_value(EightBitsEncoding::EBCDIC_2_UTF8(buf[0,length]).to_i)
66
- return f
88
+ class Numebc < Fix
89
+ def build_field(buf,f,length)
90
+ f.set_value(EightBitsEncoding::EBCDIC_2_UTF8(buf.slice!(0...length)).to_i)
67
91
  end
68
92
 
69
- def encode(field)
93
+ def encode(buf, field)
70
94
  out = field.get_value.to_s
71
95
  if @length > 0
72
96
  out = out.rjust(@length,"0")
73
97
  raise TooLongDataException if out.length > @length
74
98
  end
75
- return EightBitsEncoding::UTF8_2_EBCDIC(out)
99
+ buf << EightBitsEncoding::UTF8_2_EBCDIC(out)
100
+ return out.length
76
101
  end
77
102
 
78
103
  end
79
104
 
80
- class Ebcdic < Base
81
- def build_field(buf,length)
82
- f = Field.new(@id)
83
- f.set_value(EightBitsEncoding::EBCDIC_2_UTF8(buf[0,length]))
84
- return f
105
+ class Ebcdic < Fix
106
+ def build_field(buf, f, length)
107
+ f.set_value(EightBitsEncoding::EBCDIC_2_UTF8(buf.slice!(0...length)))
85
108
  end
86
109
 
87
- def encode(f)
110
+ def encode(buf, f)
88
111
  out = f.get_value
89
112
  if @length > 0
90
113
  raise TooLongDataException if out.length > @length
91
114
  out = out.ljust(@length," ")
92
115
  end
93
- return EightBitsEncoding::UTF8_2_EBCDIC(out)
116
+ buf << EightBitsEncoding::UTF8_2_EBCDIC(out)
117
+ return out.length
94
118
  end
95
119
  end
96
120
 
97
- class Ascii < Base
98
- def build_field(buf,length)
99
- f = Field.new(@id)
100
- f.set_value(EightBitsEncoding::ASCII_2_UTF8(buf[0,length]))
101
- return f
121
+ class Ascii < Fix
122
+ def build_field(buf, f, length)
123
+ f.set_value(EightBitsEncoding::ASCII_2_UTF8(buf.slice!(0...length)))
102
124
  end
103
125
 
104
- def encode(f)
126
+ def encode(buf, f)
105
127
  out = f.get_value
106
128
  if @length > 0
107
129
  raise TooLongDataException if out.length > @length
108
130
  out = out.ljust(@length," ")
109
131
  end
110
- return EightBitsEncoding::UTF8_2_ASCII(out)
132
+ buf << EightBitsEncoding::UTF8_2_ASCII(out)
133
+ return out.length
111
134
  end
112
135
  end
113
136
 
114
137
 
115
- class String < Base
116
- def build_field(buf,length)
117
- f = Field.new(@id)
118
- f.set_value(buf[0,length])
119
- return f
138
+ class String < Fix
139
+ def build_field(buf, f, length)
140
+ f.set_value(buf.slice!(0...length))
120
141
  end
121
142
 
122
- def encode(f)
143
+ def encode(buf, f)
123
144
  out = f.get_value
124
145
  if @length > 0
125
146
  raise TooLongDataException if out.length > @length
126
147
  out = out.ljust(@length," ")
127
148
  end
128
- return out
149
+ buf << out
150
+ return out.length
129
151
  end
130
152
  end
131
153
 
132
- class Binary < Base
133
- def build_field(buf,length)
134
- f = Field.new(@id)
135
- f.set_value(buf[0,length].unpack("H*").first.upcase)
136
- return f
154
+ class Binary < Fix
155
+ def build_field(buf, field, length)
156
+ field.set_value(buf.slice!(0...length).unpack("H*").first.upcase)
137
157
  end
138
158
 
139
- def encode(f)
159
+ def encode(buf, f)
140
160
  out = [f.get_value].pack("H*")
141
161
  if @length > 0
142
162
  raise TooLongDataException if out.length > @length
143
163
  out = out.ljust(@length,0.chr)
144
164
  end
145
- return out
165
+ buf << out
166
+ return out.length
146
167
  end
147
168
  end
148
169
 
@@ -157,33 +178,30 @@ module Codec
157
178
  "5C9F535455565758595AF4F5F6F7F8F930313233343536373839FAFBFCFDFEFF"].pack("H*")
158
179
 
159
180
  class Numace < Numstr
160
- def build_field(buf,length)
161
- f = Field.new(@id)
162
-
181
+ def build_field(buffer, field, length)
163
182
  data = ""
183
+ buf = buffer.slice!(0...length)
164
184
  # if buf to decode is in EBCDIC then convert buf in ASCII
165
- if ( buf[0,length].unpack("C*").select{|c| c >= 128}.size > 0)
166
- buf[0,length].unpack("C*").each { |c| data += EBCDIC_2_ASCII[c] }
185
+ if ( buf.unpack("C*").select{|c| c >= 128}.size > 0)
186
+ buf.unpack("C*").each { |c| data << EBCDIC_2_ASCII[c] }
167
187
  else
168
- data = buf[0,length]
188
+ data = buf
169
189
  end
170
- f.set_value(data.to_i)
171
- return f
190
+ field.set_value(data.to_i)
172
191
  end
173
192
  end
174
193
 
175
194
  class Strace < String
176
- def build_field(buf,length)
177
- f = Field.new(@id)
195
+ def build_field(buffer, field, length)
178
196
  data = ""
197
+ buf = buffer.slice!(0...length)
179
198
  # if buf to decode is in EBCDIC then convert buf in ASCII
180
- if ( buf[0,length].unpack("C*").select{|c| c >= 128}.size > 0)
181
- buf[0,length].unpack("C*").each { |c| data += EBCDIC_2_ASCII[c] }
199
+ if ( buf.unpack("C*").select{|c| c >= 128}.size > 0)
200
+ buf.unpack("C*").each { |c| data += EBCDIC_2_ASCII[c] }
182
201
  else
183
- data = buf[0,length]
202
+ data = buf
184
203
  end
185
- f.set_value(data)
186
- return f
204
+ field.set_value(data)
187
205
  end
188
206
  end
189
207
  end