]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/basic/hexdecoct.c
network: fix typo in log message
[thirdparty/systemd.git] / src / basic / hexdecoct.c
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
e4e73a63
LP
2/***
3 This file is part of systemd.
4
5 Copyright 2010 Lennart Poettering
6
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.
11
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.
16
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/>.
19***/
20
21#include <ctype.h>
11c3a366
TA
22#include <errno.h>
23#include <stdint.h>
24#include <stdlib.h>
e4e73a63 25
b5efdb8a 26#include "alloc-util.h"
e4e73a63 27#include "hexdecoct.h"
11c3a366 28#include "macro.h"
7bf7ce28 29#include "string-util.h"
75f32f04 30#include "util.h"
e4e73a63
LP
31
32char octchar(int x) {
33 return '0' + (x & 7);
34}
35
36int unoctchar(char c) {
37
38 if (c >= '0' && c <= '7')
39 return c - '0';
40
41 return -EINVAL;
42}
43
44char decchar(int x) {
45 return '0' + (x % 10);
46}
47
48int undecchar(char c) {
49
50 if (c >= '0' && c <= '9')
51 return c - '0';
52
53 return -EINVAL;
54}
55
56char hexchar(int x) {
57 static const char table[16] = "0123456789abcdef";
58
59 return table[x & 15];
60}
61
62int unhexchar(char c) {
63
64 if (c >= '0' && c <= '9')
65 return c - '0';
66
67 if (c >= 'a' && c <= 'f')
68 return c - 'a' + 10;
69
70 if (c >= 'A' && c <= 'F')
71 return c - 'A' + 10;
72
73 return -EINVAL;
74}
75
76char *hexmem(const void *p, size_t l) {
e4e73a63 77 const uint8_t *x;
9ff233dc 78 char *r, *z;
e4e73a63 79
9ff233dc 80 z = r = new(char, l * 2 + 1);
e4e73a63
LP
81 if (!r)
82 return NULL;
83
84 for (x = p; x < (const uint8_t*) p + l; x++) {
85 *(z++) = hexchar(*x >> 4);
86 *(z++) = hexchar(*x & 15);
87 }
88
89 *z = 0;
90 return r;
91}
92
93int unhexmem(const char *p, size_t l, void **mem, size_t *len) {
94 _cleanup_free_ uint8_t *r = NULL;
95 uint8_t *z;
96 const char *x;
97
98 assert(mem);
99 assert(len);
ae6e414a
LP
100 assert(p || l == 0);
101
102 if (l == (size_t) -1)
103 l = strlen(p);
e4e73a63 104
a93c4776
LP
105 if (l % 2 != 0)
106 return -EINVAL;
107
e4e73a63
LP
108 z = r = malloc((l + 1) / 2 + 1);
109 if (!r)
110 return -ENOMEM;
111
112 for (x = p; x < p + l; x += 2) {
113 int a, b;
114
115 a = unhexchar(x[0]);
116 if (a < 0)
117 return a;
a93c4776
LP
118
119 b = unhexchar(x[1]);
120 if (b < 0)
121 return b;
e4e73a63
LP
122
123 *(z++) = (uint8_t) a << 4 | (uint8_t) b;
124 }
125
126 *z = 0;
127
128 *mem = r;
129 r = NULL;
130 *len = (l + 1) / 2;
131
132 return 0;
133}
134
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. */
141char base32hexchar(int x) {
142 static const char table[32] = "0123456789"
143 "ABCDEFGHIJKLMNOPQRSTUV";
144
145 return table[x & 31];
146}
147
148int unbase32hexchar(char c) {
149 unsigned offset;
150
151 if (c >= '0' && c <= '9')
152 return c - '0';
153
154 offset = '9' - '0' + 1;
155
156 if (c >= 'A' && c <= 'V')
157 return c - 'A' + offset;
158
159 return -EINVAL;
160}
161
162char *base32hexmem(const void *p, size_t l, bool padding) {
163 char *r, *z;
164 const uint8_t *x;
165 size_t len;
166
ae6e414a
LP
167 assert(p || l == 0);
168
e4e73a63
LP
169 if (padding)
170 /* five input bytes makes eight output bytes, padding is added so we must round up */
171 len = 8 * (l + 4) / 5;
172 else {
173 /* same, but round down as there is no padding */
174 len = 8 * l / 5;
175
176 switch (l % 5) {
177 case 4:
178 len += 7;
179 break;
180 case 3:
181 len += 5;
182 break;
183 case 2:
184 len += 4;
185 break;
186 case 1:
187 len += 2;
188 break;
189 }
190 }
191
192 z = r = malloc(len + 1);
193 if (!r)
194 return NULL;
195
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 */
207 }
208
209 switch (l % 5) {
210 case 4:
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 */
218 if (padding)
219 *(z++) = '=';
220
221 break;
222
223 case 3:
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 */
229 if (padding) {
230 *(z++) = '=';
231 *(z++) = '=';
232 *(z++) = '=';
233 }
234
235 break;
236
237 case 2:
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 */
242 if (padding) {
243 *(z++) = '=';
244 *(z++) = '=';
245 *(z++) = '=';
246 *(z++) = '=';
247 }
248
249 break;
250
251 case 1:
252 *(z++) = base32hexchar(x[0] >> 3); /* 000XXXXX */
253 *(z++) = base32hexchar((x[0] & 7) << 2); /* 000XXX00 */
254 if (padding) {
255 *(z++) = '=';
256 *(z++) = '=';
257 *(z++) = '=';
258 *(z++) = '=';
259 *(z++) = '=';
260 *(z++) = '=';
261 }
262
263 break;
264 }
265
266 *z = 0;
267 return r;
268}
269
270int 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;
273 uint8_t *z;
274 const char *x;
275 size_t len;
276 unsigned pad = 0;
277
ae6e414a
LP
278 assert(p || l == 0);
279 assert(mem);
280 assert(_len);
281
282 if (l == (size_t) -1)
283 l = strlen(p);
e4e73a63
LP
284
285 /* padding ensures any base32hex input has input divisible by 8 */
286 if (padding && l % 8 != 0)
287 return -EINVAL;
288
289 if (padding) {
290 /* strip the padding */
291 while (l > 0 && p[l - 1] == '=' && pad < 7) {
313cefa1
VC
292 pad++;
293 l--;
e4e73a63
LP
294 }
295 }
296
297 /* a group of eight input bytes needs five output bytes, in case of
298 padding we need to add some extra bytes */
299 len = (l / 8) * 5;
300
301 switch (l % 8) {
302 case 7:
303 len += 4;
304 break;
305 case 5:
306 len += 3;
307 break;
308 case 4:
309 len += 2;
310 break;
311 case 2:
312 len += 1;
313 break;
314 case 0:
315 break;
316 default:
317 return -EINVAL;
318 }
319
320 z = r = malloc(len + 1);
321 if (!r)
322 return -ENOMEM;
323
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]);
328 if (a < 0)
329 return -EINVAL;
330
331 b = unbase32hexchar(x[1]);
332 if (b < 0)
333 return -EINVAL;
334
335 c = unbase32hexchar(x[2]);
336 if (c < 0)
337 return -EINVAL;
338
339 d = unbase32hexchar(x[3]);
340 if (d < 0)
341 return -EINVAL;
342
343 e = unbase32hexchar(x[4]);
344 if (e < 0)
345 return -EINVAL;
346
347 f = unbase32hexchar(x[5]);
348 if (f < 0)
349 return -EINVAL;
350
351 g = unbase32hexchar(x[6]);
352 if (g < 0)
353 return -EINVAL;
354
355 h = unbase32hexchar(x[7]);
356 if (h < 0)
357 return -EINVAL;
358
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 */
364 }
365
366 switch (l % 8) {
367 case 7:
368 a = unbase32hexchar(x[0]);
369 if (a < 0)
370 return -EINVAL;
371
372 b = unbase32hexchar(x[1]);
373 if (b < 0)
374 return -EINVAL;
375
376 c = unbase32hexchar(x[2]);
377 if (c < 0)
378 return -EINVAL;
379
380 d = unbase32hexchar(x[3]);
381 if (d < 0)
382 return -EINVAL;
383
384 e = unbase32hexchar(x[4]);
385 if (e < 0)
386 return -EINVAL;
387
388 f = unbase32hexchar(x[5]);
389 if (f < 0)
390 return -EINVAL;
391
392 g = unbase32hexchar(x[6]);
393 if (g < 0)
394 return -EINVAL;
395
396 /* g == 000VV000 */
397 if (g & 7)
398 return -EINVAL;
399
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 */
404
405 break;
406 case 5:
407 a = unbase32hexchar(x[0]);
408 if (a < 0)
409 return -EINVAL;
410
411 b = unbase32hexchar(x[1]);
412 if (b < 0)
413 return -EINVAL;
414
415 c = unbase32hexchar(x[2]);
416 if (c < 0)
417 return -EINVAL;
418
419 d = unbase32hexchar(x[3]);
420 if (d < 0)
421 return -EINVAL;
422
423 e = unbase32hexchar(x[4]);
424 if (e < 0)
425 return -EINVAL;
426
427 /* e == 000SSSS0 */
428 if (e & 1)
429 return -EINVAL;
430
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 */
434
435 break;
436 case 4:
437 a = unbase32hexchar(x[0]);
438 if (a < 0)
439 return -EINVAL;
440
441 b = unbase32hexchar(x[1]);
442 if (b < 0)
443 return -EINVAL;
444
445 c = unbase32hexchar(x[2]);
446 if (c < 0)
447 return -EINVAL;
448
449 d = unbase32hexchar(x[3]);
450 if (d < 0)
451 return -EINVAL;
452
453 /* d == 000W0000 */
454 if (d & 15)
455 return -EINVAL;
456
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 */
459
460 break;
461 case 2:
462 a = unbase32hexchar(x[0]);
463 if (a < 0)
464 return -EINVAL;
465
466 b = unbase32hexchar(x[1]);
467 if (b < 0)
468 return -EINVAL;
469
470 /* b == 000YYY00 */
471 if (b & 3)
472 return -EINVAL;
473
474 *(z++) = (uint8_t) a << 3 | (uint8_t) b >> 2; /* XXXXXYYY */
475
476 break;
477 case 0:
478 break;
479 default:
480 return -EINVAL;
481 }
482
483 *z = 0;
484
485 *mem = r;
486 r = NULL;
487 *_len = len;
488
489 return 0;
490}
491
492/* https://tools.ietf.org/html/rfc4648#section-4 */
493char base64char(int x) {
494 static const char table[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
495 "abcdefghijklmnopqrstuvwxyz"
496 "0123456789+/";
497 return table[x & 63];
498}
499
500int unbase64char(char c) {
501 unsigned offset;
502
503 if (c >= 'A' && c <= 'Z')
504 return c - 'A';
505
506 offset = 'Z' - 'A' + 1;
507
508 if (c >= 'a' && c <= 'z')
509 return c - 'a' + offset;
510
511 offset += 'z' - 'a' + 1;
512
513 if (c >= '0' && c <= '9')
514 return c - '0' + offset;
515
516 offset += '9' - '0' + 1;
517
518 if (c == '+')
519 return offset;
520
313cefa1 521 offset++;
e4e73a63
LP
522
523 if (c == '/')
524 return offset;
525
526 return -EINVAL;
527}
528
d7671a3e 529ssize_t base64mem(const void *p, size_t l, char **out) {
e4e73a63
LP
530 char *r, *z;
531 const uint8_t *x;
532
ae6e414a
LP
533 assert(p || l == 0);
534 assert(out);
535
e4e73a63
LP
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);
538 if (!r)
d7671a3e 539 return -ENOMEM;
e4e73a63
LP
540
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 */
547 }
548
549 switch (l % 3) {
550 case 2:
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 */
554 *(z++) = '=';
555
556 break;
557 case 1:
558 *(z++) = base64char(x[0] >> 2); /* 00XXXXXX */
559 *(z++) = base64char((x[0] & 3) << 4); /* 00XX0000 */
560 *(z++) = '=';
561 *(z++) = '=';
562
563 break;
564 }
565
566 *z = 0;
d7671a3e
ZJS
567 *out = r;
568 return z - r;
569}
570
ae6e414a
LP
571static int base64_append_width(
572 char **prefix, int plen,
573 const char *sep, int indent,
574 const void *p, size_t l,
575 int width) {
d7671a3e
ZJS
576
577 _cleanup_free_ char *x = NULL;
578 char *t, *s;
579 ssize_t slen, len, avail;
580 int line, lines;
581
582 len = base64mem(p, l, &x);
583 if (len <= 0)
584 return len;
585
be6b0c21 586 lines = DIV_ROUND_UP(len, width);
d7671a3e 587
7bf7ce28 588 slen = strlen_ptr(sep);
d7671a3e
ZJS
589 t = realloc(*prefix, plen + 1 + slen + (indent + width + 1) * lines);
590 if (!t)
591 return -ENOMEM;
592
75f32f04 593 memcpy_safe(t + plen, sep, slen);
d7671a3e
ZJS
594
595 for (line = 0, s = t + plen + slen, avail = len; line < lines; line++) {
596 int act = MIN(width, avail);
597
598 if (line > 0 || sep) {
599 memset(s, ' ', indent);
600 s += indent;
601 }
602
603 memcpy(s, x + width * line, act);
604 s += act;
605 *(s++) = line < lines - 1 ? '\n' : '\0';
606 avail -= act;
607 }
608 assert(avail == 0);
609
610 *prefix = t;
611 return 0;
e4e73a63
LP
612}
613
ae6e414a
LP
614int base64_append(
615 char **prefix, int plen,
616 const void *p, size_t l,
617 int indent, int width) {
618
d7671a3e
ZJS
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);
622 else
623 /* leave plen on the left, keep last column free */
624 return base64_append_width(prefix, plen, NULL, plen, p, l, width - plen - 1);
ae6e414a 625}
d7671a3e 626
081f36d8
LP
627static int unbase64_next(const char **p, size_t *l) {
628 int ret;
629
630 assert(p);
631 assert(l);
632
633 /* Find the next non-whitespace character, and decode it. If we find padding, we return it as INT_MAX. We
634 * greedily skip all preceeding and all following whitespace. */
635
636 for (;;) {
637 if (*l == 0)
638 return -EPIPE;
639
640 if (!strchr(WHITESPACE, **p))
641 break;
642
643 /* Skip leading whitespace */
644 (*p)++, (*l)--;
645 }
646
647 if (**p == '=')
648 ret = INT_MAX; /* return padding as INT_MAX */
649 else {
650 ret = unbase64char(**p);
651 if (ret < 0)
652 return ret;
653 }
654
655 for (;;) {
656 (*p)++, (*l)--;
657
658 if (*l == 0)
659 break;
660 if (!strchr(WHITESPACE, **p))
661 break;
662
663 /* Skip following whitespace */
664 }
665
666 return ret;
667}
668
669int unbase64mem(const char *p, size_t l, void **ret, size_t *ret_size) {
670 _cleanup_free_ uint8_t *buf = NULL;
e4e73a63 671 const char *x;
081f36d8 672 uint8_t *z;
e4e73a63
LP
673 size_t len;
674
ae6e414a 675 assert(p || l == 0);
081f36d8
LP
676 assert(ret);
677 assert(ret_size);
ae6e414a
LP
678
679 if (l == (size_t) -1)
680 l = strlen(p);
e4e73a63 681
081f36d8
LP
682 /* A group of four input bytes needs three output bytes, in case of padding we need to add two or three extra
683 bytes. Note that this calculation is an upper boundary, as we ignore whitespace while decoding */
684 len = (l / 4) * 3 + (l % 4 != 0 ? (l % 4) - 1 : 0);
e4e73a63 685
081f36d8
LP
686 buf = malloc(len + 1);
687 if (!buf)
e4e73a63
LP
688 return -ENOMEM;
689
081f36d8
LP
690 for (x = p, z = buf;;) {
691 int a, b, c, d; /* a == 00XXXXXX; b == 00YYYYYY; c == 00ZZZZZZ; d == 00WWWWWW */
692
693 a = unbase64_next(&x, &l);
694 if (a == -EPIPE) /* End of string */
695 break;
e4e73a63 696 if (a < 0)
081f36d8 697 return a;
0eb89fe6 698 if (a == INT_MAX) /* Padding is not allowed at the beginning of a 4ch block */
e4e73a63
LP
699 return -EINVAL;
700
081f36d8 701 b = unbase64_next(&x, &l);
e4e73a63 702 if (b < 0)
081f36d8
LP
703 return b;
704 if (b == INT_MAX) /* Padding is not allowed at the second character of a 4ch block either */
e4e73a63
LP
705 return -EINVAL;
706
081f36d8 707 c = unbase64_next(&x, &l);
e4e73a63 708 if (c < 0)
081f36d8 709 return c;
e4e73a63 710
081f36d8 711 d = unbase64_next(&x, &l);
e4e73a63 712 if (d < 0)
081f36d8 713 return d;
ae6e414a 714
081f36d8 715 if (c == INT_MAX) { /* Padding at the third character */
e4e73a63 716
081f36d8
LP
717 if (d != INT_MAX) /* If the third character is padding, the fourth must be too */
718 return -EINVAL;
e4e73a63 719
081f36d8
LP
720 /* b == 00YY0000 */
721 if (b & 15)
722 return -EINVAL;
e4e73a63 723
081f36d8
LP
724 if (l > 0) /* Trailing rubbish? */
725 return -ENAMETOOLONG;
e4e73a63 726
081f36d8
LP
727 *(z++) = (uint8_t) a << 2 | (uint8_t) (b >> 4); /* XXXXXXYY */
728 break;
729 }
e4e73a63 730
081f36d8
LP
731 if (d == INT_MAX) {
732 /* c == 00ZZZZ00 */
733 if (c & 3)
734 return -EINVAL;
e4e73a63 735
081f36d8
LP
736 if (l > 0) /* Trailing rubbish? */
737 return -ENAMETOOLONG;
e4e73a63 738
081f36d8
LP
739 *(z++) = (uint8_t) a << 2 | (uint8_t) b >> 4; /* XXXXXXYY */
740 *(z++) = (uint8_t) b << 4 | (uint8_t) c >> 2; /* YYYYZZZZ */
741 break;
742 }
e4e73a63 743
081f36d8
LP
744 *(z++) = (uint8_t) a << 2 | (uint8_t) b >> 4; /* XXXXXXYY */
745 *(z++) = (uint8_t) b << 4 | (uint8_t) c >> 2; /* YYYYZZZZ */
746 *(z++) = (uint8_t) c << 6 | (uint8_t) d; /* ZZWWWWWW */
e4e73a63
LP
747 }
748
749 *z = 0;
750
081f36d8
LP
751 if (ret_size)
752 *ret_size = (size_t) (z - buf);
753
754 *ret = buf;
755 buf = NULL;
e4e73a63
LP
756
757 return 0;
758}
759
760void hexdump(FILE *f, const void *p, size_t s) {
761 const uint8_t *b = p;
762 unsigned n = 0;
763
a3ab8f2a
LP
764 assert(b || s == 0);
765
766 if (!f)
767 f = stdout;
e4e73a63
LP
768
769 while (s > 0) {
770 size_t i;
771
772 fprintf(f, "%04x ", n);
773
774 for (i = 0; i < 16; i++) {
775
776 if (i >= s)
777 fputs(" ", f);
778 else
779 fprintf(f, "%02x ", b[i]);
780
781 if (i == 7)
782 fputc(' ', f);
783 }
784
785 fputc(' ', f);
786
787 for (i = 0; i < 16; i++) {
788
789 if (i >= s)
790 fputc(' ', f);
791 else
792 fputc(isprint(b[i]) ? (char) b[i] : '.', f);
793 }
794
795 fputc('\n', f);
796
797 if (s < 16)
798 break;
799
800 n += 16;
801 b += 16;
802 s -= 16;
803 }
804}