Merge pull request #25653 from yuwata/base64_append

hexdecoct: several fixes for base64_append()
This commit is contained in:
Zbigniew Jędrzejewski-Szmek
2022-12-08 21:22:32 +01:00
committed by GitHub
9 changed files with 217 additions and 46 deletions
+44 -26
View File
@@ -59,11 +59,13 @@ char *hexmem(const void *p, size_t l) {
const uint8_t *x;
char *r, *z;
assert(p || l == 0);
z = r = new(char, l * 2 + 1);
if (!r)
return NULL;
for (x = p; x < (const uint8_t*) p + l; x++) {
for (x = p; x && x < (const uint8_t*) p + l; x++) {
*(z++) = hexchar(*x >> 4);
*(z++) = hexchar(*x & 15);
}
@@ -606,7 +608,7 @@ ssize_t base64mem_full(
if (!r)
return -ENOMEM;
for (x = p; x < (const uint8_t*) p + (l / 3) * 3; x += 3) {
for (x = p; x && x < (const uint8_t*) p + (l / 3) * 3; x += 3) {
/* x[0] == XXXXXXXX; x[1] == YYYYYYYY; x[2] == ZZZZZZZZ */
maybe_line_break(&z, r, line_break);
*(z++) = base64char(x[0] >> 2); /* 00XXXXXX */
@@ -649,58 +651,74 @@ ssize_t base64mem_full(
return z - r;
}
static int base64_append_width(
char **prefix, int plen,
char sep, int indent,
const void *p, size_t l,
int width) {
static ssize_t base64_append_width(
char **prefix,
size_t plen,
char sep,
size_t indent,
const void *p,
size_t l,
size_t width) {
_cleanup_free_ char *x = NULL;
char *t, *s;
ssize_t len, avail, line, lines;
size_t lines;
ssize_t len;
assert(prefix);
assert(*prefix || plen == 0);
assert(p || l == 0);
len = base64mem(p, l, &x);
if (len <= 0)
if (len < 0)
return len;
if (len == 0)
return plen;
lines = DIV_ROUND_UP(len, width);
if ((size_t) plen >= SSIZE_MAX - 1 - 1 ||
if (plen >= SSIZE_MAX - 1 - 1 ||
lines > (SSIZE_MAX - plen - 1 - 1) / (indent + width + 1))
return -ENOMEM;
t = realloc(*prefix, (ssize_t) plen + 1 + 1 + (indent + width + 1) * lines);
t = realloc(*prefix, plen + 1 + 1 + (indent + width + 1) * lines);
if (!t)
return -ENOMEM;
t[plen] = sep;
s = t + plen;
for (size_t line = 0; line < lines; line++) {
size_t act = MIN(width, (size_t) len);
for (line = 0, s = t + plen + 1, avail = len; line < lines; line++) {
int act = MIN(width, avail);
if (line > 0)
sep = '\n';
if (line > 0 || sep == '\n') {
memset(s, ' ', indent);
s += indent;
if (s > t) {
*s++ = sep;
if (sep == '\n')
s = mempset(s, ' ', indent);
}
s = mempcpy(s, x + width * line, act);
*(s++) = line < lines - 1 ? '\n' : '\0';
avail -= act;
len -= act;
}
assert(avail == 0);
assert(len == 0);
*s = '\0';
*prefix = t;
return 0;
return s - t;
}
int base64_append(
char **prefix, int plen,
const void *p, size_t l,
int indent, int width) {
ssize_t base64_append(
char **prefix,
size_t plen,
const void *p,
size_t l,
size_t indent,
size_t width) {
if (plen > width / 2 || plen + indent > width)
/* leave indent on the left, keep last column free */
return base64_append_width(prefix, plen, '\n', indent, p, l, width - indent - 1);
return base64_append_width(prefix, plen, '\n', indent, p, l, width - indent);
else
/* leave plen on the left, keep last column free */
return base64_append_width(prefix, plen, ' ', plen + 1, p, l, width - plen - 1);
+7 -3
View File
@@ -38,9 +38,13 @@ static inline ssize_t base64mem(const void *p, size_t l, char **ret) {
return base64mem_full(p, l, SIZE_MAX, ret);
}
int base64_append(char **prefix, int plen,
const void *p, size_t l,
int margin, int width);
ssize_t base64_append(
char **prefix,
size_t plen,
const void *p,
size_t l,
size_t margin,
size_t width);
int unbase64mem_full(const char *p, size_t l, bool secure, void **mem, size_t *len);
static inline int unbase64mem(const char *p, size_t l, void **mem, size_t *len) {
return unbase64mem_full(p, l, false, mem, len);
+33 -17
View File
@@ -1889,6 +1889,36 @@ static int type_bitmap_to_json(Bitmap *b, JsonVariant **ret) {
return 0;
}
static int txt_to_json(DnsTxtItem *items, JsonVariant **ret) {
JsonVariant **elements = NULL;
size_t n = 0;
int r;
assert(ret);
LIST_FOREACH(items, i, items) {
if (!GREEDY_REALLOC(elements, n + 1)) {
r = -ENOMEM;
goto finalize;
}
r = json_variant_new_octescape(elements + n, i->data, i->length);
if (r < 0)
goto finalize;
n++;
}
r = json_variant_new_array(ret, elements, n);
finalize:
for (size_t i = 0; i < n; i++)
json_variant_unref(elements[i]);
free(elements);
return r;
}
int dns_resource_record_to_json(DnsResourceRecord *rr, JsonVariant **ret) {
_cleanup_(json_variant_unrefp) JsonVariant *k = NULL;
int r;
@@ -1931,23 +1961,9 @@ int dns_resource_record_to_json(DnsResourceRecord *rr, JsonVariant **ret) {
case DNS_TYPE_TXT: {
_cleanup_(json_variant_unrefp) JsonVariant *l = NULL;
LIST_FOREACH(items, i, rr->txt.items) {
_cleanup_(json_variant_unrefp) JsonVariant *b = NULL;
r = json_variant_new_octescape(&b, i->data, i->length);
if (r < 0)
return r;
r = json_variant_append_array(&l, b);
if (r < 0)
return r;
}
if (!l) {
r = json_variant_new_array(&l, NULL, 0);
if (r < 0)
return r;
}
r = txt_to_json(rr->txt.items, &l);
if (r < 0)
return r;
return json_build(ret,
JSON_BUILD_OBJECT(
+133
View File
@@ -73,6 +73,25 @@ TEST(undecchar) {
assert_se(undecchar('9') == 9);
}
static void test_hexmem_one(const char *in, const char *expected) {
_cleanup_free_ char *result = NULL;
_cleanup_free_ void *mem = NULL;
size_t len;
assert_se(result = hexmem(in, strlen_ptr(in)));
log_debug("hexmem(\"%s\") → \"%s\" (expected: \"%s\")", strnull(in), result, expected);
assert_se(streq(result, expected));
assert_se(unhexmem(result, SIZE_MAX, &mem, &len) >= 0);
assert_se(memcmp_safe(mem, in, len) == 0);
}
TEST(hexmem) {
test_hexmem_one(NULL, "");
test_hexmem_one("", "");
test_hexmem_one("foo", "666f6f");
}
static void test_unhexmem_one(const char *s, size_t l, int retval) {
_cleanup_free_ char *hex = NULL;
_cleanup_free_ void *mem = NULL;
@@ -308,6 +327,120 @@ TEST(base64mem_linebreak) {
}
}
static void test_base64_append_one(char **buf, size_t *len, const char *in, const char *expected) {
ssize_t new_len;
new_len = base64_append(buf, *len, in, strlen_ptr(in), 8, 12);
assert_se(new_len >= 0);
log_debug("base64_append_one(\"%s\")\nresult:\n%s\nexpected:\n%s", in, strnull(*buf), strnull(expected));
assert_se((size_t) new_len == strlen_ptr(*buf));
assert_se(streq_ptr(*buf, expected));
*len = new_len;
}
TEST(base64_append) {
_cleanup_free_ char *buf = NULL;
size_t len = 0;
test_base64_append_one(&buf, &len, "", NULL);
test_base64_append_one(&buf, &len, "f",
"Zg==");
test_base64_append_one(&buf, &len, "fo",
"Zg== Zm8=");
test_base64_append_one(&buf, &len, "foo",
"Zg== Zm8=\n"
" Zm9v");
test_base64_append_one(&buf, &len, "foob",
"Zg== Zm8=\n"
" Zm9v\n"
" Zm9v\n"
" Yg==");
test_base64_append_one(&buf, &len, "fooba",
"Zg== Zm8=\n"
" Zm9v\n"
" Zm9v\n"
" Yg==\n"
" Zm9v\n"
" YmE=");
test_base64_append_one(&buf, &len, "foobar",
"Zg== Zm8=\n"
" Zm9v\n"
" Zm9v\n"
" Yg==\n"
" Zm9v\n"
" YmE=\n"
" Zm9v\n"
" YmFy");
assert_se(free_and_strdup(&buf, "hogehogehogehoge") >= 0);
len = strlen(buf);
test_base64_append_one(&buf, &len, "",
"hogehogehogehoge");
test_base64_append_one(&buf, &len, "f",
"hogehogehogehoge\n"
" Zg==");
test_base64_append_one(&buf, &len, "fo",
"hogehogehogehoge\n"
" Zg==\n"
" Zm8=");
test_base64_append_one(&buf, &len, "foo",
"hogehogehogehoge\n"
" Zg==\n"
" Zm8=\n"
" Zm9v");
test_base64_append_one(&buf, &len, "foob",
"hogehogehogehoge\n"
" Zg==\n"
" Zm8=\n"
" Zm9v\n"
" Zm9v\n"
" Yg==");
test_base64_append_one(&buf, &len, "fooba",
"hogehogehogehoge\n"
" Zg==\n"
" Zm8=\n"
" Zm9v\n"
" Zm9v\n"
" Yg==\n"
" Zm9v\n"
" YmE=");
test_base64_append_one(&buf, &len, "foobar",
"hogehogehogehoge\n"
" Zg==\n"
" Zm8=\n"
" Zm9v\n"
" Zm9v\n"
" Yg==\n"
" Zm9v\n"
" YmE=\n"
" Zm9v\n"
" YmFy");
assert_se(free_and_strdup(&buf, "hogehogehogehoge") >= 0);
len = strlen(buf);
test_base64_append_one(&buf, &len, "foobarfoobarfoobarfoobar",
"hogehogehogehoge\n"
" Zm9v\n"
" YmFy\n"
" Zm9v\n"
" YmFy\n"
" Zm9v\n"
" YmFy\n"
" Zm9v\n"
" YmFy");
assert_se(free_and_strdup(&buf, "aaa") >= 0);
len = strlen(buf);
test_base64_append_one(&buf, &len, "foobarfoobarfoobarfoobar",
"aaa Zm9vYmFy\n"
" Zm9vYmFy\n"
" Zm9vYmFy\n"
" Zm9vYmFy");
}
static void test_unbase64mem_one(const char *input, const char *output, int ret) {
_cleanup_free_ void *buffer = NULL;
size_t size = 0;
Binary file not shown.
Binary file not shown.
Binary file not shown.