]>
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
;
135 /* https://tools.ietf.org/html/rfc4648#section-6
136 * Notice that base32hex differs from base32 in the alphabet it uses.
137 * The distinction is that the base32hex representation preserves the
138 * order of the underlying data when compared as bytestrings, this is
139 * useful when representing NSEC3 hashes, as one can then verify the
140 * order of hashes directly from their representation. */
141 char base32hexchar(int x
) {
142 static const char table
[32] = "0123456789"
143 "ABCDEFGHIJKLMNOPQRSTUV";
145 return table
[x
& 31];
148 int unbase32hexchar(char c
) {
151 if (c
>= '0' && c
<= '9')
154 offset
= '9' - '0' + 1;
156 if (c
>= 'A' && c
<= 'V')
157 return c
- 'A' + offset
;
162 char *base32hexmem(const void *p
, size_t l
, bool padding
) {
170 /* five input bytes makes eight output bytes, padding is added so we must round up */
171 len
= 8 * (l
+ 4) / 5;
173 /* same, but round down as there is no padding */
192 z
= r
= malloc(len
+ 1);
196 for (x
= p
; x
< (const uint8_t*) p
+ (l
/ 5) * 5; x
+= 5) {
197 /* x[0] == XXXXXXXX; x[1] == YYYYYYYY; x[2] == ZZZZZZZZ
198 x[3] == QQQQQQQQ; x[4] == WWWWWWWW */
199 *(z
++) = base32hexchar(x
[0] >> 3); /* 000XXXXX */
200 *(z
++) = base32hexchar((x
[0] & 7) << 2 | x
[1] >> 6); /* 000XXXYY */
201 *(z
++) = base32hexchar((x
[1] & 63) >> 1); /* 000YYYYY */
202 *(z
++) = base32hexchar((x
[1] & 1) << 4 | x
[2] >> 4); /* 000YZZZZ */
203 *(z
++) = base32hexchar((x
[2] & 15) << 1 | x
[3] >> 7); /* 000ZZZZQ */
204 *(z
++) = base32hexchar((x
[3] & 127) >> 2); /* 000QQQQQ */
205 *(z
++) = base32hexchar((x
[3] & 3) << 3 | x
[4] >> 5); /* 000QQWWW */
206 *(z
++) = base32hexchar((x
[4] & 31)); /* 000WWWWW */
211 *(z
++) = base32hexchar(x
[0] >> 3); /* 000XXXXX */
212 *(z
++) = base32hexchar((x
[0] & 7) << 2 | x
[1] >> 6); /* 000XXXYY */
213 *(z
++) = base32hexchar((x
[1] & 63) >> 1); /* 000YYYYY */
214 *(z
++) = base32hexchar((x
[1] & 1) << 4 | x
[2] >> 4); /* 000YZZZZ */
215 *(z
++) = base32hexchar((x
[2] & 15) << 1 | x
[3] >> 7); /* 000ZZZZQ */
216 *(z
++) = base32hexchar((x
[3] & 127) >> 2); /* 000QQQQQ */
217 *(z
++) = base32hexchar((x
[3] & 3) << 3); /* 000QQ000 */
224 *(z
++) = base32hexchar(x
[0] >> 3); /* 000XXXXX */
225 *(z
++) = base32hexchar((x
[0] & 7) << 2 | x
[1] >> 6); /* 000XXXYY */
226 *(z
++) = base32hexchar((x
[1] & 63) >> 1); /* 000YYYYY */
227 *(z
++) = base32hexchar((x
[1] & 1) << 4 | x
[2] >> 4); /* 000YZZZZ */
228 *(z
++) = base32hexchar((x
[2] & 15) << 1); /* 000ZZZZ0 */
238 *(z
++) = base32hexchar(x
[0] >> 3); /* 000XXXXX */
239 *(z
++) = base32hexchar((x
[0] & 7) << 2 | x
[1] >> 6); /* 000XXXYY */
240 *(z
++) = base32hexchar((x
[1] & 63) >> 1); /* 000YYYYY */
241 *(z
++) = base32hexchar((x
[1] & 1) << 4); /* 000Y0000 */
252 *(z
++) = base32hexchar(x
[0] >> 3); /* 000XXXXX */
253 *(z
++) = base32hexchar((x
[0] & 7) << 2); /* 000XXX00 */
270 int unbase32hexmem(const char *p
, size_t l
, bool padding
, void **mem
, size_t *_len
) {
271 _cleanup_free_
uint8_t *r
= NULL
;
272 int a
, b
, c
, d
, e
, f
, g
, h
;
282 if (l
== (size_t) -1)
285 /* padding ensures any base32hex input has input divisible by 8 */
286 if (padding
&& l
% 8 != 0)
290 /* strip the padding */
291 while (l
> 0 && p
[l
- 1] == '=' && pad
< 7) {
297 /* a group of eight input bytes needs five output bytes, in case of
298 padding we need to add some extra bytes */
320 z
= r
= malloc(len
+ 1);
324 for (x
= p
; x
< p
+ (l
/ 8) * 8; x
+= 8) {
325 /* a == 000XXXXX; b == 000YYYYY; c == 000ZZZZZ; d == 000WWWWW
326 e == 000SSSSS; f == 000QQQQQ; g == 000VVVVV; h == 000RRRRR */
327 a
= unbase32hexchar(x
[0]);
331 b
= unbase32hexchar(x
[1]);
335 c
= unbase32hexchar(x
[2]);
339 d
= unbase32hexchar(x
[3]);
343 e
= unbase32hexchar(x
[4]);
347 f
= unbase32hexchar(x
[5]);
351 g
= unbase32hexchar(x
[6]);
355 h
= unbase32hexchar(x
[7]);
359 *(z
++) = (uint8_t) a
<< 3 | (uint8_t) b
>> 2; /* XXXXXYYY */
360 *(z
++) = (uint8_t) b
<< 6 | (uint8_t) c
<< 1 | (uint8_t) d
>> 4; /* YYZZZZZW */
361 *(z
++) = (uint8_t) d
<< 4 | (uint8_t) e
>> 1; /* WWWWSSSS */
362 *(z
++) = (uint8_t) e
<< 7 | (uint8_t) f
<< 2 | (uint8_t) g
>> 3; /* SQQQQQVV */
363 *(z
++) = (uint8_t) g
<< 5 | (uint8_t) h
; /* VVVRRRRR */
368 a
= unbase32hexchar(x
[0]);
372 b
= unbase32hexchar(x
[1]);
376 c
= unbase32hexchar(x
[2]);
380 d
= unbase32hexchar(x
[3]);
384 e
= unbase32hexchar(x
[4]);
388 f
= unbase32hexchar(x
[5]);
392 g
= unbase32hexchar(x
[6]);
400 *(z
++) = (uint8_t) a
<< 3 | (uint8_t) b
>> 2; /* XXXXXYYY */
401 *(z
++) = (uint8_t) b
<< 6 | (uint8_t) c
<< 1 | (uint8_t) d
>> 4; /* YYZZZZZW */
402 *(z
++) = (uint8_t) d
<< 4 | (uint8_t) e
>> 1; /* WWWWSSSS */
403 *(z
++) = (uint8_t) e
<< 7 | (uint8_t) f
<< 2 | (uint8_t) g
>> 3; /* SQQQQQVV */
407 a
= unbase32hexchar(x
[0]);
411 b
= unbase32hexchar(x
[1]);
415 c
= unbase32hexchar(x
[2]);
419 d
= unbase32hexchar(x
[3]);
423 e
= unbase32hexchar(x
[4]);
431 *(z
++) = (uint8_t) a
<< 3 | (uint8_t) b
>> 2; /* XXXXXYYY */
432 *(z
++) = (uint8_t) b
<< 6 | (uint8_t) c
<< 1 | (uint8_t) d
>> 4; /* YYZZZZZW */
433 *(z
++) = (uint8_t) d
<< 4 | (uint8_t) e
>> 1; /* WWWWSSSS */
437 a
= unbase32hexchar(x
[0]);
441 b
= unbase32hexchar(x
[1]);
445 c
= unbase32hexchar(x
[2]);
449 d
= unbase32hexchar(x
[3]);
457 *(z
++) = (uint8_t) a
<< 3 | (uint8_t) b
>> 2; /* XXXXXYYY */
458 *(z
++) = (uint8_t) b
<< 6 | (uint8_t) c
<< 1 | (uint8_t) d
>> 4; /* YYZZZZZW */
462 a
= unbase32hexchar(x
[0]);
466 b
= unbase32hexchar(x
[1]);
474 *(z
++) = (uint8_t) a
<< 3 | (uint8_t) b
>> 2; /* XXXXXYYY */
492 /* https://tools.ietf.org/html/rfc4648#section-4 */
493 char base64char(int x
) {
494 static const char table
[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
495 "abcdefghijklmnopqrstuvwxyz"
497 return table
[x
& 63];
500 int unbase64char(char c
) {
503 if (c
>= 'A' && c
<= 'Z')
506 offset
= 'Z' - 'A' + 1;
508 if (c
>= 'a' && c
<= 'z')
509 return c
- 'a' + offset
;
511 offset
+= 'z' - 'a' + 1;
513 if (c
>= '0' && c
<= '9')
514 return c
- '0' + offset
;
516 offset
+= '9' - '0' + 1;
529 ssize_t
base64mem(const void *p
, size_t l
, char **out
) {
536 /* three input bytes makes four output bytes, padding is added so we must round up */
537 z
= r
= malloc(4 * (l
+ 2) / 3 + 1);
541 for (x
= p
; x
< (const uint8_t*) p
+ (l
/ 3) * 3; x
+= 3) {
542 /* x[0] == XXXXXXXX; x[1] == YYYYYYYY; x[2] == ZZZZZZZZ */
543 *(z
++) = base64char(x
[0] >> 2); /* 00XXXXXX */
544 *(z
++) = base64char((x
[0] & 3) << 4 | x
[1] >> 4); /* 00XXYYYY */
545 *(z
++) = base64char((x
[1] & 15) << 2 | x
[2] >> 6); /* 00YYYYZZ */
546 *(z
++) = base64char(x
[2] & 63); /* 00ZZZZZZ */
551 *(z
++) = base64char(x
[0] >> 2); /* 00XXXXXX */
552 *(z
++) = base64char((x
[0] & 3) << 4 | x
[1] >> 4); /* 00XXYYYY */
553 *(z
++) = base64char((x
[1] & 15) << 2); /* 00YYYY00 */
558 *(z
++) = base64char(x
[0] >> 2); /* 00XXXXXX */
559 *(z
++) = base64char((x
[0] & 3) << 4); /* 00XX0000 */
571 static int base64_append_width(
572 char **prefix
, int plen
,
573 const char *sep
, int indent
,
574 const void *p
, size_t l
,
577 _cleanup_free_
char *x
= NULL
;
579 ssize_t slen
, len
, avail
;
582 len
= base64mem(p
, l
, &x
);
586 lines
= (len
+ width
- 1) / width
;
588 slen
= strlen_ptr(sep
);
589 t
= realloc(*prefix
, plen
+ 1 + slen
+ (indent
+ width
+ 1) * lines
);
593 memcpy_safe(t
+ plen
, sep
, slen
);
595 for (line
= 0, s
= t
+ plen
+ slen
, avail
= len
; line
< lines
; line
++) {
596 int act
= MIN(width
, avail
);
598 if (line
> 0 || sep
) {
599 memset(s
, ' ', indent
);
603 memcpy(s
, x
+ width
* line
, act
);
605 *(s
++) = line
< lines
- 1 ? '\n' : '\0';
615 char **prefix
, int plen
,
616 const void *p
, size_t l
,
617 int indent
, int width
) {
619 if (plen
> width
/ 2 || plen
+ indent
> width
)
620 /* leave indent on the left, keep last column free */
621 return base64_append_width(prefix
, plen
, "\n", indent
, p
, l
, width
- indent
- 1);
623 /* leave plen on the left, keep last column free */
624 return base64_append_width(prefix
, plen
, NULL
, plen
, p
, l
, width
- plen
- 1);
627 int unbase64mem(const char *p
, size_t l
, void **mem
, size_t *_len
) {
628 _cleanup_free_
uint8_t *r
= NULL
;
638 if (l
== (size_t) -1)
641 /* padding ensures any base63 input has input divisible by 4 */
645 /* strip the padding */
646 if (l
> 0 && p
[l
- 1] == '=')
648 if (l
> 0 && p
[l
- 1] == '=')
651 /* a group of four input bytes needs three output bytes, in case of
652 padding we need to add two or three extra bytes */
653 len
= (l
/ 4) * 3 + (l
% 4 ? (l
% 4) - 1 : 0);
655 z
= r
= malloc(len
+ 1);
659 for (x
= p
; x
< p
+ (l
/ 4) * 4; x
+= 4) {
660 /* a == 00XXXXXX; b == 00YYYYYY; c == 00ZZZZZZ; d == 00WWWWWW */
661 a
= unbase64char(x
[0]);
665 b
= unbase64char(x
[1]);
669 c
= unbase64char(x
[2]);
673 d
= unbase64char(x
[3]);
677 *(z
++) = (uint8_t) a
<< 2 | (uint8_t) b
>> 4; /* XXXXXXYY */
678 *(z
++) = (uint8_t) b
<< 4 | (uint8_t) c
>> 2; /* YYYYZZZZ */
679 *(z
++) = (uint8_t) c
<< 6 | (uint8_t) d
; /* ZZWWWWWW */
685 a
= unbase64char(x
[0]);
689 b
= unbase64char(x
[1]);
693 c
= unbase64char(x
[2]);
701 *(z
++) = (uint8_t) a
<< 2 | (uint8_t) b
>> 4; /* XXXXXXYY */
702 *(z
++) = (uint8_t) b
<< 4 | (uint8_t) c
>> 2; /* YYYYZZZZ */
706 a
= unbase64char(x
[0]);
710 b
= unbase64char(x
[1]);
718 *(z
++) = (uint8_t) a
<< 2 | (uint8_t) (b
>> 4); /* XXXXXXYY */
737 void hexdump(FILE *f
, const void *p
, size_t s
) {
738 const uint8_t *b
= p
;
749 fprintf(f
, "%04x ", n
);
751 for (i
= 0; i
< 16; i
++) {
756 fprintf(f
, "%02x ", b
[i
]);
764 for (i
= 0; i
< 16; i
++) {
769 fputc(isprint(b
[i
]) ? (char) b
[i
] : '.', f
);