diff --git a/src/utils/common.c b/src/utils/common.c index 99861aeba..c814e89a7 100644 --- a/src/utils/common.c +++ b/src/utils/common.c @@ -344,6 +344,135 @@ TCHAR * wpa_strdup_tchar(const char *str) #endif /* CONFIG_NATIVE_WINDOWS */ +void printf_encode(char *txt, size_t maxlen, const u8 *data, size_t len) +{ + char *end = txt + maxlen; + size_t i; + + for (i = 0; i < len; i++) { + if (txt + 4 > end) + break; + + switch (data[i]) { + case '\"': + *txt++ = '\\'; + *txt++ = '\"'; + break; + case '\\': + *txt++ = '\\'; + *txt++ = '\\'; + break; + case '\e': + *txt++ = '\\'; + *txt++ = 'e'; + break; + case '\n': + *txt++ = '\\'; + *txt++ = 'n'; + break; + case '\r': + *txt++ = '\\'; + *txt++ = 'r'; + break; + case '\t': + *txt++ = '\\'; + *txt++ = 't'; + break; + default: + if (data[i] >= 32 && data[i] <= 127) { + *txt++ = data[i]; + } else { + txt += os_snprintf(txt, end - txt, "\\x%02x", + data[i]); + } + break; + } + } + + *txt = '\0'; +} + + +size_t printf_decode(u8 *buf, size_t maxlen, const char *str) +{ + const char *pos = str; + size_t len = 0; + int val; + + while (*pos) { + if (len == maxlen) + break; + switch (*pos) { + case '\\': + pos++; + switch (*pos) { + case '\\': + buf[len++] = '\\'; + pos++; + break; + case '"': + buf[len++] = '"'; + pos++; + break; + case 'n': + buf[len++] = '\n'; + pos++; + break; + case 'r': + buf[len++] = '\r'; + pos++; + break; + case 't': + buf[len++] = '\t'; + pos++; + break; + case 'e': + buf[len++] = '\e'; + pos++; + break; + case 'x': + pos++; + val = hex2byte(pos); + if (val < 0) { + val = hex2num(*pos); + if (val < 0) + break; + buf[len++] = val; + pos++; + } else { + buf[len++] = val; + pos += 2; + } + break; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + val = *pos++ - '0'; + if (*pos >= '0' && *pos <= '7') + val = val * 8 + (*pos++ - '0'); + if (*pos >= '0' && *pos <= '7') + val = val * 8 + (*pos++ - '0'); + buf[len++] = val; + break; + default: + break; + } + break; + default: + buf[len++] = *pos++; + break; + } + } + + return len; +} + + /** * wpa_ssid_txt - Convert SSID to a printable string * @ssid: SSID (32-octet string) diff --git a/src/utils/common.h b/src/utils/common.h index 7f115efe8..fbc61191e 100644 --- a/src/utils/common.h +++ b/src/utils/common.h @@ -441,6 +441,9 @@ TCHAR * wpa_strdup_tchar(const char *str); #define wpa_strdup_tchar(s) strdup((s)) #endif /* CONFIG_NATIVE_WINDOWS */ +void printf_encode(char *txt, size_t maxlen, const u8 *data, size_t len); +size_t printf_decode(u8 *buf, size_t maxlen, const char *str); + const char * wpa_ssid_txt(const u8 *ssid, size_t ssid_len); static inline int is_zero_ether_addr(const u8 *a) diff --git a/tests/.gitignore b/tests/.gitignore index 39c7447fd..bef38cfa9 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -7,6 +7,7 @@ test-md4 test-md5 test-milenage test-ms_funcs +test-printf test-rc4 test-sha1 test-sha256 diff --git a/tests/Makefile b/tests/Makefile index 0774337e7..d49633084 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -1,4 +1,6 @@ -TESTS=test-base64 test-md4 test-md5 test-milenage test-ms_funcs test-sha1 \ +TESTS=test-base64 test-md4 test-md5 test-milenage test-ms_funcs \ + test-printf \ + test-sha1 \ test-sha256 test-aes test-asn1 test-x509 test-x509v3 test-list test-rc4 all: $(TESTS) @@ -63,6 +65,9 @@ test-milenage: test-milenage.o $(LIBS) test-ms_funcs: test-ms_funcs.o $(LIBS) $(LDO) $(LDFLAGS) -o $@ $^ +test-printf: test-printf.o $(LIBS) + $(LDO) $(LDFLAGS) -o $@ $^ + test-rc4: test-rc4.o $(LIBS) $(LDO) $(LDFLAGS) -o $@ $^ @@ -85,6 +90,7 @@ run-tests: $(TESTS) ./test-md4 ./test-md5 ./test-milenage + ./test-printf ./test-sha1 ./test-sha256 @echo diff --git a/tests/test-printf.c b/tests/test-printf.c new file mode 100644 index 000000000..a8a2e258e --- /dev/null +++ b/tests/test-printf.c @@ -0,0 +1,83 @@ +/* + * printf format routines - test program + * Copyright (c) 2012, Jouni Malinen + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#include "utils/includes.h" +#include "utils/os.h" +#include "utils/common.h" + + +struct test_data { + u8 *data; + size_t len; + char *encoded; +}; + +static const struct test_data tests[] = { + { (u8 *) "abcde", 5, "abcde" }, + { (u8 *) "a\0b\nc\ed\re\tf", 11, "a\\0b\\nc\\ed\\re\\tf" }, + { (u8 *) "\x00\x31\x00\x32\x00\x39", 6, "\\x001\\0002\\09" }, + { (u8 *) "\n\n\n", 3, "\n\12\x0a" }, + { (u8 *) "\303\245\303\244\303\266\303\205\303\204\303\226", 12, + "\\xc3\\xa5\xc3\\xa4\\xc3\\xb6\\xc3\\x85\\xc3\\x84\\xc3\\x96" }, + { (u8 *) "\303\245\303\244\303\266\303\205\303\204\303\226", 12, + "\\303\\245\\303\\244\\303\\266\\303\\205\\303\\204\\303\\226" }, + { (u8 *) "\xe5\xe4\xf6\xc5\xc4\xd6", 6, + "\\xe5\\xe4\\xf6\\xc5\\xc4\\xd6" }, + { NULL, 0, NULL } +}; + + +static void print_hex(const u8 *data, size_t len) +{ + size_t i; + for (i = 0; i < len; i++) + printf(" %02x", data[i]); +} + + +int main(int argc, char *argv[]) +{ + int i; + size_t binlen; + char buf[100]; + u8 bin[100]; + int errors = 0; + + for (i = 0; tests[i].data; i++) { + const struct test_data *test = &tests[i]; + printf("%d:", i); + print_hex(test->data, test->len); + printf_encode(buf, sizeof(buf), test->data, test->len); + printf(" -> \"%s\"\n", buf); + + binlen = printf_decode(bin, sizeof(bin), buf); + if (binlen != test->len || + os_memcmp(bin, test->data, binlen) != 0) { + printf("Error in decoding#1:"); + print_hex(bin, binlen); + printf("\n"); + errors++; + } + + binlen = printf_decode(bin, sizeof(bin), test->encoded); + if (binlen != test->len || + os_memcmp(bin, test->data, binlen) != 0) { + printf("Error in decoding#2:"); + print_hex(bin, binlen); + printf("\n"); + errors++; + } + } + + if (errors) { + printf("%d test(s) failed\n", errors); + return -1; + } + + return 0; +}