]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/basic/hexdecoct.c
basic/extract-word,man: clarify "correction" of invalid escapes
[thirdparty/systemd.git] / src / basic / hexdecoct.c
CommitLineData
e4e73a63
LP
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>
11c3a366
TA
21#include <errno.h>
22#include <stdint.h>
23#include <stdlib.h>
e4e73a63 24
b5efdb8a 25#include "alloc-util.h"
e4e73a63 26#include "hexdecoct.h"
11c3a366 27#include "macro.h"
75f32f04 28#include "util.h"
e4e73a63
LP
29
30char octchar(int x) {
31 return '0' + (x & 7);
32}
33
34int unoctchar(char c) {
35
36 if (c >= '0' && c <= '7')
37 return c - '0';
38
39 return -EINVAL;
40}
41
42char decchar(int x) {
43 return '0' + (x % 10);
44}
45
46int undecchar(char c) {
47
48 if (c >= '0' && c <= '9')
49 return c - '0';
50
51 return -EINVAL;
52}
53
54char hexchar(int x) {
55 static const char table[16] = "0123456789abcdef";
56
57 return table[x & 15];
58}
59
60int 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
74char *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
91int 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. */
135char base32hexchar(int x) {
136 static const char table[32] = "0123456789"
137 "ABCDEFGHIJKLMNOPQRSTUV";
138
139 return table[x & 31];
140}
141
142int 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
156char *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
262int 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) {
313cefa1
VC
279 pad++;
280 l--;
e4e73a63
LP
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 */
480char base64char(int x) {
481 static const char table[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
482 "abcdefghijklmnopqrstuvwxyz"
483 "0123456789+/";
484 return table[x & 63];
485}
486
487int 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
313cefa1 508 offset++;
e4e73a63
LP
509
510 if (c == '/')
511 return offset;
512
513 return -EINVAL;
514}
515
d7671a3e 516ssize_t base64mem(const void *p, size_t l, char **out) {
e4e73a63
LP
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)
d7671a3e 523 return -ENOMEM;
e4e73a63
LP
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;
d7671a3e
ZJS
551 *out = r;
552 return z - r;
553}
554
555static 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
75f32f04 576 memcpy_safe(t + plen, sep, slen);
d7671a3e
ZJS
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;
e4e73a63
LP
595}
596
d7671a3e
ZJS
597int 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
e4e73a63
LP
609int 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] == '=')
313cefa1 624 l--;
e4e73a63 625 if (l > 0 && p[l - 1] == '=')
313cefa1 626 l--;
e4e73a63
LP
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
713void 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}