summaryrefslogtreecommitdiff
path: root/vere/pkg/noun/jets/e/base.c
diff options
context:
space:
mode:
Diffstat (limited to 'vere/pkg/noun/jets/e/base.c')
-rw-r--r--vere/pkg/noun/jets/e/base.c152
1 files changed, 152 insertions, 0 deletions
diff --git a/vere/pkg/noun/jets/e/base.c b/vere/pkg/noun/jets/e/base.c
new file mode 100644
index 0000000..8bbc761
--- /dev/null
+++ b/vere/pkg/noun/jets/e/base.c
@@ -0,0 +1,152 @@
+/// @file
+
+#include "jets/q.h"
+#include "jets/w.h"
+
+#include "noun.h"
+
+u3_noun
+u3qe_en_base16(u3_atom len, u3_atom dat)
+{
+ if ( c3n == u3a_is_cat(len) ) {
+ return u3m_bail(c3__fail);
+ }
+ else {
+ c3_w len_w = (c3_w)len;
+ u3i_slab sab_u;
+
+ u3i_slab_bare(&sab_u, 4, len_w);
+ sab_u.buf_w[sab_u.len_w - 1] = 0;
+
+ {
+ c3_y* buf_y = sab_u.buf_y;
+ c3_y inp_y;
+
+ while ( len_w-- ) {
+ inp_y = u3r_byte(len_w, dat);
+
+ *buf_y++ = u3s_dit_y[inp_y >> 4];
+ *buf_y++ = u3s_dit_y[inp_y & 0xf];
+ }
+ }
+
+ return u3i_slab_moot_bytes(&sab_u);
+ }
+}
+
+static inline c3_o
+_of_hex_digit(c3_y inp_y, c3_y* out_y)
+{
+ if ( inp_y >= '0' && inp_y <= '9' ) {
+ *out_y = inp_y - '0';
+ return c3y;
+ }
+ else if ( inp_y >= 'a' && inp_y <= 'f' ) {
+ *out_y = inp_y - 87;
+ return c3y;
+ }
+ else if ( inp_y >= 'A' && inp_y <= 'F' ) {
+ *out_y = inp_y - 55;
+ return c3y;
+ }
+
+ return c3n;
+}
+
+static inline c3_o
+_of_hex_odd(u3_atom inp, c3_w len_w, c3_w byt_w, c3_y* buf_y)
+{
+ c3_y low_y, hig_y, lit_y, hit_y;
+
+ hig_y = u3r_byte(--byt_w, inp);
+
+ while ( --len_w ) {
+ low_y = u3r_byte(--byt_w, inp);
+
+ if ( (c3n == _of_hex_digit(low_y, &lit_y))
+ || (c3n == _of_hex_digit(hig_y, &hit_y)) )
+ {
+ return c3n;
+ }
+ else {
+ *buf_y++ = (hit_y & 0xf) ^ (lit_y << 4);
+ }
+
+ hig_y = u3r_byte(--byt_w, inp);
+ }
+
+ if ( c3n == _of_hex_digit(hig_y, &hit_y) ) {
+ return c3n;
+ }
+ else {
+ *buf_y = hit_y & 0xf;
+ }
+
+ return c3y;
+}
+
+static inline c3_o
+_of_hex_even(u3_atom inp, c3_w len_w, c3_y* buf_y)
+{
+ c3_y lit_y, hit_y;
+ c3_s inp_s;
+
+ while ( len_w-- ) {
+ inp_s = u3r_short(len_w, inp);
+
+ if ( (c3n == _of_hex_digit(inp_s & 0xff, &lit_y))
+ || (c3n == _of_hex_digit(inp_s >> 8, &hit_y)) )
+ {
+ return c3n;
+ }
+ else {
+ *buf_y++ = (hit_y & 0xf) ^ (lit_y << 4);
+ }
+ }
+
+ return c3y;
+}
+
+u3_noun
+u3qe_de_base16(u3_atom inp)
+{
+ c3_w len_w = u3r_met(4, inp);
+ u3i_slab sab_u;
+
+ u3i_slab_bare(&sab_u, 3, len_w);
+ sab_u.buf_w[sab_u.len_w - 1] = 0;
+
+ // even byte-length input can be parsed in aligned, 16-bit increments,
+ // but odd byte-length input cannot, and is expressed more simply in bytes.
+ //
+ {
+ c3_w byt_w = u3r_met(3, inp);
+ c3_o ret_o = ( byt_w & 1 )
+ ? _of_hex_odd(inp, len_w, byt_w, sab_u.buf_y)
+ : _of_hex_even(inp, len_w, sab_u.buf_y);
+
+ if ( c3n == ret_o ) {
+ u3i_slab_free(&sab_u);
+ return u3_nul;
+ }
+ else {
+ u3_noun dat = u3i_slab_mint_bytes(&sab_u);
+ return u3nt(u3_nul, u3i_word(len_w), dat);
+ }
+ }
+}
+
+u3_noun
+u3we_en_base16(u3_noun cor)
+{
+ u3_noun a, b;
+ u3x_mean(cor, u3x_sam_2, &a, u3x_sam_3, &b, 0);
+ return u3qe_en_base16(u3x_atom(a), u3x_atom(b));
+}
+
+u3_noun
+u3we_de_base16(u3_noun cor)
+{
+ u3_noun sam = u3x_at(u3x_sam, cor);
+ return u3qe_de_base16(u3x_atom(sam));
+}