]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/basic/hexdecoct.c
man: force space in cmdsynopsis
[thirdparty/systemd.git] / src / basic / hexdecoct.c
CommitLineData
e4e73a63
LP
1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3/***
4 This file is part of systemd.
5
6 Copyright 2010 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
22#include <ctype.h>
11c3a366
TA
23#include <errno.h>
24#include <stdint.h>
25#include <stdlib.h>
e4e73a63 26
b5efdb8a 27#include "alloc-util.h"
e4e73a63 28#include "hexdecoct.h"
11c3a366 29#include "macro.h"
e4e73a63
LP
30
31char octchar(int x) {
32 return '0' + (x & 7);
33}
34
35int unoctchar(char c) {
36
37 if (c >= '0' && c <= '7')
38 return c - '0';
39
40 return -EINVAL;
41}
42
43char decchar(int x) {
44 return '0' + (x % 10);
45}
46
47int undecchar(char c) {
48
49 if (c >= '0' && c <= '9')
50 return c - '0';
51
52 return -EINVAL;
53}
54
55char hexchar(int x) {
56 static const char table[16] = "0123456789abcdef";
57
58 return table[x & 15];
59}
60
61int unhexchar(char c) {
62
63 if (c >= '0' && c <= '9')
64 return c - '0';
65
66 if (c >= 'a' && c <= 'f')
67 return c - 'a' + 10;
68
69 if (c >= 'A' && c <= 'F')
70 return c - 'A' + 10;
71
72 return -EINVAL;
73}
74
75char *hexmem(const void *p, size_t l) {
76 char *r, *z;
77 const uint8_t *x;
78
79 z = r = malloc(l * 2 + 1);
80 if (!r)
81 return NULL;
82
83 for (x = p; x < (const uint8_t*) p + l; x++) {
84 *(z++) = hexchar(*x >> 4);
85 *(z++) = hexchar(*x & 15);
86 }
87
88 *z = 0;
89 return r;
90}
91
92int unhexmem(const char *p, size_t l, void **mem, size_t *len) {
93 _cleanup_free_ uint8_t *r = NULL;
94 uint8_t *z;
95 const char *x;
96
97 assert(mem);
98 assert(len);
99 assert(p);
100
101 z = r = malloc((l + 1) / 2 + 1);
102 if (!r)
103 return -ENOMEM;
104
105 for (x = p; x < p + l; x += 2) {
106 int a, b;
107
108 a = unhexchar(x[0]);
109 if (a < 0)
110 return a;
111 else if (x+1 < p + l) {
112 b = unhexchar(x[1]);
113 if (b < 0)
114 return b;
115 } else
116 b = 0;
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. */
136char base32hexchar(int x) {
137 static const char table[32] = "0123456789"
138 "ABCDEFGHIJKLMNOPQRSTUV";
139
140 return table[x & 31];
141}
142
143int 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
157char *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
263int 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 */
481char base64char(int x) {
482 static const char table[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
483 "abcdefghijklmnopqrstuvwxyz"
484 "0123456789+/";
485 return table[x & 63];
486}
487
488int 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
517char *base64mem(const void *p, size_t l) {
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 NULL;
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 return r;
553}
554
555int unbase64mem(const char *p, size_t l, void **mem, size_t *_len) {
556 _cleanup_free_ uint8_t *r = NULL;
557 int a, b, c, d;
558 uint8_t *z;
559 const char *x;
560 size_t len;
561
562 assert(p);
563
564 /* padding ensures any base63 input has input divisible by 4 */
565 if (l % 4 != 0)
566 return -EINVAL;
567
568 /* strip the padding */
569 if (l > 0 && p[l - 1] == '=')
570 l --;
571 if (l > 0 && p[l - 1] == '=')
572 l --;
573
574 /* a group of four input bytes needs three output bytes, in case of
575 padding we need to add two or three extra bytes */
576 len = (l / 4) * 3 + (l % 4 ? (l % 4) - 1 : 0);
577
578 z = r = malloc(len + 1);
579 if (!r)
580 return -ENOMEM;
581
582 for (x = p; x < p + (l / 4) * 4; x += 4) {
583 /* a == 00XXXXXX; b == 00YYYYYY; c == 00ZZZZZZ; d == 00WWWWWW */
584 a = unbase64char(x[0]);
585 if (a < 0)
586 return -EINVAL;
587
588 b = unbase64char(x[1]);
589 if (b < 0)
590 return -EINVAL;
591
592 c = unbase64char(x[2]);
593 if (c < 0)
594 return -EINVAL;
595
596 d = unbase64char(x[3]);
597 if (d < 0)
598 return -EINVAL;
599
600 *(z++) = (uint8_t) a << 2 | (uint8_t) b >> 4; /* XXXXXXYY */
601 *(z++) = (uint8_t) b << 4 | (uint8_t) c >> 2; /* YYYYZZZZ */
602 *(z++) = (uint8_t) c << 6 | (uint8_t) d; /* ZZWWWWWW */
603 }
604
605 switch (l % 4) {
606 case 3:
607 a = unbase64char(x[0]);
608 if (a < 0)
609 return -EINVAL;
610
611 b = unbase64char(x[1]);
612 if (b < 0)
613 return -EINVAL;
614
615 c = unbase64char(x[2]);
616 if (c < 0)
617 return -EINVAL;
618
619 /* c == 00ZZZZ00 */
620 if (c & 3)
621 return -EINVAL;
622
623 *(z++) = (uint8_t) a << 2 | (uint8_t) b >> 4; /* XXXXXXYY */
624 *(z++) = (uint8_t) b << 4 | (uint8_t) c >> 2; /* YYYYZZZZ */
625
626 break;
627 case 2:
628 a = unbase64char(x[0]);
629 if (a < 0)
630 return -EINVAL;
631
632 b = unbase64char(x[1]);
633 if (b < 0)
634 return -EINVAL;
635
636 /* b == 00YY0000 */
637 if (b & 15)
638 return -EINVAL;
639
640 *(z++) = (uint8_t) a << 2 | (uint8_t) (b >> 4); /* XXXXXXYY */
641
642 break;
643 case 0:
644
645 break;
646 default:
647 return -EINVAL;
648 }
649
650 *z = 0;
651
652 *mem = r;
653 r = NULL;
654 *_len = len;
655
656 return 0;
657}
658
659void hexdump(FILE *f, const void *p, size_t s) {
660 const uint8_t *b = p;
661 unsigned n = 0;
662
663 assert(s == 0 || b);
664
665 while (s > 0) {
666 size_t i;
667
668 fprintf(f, "%04x ", n);
669
670 for (i = 0; i < 16; i++) {
671
672 if (i >= s)
673 fputs(" ", f);
674 else
675 fprintf(f, "%02x ", b[i]);
676
677 if (i == 7)
678 fputc(' ', f);
679 }
680
681 fputc(' ', f);
682
683 for (i = 0; i < 16; i++) {
684
685 if (i >= s)
686 fputc(' ', f);
687 else
688 fputc(isprint(b[i]) ? (char) b[i] : '.', f);
689 }
690
691 fputc('\n', f);
692
693 if (s < 16)
694 break;
695
696 n += 16;
697 b += 16;
698 s -= 16;
699 }
700}