]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/basic/hexdecoct.c
process-util: slightly optimize querying of our own process metadata
[thirdparty/systemd.git] / src / basic / hexdecoct.c
CommitLineData
e4e73a63
LP
1/***
2 This file is part of systemd.
3
4 Copyright 2010 Lennart Poettering
5
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.
10
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.
15
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/>.
18***/
19
20#include <ctype.h>
11c3a366
TA
21#include <errno.h>
22#include <stdint.h>
23#include <stdlib.h>
e4e73a63 24
b5efdb8a 25#include "alloc-util.h"
e4e73a63 26#include "hexdecoct.h"
11c3a366 27#include "macro.h"
75f32f04 28#include "util.h"
e4e73a63
LP
29
30char octchar(int x) {
31 return '0' + (x & 7);
32}
33
34int unoctchar(char c) {
35
36 if (c >= '0' && c <= '7')
37 return c - '0';
38
39 return -EINVAL;
40}
41
42char decchar(int x) {
43 return '0' + (x % 10);
44}
45
46int undecchar(char c) {
47
48 if (c >= '0' && c <= '9')
49 return c - '0';
50
51 return -EINVAL;
52}
53
54char hexchar(int x) {
55 static const char table[16] = "0123456789abcdef";
56
57 return table[x & 15];
58}
59
60int unhexchar(char c) {
61
62 if (c >= '0' && c <= '9')
63 return c - '0';
64
65 if (c >= 'a' && c <= 'f')
66 return c - 'a' + 10;
67
68 if (c >= 'A' && c <= 'F')
69 return c - 'A' + 10;
70
71 return -EINVAL;
72}
73
74char *hexmem(const void *p, size_t l) {
e4e73a63 75 const uint8_t *x;
9ff233dc 76 char *r, *z;
e4e73a63 77
9ff233dc 78 z = r = new(char, l * 2 + 1);
e4e73a63
LP
79 if (!r)
80 return NULL;
81
82 for (x = p; x < (const uint8_t*) p + l; x++) {
83 *(z++) = hexchar(*x >> 4);
84 *(z++) = hexchar(*x & 15);
85 }
86
87 *z = 0;
88 return r;
89}
90
91int unhexmem(const char *p, size_t l, void **mem, size_t *len) {
92 _cleanup_free_ uint8_t *r = NULL;
93 uint8_t *z;
94 const char *x;
95
96 assert(mem);
97 assert(len);
98 assert(p);
99
a93c4776
LP
100 if (l % 2 != 0)
101 return -EINVAL;
102
e4e73a63
LP
103 z = r = malloc((l + 1) / 2 + 1);
104 if (!r)
105 return -ENOMEM;
106
107 for (x = p; x < p + l; x += 2) {
108 int a, b;
109
110 a = unhexchar(x[0]);
111 if (a < 0)
112 return a;
a93c4776
LP
113
114 b = unhexchar(x[1]);
115 if (b < 0)
116 return b;
e4e73a63
LP
117
118 *(z++) = (uint8_t) a << 4 | (uint8_t) b;
119 }
120
121 *z = 0;
122
123 *mem = r;
124 r = NULL;
125 *len = (l + 1) / 2;
126
127 return 0;
128}
129
130/* https://tools.ietf.org/html/rfc4648#section-6
131 * Notice that base32hex differs from base32 in the alphabet it uses.
132 * The distinction is that the base32hex representation preserves the
133 * order of the underlying data when compared as bytestrings, this is
134 * useful when representing NSEC3 hashes, as one can then verify the
135 * order of hashes directly from their representation. */
136char base32hexchar(int x) {
137 static const char table[32] = "0123456789"
138 "ABCDEFGHIJKLMNOPQRSTUV";
139
140 return table[x & 31];
141}
142
143int unbase32hexchar(char c) {
144 unsigned offset;
145
146 if (c >= '0' && c <= '9')
147 return c - '0';
148
149 offset = '9' - '0' + 1;
150
151 if (c >= 'A' && c <= 'V')
152 return c - 'A' + offset;
153
154 return -EINVAL;
155}
156
157char *base32hexmem(const void *p, size_t l, bool padding) {
158 char *r, *z;
159 const uint8_t *x;
160 size_t len;
161
162 if (padding)
163 /* five input bytes makes eight output bytes, padding is added so we must round up */
164 len = 8 * (l + 4) / 5;
165 else {
166 /* same, but round down as there is no padding */
167 len = 8 * l / 5;
168
169 switch (l % 5) {
170 case 4:
171 len += 7;
172 break;
173 case 3:
174 len += 5;
175 break;
176 case 2:
177 len += 4;
178 break;
179 case 1:
180 len += 2;
181 break;
182 }
183 }
184
185 z = r = malloc(len + 1);
186 if (!r)
187 return NULL;
188
189 for (x = p; x < (const uint8_t*) p + (l / 5) * 5; x += 5) {
190 /* x[0] == XXXXXXXX; x[1] == YYYYYYYY; x[2] == ZZZZZZZZ
191 x[3] == QQQQQQQQ; x[4] == WWWWWWWW */
192 *(z++) = base32hexchar(x[0] >> 3); /* 000XXXXX */
193 *(z++) = base32hexchar((x[0] & 7) << 2 | x[1] >> 6); /* 000XXXYY */
194 *(z++) = base32hexchar((x[1] & 63) >> 1); /* 000YYYYY */
195 *(z++) = base32hexchar((x[1] & 1) << 4 | x[2] >> 4); /* 000YZZZZ */
196 *(z++) = base32hexchar((x[2] & 15) << 1 | x[3] >> 7); /* 000ZZZZQ */
197 *(z++) = base32hexchar((x[3] & 127) >> 2); /* 000QQQQQ */
198 *(z++) = base32hexchar((x[3] & 3) << 3 | x[4] >> 5); /* 000QQWWW */
199 *(z++) = base32hexchar((x[4] & 31)); /* 000WWWWW */
200 }
201
202 switch (l % 5) {
203 case 4:
204 *(z++) = base32hexchar(x[0] >> 3); /* 000XXXXX */
205 *(z++) = base32hexchar((x[0] & 7) << 2 | x[1] >> 6); /* 000XXXYY */
206 *(z++) = base32hexchar((x[1] & 63) >> 1); /* 000YYYYY */
207 *(z++) = base32hexchar((x[1] & 1) << 4 | x[2] >> 4); /* 000YZZZZ */
208 *(z++) = base32hexchar((x[2] & 15) << 1 | x[3] >> 7); /* 000ZZZZQ */
209 *(z++) = base32hexchar((x[3] & 127) >> 2); /* 000QQQQQ */
210 *(z++) = base32hexchar((x[3] & 3) << 3); /* 000QQ000 */
211 if (padding)
212 *(z++) = '=';
213
214 break;
215
216 case 3:
217 *(z++) = base32hexchar(x[0] >> 3); /* 000XXXXX */
218 *(z++) = base32hexchar((x[0] & 7) << 2 | x[1] >> 6); /* 000XXXYY */
219 *(z++) = base32hexchar((x[1] & 63) >> 1); /* 000YYYYY */
220 *(z++) = base32hexchar((x[1] & 1) << 4 | x[2] >> 4); /* 000YZZZZ */
221 *(z++) = base32hexchar((x[2] & 15) << 1); /* 000ZZZZ0 */
222 if (padding) {
223 *(z++) = '=';
224 *(z++) = '=';
225 *(z++) = '=';
226 }
227
228 break;
229
230 case 2:
231 *(z++) = base32hexchar(x[0] >> 3); /* 000XXXXX */
232 *(z++) = base32hexchar((x[0] & 7) << 2 | x[1] >> 6); /* 000XXXYY */
233 *(z++) = base32hexchar((x[1] & 63) >> 1); /* 000YYYYY */
234 *(z++) = base32hexchar((x[1] & 1) << 4); /* 000Y0000 */
235 if (padding) {
236 *(z++) = '=';
237 *(z++) = '=';
238 *(z++) = '=';
239 *(z++) = '=';
240 }
241
242 break;
243
244 case 1:
245 *(z++) = base32hexchar(x[0] >> 3); /* 000XXXXX */
246 *(z++) = base32hexchar((x[0] & 7) << 2); /* 000XXX00 */
247 if (padding) {
248 *(z++) = '=';
249 *(z++) = '=';
250 *(z++) = '=';
251 *(z++) = '=';
252 *(z++) = '=';
253 *(z++) = '=';
254 }
255
256 break;
257 }
258
259 *z = 0;
260 return r;
261}
262
263int unbase32hexmem(const char *p, size_t l, bool padding, void **mem, size_t *_len) {
264 _cleanup_free_ uint8_t *r = NULL;
265 int a, b, c, d, e, f, g, h;
266 uint8_t *z;
267 const char *x;
268 size_t len;
269 unsigned pad = 0;
270
271 assert(p);
272
273 /* padding ensures any base32hex input has input divisible by 8 */
274 if (padding && l % 8 != 0)
275 return -EINVAL;
276
277 if (padding) {
278 /* strip the padding */
279 while (l > 0 && p[l - 1] == '=' && pad < 7) {
313cefa1
VC
280 pad++;
281 l--;
e4e73a63
LP
282 }
283 }
284
285 /* a group of eight input bytes needs five output bytes, in case of
286 padding we need to add some extra bytes */
287 len = (l / 8) * 5;
288
289 switch (l % 8) {
290 case 7:
291 len += 4;
292 break;
293 case 5:
294 len += 3;
295 break;
296 case 4:
297 len += 2;
298 break;
299 case 2:
300 len += 1;
301 break;
302 case 0:
303 break;
304 default:
305 return -EINVAL;
306 }
307
308 z = r = malloc(len + 1);
309 if (!r)
310 return -ENOMEM;
311
312 for (x = p; x < p + (l / 8) * 8; x += 8) {
313 /* a == 000XXXXX; b == 000YYYYY; c == 000ZZZZZ; d == 000WWWWW
314 e == 000SSSSS; f == 000QQQQQ; g == 000VVVVV; h == 000RRRRR */
315 a = unbase32hexchar(x[0]);
316 if (a < 0)
317 return -EINVAL;
318
319 b = unbase32hexchar(x[1]);
320 if (b < 0)
321 return -EINVAL;
322
323 c = unbase32hexchar(x[2]);
324 if (c < 0)
325 return -EINVAL;
326
327 d = unbase32hexchar(x[3]);
328 if (d < 0)
329 return -EINVAL;
330
331 e = unbase32hexchar(x[4]);
332 if (e < 0)
333 return -EINVAL;
334
335 f = unbase32hexchar(x[5]);
336 if (f < 0)
337 return -EINVAL;
338
339 g = unbase32hexchar(x[6]);
340 if (g < 0)
341 return -EINVAL;
342
343 h = unbase32hexchar(x[7]);
344 if (h < 0)
345 return -EINVAL;
346
347 *(z++) = (uint8_t) a << 3 | (uint8_t) b >> 2; /* XXXXXYYY */
348 *(z++) = (uint8_t) b << 6 | (uint8_t) c << 1 | (uint8_t) d >> 4; /* YYZZZZZW */
349 *(z++) = (uint8_t) d << 4 | (uint8_t) e >> 1; /* WWWWSSSS */
350 *(z++) = (uint8_t) e << 7 | (uint8_t) f << 2 | (uint8_t) g >> 3; /* SQQQQQVV */
351 *(z++) = (uint8_t) g << 5 | (uint8_t) h; /* VVVRRRRR */
352 }
353
354 switch (l % 8) {
355 case 7:
356 a = unbase32hexchar(x[0]);
357 if (a < 0)
358 return -EINVAL;
359
360 b = unbase32hexchar(x[1]);
361 if (b < 0)
362 return -EINVAL;
363
364 c = unbase32hexchar(x[2]);
365 if (c < 0)
366 return -EINVAL;
367
368 d = unbase32hexchar(x[3]);
369 if (d < 0)
370 return -EINVAL;
371
372 e = unbase32hexchar(x[4]);
373 if (e < 0)
374 return -EINVAL;
375
376 f = unbase32hexchar(x[5]);
377 if (f < 0)
378 return -EINVAL;
379
380 g = unbase32hexchar(x[6]);
381 if (g < 0)
382 return -EINVAL;
383
384 /* g == 000VV000 */
385 if (g & 7)
386 return -EINVAL;
387
388 *(z++) = (uint8_t) a << 3 | (uint8_t) b >> 2; /* XXXXXYYY */
389 *(z++) = (uint8_t) b << 6 | (uint8_t) c << 1 | (uint8_t) d >> 4; /* YYZZZZZW */
390 *(z++) = (uint8_t) d << 4 | (uint8_t) e >> 1; /* WWWWSSSS */
391 *(z++) = (uint8_t) e << 7 | (uint8_t) f << 2 | (uint8_t) g >> 3; /* SQQQQQVV */
392
393 break;
394 case 5:
395 a = unbase32hexchar(x[0]);
396 if (a < 0)
397 return -EINVAL;
398
399 b = unbase32hexchar(x[1]);
400 if (b < 0)
401 return -EINVAL;
402
403 c = unbase32hexchar(x[2]);
404 if (c < 0)
405 return -EINVAL;
406
407 d = unbase32hexchar(x[3]);
408 if (d < 0)
409 return -EINVAL;
410
411 e = unbase32hexchar(x[4]);
412 if (e < 0)
413 return -EINVAL;
414
415 /* e == 000SSSS0 */
416 if (e & 1)
417 return -EINVAL;
418
419 *(z++) = (uint8_t) a << 3 | (uint8_t) b >> 2; /* XXXXXYYY */
420 *(z++) = (uint8_t) b << 6 | (uint8_t) c << 1 | (uint8_t) d >> 4; /* YYZZZZZW */
421 *(z++) = (uint8_t) d << 4 | (uint8_t) e >> 1; /* WWWWSSSS */
422
423 break;
424 case 4:
425 a = unbase32hexchar(x[0]);
426 if (a < 0)
427 return -EINVAL;
428
429 b = unbase32hexchar(x[1]);
430 if (b < 0)
431 return -EINVAL;
432
433 c = unbase32hexchar(x[2]);
434 if (c < 0)
435 return -EINVAL;
436
437 d = unbase32hexchar(x[3]);
438 if (d < 0)
439 return -EINVAL;
440
441 /* d == 000W0000 */
442 if (d & 15)
443 return -EINVAL;
444
445 *(z++) = (uint8_t) a << 3 | (uint8_t) b >> 2; /* XXXXXYYY */
446 *(z++) = (uint8_t) b << 6 | (uint8_t) c << 1 | (uint8_t) d >> 4; /* YYZZZZZW */
447
448 break;
449 case 2:
450 a = unbase32hexchar(x[0]);
451 if (a < 0)
452 return -EINVAL;
453
454 b = unbase32hexchar(x[1]);
455 if (b < 0)
456 return -EINVAL;
457
458 /* b == 000YYY00 */
459 if (b & 3)
460 return -EINVAL;
461
462 *(z++) = (uint8_t) a << 3 | (uint8_t) b >> 2; /* XXXXXYYY */
463
464 break;
465 case 0:
466 break;
467 default:
468 return -EINVAL;
469 }
470
471 *z = 0;
472
473 *mem = r;
474 r = NULL;
475 *_len = len;
476
477 return 0;
478}
479
480/* https://tools.ietf.org/html/rfc4648#section-4 */
481char base64char(int x) {
482 static const char table[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
483 "abcdefghijklmnopqrstuvwxyz"
484 "0123456789+/";
485 return table[x & 63];
486}
487
488int unbase64char(char c) {
489 unsigned offset;
490
491 if (c >= 'A' && c <= 'Z')
492 return c - 'A';
493
494 offset = 'Z' - 'A' + 1;
495
496 if (c >= 'a' && c <= 'z')
497 return c - 'a' + offset;
498
499 offset += 'z' - 'a' + 1;
500
501 if (c >= '0' && c <= '9')
502 return c - '0' + offset;
503
504 offset += '9' - '0' + 1;
505
506 if (c == '+')
507 return offset;
508
313cefa1 509 offset++;
e4e73a63
LP
510
511 if (c == '/')
512 return offset;
513
514 return -EINVAL;
515}
516
d7671a3e 517ssize_t base64mem(const void *p, size_t l, char **out) {
e4e73a63
LP
518 char *r, *z;
519 const uint8_t *x;
520
521 /* three input bytes makes four output bytes, padding is added so we must round up */
522 z = r = malloc(4 * (l + 2) / 3 + 1);
523 if (!r)
d7671a3e 524 return -ENOMEM;
e4e73a63
LP
525
526 for (x = p; x < (const uint8_t*) p + (l / 3) * 3; x += 3) {
527 /* x[0] == XXXXXXXX; x[1] == YYYYYYYY; x[2] == ZZZZZZZZ */
528 *(z++) = base64char(x[0] >> 2); /* 00XXXXXX */
529 *(z++) = base64char((x[0] & 3) << 4 | x[1] >> 4); /* 00XXYYYY */
530 *(z++) = base64char((x[1] & 15) << 2 | x[2] >> 6); /* 00YYYYZZ */
531 *(z++) = base64char(x[2] & 63); /* 00ZZZZZZ */
532 }
533
534 switch (l % 3) {
535 case 2:
536 *(z++) = base64char(x[0] >> 2); /* 00XXXXXX */
537 *(z++) = base64char((x[0] & 3) << 4 | x[1] >> 4); /* 00XXYYYY */
538 *(z++) = base64char((x[1] & 15) << 2); /* 00YYYY00 */
539 *(z++) = '=';
540
541 break;
542 case 1:
543 *(z++) = base64char(x[0] >> 2); /* 00XXXXXX */
544 *(z++) = base64char((x[0] & 3) << 4); /* 00XX0000 */
545 *(z++) = '=';
546 *(z++) = '=';
547
548 break;
549 }
550
551 *z = 0;
d7671a3e
ZJS
552 *out = r;
553 return z - r;
554}
555
556static int base64_append_width(char **prefix, int plen,
557 const char *sep, int indent,
558 const void *p, size_t l,
559 int width) {
560
561 _cleanup_free_ char *x = NULL;
562 char *t, *s;
563 ssize_t slen, len, avail;
564 int line, lines;
565
566 len = base64mem(p, l, &x);
567 if (len <= 0)
568 return len;
569
570 lines = (len + width - 1) / width;
571
572 slen = sep ? strlen(sep) : 0;
573 t = realloc(*prefix, plen + 1 + slen + (indent + width + 1) * lines);
574 if (!t)
575 return -ENOMEM;
576
75f32f04 577 memcpy_safe(t + plen, sep, slen);
d7671a3e
ZJS
578
579 for (line = 0, s = t + plen + slen, avail = len; line < lines; line++) {
580 int act = MIN(width, avail);
581
582 if (line > 0 || sep) {
583 memset(s, ' ', indent);
584 s += indent;
585 }
586
587 memcpy(s, x + width * line, act);
588 s += act;
589 *(s++) = line < lines - 1 ? '\n' : '\0';
590 avail -= act;
591 }
592 assert(avail == 0);
593
594 *prefix = t;
595 return 0;
e4e73a63
LP
596}
597
d7671a3e
ZJS
598int base64_append(char **prefix, int plen,
599 const void *p, size_t l,
600 int indent, int width) {
601 if (plen > width / 2 || plen + indent > width)
602 /* leave indent on the left, keep last column free */
603 return base64_append_width(prefix, plen, "\n", indent, p, l, width - indent - 1);
604 else
605 /* leave plen on the left, keep last column free */
606 return base64_append_width(prefix, plen, NULL, plen, p, l, width - plen - 1);
607};
608
609
e4e73a63
LP
610int unbase64mem(const char *p, size_t l, void **mem, size_t *_len) {
611 _cleanup_free_ uint8_t *r = NULL;
612 int a, b, c, d;
613 uint8_t *z;
614 const char *x;
615 size_t len;
616
617 assert(p);
618
619 /* padding ensures any base63 input has input divisible by 4 */
620 if (l % 4 != 0)
621 return -EINVAL;
622
623 /* strip the padding */
624 if (l > 0 && p[l - 1] == '=')
313cefa1 625 l--;
e4e73a63 626 if (l > 0 && p[l - 1] == '=')
313cefa1 627 l--;
e4e73a63
LP
628
629 /* a group of four input bytes needs three output bytes, in case of
630 padding we need to add two or three extra bytes */
631 len = (l / 4) * 3 + (l % 4 ? (l % 4) - 1 : 0);
632
633 z = r = malloc(len + 1);
634 if (!r)
635 return -ENOMEM;
636
637 for (x = p; x < p + (l / 4) * 4; x += 4) {
638 /* a == 00XXXXXX; b == 00YYYYYY; c == 00ZZZZZZ; d == 00WWWWWW */
639 a = unbase64char(x[0]);
640 if (a < 0)
641 return -EINVAL;
642
643 b = unbase64char(x[1]);
644 if (b < 0)
645 return -EINVAL;
646
647 c = unbase64char(x[2]);
648 if (c < 0)
649 return -EINVAL;
650
651 d = unbase64char(x[3]);
652 if (d < 0)
653 return -EINVAL;
654
655 *(z++) = (uint8_t) a << 2 | (uint8_t) b >> 4; /* XXXXXXYY */
656 *(z++) = (uint8_t) b << 4 | (uint8_t) c >> 2; /* YYYYZZZZ */
657 *(z++) = (uint8_t) c << 6 | (uint8_t) d; /* ZZWWWWWW */
658 }
659
660 switch (l % 4) {
661 case 3:
662 a = unbase64char(x[0]);
663 if (a < 0)
664 return -EINVAL;
665
666 b = unbase64char(x[1]);
667 if (b < 0)
668 return -EINVAL;
669
670 c = unbase64char(x[2]);
671 if (c < 0)
672 return -EINVAL;
673
674 /* c == 00ZZZZ00 */
675 if (c & 3)
676 return -EINVAL;
677
678 *(z++) = (uint8_t) a << 2 | (uint8_t) b >> 4; /* XXXXXXYY */
679 *(z++) = (uint8_t) b << 4 | (uint8_t) c >> 2; /* YYYYZZZZ */
680
681 break;
682 case 2:
683 a = unbase64char(x[0]);
684 if (a < 0)
685 return -EINVAL;
686
687 b = unbase64char(x[1]);
688 if (b < 0)
689 return -EINVAL;
690
691 /* b == 00YY0000 */
692 if (b & 15)
693 return -EINVAL;
694
695 *(z++) = (uint8_t) a << 2 | (uint8_t) (b >> 4); /* XXXXXXYY */
696
697 break;
698 case 0:
699
700 break;
701 default:
702 return -EINVAL;
703 }
704
705 *z = 0;
706
707 *mem = r;
708 r = NULL;
709 *_len = len;
710
711 return 0;
712}
713
714void hexdump(FILE *f, const void *p, size_t s) {
715 const uint8_t *b = p;
716 unsigned n = 0;
717
718 assert(s == 0 || b);
719
720 while (s > 0) {
721 size_t i;
722
723 fprintf(f, "%04x ", n);
724
725 for (i = 0; i < 16; i++) {
726
727 if (i >= s)
728 fputs(" ", f);
729 else
730 fprintf(f, "%02x ", b[i]);
731
732 if (i == 7)
733 fputc(' ', f);
734 }
735
736 fputc(' ', f);
737
738 for (i = 0; i < 16; i++) {
739
740 if (i >= s)
741 fputc(' ', f);
742 else
743 fputc(isprint(b[i]) ? (char) b[i] : '.', f);
744 }
745
746 fputc('\n', f);
747
748 if (s < 16)
749 break;
750
751 n += 16;
752 b += 16;
753 s -= 16;
754 }
755}