chiark / gitweb /
tests: add tests for environment serialization
[elogind.git] / src / basic / hexdecoct.c
1 /***
2   This file is part of systemd.
3
4   Copyright 2010 Lennart Poettering
5
6   systemd is free software; you can redistribute it and/or modify it
7   under the terms of the GNU Lesser General Public License as published by
8   the Free Software Foundation; either version 2.1 of the License, or
9   (at your option) any later version.
10
11   systemd is distributed in the hope that it will be useful, but
12   WITHOUT ANY WARRANTY; without even the implied warranty of
13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14   Lesser General Public License for more details.
15
16   You should have received a copy of the GNU Lesser General Public License
17   along with systemd; If not, see <http://www.gnu.org/licenses/>.
18 ***/
19
20 #include <ctype.h>
21 #include <errno.h>
22 #include <stdint.h>
23 #include <stdlib.h>
24
25 #include "alloc-util.h"
26 #include "hexdecoct.h"
27 #include "macro.h"
28 #include "util.h"
29
30 char octchar(int x) {
31         return '0' + (x & 7);
32 }
33
34 int unoctchar(char c) {
35
36         if (c >= '0' && c <= '7')
37                 return c - '0';
38
39         return -EINVAL;
40 }
41
42 char decchar(int x) {
43         return '0' + (x % 10);
44 }
45
46 int undecchar(char c) {
47
48         if (c >= '0' && c <= '9')
49                 return c - '0';
50
51         return -EINVAL;
52 }
53
54 char hexchar(int x) {
55         static const char table[16] = "0123456789abcdef";
56
57         return table[x & 15];
58 }
59
60 int unhexchar(char c) {
61
62         if (c >= '0' && c <= '9')
63                 return c - '0';
64
65         if (c >= 'a' && c <= 'f')
66                 return c - 'a' + 10;
67
68         if (c >= 'A' && c <= 'F')
69                 return c - 'A' + 10;
70
71         return -EINVAL;
72 }
73
74 char *hexmem(const void *p, size_t l) {
75         const uint8_t *x;
76         char *r, *z;
77
78         z = r = new(char, l * 2 + 1);
79         if (!r)
80                 return NULL;
81
82         for (x = p; x < (const uint8_t*) p + l; x++) {
83                 *(z++) = hexchar(*x >> 4);
84                 *(z++) = hexchar(*x & 15);
85         }
86
87         *z = 0;
88         return r;
89 }
90
91 int unhexmem(const char *p, size_t l, void **mem, size_t *len) {
92         _cleanup_free_ uint8_t *r = NULL;
93         uint8_t *z;
94         const char *x;
95
96         assert(mem);
97         assert(len);
98         assert(p);
99
100         if (l % 2 != 0)
101                 return -EINVAL;
102
103         z = r = malloc((l + 1) / 2 + 1);
104         if (!r)
105                 return -ENOMEM;
106
107         for (x = p; x < p + l; x += 2) {
108                 int a, b;
109
110                 a = unhexchar(x[0]);
111                 if (a < 0)
112                         return a;
113
114                 b = unhexchar(x[1]);
115                 if (b < 0)
116                         return b;
117
118                 *(z++) = (uint8_t) a << 4 | (uint8_t) b;
119         }
120
121         *z = 0;
122
123         *mem = r;
124         r = NULL;
125         *len = (l + 1) / 2;
126
127         return 0;
128 }
129
130 /* https://tools.ietf.org/html/rfc4648#section-6
131  * Notice that base32hex differs from base32 in the alphabet it uses.
132  * The distinction is that the base32hex representation preserves the
133  * order of the underlying data when compared as bytestrings, this is
134  * useful when representing NSEC3 hashes, as one can then verify the
135  * order of hashes directly from their representation. */
136 char base32hexchar(int x) {
137         static const char table[32] = "0123456789"
138                                       "ABCDEFGHIJKLMNOPQRSTUV";
139
140         return table[x & 31];
141 }
142
143 int unbase32hexchar(char c) {
144         unsigned offset;
145
146         if (c >= '0' && c <= '9')
147                 return c - '0';
148
149         offset = '9' - '0' + 1;
150
151         if (c >= 'A' && c <= 'V')
152                 return c - 'A' + offset;
153
154         return -EINVAL;
155 }
156
157 char *base32hexmem(const void *p, size_t l, bool padding) {
158         char *r, *z;
159         const uint8_t *x;
160         size_t len;
161
162         if (padding)
163                 /* five input bytes makes eight output bytes, padding is added so we must round up */
164                 len = 8 * (l + 4) / 5;
165         else {
166                 /* same, but round down as there is no padding */
167                 len = 8 * l / 5;
168
169                 switch (l % 5) {
170                 case 4:
171                         len += 7;
172                         break;
173                 case 3:
174                         len += 5;
175                         break;
176                 case 2:
177                         len += 4;
178                         break;
179                 case 1:
180                         len += 2;
181                         break;
182                 }
183         }
184
185         z = r = malloc(len + 1);
186         if (!r)
187                 return NULL;
188
189         for (x = p; x < (const uint8_t*) p + (l / 5) * 5; x += 5) {
190                 /* x[0] == XXXXXXXX; x[1] == YYYYYYYY; x[2] == ZZZZZZZZ
191                    x[3] == QQQQQQQQ; x[4] == WWWWWWWW */
192                 *(z++) = base32hexchar(x[0] >> 3);                    /* 000XXXXX */
193                 *(z++) = base32hexchar((x[0] & 7) << 2 | x[1] >> 6);  /* 000XXXYY */
194                 *(z++) = base32hexchar((x[1] & 63) >> 1);             /* 000YYYYY */
195                 *(z++) = base32hexchar((x[1] & 1) << 4 | x[2] >> 4);  /* 000YZZZZ */
196                 *(z++) = base32hexchar((x[2] & 15) << 1 | x[3] >> 7); /* 000ZZZZQ */
197                 *(z++) = base32hexchar((x[3] & 127) >> 2);            /* 000QQQQQ */
198                 *(z++) = base32hexchar((x[3] & 3) << 3 | x[4] >> 5);  /* 000QQWWW */
199                 *(z++) = base32hexchar((x[4] & 31));                  /* 000WWWWW */
200         }
201
202         switch (l % 5) {
203         case 4:
204                 *(z++) = base32hexchar(x[0] >> 3);                    /* 000XXXXX */
205                 *(z++) = base32hexchar((x[0] & 7) << 2 | x[1] >> 6);  /* 000XXXYY */
206                 *(z++) = base32hexchar((x[1] & 63) >> 1);             /* 000YYYYY */
207                 *(z++) = base32hexchar((x[1] & 1) << 4 | x[2] >> 4);   /* 000YZZZZ */
208                 *(z++) = base32hexchar((x[2] & 15) << 1 | x[3] >> 7); /* 000ZZZZQ */
209                 *(z++) = base32hexchar((x[3] & 127) >> 2);            /* 000QQQQQ */
210                 *(z++) = base32hexchar((x[3] & 3) << 3);              /* 000QQ000 */
211                 if (padding)
212                         *(z++) = '=';
213
214                 break;
215
216         case 3:
217                 *(z++) = base32hexchar(x[0] >> 3);                   /* 000XXXXX */
218                 *(z++) = base32hexchar((x[0] & 7) << 2 | x[1] >> 6); /* 000XXXYY */
219                 *(z++) = base32hexchar((x[1] & 63) >> 1);            /* 000YYYYY */
220                 *(z++) = base32hexchar((x[1] & 1) << 4 | x[2] >> 4); /* 000YZZZZ */
221                 *(z++) = base32hexchar((x[2] & 15) << 1);            /* 000ZZZZ0 */
222                 if (padding) {
223                         *(z++) = '=';
224                         *(z++) = '=';
225                         *(z++) = '=';
226                 }
227
228                 break;
229
230         case 2:
231                 *(z++) = base32hexchar(x[0] >> 3);                   /* 000XXXXX */
232                 *(z++) = base32hexchar((x[0] & 7) << 2 | x[1] >> 6); /* 000XXXYY */
233                 *(z++) = base32hexchar((x[1] & 63) >> 1);            /* 000YYYYY */
234                 *(z++) = base32hexchar((x[1] & 1) << 4);             /* 000Y0000 */
235                 if (padding) {
236                         *(z++) = '=';
237                         *(z++) = '=';
238                         *(z++) = '=';
239                         *(z++) = '=';
240                 }
241
242                 break;
243
244         case 1:
245                 *(z++) = base32hexchar(x[0] >> 3);       /* 000XXXXX */
246                 *(z++) = base32hexchar((x[0] & 7) << 2); /* 000XXX00 */
247                 if (padding) {
248                         *(z++) = '=';
249                         *(z++) = '=';
250                         *(z++) = '=';
251                         *(z++) = '=';
252                         *(z++) = '=';
253                         *(z++) = '=';
254                 }
255
256                 break;
257         }
258
259         *z = 0;
260         return r;
261 }
262
263 int unbase32hexmem(const char *p, size_t l, bool padding, void **mem, size_t *_len) {
264         _cleanup_free_ uint8_t *r = NULL;
265         int a, b, c, d, e, f, g, h;
266         uint8_t *z;
267         const char *x;
268         size_t len;
269         unsigned pad = 0;
270
271         assert(p);
272
273         /* padding ensures any base32hex input has input divisible by 8 */
274         if (padding && l % 8 != 0)
275                 return -EINVAL;
276
277         if (padding) {
278                 /* strip the padding */
279                 while (l > 0 && p[l - 1] == '=' && pad < 7) {
280                         pad++;
281                         l--;
282                 }
283         }
284
285         /* a group of eight input bytes needs five output bytes, in case of
286            padding we need to add some extra bytes */
287         len = (l / 8) * 5;
288
289         switch (l % 8) {
290         case 7:
291                 len += 4;
292                 break;
293         case 5:
294                 len += 3;
295                 break;
296         case 4:
297                 len += 2;
298                 break;
299         case 2:
300                 len += 1;
301                 break;
302         case 0:
303                 break;
304         default:
305                 return -EINVAL;
306         }
307
308         z = r = malloc(len + 1);
309         if (!r)
310                 return -ENOMEM;
311
312         for (x = p; x < p + (l / 8) * 8; x += 8) {
313                 /* a == 000XXXXX; b == 000YYYYY; c == 000ZZZZZ; d == 000WWWWW
314                    e == 000SSSSS; f == 000QQQQQ; g == 000VVVVV; h == 000RRRRR */
315                 a = unbase32hexchar(x[0]);
316                 if (a < 0)
317                         return -EINVAL;
318
319                 b = unbase32hexchar(x[1]);
320                 if (b < 0)
321                         return -EINVAL;
322
323                 c = unbase32hexchar(x[2]);
324                 if (c < 0)
325                         return -EINVAL;
326
327                 d = unbase32hexchar(x[3]);
328                 if (d < 0)
329                         return -EINVAL;
330
331                 e = unbase32hexchar(x[4]);
332                 if (e < 0)
333                         return -EINVAL;
334
335                 f = unbase32hexchar(x[5]);
336                 if (f < 0)
337                         return -EINVAL;
338
339                 g = unbase32hexchar(x[6]);
340                 if (g < 0)
341                         return -EINVAL;
342
343                 h = unbase32hexchar(x[7]);
344                 if (h < 0)
345                         return -EINVAL;
346
347                 *(z++) = (uint8_t) a << 3 | (uint8_t) b >> 2;                    /* XXXXXYYY */
348                 *(z++) = (uint8_t) b << 6 | (uint8_t) c << 1 | (uint8_t) d >> 4; /* YYZZZZZW */
349                 *(z++) = (uint8_t) d << 4 | (uint8_t) e >> 1;                    /* WWWWSSSS */
350                 *(z++) = (uint8_t) e << 7 | (uint8_t) f << 2 | (uint8_t) g >> 3; /* SQQQQQVV */
351                 *(z++) = (uint8_t) g << 5 | (uint8_t) h;                         /* VVVRRRRR */
352         }
353
354         switch (l % 8) {
355         case 7:
356                 a = unbase32hexchar(x[0]);
357                 if (a < 0)
358                         return -EINVAL;
359
360                 b = unbase32hexchar(x[1]);
361                 if (b < 0)
362                         return -EINVAL;
363
364                 c = unbase32hexchar(x[2]);
365                 if (c < 0)
366                         return -EINVAL;
367
368                 d = unbase32hexchar(x[3]);
369                 if (d < 0)
370                         return -EINVAL;
371
372                 e = unbase32hexchar(x[4]);
373                 if (e < 0)
374                         return -EINVAL;
375
376                 f = unbase32hexchar(x[5]);
377                 if (f < 0)
378                         return -EINVAL;
379
380                 g = unbase32hexchar(x[6]);
381                 if (g < 0)
382                         return -EINVAL;
383
384                 /* g == 000VV000 */
385                 if (g & 7)
386                         return -EINVAL;
387
388                 *(z++) = (uint8_t) a << 3 | (uint8_t) b >> 2;                    /* XXXXXYYY */
389                 *(z++) = (uint8_t) b << 6 | (uint8_t) c << 1 | (uint8_t) d >> 4; /* YYZZZZZW */
390                 *(z++) = (uint8_t) d << 4 | (uint8_t) e >> 1;                    /* WWWWSSSS */
391                 *(z++) = (uint8_t) e << 7 | (uint8_t) f << 2 | (uint8_t) g >> 3; /* SQQQQQVV */
392
393                 break;
394         case 5:
395                 a = unbase32hexchar(x[0]);
396                 if (a < 0)
397                         return -EINVAL;
398
399                 b = unbase32hexchar(x[1]);
400                 if (b < 0)
401                         return -EINVAL;
402
403                 c = unbase32hexchar(x[2]);
404                 if (c < 0)
405                         return -EINVAL;
406
407                 d = unbase32hexchar(x[3]);
408                 if (d < 0)
409                         return -EINVAL;
410
411                 e = unbase32hexchar(x[4]);
412                 if (e < 0)
413                         return -EINVAL;
414
415                 /* e == 000SSSS0 */
416                 if (e & 1)
417                         return -EINVAL;
418
419                 *(z++) = (uint8_t) a << 3 | (uint8_t) b >> 2;                    /* XXXXXYYY */
420                 *(z++) = (uint8_t) b << 6 | (uint8_t) c << 1 | (uint8_t) d >> 4; /* YYZZZZZW */
421                 *(z++) = (uint8_t) d << 4 | (uint8_t) e >> 1;                    /* WWWWSSSS */
422
423                 break;
424         case 4:
425                 a = unbase32hexchar(x[0]);
426                 if (a < 0)
427                         return -EINVAL;
428
429                 b = unbase32hexchar(x[1]);
430                 if (b < 0)
431                         return -EINVAL;
432
433                 c = unbase32hexchar(x[2]);
434                 if (c < 0)
435                         return -EINVAL;
436
437                 d = unbase32hexchar(x[3]);
438                 if (d < 0)
439                         return -EINVAL;
440
441                 /* d == 000W0000 */
442                 if (d & 15)
443                         return -EINVAL;
444
445                 *(z++) = (uint8_t) a << 3 | (uint8_t) b >> 2;                    /* XXXXXYYY */
446                 *(z++) = (uint8_t) b << 6 | (uint8_t) c << 1 | (uint8_t) d >> 4; /* YYZZZZZW */
447
448                 break;
449         case 2:
450                 a = unbase32hexchar(x[0]);
451                 if (a < 0)
452                         return -EINVAL;
453
454                 b = unbase32hexchar(x[1]);
455                 if (b < 0)
456                         return -EINVAL;
457
458                 /* b == 000YYY00 */
459                 if (b & 3)
460                         return -EINVAL;
461
462                 *(z++) = (uint8_t) a << 3 | (uint8_t) b >> 2; /* XXXXXYYY */
463
464                 break;
465         case 0:
466                 break;
467         default:
468                 return -EINVAL;
469         }
470
471         *z = 0;
472
473         *mem = r;
474         r = NULL;
475         *_len = len;
476
477         return 0;
478 }
479
480 /* https://tools.ietf.org/html/rfc4648#section-4 */
481 char base64char(int x) {
482         static const char table[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
483                                       "abcdefghijklmnopqrstuvwxyz"
484                                       "0123456789+/";
485         return table[x & 63];
486 }
487
488 int unbase64char(char c) {
489         unsigned offset;
490
491         if (c >= 'A' && c <= 'Z')
492                 return c - 'A';
493
494         offset = 'Z' - 'A' + 1;
495
496         if (c >= 'a' && c <= 'z')
497                 return c - 'a' + offset;
498
499         offset += 'z' - 'a' + 1;
500
501         if (c >= '0' && c <= '9')
502                 return c - '0' + offset;
503
504         offset += '9' - '0' + 1;
505
506         if (c == '+')
507                 return offset;
508
509         offset++;
510
511         if (c == '/')
512                 return offset;
513
514         return -EINVAL;
515 }
516
517 ssize_t base64mem(const void *p, size_t l, char **out) {
518         char *r, *z;
519         const uint8_t *x;
520
521         /* three input bytes makes four output bytes, padding is added so we must round up */
522         z = r = malloc(4 * (l + 2) / 3 + 1);
523         if (!r)
524                 return -ENOMEM;
525
526         for (x = p; x < (const uint8_t*) p + (l / 3) * 3; x += 3) {
527                 /* x[0] == XXXXXXXX; x[1] == YYYYYYYY; x[2] == ZZZZZZZZ */
528                 *(z++) = base64char(x[0] >> 2);                    /* 00XXXXXX */
529                 *(z++) = base64char((x[0] & 3) << 4 | x[1] >> 4);  /* 00XXYYYY */
530                 *(z++) = base64char((x[1] & 15) << 2 | x[2] >> 6); /* 00YYYYZZ */
531                 *(z++) = base64char(x[2] & 63);                    /* 00ZZZZZZ */
532         }
533
534         switch (l % 3) {
535         case 2:
536                 *(z++) = base64char(x[0] >> 2);                   /* 00XXXXXX */
537                 *(z++) = base64char((x[0] & 3) << 4 | x[1] >> 4); /* 00XXYYYY */
538                 *(z++) = base64char((x[1] & 15) << 2);            /* 00YYYY00 */
539                 *(z++) = '=';
540
541                 break;
542         case 1:
543                 *(z++) = base64char(x[0] >> 2);        /* 00XXXXXX */
544                 *(z++) = base64char((x[0] & 3) << 4);  /* 00XX0000 */
545                 *(z++) = '=';
546                 *(z++) = '=';
547
548                 break;
549         }
550
551         *z = 0;
552         *out = r;
553         return z - r;
554 }
555
556 static int base64_append_width(char **prefix, int plen,
557                                const char *sep, int indent,
558                                const void *p, size_t l,
559                                int width) {
560
561         _cleanup_free_ char *x = NULL;
562         char *t, *s;
563         ssize_t slen, len, avail;
564         int line, lines;
565
566         len = base64mem(p, l, &x);
567         if (len <= 0)
568                 return len;
569
570         lines = (len + width - 1) / width;
571
572         slen = sep ? strlen(sep) : 0;
573         t = realloc(*prefix, plen + 1 + slen + (indent + width + 1) * lines);
574         if (!t)
575                 return -ENOMEM;
576
577         memcpy_safe(t + plen, sep, slen);
578
579         for (line = 0, s = t + plen + slen, avail = len; line < lines; line++) {
580                 int act = MIN(width, avail);
581
582                 if (line > 0 || sep) {
583                         memset(s, ' ', indent);
584                         s += indent;
585                 }
586
587                 memcpy(s, x + width * line, act);
588                 s += act;
589                 *(s++) = line < lines - 1 ? '\n' : '\0';
590                 avail -= act;
591         }
592         assert(avail == 0);
593
594         *prefix = t;
595         return 0;
596 }
597
598 int base64_append(char **prefix, int plen,
599                   const void *p, size_t l,
600                   int indent, int width) {
601         if (plen > width / 2 || plen + indent > width)
602                 /* leave indent on the left, keep last column free */
603                 return base64_append_width(prefix, plen, "\n", indent, p, l, width - indent - 1);
604         else
605                 /* leave plen on the left, keep last column free */
606                 return base64_append_width(prefix, plen, NULL, plen, p, l, width - plen - 1);
607 };
608
609
610 int unbase64mem(const char *p, size_t l, void **mem, size_t *_len) {
611         _cleanup_free_ uint8_t *r = NULL;
612         int a, b, c, d;
613         uint8_t *z;
614         const char *x;
615         size_t len;
616
617         assert(p);
618
619         /* padding ensures any base63 input has input divisible by 4 */
620         if (l % 4 != 0)
621                 return -EINVAL;
622
623         /* strip the padding */
624         if (l > 0 && p[l - 1] == '=')
625                 l--;
626         if (l > 0 && p[l - 1] == '=')
627                 l--;
628
629         /* a group of four input bytes needs three output bytes, in case of
630            padding we need to add two or three extra bytes */
631         len = (l / 4) * 3 + (l % 4 ? (l % 4) - 1 : 0);
632
633         z = r = malloc(len + 1);
634         if (!r)
635                 return -ENOMEM;
636
637         for (x = p; x < p + (l / 4) * 4; x += 4) {
638                 /* a == 00XXXXXX; b == 00YYYYYY; c == 00ZZZZZZ; d == 00WWWWWW */
639                 a = unbase64char(x[0]);
640                 if (a < 0)
641                         return -EINVAL;
642
643                 b = unbase64char(x[1]);
644                 if (b < 0)
645                         return -EINVAL;
646
647                 c = unbase64char(x[2]);
648                 if (c < 0)
649                         return -EINVAL;
650
651                 d = unbase64char(x[3]);
652                 if (d < 0)
653                         return -EINVAL;
654
655                 *(z++) = (uint8_t) a << 2 | (uint8_t) b >> 4; /* XXXXXXYY */
656                 *(z++) = (uint8_t) b << 4 | (uint8_t) c >> 2; /* YYYYZZZZ */
657                 *(z++) = (uint8_t) c << 6 | (uint8_t) d;      /* ZZWWWWWW */
658         }
659
660         switch (l % 4) {
661         case 3:
662                 a = unbase64char(x[0]);
663                 if (a < 0)
664                         return -EINVAL;
665
666                 b = unbase64char(x[1]);
667                 if (b < 0)
668                         return -EINVAL;
669
670                 c = unbase64char(x[2]);
671                 if (c < 0)
672                         return -EINVAL;
673
674                 /* c == 00ZZZZ00 */
675                 if (c & 3)
676                         return -EINVAL;
677
678                 *(z++) = (uint8_t) a << 2 | (uint8_t) b >> 4; /* XXXXXXYY */
679                 *(z++) = (uint8_t) b << 4 | (uint8_t) c >> 2; /* YYYYZZZZ */
680
681                 break;
682         case 2:
683                 a = unbase64char(x[0]);
684                 if (a < 0)
685                         return -EINVAL;
686
687                 b = unbase64char(x[1]);
688                 if (b < 0)
689                         return -EINVAL;
690
691                 /* b == 00YY0000 */
692                 if (b & 15)
693                         return -EINVAL;
694
695                 *(z++) = (uint8_t) a << 2 | (uint8_t) (b >> 4); /* XXXXXXYY */
696
697                 break;
698         case 0:
699
700                 break;
701         default:
702                 return -EINVAL;
703         }
704
705         *z = 0;
706
707         *mem = r;
708         r = NULL;
709         *_len = len;
710
711         return 0;
712 }
713
714 void hexdump(FILE *f, const void *p, size_t s) {
715         const uint8_t *b = p;
716         unsigned n = 0;
717
718         assert(s == 0 || b);
719
720         while (s > 0) {
721                 size_t i;
722
723                 fprintf(f, "%04x  ", n);
724
725                 for (i = 0; i < 16; i++) {
726
727                         if (i >= s)
728                                 fputs("   ", f);
729                         else
730                                 fprintf(f, "%02x ", b[i]);
731
732                         if (i == 7)
733                                 fputc(' ', f);
734                 }
735
736                 fputc(' ', f);
737
738                 for (i = 0; i < 16; i++) {
739
740                         if (i >= s)
741                                 fputc(' ', f);
742                         else
743                                 fputc(isprint(b[i]) ? (char) b[i] : '.', f);
744                 }
745
746                 fputc('\n', f);
747
748                 if (s < 16)
749                         break;
750
751                 n += 16;
752                 b += 16;
753                 s -= 16;
754         }
755 }