]>
git.ipfire.org Git - thirdparty/systemd.git/blob - src/basic/hexdecoct.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 This file is part of systemd.
5 Copyright 2010 Lennart Poettering
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
26 #include "alloc-util.h"
27 #include "hexdecoct.h"
29 #include "string-util.h"
36 int unoctchar(char c
) {
38 if (c
>= '0' && c
<= '7')
45 return '0' + (x
% 10);
48 int undecchar(char c
) {
50 if (c
>= '0' && c
<= '9')
57 static const char table
[16] = "0123456789abcdef";
62 int unhexchar(char c
) {
64 if (c
>= '0' && c
<= '9')
67 if (c
>= 'a' && c
<= 'f')
70 if (c
>= 'A' && c
<= 'F')
76 char *hexmem(const void *p
, size_t l
) {
80 z
= r
= new(char, l
* 2 + 1);
84 for (x
= p
; x
< (const uint8_t*) p
+ l
; x
++) {
85 *(z
++) = hexchar(*x
>> 4);
86 *(z
++) = hexchar(*x
& 15);
93 int unhexmem(const char *p
, size_t l
, void **mem
, size_t *len
) {
94 _cleanup_free_
uint8_t *r
= NULL
;
102 if (l
== (size_t) -1)
108 z
= r
= malloc((l
+ 1) / 2 + 1);
112 for (x
= p
; x
< p
+ l
; x
+= 2) {
123 *(z
++) = (uint8_t) a
<< 4 | (uint8_t) b
;
134 /* https://tools.ietf.org/html/rfc4648#section-6
135 * Notice that base32hex differs from base32 in the alphabet it uses.
136 * The distinction is that the base32hex representation preserves the
137 * order of the underlying data when compared as bytestrings, this is
138 * useful when representing NSEC3 hashes, as one can then verify the
139 * order of hashes directly from their representation. */
140 char base32hexchar(int x
) {
141 static const char table
[32] = "0123456789"
142 "ABCDEFGHIJKLMNOPQRSTUV";
144 return table
[x
& 31];
147 int unbase32hexchar(char c
) {
150 if (c
>= '0' && c
<= '9')
153 offset
= '9' - '0' + 1;
155 if (c
>= 'A' && c
<= 'V')
156 return c
- 'A' + offset
;
161 char *base32hexmem(const void *p
, size_t l
, bool padding
) {
169 /* five input bytes makes eight output bytes, padding is added so we must round up */
170 len
= 8 * (l
+ 4) / 5;
172 /* same, but round down as there is no padding */
191 z
= r
= malloc(len
+ 1);
195 for (x
= p
; x
< (const uint8_t*) p
+ (l
/ 5) * 5; x
+= 5) {
196 /* x[0] == XXXXXXXX; x[1] == YYYYYYYY; x[2] == ZZZZZZZZ
197 x[3] == QQQQQQQQ; x[4] == WWWWWWWW */
198 *(z
++) = base32hexchar(x
[0] >> 3); /* 000XXXXX */
199 *(z
++) = base32hexchar((x
[0] & 7) << 2 | x
[1] >> 6); /* 000XXXYY */
200 *(z
++) = base32hexchar((x
[1] & 63) >> 1); /* 000YYYYY */
201 *(z
++) = base32hexchar((x
[1] & 1) << 4 | x
[2] >> 4); /* 000YZZZZ */
202 *(z
++) = base32hexchar((x
[2] & 15) << 1 | x
[3] >> 7); /* 000ZZZZQ */
203 *(z
++) = base32hexchar((x
[3] & 127) >> 2); /* 000QQQQQ */
204 *(z
++) = base32hexchar((x
[3] & 3) << 3 | x
[4] >> 5); /* 000QQWWW */
205 *(z
++) = base32hexchar((x
[4] & 31)); /* 000WWWWW */
210 *(z
++) = base32hexchar(x
[0] >> 3); /* 000XXXXX */
211 *(z
++) = base32hexchar((x
[0] & 7) << 2 | x
[1] >> 6); /* 000XXXYY */
212 *(z
++) = base32hexchar((x
[1] & 63) >> 1); /* 000YYYYY */
213 *(z
++) = base32hexchar((x
[1] & 1) << 4 | x
[2] >> 4); /* 000YZZZZ */
214 *(z
++) = base32hexchar((x
[2] & 15) << 1 | x
[3] >> 7); /* 000ZZZZQ */
215 *(z
++) = base32hexchar((x
[3] & 127) >> 2); /* 000QQQQQ */
216 *(z
++) = base32hexchar((x
[3] & 3) << 3); /* 000QQ000 */
223 *(z
++) = base32hexchar(x
[0] >> 3); /* 000XXXXX */
224 *(z
++) = base32hexchar((x
[0] & 7) << 2 | x
[1] >> 6); /* 000XXXYY */
225 *(z
++) = base32hexchar((x
[1] & 63) >> 1); /* 000YYYYY */
226 *(z
++) = base32hexchar((x
[1] & 1) << 4 | x
[2] >> 4); /* 000YZZZZ */
227 *(z
++) = base32hexchar((x
[2] & 15) << 1); /* 000ZZZZ0 */
237 *(z
++) = base32hexchar(x
[0] >> 3); /* 000XXXXX */
238 *(z
++) = base32hexchar((x
[0] & 7) << 2 | x
[1] >> 6); /* 000XXXYY */
239 *(z
++) = base32hexchar((x
[1] & 63) >> 1); /* 000YYYYY */
240 *(z
++) = base32hexchar((x
[1] & 1) << 4); /* 000Y0000 */
251 *(z
++) = base32hexchar(x
[0] >> 3); /* 000XXXXX */
252 *(z
++) = base32hexchar((x
[0] & 7) << 2); /* 000XXX00 */
269 int unbase32hexmem(const char *p
, size_t l
, bool padding
, void **mem
, size_t *_len
) {
270 _cleanup_free_
uint8_t *r
= NULL
;
271 int a
, b
, c
, d
, e
, f
, g
, h
;
281 if (l
== (size_t) -1)
284 /* padding ensures any base32hex input has input divisible by 8 */
285 if (padding
&& l
% 8 != 0)
289 /* strip the padding */
290 while (l
> 0 && p
[l
- 1] == '=' && pad
< 7) {
296 /* a group of eight input bytes needs five output bytes, in case of
297 padding we need to add some extra bytes */
319 z
= r
= malloc(len
+ 1);
323 for (x
= p
; x
< p
+ (l
/ 8) * 8; x
+= 8) {
324 /* a == 000XXXXX; b == 000YYYYY; c == 000ZZZZZ; d == 000WWWWW
325 e == 000SSSSS; f == 000QQQQQ; g == 000VVVVV; h == 000RRRRR */
326 a
= unbase32hexchar(x
[0]);
330 b
= unbase32hexchar(x
[1]);
334 c
= unbase32hexchar(x
[2]);
338 d
= unbase32hexchar(x
[3]);
342 e
= unbase32hexchar(x
[4]);
346 f
= unbase32hexchar(x
[5]);
350 g
= unbase32hexchar(x
[6]);
354 h
= unbase32hexchar(x
[7]);
358 *(z
++) = (uint8_t) a
<< 3 | (uint8_t) b
>> 2; /* XXXXXYYY */
359 *(z
++) = (uint8_t) b
<< 6 | (uint8_t) c
<< 1 | (uint8_t) d
>> 4; /* YYZZZZZW */
360 *(z
++) = (uint8_t) d
<< 4 | (uint8_t) e
>> 1; /* WWWWSSSS */
361 *(z
++) = (uint8_t) e
<< 7 | (uint8_t) f
<< 2 | (uint8_t) g
>> 3; /* SQQQQQVV */
362 *(z
++) = (uint8_t) g
<< 5 | (uint8_t) h
; /* VVVRRRRR */
367 a
= unbase32hexchar(x
[0]);
371 b
= unbase32hexchar(x
[1]);
375 c
= unbase32hexchar(x
[2]);
379 d
= unbase32hexchar(x
[3]);
383 e
= unbase32hexchar(x
[4]);
387 f
= unbase32hexchar(x
[5]);
391 g
= unbase32hexchar(x
[6]);
399 *(z
++) = (uint8_t) a
<< 3 | (uint8_t) b
>> 2; /* XXXXXYYY */
400 *(z
++) = (uint8_t) b
<< 6 | (uint8_t) c
<< 1 | (uint8_t) d
>> 4; /* YYZZZZZW */
401 *(z
++) = (uint8_t) d
<< 4 | (uint8_t) e
>> 1; /* WWWWSSSS */
402 *(z
++) = (uint8_t) e
<< 7 | (uint8_t) f
<< 2 | (uint8_t) g
>> 3; /* SQQQQQVV */
406 a
= unbase32hexchar(x
[0]);
410 b
= unbase32hexchar(x
[1]);
414 c
= unbase32hexchar(x
[2]);
418 d
= unbase32hexchar(x
[3]);
422 e
= unbase32hexchar(x
[4]);
430 *(z
++) = (uint8_t) a
<< 3 | (uint8_t) b
>> 2; /* XXXXXYYY */
431 *(z
++) = (uint8_t) b
<< 6 | (uint8_t) c
<< 1 | (uint8_t) d
>> 4; /* YYZZZZZW */
432 *(z
++) = (uint8_t) d
<< 4 | (uint8_t) e
>> 1; /* WWWWSSSS */
436 a
= unbase32hexchar(x
[0]);
440 b
= unbase32hexchar(x
[1]);
444 c
= unbase32hexchar(x
[2]);
448 d
= unbase32hexchar(x
[3]);
456 *(z
++) = (uint8_t) a
<< 3 | (uint8_t) b
>> 2; /* XXXXXYYY */
457 *(z
++) = (uint8_t) b
<< 6 | (uint8_t) c
<< 1 | (uint8_t) d
>> 4; /* YYZZZZZW */
461 a
= unbase32hexchar(x
[0]);
465 b
= unbase32hexchar(x
[1]);
473 *(z
++) = (uint8_t) a
<< 3 | (uint8_t) b
>> 2; /* XXXXXYYY */
490 /* https://tools.ietf.org/html/rfc4648#section-4 */
491 char base64char(int x
) {
492 static const char table
[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
493 "abcdefghijklmnopqrstuvwxyz"
495 return table
[x
& 63];
498 int unbase64char(char c
) {
501 if (c
>= 'A' && c
<= 'Z')
504 offset
= 'Z' - 'A' + 1;
506 if (c
>= 'a' && c
<= 'z')
507 return c
- 'a' + offset
;
509 offset
+= 'z' - 'a' + 1;
511 if (c
>= '0' && c
<= '9')
512 return c
- '0' + offset
;
514 offset
+= '9' - '0' + 1;
527 ssize_t
base64mem(const void *p
, size_t l
, char **out
) {
534 /* three input bytes makes four output bytes, padding is added so we must round up */
535 z
= r
= malloc(4 * (l
+ 2) / 3 + 1);
539 for (x
= p
; x
< (const uint8_t*) p
+ (l
/ 3) * 3; x
+= 3) {
540 /* x[0] == XXXXXXXX; x[1] == YYYYYYYY; x[2] == ZZZZZZZZ */
541 *(z
++) = base64char(x
[0] >> 2); /* 00XXXXXX */
542 *(z
++) = base64char((x
[0] & 3) << 4 | x
[1] >> 4); /* 00XXYYYY */
543 *(z
++) = base64char((x
[1] & 15) << 2 | x
[2] >> 6); /* 00YYYYZZ */
544 *(z
++) = base64char(x
[2] & 63); /* 00ZZZZZZ */
549 *(z
++) = base64char(x
[0] >> 2); /* 00XXXXXX */
550 *(z
++) = base64char((x
[0] & 3) << 4 | x
[1] >> 4); /* 00XXYYYY */
551 *(z
++) = base64char((x
[1] & 15) << 2); /* 00YYYY00 */
556 *(z
++) = base64char(x
[0] >> 2); /* 00XXXXXX */
557 *(z
++) = base64char((x
[0] & 3) << 4); /* 00XX0000 */
569 static int base64_append_width(
570 char **prefix
, int plen
,
571 const char *sep
, int indent
,
572 const void *p
, size_t l
,
575 _cleanup_free_
char *x
= NULL
;
577 ssize_t slen
, len
, avail
;
580 len
= base64mem(p
, l
, &x
);
584 lines
= DIV_ROUND_UP(len
, width
);
586 slen
= strlen_ptr(sep
);
587 t
= realloc(*prefix
, plen
+ 1 + slen
+ (indent
+ width
+ 1) * lines
);
591 memcpy_safe(t
+ plen
, sep
, slen
);
593 for (line
= 0, s
= t
+ plen
+ slen
, avail
= len
; line
< lines
; line
++) {
594 int act
= MIN(width
, avail
);
596 if (line
> 0 || sep
) {
597 memset(s
, ' ', indent
);
601 memcpy(s
, x
+ width
* line
, act
);
603 *(s
++) = line
< lines
- 1 ? '\n' : '\0';
613 char **prefix
, int plen
,
614 const void *p
, size_t l
,
615 int indent
, int width
) {
617 if (plen
> width
/ 2 || plen
+ indent
> width
)
618 /* leave indent on the left, keep last column free */
619 return base64_append_width(prefix
, plen
, "\n", indent
, p
, l
, width
- indent
- 1);
621 /* leave plen on the left, keep last column free */
622 return base64_append_width(prefix
, plen
, NULL
, plen
, p
, l
, width
- plen
- 1);
625 static int unbase64_next(const char **p
, size_t *l
) {
631 /* Find the next non-whitespace character, and decode it. If we find padding, we return it as INT_MAX. We
632 * greedily skip all preceeding and all following whitespace. */
638 if (!strchr(WHITESPACE
, **p
))
641 /* Skip leading whitespace */
646 ret
= INT_MAX
; /* return padding as INT_MAX */
648 ret
= unbase64char(**p
);
658 if (!strchr(WHITESPACE
, **p
))
661 /* Skip following whitespace */
667 int unbase64mem(const char *p
, size_t l
, void **ret
, size_t *ret_size
) {
668 _cleanup_free_
uint8_t *buf
= NULL
;
677 if (l
== (size_t) -1)
680 /* A group of four input bytes needs three output bytes, in case of padding we need to add two or three extra
681 bytes. Note that this calculation is an upper boundary, as we ignore whitespace while decoding */
682 len
= (l
/ 4) * 3 + (l
% 4 != 0 ? (l
% 4) - 1 : 0);
684 buf
= malloc(len
+ 1);
688 for (x
= p
, z
= buf
;;) {
689 int a
, b
, c
, d
; /* a == 00XXXXXX; b == 00YYYYYY; c == 00ZZZZZZ; d == 00WWWWWW */
691 a
= unbase64_next(&x
, &l
);
692 if (a
== -EPIPE
) /* End of string */
696 if (a
== INT_MAX
) /* Padding is not allowed at the beginning of a 4ch block */
699 b
= unbase64_next(&x
, &l
);
702 if (b
== INT_MAX
) /* Padding is not allowed at the second character of a 4ch block either */
705 c
= unbase64_next(&x
, &l
);
709 d
= unbase64_next(&x
, &l
);
713 if (c
== INT_MAX
) { /* Padding at the third character */
715 if (d
!= INT_MAX
) /* If the third character is padding, the fourth must be too */
722 if (l
> 0) /* Trailing rubbish? */
723 return -ENAMETOOLONG
;
725 *(z
++) = (uint8_t) a
<< 2 | (uint8_t) (b
>> 4); /* XXXXXXYY */
734 if (l
> 0) /* Trailing rubbish? */
735 return -ENAMETOOLONG
;
737 *(z
++) = (uint8_t) a
<< 2 | (uint8_t) b
>> 4; /* XXXXXXYY */
738 *(z
++) = (uint8_t) b
<< 4 | (uint8_t) c
>> 2; /* YYYYZZZZ */
742 *(z
++) = (uint8_t) a
<< 2 | (uint8_t) b
>> 4; /* XXXXXXYY */
743 *(z
++) = (uint8_t) b
<< 4 | (uint8_t) c
>> 2; /* YYYYZZZZ */
744 *(z
++) = (uint8_t) c
<< 6 | (uint8_t) d
; /* ZZWWWWWW */
750 *ret_size
= (size_t) (z
- buf
);
752 *ret
= TAKE_PTR(buf
);
757 void hexdump(FILE *f
, const void *p
, size_t s
) {
758 const uint8_t *b
= p
;
769 fprintf(f
, "%04x ", n
);
771 for (i
= 0; i
< 16; i
++) {
776 fprintf(f
, "%02x ", b
[i
]);
784 for (i
= 0; i
< 16; i
++) {
789 fputc(isprint(b
[i
]) ? (char) b
[i
] : '.', f
);