Step 1 of 5 · Reading · ~3 min
Read
Decoding
Four Characters Become Three Bytes
Lesson 3, "Three Bytes Become Four Characters", run backwards: four characters in, three bytes out, with the = count deciding how many of those bytes are real.
How it works
Four base64 characters carry four 6-bit values -- lesson 2's alphabet, "The 64 Characters", read the other way round, character to index. Four sixes are 24 bits, and 24 bits is also three 8-bit bytes. That is the whole lesson: the same 24 bits, recut into three groups of eight instead of four of six.
The shifts and masks are lesson 3's, now on 8-bit fields -- 255 is the mask that keeps eight bits, where 63 kept six.
Packing is lesson 3's cut run backwards: v0 goes 18 places up, each later value shifts 6 fewer than the one before it, the last not at all, and | merges the four into one 24-bit number. Cutting walks back down that number in steps of eight:
b0 = (n >> 16) & 255
Each later byte shifts 8 fewer, so the third needs no shift at all -- only its mask.
Trace SGk=. Count the = first, then pack it as the value 0:
character S G k =
value 18 6 36 0 (pad, packed as 0)
bits 010010 000110 100100 000000
24 bits 010010000110100100000000
regrouped 01001000 01101001 00000000
bytes 48 69 00
Nothing moved between the 24 bits row and the regrouped row: the same twenty-four digits, cut after every eighth instead of after every sixth.
The = count then says how many of the three bytes to keep -- no = keeps 3, one keeps 2, two keep 1. One = here, so keep two and print 4869. The 00 behind them is the encoder's zero fill from lesson 4, "When the Last Group Is Short": dropped, never rounded up into a byte.
The algorithm
for each line of input:
hex = empty string
for i = 0, 4, 8, ... while i + 4 <= line length:
for each byte in decode_group(the four characters at i):
append it as two lowercase hex digits to hex
print hex and a newline
decode_group(group): <- your part
pad = how many '=' the group contains
v0..v3 = each character's 6-bit value, using 0 for '='
n = the four values packed into one 24-bit number
cut three bytes out of n, most significant first
return the first (3 - pad) of them
What the grader runs
Input arrives on stdin, the program's standard input: zero or more lines, each a well-formed base64 string -- length a non-zero multiple of 4, characters from A-Z a-z 0-9 + /, at most two = and only at the end. Bad input is lesson 6's job, "A Strict Decoder Refuses Bad Input".
For each input line print one line: the decoded bytes as lowercase hex, two digits per byte, no separators. Empty stdin prints nothing at all.
input:
SGVsbG8=
SGk=
SA==
////
output:
48656c6c6f
4869
48
ffffff
input:
AAAA
AA==
output:
000000
00
Print exactly this, one result per line, newline-terminated, nothing else.
Notes
- A decoded zero byte is still a byte, printed like any other:
AAA=is0000andAAE=is0001-- never01or1, and hex letters are lowercase. - All-ones data is checked at both pad counts:
//8=isffff,/w==isff. Three=never appears. - Only a line's last group can be padded, so trim by each group's own
=count, not a fixed number. Lines run to 600 characters. - Primary source: RFC 4648, https://www.rfc-editor.org/rfc/rfc4648
Your exercise
Implement decode_group: one 4-character group in, the byte values it carries out. The starter holds the lesson 2 alphabet and lookup, walks each line four characters at a time and prints the hex. Most common mistake: keeping the trailing zero byte of a padded group, so SA== gives 4800 instead of 48.
Discussion
Ask a question, share an insight, or help someone who’s stuck.
Sign in to post a comment or reply.
Loading…