@@ -40,100 +40,97 @@ module BERParser
4040 # of this one.
4141 #
4242 def read_ber syntax = nil
43- # don't bother with this line, since IO#getc by definition returns nil on eof.
44- #return nil if eof?
43+ # don't bother with this line, since IO#getc by definition returns nil on eof.
44+ #return nil if eof?
4545
46- # here we'll create two different procs, one for 1.8 and one for 1.9
47- # the reason being getc doesn't return a byte value in 1.9, so we need to
48- # get the byte code out of the 1.9 encoded string
46+ # here we'll create two different procs, one for 1.8 and one for 1.9
47+ # the reason being getc doesn't return a byte value in 1.9, so we need to
48+ # get the byte code out of the 1.9 encoded string
4949
50- if RUBY_VERSION =~ /^1\. 9/
51- fetch_byte = Proc . new { getc . bytes . first }
50+ if RUBY_VERSION =~ /^1\. 9/
51+ fetch_byte = Proc . new { getc . bytes . first }
5252 elsif RUBY_VERSION =~ /^1\. 8/
53- fetch_byte = Proc . new { getc }
54- end
55-
56- id = fetch_byte . call or return nil # don't trash this value, we'll use it later
57- #tag = id & 31
58- #tag < 31 or raise BerError.new( "unsupported tag encoding: #{id}" )
59- #tagclass = TagClasses[ id >> 6 ]
60- #encoding = (id & 0x20 != 0) ? :constructed : :primitive
61-
62- n = fetch_byte . call
63- lengthlength , contentlength = if n <= 127
64- [ 1 , n ]
65- else
66- # Replaced the inject because it profiles hot.
67- #j = (0...(n & 127)).inject(0) {|mem,x| mem = (mem << 8) + getc}
68- j = 0
69- read ( n & 127 ) . each_byte { |n1 | j = ( j << 8 ) + n1 }
70- [ 1 + ( n & 127 ) , j ]
71- end
72-
73- newobj = read contentlength
53+ fetch_byte = Proc . new { getc }
54+ end
7455
75- # This exceptionally clever and clear bit of code is verrrry slow.
76- objtype = ( syntax && syntax [ id ] ) || BuiltinSyntax [ id ]
56+ id = fetch_byte . call or return nil # don't trash this value, we'll use it later
57+ #tag = id & 31
58+ #tag < 31 or raise BerError.new( "unsupported tag encoding: #{id}" )
59+ #tagclass = TagClasses[ id >> 6 ]
60+ #encoding = (id & 0x20 != 0) ? :constructed : :primitive
7761
62+ n = fetch_byte . call
63+ lengthlength , contentlength = if n <= 127
64+ [ 1 , n ]
65+ else
66+ # Replaced the inject because it profiles hot.
67+ #j = (0...(n & 127)).inject(0) {|mem,x| mem = (mem << 8) + getc}
68+ j = 0
69+ read ( n & 127 ) . each_byte { |n1 | j = ( j << 8 ) + n1 }
70+ [ 1 + ( n & 127 ) , j ]
71+ end
7872
79- # == is expensive so sort this if/else so the common cases are at the top.
80- obj = if objtype == :string
81- #(newobj || "").dup
82- s = BerIdentifiedString . new ( newobj || "" )
83- s . ber_identifier = id
84- s
85- elsif objtype == :integer
86- j = 0
87- newobj . each_byte { |b | j = ( j << 8 ) + b }
88- j
89- elsif objtype == :oid
90- # cf X.690 pgh 8.19 for an explanation of this algorithm.
91- # Potentially not good enough. We may need a BerIdentifiedOid
92- # as a subclass of BerIdentifiedArray, to get the ber identifier
93- # and also a to_s method that produces the familiar dotted notation.
94- oid = newobj . unpack ( "w*" )
95- f = oid . shift
96- g = if f < 40
73+ newobj = read contentlength
74+
75+ # This exceptionally clever and clear bit of code is verrrry slow.
76+ objtype = ( syntax && syntax [ id ] ) || BuiltinSyntax [ id ]
77+
78+ # == is expensive so sort this if/else so the common cases are at the top.
79+ obj = if objtype == :string
80+ #(newobj || "").dup
81+ s = BerIdentifiedString . new ( newobj || "" )
82+ s . ber_identifier = id
83+ s
84+ elsif objtype == :integer
85+ j = 0
86+ newobj . each_byte { |b | j = ( j << 8 ) + b }
87+ j
88+ elsif objtype == :oid
89+ # cf X.690 pgh 8.19 for an explanation of this algorithm.
90+ # Potentially not good enough. We may need a BerIdentifiedOid
91+ # as a subclass of BerIdentifiedArray, to get the ber identifier
92+ # and also a to_s method that produces the familiar dotted notation.
93+ oid = newobj . unpack ( "w*" )
94+ f = oid . shift
95+ g = if f < 40
9796 [ 0 , f ]
98- elsif f < 80
97+ elsif f < 80
9998 [ 1 , f -40 ]
100- else
99+ else
101100 [ 2 , f -80 ] # f-80 can easily be > 80. What a weird optimization.
101+ end
102+ oid . unshift g . last
103+ oid . unshift g . first
104+ oid
105+ elsif objtype == :array
106+ #seq = []
107+ seq = BerIdentifiedArray . new
108+ seq . ber_identifier = id
109+ sio = StringIO . new ( newobj || "" )
110+ # Interpret the subobject, but note how the loop
111+ # is built: nil ends the loop, but false (a valid
112+ # BER value) does not!
113+ while ( e = sio . read_ber ( syntax ) ) != nil
114+ seq << e
115+ end
116+ seq
117+ elsif objtype == :boolean
118+ newobj != "\000 "
119+ elsif objtype == :null
120+ n = BerIdentifiedNull . new
121+ n . ber_identifier = id
122+ n
123+ else
124+ #raise BerError.new( "unsupported object type: class=#{tagclass}, encoding=#{encoding}, tag=#{tag}" )
125+ raise BerError . new ( "unsupported object type: id=#{ id } " )
102126 end
103- oid . unshift g . last
104- oid . unshift g . first
105- oid
106- elsif objtype == :array
107- #seq = []
108- seq = BerIdentifiedArray . new
109- seq . ber_identifier = id
110- sio = StringIO . new ( newobj || "" )
111- # Interpret the subobject, but note how the loop
112- # is built: nil ends the loop, but false (a valid
113- # BER value) does not!
114- while ( e = sio . read_ber ( syntax ) ) != nil
115- seq << e
116- end
117- seq
118- elsif objtype == :boolean
119- newobj != "\000 "
120- elsif objtype == :null
121- n = BerIdentifiedNull . new
122- n . ber_identifier = id
123- n
124- else
125- #raise BerError.new( "unsupported object type: class=#{tagclass}, encoding=#{encoding}, tag=#{tag}" )
126- raise BerError . new ( "unsupported object type: id=#{ id } " )
127- end
128-
129- # Add the identifier bits into the object if it's a String or an Array.
130- # We can't add extra stuff to Fixnums and booleans, not that it makes much sense anyway.
131- # Replaced this mechanism with subclasses because the instance_eval profiled too hot.
132- #obj and ([String,Array].include? obj.class) and obj.instance_eval "def ber_identifier; #{id}; end"
133- #obj.ber_identifier = id if obj.respond_to?(:ber_identifier)
134- obj
135-
136- end
127+ # Add the identifier bits into the object if it's a String or an Array.
128+ # We can't add extra stuff to Fixnums and booleans, not that it makes much sense anyway.
129+ # Replaced this mechanism with subclasses because the instance_eval profiled too hot.
130+ #obj and ([String,Array].include? obj.class) and obj.instance_eval "def ber_identifier; #{id}; end"
131+ #obj.ber_identifier = id if obj.respond_to?(:ber_identifier)
132+ obj
133+ end
137134
138135 #--
139136 # Violates DRY! This replicates the functionality of #read_ber.
@@ -145,77 +142,77 @@ def read_ber syntax=nil
145142 #
146143 # Observe that weirdly we recursively call the original #read_ber in here.
147144 # That needs to be fixed if we ever obsolete the original method in favor of this one.
148- def read_ber_from_string str , syntax = nil
149- id = str [ 0 ] or return nil
150- n = str [ 1 ] or return nil
151- n_consumed = 2
152- lengthlength , contentlength = if n <= 127
153- [ 1 , n ]
154- else
155- n1 = n & 127
156- return nil unless str . length >= ( n_consumed + n1 )
157- j = 0
158- n1 . times {
159- j = ( j << 8 ) + str [ n_consumed ]
160- n_consumed += 1
161- }
162- [ 1 + ( n1 ) , j ]
163- end
164-
165- return nil unless str . length >= ( n_consumed + contentlength )
145+ def read_ber_from_string str , syntax = nil
146+ id = str [ 0 ] . ord or return nil
147+ n = str [ 1 ] . ord or return nil
148+ n_consumed = 2
149+ lengthlength , contentlength = if n <= 127
150+ [ 1 , n ]
151+ else
152+ n1 = n & 127
153+ return nil unless str . length >= ( n_consumed + n1 )
154+ j = 0
155+ n1 . times {
156+ j = ( j << 8 ) + str [ n_consumed ]
157+ n_consumed += 1
158+ }
159+ [ 1 + ( n1 ) , j ]
160+ end
161+
162+ return nil unless str . length >= ( n_consumed + contentlength )
166163 newobj = str [ n_consumed ...( n_consumed + contentlength ) ]
167164 n_consumed += contentlength
168165
169166 objtype = ( syntax && syntax [ id ] ) || BuiltinSyntax [ id ]
170167
171168 # == is expensive so sort this if/else so the common cases are at the top.
172169 obj = if objtype == :array
173- seq = BerIdentifiedArray . new
174- seq . ber_identifier = id
175- sio = StringIO . new ( newobj || "" )
176- # Interpret the subobject, but note how the loop
177- # is built: nil ends the loop, but false (a valid
178- # BER value) does not!
179- # Also, we can use the standard read_ber method because
180- # we know for sure we have enough data. (Although this
181- # might be faster than the standard method.)
182- while ( e = sio . read_ber ( syntax ) ) != nil
183- seq << e
184- end
185- seq
170+ seq = BerIdentifiedArray . new
171+ seq . ber_identifier = id
172+ sio = StringIO . new ( newobj || "" )
173+ # Interpret the subobject, but note how the loop
174+ # is built: nil ends the loop, but false (a valid
175+ # BER value) does not!
176+ # Also, we can use the standard read_ber method because
177+ # we know for sure we have enough data. (Although this
178+ # might be faster than the standard method.)
179+ while ( e = sio . read_ber ( syntax ) ) != nil
180+ seq << e
181+ end
182+ seq
186183 elsif objtype == :string
187- s = BerIdentifiedString . new ( newobj || "" )
188- s . ber_identifier = id
189- s
184+ s = BerIdentifiedString . new ( newobj || "" )
185+ s . ber_identifier = id
186+ s
190187 elsif objtype == :integer
191- j = 0
192- newobj . each_byte { |b | j = ( j << 8 ) + b }
193- j
188+ j = 0
189+ newobj . each_byte { |b | j = ( j << 8 ) + b }
190+ j
194191 elsif objtype == :oid
195- # cf X.690 pgh 8.19 for an explanation of this algorithm.
196- # Potentially not good enough. We may need a BerIdentifiedOid
197- # as a subclass of BerIdentifiedArray, to get the ber identifier
198- # and also a to_s method that produces the familiar dotted notation.
199- oid = newobj . unpack ( "w*" )
200- f = oid . shift
201- g = if f < 40
202- [ 0 , f ]
203- elsif f < 80
204- [ 1 , f -40 ]
205- else
206- [ 2 , f -80 ] # f-80 can easily be > 80. What a weird optimization.
207- end
208- oid . unshift g . last
209- oid . unshift g . first
210- oid
192+ # cf X.690 pgh 8.19 for an explanation of this algorithm.
193+ # Potentially not good enough. We may need a BerIdentifiedOid
194+ # as a subclass of BerIdentifiedArray, to get the ber identifier
195+ # and also a to_s method that produces the familiar dotted notation.
196+ oid = newobj . unpack ( "w*" )
197+ f = oid . shift
198+ g = if f < 40
199+ [ 0 , f ]
200+ elsif f < 80
201+ [ 1 , f -40 ]
202+ else
203+ [ 2 , f -80 ] # f-80 can easily be > 80. What a weird optimization.
204+ end
205+ oid . unshift g . last
206+ oid . unshift g . first
207+ oid
211208 elsif objtype == :boolean
212- newobj != "\000 "
209+ newobj != "\000 "
213210 elsif objtype == :null
214- n = BerIdentifiedNull . new
215- n . ber_identifier = id
216- n
211+ n = BerIdentifiedNull . new
212+ n . ber_identifier = id
213+ n
217214 else
218- raise BerError . new ( "unsupported object type: id=#{ id } " )
215+ raise BerError . new ( "unsupported object type: id=#{ id } " )
219216 end
220217
221218 [ obj , n_consumed ]
0 commit comments