libidav/utils.c

changeset 344
72791e299d64
parent 337
d7bda914d120
child 349
0b4ecadaf3f9
--- a/libidav/utils.c	Sun Dec 03 13:09:14 2017 +0100
+++ b/libidav/utils.c	Wed Dec 13 19:48:44 2017 +0100
@@ -466,41 +466,139 @@
     return util_base64decode_len(in, &len);
 }
 
+#define WHITESPACE 64
+#define EQUALS     65
+#define INVALID    66
+static char b64dectable[] = {
+    66,66,66,66,66,66,66,66,66,66,64,66,66,66,66,66,66,66,66,66,66,66,66,66,66,
+    66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,62,66,66,66,63,52,53,
+    54,55,56,57,58,59,60,61,66,66,66,65,66,66,66, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+    10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,66,66,66,66,66,66,26,27,28,
+    29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,66,66,
+    66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,
+    66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,
+    66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,
+    66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,
+    66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,
+    66,66,66,66,66,66
+};
 char* util_base64decode_len(char* in, int *outlen) {
-    size_t len = strlen(in);
-    char *out = calloc(1, len);
+    /* code is mostly from wikibooks */
+    
+    size_t inlen = strlen(in);
+    size_t bufsize = (inlen*3) / 4;
+    char *outbuf = malloc(bufsize+1);
+    *outlen = -1;
+    
+    unsigned char *out = outbuf;
+    
+    char *end = in + inlen;
+    char iter = 0;
+    uint32_t buf = 0;
+    size_t len = 0;
     
-    BIO *b = BIO_new_mem_buf(in, len);
-    BIO *d = BIO_new(BIO_f_base64());
-    BIO_set_flags(d, BIO_FLAGS_BASE64_NO_NL);
-    b = BIO_push(d, b);
+    while (in < end) {
+        unsigned char c = b64dectable[*in++];
+        
+        switch (c) {
+            case WHITESPACE: continue; /* skip whitespace */
+            case INVALID: {
+                  /* invalid input */
+                outbuf[0] = 0;
+                return outbuf;
+            }
+            case EQUALS: {
+                /* pad character, end of data */
+                in = end;
+                continue;
+            }
+            default: {
+                buf = buf << 6 | c;
+                iter++; // increment the number of iteration
+                /* If the buffer is full, split it into bytes */
+                if (iter == 4) {
+                    if ((len += 3) > bufsize) {
+                        /* buffer overflow */
+                        outbuf[0] = 0;
+                        return outbuf;
+                    }
+                    *(out++) = (buf >> 16) & 255;
+                    *(out++) = (buf >> 8) & 255;
+                    *(out++) = buf & 255;
+                    buf = 0; iter = 0;
 
-    *outlen = BIO_read(b, out, len);
-    BIO_free_all(b);
-    
-    return out;
+                }
+            }
+        }
+    }
+   
+    if (iter == 3) {
+        if ((len += 2) > bufsize) {
+            /* buffer overflow */
+            outbuf[0] = 0;
+            return outbuf;
+        }
+        *(out++) = (buf >> 10) & 255;
+        *(out++) = (buf >> 2) & 255;
+    }
+    else if (iter == 2) {
+        if (++len > bufsize) {
+            /* buffer overflow */
+            outbuf[0] = 0;
+            return outbuf;
+        }
+        *(out++) = (buf >> 4) & 255;
+    }
+
+    *outlen = len; /* modify to reflect the actual output size */
+    outbuf[len] = 0;
+    return outbuf;
 }
 
-char* util_base64encode(char *in, size_t len) { 
-    BIO *b;
-    BIO *e;
-    BUF_MEM *mem;
 
-    e = BIO_new(BIO_f_base64());
-    b = BIO_new(BIO_s_mem());
-    BIO_set_flags(e, BIO_FLAGS_BASE64_NO_NL);
+static char* b64enctable = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+char* util_base64encode(char *in, size_t len) {
+    // calculate length of base64 output and create buffer
+    size_t outlen = 4 * ((len + 2) / 3);
+    int pad = len % 3;
+    
+    char *out = malloc(outlen + 1);
+    out[outlen] = 0;
+    size_t pos = 0;
     
-    e = BIO_push(e, b);
-    BIO_write(e, in, len);
-    BIO_flush(e);
+    // encode blocks of 3 bytes
+    size_t i;
+    size_t blockend = len - pad;
+    for(i=0;i<blockend;i++) {
+        unsigned char b1 = in[i++];
+        unsigned char b2 = in[i++];
+        unsigned char b3 = in[i];
+        uint32_t inb = b1 << 16 | (b2 << 8) | b3;
+        out[pos++] = b64enctable[(inb >> 18) & 63];
+        out[pos++] = b64enctable[(inb >> 12) & 63];
+        out[pos++] = b64enctable[(inb >> 6) & 63];
+        out[pos++] = b64enctable[(inb) & 63];
+    }
     
-    BIO_get_mem_ptr(e, &mem);
-    char *out = malloc(mem->length + 1);
-    memcpy(out, mem->data, mem->length);
-    out[mem->length] = '\0';
-
-    BIO_free_all(e);
-
+    // encode last bytes
+    if(pad > 0) {
+        char p[3] = {0, 0, 0};
+        for(int j=0;i<len;i++) {
+            p[j++] = in[i];
+        }
+        unsigned char b1 = p[0];
+        unsigned char b2 = p[1];
+        unsigned char b3 = p[2];
+        uint32_t inb = (b1 << 16) | (b2 << 8) | b3;
+        out[pos++] = b64enctable[(inb >> 18) & 63];
+        out[pos++] = b64enctable[(inb >> 12) & 63];
+        out[pos++] = b64enctable[(inb >> 6) & 63];
+        out[pos++] = b64enctable[(inb) & 63];
+        for(int k=outlen-1;k>=outlen-(3-pad);k--) {
+            out[k] = '=';
+        }
+    }
+    
     return out;
 }
 

mercurial