Ascii85 2.0.0 → 2.0.1
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +6 -0
- data/lib/Ascii85/version.rb +1 -1
- data/lib/ascii85.rb +34 -20
- data/spec/lib/ascii85_spec.rb +24 -1
- metadata +2 -2
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA256:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: 32c27ed5387adae778bb5f1b5ef82da6ca878d6cd3128dd9a6d65c182ad89296
         | 
| 4 | 
            +
              data.tar.gz: 81ba054e37db894fcb7411c143c6cfade2437bc91fd00956eeaf16233e96c25e
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: da7757b98444ed6e745c0c9aa7930aa20346a273f94d316cb6eae473a6be293fd592320718f3d1eaef0ebc7d877deb4cb8ec0a43b13f4595835f56053abf3e5d
         | 
| 7 | 
            +
              data.tar.gz: e881585d8b1f1cbdba501e7891daa2ed19b268c0b67d0cc8e424d944ce84d16c685b563bc18f34cd92db45b9a8e306e99e7b62b6d41908443eecdc15ee8bcf30
         | 
    
        data/CHANGELOG.md
    CHANGED
    
    
    
        data/lib/Ascii85/version.rb
    CHANGED
    
    
    
        data/lib/ascii85.rb
    CHANGED
    
    | @@ -14,6 +14,11 @@ require 'stringio' | |
| 14 14 | 
             
            #
         | 
| 15 15 | 
             
            module Ascii85
         | 
| 16 16 | 
             
              class << self
         | 
| 17 | 
            +
                EMPTY_STRING  = ''.dup.force_encoding(Encoding::ASCII_8BIT)
         | 
| 18 | 
            +
                START_MARKER  = '<~'.dup.force_encoding(Encoding::ASCII_8BIT)
         | 
| 19 | 
            +
                ENDING_MARKER = '~>'.dup.force_encoding(Encoding::ASCII_8BIT)
         | 
| 20 | 
            +
                LINE_BREAK    = "\n".dup.force_encoding(Encoding::ASCII_8BIT)
         | 
| 21 | 
            +
             | 
| 17 22 | 
             
                #
         | 
| 18 23 | 
             
                # Encodes the bytes of the given String or IO-like object as Ascii85.
         | 
| 19 24 | 
             
                #
         | 
| @@ -55,22 +60,24 @@ module Ascii85 | |
| 55 60 | 
             
                             StringIO.new(str_or_io.to_s, 'rb')
         | 
| 56 61 | 
             
                           end
         | 
| 57 62 |  | 
| 58 | 
            -
                  return  | 
| 63 | 
            +
                  return EMPTY_STRING.dup if reader.eof?
         | 
| 59 64 |  | 
| 60 65 | 
             
                  # Setup buffered Reader and Writers
         | 
| 61 66 | 
             
                  bufreader = BufferedReader.new(reader, unencoded_chunk_size)
         | 
| 62 67 | 
             
                  bufwriter = BufferedWriter.new(out || StringIO.new(String.new, 'wb'), encoded_chunk_size)
         | 
| 63 68 | 
             
                  writer = wrap_lines ? Wrapper.new(bufwriter, wrap_lines) : DummyWrapper.new(bufwriter)
         | 
| 64 69 |  | 
| 65 | 
            -
                  padding = "\0\0\0\0"
         | 
| 66 | 
            -
                  tuplebuf = '!!!!!' | 
| 70 | 
            +
                  padding = unfrozen_binary_copy("\0\0\0\0")
         | 
| 71 | 
            +
                  tuplebuf = unfrozen_binary_copy('!!!!!')
         | 
| 72 | 
            +
                  exclamations = unfrozen_binary_copy('!!!!!')
         | 
| 73 | 
            +
                  z = unfrozen_binary_copy('z')
         | 
| 67 74 |  | 
| 68 75 | 
             
                  bufreader.each_chunk do |chunk|
         | 
| 69 76 | 
             
                    chunk.unpack('N*').each do |word|
         | 
| 70 77 | 
             
                      # Encode each big-endian 32-bit word into a 5-character tuple (except
         | 
| 71 78 | 
             
                      # for 0, which encodes to 'z')
         | 
| 72 79 | 
             
                      if word.zero?
         | 
| 73 | 
            -
                        writer.write( | 
| 80 | 
            +
                        writer.write(z)
         | 
| 74 81 | 
             
                      else
         | 
| 75 82 | 
             
                        word, b0 = word.divmod(85)
         | 
| 76 83 | 
             
                        word, b1 = word.divmod(85)
         | 
| @@ -98,7 +105,7 @@ module Ascii85 | |
| 98 105 |  | 
| 99 106 | 
             
                    # Encode the last word and cut off any padding
         | 
| 100 107 | 
             
                    if word.zero?
         | 
| 101 | 
            -
                      writer.write( | 
| 108 | 
            +
                      writer.write(exclamations[0..(4 - padding_length)])
         | 
| 102 109 | 
             
                    else
         | 
| 103 110 | 
             
                      word, b0 = word.divmod(85)
         | 
| 104 111 | 
             
                      word, b1 = word.divmod(85)
         | 
| @@ -119,7 +126,7 @@ module Ascii85 | |
| 119 126 | 
             
                  # If no output IO-object was provided, extract the encoded String from the
         | 
| 120 127 | 
             
                  # default StringIO writer. We force the encoding to 'ASCII-8BIT' to work
         | 
| 121 128 | 
             
                  # around a TruffleRuby bug.
         | 
| 122 | 
            -
                  return writer.finish.io.string.force_encoding( | 
| 129 | 
            +
                  return writer.finish.io.string.force_encoding(Encoding::ASCII_8BIT) if out.nil?
         | 
| 123 130 |  | 
| 124 131 | 
             
                  # Otherwise we make sure to flush the output writer, and then return it.
         | 
| 125 132 | 
             
                  writer.finish.io
         | 
| @@ -151,8 +158,8 @@ module Ascii85 | |
| 151 158 |  | 
| 152 159 | 
             
                  # Get the positions of the opening/closing delimiters. If there is no pair
         | 
| 153 160 | 
             
                  # of opening/closing delimiters, return an unfrozen empty String.
         | 
| 154 | 
            -
                  (start_pos = input.index(opening_delim))                or return  | 
| 155 | 
            -
                  (end_pos   = input.index(closing_delim, start_pos + 2)) or return  | 
| 161 | 
            +
                  (start_pos = input.index(opening_delim))                or return EMPTY_STRING.dup
         | 
| 162 | 
            +
                  (end_pos   = input.index(closing_delim, start_pos + 2)) or return EMPTY_STRING.dup
         | 
| 156 163 |  | 
| 157 164 | 
             
                  # Get the String inside the delimiter-pair
         | 
| 158 165 | 
             
                  input[(start_pos + 2)...end_pos]
         | 
| @@ -226,7 +233,7 @@ module Ascii85 | |
| 226 233 | 
             
                           end
         | 
| 227 234 |  | 
| 228 235 | 
             
                  # Return an unfrozen String on empty input
         | 
| 229 | 
            -
                  return  | 
| 236 | 
            +
                  return EMPTY_STRING.dup if reader.eof?
         | 
| 230 237 |  | 
| 231 238 | 
             
                  # Setup buffered Reader and Writers
         | 
| 232 239 | 
             
                  bufreader = BufferedReader.new(reader, encoded_chunk_size)
         | 
| @@ -238,7 +245,8 @@ module Ascii85 | |
| 238 245 | 
             
                  # Decode
         | 
| 239 246 | 
             
                  word   = 0
         | 
| 240 247 | 
             
                  count  = 0
         | 
| 241 | 
            -
                   | 
| 248 | 
            +
                  zeroes = unfrozen_binary_copy("\0\0\0\0")
         | 
| 249 | 
            +
                  wordbuf = zeroes.dup
         | 
| 242 250 |  | 
| 243 251 | 
             
                  bufreader.each_chunk do |chunk|
         | 
| 244 252 | 
             
                    chunk.each_byte do |c|
         | 
| @@ -251,7 +259,7 @@ module Ascii85 | |
| 251 259 | 
             
                        raise(Ascii85::DecodingError, "Found 'z' inside Ascii85 5-tuple") unless count.zero?
         | 
| 252 260 |  | 
| 253 261 | 
             
                        # Expand z to 0-word
         | 
| 254 | 
            -
                        bufwriter.write( | 
| 262 | 
            +
                        bufwriter.write(zeroes)
         | 
| 255 263 |  | 
| 256 264 | 
             
                      when '!'..'u'
         | 
| 257 265 | 
             
                        # Decode 5 characters into a 4-byte word
         | 
| @@ -286,7 +294,7 @@ module Ascii85 | |
| 286 294 | 
             
                  # We're done if all 5-tuples have been consumed
         | 
| 287 295 | 
             
                  if count.zero?
         | 
| 288 296 | 
             
                    bufwriter.flush
         | 
| 289 | 
            -
                    return out || bufwriter.io.string.force_encoding( | 
| 297 | 
            +
                    return out || bufwriter.io.string.force_encoding(Encoding::ASCII_8BIT)
         | 
| 290 298 | 
             
                  end
         | 
| 291 299 |  | 
| 292 300 | 
             
                  raise(Ascii85::DecodingError, 'Last 5-tuple consists of single character') if count == 1
         | 
| @@ -300,11 +308,17 @@ module Ascii85 | |
| 300 308 | 
             
                  bufwriter.write(((word >> 8) & 0xff).chr) if count == 3
         | 
| 301 309 | 
             
                  bufwriter.flush
         | 
| 302 310 |  | 
| 303 | 
            -
                  out || bufwriter.io.string.force_encoding( | 
| 311 | 
            +
                  out || bufwriter.io.string.force_encoding(Encoding::ASCII_8BIT)
         | 
| 304 312 | 
             
                end
         | 
| 305 313 |  | 
| 306 314 | 
             
                private
         | 
| 307 315 |  | 
| 316 | 
            +
                # Copies the given String and forces the encoding of the returned copy to
         | 
| 317 | 
            +
                # be Encoding::ASCII_8BIT.
         | 
| 318 | 
            +
                def unfrozen_binary_copy(str)
         | 
| 319 | 
            +
                  str.dup.force_encoding(Encoding::ASCII_8BIT)
         | 
| 320 | 
            +
                end
         | 
| 321 | 
            +
             | 
| 308 322 | 
             
                # Buffers an underlying IO object to increase efficiency. You do not need
         | 
| 309 323 | 
             
                # to use this directly.
         | 
| 310 324 | 
             
                #
         | 
| @@ -337,7 +351,7 @@ module Ascii85 | |
| 337 351 | 
             
                  def initialize(io, buffer_size)
         | 
| 338 352 | 
             
                    @io = io
         | 
| 339 353 | 
             
                    @buffer_size = buffer_size
         | 
| 340 | 
            -
                    @buffer = String.new(capacity: buffer_size)
         | 
| 354 | 
            +
                    @buffer = String.new(capacity: buffer_size, encoding: Encoding::ASCII_8BIT)
         | 
| 341 355 | 
             
                  end
         | 
| 342 356 |  | 
| 343 357 | 
             
                  def write(tuple)
         | 
| @@ -360,7 +374,7 @@ module Ascii85 | |
| 360 374 | 
             
                class DummyWrapper
         | 
| 361 375 | 
             
                  def initialize(out)
         | 
| 362 376 | 
             
                    @out = out
         | 
| 363 | 
            -
                    @out.write( | 
| 377 | 
            +
                    @out.write(START_MARKER)
         | 
| 364 378 | 
             
                  end
         | 
| 365 379 |  | 
| 366 380 | 
             
                  def write(buffer)
         | 
| @@ -368,7 +382,7 @@ module Ascii85 | |
| 368 382 | 
             
                  end
         | 
| 369 383 |  | 
| 370 384 | 
             
                  def finish
         | 
| 371 | 
            -
                    @out.write( | 
| 385 | 
            +
                    @out.write(ENDING_MARKER)
         | 
| 372 386 | 
             
                    @out.flush
         | 
| 373 387 |  | 
| 374 388 | 
             
                    @out
         | 
| @@ -385,7 +399,7 @@ module Ascii85 | |
| 385 399 | 
             
                    @line_length = [2, wrap_lines.to_i].max
         | 
| 386 400 |  | 
| 387 401 | 
             
                    @out = out
         | 
| 388 | 
            -
                    @out.write( | 
| 402 | 
            +
                    @out.write(START_MARKER)
         | 
| 389 403 |  | 
| 390 404 | 
             
                    @cur_len = 2
         | 
| 391 405 | 
             
                  end
         | 
| @@ -402,7 +416,7 @@ module Ascii85 | |
| 402 416 |  | 
| 403 417 | 
             
                      remaining = @line_length - @cur_len
         | 
| 404 418 | 
             
                      @out.write(buffer[0...remaining])
         | 
| 405 | 
            -
                      @out.write( | 
| 419 | 
            +
                      @out.write(LINE_BREAK)
         | 
| 406 420 | 
             
                      @cur_len = 0
         | 
| 407 421 | 
             
                      buffer = buffer[remaining..]
         | 
| 408 422 | 
             
                      return if buffer.empty?
         | 
| @@ -411,8 +425,8 @@ module Ascii85 | |
| 411 425 |  | 
| 412 426 | 
             
                  def finish
         | 
| 413 427 | 
             
                    # Add the closing delimiter (may need to be pushed to the next line)
         | 
| 414 | 
            -
                    @out.write( | 
| 415 | 
            -
                    @out.write( | 
| 428 | 
            +
                    @out.write(LINE_BREAK) if @cur_len + 2 > @line_length
         | 
| 429 | 
            +
                    @out.write(ENDING_MARKER)
         | 
| 416 430 |  | 
| 417 431 | 
             
                    @out.flush
         | 
| 418 432 | 
             
                    @out
         | 
    
        data/spec/lib/ascii85_spec.rb
    CHANGED
    
    | @@ -35,7 +35,11 @@ TEST_CASES = { | |
| 35 35 | 
             
                  '<~j+42iJVN3:K&_E6j+<0KJW/W?W8iG`j+EuaK"9on^Z0sZj+FJoK:LtSKB%T?~>',
         | 
| 36 36 |  | 
| 37 37 | 
             
              [Math::PI].pack('G') => '<~5RAV2<(&;T~>',
         | 
| 38 | 
            -
              [Math::E].pack('G') => '<~5R"n0M\\K6,~>'
         | 
| 38 | 
            +
              [Math::E].pack('G') => '<~5R"n0M\\K6,~>',
         | 
| 39 | 
            +
             | 
| 40 | 
            +
              # Minified example from Github issue 8.
         | 
| 41 | 
            +
              # Note that OT and OU as the trailing characters are equivalent.
         | 
| 42 | 
            +
              "\x9B\xB6\xB9+\x91" => '<~S$ojXOT~>'
         | 
| 39 43 | 
             
            }.freeze
         | 
| 40 44 |  | 
| 41 45 | 
             
            describe Ascii85 do
         | 
| @@ -59,6 +63,12 @@ describe Ascii85 do | |
| 59 63 | 
             
                  end
         | 
| 60 64 | 
             
                end
         | 
| 61 65 |  | 
| 66 | 
            +
                it 'should always return unfrozen Strings' do
         | 
| 67 | 
            +
                  TEST_CASES.each_pair do |input, encoded|
         | 
| 68 | 
            +
                    assert_equal false, Ascii85.encode(input).frozen?
         | 
| 69 | 
            +
                  end
         | 
| 70 | 
            +
                end
         | 
| 71 | 
            +
             | 
| 62 72 | 
             
                it 'should encode Strings in different encodings correctly' do
         | 
| 63 73 | 
             
                  input_euc_jp = 'どうもありがとうミスターロボット'.encode('EUC-JP')
         | 
| 64 74 | 
             
                  input_binary = input_euc_jp.force_encoding('ASCII-8BIT')
         | 
| @@ -139,6 +149,12 @@ describe Ascii85 do | |
| 139 149 | 
             
                  end
         | 
| 140 150 | 
             
                end
         | 
| 141 151 |  | 
| 152 | 
            +
                it 'should always return unfrozen Strings' do
         | 
| 153 | 
            +
                  TEST_CASES.each_pair do |input, encoded|
         | 
| 154 | 
            +
                    assert_equal false, Ascii85.decode(encoded).frozen?
         | 
| 155 | 
            +
                  end
         | 
| 156 | 
            +
                end
         | 
| 157 | 
            +
             | 
| 142 158 | 
             
                it 'should accept valid input in encodings other than the default' do
         | 
| 143 159 | 
             
                  input = 'Ragnarök  τέχνη  русский язык  I ♥ Ruby'
         | 
| 144 160 | 
             
                  input_ascii85 = Ascii85.encode(input)
         | 
| @@ -217,6 +233,13 @@ describe Ascii85 do | |
| 217 233 | 
             
                  end
         | 
| 218 234 | 
             
                end
         | 
| 219 235 |  | 
| 236 | 
            +
                it 'should always return unfrozen Strings' do
         | 
| 237 | 
            +
                  TEST_CASES.each_pair do |decoded, input|
         | 
| 238 | 
            +
                    raw_input = input[2...-2] # Remove '<~' and '~>'
         | 
| 239 | 
            +
                    assert_equal false, Ascii85.decode_raw(raw_input).frozen?
         | 
| 240 | 
            +
                  end
         | 
| 241 | 
            +
                end
         | 
| 242 | 
            +
             | 
| 220 243 | 
             
                it 'should decode from an IO object' do
         | 
| 221 244 | 
             
                  input = StringIO.new(';KZGo')
         | 
| 222 245 | 
             
                  result = Ascii85.decode_raw(input)
         | 
    
        metadata
    CHANGED
    
    | @@ -1,14 +1,14 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: Ascii85
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version: 2.0. | 
| 4 | 
            +
              version: 2.0.1
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - Johannes Holzfuß
         | 
| 8 8 | 
             
            autorequire:
         | 
| 9 9 | 
             
            bindir: bin
         | 
| 10 10 | 
             
            cert_chain: []
         | 
| 11 | 
            -
            date: 2024- | 
| 11 | 
            +
            date: 2024-09-15 00:00:00.000000000 Z
         | 
| 12 12 | 
             
            dependencies:
         | 
| 13 13 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 14 14 | 
             
              name: minitest
         |