struct Base64Encoder [src]

Fields

alphabet_chars: [64]u8
pad_char: ?u8

Members

Source

pub const Base64Encoder = struct { alphabet_chars: [64]u8, pad_char: ?u8, /// A bunch of assertions, then simply pass the data right through. pub fn init(alphabet_chars: [64]u8, pad_char: ?u8) Base64Encoder { assert(alphabet_chars.len == 64); var char_in_alphabet = [_]bool{false} ** 256; for (alphabet_chars) |c| { assert(!char_in_alphabet[c]); assert(pad_char == null or c != pad_char.?); char_in_alphabet[c] = true; } return Base64Encoder{ .alphabet_chars = alphabet_chars, .pad_char = pad_char, }; } /// Compute the encoded length pub fn calcSize(encoder: *const Base64Encoder, source_len: usize) usize { if (encoder.pad_char != null) { return @divTrunc(source_len + 2, 3) * 4; } else { const leftover = source_len % 3; return @divTrunc(source_len, 3) * 4 + @divTrunc(leftover * 4 + 2, 3); } } // dest must be compatible with std.io.Writer's writeAll interface pub fn encodeWriter(encoder: *const Base64Encoder, dest: anytype, source: []const u8) !void { var chunker = window(u8, source, 3, 3); while (chunker.next()) |chunk| { var temp: [5]u8 = undefined; const s = encoder.encode(&temp, chunk); try dest.writeAll(s); } } // destWriter must be compatible with std.io.Writer's writeAll interface // sourceReader must be compatible with std.io.Reader's read interface pub fn encodeFromReaderToWriter(encoder: *const Base64Encoder, destWriter: anytype, sourceReader: anytype) !void { while (true) { var tempSource: [3]u8 = undefined; const bytesRead = try sourceReader.read(&tempSource); if (bytesRead == 0) { break; } var temp: [5]u8 = undefined; const s = encoder.encode(&temp, tempSource[0..bytesRead]); try destWriter.writeAll(s); } } /// dest.len must at least be what you get from ::calcSize. pub fn encode(encoder: *const Base64Encoder, dest: []u8, source: []const u8) []const u8 { const out_len = encoder.calcSize(source.len); assert(dest.len >= out_len); var idx: usize = 0; var out_idx: usize = 0; while (idx + 15 < source.len) : (idx += 12) { const bits = std.mem.readInt(u128, source[idx..][0..16], .big); inline for (0..16) |i| { dest[out_idx + i] = encoder.alphabet_chars[@truncate((bits >> (122 - i * 6)) & 0x3f)]; } out_idx += 16; } while (idx + 3 < source.len) : (idx += 3) { const bits = std.mem.readInt(u32, source[idx..][0..4], .big); dest[out_idx] = encoder.alphabet_chars[(bits >> 26) & 0x3f]; dest[out_idx + 1] = encoder.alphabet_chars[(bits >> 20) & 0x3f]; dest[out_idx + 2] = encoder.alphabet_chars[(bits >> 14) & 0x3f]; dest[out_idx + 3] = encoder.alphabet_chars[(bits >> 8) & 0x3f]; out_idx += 4; } if (idx + 2 < source.len) { dest[out_idx] = encoder.alphabet_chars[source[idx] >> 2]; dest[out_idx + 1] = encoder.alphabet_chars[((source[idx] & 0x3) << 4) | (source[idx + 1] >> 4)]; dest[out_idx + 2] = encoder.alphabet_chars[(source[idx + 1] & 0xf) << 2 | (source[idx + 2] >> 6)]; dest[out_idx + 3] = encoder.alphabet_chars[source[idx + 2] & 0x3f]; out_idx += 4; } else if (idx + 1 < source.len) { dest[out_idx] = encoder.alphabet_chars[source[idx] >> 2]; dest[out_idx + 1] = encoder.alphabet_chars[((source[idx] & 0x3) << 4) | (source[idx + 1] >> 4)]; dest[out_idx + 2] = encoder.alphabet_chars[(source[idx + 1] & 0xf) << 2]; out_idx += 3; } else if (idx < source.len) { dest[out_idx] = encoder.alphabet_chars[source[idx] >> 2]; dest[out_idx + 1] = encoder.alphabet_chars[(source[idx] & 0x3) << 4]; out_idx += 2; } if (encoder.pad_char) |pad_char| { for (dest[out_idx..out_len]) |*pad| { pad.* = pad_char; } } return dest[0..out_len]; } }