]>
git.ipfire.org Git - thirdparty/systemd.git/blob - src/basic/hexdecoct.c
b3ea05ce53e6d1b315edd429ee62027242d5aa6d
1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 This file is part of systemd.
5 Copyright 2010 Lennart Poettering
13 #include "alloc-util.h"
14 #include "hexdecoct.h"
16 #include "string-util.h"
23 int unoctchar(char c
) {
25 if (c
>= '0' && c
<= '7')
32 return '0' + (x
% 10);
35 int undecchar(char c
) {
37 if (c
>= '0' && c
<= '9')
44 static const char table
[16] = "0123456789abcdef";
49 int unhexchar(char c
) {
51 if (c
>= '0' && c
<= '9')
54 if (c
>= 'a' && c
<= 'f')
57 if (c
>= 'A' && c
<= 'F')
63 char *hexmem(const void *p
, size_t l
) {
67 z
= r
= new(char, l
* 2 + 1);
71 for (x
= p
; x
< (const uint8_t*) p
+ l
; x
++) {
72 *(z
++) = hexchar(*x
>> 4);
73 *(z
++) = hexchar(*x
& 15);
80 static int unhex_next(const char **p
, size_t *l
) {
86 /* Find the next non-whitespace character, and decode it. We
87 * greedily skip all preceeding and all following whitespace. */
93 if (!strchr(WHITESPACE
, **p
))
96 /* Skip leading whitespace */
107 if (*l
== 0 || !strchr(WHITESPACE
, **p
))
110 /* Skip following whitespace */
116 int unhexmem(const char *p
, size_t l
, void **ret
, size_t *ret_len
) {
117 _cleanup_free_
uint8_t *buf
= NULL
;
125 if (l
== (size_t) -1)
128 /* Note that the calculation of memory size is an upper boundary, as we ignore whitespace while decoding */
129 buf
= malloc((l
+ 1) / 2 + 1);
133 for (x
= p
, z
= buf
;;) {
136 a
= unhex_next(&x
, &l
);
137 if (a
== -EPIPE
) /* End of string */
142 b
= unhex_next(&x
, &l
);
146 *(z
++) = (uint8_t) a
<< 4 | (uint8_t) b
;
151 *ret_len
= (size_t) (z
- buf
);
152 *ret
= TAKE_PTR(buf
);
157 /* https://tools.ietf.org/html/rfc4648#section-6
158 * Notice that base32hex differs from base32 in the alphabet it uses.
159 * The distinction is that the base32hex representation preserves the
160 * order of the underlying data when compared as bytestrings, this is
161 * useful when representing NSEC3 hashes, as one can then verify the
162 * order of hashes directly from their representation. */
163 char base32hexchar(int x
) {
164 static const char table
[32] = "0123456789"
165 "ABCDEFGHIJKLMNOPQRSTUV";
167 return table
[x
& 31];
170 int unbase32hexchar(char c
) {
173 if (c
>= '0' && c
<= '9')
176 offset
= '9' - '0' + 1;
178 if (c
>= 'A' && c
<= 'V')
179 return c
- 'A' + offset
;
184 char *base32hexmem(const void *p
, size_t l
, bool padding
) {
192 /* five input bytes makes eight output bytes, padding is added so we must round up */
193 len
= 8 * (l
+ 4) / 5;
195 /* same, but round down as there is no padding */
214 z
= r
= malloc(len
+ 1);
218 for (x
= p
; x
< (const uint8_t*) p
+ (l
/ 5) * 5; x
+= 5) {
219 /* x[0] == XXXXXXXX; x[1] == YYYYYYYY; x[2] == ZZZZZZZZ
220 * x[3] == QQQQQQQQ; x[4] == WWWWWWWW */
221 *(z
++) = base32hexchar(x
[0] >> 3); /* 000XXXXX */
222 *(z
++) = base32hexchar((x
[0] & 7) << 2 | x
[1] >> 6); /* 000XXXYY */
223 *(z
++) = base32hexchar((x
[1] & 63) >> 1); /* 000YYYYY */
224 *(z
++) = base32hexchar((x
[1] & 1) << 4 | x
[2] >> 4); /* 000YZZZZ */
225 *(z
++) = base32hexchar((x
[2] & 15) << 1 | x
[3] >> 7); /* 000ZZZZQ */
226 *(z
++) = base32hexchar((x
[3] & 127) >> 2); /* 000QQQQQ */
227 *(z
++) = base32hexchar((x
[3] & 3) << 3 | x
[4] >> 5); /* 000QQWWW */
228 *(z
++) = base32hexchar((x
[4] & 31)); /* 000WWWWW */
233 *(z
++) = base32hexchar(x
[0] >> 3); /* 000XXXXX */
234 *(z
++) = base32hexchar((x
[0] & 7) << 2 | x
[1] >> 6); /* 000XXXYY */
235 *(z
++) = base32hexchar((x
[1] & 63) >> 1); /* 000YYYYY */
236 *(z
++) = base32hexchar((x
[1] & 1) << 4 | x
[2] >> 4); /* 000YZZZZ */
237 *(z
++) = base32hexchar((x
[2] & 15) << 1 | x
[3] >> 7); /* 000ZZZZQ */
238 *(z
++) = base32hexchar((x
[3] & 127) >> 2); /* 000QQQQQ */
239 *(z
++) = base32hexchar((x
[3] & 3) << 3); /* 000QQ000 */
246 *(z
++) = base32hexchar(x
[0] >> 3); /* 000XXXXX */
247 *(z
++) = base32hexchar((x
[0] & 7) << 2 | x
[1] >> 6); /* 000XXXYY */
248 *(z
++) = base32hexchar((x
[1] & 63) >> 1); /* 000YYYYY */
249 *(z
++) = base32hexchar((x
[1] & 1) << 4 | x
[2] >> 4); /* 000YZZZZ */
250 *(z
++) = base32hexchar((x
[2] & 15) << 1); /* 000ZZZZ0 */
260 *(z
++) = base32hexchar(x
[0] >> 3); /* 000XXXXX */
261 *(z
++) = base32hexchar((x
[0] & 7) << 2 | x
[1] >> 6); /* 000XXXYY */
262 *(z
++) = base32hexchar((x
[1] & 63) >> 1); /* 000YYYYY */
263 *(z
++) = base32hexchar((x
[1] & 1) << 4); /* 000Y0000 */
274 *(z
++) = base32hexchar(x
[0] >> 3); /* 000XXXXX */
275 *(z
++) = base32hexchar((x
[0] & 7) << 2); /* 000XXX00 */
292 int unbase32hexmem(const char *p
, size_t l
, bool padding
, void **mem
, size_t *_len
) {
293 _cleanup_free_
uint8_t *r
= NULL
;
294 int a
, b
, c
, d
, e
, f
, g
, h
;
304 if (l
== (size_t) -1)
307 /* padding ensures any base32hex input has input divisible by 8 */
308 if (padding
&& l
% 8 != 0)
312 /* strip the padding */
313 while (l
> 0 && p
[l
- 1] == '=' && pad
< 7) {
319 /* a group of eight input bytes needs five output bytes, in case of
320 * padding we need to add some extra bytes */
342 z
= r
= malloc(len
+ 1);
346 for (x
= p
; x
< p
+ (l
/ 8) * 8; x
+= 8) {
347 /* a == 000XXXXX; b == 000YYYYY; c == 000ZZZZZ; d == 000WWWWW
348 * e == 000SSSSS; f == 000QQQQQ; g == 000VVVVV; h == 000RRRRR */
349 a
= unbase32hexchar(x
[0]);
353 b
= unbase32hexchar(x
[1]);
357 c
= unbase32hexchar(x
[2]);
361 d
= unbase32hexchar(x
[3]);
365 e
= unbase32hexchar(x
[4]);
369 f
= unbase32hexchar(x
[5]);
373 g
= unbase32hexchar(x
[6]);
377 h
= unbase32hexchar(x
[7]);
381 *(z
++) = (uint8_t) a
<< 3 | (uint8_t) b
>> 2; /* XXXXXYYY */
382 *(z
++) = (uint8_t) b
<< 6 | (uint8_t) c
<< 1 | (uint8_t) d
>> 4; /* YYZZZZZW */
383 *(z
++) = (uint8_t) d
<< 4 | (uint8_t) e
>> 1; /* WWWWSSSS */
384 *(z
++) = (uint8_t) e
<< 7 | (uint8_t) f
<< 2 | (uint8_t) g
>> 3; /* SQQQQQVV */
385 *(z
++) = (uint8_t) g
<< 5 | (uint8_t) h
; /* VVVRRRRR */
390 a
= unbase32hexchar(x
[0]);
394 b
= unbase32hexchar(x
[1]);
398 c
= unbase32hexchar(x
[2]);
402 d
= unbase32hexchar(x
[3]);
406 e
= unbase32hexchar(x
[4]);
410 f
= unbase32hexchar(x
[5]);
414 g
= unbase32hexchar(x
[6]);
422 *(z
++) = (uint8_t) a
<< 3 | (uint8_t) b
>> 2; /* XXXXXYYY */
423 *(z
++) = (uint8_t) b
<< 6 | (uint8_t) c
<< 1 | (uint8_t) d
>> 4; /* YYZZZZZW */
424 *(z
++) = (uint8_t) d
<< 4 | (uint8_t) e
>> 1; /* WWWWSSSS */
425 *(z
++) = (uint8_t) e
<< 7 | (uint8_t) f
<< 2 | (uint8_t) g
>> 3; /* SQQQQQVV */
429 a
= unbase32hexchar(x
[0]);
433 b
= unbase32hexchar(x
[1]);
437 c
= unbase32hexchar(x
[2]);
441 d
= unbase32hexchar(x
[3]);
445 e
= unbase32hexchar(x
[4]);
453 *(z
++) = (uint8_t) a
<< 3 | (uint8_t) b
>> 2; /* XXXXXYYY */
454 *(z
++) = (uint8_t) b
<< 6 | (uint8_t) c
<< 1 | (uint8_t) d
>> 4; /* YYZZZZZW */
455 *(z
++) = (uint8_t) d
<< 4 | (uint8_t) e
>> 1; /* WWWWSSSS */
459 a
= unbase32hexchar(x
[0]);
463 b
= unbase32hexchar(x
[1]);
467 c
= unbase32hexchar(x
[2]);
471 d
= unbase32hexchar(x
[3]);
479 *(z
++) = (uint8_t) a
<< 3 | (uint8_t) b
>> 2; /* XXXXXYYY */
480 *(z
++) = (uint8_t) b
<< 6 | (uint8_t) c
<< 1 | (uint8_t) d
>> 4; /* YYZZZZZW */
484 a
= unbase32hexchar(x
[0]);
488 b
= unbase32hexchar(x
[1]);
496 *(z
++) = (uint8_t) a
<< 3 | (uint8_t) b
>> 2; /* XXXXXYYY */
513 /* https://tools.ietf.org/html/rfc4648#section-4 */
514 char base64char(int x
) {
515 static const char table
[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
516 "abcdefghijklmnopqrstuvwxyz"
518 return table
[x
& 63];
521 int unbase64char(char c
) {
524 if (c
>= 'A' && c
<= 'Z')
527 offset
= 'Z' - 'A' + 1;
529 if (c
>= 'a' && c
<= 'z')
530 return c
- 'a' + offset
;
532 offset
+= 'z' - 'a' + 1;
534 if (c
>= '0' && c
<= '9')
535 return c
- '0' + offset
;
537 offset
+= '9' - '0' + 1;
550 ssize_t
base64mem(const void *p
, size_t l
, char **out
) {
557 /* three input bytes makes four output bytes, padding is added so we must round up */
558 z
= r
= malloc(4 * (l
+ 2) / 3 + 1);
562 for (x
= p
; x
< (const uint8_t*) p
+ (l
/ 3) * 3; x
+= 3) {
563 /* x[0] == XXXXXXXX; x[1] == YYYYYYYY; x[2] == ZZZZZZZZ */
564 *(z
++) = base64char(x
[0] >> 2); /* 00XXXXXX */
565 *(z
++) = base64char((x
[0] & 3) << 4 | x
[1] >> 4); /* 00XXYYYY */
566 *(z
++) = base64char((x
[1] & 15) << 2 | x
[2] >> 6); /* 00YYYYZZ */
567 *(z
++) = base64char(x
[2] & 63); /* 00ZZZZZZ */
572 *(z
++) = base64char(x
[0] >> 2); /* 00XXXXXX */
573 *(z
++) = base64char((x
[0] & 3) << 4 | x
[1] >> 4); /* 00XXYYYY */
574 *(z
++) = base64char((x
[1] & 15) << 2); /* 00YYYY00 */
579 *(z
++) = base64char(x
[0] >> 2); /* 00XXXXXX */
580 *(z
++) = base64char((x
[0] & 3) << 4); /* 00XX0000 */
592 static int base64_append_width(
593 char **prefix
, int plen
,
594 const char *sep
, int indent
,
595 const void *p
, size_t l
,
598 _cleanup_free_
char *x
= NULL
;
600 ssize_t slen
, len
, avail
;
603 len
= base64mem(p
, l
, &x
);
607 lines
= DIV_ROUND_UP(len
, width
);
609 slen
= strlen_ptr(sep
);
610 t
= realloc(*prefix
, plen
+ 1 + slen
+ (indent
+ width
+ 1) * lines
);
614 memcpy_safe(t
+ plen
, sep
, slen
);
616 for (line
= 0, s
= t
+ plen
+ slen
, avail
= len
; line
< lines
; line
++) {
617 int act
= MIN(width
, avail
);
619 if (line
> 0 || sep
) {
620 memset(s
, ' ', indent
);
624 memcpy(s
, x
+ width
* line
, act
);
626 *(s
++) = line
< lines
- 1 ? '\n' : '\0';
636 char **prefix
, int plen
,
637 const void *p
, size_t l
,
638 int indent
, int width
) {
640 if (plen
> width
/ 2 || plen
+ indent
> width
)
641 /* leave indent on the left, keep last column free */
642 return base64_append_width(prefix
, plen
, "\n", indent
, p
, l
, width
- indent
- 1);
644 /* leave plen on the left, keep last column free */
645 return base64_append_width(prefix
, plen
, NULL
, plen
, p
, l
, width
- plen
- 1);
648 static int unbase64_next(const char **p
, size_t *l
) {
654 /* Find the next non-whitespace character, and decode it. If we find padding, we return it as INT_MAX. We
655 * greedily skip all preceeding and all following whitespace. */
661 if (!strchr(WHITESPACE
, **p
))
664 /* Skip leading whitespace */
669 ret
= INT_MAX
; /* return padding as INT_MAX */
671 ret
= unbase64char(**p
);
681 if (!strchr(WHITESPACE
, **p
))
684 /* Skip following whitespace */
690 int unbase64mem(const char *p
, size_t l
, void **ret
, size_t *ret_size
) {
691 _cleanup_free_
uint8_t *buf
= NULL
;
700 if (l
== (size_t) -1)
703 /* A group of four input bytes needs three output bytes, in case of padding we need to add two or three extra
704 * bytes. Note that this calculation is an upper boundary, as we ignore whitespace while decoding */
705 len
= (l
/ 4) * 3 + (l
% 4 != 0 ? (l
% 4) - 1 : 0);
707 buf
= malloc(len
+ 1);
711 for (x
= p
, z
= buf
;;) {
712 int a
, b
, c
, d
; /* a == 00XXXXXX; b == 00YYYYYY; c == 00ZZZZZZ; d == 00WWWWWW */
714 a
= unbase64_next(&x
, &l
);
715 if (a
== -EPIPE
) /* End of string */
719 if (a
== INT_MAX
) /* Padding is not allowed at the beginning of a 4ch block */
722 b
= unbase64_next(&x
, &l
);
725 if (b
== INT_MAX
) /* Padding is not allowed at the second character of a 4ch block either */
728 c
= unbase64_next(&x
, &l
);
732 d
= unbase64_next(&x
, &l
);
736 if (c
== INT_MAX
) { /* Padding at the third character */
738 if (d
!= INT_MAX
) /* If the third character is padding, the fourth must be too */
745 if (l
> 0) /* Trailing rubbish? */
746 return -ENAMETOOLONG
;
748 *(z
++) = (uint8_t) a
<< 2 | (uint8_t) (b
>> 4); /* XXXXXXYY */
757 if (l
> 0) /* Trailing rubbish? */
758 return -ENAMETOOLONG
;
760 *(z
++) = (uint8_t) a
<< 2 | (uint8_t) b
>> 4; /* XXXXXXYY */
761 *(z
++) = (uint8_t) b
<< 4 | (uint8_t) c
>> 2; /* YYYYZZZZ */
765 *(z
++) = (uint8_t) a
<< 2 | (uint8_t) b
>> 4; /* XXXXXXYY */
766 *(z
++) = (uint8_t) b
<< 4 | (uint8_t) c
>> 2; /* YYYYZZZZ */
767 *(z
++) = (uint8_t) c
<< 6 | (uint8_t) d
; /* ZZWWWWWW */
772 *ret_size
= (size_t) (z
- buf
);
773 *ret
= TAKE_PTR(buf
);
778 void hexdump(FILE *f
, const void *p
, size_t s
) {
779 const uint8_t *b
= p
;
790 fprintf(f
, "%04x ", n
);
792 for (i
= 0; i
< 16; i
++) {
797 fprintf(f
, "%02x ", b
[i
]);
805 for (i
= 0; i
< 16; i
++) {
810 fputc(isprint(b
[i
]) ? (char) b
[i
] : '.', f
);