From 46dbb25e1d9cf8c44381602d6e6d34e6e5f32409 Mon Sep 17 00:00:00 2001 From: Sergey Lyubka Date: Fri, 30 Dec 2016 15:52:18 +0000 Subject: [PATCH] Add %H PUBLISHED_FROM=8345a4602c0b1f2898a52872e6e1d4f86dac07ad --- frozen.c | 31 +++++++++++++++++++++++++++++++ frozen.h | 6 ++++++ unit_test.c | 17 +++++++++++++++++ 3 files changed, 54 insertions(+) diff --git a/frozen.c b/frozen.c index e2fcdcf..3de1999 100644 --- a/frozen.c +++ b/frozen.c @@ -491,6 +491,13 @@ static int b64rev(int c) { } } +static uint8_t hexdec(const char *s) { +#define HEXTOI(x) (x >= '0' && x <= '9' ? x - '0' : x - 'W') + int a = tolower(*(const unsigned char *) s); + int b = tolower(*(const unsigned char *) (s + 1)); + return (HEXTOI(a) << 4) | HEXTOI(b); +} + static int b64enc(struct json_out *out, const unsigned char *p, int n) { char buf[4]; int i, len = 0; @@ -557,6 +564,16 @@ int json_vprintf(struct json_out *out, const char *fmt, va_list xap) { int val = va_arg(ap, int); const char *str = val ? "true" : "false"; len += out->printer(out, str, strlen(str)); + } else if (fmt[1] == 'H') { + const char *hex = "0123456789abcdef"; + int i, n = va_arg(ap, int); + const unsigned char *p = va_arg(ap, const unsigned char *); + len += out->printer(out, quote, 1); + for (i = 0; i < n; i++) { + len += out->printer(out, &hex[(p[i] >> 4) & 0xf], 1); + len += out->printer(out, &hex[p[i] & 0xf], 1); + } + len += out->printer(out, quote, 1); } else if (fmt[1] == 'V') { const unsigned char *p = va_arg(ap, const unsigned char *); int n = va_arg(ap, int); @@ -857,6 +874,19 @@ static void json_scanf_cb(void *callback_data, const char *name, } break; } + case 'H': { + char **dst = (char **) info->user_data; + int i, len = token->len / 2; + *(int *) info->target = len; + if ((*dst = (char *) malloc(len + 1)) != NULL) { + for (i = 0; i < len; i++) { + (*dst)[i] = hexdec(token->ptr + 2 * i); + } + (*dst)[len] = '\0'; + info->num_conversions++; + } + break; + } case 'V': { char **dst = (char **) info->target; int len = token->len * 4 / 3 + 2; @@ -897,6 +927,7 @@ int json_vscanf(const char *s, int len, const char *fmt, va_list ap) { switch (fmt[i + 1]) { case 'M': case 'V': + case 'H': info.user_data = va_arg(ap, void *); /* FALLTHROUGH */ case 'B': diff --git a/frozen.h b/frozen.h index 31aaff6..6822d33 100644 --- a/frozen.h +++ b/frozen.h @@ -140,6 +140,7 @@ typedef int (*json_printf_callback_t)(struct json_out *, va_list *ap); * - `%Q` print quoted escaped string or `null`. Accepts a `const char *`. * - `%.*Q` same as `%Q`, but with length. Accepts `int`, `const char *` * - `%V` print quoted base64-encoded string. Accepts a `const char *`, `int`. + * - `%H` print quoted hex-encoded string. Accepts a `int`, `const char *`. * - `%M` invokes a json_printf_callback_t function. That callback function * can consume more parameters. * @@ -171,6 +172,11 @@ int json_printf_array(struct json_out *, va_list *ap); * Result string is base64-decoded, malloced and NUL-terminated. * The length of result string is stored in `int *` placeholder. * Caller must free() the result. + * - %H: consumes `int *`, `char **`. + * Expects a hex-encoded string, e.g. "fa014f". + * Result string is hex-decoded, malloced and NUL-terminated. + * The length of the result string is stored in `int *` placeholder. + * Caller must free() the result. * - %M: consumes custom scanning function pointer and * `void *user_data` parameter - see json_scanner_t definition. * - %T: consumes `struct json_token *`, fills it out with matched token. diff --git a/unit_test.c b/unit_test.c index 6f39dcb..d7b7e33 100644 --- a/unit_test.c +++ b/unit_test.c @@ -315,6 +315,13 @@ static const char *test_json_printf(void) { ASSERT(strcmp(buf, "\"ACABIAIgYWJj\"") == 0); } + { + struct json_out out = JSON_OUT_BUF(buf, sizeof(buf)); + memset(buf, 0, sizeof(buf)); + ASSERT(json_printf(&out, "%H", 9, "\x00 \x01 \x02 abc") > 0); + ASSERT(strcmp(buf, "\"002001200220616263\"") == 0); + } + return NULL; } @@ -499,6 +506,16 @@ static const char *test_scanf(void) { free(result); } + { + const char *str = "{a : \"61626320\" }"; + int len = 0; + char *result = NULL; + ASSERT(json_scanf(str, strlen(str), "{a: %H}", &len, &result) == 1); + ASSERT(len == 4); + ASSERT(strcmp(result, "abc ") == 0); + free(result); + } + { const char *str = "{a : \"0L/RgNC40LLQtdGC0Ys=\" }"; int len;