From 97b13672ced335dd7a8c4c926a150ddffb63d401 Mon Sep 17 00:00:00 2001
From: "Sven M. Hallberg" <pesco@khjk.org>
Date: Fri, 11 Jan 2013 00:41:34 +0100
Subject: [PATCH] generalize act_base64_n

---
 examples/base64_sem1.c | 73 ++++++++++++++++--------------------------
 1 file changed, 27 insertions(+), 46 deletions(-)

diff --git a/examples/base64_sem1.c b/examples/base64_sem1.c
index 7839435a..6dbb2fd3 100644
--- a/examples/base64_sem1.c
+++ b/examples/base64_sem1.c
@@ -78,70 +78,51 @@ const HParsedToken *act_bsfdig(const HParseResult *p)
 
 #define act_document     act_index0
 
-// helper
-void carray_append_uint(HCountedArray *array, uint8_t value)
-{
-    HParsedToken *item = h_arena_malloc(array->arena, sizeof(HParsedToken));
-    item->token_type = TT_UINT;
-    item->uint = value;
-    h_carray_append(array, item);
-}
-
-const HParsedToken *act_base64_3(const HParseResult *p)
+// General-form action to turn a block of base64 digits into bytes.
+const HParsedToken *act_base64_n(int n, const HParseResult *p)
 {
     assert(p->ast->token_type == TT_SEQUENCE);
 
     HParsedToken *res = h_arena_malloc(p->arena, sizeof(HParsedToken));
     res->token_type = TT_SEQUENCE;
-    res->seq = h_carray_new_sized(p->arena, 4);
+    res->seq = h_carray_new_sized(p->arena, n);
 
     HParsedToken **digits = p->ast->seq->elements;
-    uint32_t x = digits[0]->uint;
-    x <<= 6; x |= digits[1]->uint;
-    x <<= 6; x |= digits[2]->uint;
-    x <<= 6; x |= digits[3]->uint;
 
-    carray_append_uint(res->seq, (x >> 16) & 0xFF);
-    carray_append_uint(res->seq, (x >> 8) & 0xFF);
-    carray_append_uint(res->seq, x & 0xFF);
+    uint32_t x = 0;
+    int bits = 0;
+    for(int i=0; i<n+1; i++) {
+        x <<= 6; x |= digits[i]->uint;
+        bits += 6;
+    }
+    x >>= bits%8;   // align, i.e. cut off extra bits
+
+    for(int i=0; i<n; i++) {
+        HParsedToken *item = h_arena_malloc(p->arena, sizeof(HParsedToken));
+        item->token_type = TT_UINT;
+        item->uint = x & 0xFF;
+
+        res->seq->elements[n-1-i] = item;   // output the last byte and
+        x >>= 8;                            // discard it
+    }
+    res->seq->used = n;
 
     return res;
 }
 
-const HParsedToken *act_base64_2(const HParseResult *p)
+const HParsedToken *act_base64_3(const HParseResult *p)
 {
-    assert(p->ast->token_type == TT_SEQUENCE);
-
-    HParsedToken *res = h_arena_malloc(p->arena, sizeof(HParsedToken));
-    res->token_type = TT_SEQUENCE;
-    res->seq = h_carray_new_sized(p->arena, 4);
-
-    HParsedToken **digits = p->ast->seq->elements;
-    uint32_t x = digits[0]->uint;
-    x <<= 6; x |= digits[1]->uint;
-    x <<= 6; x |= digits[2]->uint;
-
-    carray_append_uint(res->seq, (x >> 10) & 0xFF);
-    carray_append_uint(res->seq, (x >> 2) & 0xFF);
+    return act_base64_n(3, p);
+}
 
-    return res;
+const HParsedToken *act_base64_2(const HParseResult *p)
+{
+    return act_base64_n(2, p);
 }
 
 const HParsedToken *act_base64_1(const HParseResult *p)
 {
-    assert(p->ast->token_type == TT_SEQUENCE);
-
-    HParsedToken *res = h_arena_malloc(p->arena, sizeof(HParsedToken));
-    res->token_type = TT_SEQUENCE;
-    res->seq = h_carray_new_sized(p->arena, 4);
-
-    HParsedToken **digits = p->ast->seq->elements;
-    uint32_t x = digits[0]->uint;
-    x <<= 6; x |= digits[1]->uint;
-
-    carray_append_uint(res->seq, (x >> 4) & 0xFF);
-
-    return res;
+    return act_base64_n(1, p);
 }
 
 #if 0
-- 
GitLab