diff --git a/common/percent.c b/common/percent.c index 569c5fd99..eeb026fbe 100644 --- a/common/percent.c +++ b/common/percent.c @@ -87,6 +87,50 @@ percent_plus_escape (const char *string) } +/* Create a newly alloced string from (DATA,DATALEN) with embedded + * Nuls quoted as %00. The standard percent unescaping can be + * used to reverse this encoding. */ +char * +percent_data_escape (const void *data, size_t datalen) +{ + char *buffer, *p; + const char *s; + size_t n, length; + + for (length=1, s=data, n=datalen; n; s++, n--) + { + if (!*s || *s == '%') + length += 3; + else + length++; + } + + buffer = p = xtrymalloc (length); + if (!buffer) + return NULL; + + for (s=data, n=datalen; n; s++, n--) + { + if (!*s) + { + memcpy (p, "%00", 3); + p += 3; + } + else if (*s == '%') + { + memcpy (p, "%25", 3); + p += 3; + } + else + *p++ = *s; + } + *p = 0; + + return buffer; + +} + + /* Do the percent and plus/space unescaping from STRING to BUFFER and return the length of the valid buffer. Plus unescaping is only done if WITHPLUS is true. An escaped Nul character will be diff --git a/common/t-percent.c b/common/t-percent.c index 145a89bf3..94ece9249 100644 --- a/common/t-percent.c +++ b/common/t-percent.c @@ -99,6 +99,55 @@ test_percent_plus_escape (void) } +static void +test_percent_data_escape (void) +{ + static struct { + const char *data; + size_t datalen; + const char *expect; + } tbl[] = { + { + "", 0, + "" + }, { + "a", 1, + "a", + }, { + "%22", 3, + "%2522" + }, { + "%%", 3, + "%25%25%00" + }, { + "\n \0BC\t", 6, + "\n %00BC\t" + }, { NULL, 0, NULL } + }; + char *buf; + int i; + size_t len; + + for (i=0; tbl[i].data; i++) + { + buf = percent_data_escape (tbl[i].data, tbl[i].datalen); + if (!buf) + { + fprintf (stderr, "out of core: %s\n", strerror (errno)); + exit (2); + } + if (strcmp (buf, tbl[i].expect)) + fail (i); + len = percent_plus_unescape_inplace (buf, 0); + if (len != tbl[i].datalen) + fail (i); + else if (memcmp (buf, tbl[i].data, tbl[i].datalen)) + fail (i); + xfree (buf); + } +} + + int main (int argc, char **argv) @@ -109,6 +158,6 @@ main (int argc, char **argv) /* FIXME: We escape_unescape is not tested - only percent_plus_unescape. */ test_percent_plus_escape (); - + test_percent_data_escape (); return 0; } diff --git a/common/util.h b/common/util.h index 123d88079..682415d92 100644 --- a/common/util.h +++ b/common/util.h @@ -201,6 +201,7 @@ char *hex2str_alloc (const char *hexstring, size_t *r_count); /*-- percent.c --*/ char *percent_plus_escape (const char *string); +char *percent_data_escape (const void *data, size_t datalen); char *percent_plus_unescape (const char *string, int nulrepl); char *percent_unescape (const char *string, int nulrepl);