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