Browse Source

Add %H

PUBLISHED_FROM=8345a4602c0b1f2898a52872e6e1d4f86dac07ad
Sergey Lyubka 8 years ago
parent
commit
46dbb25e1d
3 changed files with 54 additions and 0 deletions
  1. 31 0
      frozen.c
  2. 6 0
      frozen.h
  3. 17 0
      unit_test.c

+ 31 - 0
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) {
 static int b64enc(struct json_out *out, const unsigned char *p, int n) {
   char buf[4];
   char buf[4];
   int i, len = 0;
   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);
         int val = va_arg(ap, int);
         const char *str = val ? "true" : "false";
         const char *str = val ? "true" : "false";
         len += out->printer(out, str, strlen(str));
         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') {
       } else if (fmt[1] == 'V') {
         const unsigned char *p = va_arg(ap, const unsigned char *);
         const unsigned char *p = va_arg(ap, const unsigned char *);
         int n = va_arg(ap, int);
         int n = va_arg(ap, int);
@@ -857,6 +874,19 @@ static void json_scanf_cb(void *callback_data, const char *name,
       }
       }
       break;
       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': {
     case 'V': {
       char **dst = (char **) info->target;
       char **dst = (char **) info->target;
       int len = token->len * 4 / 3 + 2;
       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]) {
       switch (fmt[i + 1]) {
         case 'M':
         case 'M':
         case 'V':
         case 'V':
+        case 'H':
           info.user_data = va_arg(ap, void *);
           info.user_data = va_arg(ap, void *);
         /* FALLTHROUGH */
         /* FALLTHROUGH */
         case 'B':
         case 'B':

+ 6 - 0
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` print quoted escaped string or `null`. Accepts a `const char *`.
  *  - `%.*Q` same as `%Q`, but with length. Accepts `int`, `const char *`
  *  - `%.*Q` same as `%Q`, but with length. Accepts `int`, `const char *`
  *  - `%V` print quoted base64-encoded string. Accepts a `const char *`, `int`.
  *  - `%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
  *  - `%M` invokes a json_printf_callback_t function. That callback function
  *  can consume more parameters.
  *  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.
  *       Result string is base64-decoded, malloced and NUL-terminated.
  *       The length of result string is stored in `int *` placeholder.
  *       The length of result string is stored in `int *` placeholder.
  *       Caller must free() the result.
  *       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
  *    - %M: consumes custom scanning function pointer and
  *       `void *user_data` parameter - see json_scanner_t definition.
  *       `void *user_data` parameter - see json_scanner_t definition.
  *    - %T: consumes `struct json_token *`, fills it out with matched token.
  *    - %T: consumes `struct json_token *`, fills it out with matched token.

+ 17 - 0
unit_test.c

@@ -315,6 +315,13 @@ static const char *test_json_printf(void) {
     ASSERT(strcmp(buf, "\"ACABIAIgYWJj\"") == 0);
     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;
   return NULL;
 }
 }
 
 
@@ -499,6 +506,16 @@ static const char *test_scanf(void) {
     free(result);
     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=\" }";
     const char *str = "{a : \"0L/RgNC40LLQtdGC0Ys=\" }";
     int len;
     int len;