struct Base32Params {
input_len: u32,
output_capacity: u32,
reserved0: u32,
reserved1: u32,
}
@group(0) @binding(0) var<uniform> params: Base32Params;
@group(0) @binding(1) var<storage, read> input_words: array<u32>;
@group(0) @binding(2) var<storage, read_write> output_words: array<u32>;
@group(0) @binding(3) var<storage, read_write> status: array<u32>;
fn decode_base32_value(byte: u32) -> u32 {
if (byte >= 65u && byte <= 90u) { return byte - 65u; }
if (byte >= 50u && byte <= 55u) { return byte - 24u; }
return 0xffffffffu;
}
@compute @workgroup_size(1, 1, 1)
fn decode_base32(@builtin(global_invocation_id) id: vec3<u32>) {
if (id.x != 0u) {
return;
}
status[0] = 0u;
status[1] = 0u;
var data_len = params.input_len;
var first_pad = params.input_len;
var scan = 0u;
loop {
if (scan >= params.input_len) { break; }
if (vyre_packed_byte(&input_words, scan) == 61u) {
first_pad = scan;
data_len = scan;
break;
}
scan = scan + 1u;
}
if (first_pad < params.input_len) {
var pad = first_pad;
loop {
if (pad >= params.input_len) { break; }
if (vyre_packed_byte(&input_words, pad) != 61u) {
status[0] = 3u;
status[1] = pad;
return;
}
pad = pad + 1u;
}
if ((params.input_len & 7u) != 0u) {
status[0] = 3u;
status[1] = first_pad;
return;
}
}
let residue = data_len & 7u;
if (residue == 1u || residue == 3u || residue == 6u) {
status[0] = 1u;
return;
}
var buffer = 0u;
var bits = 0u;
var out = 0u;
var input = 0u;
loop {
if (input >= data_len) { break; }
let value = decode_base32_value(vyre_packed_byte(&input_words, input));
if (value == 0xffffffffu) {
status[0] = 2u;
status[1] = input;
return;
}
buffer = (buffer << 5u) | value;
bits = bits + 5u;
if (bits >= 8u) {
if (out >= params.output_capacity) {
status[0] = 5u;
return;
}
bits = bits - 8u;
vyre_store_packed_byte(&output_words, out, (buffer >> bits) & 0xffu);
out = out + 1u;
}
input = input + 1u;
}
if (bits > 0u && (buffer & ((1u << bits) - 1u)) != 0u) {
status[0] = 4u;
return;
}
status[1] = out;
}