json_dumper: add base64 routines.
authorDario Lombardo <lomato@gmail.com>
Thu, 13 Dec 2018 14:39:21 +0000 (15:39 +0100)
committerPeter Wu <peter@lekensteyn.nl>
Sun, 23 Dec 2018 21:10:47 +0000 (21:10 +0000)
Change-Id: Iab9a201fe951e5557501f4e675ab74ecd9dbb930
Reviewed-on: https://code.wireshark.org/review/31034
Petri-Dish: Dario Lombardo <lomato@gmail.com>
Tested-by: Petri Dish Buildbot
Reviewed-by: Peter Wu <peter@lekensteyn.nl>
debian/libwsutil0.symbols
wsutil/json_dumper.c
wsutil/json_dumper.h

index 791decb8fe2995babfc7e6b5bf5c847c467c6632..61464924680e02b06dbf7d28740f79d00c6275c2 100644 (file)
@@ -102,13 +102,16 @@ libwsutil.so.0 libwsutil0 #MINVER#
  isprint_utf8_string@Base 2.6.1
  json_decode_string_inplace@Base 2.9.0
  json_dumper_begin_array@Base 2.9.0
+ json_dumper_begin_base64@Base 2.9.1
  json_dumper_begin_object@Base 2.9.0
  json_dumper_end_array@Base 2.9.0
+ json_dumper_end_base64@Base 2.9.1
  json_dumper_end_object@Base 2.9.0
  json_dumper_finish@Base 2.9.0
  json_dumper_set_member_name@Base 2.9.0
  json_dumper_value_anyf@Base 2.9.0
  json_dumper_value_string@Base 2.9.0
+ json_dumper_write_base64@Base 2.9.1
  json_parse@Base 2.9.0
  json_validate@Base 2.9.0
  linear2alaw@Base 1.12.0~rc1
index 195049c99d7b61475cb49544a86fb8abdffd76b0..5162b6b8c90ba84c2d46da57b1ef9fa6f761a381 100644 (file)
@@ -23,9 +23,10 @@ enum json_dumper_element_type {
     JSON_DUMPER_TYPE_VALUE = 1,
     JSON_DUMPER_TYPE_OBJECT = 2,
     JSON_DUMPER_TYPE_ARRAY = 3,
+    JSON_DUMPER_TYPE_BASE64 = 4,
 };
-#define JSON_DUMPER_TYPE(state)         ((enum json_dumper_element_type)((state) & 3))
-#define JSON_DUMPER_HAS_NAME            (1 << 2)
+#define JSON_DUMPER_TYPE(state)         ((enum json_dumper_element_type)((state) & 7))
+#define JSON_DUMPER_HAS_NAME            (1 << 3)
 
 #define JSON_DUMPER_FLAGS_ERROR     (1 << 16)   /* Output flag: an error occurred. */
 #define JSON_DUMPER_FLAGS_NO_DEBUG  (1 << 17)   /* Input flag: disable debug prints (intended for speeding up fuzzing). */
@@ -35,6 +36,7 @@ enum json_dumper_change {
     JSON_DUMPER_END,
     JSON_DUMPER_SET_NAME,
     JSON_DUMPER_SET_VALUE,
+    JSON_DUMPER_WRITE_BASE64,
     JSON_DUMPER_FINISH,
 };
 
@@ -137,10 +139,16 @@ json_dumper_check_state(json_dumper *dumper, enum json_dumper_change change, enu
                 ok = (prev_state & JSON_DUMPER_HAS_NAME);
             } else if (prev_type == JSON_DUMPER_TYPE_ARRAY) {
                 ok = TRUE;
+            } else if (prev_type == JSON_DUMPER_TYPE_BASE64) {
+                ok = FALSE;
             } else {
                 ok = JSON_DUMPER_TYPE(dumper->state[depth]) == JSON_DUMPER_TYPE_NONE;
             }
             break;
+        case JSON_DUMPER_WRITE_BASE64:
+            ok = (prev_type == JSON_DUMPER_TYPE_BASE64) &&
+                (type == JSON_DUMPER_TYPE_NONE || type == JSON_DUMPER_TYPE_BASE64);
+            break;
         case JSON_DUMPER_FINISH:
             ok = depth == 0;
             break;
@@ -324,3 +332,61 @@ json_dumper_finish(json_dumper *dumper)
     dumper->state[0] = 0;
     return TRUE;
 }
+
+void
+json_dumper_begin_base64(json_dumper *dumper)
+{
+    if (!json_dumper_check_state(dumper, JSON_DUMPER_BEGIN, JSON_DUMPER_TYPE_BASE64)) {
+        return;
+    }
+
+    dumper->base64_state = 0;
+    dumper->base64_save = 0;
+
+    prepare_token(dumper);
+
+    fputc('"', dumper->output_file);
+
+    dumper->state[dumper->current_depth] = JSON_DUMPER_TYPE_BASE64;
+    ++dumper->current_depth;
+    dumper->state[dumper->current_depth] = 0;
+}
+
+void
+json_dumper_write_base64(json_dumper* dumper, const guchar *data, size_t len)
+{
+    if (!json_dumper_check_state(dumper, JSON_DUMPER_WRITE_BASE64, JSON_DUMPER_TYPE_BASE64)) {
+        return;
+    }
+
+    #define CHUNK_SIZE 1024
+    gchar buf[(CHUNK_SIZE / 3 + 1) * 4 + 4];
+
+    while (len > 0) {
+        gsize chunk_size = len < CHUNK_SIZE ? len : CHUNK_SIZE;
+        gsize output_size = g_base64_encode_step(data, chunk_size, FALSE, buf, &dumper->base64_state, &dumper->base64_save);
+        fwrite(buf, 1, output_size, dumper->output_file);
+        data += chunk_size;
+        len -= chunk_size;
+    }
+
+    dumper->state[dumper->current_depth] = JSON_DUMPER_TYPE_BASE64;
+}
+
+void
+json_dumper_end_base64(json_dumper *dumper)
+{
+    if (!json_dumper_check_state(dumper, JSON_DUMPER_END, JSON_DUMPER_TYPE_BASE64)) {
+        return;
+    }
+
+    gchar buf[4];
+    gsize wrote;
+
+    wrote = g_base64_encode_close(FALSE, buf, &dumper->base64_state, &dumper->base64_save);
+    fwrite(buf, 1, wrote, dumper->output_file);
+
+    fputc('"', dumper->output_file);
+
+    --dumper->current_depth;
+}
index 68e1777d4677523120b797b6db898de4bd0d7b24..bc0d4cb010bbc3eb38707791159311063d7da5c0 100644 (file)
@@ -35,6 +35,10 @@ extern "C" {
  *  json_dumper_begin_array(&dumper);
  *  json_dumper_value_anyf(&dumper, "true");
  *  json_dumper_value_anyf(&dumper, "1.0");
+ *  json_dumper_begin_base64(&dumper);
+ *  json_dumper_write_base64(&dumper, (const guchar *)"abcd", 4);
+ *  json_dumper_write_base64(&dumper, (const guchar *)"1234", 4);
+ *  json_dumper_end_base64(&dumper);
  *  json_dumper_begin_object(&dumper);
  *  json_dumper_end_object(&dumper);
  *  json_dumper_begin_array(&dumper);
@@ -53,6 +57,8 @@ typedef struct json_dumper {
     int     flags;
     /* for internal use, initialize with zeroes. */
     int     current_depth;
+    gint    base64_state;
+    gint    base64_save;
     guint8  state[JSON_DUMPER_MAX_DEPTH];
 } json_dumper;
 
@@ -81,6 +87,15 @@ WS_DLL_PUBLIC void
 json_dumper_value_anyf(json_dumper *dumper, const char *format, ...)
 G_GNUC_PRINTF(2, 3);
 
+WS_DLL_PUBLIC void
+json_dumper_begin_base64(json_dumper *dumper);
+
+WS_DLL_PUBLIC void
+json_dumper_end_base64(json_dumper *dumper);
+
+WS_DLL_PUBLIC void
+json_dumper_write_base64(json_dumper *dumper, const guchar *data, size_t len);
+
 /**
  * Finishes dumping data. Returns TRUE if everything is okay and FALSE if
  * something went wrong (open/close mismatch, missing values, etc.).