Class: Junkfood::Base32
- Inherits:
-
Object
- Object
- Junkfood::Base32
- Defined in:
- lib/junkfood/base32.rb
Overview
Base32 (RFC4668/3548) encodes and decodes strings of data.
Requires at least Ruby 1.9
Constant Summary collapse
- ALPHABET =
The Base32 alphabet, all caps.
'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567'
- ALPHABET_DOWNCASE =
The Base32 alphabet, all lowercase.
ALPHABET.downcase
- BYTE_MAP =
Once populated, this is Base32 alphabet to byte mapping.
{}
- IGNORED =
Spacer characters to ignore when parsing a Base32 encoded string.
"\r\n-_\s".bytes.to_a
- SPLITS =
The hash of available break strings that can be inserted between X number of Base32 characters (during the encoding process).
{ dash: '-', newline: "\n", space: ' ', underscore: '_' }.freeze
Class Method Summary collapse
-
.decode(input, options = {}) ⇒ Object
Base32 decodes the input object and writes to the output io object.
-
.encode(input, options = {}) ⇒ Object
Base32 encodes the input object and writes to the output io object.
Class Method Details
.decode(input, options = {}) ⇒ Object
Base32 decodes the input object and writes to the output io object.
175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 |
# File 'lib/junkfood/base32.rb', line 175 def self.decode(input, ={}) output = [:output] || StringIO.new(''.force_encoding('BINARY')) buffer = 0 bits_left = 0 input.each_byte do |byte| next if IGNORED.include? byte raise Base32DecodeError.new("Invalid input byte: #{byte}") unless( BYTE_MAP.key? byte) buffer = (buffer << 5) | BYTE_MAP[byte] bits_left += 5 if bits_left >= 8 bits_left -= 8 output.putc(buffer >> bits_left) buffer &= (2 ** bits_left - 1) end end # We ignore remaining bits in the buffer in cases where there is an # incomplete Base32 quantum (ie, the number of characters are unaligned # with the 40-bit boundries). return output end |
.encode(input, options = {}) ⇒ Object
Base32 encodes the input object and writes to the output io object.
76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 |
# File 'lib/junkfood/base32.rb', line 76 def self.encode(input, ={}) output = [:output] || StringIO.new(''.force_encoding('US-ASCII')) alphabet = [:use_downcase] ? ALPHABET_DOWNCASE : ALPHABET split = SPLITS[[:split]] split_length = [:split_length] || 79 # Set up the lambda that does the actual work of writing the # quintet to the output stream. if split # This lambda will split up the output stream with a "break" character # for every N quintets (where N is the split_length). split_count = 0 write = lambda do |quintet| output.putc alphabet.getbyte(quintet) split_count += 1 if split_count >= split_length output.putc split split_count = 0 end end else # This lambda just writes out the quintets write = lambda do |quintet| output.putc alphabet.getbyte(quintet) end end position = 0 buffer = 0 input.each_byte do |byte| case position when 0 # Current Buffer: 0 bits from previous byte # Quintet: 5 bits from current byte # New Buffer: Lowest 3 bits of current byte write.call(byte >> 3) buffer = byte & 0x07 when 1 # Current Buffer: 3 bits from previous byte # Quintet 1: 3 bits of buffer and first 2 bits of current byte # Quintet 2: next 5 bits of byte # New Buffer: Lowest 1 bit of current byte write.call((buffer << 2) | (byte >> 6)) write.call((byte >> 1) & 0x1f) buffer = byte & 0x01 when 2 # Current Buffer: 1 bits from previous byte # Quintet 1: 1 bits of buffer and 4 bits of current byte # New Buffer: Lowest 4 bits of current byte write.call((buffer << 4) | (byte >> 4)) buffer = byte & 0x0f when 3 # Current Buffer: 4 bits from previous byte # Quintet 1: 4 bits of buffer and top bit of byte # Quintet 2: next 5 bits of byte # New Buffer: bottom 2 bit of byte write.call((buffer << 1) | (byte >> 7)) write.call((byte >> 2) & 0x1f) buffer = byte & 0x03 when 4 # Current Buffer: 2 bits from previous byte # Quintet 1: 2 bits of buffer and top 3 bits of byte # Quintet 2: bottom 5 bits of byte write.call((buffer << 3) | (byte >> 5)) write.call(byte & 0x1f) buffer = 0 end position = (position + 1) % 5 end case position when 0 # We are 40-bit aligned, so nothing to do. when 1 # 3 bits in buffer write.call(buffer << 2) when 2 # 1 bit in buffer write.call(buffer << 4) when 3 # 4 bits in buffer write.call(buffer << 1) when 4 # 2 bits in buffer write.call(buffer << 3) end return output end |