From d03bda416f85b377c0a6666e94f09a27acd22d36 Mon Sep 17 00:00:00 2001 From: Abdelrahman Date: Sun, 10 Aug 2025 22:38:11 +0100 Subject: [PATCH] Complete base64 project --- base64/base64.odin | 142 +++++++++++++++++++++++++++++++++++++++++++++ base64/main.odin | 17 ++++++ 2 files changed, 159 insertions(+) create mode 100644 base64/base64.odin create mode 100644 base64/main.odin diff --git a/base64/base64.odin b/base64/base64.odin new file mode 100644 index 0000000..5ba0d7d --- /dev/null +++ b/base64/base64.odin @@ -0,0 +1,142 @@ +package main + +import "core:math" +import "core:strings" + +@(private="file") +alphabet := "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + +encode :: proc(s: string) -> string { + if len(s) == 0 do return ""; + + n_out := calc_encode_length(s); + + bytes := make([]u8, n_out); + defer delete(bytes); + + buf : [3]u8 = {}; + count : u8 = 0; + iout : u64 = 0; + + for i in 0..> 2); + bytes[iout + 1] = char_at(((buf[0] & 0x03) << 4) + (buf[1] >> 4)); + bytes[iout + 2] = char_at(((buf[1] & 0x0f) << 2) + (buf[2] >> 6)); + bytes[iout + 3] = char_at(buf[2] & 0x3f); + + iout += 4; + count = 0; + } + } + + if count == 1 { + bytes[iout] = char_at(buf[0] >> 2); + bytes[iout + 1] = char_at((buf[0] & 0x03) << 4); + bytes[iout + 2] = '='; + bytes[iout + 3] = '='; + } + + if count == 2 { + bytes[iout] = char_at(buf[0] >> 2); + bytes[iout + 1] = char_at(((buf[0] & 0x03) << 4) + (buf[1] >> 4)); + bytes[iout + 2] = char_at((buf[1] & 0x0f) << 2); + bytes[iout + 3] = '='; + + iout += 4; + } + + output, err := strings.clone_from_bytes(bytes[:]); + if err != nil { + return ""; + } + + return output; +} + +decode :: proc(s: string) -> string { + if len(s) == 0 do return ""; + + n_out := calc_decode_length(s); + + bytes := make([]u8, n_out); + defer delete(bytes); + + buf : [4]u8 = {}; + count : u8 = 0; + iout : u64 = 0; + + for i in 0..> 4); + if buf[2] != 64 { + bytes[iout + 1] = (buf[1] << 4) + (buf[2] >> 2); + } + if buf[3] != 64 { + bytes[iout + 2] = (buf[2] << 6) + buf[3]; + } + + iout += 3; + count = 0; + } + } + + output, err := strings.clone_from_bytes(bytes[:]); + if err != nil { + return ""; + } + + return output; +} + +@(private="file") +char_at :: proc(index: u8) -> u8 { + return alphabet[index]; +} + +@(private="file") +char_index :: proc(char: u8) -> u8 { + if char == '=' { + return 64; + } + + index : u8 = 0; + for c in alphabet { + if c == rune(char) do break; + index += 1; + } + + return index; +} + +@(private="file") +calc_encode_length :: proc(s: string) -> u64 { + if len(s) < 3 { + return 4; + } + + groups := u64(math.ceil_f32(f32(len(s)) / 3.0)); + + return groups * 4; +} + +@(private="file") +calc_decode_length :: proc(s: string) -> u64 { + if len(s) < 4 { + return 3; + } + + n_groups := u64(math.floor_f32(f32(len(s)) / 4.0)); + groups := n_groups * 3; + #reverse for char in s { + if char == '=' { + groups -= 1; + } + } + + return groups; +} diff --git a/base64/main.odin b/base64/main.odin new file mode 100644 index 0000000..da0ecb3 --- /dev/null +++ b/base64/main.odin @@ -0,0 +1,17 @@ +package main + +import "core:fmt" + +main :: proc() { + text :: "Testing some more stuff"; + etext :: "VGVzdGluZyBzb21lIG1vcmUgc3R1ZmY="; + + encoded_text := encode(text); + defer delete(encoded_text); + + decoded_text := decode(etext); + defer delete(decoded_text); + + fmt.println("Encoded text:", encoded_text); + fmt.println("Decoded text:", decoded_text); +}