63929aebd74d8237deba9c938ffe75f5b82467de
[src/app-framework-main.git] / src / wgtpkg-base64.c
1 /*
2  Copyright 2015 IoT.bzh
3
4  author: José Bollo <jose.bollo@iot.bzh>
5
6  Licensed under the Apache License, Version 2.0 (the "License");
7  you may not use this file except in compliance with the License.
8  You may obtain a copy of the License at
9
10      http://www.apache.org/licenses/LICENSE-2.0
11
12  Unless required by applicable law or agreed to in writing, software
13  distributed under the License is distributed on an "AS IS" BASIS,
14  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  See the License for the specific language governing permissions and
16  limitations under the License.
17 */
18
19
20 #include <stdlib.h>
21 #include <string.h>
22
23 #include "verbose.h"
24 #include "wgtpkg-base64.h"
25
26 static char tob64(char x)
27 {
28         if (x < 26)
29                 return 'A' + x;
30         if (x < 52)
31                 return 'a' + x - 26;
32         if (x < 62)
33                 return '0' + x - 52;
34         return x == 62 ? '+' : '/';
35 }
36
37 char *base64encw(const char *buffer, int length, int width)
38 {
39         int remain, in, out;
40         char *result;
41
42         if (width == 0 || width % 4) {
43                 ERROR("bad width in base64enc");
44                 return NULL;
45         }
46         result = malloc(2 + 4 * ((length + 2) / 3) + (length / width));
47         if (result == NULL) {
48                 ERROR("malloc failed in base64enc");
49                 return NULL;
50         }
51         in = out = 0;
52         remain = length;
53         while (remain >= 3) {
54                 if (out % (width + 1) == width)
55                         result[out++] = '\n'; 
56                 result[out] = tob64((buffer[in] >> 2) & '\x3f');
57                 result[out+1] = tob64(((buffer[in] << 4) & '\x30') | ((buffer[in+1] >> 4) & '\x0f'));
58                 result[out+2] = tob64(((buffer[in+1] << 2) & '\x3c') | ((buffer[in+2] >> 6) & '\x03'));
59                 result[out+3] = tob64(buffer[in+2] & '\x3f');
60                 remain -= 3;
61                 in += 3;
62                 out += 4;
63         }
64         if (remain != 0) {
65                 if (out % (width + 1) == width)
66                         result[out++] = '\n'; 
67                 result[out] = tob64((buffer[in] >> 2) & '\x3f');
68                 if (remain == 1) {
69                         result[out+1] = tob64((buffer[in] << 4) & '\x30');
70                         result[out+2] = '=';
71                 } else {
72                         result[out+1] = tob64(((buffer[in] << 4) & '\x30') | ((buffer[in+1] >> 4) & '\x0f'));
73                         result[out+2] = tob64((buffer[in+1] << 2) & '\x3c');
74                 }
75                 result[out+3] = '=';
76                 out += 4;
77         }
78         result[out] = 0;
79         return result;
80 }
81
82 char *base64enc(const char *buffer, int length)
83 {
84         return base64encw(buffer, length, 76);
85 }
86
87 static char fromb64(char x)
88 {
89         if ('A' <= x && x <= 'Z')
90                 return x - 'A';
91         if ('a' <= x && x <= 'z')
92                 return x - 'a' + 26;
93         if ('0' <= x && x <= '9')
94                 return x - '0' + 52;
95         if (x == '+')
96                 return 62;
97         if (x == '/')
98                 return 63;
99         if (x == '=')
100                 return '@';
101         return 'E';
102 }
103
104 int base64dec(const char *buffer, char **output)
105 {
106         int len, in, out;
107         char *result;
108         unsigned char x0, x1, x2, x3;
109
110         len = strlen(buffer);
111         result = malloc(3 * ((3 + len) / 4));
112         if (result == NULL) {
113                 ERROR("malloc failed in base64dec");
114                 return -1;
115         }
116         in = out = 0;
117         while (buffer[in] == '\r' || buffer[in] == '\n')
118                 in++;
119         while (buffer[in]) {
120                 if (in + 4 > len) {
121                         ERROR("unexpected input size in base64dec");
122                         free(result);
123                         return -1;
124                 }
125                 x0 = (unsigned char)fromb64(buffer[in]);
126                 x1 = (unsigned char)fromb64(buffer[in+1]);
127                 x2 = (unsigned char)fromb64(buffer[in+2]);
128                 x3 = (unsigned char)fromb64(buffer[in+3]);
129                 in += 4;
130                 if (x0 == 'E' || x1 == 'E' || x2 == 'E' || x3 == 'E') {
131                         ERROR("unexpected input character in base64dec");
132                         free(result);
133                         return -1;
134                 }
135                 if (x0 == '@' || x1 == '@' || (x2 == '@' && x3 != '@')) {
136                         ERROR("unexpected termination character in base64dec");
137                         free(result);
138                         return -1;
139                 }
140                 result[out] = (char)((x0 << 2) | (x1 >> 4));
141                 result[out+1] = (char)((x1 << 4) | ((x2 >> 2) & 15));
142                 result[out+2] = (char)((x2 << 6) | (x3 & 63));
143                 while (buffer[in] == '\r' || buffer[in] == '\n')
144                         in++;
145                 if (x3 != '@')
146                         out += 3;
147                 else if (!buffer[in])
148                         out += 1 + (x2 != '@');
149                 else {
150                         ERROR("unexpected continuation in base64dec");
151                         free(result);
152                         return -1;
153                 }
154         }
155         *output = result;
156         return out;
157 }
158
159 int base64eq(const char *buf1, const char *buf2)
160 {
161         for(;;) {
162                 while(*buf1 == '\n' || *buf1 == '\r')
163                         buf1++;
164                 while(*buf2 == '\n' || *buf2 == '\r')
165                         buf2++;
166                 if (*buf1 != *buf2)
167                         return 0;
168                 if (!*buf1)
169                         return 1;
170                 buf1++;
171                 buf2++;
172         }
173 }
174
175 #ifdef TESTBASE64
176 #include <fcntl.h>
177 #include <string.h>
178
179 int main(int ac, char **av)
180 {
181         char buffer[32768];
182         int fd, l0, l1, l2;
183         char *p1, *p2;
184
185         while(*++av) {
186                 fd = open(*av, O_RDONLY);
187                 if (fd < 0) continue;
188                 l0 = read(fd, buffer, sizeof buffer);
189                 if (l0 <= 0) continue;
190                 close(fd);
191                 p1 = base64enc(buffer, l0);
192                 if (!p1) continue;
193                 l1 = strlen(p1);
194                 l2 = base64dec(p1, &p2);
195                 if (l2 <= 0) continue;
196 printf("[[[%.*s]]]\n",l2,p2);
197                 if (l0 != l2) printf("length mismatch\n");
198                 else if (memcmp(buffer, p2, l0)) printf("content mismatch\n");
199                 free(p1);
200                 free(p2);
201         }
202         return 0;
203 }
204
205 #endif