finish
This commit is contained in:
parent
607bf5021e
commit
8fb7891fe1
110
src/base64.zig
110
src/base64.zig
@ -5,24 +5,18 @@ pub const err = error{
|
||||
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(self: Base64, allocator: std.mem.Allocator, input: []const u8) ![]u8 {
|
||||
pub fn encode(allocator: std.mem.Allocator, input: []const u8) ![]u8 {
|
||||
if (input.len == 0) {
|
||||
return "";
|
||||
}
|
||||
|
||||
const encode_length = try calc_encode_length(input);
|
||||
var out = try allocator.alloc(u8, encode_length);
|
||||
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;
|
||||
@ -31,79 +25,83 @@ pub const Base64 = struct {
|
||||
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);
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
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] = 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] = self.char_at(buf[0] >> 2);
|
||||
out[outc + 1] = self.char_at((buf[0] & 0x03) << 4);
|
||||
out[outc] = char_at(buf[0] >> 2);
|
||||
out[outc + 1] = char_at((buf[0] & 0x03) << 4);
|
||||
out[outc + 2] = '=';
|
||||
out[outc + 3] = '=';
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
}
|
||||
|
||||
fn decode_index(self: Base64, char: u8) err!u8 {
|
||||
fn decode_index(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;
|
||||
} else if (char >= '0' and char <= '9') {
|
||||
return char - '0' + 52;
|
||||
}
|
||||
|
||||
pub fn decode(self: Base64, allocator: std.mem.Allocator, input: []const u8) ![]u8 {
|
||||
switch (char) {
|
||||
'+' => { return 62; },
|
||||
'/' => { return 63; },
|
||||
'=' => { return 64; },
|
||||
else => { return err.IndexNotFound; }
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
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]);
|
||||
buf[count] = try decode_index(input[i]);
|
||||
count += 1;
|
||||
if (count == 4) {
|
||||
output[iout] = (buf[0] << 2) + (buf[1] >> 4);
|
||||
out[iout] = (buf[0] << 2) + (buf[1] >> 4);
|
||||
if (buf[2] != 64) {
|
||||
output[iout + 1] = (buf[1] << 4) + (buf[2] >> 2);
|
||||
out[iout + 1] = (buf[1] << 4) + (buf[2] >> 2);
|
||||
cutoff = 2;
|
||||
}
|
||||
if (buf[3] != 64) {
|
||||
output[iout + 2] = (buf[2] << 6) + buf[3];
|
||||
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) {
|
||||
@ -122,57 +120,51 @@ fn calc_decode_length(input: []const u8) !usize {
|
||||
}
|
||||
|
||||
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, b.decode_index('{'));
|
||||
try std.testing.expectError(err.IndexNotFound, 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);
|
||||
}
|
||||
|
32
src/main.zig
32
src/main.zig
@ -1,7 +1,7 @@
|
||||
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
|
||||
@ -16,22 +16,34 @@ pub fn main() !void {
|
||||
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);
|
||||
decodeSwitch = true;
|
||||
} else {
|
||||
input = arg;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (decodeSwitch) {
|
||||
const decoded = try Base64.decode(allocator, input);
|
||||
try stdout.print("{s}", .{decoded});
|
||||
} else {
|
||||
const encoded = try b.decode(allocator, arg);
|
||||
const encoded = try Base64.encode(allocator, input);
|
||||
try stdout.print("{s}", .{encoded});
|
||||
}
|
||||
} else {
|
||||
try stdout.print("{s}", .{usageText});
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user