#include "dtob_internal.h"
size_t trit_encode_padded(const uint8_t *bytes, size_t byte_len,
uint8_t **out_buf)
{
if (byte_len == 0) { *out_buf = NULL; return 0; }
size_t total_bits = byte_len * 12;
size_t padded_bits = (total_bits + 7) & ~(size_t)7;
size_t out_len = padded_bits / 8;
uint8_t *buf = calloc(out_len, 1);
if (!buf) { *out_buf = NULL; return 0; }
size_t bit_pos = 0;
for (size_t i = 0; i < byte_len; i++) {
uint8_t val = bytes[i];
uint8_t trits[6];
for (int t = 5; t >= 0; t--) {
trits[t] = val % 3;
val /= 3;
}
for (int t = 0; t < 6; t++) {
size_t byte_idx = bit_pos / 8;
int shift = 6 - (bit_pos % 8);
buf[byte_idx] |= (trits[t] & 0x03) << shift;
bit_pos += 2;
}
}
while (bit_pos < padded_bits) {
size_t byte_idx = bit_pos / 8;
int shift = 6 - (bit_pos % 8);
buf[byte_idx] |= 0x03 << shift;
bit_pos += 2;
}
*out_buf = buf;
return out_len;
}
size_t trit_decode_padded(const uint8_t *buf, size_t buf_len,
uint8_t **out_bytes)
{
if (buf_len == 0) { *out_bytes = NULL; return 0; }
uint8_t *trits = malloc(buf_len * 4);
if (!trits) { *out_bytes = NULL; return 0; }
size_t trit_count = 0;
int in_padding = 0;
for (size_t bit_pos = 0; bit_pos < buf_len * 8; bit_pos += 2) {
size_t byte_idx = bit_pos / 8;
int shift = 6 - (bit_pos % 8);
uint8_t pair = (buf[byte_idx] >> shift) & 0x03;
if (pair == 3) {
in_padding = 1;
continue;
}
if (in_padding) {
fprintf(stderr, "dtob: data after padding at byte %zu\n", byte_idx);
free(trits);
*out_bytes = NULL;
return 0;
}
trits[trit_count++] = pair;
}
if (trit_count % 6 != 0) {
free(trits);
*out_bytes = NULL;
return 0;
}
size_t n_bytes = trit_count / 6;
uint8_t *bytes = malloc(n_bytes ? n_bytes : 1);
if (!bytes) { free(trits); *out_bytes = NULL; return 0; }
for (size_t i = 0; i < n_bytes; i++) {
unsigned int val = 0;
for (int t = 0; t < 6; t++) {
val = val * 3 + trits[i * 6 + t];
}
if (val > 255) {
fprintf(stderr, "dtob: trit decode produced value %u > 255\n", val);
free(trits);
free(bytes);
*out_bytes = NULL;
return 0;
}
bytes[i] = (uint8_t)val;
}
free(trits);
*out_bytes = bytes;
return n_bytes;
}