lib/ascii85.rb in Ascii85-1.0.1 vs lib/ascii85.rb in Ascii85-1.0.2

- old
+ new

@@ -8,11 +8,11 @@ # See http://www.adobe.com/products/postscript/pdfs/PLRM.pdf page 131 # and http://en.wikipedia.org/wiki/Ascii85 for more information about # the format. # # Author:: Johannes Holzfuß (DataWraith@web.de) -# License:: Distributed under the MIT License (see README.rdoc) +# License:: Distributed under the MIT License (see LICENSE file) # module Ascii85 @@ -40,11 +40,11 @@ to_encode = str.to_s return '' if to_encode.empty? # Deal with multi-byte encodings - if to_encode.methods.include?(:bytesize) + if to_encode.respond_to?(:bytesize) input_size = to_encode.bytesize else input_size = to_encode.size end @@ -123,45 +123,41 @@ # def self.decode(str) input = str.to_s - # Try to compile the regular expression for finding the input between - # the <~ and ~> delimiters. In order to work properly with different - # input encodings, the RegExp itself is re-encoded to the input encoding - # if possible. Thanks to Myrddin Emrys for suggesting this approach - # (http://is.gd/5x18O) - begin - regex = "<~(.*?)?~>" + opening_delim = '<~' + closing_delim = '~>' - if regex.methods.include?(:encode) - regex = regex.encode(input.encoding) - end - regex = Regexp.compile(regex, Regexp::MULTILINE) - - # Find the actual data to be decoded - input = input.match(regex) - - rescue EncodingError - raise ArgumentError, "Incompatible input encoding: #{str.encoding.inspect}" + # Make sure the delimiter strings have the correct encoding. + # + # Although I don't think it likely, this may raise encoding + # errors if an especially exotic input encoding is introduced. + # As of Ruby 1.9.2 all non-dummy encodings work fine though. + # + if opening_delim.respond_to?(:encode!) + opening_delim.encode!(input.encoding) + closing_delim.encode!(input.encoding) end - return '' if input.nil? + # Get the positions of the opening/closing delimiters. If there is + # no pair of opening/closing delimiters, return the empty string. + (start_pos = input.index(opening_delim)) or return '' + (end_pos = input.index(closing_delim, start_pos + 2)) or return '' - # Get the matched data as String - input = input.captures.first + # Get the string inside the delimiter-pair + input = input[(start_pos + 2)...end_pos] # Decode + word = 0 + count = 0 result = [] - count = 0 - word = 0 - input.each_byte do |c| case c.chr - when /[ \t\r\n\f\0]/ + when " ", "\t", "\r", "\n", "\f", "\0" # Ignore whitespace next when 'z' if count == 0 @@ -171,22 +167,23 @@ raise(Ascii85::DecodingError, "Found 'z' inside Ascii85 5-tuple") end when '!'..'u' # Decode 5 characters into a 4-byte word - word += (c - 33) * 85**(4 - count) + word += (c - 33) * 85**(4 - count) count += 1 if count == 5 if word > 0xffffffff raise(Ascii85::DecodingError, "Invalid Ascii85 5-tuple (#{word} >= 2**32)") end result << word - word = 0 + + word = 0 count = 0 end else raise(Ascii85::DecodingError, @@ -205,10 +202,10 @@ raise(Ascii85::DecodingError, "Last 5-tuple consists of single character") end count -= 1 - word += 85**(4 - count) + word += 85**(4 - count) result << ((word >> 24) & 255).chr if count >= 1 result << ((word >> 16) & 255).chr if count >= 2 result << ((word >> 8) & 255).chr if count == 3 end