diff options
author | Lennart Poettering <lennart@poettering.net> | 2015-10-26 16:41:43 +0100 |
---|---|---|
committer | Lennart Poettering <lennart@poettering.net> | 2015-10-27 13:25:55 +0100 |
commit | e4e73a632524c382139034d4271f53b6089ab4cb (patch) | |
tree | 48e286e7dbac59a562431ad05d506833db968f6e /src/basic | |
parent | 6bedfcbb2970e06a4d3280c8fb62083d252ede73 (diff) |
util-lib: split out hex/dec/oct encoding/decoding into its own file
Diffstat (limited to 'src/basic')
-rw-r--r-- | src/basic/bus-label.c | 6 | ||||
-rw-r--r-- | src/basic/escape.c | 4 | ||||
-rw-r--r-- | src/basic/hexdecoct.c | 697 | ||||
-rw-r--r-- | src/basic/hexdecoct.h | 54 | ||||
-rw-r--r-- | src/basic/json.c | 3 | ||||
-rw-r--r-- | src/basic/unit-name.c | 1 | ||||
-rw-r--r-- | src/basic/utf8.c | 1 | ||||
-rw-r--r-- | src/basic/util.c | 672 | ||||
-rw-r--r-- | src/basic/util.h | 22 |
9 files changed, 761 insertions, 699 deletions
diff --git a/src/basic/bus-label.c b/src/basic/bus-label.c index ccc9f2bf8e..6f39528f13 100644 --- a/src/basic/bus-label.c +++ b/src/basic/bus-label.c @@ -21,10 +21,10 @@ #include <stdlib.h> -#include "util.h" -#include "macro.h" - #include "bus-label.h" +#include "macro.h" +#include "hexdecoct.h" +#include "util.h" char *bus_label_escape(const char *s) { char *r, *t; diff --git a/src/basic/escape.c b/src/basic/escape.c index cf05ce10ef..e763b5dac2 100644 --- a/src/basic/escape.c +++ b/src/basic/escape.c @@ -19,11 +19,11 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include "escape.h" +#include "hexdecoct.h" #include "utf8.h" #include "util.h" -#include "escape.h" - size_t cescape_char(char c, char *buf) { char * buf_old = buf; diff --git a/src/basic/hexdecoct.c b/src/basic/hexdecoct.c new file mode 100644 index 0000000000..f958582e68 --- /dev/null +++ b/src/basic/hexdecoct.c @@ -0,0 +1,697 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include <ctype.h> +#include <inttypes.h> + +#include "hexdecoct.h" +#include "util.h" + +char octchar(int x) { + return '0' + (x & 7); +} + +int unoctchar(char c) { + + if (c >= '0' && c <= '7') + return c - '0'; + + return -EINVAL; +} + +char decchar(int x) { + return '0' + (x % 10); +} + +int undecchar(char c) { + + if (c >= '0' && c <= '9') + return c - '0'; + + return -EINVAL; +} + +char hexchar(int x) { + static const char table[16] = "0123456789abcdef"; + + return table[x & 15]; +} + +int unhexchar(char c) { + + if (c >= '0' && c <= '9') + return c - '0'; + + if (c >= 'a' && c <= 'f') + return c - 'a' + 10; + + if (c >= 'A' && c <= 'F') + return c - 'A' + 10; + + return -EINVAL; +} + +char *hexmem(const void *p, size_t l) { + char *r, *z; + const uint8_t *x; + + z = r = malloc(l * 2 + 1); + if (!r) + return NULL; + + for (x = p; x < (const uint8_t*) p + l; x++) { + *(z++) = hexchar(*x >> 4); + *(z++) = hexchar(*x & 15); + } + + *z = 0; + return r; +} + +int unhexmem(const char *p, size_t l, void **mem, size_t *len) { + _cleanup_free_ uint8_t *r = NULL; + uint8_t *z; + const char *x; + + assert(mem); + assert(len); + assert(p); + + z = r = malloc((l + 1) / 2 + 1); + if (!r) + return -ENOMEM; + + for (x = p; x < p + l; x += 2) { + int a, b; + + a = unhexchar(x[0]); + if (a < 0) + return a; + else if (x+1 < p + l) { + b = unhexchar(x[1]); + if (b < 0) + return b; + } else + b = 0; + + *(z++) = (uint8_t) a << 4 | (uint8_t) b; + } + + *z = 0; + + *mem = r; + r = NULL; + *len = (l + 1) / 2; + + return 0; +} + +/* https://tools.ietf.org/html/rfc4648#section-6 + * Notice that base32hex differs from base32 in the alphabet it uses. + * The distinction is that the base32hex representation preserves the + * order of the underlying data when compared as bytestrings, this is + * useful when representing NSEC3 hashes, as one can then verify the + * order of hashes directly from their representation. */ +char base32hexchar(int x) { + static const char table[32] = "0123456789" + "ABCDEFGHIJKLMNOPQRSTUV"; + + return table[x & 31]; +} + +int unbase32hexchar(char c) { + unsigned offset; + + if (c >= '0' && c <= '9') + return c - '0'; + + offset = '9' - '0' + 1; + + if (c >= 'A' && c <= 'V') + return c - 'A' + offset; + + return -EINVAL; +} + +char *base32hexmem(const void *p, size_t l, bool padding) { + char *r, *z; + const uint8_t *x; + size_t len; + + if (padding) + /* five input bytes makes eight output bytes, padding is added so we must round up */ + len = 8 * (l + 4) / 5; + else { + /* same, but round down as there is no padding */ + len = 8 * l / 5; + + switch (l % 5) { + case 4: + len += 7; + break; + case 3: + len += 5; + break; + case 2: + len += 4; + break; + case 1: + len += 2; + break; + } + } + + z = r = malloc(len + 1); + if (!r) + return NULL; + + for (x = p; x < (const uint8_t*) p + (l / 5) * 5; x += 5) { + /* x[0] == XXXXXXXX; x[1] == YYYYYYYY; x[2] == ZZZZZZZZ + x[3] == QQQQQQQQ; x[4] == WWWWWWWW */ + *(z++) = base32hexchar(x[0] >> 3); /* 000XXXXX */ + *(z++) = base32hexchar((x[0] & 7) << 2 | x[1] >> 6); /* 000XXXYY */ + *(z++) = base32hexchar((x[1] & 63) >> 1); /* 000YYYYY */ + *(z++) = base32hexchar((x[1] & 1) << 4 | x[2] >> 4); /* 000YZZZZ */ + *(z++) = base32hexchar((x[2] & 15) << 1 | x[3] >> 7); /* 000ZZZZQ */ + *(z++) = base32hexchar((x[3] & 127) >> 2); /* 000QQQQQ */ + *(z++) = base32hexchar((x[3] & 3) << 3 | x[4] >> 5); /* 000QQWWW */ + *(z++) = base32hexchar((x[4] & 31)); /* 000WWWWW */ + } + + switch (l % 5) { + case 4: + *(z++) = base32hexchar(x[0] >> 3); /* 000XXXXX */ + *(z++) = base32hexchar((x[0] & 7) << 2 | x[1] >> 6); /* 000XXXYY */ + *(z++) = base32hexchar((x[1] & 63) >> 1); /* 000YYYYY */ + *(z++) = base32hexchar((x[1] & 1) << 4 | x[2] >> 4); /* 000YZZZZ */ + *(z++) = base32hexchar((x[2] & 15) << 1 | x[3] >> 7); /* 000ZZZZQ */ + *(z++) = base32hexchar((x[3] & 127) >> 2); /* 000QQQQQ */ + *(z++) = base32hexchar((x[3] & 3) << 3); /* 000QQ000 */ + if (padding) + *(z++) = '='; + + break; + + case 3: + *(z++) = base32hexchar(x[0] >> 3); /* 000XXXXX */ + *(z++) = base32hexchar((x[0] & 7) << 2 | x[1] >> 6); /* 000XXXYY */ + *(z++) = base32hexchar((x[1] & 63) >> 1); /* 000YYYYY */ + *(z++) = base32hexchar((x[1] & 1) << 4 | x[2] >> 4); /* 000YZZZZ */ + *(z++) = base32hexchar((x[2] & 15) << 1); /* 000ZZZZ0 */ + if (padding) { + *(z++) = '='; + *(z++) = '='; + *(z++) = '='; + } + + break; + + case 2: + *(z++) = base32hexchar(x[0] >> 3); /* 000XXXXX */ + *(z++) = base32hexchar((x[0] & 7) << 2 | x[1] >> 6); /* 000XXXYY */ + *(z++) = base32hexchar((x[1] & 63) >> 1); /* 000YYYYY */ + *(z++) = base32hexchar((x[1] & 1) << 4); /* 000Y0000 */ + if (padding) { + *(z++) = '='; + *(z++) = '='; + *(z++) = '='; + *(z++) = '='; + } + + break; + + case 1: + *(z++) = base32hexchar(x[0] >> 3); /* 000XXXXX */ + *(z++) = base32hexchar((x[0] & 7) << 2); /* 000XXX00 */ + if (padding) { + *(z++) = '='; + *(z++) = '='; + *(z++) = '='; + *(z++) = '='; + *(z++) = '='; + *(z++) = '='; + } + + break; + } + + *z = 0; + return r; +} + +int unbase32hexmem(const char *p, size_t l, bool padding, void **mem, size_t *_len) { + _cleanup_free_ uint8_t *r = NULL; + int a, b, c, d, e, f, g, h; + uint8_t *z; + const char *x; + size_t len; + unsigned pad = 0; + + assert(p); + + /* padding ensures any base32hex input has input divisible by 8 */ + if (padding && l % 8 != 0) + return -EINVAL; + + if (padding) { + /* strip the padding */ + while (l > 0 && p[l - 1] == '=' && pad < 7) { + pad ++; + l --; + } + } + + /* a group of eight input bytes needs five output bytes, in case of + padding we need to add some extra bytes */ + len = (l / 8) * 5; + + switch (l % 8) { + case 7: + len += 4; + break; + case 5: + len += 3; + break; + case 4: + len += 2; + break; + case 2: + len += 1; + break; + case 0: + break; + default: + return -EINVAL; + } + + z = r = malloc(len + 1); + if (!r) + return -ENOMEM; + + for (x = p; x < p + (l / 8) * 8; x += 8) { + /* a == 000XXXXX; b == 000YYYYY; c == 000ZZZZZ; d == 000WWWWW + e == 000SSSSS; f == 000QQQQQ; g == 000VVVVV; h == 000RRRRR */ + a = unbase32hexchar(x[0]); + if (a < 0) + return -EINVAL; + + b = unbase32hexchar(x[1]); + if (b < 0) + return -EINVAL; + + c = unbase32hexchar(x[2]); + if (c < 0) + return -EINVAL; + + d = unbase32hexchar(x[3]); + if (d < 0) + return -EINVAL; + + e = unbase32hexchar(x[4]); + if (e < 0) + return -EINVAL; + + f = unbase32hexchar(x[5]); + if (f < 0) + return -EINVAL; + + g = unbase32hexchar(x[6]); + if (g < 0) + return -EINVAL; + + h = unbase32hexchar(x[7]); + if (h < 0) + return -EINVAL; + + *(z++) = (uint8_t) a << 3 | (uint8_t) b >> 2; /* XXXXXYYY */ + *(z++) = (uint8_t) b << 6 | (uint8_t) c << 1 | (uint8_t) d >> 4; /* YYZZZZZW */ + *(z++) = (uint8_t) d << 4 | (uint8_t) e >> 1; /* WWWWSSSS */ + *(z++) = (uint8_t) e << 7 | (uint8_t) f << 2 | (uint8_t) g >> 3; /* SQQQQQVV */ + *(z++) = (uint8_t) g << 5 | (uint8_t) h; /* VVVRRRRR */ + } + + switch (l % 8) { + case 7: + a = unbase32hexchar(x[0]); + if (a < 0) + return -EINVAL; + + b = unbase32hexchar(x[1]); + if (b < 0) + return -EINVAL; + + c = unbase32hexchar(x[2]); + if (c < 0) + return -EINVAL; + + d = unbase32hexchar(x[3]); + if (d < 0) + return -EINVAL; + + e = unbase32hexchar(x[4]); + if (e < 0) + return -EINVAL; + + f = unbase32hexchar(x[5]); + if (f < 0) + return -EINVAL; + + g = unbase32hexchar(x[6]); + if (g < 0) + return -EINVAL; + + /* g == 000VV000 */ + if (g & 7) + return -EINVAL; + + *(z++) = (uint8_t) a << 3 | (uint8_t) b >> 2; /* XXXXXYYY */ + *(z++) = (uint8_t) b << 6 | (uint8_t) c << 1 | (uint8_t) d >> 4; /* YYZZZZZW */ + *(z++) = (uint8_t) d << 4 | (uint8_t) e >> 1; /* WWWWSSSS */ + *(z++) = (uint8_t) e << 7 | (uint8_t) f << 2 | (uint8_t) g >> 3; /* SQQQQQVV */ + + break; + case 5: + a = unbase32hexchar(x[0]); + if (a < 0) + return -EINVAL; + + b = unbase32hexchar(x[1]); + if (b < 0) + return -EINVAL; + + c = unbase32hexchar(x[2]); + if (c < 0) + return -EINVAL; + + d = unbase32hexchar(x[3]); + if (d < 0) + return -EINVAL; + + e = unbase32hexchar(x[4]); + if (e < 0) + return -EINVAL; + + /* e == 000SSSS0 */ + if (e & 1) + return -EINVAL; + + *(z++) = (uint8_t) a << 3 | (uint8_t) b >> 2; /* XXXXXYYY */ + *(z++) = (uint8_t) b << 6 | (uint8_t) c << 1 | (uint8_t) d >> 4; /* YYZZZZZW */ + *(z++) = (uint8_t) d << 4 | (uint8_t) e >> 1; /* WWWWSSSS */ + + break; + case 4: + a = unbase32hexchar(x[0]); + if (a < 0) + return -EINVAL; + + b = unbase32hexchar(x[1]); + if (b < 0) + return -EINVAL; + + c = unbase32hexchar(x[2]); + if (c < 0) + return -EINVAL; + + d = unbase32hexchar(x[3]); + if (d < 0) + return -EINVAL; + + /* d == 000W0000 */ + if (d & 15) + return -EINVAL; + + *(z++) = (uint8_t) a << 3 | (uint8_t) b >> 2; /* XXXXXYYY */ + *(z++) = (uint8_t) b << 6 | (uint8_t) c << 1 | (uint8_t) d >> 4; /* YYZZZZZW */ + + break; + case 2: + a = unbase32hexchar(x[0]); + if (a < 0) + return -EINVAL; + + b = unbase32hexchar(x[1]); + if (b < 0) + return -EINVAL; + + /* b == 000YYY00 */ + if (b & 3) + return -EINVAL; + + *(z++) = (uint8_t) a << 3 | (uint8_t) b >> 2; /* XXXXXYYY */ + + break; + case 0: + break; + default: + return -EINVAL; + } + + *z = 0; + + *mem = r; + r = NULL; + *_len = len; + + return 0; +} + +/* https://tools.ietf.org/html/rfc4648#section-4 */ +char base64char(int x) { + static const char table[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz" + "0123456789+/"; + return table[x & 63]; +} + +int unbase64char(char c) { + unsigned offset; + + if (c >= 'A' && c <= 'Z') + return c - 'A'; + + offset = 'Z' - 'A' + 1; + + if (c >= 'a' && c <= 'z') + return c - 'a' + offset; + + offset += 'z' - 'a' + 1; + + if (c >= '0' && c <= '9') + return c - '0' + offset; + + offset += '9' - '0' + 1; + + if (c == '+') + return offset; + + offset ++; + + if (c == '/') + return offset; + + return -EINVAL; +} + +char *base64mem(const void *p, size_t l) { + char *r, *z; + const uint8_t *x; + + /* three input bytes makes four output bytes, padding is added so we must round up */ + z = r = malloc(4 * (l + 2) / 3 + 1); + if (!r) + return NULL; + + for (x = p; x < (const uint8_t*) p + (l / 3) * 3; x += 3) { + /* x[0] == XXXXXXXX; x[1] == YYYYYYYY; x[2] == ZZZZZZZZ */ + *(z++) = base64char(x[0] >> 2); /* 00XXXXXX */ + *(z++) = base64char((x[0] & 3) << 4 | x[1] >> 4); /* 00XXYYYY */ + *(z++) = base64char((x[1] & 15) << 2 | x[2] >> 6); /* 00YYYYZZ */ + *(z++) = base64char(x[2] & 63); /* 00ZZZZZZ */ + } + + switch (l % 3) { + case 2: + *(z++) = base64char(x[0] >> 2); /* 00XXXXXX */ + *(z++) = base64char((x[0] & 3) << 4 | x[1] >> 4); /* 00XXYYYY */ + *(z++) = base64char((x[1] & 15) << 2); /* 00YYYY00 */ + *(z++) = '='; + + break; + case 1: + *(z++) = base64char(x[0] >> 2); /* 00XXXXXX */ + *(z++) = base64char((x[0] & 3) << 4); /* 00XX0000 */ + *(z++) = '='; + *(z++) = '='; + + break; + } + + *z = 0; + return r; +} + +int unbase64mem(const char *p, size_t l, void **mem, size_t *_len) { + _cleanup_free_ uint8_t *r = NULL; + int a, b, c, d; + uint8_t *z; + const char *x; + size_t len; + + assert(p); + + /* padding ensures any base63 input has input divisible by 4 */ + if (l % 4 != 0) + return -EINVAL; + + /* strip the padding */ + if (l > 0 && p[l - 1] == '=') + l --; + if (l > 0 && p[l - 1] == '=') + l --; + + /* a group of four input bytes needs three output bytes, in case of + padding we need to add two or three extra bytes */ + len = (l / 4) * 3 + (l % 4 ? (l % 4) - 1 : 0); + + z = r = malloc(len + 1); + if (!r) + return -ENOMEM; + + for (x = p; x < p + (l / 4) * 4; x += 4) { + /* a == 00XXXXXX; b == 00YYYYYY; c == 00ZZZZZZ; d == 00WWWWWW */ + a = unbase64char(x[0]); + if (a < 0) + return -EINVAL; + + b = unbase64char(x[1]); + if (b < 0) + return -EINVAL; + + c = unbase64char(x[2]); + if (c < 0) + return -EINVAL; + + d = unbase64char(x[3]); + if (d < 0) + return -EINVAL; + + *(z++) = (uint8_t) a << 2 | (uint8_t) b >> 4; /* XXXXXXYY */ + *(z++) = (uint8_t) b << 4 | (uint8_t) c >> 2; /* YYYYZZZZ */ + *(z++) = (uint8_t) c << 6 | (uint8_t) d; /* ZZWWWWWW */ + } + + switch (l % 4) { + case 3: + a = unbase64char(x[0]); + if (a < 0) + return -EINVAL; + + b = unbase64char(x[1]); + if (b < 0) + return -EINVAL; + + c = unbase64char(x[2]); + if (c < 0) + return -EINVAL; + + /* c == 00ZZZZ00 */ + if (c & 3) + return -EINVAL; + + *(z++) = (uint8_t) a << 2 | (uint8_t) b >> 4; /* XXXXXXYY */ + *(z++) = (uint8_t) b << 4 | (uint8_t) c >> 2; /* YYYYZZZZ */ + + break; + case 2: + a = unbase64char(x[0]); + if (a < 0) + return -EINVAL; + + b = unbase64char(x[1]); + if (b < 0) + return -EINVAL; + + /* b == 00YY0000 */ + if (b & 15) + return -EINVAL; + + *(z++) = (uint8_t) a << 2 | (uint8_t) (b >> 4); /* XXXXXXYY */ + + break; + case 0: + + break; + default: + return -EINVAL; + } + + *z = 0; + + *mem = r; + r = NULL; + *_len = len; + + return 0; +} + +void hexdump(FILE *f, const void *p, size_t s) { + const uint8_t *b = p; + unsigned n = 0; + + assert(s == 0 || b); + + while (s > 0) { + size_t i; + + fprintf(f, "%04x ", n); + + for (i = 0; i < 16; i++) { + + if (i >= s) + fputs(" ", f); + else + fprintf(f, "%02x ", b[i]); + + if (i == 7) + fputc(' ', f); + } + + fputc(' ', f); + + for (i = 0; i < 16; i++) { + + if (i >= s) + fputc(' ', f); + else + fputc(isprint(b[i]) ? (char) b[i] : '.', f); + } + + fputc('\n', f); + + if (s < 16) + break; + + n += 16; + b += 16; + s -= 16; + } +} diff --git a/src/basic/hexdecoct.h b/src/basic/hexdecoct.h new file mode 100644 index 0000000000..4aeb4c3bdc --- /dev/null +++ b/src/basic/hexdecoct.h @@ -0,0 +1,54 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include <stdbool.h> +#include <stdio.h> +#include <sys/types.h> + +#include "macro.h" + +char octchar(int x) _const_; +int unoctchar(char c) _const_; + +char decchar(int x) _const_; +int undecchar(char c) _const_; + +char hexchar(int x) _const_; +int unhexchar(char c) _const_; + +char *hexmem(const void *p, size_t l); +int unhexmem(const char *p, size_t l, void **mem, size_t *len); + +char base32hexchar(int x) _const_; +int unbase32hexchar(char c) _const_; + +char base64char(int x) _const_; +int unbase64char(char c) _const_; + +char *base32hexmem(const void *p, size_t l, bool padding); +int unbase32hexmem(const char *p, size_t l, bool padding, void **mem, size_t *len); + +char *base64mem(const void *p, size_t l); +int unbase64mem(const char *p, size_t l, void **mem, size_t *len); + +void hexdump(FILE *f, const void *p, size_t s); diff --git a/src/basic/json.c b/src/basic/json.c index 2b634aa7f8..efe635e20e 100644 --- a/src/basic/json.c +++ b/src/basic/json.c @@ -22,10 +22,11 @@ #include <math.h> #include <sys/types.h> +#include "json.h" #include "macro.h" +#include "hexdecoct.h" #include "string-util.h" #include "utf8.h" -#include "json.h" int json_variant_new(JsonVariant **ret, JsonVariantType type) { JsonVariant *v; diff --git a/src/basic/unit-name.c b/src/basic/unit-name.c index 383c4ab871..c6ba9afb5a 100644 --- a/src/basic/unit-name.c +++ b/src/basic/unit-name.c @@ -29,6 +29,7 @@ #include "strv.h" #include "util.h" #include "unit-name.h" +#include "hexdecoct.h" #define VALID_CHARS \ DIGITS LETTERS \ diff --git a/src/basic/utf8.c b/src/basic/utf8.c index 800884ffee..de124abbde 100644 --- a/src/basic/utf8.c +++ b/src/basic/utf8.c @@ -49,6 +49,7 @@ #include <string.h> #include <stdbool.h> +#include "hexdecoct.h" #include "utf8.h" #include "util.h" diff --git a/src/basic/util.c b/src/basic/util.c index 66b7978c60..5e3a363bb4 100644 --- a/src/basic/util.c +++ b/src/basic/util.c @@ -89,6 +89,7 @@ #include "macro.h" #include "missing.h" #include "mkdir.h" +#include "hexdecoct.h" #include "parse-util.h" #include "path-util.h" #include "process-util.h" @@ -320,634 +321,6 @@ int rmdir_parents(const char *path, const char *stop) { return 0; } -char hexchar(int x) { - static const char table[16] = "0123456789abcdef"; - - return table[x & 15]; -} - -int unhexchar(char c) { - - if (c >= '0' && c <= '9') - return c - '0'; - - if (c >= 'a' && c <= 'f') - return c - 'a' + 10; - - if (c >= 'A' && c <= 'F') - return c - 'A' + 10; - - return -EINVAL; -} - -char *hexmem(const void *p, size_t l) { - char *r, *z; - const uint8_t *x; - - z = r = malloc(l * 2 + 1); - if (!r) - return NULL; - - for (x = p; x < (const uint8_t*) p + l; x++) { - *(z++) = hexchar(*x >> 4); - *(z++) = hexchar(*x & 15); - } - - *z = 0; - return r; -} - -int unhexmem(const char *p, size_t l, void **mem, size_t *len) { - _cleanup_free_ uint8_t *r = NULL; - uint8_t *z; - const char *x; - - assert(mem); - assert(len); - assert(p); - - z = r = malloc((l + 1) / 2 + 1); - if (!r) - return -ENOMEM; - - for (x = p; x < p + l; x += 2) { - int a, b; - - a = unhexchar(x[0]); - if (a < 0) - return a; - else if (x+1 < p + l) { - b = unhexchar(x[1]); - if (b < 0) - return b; - } else - b = 0; - - *(z++) = (uint8_t) a << 4 | (uint8_t) b; - } - - *z = 0; - - *mem = r; - r = NULL; - *len = (l + 1) / 2; - - return 0; -} - -/* https://tools.ietf.org/html/rfc4648#section-6 - * Notice that base32hex differs from base32 in the alphabet it uses. - * The distinction is that the base32hex representation preserves the - * order of the underlying data when compared as bytestrings, this is - * useful when representing NSEC3 hashes, as one can then verify the - * order of hashes directly from their representation. */ -char base32hexchar(int x) { - static const char table[32] = "0123456789" - "ABCDEFGHIJKLMNOPQRSTUV"; - - return table[x & 31]; -} - -int unbase32hexchar(char c) { - unsigned offset; - - if (c >= '0' && c <= '9') - return c - '0'; - - offset = '9' - '0' + 1; - - if (c >= 'A' && c <= 'V') - return c - 'A' + offset; - - return -EINVAL; -} - -char *base32hexmem(const void *p, size_t l, bool padding) { - char *r, *z; - const uint8_t *x; - size_t len; - - if (padding) - /* five input bytes makes eight output bytes, padding is added so we must round up */ - len = 8 * (l + 4) / 5; - else { - /* same, but round down as there is no padding */ - len = 8 * l / 5; - - switch (l % 5) { - case 4: - len += 7; - break; - case 3: - len += 5; - break; - case 2: - len += 4; - break; - case 1: - len += 2; - break; - } - } - - z = r = malloc(len + 1); - if (!r) - return NULL; - - for (x = p; x < (const uint8_t*) p + (l / 5) * 5; x += 5) { - /* x[0] == XXXXXXXX; x[1] == YYYYYYYY; x[2] == ZZZZZZZZ - x[3] == QQQQQQQQ; x[4] == WWWWWWWW */ - *(z++) = base32hexchar(x[0] >> 3); /* 000XXXXX */ - *(z++) = base32hexchar((x[0] & 7) << 2 | x[1] >> 6); /* 000XXXYY */ - *(z++) = base32hexchar((x[1] & 63) >> 1); /* 000YYYYY */ - *(z++) = base32hexchar((x[1] & 1) << 4 | x[2] >> 4); /* 000YZZZZ */ - *(z++) = base32hexchar((x[2] & 15) << 1 | x[3] >> 7); /* 000ZZZZQ */ - *(z++) = base32hexchar((x[3] & 127) >> 2); /* 000QQQQQ */ - *(z++) = base32hexchar((x[3] & 3) << 3 | x[4] >> 5); /* 000QQWWW */ - *(z++) = base32hexchar((x[4] & 31)); /* 000WWWWW */ - } - - switch (l % 5) { - case 4: - *(z++) = base32hexchar(x[0] >> 3); /* 000XXXXX */ - *(z++) = base32hexchar((x[0] & 7) << 2 | x[1] >> 6); /* 000XXXYY */ - *(z++) = base32hexchar((x[1] & 63) >> 1); /* 000YYYYY */ - *(z++) = base32hexchar((x[1] & 1) << 4 | x[2] >> 4); /* 000YZZZZ */ - *(z++) = base32hexchar((x[2] & 15) << 1 | x[3] >> 7); /* 000ZZZZQ */ - *(z++) = base32hexchar((x[3] & 127) >> 2); /* 000QQQQQ */ - *(z++) = base32hexchar((x[3] & 3) << 3); /* 000QQ000 */ - if (padding) - *(z++) = '='; - - break; - - case 3: - *(z++) = base32hexchar(x[0] >> 3); /* 000XXXXX */ - *(z++) = base32hexchar((x[0] & 7) << 2 | x[1] >> 6); /* 000XXXYY */ - *(z++) = base32hexchar((x[1] & 63) >> 1); /* 000YYYYY */ - *(z++) = base32hexchar((x[1] & 1) << 4 | x[2] >> 4); /* 000YZZZZ */ - *(z++) = base32hexchar((x[2] & 15) << 1); /* 000ZZZZ0 */ - if (padding) { - *(z++) = '='; - *(z++) = '='; - *(z++) = '='; - } - - break; - - case 2: - *(z++) = base32hexchar(x[0] >> 3); /* 000XXXXX */ - *(z++) = base32hexchar((x[0] & 7) << 2 | x[1] >> 6); /* 000XXXYY */ - *(z++) = base32hexchar((x[1] & 63) >> 1); /* 000YYYYY */ - *(z++) = base32hexchar((x[1] & 1) << 4); /* 000Y0000 */ - if (padding) { - *(z++) = '='; - *(z++) = '='; - *(z++) = '='; - *(z++) = '='; - } - - break; - - case 1: - *(z++) = base32hexchar(x[0] >> 3); /* 000XXXXX */ - *(z++) = base32hexchar((x[0] & 7) << 2); /* 000XXX00 */ - if (padding) { - *(z++) = '='; - *(z++) = '='; - *(z++) = '='; - *(z++) = '='; - *(z++) = '='; - *(z++) = '='; - } - - break; - } - - *z = 0; - return r; -} - -int unbase32hexmem(const char *p, size_t l, bool padding, void **mem, size_t *_len) { - _cleanup_free_ uint8_t *r = NULL; - int a, b, c, d, e, f, g, h; - uint8_t *z; - const char *x; - size_t len; - unsigned pad = 0; - - assert(p); - - /* padding ensures any base32hex input has input divisible by 8 */ - if (padding && l % 8 != 0) - return -EINVAL; - - if (padding) { - /* strip the padding */ - while (l > 0 && p[l - 1] == '=' && pad < 7) { - pad ++; - l --; - } - } - - /* a group of eight input bytes needs five output bytes, in case of - padding we need to add some extra bytes */ - len = (l / 8) * 5; - - switch (l % 8) { - case 7: - len += 4; - break; - case 5: - len += 3; - break; - case 4: - len += 2; - break; - case 2: - len += 1; - break; - case 0: - break; - default: - return -EINVAL; - } - - z = r = malloc(len + 1); - if (!r) - return -ENOMEM; - - for (x = p; x < p + (l / 8) * 8; x += 8) { - /* a == 000XXXXX; b == 000YYYYY; c == 000ZZZZZ; d == 000WWWWW - e == 000SSSSS; f == 000QQQQQ; g == 000VVVVV; h == 000RRRRR */ - a = unbase32hexchar(x[0]); - if (a < 0) - return -EINVAL; - - b = unbase32hexchar(x[1]); - if (b < 0) - return -EINVAL; - - c = unbase32hexchar(x[2]); - if (c < 0) - return -EINVAL; - - d = unbase32hexchar(x[3]); - if (d < 0) - return -EINVAL; - - e = unbase32hexchar(x[4]); - if (e < 0) - return -EINVAL; - - f = unbase32hexchar(x[5]); - if (f < 0) - return -EINVAL; - - g = unbase32hexchar(x[6]); - if (g < 0) - return -EINVAL; - - h = unbase32hexchar(x[7]); - if (h < 0) - return -EINVAL; - - *(z++) = (uint8_t) a << 3 | (uint8_t) b >> 2; /* XXXXXYYY */ - *(z++) = (uint8_t) b << 6 | (uint8_t) c << 1 | (uint8_t) d >> 4; /* YYZZZZZW */ - *(z++) = (uint8_t) d << 4 | (uint8_t) e >> 1; /* WWWWSSSS */ - *(z++) = (uint8_t) e << 7 | (uint8_t) f << 2 | (uint8_t) g >> 3; /* SQQQQQVV */ - *(z++) = (uint8_t) g << 5 | (uint8_t) h; /* VVVRRRRR */ - } - - switch (l % 8) { - case 7: - a = unbase32hexchar(x[0]); - if (a < 0) - return -EINVAL; - - b = unbase32hexchar(x[1]); - if (b < 0) - return -EINVAL; - - c = unbase32hexchar(x[2]); - if (c < 0) - return -EINVAL; - - d = unbase32hexchar(x[3]); - if (d < 0) - return -EINVAL; - - e = unbase32hexchar(x[4]); - if (e < 0) - return -EINVAL; - - f = unbase32hexchar(x[5]); - if (f < 0) - return -EINVAL; - - g = unbase32hexchar(x[6]); - if (g < 0) - return -EINVAL; - - /* g == 000VV000 */ - if (g & 7) - return -EINVAL; - - *(z++) = (uint8_t) a << 3 | (uint8_t) b >> 2; /* XXXXXYYY */ - *(z++) = (uint8_t) b << 6 | (uint8_t) c << 1 | (uint8_t) d >> 4; /* YYZZZZZW */ - *(z++) = (uint8_t) d << 4 | (uint8_t) e >> 1; /* WWWWSSSS */ - *(z++) = (uint8_t) e << 7 | (uint8_t) f << 2 | (uint8_t) g >> 3; /* SQQQQQVV */ - - break; - case 5: - a = unbase32hexchar(x[0]); - if (a < 0) - return -EINVAL; - - b = unbase32hexchar(x[1]); - if (b < 0) - return -EINVAL; - - c = unbase32hexchar(x[2]); - if (c < 0) - return -EINVAL; - - d = unbase32hexchar(x[3]); - if (d < 0) - return -EINVAL; - - e = unbase32hexchar(x[4]); - if (e < 0) - return -EINVAL; - - /* e == 000SSSS0 */ - if (e & 1) - return -EINVAL; - - *(z++) = (uint8_t) a << 3 | (uint8_t) b >> 2; /* XXXXXYYY */ - *(z++) = (uint8_t) b << 6 | (uint8_t) c << 1 | (uint8_t) d >> 4; /* YYZZZZZW */ - *(z++) = (uint8_t) d << 4 | (uint8_t) e >> 1; /* WWWWSSSS */ - - break; - case 4: - a = unbase32hexchar(x[0]); - if (a < 0) - return -EINVAL; - - b = unbase32hexchar(x[1]); - if (b < 0) - return -EINVAL; - - c = unbase32hexchar(x[2]); - if (c < 0) - return -EINVAL; - - d = unbase32hexchar(x[3]); - if (d < 0) - return -EINVAL; - - /* d == 000W0000 */ - if (d & 15) - return -EINVAL; - - *(z++) = (uint8_t) a << 3 | (uint8_t) b >> 2; /* XXXXXYYY */ - *(z++) = (uint8_t) b << 6 | (uint8_t) c << 1 | (uint8_t) d >> 4; /* YYZZZZZW */ - - break; - case 2: - a = unbase32hexchar(x[0]); - if (a < 0) - return -EINVAL; - - b = unbase32hexchar(x[1]); - if (b < 0) - return -EINVAL; - - /* b == 000YYY00 */ - if (b & 3) - return -EINVAL; - - *(z++) = (uint8_t) a << 3 | (uint8_t) b >> 2; /* XXXXXYYY */ - - break; - case 0: - break; - default: - return -EINVAL; - } - - *z = 0; - - *mem = r; - r = NULL; - *_len = len; - - return 0; -} - -/* https://tools.ietf.org/html/rfc4648#section-4 */ -char base64char(int x) { - static const char table[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" - "abcdefghijklmnopqrstuvwxyz" - "0123456789+/"; - return table[x & 63]; -} - -int unbase64char(char c) { - unsigned offset; - - if (c >= 'A' && c <= 'Z') - return c - 'A'; - - offset = 'Z' - 'A' + 1; - - if (c >= 'a' && c <= 'z') - return c - 'a' + offset; - - offset += 'z' - 'a' + 1; - - if (c >= '0' && c <= '9') - return c - '0' + offset; - - offset += '9' - '0' + 1; - - if (c == '+') - return offset; - - offset ++; - - if (c == '/') - return offset; - - return -EINVAL; -} - -char *base64mem(const void *p, size_t l) { - char *r, *z; - const uint8_t *x; - - /* three input bytes makes four output bytes, padding is added so we must round up */ - z = r = malloc(4 * (l + 2) / 3 + 1); - if (!r) - return NULL; - - for (x = p; x < (const uint8_t*) p + (l / 3) * 3; x += 3) { - /* x[0] == XXXXXXXX; x[1] == YYYYYYYY; x[2] == ZZZZZZZZ */ - *(z++) = base64char(x[0] >> 2); /* 00XXXXXX */ - *(z++) = base64char((x[0] & 3) << 4 | x[1] >> 4); /* 00XXYYYY */ - *(z++) = base64char((x[1] & 15) << 2 | x[2] >> 6); /* 00YYYYZZ */ - *(z++) = base64char(x[2] & 63); /* 00ZZZZZZ */ - } - - switch (l % 3) { - case 2: - *(z++) = base64char(x[0] >> 2); /* 00XXXXXX */ - *(z++) = base64char((x[0] & 3) << 4 | x[1] >> 4); /* 00XXYYYY */ - *(z++) = base64char((x[1] & 15) << 2); /* 00YYYY00 */ - *(z++) = '='; - - break; - case 1: - *(z++) = base64char(x[0] >> 2); /* 00XXXXXX */ - *(z++) = base64char((x[0] & 3) << 4); /* 00XX0000 */ - *(z++) = '='; - *(z++) = '='; - - break; - } - - *z = 0; - return r; -} - -int unbase64mem(const char *p, size_t l, void **mem, size_t *_len) { - _cleanup_free_ uint8_t *r = NULL; - int a, b, c, d; - uint8_t *z; - const char *x; - size_t len; - - assert(p); - - /* padding ensures any base63 input has input divisible by 4 */ - if (l % 4 != 0) - return -EINVAL; - - /* strip the padding */ - if (l > 0 && p[l - 1] == '=') - l --; - if (l > 0 && p[l - 1] == '=') - l --; - - /* a group of four input bytes needs three output bytes, in case of - padding we need to add two or three extra bytes */ - len = (l / 4) * 3 + (l % 4 ? (l % 4) - 1 : 0); - - z = r = malloc(len + 1); - if (!r) - return -ENOMEM; - - for (x = p; x < p + (l / 4) * 4; x += 4) { - /* a == 00XXXXXX; b == 00YYYYYY; c == 00ZZZZZZ; d == 00WWWWWW */ - a = unbase64char(x[0]); - if (a < 0) - return -EINVAL; - - b = unbase64char(x[1]); - if (b < 0) - return -EINVAL; - - c = unbase64char(x[2]); - if (c < 0) - return -EINVAL; - - d = unbase64char(x[3]); - if (d < 0) - return -EINVAL; - - *(z++) = (uint8_t) a << 2 | (uint8_t) b >> 4; /* XXXXXXYY */ - *(z++) = (uint8_t) b << 4 | (uint8_t) c >> 2; /* YYYYZZZZ */ - *(z++) = (uint8_t) c << 6 | (uint8_t) d; /* ZZWWWWWW */ - } - - switch (l % 4) { - case 3: - a = unbase64char(x[0]); - if (a < 0) - return -EINVAL; - - b = unbase64char(x[1]); - if (b < 0) - return -EINVAL; - - c = unbase64char(x[2]); - if (c < 0) - return -EINVAL; - - /* c == 00ZZZZ00 */ - if (c & 3) - return -EINVAL; - - *(z++) = (uint8_t) a << 2 | (uint8_t) b >> 4; /* XXXXXXYY */ - *(z++) = (uint8_t) b << 4 | (uint8_t) c >> 2; /* YYYYZZZZ */ - - break; - case 2: - a = unbase64char(x[0]); - if (a < 0) - return -EINVAL; - - b = unbase64char(x[1]); - if (b < 0) - return -EINVAL; - - /* b == 00YY0000 */ - if (b & 15) - return -EINVAL; - - *(z++) = (uint8_t) a << 2 | (uint8_t) (b >> 4); /* XXXXXXYY */ - - break; - case 0: - - break; - default: - return -EINVAL; - } - - *z = 0; - - *mem = r; - r = NULL; - *_len = len; - - return 0; -} - -char octchar(int x) { - return '0' + (x & 7); -} - -int unoctchar(char c) { - - if (c >= '0' && c <= '7') - return c - '0'; - - return -EINVAL; -} - -char decchar(int x) { - return '0' + (x % 10); -} - -int undecchar(char c) { - - if (c >= '0' && c <= '9') - return c - '0'; - - return -EINVAL; -} - _pure_ static bool hidden_file_allow_backup(const char *filename) { assert(filename); @@ -3000,49 +2373,6 @@ uint64_t physical_memory(void) { return (uint64_t) mem * (uint64_t) page_size(); } -void hexdump(FILE *f, const void *p, size_t s) { - const uint8_t *b = p; - unsigned n = 0; - - assert(s == 0 || b); - - while (s > 0) { - size_t i; - - fprintf(f, "%04x ", n); - - for (i = 0; i < 16; i++) { - - if (i >= s) - fputs(" ", f); - else - fprintf(f, "%02x ", b[i]); - - if (i == 7) - fputc(' ', f); - } - - fputc(' ', f); - - for (i = 0; i < 16; i++) { - - if (i >= s) - fputc(' ', f); - else - fputc(isprint(b[i]) ? (char) b[i] : '.', f); - } - - fputc('\n', f); - - if (s < 16) - break; - - n += 16; - b += 16; - s -= 16; - } -} - int update_reboot_param_file(const char *param) { int r = 0; diff --git a/src/basic/util.h b/src/basic/util.h index d51b824294..6c3449a706 100644 --- a/src/basic/util.h +++ b/src/basic/util.h @@ -95,17 +95,6 @@ char *file_in_same_dir(const char *path, const char *filename); int rmdir_parents(const char *path, const char *stop); -char hexchar(int x) _const_; -int unhexchar(char c) _const_; -char octchar(int x) _const_; -int unoctchar(char c) _const_; -char decchar(int x) _const_; -int undecchar(char c) _const_; -char base32hexchar(int x) _const_; -int unbase32hexchar(char c) _const_; -char base64char(int x) _const_; -int unbase64char(char c) _const_; - bool dirent_is_file(const struct dirent *de) _pure_; bool dirent_is_file_with_suffix(const struct dirent *de, const char *suffix) _pure_; @@ -398,15 +387,6 @@ static inline void *mempset(void *s, int c, size_t n) { return (uint8_t*)s + n; } -char *hexmem(const void *p, size_t l); -int unhexmem(const char *p, size_t l, void **mem, size_t *len); - -char *base32hexmem(const void *p, size_t l, bool padding); -int unbase32hexmem(const char *p, size_t l, bool padding, void **mem, size_t *len); - -char *base64mem(const void *p, size_t l); -int unbase64mem(const char *p, size_t l, void **mem, size_t *len); - void* greedy_realloc(void **p, size_t *allocated, size_t need, size_t size); void* greedy_realloc0(void **p, size_t *allocated, size_t need, size_t size); #define GREEDY_REALLOC(array, allocated, need) \ @@ -559,8 +539,6 @@ const char *personality_to_string(unsigned long); uint64_t physical_memory(void); -void hexdump(FILE *f, const void *p, size_t s); - union file_handle_union { struct file_handle handle; char padding[sizeof(struct file_handle) + MAX_HANDLE_SZ]; |