summaryrefslogtreecommitdiffstats
path: root/wgtpkg-base64.c
diff options
context:
space:
mode:
Diffstat (limited to 'wgtpkg-base64.c')
-rw-r--r--wgtpkg-base64.c203
1 files changed, 203 insertions, 0 deletions
diff --git a/wgtpkg-base64.c b/wgtpkg-base64.c
new file mode 100644
index 0000000..5cf6f8a
--- /dev/null
+++ b/wgtpkg-base64.c
@@ -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