]>
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
;
105 z
= r
= malloc((l
+ 1) / 2 + 1);
109 for (x
= p
; x
< p
+ l
; x
+= 2) {
120 *(z
++) = (uint8_t) a
<< 4 | (uint8_t) b
;
132 /* https://tools.ietf.org/html/rfc4648#section-6
133 * Notice that base32hex differs from base32 in the alphabet it uses.
134 * The distinction is that the base32hex representation preserves the
135 * order of the underlying data when compared as bytestrings, this is
136 * useful when representing NSEC3 hashes, as one can then verify the
137 * order of hashes directly from their representation. */
138 char base32hexchar(int x
) {
139 static const char table
[32] = "0123456789"
140 "ABCDEFGHIJKLMNOPQRSTUV";
142 return table
[x
& 31];
145 int unbase32hexchar(char c
) {
148 if (c
>= '0' && c
<= '9')
151 offset
= '9' - '0' + 1;
153 if (c
>= 'A' && c
<= 'V')
154 return c
- 'A' + offset
;
159 char *base32hexmem(const void *p
, size_t l
, bool padding
) {
165 /* five input bytes makes eight output bytes, padding is added so we must round up */
166 len
= 8 * (l
+ 4) / 5;
168 /* same, but round down as there is no padding */
187 z
= r
= malloc(len
+ 1);
191 for (x
= p
; x
< (const uint8_t*) p
+ (l
/ 5) * 5; x
+= 5) {
192 /* x[0] == XXXXXXXX; x[1] == YYYYYYYY; x[2] == ZZZZZZZZ
193 x[3] == QQQQQQQQ; x[4] == WWWWWWWW */
194 *(z
++) = base32hexchar(x
[0] >> 3); /* 000XXXXX */
195 *(z
++) = base32hexchar((x
[0] & 7) << 2 | x
[1] >> 6); /* 000XXXYY */
196 *(z
++) = base32hexchar((x
[1] & 63) >> 1); /* 000YYYYY */
197 *(z
++) = base32hexchar((x
[1] & 1) << 4 | x
[2] >> 4); /* 000YZZZZ */
198 *(z
++) = base32hexchar((x
[2] & 15) << 1 | x
[3] >> 7); /* 000ZZZZQ */
199 *(z
++) = base32hexchar((x
[3] & 127) >> 2); /* 000QQQQQ */
200 *(z
++) = base32hexchar((x
[3] & 3) << 3 | x
[4] >> 5); /* 000QQWWW */
201 *(z
++) = base32hexchar((x
[4] & 31)); /* 000WWWWW */
206 *(z
++) = base32hexchar(x
[0] >> 3); /* 000XXXXX */
207 *(z
++) = base32hexchar((x
[0] & 7) << 2 | x
[1] >> 6); /* 000XXXYY */
208 *(z
++) = base32hexchar((x
[1] & 63) >> 1); /* 000YYYYY */
209 *(z
++) = base32hexchar((x
[1] & 1) << 4 | x
[2] >> 4); /* 000YZZZZ */
210 *(z
++) = base32hexchar((x
[2] & 15) << 1 | x
[3] >> 7); /* 000ZZZZQ */
211 *(z
++) = base32hexchar((x
[3] & 127) >> 2); /* 000QQQQQ */
212 *(z
++) = base32hexchar((x
[3] & 3) << 3); /* 000QQ000 */
219 *(z
++) = base32hexchar(x
[0] >> 3); /* 000XXXXX */
220 *(z
++) = base32hexchar((x
[0] & 7) << 2 | x
[1] >> 6); /* 000XXXYY */
221 *(z
++) = base32hexchar((x
[1] & 63) >> 1); /* 000YYYYY */
222 *(z
++) = base32hexchar((x
[1] & 1) << 4 | x
[2] >> 4); /* 000YZZZZ */
223 *(z
++) = base32hexchar((x
[2] & 15) << 1); /* 000ZZZZ0 */
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); /* 000Y0000 */
247 *(z
++) = base32hexchar(x
[0] >> 3); /* 000XXXXX */
248 *(z
++) = base32hexchar((x
[0] & 7) << 2); /* 000XXX00 */
265 int unbase32hexmem(const char *p
, size_t l
, bool padding
, void **mem
, size_t *_len
) {
266 _cleanup_free_
uint8_t *r
= NULL
;
267 int a
, b
, c
, d
, e
, f
, g
, h
;
275 /* padding ensures any base32hex input has input divisible by 8 */
276 if (padding
&& l
% 8 != 0)
280 /* strip the padding */
281 while (l
> 0 && p
[l
- 1] == '=' && pad
< 7) {
287 /* a group of eight input bytes needs five output bytes, in case of
288 padding we need to add some extra bytes */
310 z
= r
= malloc(len
+ 1);
314 for (x
= p
; x
< p
+ (l
/ 8) * 8; x
+= 8) {
315 /* a == 000XXXXX; b == 000YYYYY; c == 000ZZZZZ; d == 000WWWWW
316 e == 000SSSSS; f == 000QQQQQ; g == 000VVVVV; h == 000RRRRR */
317 a
= unbase32hexchar(x
[0]);
321 b
= unbase32hexchar(x
[1]);
325 c
= unbase32hexchar(x
[2]);
329 d
= unbase32hexchar(x
[3]);
333 e
= unbase32hexchar(x
[4]);
337 f
= unbase32hexchar(x
[5]);
341 g
= unbase32hexchar(x
[6]);
345 h
= unbase32hexchar(x
[7]);
349 *(z
++) = (uint8_t) a
<< 3 | (uint8_t) b
>> 2; /* XXXXXYYY */
350 *(z
++) = (uint8_t) b
<< 6 | (uint8_t) c
<< 1 | (uint8_t) d
>> 4; /* YYZZZZZW */
351 *(z
++) = (uint8_t) d
<< 4 | (uint8_t) e
>> 1; /* WWWWSSSS */
352 *(z
++) = (uint8_t) e
<< 7 | (uint8_t) f
<< 2 | (uint8_t) g
>> 3; /* SQQQQQVV */
353 *(z
++) = (uint8_t) g
<< 5 | (uint8_t) h
; /* VVVRRRRR */
358 a
= unbase32hexchar(x
[0]);
362 b
= unbase32hexchar(x
[1]);
366 c
= unbase32hexchar(x
[2]);
370 d
= unbase32hexchar(x
[3]);
374 e
= unbase32hexchar(x
[4]);
378 f
= unbase32hexchar(x
[5]);
382 g
= unbase32hexchar(x
[6]);
390 *(z
++) = (uint8_t) a
<< 3 | (uint8_t) b
>> 2; /* XXXXXYYY */
391 *(z
++) = (uint8_t) b
<< 6 | (uint8_t) c
<< 1 | (uint8_t) d
>> 4; /* YYZZZZZW */
392 *(z
++) = (uint8_t) d
<< 4 | (uint8_t) e
>> 1; /* WWWWSSSS */
393 *(z
++) = (uint8_t) e
<< 7 | (uint8_t) f
<< 2 | (uint8_t) g
>> 3; /* SQQQQQVV */
397 a
= unbase32hexchar(x
[0]);
401 b
= unbase32hexchar(x
[1]);
405 c
= unbase32hexchar(x
[2]);
409 d
= unbase32hexchar(x
[3]);
413 e
= unbase32hexchar(x
[4]);
421 *(z
++) = (uint8_t) a
<< 3 | (uint8_t) b
>> 2; /* XXXXXYYY */
422 *(z
++) = (uint8_t) b
<< 6 | (uint8_t) c
<< 1 | (uint8_t) d
>> 4; /* YYZZZZZW */
423 *(z
++) = (uint8_t) d
<< 4 | (uint8_t) e
>> 1; /* WWWWSSSS */
427 a
= unbase32hexchar(x
[0]);
431 b
= unbase32hexchar(x
[1]);
435 c
= unbase32hexchar(x
[2]);
439 d
= unbase32hexchar(x
[3]);
447 *(z
++) = (uint8_t) a
<< 3 | (uint8_t) b
>> 2; /* XXXXXYYY */
448 *(z
++) = (uint8_t) b
<< 6 | (uint8_t) c
<< 1 | (uint8_t) d
>> 4; /* YYZZZZZW */
452 a
= unbase32hexchar(x
[0]);
456 b
= unbase32hexchar(x
[1]);
464 *(z
++) = (uint8_t) a
<< 3 | (uint8_t) b
>> 2; /* XXXXXYYY */
482 /* https://tools.ietf.org/html/rfc4648#section-4 */
483 char base64char(int x
) {
484 static const char table
[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
485 "abcdefghijklmnopqrstuvwxyz"
487 return table
[x
& 63];
490 int unbase64char(char c
) {
493 if (c
>= 'A' && c
<= 'Z')
496 offset
= 'Z' - 'A' + 1;
498 if (c
>= 'a' && c
<= 'z')
499 return c
- 'a' + offset
;
501 offset
+= 'z' - 'a' + 1;
503 if (c
>= '0' && c
<= '9')
504 return c
- '0' + offset
;
506 offset
+= '9' - '0' + 1;
519 ssize_t
base64mem(const void *p
, size_t l
, char **out
) {
523 /* three input bytes makes four output bytes, padding is added so we must round up */
524 z
= r
= malloc(4 * (l
+ 2) / 3 + 1);
528 for (x
= p
; x
< (const uint8_t*) p
+ (l
/ 3) * 3; x
+= 3) {
529 /* x[0] == XXXXXXXX; x[1] == YYYYYYYY; x[2] == ZZZZZZZZ */
530 *(z
++) = base64char(x
[0] >> 2); /* 00XXXXXX */
531 *(z
++) = base64char((x
[0] & 3) << 4 | x
[1] >> 4); /* 00XXYYYY */
532 *(z
++) = base64char((x
[1] & 15) << 2 | x
[2] >> 6); /* 00YYYYZZ */
533 *(z
++) = base64char(x
[2] & 63); /* 00ZZZZZZ */
538 *(z
++) = base64char(x
[0] >> 2); /* 00XXXXXX */
539 *(z
++) = base64char((x
[0] & 3) << 4 | x
[1] >> 4); /* 00XXYYYY */
540 *(z
++) = base64char((x
[1] & 15) << 2); /* 00YYYY00 */
545 *(z
++) = base64char(x
[0] >> 2); /* 00XXXXXX */
546 *(z
++) = base64char((x
[0] & 3) << 4); /* 00XX0000 */
558 static int base64_append_width(char **prefix
, int plen
,
559 const char *sep
, int indent
,
560 const void *p
, size_t l
,
563 _cleanup_free_
char *x
= NULL
;
565 ssize_t slen
, len
, avail
;
568 len
= base64mem(p
, l
, &x
);
572 lines
= (len
+ width
- 1) / width
;
574 slen
= strlen_ptr(sep
);
575 t
= realloc(*prefix
, plen
+ 1 + slen
+ (indent
+ width
+ 1) * lines
);
579 memcpy_safe(t
+ plen
, sep
, slen
);
581 for (line
= 0, s
= t
+ plen
+ slen
, avail
= len
; line
< lines
; line
++) {
582 int act
= MIN(width
, avail
);
584 if (line
> 0 || sep
) {
585 memset(s
, ' ', indent
);
589 memcpy(s
, x
+ width
* line
, act
);
591 *(s
++) = line
< lines
- 1 ? '\n' : '\0';
600 int base64_append(char **prefix
, int plen
,
601 const void *p
, size_t l
,
602 int indent
, int width
) {
603 if (plen
> width
/ 2 || plen
+ indent
> width
)
604 /* leave indent on the left, keep last column free */
605 return base64_append_width(prefix
, plen
, "\n", indent
, p
, l
, width
- indent
- 1);
607 /* leave plen on the left, keep last column free */
608 return base64_append_width(prefix
, plen
, NULL
, plen
, p
, l
, width
- plen
- 1);
612 int unbase64mem(const char *p
, size_t l
, void **mem
, size_t *_len
) {
613 _cleanup_free_
uint8_t *r
= NULL
;
621 /* padding ensures any base63 input has input divisible by 4 */
625 /* strip the padding */
626 if (l
> 0 && p
[l
- 1] == '=')
628 if (l
> 0 && p
[l
- 1] == '=')
631 /* a group of four input bytes needs three output bytes, in case of
632 padding we need to add two or three extra bytes */
633 len
= (l
/ 4) * 3 + (l
% 4 ? (l
% 4) - 1 : 0);
635 z
= r
= malloc(len
+ 1);
639 for (x
= p
; x
< p
+ (l
/ 4) * 4; x
+= 4) {
640 /* a == 00XXXXXX; b == 00YYYYYY; c == 00ZZZZZZ; d == 00WWWWWW */
641 a
= unbase64char(x
[0]);
645 b
= unbase64char(x
[1]);
649 c
= unbase64char(x
[2]);
653 d
= unbase64char(x
[3]);
657 *(z
++) = (uint8_t) a
<< 2 | (uint8_t) b
>> 4; /* XXXXXXYY */
658 *(z
++) = (uint8_t) b
<< 4 | (uint8_t) c
>> 2; /* YYYYZZZZ */
659 *(z
++) = (uint8_t) c
<< 6 | (uint8_t) d
; /* ZZWWWWWW */
664 a
= unbase64char(x
[0]);
668 b
= unbase64char(x
[1]);
672 c
= unbase64char(x
[2]);
680 *(z
++) = (uint8_t) a
<< 2 | (uint8_t) b
>> 4; /* XXXXXXYY */
681 *(z
++) = (uint8_t) b
<< 4 | (uint8_t) c
>> 2; /* YYYYZZZZ */
685 a
= unbase64char(x
[0]);
689 b
= unbase64char(x
[1]);
697 *(z
++) = (uint8_t) a
<< 2 | (uint8_t) (b
>> 4); /* XXXXXXYY */
716 void hexdump(FILE *f
, const void *p
, size_t s
) {
717 const uint8_t *b
= p
;
725 fprintf(f
, "%04x ", n
);
727 for (i
= 0; i
< 16; i
++) {
732 fprintf(f
, "%02x ", b
[i
]);
740 for (i
= 0; i
< 16; i
++) {
745 fputc(isprint(b
[i
]) ? (char) b
[i
] : '.', f
);