Permalink
Browse files

Add %H

PUBLISHED_FROM=8345a4602c0b1f2898a52872e6e1d4f86dac07ad
1 parent d3c11e0 commit 46dbb25e1d9cf8c44381602d6e6d34e6e5f32409 @cpq cpq committed with cesantabot Dec 30, 2016
Showing with 54 additions and 0 deletions.
  1. +31 −0 frozen.c
  2. +6 −0 frozen.h
  3. +17 −0 unit_test.c
View
@@ -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':
View
@@ -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.
View
@@ -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;
}
@@ -500,6 +507,16 @@ static const char *test_scanf(void) {
}
{
+ 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;
char *result;

0 comments on commit 46dbb25

Please sign in to comment.