Add routines for encoding/decoding printf escaping mechanism
This can be used to build ASCII strings from binary data that is more likely to use ASCII (i.e., text format is more natural option than hexdump, but there is possibility of some non-ASCII characters). Signed-hostap: Jouni Malinen <j@w1.fi>
This commit is contained in:
parent
059d3a9075
commit
0d7773b63f
5 changed files with 223 additions and 1 deletions
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
1
tests/.gitignore
vendored
1
tests/.gitignore
vendored
|
@ -7,6 +7,7 @@ test-md4
|
|||
test-md5
|
||||
test-milenage
|
||||
test-ms_funcs
|
||||
test-printf
|
||||
test-rc4
|
||||
test-sha1
|
||||
test-sha256
|
||||
|
|
|
@ -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
|
||||
|
|
83
tests/test-printf.c
Normal file
83
tests/test-printf.c
Normal file
|
@ -0,0 +1,83 @@
|
|||
/*
|
||||
* printf format routines - test program
|
||||
* Copyright (c) 2012, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* 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;
|
||||
}
|
Loading…
Reference in a new issue