refactoring sources
[src/app-framework-main.git] / src / wgtpkg-base64.c
diff --git a/src/wgtpkg-base64.c b/src/wgtpkg-base64.c
new file mode 100644 (file)
index 0000000..5cf6f8a
--- /dev/null
@@ -0,0 +1,203 @@
+/*
+ Copyright 2015 IoT.bzh
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+
+#include "wgtpkg.h"
+
+static char tob64(char x)
+{
+       if (x < 26)
+               return 'A' + x;
+       if (x < 52)
+               return 'a' + x - 26;
+       if (x < 62)
+               return '0' + x - 52;
+       return x == 62 ? '+' : '/';
+}
+
+char *base64encw(const char *buffer, int length, int width)
+{
+       int remain, in, out;
+       char *result;
+
+       if (width == 0 || width % 4) {
+               syslog(LOG_ERR, "bad width in base64enc");
+               return NULL;
+       }
+       result = malloc(2 + 4 * ((length + 2) / 3) + (length / width));
+       if (result == NULL) {
+               syslog(LOG_ERR, "malloc failed in base64enc");
+               return NULL;
+       }
+       in = out = 0;
+       remain = length;
+       while (remain >= 3) {
+               if (out % (width + 1) == width)
+                       result[out++] = '\n'; 
+               result[out] = tob64((buffer[in] >> 2) & '\x3f');
+               result[out+1] = tob64(((buffer[in] << 4) & '\x30') | ((buffer[in+1] >> 4) & '\x0f'));
+               result[out+2] = tob64(((buffer[in+1] << 2) & '\x3c') | ((buffer[in+2] >> 6) & '\x03'));
+               result[out+3] = tob64(buffer[in+2] & '\x3f');
+               remain -= 3;
+               in += 3;
+               out += 4;
+       }
+       if (remain != 0) {
+               if (out % (width + 1) == width)
+                       result[out++] = '\n'; 
+               result[out] = tob64((buffer[in] >> 2) & '\x3f');
+               if (remain == 1) {
+                       result[out+1] = tob64((buffer[in] << 4) & '\x30');
+                       result[out+2] = '=';
+               } else {
+                       result[out+1] = tob64(((buffer[in] << 4) & '\x30') | ((buffer[in+1] >> 4) & '\x0f'));
+                       result[out+2] = tob64((buffer[in+1] << 2) & '\x3c');
+               }
+               result[out+3] = '=';
+               out += 4;
+       }
+       result[out] = 0;
+       return result;
+}
+
+char *base64enc(const char *buffer, int length)
+{
+       return base64encw(buffer, length, 76);
+}
+
+static char fromb64(char x)
+{
+       if ('A' <= x && x <= 'Z')
+               return x - 'A';
+       if ('a' <= x && x <= 'z')
+               return x - 'a' + 26;
+       if ('0' <= x && x <= '9')
+               return x - '0' + 52;
+       if (x == '+')
+               return 62;
+       if (x == '/')
+               return 63;
+       if (x == '=')
+               return '@';
+       return 'E';
+}
+
+int base64dec(const char *buffer, char **output)
+{
+       int len, in, out;
+       char *result;
+       unsigned char x0, x1, x2, x3;
+
+       len = strlen(buffer);
+       result = malloc(3 * ((3 + len) / 4));
+       if (result == NULL) {
+               syslog(LOG_ERR, "malloc failed in base64dec");
+               return -1;
+       }
+       in = out = 0;
+       while (buffer[in] == '\r' || buffer[in] == '\n')
+               in++;
+       while (buffer[in]) {
+               if (in + 4 > len) {
+                       syslog(LOG_ERR, "unexpected input size in base64dec");
+                       free(result);
+                       return -1;
+               }
+               x0 = (unsigned char)fromb64(buffer[in]);
+               x1 = (unsigned char)fromb64(buffer[in+1]);
+               x2 = (unsigned char)fromb64(buffer[in+2]);
+               x3 = (unsigned char)fromb64(buffer[in+3]);
+               in += 4;
+               if (x0 == 'E' || x1 == 'E' || x2 == 'E' || x3 == 'E') {
+                       syslog(LOG_ERR, "unexpected input character in base64dec");
+                       free(result);
+                       return -1;
+               }
+               if (x0 == '@' || x1 == '@' || (x2 == '@' && x3 != '@')) {
+                       syslog(LOG_ERR, "unexpected termination character in base64dec");
+                       free(result);
+                       return -1;
+               }
+               result[out] = (char)((x0 << 2) | (x1 >> 4));
+               result[out+1] = (char)((x1 << 4) | ((x2 >> 2) & 15));
+               result[out+2] = (char)((x2 << 6) | (x3 & 63));
+               while (buffer[in] == '\r' || buffer[in] == '\n')
+                       in++;
+               if (x3 != '@')
+                       out += 3;
+               else if (!buffer[in])
+                       out += 1 + (x2 != '@');
+               else {
+                       syslog(LOG_ERR, "unexpected continuation in base64dec");
+                       free(result);
+                       return -1;
+               }
+       }
+       *output = result;
+       return out;
+}
+
+int base64eq(const char *buf1, const char *buf2)
+{
+       for(;;) {
+               while(*buf1 == '\n' || *buf1 == '\r')
+                       buf1++;
+               while(*buf2 == '\n' || *buf2 == '\r')
+                       buf2++;
+               if (*buf1 != *buf2)
+                       return 0;
+               if (!*buf1)
+                       return 1;
+               buf1++;
+               buf2++;
+       }
+}
+
+#ifdef TESTBASE64
+#include <fcntl.h>
+#include <string.h>
+
+int main(int ac, char **av)
+{
+       char buffer[32768];
+       int fd, l0, l1, l2;
+       char *p1, *p2;
+
+       while(*++av) {
+               fd = open(*av, O_RDONLY);
+               if (fd < 0) continue;
+               l0 = read(fd, buffer, sizeof buffer);
+               if (l0 <= 0) continue;
+               close(fd);
+               p1 = base64enc(buffer, l0);
+               if (!p1) continue;
+               l1 = strlen(p1);
+               l2 = base64dec(p1, &p2);
+               if (l2 <= 0) continue;
+printf("[[[%.*s]]]\n",l2,p2);
+               if (l0 != l2) printf("length mismatch\n");
+               else if (memcmp(buffer, p2, l0)) printf("content mismatch\n");
+               free(p1);
+               free(p2);
+       }
+       return 0;
+}
+
+#endif