codec 0.0.12 → 1.0.0

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