Module: Philiprehberger::BaseConvert::Base85

Defined in:
lib/philiprehberger/base_convert/base85.rb

Overview

ASCII85 (Base85) encoding and decoding

Uses the standard ASCII85 character set (chars 33-117)

Constant Summary collapse

ENCODE_OFFSET =
33
BASE =
85

Class Method Summary collapse

Class Method Details

.decode(string) ⇒ String

Decode an ASCII85 string

Parameters:

  • string (String)

    the ASCII85-encoded string

Returns:

  • (String)

    the decoded string

Raises:

  • (Error)

    if the string contains invalid characters



48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
# File 'lib/philiprehberger/base_convert/base85.rb', line 48

def self.decode(string)
  return '' if string.empty?

  expanded = string.gsub('z', '!!!!!')
  padding = (5 - (expanded.length % 5)) % 5
  expanded += ('u' * padding)

  result = []
  expanded.each_char.each_slice(5) do |group|
    value = 0
    group.each do |char|
      code = char.ord - ENCODE_OFFSET
      raise Error, "invalid Base85 character: #{char}" if code.negative? || code >= BASE

      value = (value * BASE) + code
    end

    result << [(value >> 24) & 0xFF, (value >> 16) & 0xFF, (value >> 8) & 0xFF, value & 0xFF]
  end

  decoded = result.flatten.pack('C*')
  decoded = decoded[0...(decoded.length - padding)] if padding.positive?
  decoded
end

.encode(string) ⇒ String

Encode a string to ASCII85

Parameters:

  • string (String)

    the input string

Returns:

  • (String)

    the ASCII85-encoded string



16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
# File 'lib/philiprehberger/base_convert/base85.rb', line 16

def self.encode(string)
  return '' if string.empty?

  padding = (4 - (string.bytesize % 4)) % 4
  padded = string + ("\x00" * padding)

  result = []
  padded.bytes.each_slice(4) do |group|
    value = (group[0] << 24) | (group[1] << 16) | (group[2] << 8) | group[3]

    if value.zero?
      result << 'z'
    else
      chunk = []
      5.times do
        chunk << ((value % BASE) + ENCODE_OFFSET).chr
        value /= BASE
      end
      result << chunk.reverse.join
    end
  end

  encoded = result.join
  encoded = encoded[0...(encoded.length - padding)] if padding.positive?
  encoded
end