]>
git.ipfire.org Git - thirdparty/systemd.git/blob - src/basic/hexdecoct.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
8 #include "alloc-util.h"
11 #include "string-util.h"
18 int unoctchar(char c
) {
20 if (c
>= '0' && c
<= '7')
27 return '0' + (x
% 10);
30 int undecchar(char c
) {
32 if (c
>= '0' && c
<= '9')
39 static const char table
[16] = "0123456789abcdef";
44 int unhexchar(char c
) {
46 if (c
>= '0' && c
<= '9')
49 if (c
>= 'a' && c
<= 'f')
52 if (c
>= 'A' && c
<= 'F')
58 char *hexmem(const void *p
, size_t l
) {
62 z
= r
= new(char, l
* 2 + 1);
66 for (x
= p
; x
< (const uint8_t*) p
+ l
; x
++) {
67 *(z
++) = hexchar(*x
>> 4);
68 *(z
++) = hexchar(*x
& 15);
75 static int unhex_next(const char **p
, size_t *l
) {
81 /* Find the next non-whitespace character, and decode it. We
82 * greedily skip all preceeding and all following whitespace. */
88 if (!strchr(WHITESPACE
, **p
))
91 /* Skip leading whitespace */
102 if (*l
== 0 || !strchr(WHITESPACE
, **p
))
105 /* Skip following whitespace */
111 int unhexmem(const char *p
, size_t l
, void **ret
, size_t *ret_len
) {
112 _cleanup_free_
uint8_t *buf
= NULL
;
120 if (l
== (size_t) -1)
123 /* Note that the calculation of memory size is an upper boundary, as we ignore whitespace while decoding */
124 buf
= malloc((l
+ 1) / 2 + 1);
128 for (x
= p
, z
= buf
;;) {
131 a
= unhex_next(&x
, &l
);
132 if (a
== -EPIPE
) /* End of string */
137 b
= unhex_next(&x
, &l
);
141 *(z
++) = (uint8_t) a
<< 4 | (uint8_t) b
;
146 *ret_len
= (size_t) (z
- buf
);
147 *ret
= TAKE_PTR(buf
);
152 /* https://tools.ietf.org/html/rfc4648#section-6
153 * Notice that base32hex differs from base32 in the alphabet it uses.
154 * The distinction is that the base32hex representation preserves the
155 * order of the underlying data when compared as bytestrings, this is
156 * useful when representing NSEC3 hashes, as one can then verify the
157 * order of hashes directly from their representation. */
158 char base32hexchar(int x
) {
159 static const char table
[32] = "0123456789"
160 "ABCDEFGHIJKLMNOPQRSTUV";
162 return table
[x
& 31];
165 int unbase32hexchar(char c
) {
168 if (c
>= '0' && c
<= '9')
171 offset
= '9' - '0' + 1;
173 if (c
>= 'A' && c
<= 'V')
174 return c
- 'A' + offset
;
179 char *base32hexmem(const void *p
, size_t l
, bool padding
) {
187 /* five input bytes makes eight output bytes, padding is added so we must round up */
188 len
= 8 * (l
+ 4) / 5;
190 /* same, but round down as there is no padding */
209 z
= r
= malloc(len
+ 1);
213 for (x
= p
; x
< (const uint8_t*) p
+ (l
/ 5) * 5; x
+= 5) {
214 /* x[0] == XXXXXXXX; x[1] == YYYYYYYY; x[2] == ZZZZZZZZ
215 * x[3] == QQQQQQQQ; x[4] == WWWWWWWW */
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 | x
[3] >> 7); /* 000ZZZZQ */
221 *(z
++) = base32hexchar((x
[3] & 127) >> 2); /* 000QQQQQ */
222 *(z
++) = base32hexchar((x
[3] & 3) << 3 | x
[4] >> 5); /* 000QQWWW */
223 *(z
++) = base32hexchar((x
[4] & 31)); /* 000WWWWW */
228 *(z
++) = base32hexchar(x
[0] >> 3); /* 000XXXXX */
229 *(z
++) = base32hexchar((x
[0] & 7) << 2 | x
[1] >> 6); /* 000XXXYY */
230 *(z
++) = base32hexchar((x
[1] & 63) >> 1); /* 000YYYYY */
231 *(z
++) = base32hexchar((x
[1] & 1) << 4 | x
[2] >> 4); /* 000YZZZZ */
232 *(z
++) = base32hexchar((x
[2] & 15) << 1 | x
[3] >> 7); /* 000ZZZZQ */
233 *(z
++) = base32hexchar((x
[3] & 127) >> 2); /* 000QQQQQ */
234 *(z
++) = base32hexchar((x
[3] & 3) << 3); /* 000QQ000 */
241 *(z
++) = base32hexchar(x
[0] >> 3); /* 000XXXXX */
242 *(z
++) = base32hexchar((x
[0] & 7) << 2 | x
[1] >> 6); /* 000XXXYY */
243 *(z
++) = base32hexchar((x
[1] & 63) >> 1); /* 000YYYYY */
244 *(z
++) = base32hexchar((x
[1] & 1) << 4 | x
[2] >> 4); /* 000YZZZZ */
245 *(z
++) = base32hexchar((x
[2] & 15) << 1); /* 000ZZZZ0 */
255 *(z
++) = base32hexchar(x
[0] >> 3); /* 000XXXXX */
256 *(z
++) = base32hexchar((x
[0] & 7) << 2 | x
[1] >> 6); /* 000XXXYY */
257 *(z
++) = base32hexchar((x
[1] & 63) >> 1); /* 000YYYYY */
258 *(z
++) = base32hexchar((x
[1] & 1) << 4); /* 000Y0000 */
269 *(z
++) = base32hexchar(x
[0] >> 3); /* 000XXXXX */
270 *(z
++) = base32hexchar((x
[0] & 7) << 2); /* 000XXX00 */
287 int unbase32hexmem(const char *p
, size_t l
, bool padding
, void **mem
, size_t *_len
) {
288 _cleanup_free_
uint8_t *r
= NULL
;
289 int a
, b
, c
, d
, e
, f
, g
, h
;
299 if (l
== (size_t) -1)
302 /* padding ensures any base32hex input has input divisible by 8 */
303 if (padding
&& l
% 8 != 0)
307 /* strip the padding */
308 while (l
> 0 && p
[l
- 1] == '=' && pad
< 7) {
314 /* a group of eight input bytes needs five output bytes, in case of
315 * padding we need to add some extra bytes */
337 z
= r
= malloc(len
+ 1);
341 for (x
= p
; x
< p
+ (l
/ 8) * 8; x
+= 8) {
342 /* a == 000XXXXX; b == 000YYYYY; c == 000ZZZZZ; d == 000WWWWW
343 * e == 000SSSSS; f == 000QQQQQ; g == 000VVVVV; h == 000RRRRR */
344 a
= unbase32hexchar(x
[0]);
348 b
= unbase32hexchar(x
[1]);
352 c
= unbase32hexchar(x
[2]);
356 d
= unbase32hexchar(x
[3]);
360 e
= unbase32hexchar(x
[4]);
364 f
= unbase32hexchar(x
[5]);
368 g
= unbase32hexchar(x
[6]);
372 h
= unbase32hexchar(x
[7]);
376 *(z
++) = (uint8_t) a
<< 3 | (uint8_t) b
>> 2; /* XXXXXYYY */
377 *(z
++) = (uint8_t) b
<< 6 | (uint8_t) c
<< 1 | (uint8_t) d
>> 4; /* YYZZZZZW */
378 *(z
++) = (uint8_t) d
<< 4 | (uint8_t) e
>> 1; /* WWWWSSSS */
379 *(z
++) = (uint8_t) e
<< 7 | (uint8_t) f
<< 2 | (uint8_t) g
>> 3; /* SQQQQQVV */
380 *(z
++) = (uint8_t) g
<< 5 | (uint8_t) h
; /* VVVRRRRR */
385 a
= unbase32hexchar(x
[0]);
389 b
= unbase32hexchar(x
[1]);
393 c
= unbase32hexchar(x
[2]);
397 d
= unbase32hexchar(x
[3]);
401 e
= unbase32hexchar(x
[4]);
405 f
= unbase32hexchar(x
[5]);
409 g
= unbase32hexchar(x
[6]);
417 *(z
++) = (uint8_t) a
<< 3 | (uint8_t) b
>> 2; /* XXXXXYYY */
418 *(z
++) = (uint8_t) b
<< 6 | (uint8_t) c
<< 1 | (uint8_t) d
>> 4; /* YYZZZZZW */
419 *(z
++) = (uint8_t) d
<< 4 | (uint8_t) e
>> 1; /* WWWWSSSS */
420 *(z
++) = (uint8_t) e
<< 7 | (uint8_t) f
<< 2 | (uint8_t) g
>> 3; /* SQQQQQVV */
424 a
= unbase32hexchar(x
[0]);
428 b
= unbase32hexchar(x
[1]);
432 c
= unbase32hexchar(x
[2]);
436 d
= unbase32hexchar(x
[3]);
440 e
= unbase32hexchar(x
[4]);
448 *(z
++) = (uint8_t) a
<< 3 | (uint8_t) b
>> 2; /* XXXXXYYY */
449 *(z
++) = (uint8_t) b
<< 6 | (uint8_t) c
<< 1 | (uint8_t) d
>> 4; /* YYZZZZZW */
450 *(z
++) = (uint8_t) d
<< 4 | (uint8_t) e
>> 1; /* WWWWSSSS */
454 a
= unbase32hexchar(x
[0]);
458 b
= unbase32hexchar(x
[1]);
462 c
= unbase32hexchar(x
[2]);
466 d
= unbase32hexchar(x
[3]);
474 *(z
++) = (uint8_t) a
<< 3 | (uint8_t) b
>> 2; /* XXXXXYYY */
475 *(z
++) = (uint8_t) b
<< 6 | (uint8_t) c
<< 1 | (uint8_t) d
>> 4; /* YYZZZZZW */
479 a
= unbase32hexchar(x
[0]);
483 b
= unbase32hexchar(x
[1]);
491 *(z
++) = (uint8_t) a
<< 3 | (uint8_t) b
>> 2; /* XXXXXYYY */
508 /* https://tools.ietf.org/html/rfc4648#section-4 */
509 char base64char(int x
) {
510 static const char table
[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
511 "abcdefghijklmnopqrstuvwxyz"
513 return table
[x
& 63];
516 int unbase64char(char c
) {
519 if (c
>= 'A' && c
<= 'Z')
522 offset
= 'Z' - 'A' + 1;
524 if (c
>= 'a' && c
<= 'z')
525 return c
- 'a' + offset
;
527 offset
+= 'z' - 'a' + 1;
529 if (c
>= '0' && c
<= '9')
530 return c
- '0' + offset
;
532 offset
+= '9' - '0' + 1;
545 ssize_t
base64mem(const void *p
, size_t l
, char **out
) {
552 /* three input bytes makes four output bytes, padding is added so we must round up */
553 z
= r
= malloc(4 * (l
+ 2) / 3 + 1);
557 for (x
= p
; x
< (const uint8_t*) p
+ (l
/ 3) * 3; x
+= 3) {
558 /* x[0] == XXXXXXXX; x[1] == YYYYYYYY; x[2] == ZZZZZZZZ */
559 *(z
++) = base64char(x
[0] >> 2); /* 00XXXXXX */
560 *(z
++) = base64char((x
[0] & 3) << 4 | x
[1] >> 4); /* 00XXYYYY */
561 *(z
++) = base64char((x
[1] & 15) << 2 | x
[2] >> 6); /* 00YYYYZZ */
562 *(z
++) = base64char(x
[2] & 63); /* 00ZZZZZZ */
567 *(z
++) = base64char(x
[0] >> 2); /* 00XXXXXX */
568 *(z
++) = base64char((x
[0] & 3) << 4 | x
[1] >> 4); /* 00XXYYYY */
569 *(z
++) = base64char((x
[1] & 15) << 2); /* 00YYYY00 */
574 *(z
++) = base64char(x
[0] >> 2); /* 00XXXXXX */
575 *(z
++) = base64char((x
[0] & 3) << 4); /* 00XX0000 */
587 static int base64_append_width(
588 char **prefix
, int plen
,
589 const char *sep
, int indent
,
590 const void *p
, size_t l
,
593 _cleanup_free_
char *x
= NULL
;
595 ssize_t slen
, len
, avail
;
598 len
= base64mem(p
, l
, &x
);
602 lines
= DIV_ROUND_UP(len
, width
);
604 slen
= strlen_ptr(sep
);
605 t
= realloc(*prefix
, plen
+ 1 + slen
+ (indent
+ width
+ 1) * lines
);
609 memcpy_safe(t
+ plen
, sep
, slen
);
611 for (line
= 0, s
= t
+ plen
+ slen
, avail
= len
; line
< lines
; line
++) {
612 int act
= MIN(width
, avail
);
614 if (line
> 0 || sep
) {
615 memset(s
, ' ', indent
);
619 memcpy(s
, x
+ width
* line
, act
);
621 *(s
++) = line
< lines
- 1 ? '\n' : '\0';
631 char **prefix
, int plen
,
632 const void *p
, size_t l
,
633 int indent
, int width
) {
635 if (plen
> width
/ 2 || plen
+ indent
> width
)
636 /* leave indent on the left, keep last column free */
637 return base64_append_width(prefix
, plen
, "\n", indent
, p
, l
, width
- indent
- 1);
639 /* leave plen on the left, keep last column free */
640 return base64_append_width(prefix
, plen
, NULL
, plen
, p
, l
, width
- plen
- 1);
643 static int unbase64_next(const char **p
, size_t *l
) {
649 /* Find the next non-whitespace character, and decode it. If we find padding, we return it as INT_MAX. We
650 * greedily skip all preceeding and all following whitespace. */
656 if (!strchr(WHITESPACE
, **p
))
659 /* Skip leading whitespace */
664 ret
= INT_MAX
; /* return padding as INT_MAX */
666 ret
= unbase64char(**p
);
676 if (!strchr(WHITESPACE
, **p
))
679 /* Skip following whitespace */
685 int unbase64mem(const char *p
, size_t l
, void **ret
, size_t *ret_size
) {
686 _cleanup_free_
uint8_t *buf
= NULL
;
695 if (l
== (size_t) -1)
698 /* A group of four input bytes needs three output bytes, in case of padding we need to add two or three extra
699 * bytes. Note that this calculation is an upper boundary, as we ignore whitespace while decoding */
700 len
= (l
/ 4) * 3 + (l
% 4 != 0 ? (l
% 4) - 1 : 0);
702 buf
= malloc(len
+ 1);
706 for (x
= p
, z
= buf
;;) {
707 int a
, b
, c
, d
; /* a == 00XXXXXX; b == 00YYYYYY; c == 00ZZZZZZ; d == 00WWWWWW */
709 a
= unbase64_next(&x
, &l
);
710 if (a
== -EPIPE
) /* End of string */
714 if (a
== INT_MAX
) /* Padding is not allowed at the beginning of a 4ch block */
717 b
= unbase64_next(&x
, &l
);
720 if (b
== INT_MAX
) /* Padding is not allowed at the second character of a 4ch block either */
723 c
= unbase64_next(&x
, &l
);
727 d
= unbase64_next(&x
, &l
);
731 if (c
== INT_MAX
) { /* Padding at the third character */
733 if (d
!= INT_MAX
) /* If the third character is padding, the fourth must be too */
740 if (l
> 0) /* Trailing rubbish? */
741 return -ENAMETOOLONG
;
743 *(z
++) = (uint8_t) a
<< 2 | (uint8_t) (b
>> 4); /* XXXXXXYY */
752 if (l
> 0) /* Trailing rubbish? */
753 return -ENAMETOOLONG
;
755 *(z
++) = (uint8_t) a
<< 2 | (uint8_t) b
>> 4; /* XXXXXXYY */
756 *(z
++) = (uint8_t) b
<< 4 | (uint8_t) c
>> 2; /* YYYYZZZZ */
760 *(z
++) = (uint8_t) a
<< 2 | (uint8_t) b
>> 4; /* XXXXXXYY */
761 *(z
++) = (uint8_t) b
<< 4 | (uint8_t) c
>> 2; /* YYYYZZZZ */
762 *(z
++) = (uint8_t) c
<< 6 | (uint8_t) d
; /* ZZWWWWWW */
767 *ret_size
= (size_t) (z
- buf
);
768 *ret
= TAKE_PTR(buf
);
773 void hexdump(FILE *f
, const void *p
, size_t s
) {
774 const uint8_t *b
= p
;
785 fprintf(f
, "%04x ", n
);
787 for (i
= 0; i
< 16; i
++) {
792 fprintf(f
, "%02x ", b
[i
]);
800 for (i
= 0; i
< 16; i
++) {
805 fputc(isprint(b
[i
]) ? (char) b
[i
] : '.', f
);