finish
This commit is contained in:
parent
607bf5021e
commit
8fb7891fe1
104
src/base64.zig
104
src/base64.zig
@ -5,24 +5,18 @@ pub const err = error{
|
|||||||
IndexNotFound,
|
IndexNotFound,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const Base64 = struct {
|
fn char_at(index: u8) u8 {
|
||||||
table: *const [64]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) {
|
if (input.len == 0) {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
const encode_length = try calc_encode_length(input);
|
const out_sz = try calc_encode_length(input);
|
||||||
var out = try allocator.alloc(u8, encode_length);
|
var out = try allocator.alloc(u8, out_sz);
|
||||||
var buf = [3]u8{0, 0, 0};
|
var buf = [3]u8{0, 0, 0};
|
||||||
var count: u16 = 0;
|
var count: u16 = 0;
|
||||||
var outc: u16 = 0;
|
var outc: u16 = 0;
|
||||||
@ -31,23 +25,23 @@ pub const Base64 = struct {
|
|||||||
buf[count] = b;
|
buf[count] = b;
|
||||||
count += 1;
|
count += 1;
|
||||||
if (count == 3) {
|
if (count == 3) {
|
||||||
out[outc] = self.char_at(buf[0] >> 2);
|
out[outc] = char_at(buf[0] >> 2);
|
||||||
out[outc + 1] = self.char_at(((buf[0] & 0x03) << 4) + (buf[1] >> 4));
|
out[outc + 1] = char_at(((buf[0] & 0x03) << 4) + (buf[1] >> 4));
|
||||||
out[outc + 2] = self.char_at(((buf[1] & 0x0F) << 2) + (buf[2] >> 6));
|
out[outc + 2] = char_at(((buf[1] & 0x0F) << 2) + (buf[2] >> 6));
|
||||||
out[outc + 3] = self.char_at(buf[2] & 0x3F);
|
out[outc + 3] = char_at(buf[2] & 0x3F);
|
||||||
count = 0;
|
count = 0;
|
||||||
outc += 4;
|
outc += 4;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (count == 2) {
|
if (count == 2) {
|
||||||
out[outc] = self.char_at(buf[0] >> 2);
|
out[outc] = char_at(buf[0] >> 2);
|
||||||
out[outc + 1] = self.char_at((buf[0] & 0x03) << 4) + (buf[1] >> 4);
|
out[outc + 1] = char_at((buf[0] & 0x03) << 4) + (buf[1] >> 4);
|
||||||
out[outc + 2] = self.char_at((buf[1] & 0x0F) << 2);
|
out[outc + 2] = char_at((buf[1] & 0x0F) << 2);
|
||||||
out[outc + 3] = '=';
|
out[outc + 3] = '=';
|
||||||
} else if (count == 1) {
|
} else if (count == 1) {
|
||||||
out[outc] = self.char_at(buf[0] >> 2);
|
out[outc] = char_at(buf[0] >> 2);
|
||||||
out[outc + 1] = self.char_at((buf[0] & 0x03) << 4);
|
out[outc + 1] = char_at((buf[0] & 0x03) << 4);
|
||||||
out[outc + 2] = '=';
|
out[outc + 2] = '=';
|
||||||
out[outc + 3] = '=';
|
out[outc + 3] = '=';
|
||||||
}
|
}
|
||||||
@ -55,55 +49,59 @@ pub const Base64 = struct {
|
|||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn decode_index(self: Base64, char: u8) err!u8 {
|
fn decode_index(char: u8) err!u8 {
|
||||||
if (char == '=') {
|
if (char == '=') {
|
||||||
return 64;
|
return 64;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (char >= 'A' and char <= 'Z') {
|
if (char >= 'A' and char <= 'Z') {
|
||||||
return char - 'A';
|
return char - 'A';
|
||||||
} else if (char >= 'a' and char <= 'z') {
|
} else if (char >= 'a' and char <= 'z') {
|
||||||
return char - 'a' + 26;
|
return char - 'a' + 26;
|
||||||
} else {
|
} else if (char >= '0' and char <= '9') {
|
||||||
for (52..64) |i| {
|
return char - '0' + 52;
|
||||||
const idx: u8 = @intCast(i);
|
|
||||||
if (self.char_at(idx) == char) {
|
|
||||||
return idx;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return err.IndexNotFound;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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) {
|
if (input.len == 0) {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
const output_sz = try calc_decode_length(input);
|
const out_sz = try calc_decode_length(input);
|
||||||
var output = try allocator.alloc(u8, output_sz);
|
var out = try allocator.alloc(u8, out_sz);
|
||||||
var count: u8 = 0;
|
var count: u8 = 0;
|
||||||
var iout: u64 = 0;
|
var iout: u64 = 0;
|
||||||
var buf = [4]u8{ 0, 0, 0, 0 };
|
var buf = [4]u8{ 0, 0, 0, 0 };
|
||||||
|
var cutoff :u8 = 0;
|
||||||
|
|
||||||
for (0..input.len) |i| {
|
for (0..input.len) |i| {
|
||||||
buf[count] = try self.decode_index(input[i]);
|
buf[count] = try decode_index(input[i]);
|
||||||
count += 1;
|
count += 1;
|
||||||
if (count == 4) {
|
if (count == 4) {
|
||||||
output[iout] = (buf[0] << 2) + (buf[1] >> 4);
|
out[iout] = (buf[0] << 2) + (buf[1] >> 4);
|
||||||
if (buf[2] != 64) {
|
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) {
|
if (buf[3] != 64) {
|
||||||
output[iout + 2] = (buf[2] << 6) + buf[3];
|
out[iout + 2] = (buf[2] << 6) + buf[3];
|
||||||
|
cutoff = 1;
|
||||||
}
|
}
|
||||||
iout += 3;
|
iout += 3;
|
||||||
count = 0;
|
count = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return output;
|
return out[0..out.len - cutoff + 1];
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
fn calc_encode_length(input: []const u8) !usize {
|
fn calc_encode_length(input: []const u8) !usize {
|
||||||
if (input.len < 3) {
|
if (input.len < 3) {
|
||||||
@ -122,57 +120,51 @@ fn calc_decode_length(input: []const u8) !usize {
|
|||||||
}
|
}
|
||||||
|
|
||||||
test "encode hello" {
|
test "encode hello" {
|
||||||
var b = Base64.init;
|
|
||||||
var gpa = std.heap.GeneralPurposeAllocator(.{}).init;
|
var gpa = std.heap.GeneralPurposeAllocator(.{}).init;
|
||||||
const allocator = gpa.allocator();
|
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="));
|
try std.testing.expect(std.mem.eql(u8, encoded, "aGVsbG8="));
|
||||||
}
|
}
|
||||||
|
|
||||||
test "encode long" {
|
test "encode long" {
|
||||||
var b = Base64.init;
|
|
||||||
var gpa = std.heap.GeneralPurposeAllocator(.{}).init;
|
var gpa = std.heap.GeneralPurposeAllocator(.{}).init;
|
||||||
const allocator = gpa.allocator();
|
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="));
|
try std.testing.expect(std.mem.eql(u8, encoded, "SGV5LCBpdCdzIG1lLiBJJ20gdGhlIHByb2JsZW0uIEl0J3MgbWU="));
|
||||||
}
|
}
|
||||||
|
|
||||||
test "decode hello" {
|
test "decode hello" {
|
||||||
var b = Base64.init;
|
|
||||||
var gpa = std.heap.GeneralPurposeAllocator(.{}).init;
|
var gpa = std.heap.GeneralPurposeAllocator(.{}).init;
|
||||||
const allocator = gpa.allocator();
|
const allocator = gpa.allocator();
|
||||||
|
|
||||||
const encoded = try b.decode(allocator, "aGVsbG8=");
|
const encoded = try decode(allocator, "aGVsbG8=");
|
||||||
try stdout.print("{s}\n", .{encoded});
|
try stdout.print("{s}\n", .{encoded});
|
||||||
try std.testing.expect(std.mem.eql(u8, encoded, "hello"));
|
try std.testing.expect(std.mem.eql(u8, encoded, "hello"));
|
||||||
}
|
}
|
||||||
|
|
||||||
test "decode long" {
|
test "decode long" {
|
||||||
var b = Base64.init;
|
|
||||||
var gpa = std.heap.GeneralPurposeAllocator(.{}).init;
|
var gpa = std.heap.GeneralPurposeAllocator(.{}).init;
|
||||||
const allocator = gpa.allocator();
|
const allocator = gpa.allocator();
|
||||||
|
|
||||||
const encoded = try b.decode(allocator, "SGV5LCBpdCdzIG1lLiBJJ20gdGhlIHByb2JsZW0uIEl0J3MgbWU=");
|
const encoded = try decode(allocator, "SGV5LCBpdCdzIG1lLiBJJ20gdGhlIHByb2JsZW0uIEl0J3MgbWU=");
|
||||||
try stdout.print("{s}\n", .{encoded});
|
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"));
|
try std.testing.expect(std.mem.eql(u8, encoded, "Hey, it's me. I'm the problem. It's me"));
|
||||||
}
|
}
|
||||||
|
|
||||||
test "decode_index" {
|
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;
|
var r :u8 = 0;
|
||||||
r = try b.decode_index('A');
|
r = try decode_index('A');
|
||||||
try std.testing.expect(r == 0);
|
try std.testing.expect(r == 0);
|
||||||
r = try b.decode_index('a');
|
r = try decode_index('a');
|
||||||
try std.testing.expect(r == 26);
|
try std.testing.expect(r == 26);
|
||||||
r = try b.decode_index('0');
|
r = try decode_index('0');
|
||||||
try std.testing.expect(r == 52);
|
try std.testing.expect(r == 52);
|
||||||
r = try b.decode_index('/');
|
r = try decode_index('/');
|
||||||
try std.testing.expect(r == 63);
|
try std.testing.expect(r == 63);
|
||||||
r = try b.decode_index('=');
|
r = try decode_index('=');
|
||||||
try std.testing.expect(r == 64);
|
try std.testing.expect(r == 64);
|
||||||
}
|
}
|
||||||
|
32
src/main.zig
32
src/main.zig
@ -1,7 +1,7 @@
|
|||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const stdout = std.io.getStdOut().writer();
|
const stdout = std.io.getStdOut().writer();
|
||||||
|
|
||||||
const b64 = @import("base64.zig");
|
const Base64 = @import("base64.zig");
|
||||||
|
|
||||||
const usageText =
|
const usageText =
|
||||||
\\Usage: baze64 {-d/-D} input
|
\\Usage: baze64 {-d/-D} input
|
||||||
@ -16,22 +16,34 @@ pub fn main() !void {
|
|||||||
var args = try std.process.argsWithAllocator(allocator);
|
var args = try std.process.argsWithAllocator(allocator);
|
||||||
defer args.deinit();
|
defer args.deinit();
|
||||||
|
|
||||||
var b = b64.Base64.init;
|
var decodeSwitch = false;
|
||||||
|
var input: []const u8 = undefined;
|
||||||
|
|
||||||
// Skip arg[0]
|
// Skip arg[0]
|
||||||
_ = args.skip();
|
_ = args.skip();
|
||||||
|
|
||||||
var a = args.next();
|
while (true) {
|
||||||
if (a) |arg| {
|
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")) {
|
if (std.mem.eql(u8, arg, "-d") or std.mem.eql(u8, arg, "-D")) {
|
||||||
a = args.next();
|
decodeSwitch = true;
|
||||||
const decoded = try b.decode(allocator, arg);
|
} else {
|
||||||
|
input = arg;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (decodeSwitch) {
|
||||||
|
const decoded = try Base64.decode(allocator, input);
|
||||||
try stdout.print("{s}", .{decoded});
|
try stdout.print("{s}", .{decoded});
|
||||||
} else {
|
} else {
|
||||||
const encoded = try b.decode(allocator, arg);
|
const encoded = try Base64.encode(allocator, input);
|
||||||
try stdout.print("{s}", .{encoded});
|
try stdout.print("{s}", .{encoded});
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
try stdout.print("{s}", .{usageText});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user