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