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