From 047ebb958b682bc058097eddc34df574c3f3d6d4 Mon Sep 17 00:00:00 2001 From: Timo Sirainen Date: Tue, 16 Jun 2009 13:49:18 -0400 Subject: [PATCH] Added str_append_tabunescaped(). str_tabescape*() now escapes also CR. Added unit tests. --HG-- branch : HEAD --- src/lib/Makefile.am | 1 + src/lib/strescape.c | 52 +++++++++++++++++++++++++++-- src/lib/strescape.h | 3 +- src/lib/test-lib.c | 1 + src/lib/test-lib.h | 1 + src/lib/test-strescape.c | 72 ++++++++++++++++++++++++++++++++++++++++ 6 files changed, 127 insertions(+), 3 deletions(-) create mode 100644 src/lib/test-strescape.c diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am index 57f3e2f2b2..9e0655d084 100644 --- a/src/lib/Makefile.am +++ b/src/lib/Makefile.am @@ -221,6 +221,7 @@ test_lib_SOURCES = \ test-primes.c \ test-priorityq.c \ test-seq-range-array.c \ + test-strescape.c \ test-str-find.c \ test-str-sanitize.c \ test-utc-mktime.c diff --git a/src/lib/strescape.c b/src/lib/strescape.c index 4d08a105f7..aa8c154f77 100644 --- a/src/lib/strescape.c +++ b/src/lib/strescape.c @@ -65,8 +65,11 @@ char *str_unescape(char *str) } for (dest = str; *str != '\0'; str++) { - if (*str == '\\' && str[1] != '\0') + if (*str == '\\') { str++; + if (*str == '\0') + break; + } *dest++ = *str; } @@ -87,6 +90,10 @@ void str_tabescape_write(string_t *dest, const char *src) str_append_c(dest, '\001'); str_append_c(dest, 't'); break; + case '\r': + str_append_c(dest, '\001'); + str_append_c(dest, 'r'); + break; case '\n': str_append_c(dest, '\001'); str_append_c(dest, 'n'); @@ -104,7 +111,7 @@ const char *str_tabescape(const char *str) const char *p; for (p = str; *p != '\0'; p++) { - if (*p <= '\n') { + if (*p <= '\r') { tmp = t_str_new(128); str_append_n(tmp, str, p-str); str_tabescape_write(tmp, p); @@ -113,3 +120,44 @@ const char *str_tabescape(const char *str) } return str; } + +void str_append_tabunescaped(string_t *dest, const void *src, size_t src_size) +{ + const unsigned char *src_c = src; + size_t start = 0, i = 0; + + while (i < src_size) { + start = i; + for (; i < src_size; i++) { + if (src_c[i] == '\001') + break; + } + + str_append_n(dest, src_c + start, i-start); + + if (i < src_size) { + i++; + if (i < src_size) { + switch (src_c[i]) { + case '1': + str_append_c(dest, '\001'); + break; + case 't': + str_append_c(dest, '\t'); + break; + case 'r': + str_append_c(dest, '\r'); + break; + case 'n': + str_append_c(dest, '\n'); + break; + default: + str_append_c(dest, src_c[i]); + break; + } + i++; + } + } + start = i; + } +} diff --git a/src/lib/strescape.h b/src/lib/strescape.h index 0918b65bf9..c9d6ee159b 100644 --- a/src/lib/strescape.h +++ b/src/lib/strescape.h @@ -12,9 +12,10 @@ void str_append_unescaped(string_t *dest, const void *src, size_t src_size); /* remove all '\' characters */ char *str_unescape(char *str); -/* For Dovecot's internal protocols: Escape \001, \t and \n characters +/* For Dovecot's internal protocols: Escape \001, \t, \r and \n characters using \001. */ const char *str_tabescape(const char *str); void str_tabescape_write(string_t *dest, const char *src); +void str_append_tabunescaped(string_t *dest, const void *src, size_t src_size); #endif diff --git a/src/lib/test-lib.c b/src/lib/test-lib.c index 21cd0bbb78..fa6befdfb8 100644 --- a/src/lib/test-lib.c +++ b/src/lib/test-lib.c @@ -16,6 +16,7 @@ int main(void) test_primes, test_priorityq, test_seq_range_array, + test_strescape, test_str_find, test_str_sanitize, test_utc_mktime, diff --git a/src/lib/test-lib.h b/src/lib/test-lib.h index 97c1b9686a..84ca1d5a99 100644 --- a/src/lib/test-lib.h +++ b/src/lib/test-lib.h @@ -15,6 +15,7 @@ void test_network(void); void test_primes(void); void test_priorityq(void); void test_seq_range_array(void); +void test_strescape(void); void test_str_find(void); void test_str_sanitize(void); void test_utc_mktime(void); diff --git a/src/lib/test-strescape.c b/src/lib/test-strescape.c new file mode 100644 index 0000000000..165b0a9d90 --- /dev/null +++ b/src/lib/test-strescape.c @@ -0,0 +1,72 @@ +/* Copyright (c) 2009 Dovecot authors, see the included COPYING file */ + +#include "test-lib.h" +#include "str.h" +#include "strescape.h" + +struct strinput { + const char *input; + const char *output; +}; + +void test_strescape(void) +{ + static struct strinput unesc[] = { + { "foo", "foo" }, + { "\\\\\\\\\\\"\\\"\\\'\\\'", "\\\\\"\"\'\'" }, + { "\\a\\n\\r\\", "anr" } + }; + static struct strinput tabesc[] = { + { "foo", "foo" }, + { "\001", "\0011" }, + { "\t", "\001t" }, + { "\r", "\001r" }, + { "\n", "\001n" }, + { "\001\001\t\t\r\r\n\n", "\0011\0011\001t\001t\001r\001r\001n\001n" } + }; + unsigned char buf[1 << CHAR_BIT]; + const char *escaped; + string_t *str; + unsigned int i; + + test_begin("str_escape"); + for (i = 1; i < sizeof(buf); i++) + buf[i-1] = i; + buf[i-1] = '\0'; + + escaped = str_escape((char *)buf); + test_assert(strlen(escaped) == (1 << CHAR_BIT) - 1 + 3); + test_assert(escaped['\"'-1] == '\\'); /* 34 */ + test_assert(escaped['\"'] == '\"'); + test_assert(escaped['\''+1-1] == '\\'); /* 39 */ + test_assert(escaped['\''+1] == '\''); + test_assert(escaped['\\'+2-1] == '\\'); /* 92 */ + test_assert(escaped['\\'+2] == '\\'); + test_assert(strcmp(str_escape("\\\\\"\"\'\'"), + "\\\\\\\\\\\"\\\"\\\'\\\'") == 0); + test_end(); + + str = t_str_new(256); + test_begin("str_unescape"); + for (i = 0; i < N_ELEMENTS(unesc); i++) { + test_assert(strcmp(str_unescape(t_strdup_noconst(unesc[i].input)), + unesc[i].output) == 0); + str_truncate(str, 0); + str_append_unescaped(str, unesc[i].input, strlen(unesc[i].input)); + test_assert(strcmp(str_c(str), unesc[i].output) == 0); + } + test_end(); + + test_begin("str_tabescape"); + for (i = 0; i < N_ELEMENTS(tabesc); i++) { + test_assert(strcmp(str_tabescape(tabesc[i].input), + tabesc[i].output) == 0); + str_truncate(str, 0); + str_append_tabunescaped(str, tabesc[i].output, strlen(tabesc[i].output)); + test_assert(strcmp(str_c(str), tabesc[i].input) == 0); + } + str_truncate(str, 0); + str_append_tabunescaped(str, "\0012\001l\001", strlen("\0012\001l\001")); + test_assert(strcmp(str_c(str), "2l") == 0); + test_end(); +} -- 2.47.3