commit - 607bf5021e1a577acad43ed656d8a9794fd9e8a2
commit + 8fb7891fe1bfed2396147321d7e595e6be6b013b
blob - 012f15012880a9e81f3aac78532b418bb34fd318
blob + 5bc4dc5387961dcd1441a86aa1367a24742cbec3
--- src/base64.zig
+++ src/base64.zig
IndexNotFound,
};
-pub const Base64 = struct {
- table: *const [64]u8,
+fn char_at(index: u8) u8 {
+ const table: *const [64]u8 = comptime "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+ return table[index];
+}
- pub const init: Base64 = .{
- .table = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",
- };
-
- fn char_at(self: Base64, index: u8) u8 {
- return self.table[index];
+pub fn encode(allocator: std.mem.Allocator, input: []const u8) ![]u8 {
+ if (input.len == 0) {
+ return "";
}
- pub fn encode(self: Base64, allocator: std.mem.Allocator, input: []const u8) ![]u8 {
- if (input.len == 0) {
- return "";
+ const out_sz = try calc_encode_length(input);
+ var out = try allocator.alloc(u8, out_sz);
+ var buf = [3]u8{0, 0, 0};
+ var count: u16 = 0;
+ var outc: u16 = 0;
+
+ for (input) |b| {
+ buf[count] = b;
+ count += 1;
+ if (count == 3) {
+ out[outc] = char_at(buf[0] >> 2);
+ out[outc + 1] = char_at(((buf[0] & 0x03) << 4) + (buf[1] >> 4));
+ out[outc + 2] = char_at(((buf[1] & 0x0F) << 2) + (buf[2] >> 6));
+ out[outc + 3] = char_at(buf[2] & 0x3F);
+ count = 0;
+ outc += 4;
}
+ }
- const encode_length = try calc_encode_length(input);
- var out = try allocator.alloc(u8, encode_length);
- var buf = [3]u8{0, 0, 0};
- var count: u16 = 0;
- var outc: u16 = 0;
+ if (count == 2) {
+ out[outc] = char_at(buf[0] >> 2);
+ out[outc + 1] = char_at((buf[0] & 0x03) << 4) + (buf[1] >> 4);
+ out[outc + 2] = char_at((buf[1] & 0x0F) << 2);
+ out[outc + 3] = '=';
+ } else if (count == 1) {
+ out[outc] = char_at(buf[0] >> 2);
+ out[outc + 1] = char_at((buf[0] & 0x03) << 4);
+ out[outc + 2] = '=';
+ out[outc + 3] = '=';
+ }
- for (input) |b| {
- buf[count] = b;
- count += 1;
- if (count == 3) {
- out[outc] = self.char_at(buf[0] >> 2);
- out[outc + 1] = self.char_at(((buf[0] & 0x03) << 4) + (buf[1] >> 4));
- out[outc + 2] = self.char_at(((buf[1] & 0x0F) << 2) + (buf[2] >> 6));
- out[outc + 3] = self.char_at(buf[2] & 0x3F);
- count = 0;
- outc += 4;
- }
- }
+ return out;
+}
- if (count == 2) {
- out[outc] = self.char_at(buf[0] >> 2);
- out[outc + 1] = self.char_at((buf[0] & 0x03) << 4) + (buf[1] >> 4);
- out[outc + 2] = self.char_at((buf[1] & 0x0F) << 2);
- out[outc + 3] = '=';
- } else if (count == 1) {
- out[outc] = self.char_at(buf[0] >> 2);
- out[outc + 1] = self.char_at((buf[0] & 0x03) << 4);
- out[outc + 2] = '=';
- out[outc + 3] = '=';
- }
+fn decode_index(char: u8) err!u8 {
+ if (char == '=') {
+ return 64;
+ }
- return out;
+ if (char >= 'A' and char <= 'Z') {
+ return char - 'A';
+ } else if (char >= 'a' and char <= 'z') {
+ return char - 'a' + 26;
+ } else if (char >= '0' and char <= '9') {
+ return char - '0' + 52;
}
- fn decode_index(self: Base64, char: u8) err!u8 {
- if (char == '=') {
- return 64;
- }
- if (char >= 'A' and char <= 'Z') {
- return char - 'A';
- } else if (char >= 'a' and char <= 'z') {
- return char - 'a' + 26;
- } else {
- for (52..64) |i| {
- const idx: u8 = @intCast(i);
- if (self.char_at(idx) == char) {
- return idx;
- }
- }
- }
- return err.IndexNotFound;
+ switch (char) {
+ '+' => { return 62; },
+ '/' => { return 63; },
+ '=' => { return 64; },
+ else => { return err.IndexNotFound; }
}
+}
- pub fn decode(self: Base64, allocator: std.mem.Allocator, input: []const u8) ![]u8 {
- if (input.len == 0) {
- return "";
- }
+pub fn decode(allocator: std.mem.Allocator, input: []const u8) ![]u8 {
+ if (input.len == 0) {
+ return "";
+ }
- const output_sz = try calc_decode_length(input);
- var output = try allocator.alloc(u8, output_sz);
- var count: u8 = 0;
- var iout: u64 = 0;
- var buf = [4]u8{ 0, 0, 0, 0 };
+ const out_sz = try calc_decode_length(input);
+ var out = try allocator.alloc(u8, out_sz);
+ var count: u8 = 0;
+ var iout: u64 = 0;
+ var buf = [4]u8{ 0, 0, 0, 0 };
+ var cutoff :u8 = 0;
- for (0..input.len) |i| {
- buf[count] = try self.decode_index(input[i]);
- count += 1;
- if (count == 4) {
- output[iout] = (buf[0] << 2) + (buf[1] >> 4);
- if (buf[2] != 64) {
- output[iout + 1] = (buf[1] << 4) + (buf[2] >> 2);
- }
- if (buf[3] != 64) {
- output[iout + 2] = (buf[2] << 6) + buf[3];
- }
- iout += 3;
- count = 0;
+ for (0..input.len) |i| {
+ buf[count] = try decode_index(input[i]);
+ count += 1;
+ if (count == 4) {
+ out[iout] = (buf[0] << 2) + (buf[1] >> 4);
+ if (buf[2] != 64) {
+ out[iout + 1] = (buf[1] << 4) + (buf[2] >> 2);
+ cutoff = 2;
}
+ if (buf[3] != 64) {
+ out[iout + 2] = (buf[2] << 6) + buf[3];
+ cutoff = 1;
+ }
+ iout += 3;
+ count = 0;
}
-
- return output;
}
-};
+ return out[0..out.len - cutoff + 1];
+}
+
fn calc_encode_length(input: []const u8) !usize {
if (input.len < 3) {
return 4;
}
test "encode hello" {
- var b = Base64.init;
var gpa = std.heap.GeneralPurposeAllocator(.{}).init;
const allocator = gpa.allocator();
- const encoded = try b.encode(allocator, "hello");
+ const encoded = try encode(allocator, "hello");
try std.testing.expect(std.mem.eql(u8, encoded, "aGVsbG8="));
}
test "encode long" {
- var b = Base64.init;
var gpa = std.heap.GeneralPurposeAllocator(.{}).init;
const allocator = gpa.allocator();
- const encoded = try b.encode(allocator, "Hey, it's me. I'm the problem. It's me");
+ const encoded = try encode(allocator, "Hey, it's me. I'm the problem. It's me");
try std.testing.expect(std.mem.eql(u8, encoded, "SGV5LCBpdCdzIG1lLiBJJ20gdGhlIHByb2JsZW0uIEl0J3MgbWU="));
}
test "decode hello" {
- var b = Base64.init;
var gpa = std.heap.GeneralPurposeAllocator(.{}).init;
const allocator = gpa.allocator();
- const encoded = try b.decode(allocator, "aGVsbG8=");
+ const encoded = try decode(allocator, "aGVsbG8=");
try stdout.print("{s}\n", .{encoded});
try std.testing.expect(std.mem.eql(u8, encoded, "hello"));
}
test "decode long" {
- var b = Base64.init;
var gpa = std.heap.GeneralPurposeAllocator(.{}).init;
const allocator = gpa.allocator();
- const encoded = try b.decode(allocator, "SGV5LCBpdCdzIG1lLiBJJ20gdGhlIHByb2JsZW0uIEl0J3MgbWU=");
+ const encoded = try decode(allocator, "SGV5LCBpdCdzIG1lLiBJJ20gdGhlIHByb2JsZW0uIEl0J3MgbWU=");
try stdout.print("{s}\n", .{encoded});
try std.testing.expect(std.mem.eql(u8, encoded, "Hey, it's me. I'm the problem. It's me"));
}
test "decode_index" {
- var b = Base64.init;
+ try std.testing.expectError(err.IndexNotFound, decode_index('{'));
- try std.testing.expectError(err.IndexNotFound, b.decode_index('{'));
-
var r :u8 = 0;
- r = try b.decode_index('A');
+ r = try decode_index('A');
try std.testing.expect(r == 0);
- r = try b.decode_index('a');
+ r = try decode_index('a');
try std.testing.expect(r == 26);
- r = try b.decode_index('0');
+ r = try decode_index('0');
try std.testing.expect(r == 52);
- r = try b.decode_index('/');
+ r = try decode_index('/');
try std.testing.expect(r == 63);
- r = try b.decode_index('=');
+ r = try decode_index('=');
try std.testing.expect(r == 64);
}
blob - 56015e8a737a28061417174c3b491cda98bf5ab1
blob + e621fefdd7350ee436ddf1bc8f6e2f59add8aee6
--- src/main.zig
+++ src/main.zig
const std = @import("std");
const stdout = std.io.getStdOut().writer();
-const b64 = @import("base64.zig");
+const Base64 = @import("base64.zig");
const usageText =
\\Usage: baze64 {-d/-D} input
var args = try std.process.argsWithAllocator(allocator);
defer args.deinit();
- var b = b64.Base64.init;
+ var decodeSwitch = false;
+ var input: []const u8 = undefined;
// Skip arg[0]
_ = args.skip();
- var a = args.next();
- if (a) |arg| {
+ while (true) {
+ const argVal = args.next();
+ var arg: []const u8 = undefined;
+ if (argVal) |a| {
+ arg = a;
+ } else {
+ break;
+ }
+
if (std.mem.eql(u8, arg, "-d") or std.mem.eql(u8, arg, "-D")) {
- a = args.next();
- const decoded = try b.decode(allocator, arg);
- try stdout.print("{s}", .{decoded});
+ decodeSwitch = true;
} else {
- const encoded = try b.decode(allocator, arg);
- try stdout.print("{s}", .{encoded});
+ input = arg;
+ break;
}
+ }
+
+ if (decodeSwitch) {
+ const decoded = try Base64.decode(allocator, input);
+ try stdout.print("{s}", .{decoded});
} else {
- try stdout.print("{s}", .{usageText});
+ const encoded = try Base64.encode(allocator, input);
+ try stdout.print("{s}", .{encoded});
}
}