]>
git.ipfire.org Git - thirdparty/systemd.git/blob - src/basic/hexdecoct.c
592df53cb56b9cee5e111c31ff0b7ad9092bc92d
2 This file is part of systemd.
4 Copyright 2010 Lennart Poettering
6 systemd is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public License
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
25 #include "alloc-util.h"
26 #include "hexdecoct.h"
33 int unoctchar(char c
) {
35 if (c
>= '0' && c
<= '7')
42 return '0' + (x
% 10);
45 int undecchar(char c
) {
47 if (c
>= '0' && c
<= '9')
54 static const char table
[16] = "0123456789abcdef";
59 int unhexchar(char c
) {
61 if (c
>= '0' && c
<= '9')
64 if (c
>= 'a' && c
<= 'f')
67 if (c
>= 'A' && c
<= 'F')
73 char *hexmem(const void *p
, size_t l
) {
77 z
= r
= malloc(l
* 2 + 1);
81 for (x
= p
; x
< (const uint8_t*) p
+ l
; x
++) {
82 *(z
++) = hexchar(*x
>> 4);
83 *(z
++) = hexchar(*x
& 15);
90 int unhexmem(const char *p
, size_t l
, void **mem
, size_t *len
) {
91 _cleanup_free_
uint8_t *r
= NULL
;
99 z
= r
= malloc((l
+ 1) / 2 + 1);
103 for (x
= p
; x
< p
+ l
; x
+= 2) {
109 else if (x
+1 < p
+ l
) {
116 *(z
++) = (uint8_t) a
<< 4 | (uint8_t) b
;
128 /* https://tools.ietf.org/html/rfc4648#section-6
129 * Notice that base32hex differs from base32 in the alphabet it uses.
130 * The distinction is that the base32hex representation preserves the
131 * order of the underlying data when compared as bytestrings, this is
132 * useful when representing NSEC3 hashes, as one can then verify the
133 * order of hashes directly from their representation. */
134 char base32hexchar(int x
) {
135 static const char table
[32] = "0123456789"
136 "ABCDEFGHIJKLMNOPQRSTUV";
138 return table
[x
& 31];
141 int unbase32hexchar(char c
) {
144 if (c
>= '0' && c
<= '9')
147 offset
= '9' - '0' + 1;
149 if (c
>= 'A' && c
<= 'V')
150 return c
- 'A' + offset
;
155 char *base32hexmem(const void *p
, size_t l
, bool padding
) {
161 /* five input bytes makes eight output bytes, padding is added so we must round up */
162 len
= 8 * (l
+ 4) / 5;
164 /* same, but round down as there is no padding */
183 z
= r
= malloc(len
+ 1);
187 for (x
= p
; x
< (const uint8_t*) p
+ (l
/ 5) * 5; x
+= 5) {
188 /* x[0] == XXXXXXXX; x[1] == YYYYYYYY; x[2] == ZZZZZZZZ
189 x[3] == QQQQQQQQ; x[4] == WWWWWWWW */
190 *(z
++) = base32hexchar(x
[0] >> 3); /* 000XXXXX */
191 *(z
++) = base32hexchar((x
[0] & 7) << 2 | x
[1] >> 6); /* 000XXXYY */
192 *(z
++) = base32hexchar((x
[1] & 63) >> 1); /* 000YYYYY */
193 *(z
++) = base32hexchar((x
[1] & 1) << 4 | x
[2] >> 4); /* 000YZZZZ */
194 *(z
++) = base32hexchar((x
[2] & 15) << 1 | x
[3] >> 7); /* 000ZZZZQ */
195 *(z
++) = base32hexchar((x
[3] & 127) >> 2); /* 000QQQQQ */
196 *(z
++) = base32hexchar((x
[3] & 3) << 3 | x
[4] >> 5); /* 000QQWWW */
197 *(z
++) = base32hexchar((x
[4] & 31)); /* 000WWWWW */
202 *(z
++) = base32hexchar(x
[0] >> 3); /* 000XXXXX */
203 *(z
++) = base32hexchar((x
[0] & 7) << 2 | x
[1] >> 6); /* 000XXXYY */
204 *(z
++) = base32hexchar((x
[1] & 63) >> 1); /* 000YYYYY */
205 *(z
++) = base32hexchar((x
[1] & 1) << 4 | x
[2] >> 4); /* 000YZZZZ */
206 *(z
++) = base32hexchar((x
[2] & 15) << 1 | x
[3] >> 7); /* 000ZZZZQ */
207 *(z
++) = base32hexchar((x
[3] & 127) >> 2); /* 000QQQQQ */
208 *(z
++) = base32hexchar((x
[3] & 3) << 3); /* 000QQ000 */
215 *(z
++) = base32hexchar(x
[0] >> 3); /* 000XXXXX */
216 *(z
++) = base32hexchar((x
[0] & 7) << 2 | x
[1] >> 6); /* 000XXXYY */
217 *(z
++) = base32hexchar((x
[1] & 63) >> 1); /* 000YYYYY */
218 *(z
++) = base32hexchar((x
[1] & 1) << 4 | x
[2] >> 4); /* 000YZZZZ */
219 *(z
++) = base32hexchar((x
[2] & 15) << 1); /* 000ZZZZ0 */
229 *(z
++) = base32hexchar(x
[0] >> 3); /* 000XXXXX */
230 *(z
++) = base32hexchar((x
[0] & 7) << 2 | x
[1] >> 6); /* 000XXXYY */
231 *(z
++) = base32hexchar((x
[1] & 63) >> 1); /* 000YYYYY */
232 *(z
++) = base32hexchar((x
[1] & 1) << 4); /* 000Y0000 */
243 *(z
++) = base32hexchar(x
[0] >> 3); /* 000XXXXX */
244 *(z
++) = base32hexchar((x
[0] & 7) << 2); /* 000XXX00 */
261 int unbase32hexmem(const char *p
, size_t l
, bool padding
, void **mem
, size_t *_len
) {
262 _cleanup_free_
uint8_t *r
= NULL
;
263 int a
, b
, c
, d
, e
, f
, g
, h
;
271 /* padding ensures any base32hex input has input divisible by 8 */
272 if (padding
&& l
% 8 != 0)
276 /* strip the padding */
277 while (l
> 0 && p
[l
- 1] == '=' && pad
< 7) {
283 /* a group of eight input bytes needs five output bytes, in case of
284 padding we need to add some extra bytes */
306 z
= r
= malloc(len
+ 1);
310 for (x
= p
; x
< p
+ (l
/ 8) * 8; x
+= 8) {
311 /* a == 000XXXXX; b == 000YYYYY; c == 000ZZZZZ; d == 000WWWWW
312 e == 000SSSSS; f == 000QQQQQ; g == 000VVVVV; h == 000RRRRR */
313 a
= unbase32hexchar(x
[0]);
317 b
= unbase32hexchar(x
[1]);
321 c
= unbase32hexchar(x
[2]);
325 d
= unbase32hexchar(x
[3]);
329 e
= unbase32hexchar(x
[4]);
333 f
= unbase32hexchar(x
[5]);
337 g
= unbase32hexchar(x
[6]);
341 h
= unbase32hexchar(x
[7]);
345 *(z
++) = (uint8_t) a
<< 3 | (uint8_t) b
>> 2; /* XXXXXYYY */
346 *(z
++) = (uint8_t) b
<< 6 | (uint8_t) c
<< 1 | (uint8_t) d
>> 4; /* YYZZZZZW */
347 *(z
++) = (uint8_t) d
<< 4 | (uint8_t) e
>> 1; /* WWWWSSSS */
348 *(z
++) = (uint8_t) e
<< 7 | (uint8_t) f
<< 2 | (uint8_t) g
>> 3; /* SQQQQQVV */
349 *(z
++) = (uint8_t) g
<< 5 | (uint8_t) h
; /* VVVRRRRR */
354 a
= unbase32hexchar(x
[0]);
358 b
= unbase32hexchar(x
[1]);
362 c
= unbase32hexchar(x
[2]);
366 d
= unbase32hexchar(x
[3]);
370 e
= unbase32hexchar(x
[4]);
374 f
= unbase32hexchar(x
[5]);
378 g
= unbase32hexchar(x
[6]);
386 *(z
++) = (uint8_t) a
<< 3 | (uint8_t) b
>> 2; /* XXXXXYYY */
387 *(z
++) = (uint8_t) b
<< 6 | (uint8_t) c
<< 1 | (uint8_t) d
>> 4; /* YYZZZZZW */
388 *(z
++) = (uint8_t) d
<< 4 | (uint8_t) e
>> 1; /* WWWWSSSS */
389 *(z
++) = (uint8_t) e
<< 7 | (uint8_t) f
<< 2 | (uint8_t) g
>> 3; /* SQQQQQVV */
393 a
= unbase32hexchar(x
[0]);
397 b
= unbase32hexchar(x
[1]);
401 c
= unbase32hexchar(x
[2]);
405 d
= unbase32hexchar(x
[3]);
409 e
= unbase32hexchar(x
[4]);
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 */
423 a
= unbase32hexchar(x
[0]);
427 b
= unbase32hexchar(x
[1]);
431 c
= unbase32hexchar(x
[2]);
435 d
= unbase32hexchar(x
[3]);
443 *(z
++) = (uint8_t) a
<< 3 | (uint8_t) b
>> 2; /* XXXXXYYY */
444 *(z
++) = (uint8_t) b
<< 6 | (uint8_t) c
<< 1 | (uint8_t) d
>> 4; /* YYZZZZZW */
448 a
= unbase32hexchar(x
[0]);
452 b
= unbase32hexchar(x
[1]);
460 *(z
++) = (uint8_t) a
<< 3 | (uint8_t) b
>> 2; /* XXXXXYYY */
478 /* https://tools.ietf.org/html/rfc4648#section-4 */
479 char base64char(int x
) {
480 static const char table
[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
481 "abcdefghijklmnopqrstuvwxyz"
483 return table
[x
& 63];
486 int unbase64char(char c
) {
489 if (c
>= 'A' && c
<= 'Z')
492 offset
= 'Z' - 'A' + 1;
494 if (c
>= 'a' && c
<= 'z')
495 return c
- 'a' + offset
;
497 offset
+= 'z' - 'a' + 1;
499 if (c
>= '0' && c
<= '9')
500 return c
- '0' + offset
;
502 offset
+= '9' - '0' + 1;
515 ssize_t
base64mem(const void *p
, size_t l
, char **out
) {
519 /* three input bytes makes four output bytes, padding is added so we must round up */
520 z
= r
= malloc(4 * (l
+ 2) / 3 + 1);
524 for (x
= p
; x
< (const uint8_t*) p
+ (l
/ 3) * 3; x
+= 3) {
525 /* x[0] == XXXXXXXX; x[1] == YYYYYYYY; x[2] == ZZZZZZZZ */
526 *(z
++) = base64char(x
[0] >> 2); /* 00XXXXXX */
527 *(z
++) = base64char((x
[0] & 3) << 4 | x
[1] >> 4); /* 00XXYYYY */
528 *(z
++) = base64char((x
[1] & 15) << 2 | x
[2] >> 6); /* 00YYYYZZ */
529 *(z
++) = base64char(x
[2] & 63); /* 00ZZZZZZ */
534 *(z
++) = base64char(x
[0] >> 2); /* 00XXXXXX */
535 *(z
++) = base64char((x
[0] & 3) << 4 | x
[1] >> 4); /* 00XXYYYY */
536 *(z
++) = base64char((x
[1] & 15) << 2); /* 00YYYY00 */
541 *(z
++) = base64char(x
[0] >> 2); /* 00XXXXXX */
542 *(z
++) = base64char((x
[0] & 3) << 4); /* 00XX0000 */
554 static int base64_append_width(char **prefix
, int plen
,
555 const char *sep
, int indent
,
556 const void *p
, size_t l
,
559 _cleanup_free_
char *x
= NULL
;
561 ssize_t slen
, len
, avail
;
564 len
= base64mem(p
, l
, &x
);
568 lines
= (len
+ width
- 1) / width
;
570 slen
= sep
? strlen(sep
) : 0;
571 t
= realloc(*prefix
, plen
+ 1 + slen
+ (indent
+ width
+ 1) * lines
);
575 memcpy(t
+ plen
, sep
, slen
);
577 for (line
= 0, s
= t
+ plen
+ slen
, avail
= len
; line
< lines
; line
++) {
578 int act
= MIN(width
, avail
);
580 if (line
> 0 || sep
) {
581 memset(s
, ' ', indent
);
585 memcpy(s
, x
+ width
* line
, act
);
587 *(s
++) = line
< lines
- 1 ? '\n' : '\0';
596 int base64_append(char **prefix
, int plen
,
597 const void *p
, size_t l
,
598 int indent
, int width
) {
599 if (plen
> width
/ 2 || plen
+ indent
> width
)
600 /* leave indent on the left, keep last column free */
601 return base64_append_width(prefix
, plen
, "\n", indent
, p
, l
, width
- indent
- 1);
603 /* leave plen on the left, keep last column free */
604 return base64_append_width(prefix
, plen
, NULL
, plen
, p
, l
, width
- plen
- 1);
608 int unbase64mem(const char *p
, size_t l
, void **mem
, size_t *_len
) {
609 _cleanup_free_
uint8_t *r
= NULL
;
617 /* padding ensures any base63 input has input divisible by 4 */
621 /* strip the padding */
622 if (l
> 0 && p
[l
- 1] == '=')
624 if (l
> 0 && p
[l
- 1] == '=')
627 /* a group of four input bytes needs three output bytes, in case of
628 padding we need to add two or three extra bytes */
629 len
= (l
/ 4) * 3 + (l
% 4 ? (l
% 4) - 1 : 0);
631 z
= r
= malloc(len
+ 1);
635 for (x
= p
; x
< p
+ (l
/ 4) * 4; x
+= 4) {
636 /* a == 00XXXXXX; b == 00YYYYYY; c == 00ZZZZZZ; d == 00WWWWWW */
637 a
= unbase64char(x
[0]);
641 b
= unbase64char(x
[1]);
645 c
= unbase64char(x
[2]);
649 d
= unbase64char(x
[3]);
653 *(z
++) = (uint8_t) a
<< 2 | (uint8_t) b
>> 4; /* XXXXXXYY */
654 *(z
++) = (uint8_t) b
<< 4 | (uint8_t) c
>> 2; /* YYYYZZZZ */
655 *(z
++) = (uint8_t) c
<< 6 | (uint8_t) d
; /* ZZWWWWWW */
660 a
= unbase64char(x
[0]);
664 b
= unbase64char(x
[1]);
668 c
= unbase64char(x
[2]);
676 *(z
++) = (uint8_t) a
<< 2 | (uint8_t) b
>> 4; /* XXXXXXYY */
677 *(z
++) = (uint8_t) b
<< 4 | (uint8_t) c
>> 2; /* YYYYZZZZ */
681 a
= unbase64char(x
[0]);
685 b
= unbase64char(x
[1]);
693 *(z
++) = (uint8_t) a
<< 2 | (uint8_t) (b
>> 4); /* XXXXXXYY */
712 void hexdump(FILE *f
, const void *p
, size_t s
) {
713 const uint8_t *b
= p
;
721 fprintf(f
, "%04x ", n
);
723 for (i
= 0; i
< 16; i
++) {
728 fprintf(f
, "%02x ", b
[i
]);
736 for (i
= 0; i
< 16; i
++) {
741 fputc(isprint(b
[i
]) ? (char) b
[i
] : '.', f
);