Created
March 14, 2025 09:14
-
-
Save nberlette/8e27170c1515ba31f5b978cc6be62c87 to your computer and use it in GitHub Desktop.
WebAssembly (WAT) implementation of atob / btoa
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(module | |
;; Memory: 1 page = 64 KiB | |
(memory $memory 1) | |
;; Exported error flag (0 = no error, 1 = error) | |
(global $error_flag (mut i32) (i32.const 0)) | |
;; Base64 encoding table | |
(data (i32.const 0) "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/") | |
;; Base64 decoding table | |
(data (i32.const 64) "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" | |
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x3e\xff\xff\xff\x3f" | |
"\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\xff\xff\xff\x00\xff\xff" | |
"\xff\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e" | |
"\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\xff\xff\xff\xff\xff" | |
"\xff\x1a\x1b\x1c\x1d\x1e\x1f\x20\x21\x22\x23\x24\x25\x26\x27\x28" | |
"\x29\x2a\x2b\x2c\x2d\x2e\x2f\x30\x31\x32\x33\xff\xff\xff\xff\xff") | |
(export "memory" (memory $memory)) | |
(export "error_flag" (global $error_flag)) | |
(export "btoa" (func $btoa)) | |
(export "atob" (func $atob)) | |
;; Encode (btoa) | |
(func $btoa | |
(param $input i32) | |
(param $len i32) | |
(result i32) | |
(local $i i32) | |
(local $o i32) | |
(local $buffer i32) | |
(local $char i32) | |
(global.set $error_flag (i32.const 0)) | |
(local.set $o (i32.const 1024)) | |
(block $exit | |
(loop $encode | |
(br_if $exit (i32.ge_u (local.get $i) (local.get $len))) | |
(local.set $buffer (i32.const 0)) | |
(local.set $buffer (i32.shl (i32.load8_u (i32.add (local.get $input) (local.get $i))) (i32.const 16))) | |
(local.set $i (i32.add (local.get $i) (i32.const 1))) | |
(if (i32.lt_u (local.get $i) (local.get $len)) | |
(then | |
(local.set $buffer (i32.or (local.get $buffer) (i32.shl (i32.load8_u (i32.add (local.get $input) (local.get $i))) (i32.const 8)))) | |
(local.set $i (i32.add (local.get $i) (i32.const 1))) | |
) | |
) | |
(if (i32.lt_u (local.get $i) (local.get $len)) | |
(then | |
(local.set $buffer (i32.or (local.get $buffer) (i32.load8_u (i32.add (local.get $input) (local.get $i))))) | |
(local.set $i (i32.add (local.get $i) (i32.const 1))) | |
) | |
) | |
(local.set $char (i32.and (i32.shr_u (local.get $buffer) (i32.const 18)) (i32.const 63))) | |
(i32.store8 (local.get $o) (i32.load8_u (i32.add (i32.const 0) (local.get $char)))) | |
(local.set $o (i32.add (local.get $o) (i32.const 1))) | |
(local.set $char (i32.and (i32.shr_u (local.get $buffer) (i32.const 12)) (i32.const 63))) | |
(i32.store8 (local.get $o) (i32.load8_u (i32.add (i32.const 0) (local.get $char)))) | |
(local.set $o (i32.add (local.get $o) (i32.const 1))) | |
(local.set $char (i32.and (i32.shr_u (local.get $buffer) (i32.const 6)) (i32.const 63))) | |
(i32.store8 (local.get $o) (i32.load8_u (i32.add (i32.const 0) (local.get $char)))) | |
(local.set $o (i32.add (local.get $o) (i32.const 1))) | |
(local.set $char (i32.and (local.get $buffer) (i32.const 63))) | |
(i32.store8 (local.get $o) (i32.load8_u (i32.add (i32.const 0) (local.get $char)))) | |
(local.set $o (i32.add (local.get $o) (i32.const 1))) | |
(br $encode) | |
) | |
) | |
(local.get $o) | |
) | |
;; Decode (atob) | |
(func $atob | |
(param $input i32) | |
(param $len i32) | |
(result i32) | |
(local $i i32) | |
(local $o i32) | |
(local $buffer i32) | |
(local $valid i32) | |
(global.set $error_flag (i32.const 0)) | |
(local.set $o (i32.const 1024)) | |
(block $exit | |
(loop $decode | |
(br_if $exit (i32.ge_u (local.get $i) (local.get $len))) | |
(local.set $valid (i32.load8_u (i32.add (i32.const 64) (i32.load8_u (i32.add (local.get $input) (local.get $i)))))) | |
(if (i32.eq (local.get $valid) (i32.const 255)) | |
(then | |
(global.set $error_flag (i32.const 1)) | |
(br $exit) | |
) | |
) | |
(local.set $buffer (i32.shl (local.get $buffer) (i32.const 6))) | |
(local.set $buffer (i32.or (local.get $buffer) (local.get $valid))) | |
(local.set $i (i32.add (local.get $i) (i32.const 1))) | |
(if (i32.eq (i32.and (local.get $i) (i32.const 3)) (i32.const 0)) | |
(then | |
(i32.store8 (local.get $o) (i32.shr_u (local.get $buffer) (i32.const 16))) | |
(local.set $o (i32.add (local.get $o) (i32.const 1))) | |
(i32.store8 (local.get $o) (i32.and (i32.shr_u (local.get $buffer) (i32.const 8)) (i32.const 255))) | |
(local.set $o (i32.add (local.get $o) (i32.const 1))) | |
(i32.store8 (local.get $o) (i32.and (local.get $buffer) (i32.const 255))) | |
(local.set $o (i32.add (local.get $o) (i32.const 1))) | |
) | |
) | |
(br $decode) | |
) | |
) | |
(local.get $o) | |
) | |
) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment