adding library for basic JSON conversions
authorChristian Grothoff <christian@grothoff.org>
Thu, 17 Mar 2016 19:24:35 +0000 (19:24 +0000)
committerChristian Grothoff <christian@grothoff.org>
Thu, 17 Mar 2016 19:24:35 +0000 (19:24 +0000)
src/Makefile.am
src/include/Makefile.am
src/include/gnunet_json_lib.h [new file with mode: 0644]
src/include/gnunet_pq_lib.h
src/include/gnunet_time_lib.h
src/json/Makefile.am [new file with mode: 0644]
src/json/json.c [new file with mode: 0644]
src/json/json_generator.c [new file with mode: 0644]
src/json/json_helper.c [new file with mode: 0644]
src/json/test_json.c [new file with mode: 0644]
src/util/time.c

index edfbb6922f9292a88bb034444276145a5cbeca4c..47d6896cbcf0b8766c868e93bb1b3d3c6faf1289 100644 (file)
@@ -21,14 +21,18 @@ if HAVE_EXPERIMENTAL
   psyc \
   rps \
   social \
-       $(CONSENSUS) \
+  $(CONSENSUS) \
   $(SECRETSHARING) \
   $(SENSOR) \
   $(SENSORDASHBOARD)
 endif
 
 if HAVE_REST
-       EXP_DIR += identity-provider
+  PROVIDER_DIR = identity-provider
+endif
+
+if HAVE_JSON
+  JSON_DIR = json
 endif
 
 if BUILD_PULSE_HELPERS
@@ -60,7 +64,8 @@ else
 SUBDIRS = \
   include $(INTLEMU_SUBDIRS) \
   util \
-       $(REST_DIR) \
+  $(JSON_DIR) \
+  $(REST_DIR) \
   hello \
   tun \
   block \
@@ -104,6 +109,7 @@ SUBDIRS = \
   exit \
   pt \
   integration-tests \
-  $(EXP_DIR)
+  $(EXP_DIR) \
+  $(PROVIDER_DIR)
 
 endif
index 626089dbc8953afaf74ed43c8009426ee49a3d07..82fa9006b30be6c9cae8d9a8de0b7ed211be6dd7 100644 (file)
@@ -65,6 +65,7 @@ gnunetinclude_HEADERS = \
   gnunet_hello_lib.h \
   gnunet_helper_lib.h \
   gnunet_identity_service.h \
+  gnunet_json_lib.h \
   gnunet_load_lib.h \
   gnunet_cadet_service.h \
   gnunet_microphone_lib.h \
diff --git a/src/include/gnunet_json_lib.h b/src/include/gnunet_json_lib.h
new file mode 100644 (file)
index 0000000..e399388
--- /dev/null
@@ -0,0 +1,354 @@
+/*
+  This file is part of GNUnet
+  Copyright (C) 2014, 2015, 2016 GNUnet e.V.
+
+  GNUnet is free software; you can redistribute it and/or modify it under the
+  terms of the GNU General Public License as published by the Free Software
+  Foundation; either version 3, or (at your option) any later version.
+
+  GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY
+  WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+  A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License along with
+  GNUnet; see the file COPYING.  If not, If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file gnunet_json_lib.h
+ * @brief functions to parse JSON objects into GNUnet objects
+ * @author Florian Dold
+ * @author Benedikt Mueller
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include <gnunet/gnunet_util_lib.h>
+#include <jansson.h>
+
+
+/* ****************** Generic parser interface ******************* */
+
+/**
+ * @brief Entry in parser specification for #GNUNET_JSON_parse().
+ */
+struct GNUNET_JSON_Specification;
+
+
+/**
+ * Function called to parse JSON argument.
+ *
+ * @param cls closure
+ * @param root JSON to parse
+ * @param spec our specification entry with further details
+ * @return #GNUNET_SYSERR on error,
+ *         #GNUNET_OK on success
+ */
+typedef int
+(*GNUNET_JSON_Parser)(void *cls,
+                      json_t *root,
+                      struct GNUNET_JSON_Specification *spec);
+
+
+/**
+ * Function called to clean up data from earlier parsing.
+ *
+ * @param cls closure
+ * @param spec our specification entry with data to clean.
+ */
+typedef void
+(*GNUNET_JSON_Cleaner)(void *cls,
+                       struct GNUNET_JSON_Specification *spec);
+
+
+/**
+ * @brief Entry in parser specification for #GNUNET_JSON_parse().
+ */
+struct GNUNET_JSON_Specification
+{
+  /**
+   * Function for how to parse this type of entry.
+   */
+  GNUNET_JSON_Parser parser;
+
+  /**
+   * Function for how to clean up this type of entry.
+   */
+  GNUNET_JSON_Cleaner cleaner;
+
+  /**
+   * Closure for @e parser and @e cleaner.
+   */
+  void *cls;
+
+  /**
+   * Name of the field to parse, use NULL to get the JSON
+   * of the main object instead of the JSON of an individual field.
+   */
+  const char *field;
+
+  /**
+   * Pointer, details specific to the @e parser.
+   */
+  void *ptr;
+
+  /**
+   * Number of bytes available in @e ptr.
+   */
+  size_t ptr_size;
+
+  /**
+   * Where should we store the final size of @e ptr.
+   */
+  size_t *size_ptr;
+
+};
+
+
+/**
+ * Navigate and parse data in a JSON tree.  Tries to parse the @a root
+ * to find all of the values given in the @a spec.  If one of the
+ * entries in @a spec cannot be found or parsed, the name of the JSON
+ * field is returned in @a error_json_name, and the offset of the
+ * entry in @a spec is returned in @a error_line.
+ *
+ * @param root the JSON node to start the navigation at.
+ * @param spec parse specification array
+ * @param[out] error_json_name which JSON field was problematic
+ * @param[out] which index into @a spec did we encounter an error
+ * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
+ */
+int
+GNUNET_JSON_parse (const json_t *root,
+                   struct GNUNET_JSON_Specification *spec,
+                   const char **error_json_name,
+                   unsigned int *error_line);
+
+
+/**
+ * Frees all elements allocated during a #GNUNET_JSON_parse()
+ * operation.
+ *
+ * @param spec specification of the parse operation
+ */
+void
+GNUNET_JSON_parse_free (struct GNUNET_JSON_Specification *spec);
+
+
+
+/* ****************** Canonical parser specifications ******************* */
+
+
+/**
+ * End of a parser specification.
+ */
+struct GNUNET_JSON_Specification
+GNUNET_JSON_spec_end (void);
+
+
+/**
+ * Variable size object (in network byte order, encoded using Crockford
+ * Base32hex encoding).
+ *
+ * @param name name of the JSON field
+ * @param[out] obj pointer where to write the data, must have @a size bytes
+ * @param size number of bytes expected in @a obj
+ */
+struct GNUNET_JSON_Specification
+GNUNET_JSON_spec_fixed (const char *name,
+                        void *obj,
+                        size_t size);
+
+
+/**
+ * Fixed size object (in network byte order, encoded using Crockford
+ * Base32hex encoding).
+ *
+ * @param name name of the JSON field
+ * @param obj pointer where to write the data (type of `*obj` will determine size)
+ */
+#define GNUNET_JSON_spec_fixed_auto(name,obj) GNUNET_JSON_spec_fixed (name, obj, sizeof (*obj))
+
+
+/**
+ * Variable size object (in network byte order, encoded using
+ * Crockford Base32hex encoding).
+ *
+ * @param name name of the JSON field
+ * @param[out] obj pointer where to write the data, will be allocated
+ * @param[out] size where to store the number of bytes allocated for @a obj
+ */
+struct GNUNET_JSON_Specification
+GNUNET_JSON_spec_varsize (const char *name,
+                          void **obj,
+                          size_t *size);
+
+
+/**
+ * The expected field stores a string.
+ *
+ * @param name name of the JSON field
+ * @param strptr where to store a pointer to the field
+ */
+struct GNUNET_JSON_Specification
+GNUNET_JSON_spec_string (const char *name,
+                         const char **strptr);
+
+/**
+ * JSON object.
+ *
+ * @param name name of the JSON field
+ * @param[out] jsonp where to store the JSON found under @a name
+ */
+struct GNUNET_JSON_Specification
+GNUNET_JSON_spec_json (const char *name,
+                       json_t **jsonp);
+
+
+/**
+ * 8-bit integer.
+ *
+ * @param name name of the JSON field
+ * @param[out] u8 where to store the integer found under @a name
+ */
+struct GNUNET_JSON_Specification
+GNUNET_JSON_spec_uint8 (const char *name,
+                        uint8_t *u8);
+
+
+/**
+ * 16-bit integer.
+ *
+ * @param name name of the JSON field
+ * @param[out] u16 where to store the integer found under @a name
+ */
+struct GNUNET_JSON_Specification
+GNUNET_JSON_spec_uint16 (const char *name,
+                         uint16_t *u16);
+
+
+/**
+ * 32-bit integer.
+ *
+ * @param name name of the JSON field
+ * @param[out] u32 where to store the integer found under @a name
+ */
+struct GNUNET_JSON_Specification
+GNUNET_JSON_spec_uint32 (const char *name,
+                         uint32_t *u32);
+
+
+/**
+ * 64-bit integer.
+ *
+ * @param name name of the JSON field
+ * @param[out] u64 where to store the integer found under @a name
+ */
+struct GNUNET_JSON_Specification
+GNUNET_JSON_spec_uint64 (const char *name,
+                         uint64_t *u64);
+
+
+/* ************ GNUnet-specific parser specifications ******************* */
+
+/**
+ * Absolute time.
+ *
+ * @param name name of the JSON field
+ * @param[out] at where to store the absolute time found under @a name
+ */
+struct GNUNET_JSON_Specification
+GNUNET_JSON_spec_absolute_time (const char *name,
+                                struct GNUNET_TIME_Absolute *at);
+
+
+/**
+ * Relative time.
+ *
+ * @param name name of the JSON field
+ * @param[out] rt where to store the relative time found under @a name
+ */
+struct GNUNET_JSON_Specification
+GNUNET_JSON_spec_relative_time (const char *name,
+                                struct GNUNET_TIME_Relative *rt);
+
+
+/**
+ * Specification for parsing an RSA public key.
+ *
+ * @param name name of the JSON field
+ * @param pk where to store the RSA key found under @a name
+ */
+struct GNUNET_JSON_Specification
+GNUNET_JSON_spec_rsa_public_key (const char *name,
+                                 struct GNUNET_CRYPTO_rsa_PublicKey **pk);
+
+
+/**
+ * Specification for parsing an RSA signature.
+ *
+ * @param name name of the JSON field
+ * @param sig where to store the RSA signature found under @a name
+ */
+struct GNUNET_JSON_Specification
+GNUNET_JSON_spec_rsa_signature (const char *name,
+                                struct GNUNET_CRYPTO_rsa_Signature **sig);
+
+
+/* ****************** Generic generator interface ******************* */
+
+
+/**
+ * Convert binary data to a JSON string with the base32crockford
+ * encoding.
+ *
+ * @param data binary data
+ * @param size size of @a data in bytes
+ * @return json string that encodes @a data
+ */
+json_t *
+GNUNET_JSON_from_data (const void *data,
+                       size_t size);
+
+
+/**
+ * Convert absolute timestamp to a json string.
+ *
+ * @param stamp the time stamp
+ * @return a json string with the timestamp in @a stamp
+ */
+json_t *
+GNUNET_JSON_from_time_abs (struct GNUNET_TIME_Absolute stamp);
+
+
+/**
+ * Convert relative timestamp to a json string.
+ *
+ * @param stamp the time stamp
+ * @return a json string with the timestamp in @a stamp
+ */
+json_t *
+GNUNET_JSON_from_time_rel (struct GNUNET_TIME_Relative stamp);
+
+
+/**
+ * Convert RSA public key to JSON.
+ *
+ * @param pk public key to convert
+ * @return corresponding JSON encoding
+ */
+json_t *
+GNUNET_JSON_from_rsa_public_key (const struct GNUNET_CRYPTO_rsa_PublicKey *pk);
+
+
+/**
+ * Convert RSA signature to JSON.
+ *
+ * @param sig signature to convert
+ * @return corresponding JSON encoding
+ */
+json_t *
+GNUNET_JSON_from_rsa_signature (const struct GNUNET_CRYPTO_rsa_Signature *sig);
+
+
+
+
+/* end of gnunet_json_lib.h */
index dd41406d306582b5a85347cbccc2a41fae3d2c71..a7525df7ed7868b22b31f91baa44442285e56079 100644 (file)
@@ -58,8 +58,7 @@ struct GNUNET_PQ_QueryParam
 {
 
   /**
-   * Format of the rest of the entry, determines the data
-   * type that is being added to the query.
+   * Function for how to handle this type of entry.
    */
   GNUNET_PQ_QueryConverter conv;
 
index b805d1e0a432b5b999a0e80a88a9430c04335633..3dad179b5339058bf543aea898db69418c3752e0 100644 (file)
@@ -258,6 +258,30 @@ struct GNUNET_TIME_Absolute
 GNUNET_TIME_relative_to_absolute (struct GNUNET_TIME_Relative rel);
 
 
+/**
+ * Round a time value so that it is suitable for transmission
+ * via JSON encodings.
+ *
+ * @param at time to round
+ * @return #GNUNET_OK if time was already rounded, #GNUNET_NO if
+ *         it was just now rounded
+ */
+int
+GNUNET_TIME_round_abs (struct GNUNET_TIME_Absolute *at);
+
+
+/**
+ * Round a time value so that it is suitable for transmission
+ * via JSON encodings.
+ *
+ * @param rt time to round
+ * @return #GNUNET_OK if time was already rounded, #GNUNET_NO if
+ *         it was just now rounded
+ */
+int
+GNUNET_TIME_round_rel (struct GNUNET_TIME_Relative *rt);
+
+
 /**
  * Return the minimum of two relative time values.
  *
diff --git a/src/json/Makefile.am b/src/json/Makefile.am
new file mode 100644 (file)
index 0000000..83cd6dd
--- /dev/null
@@ -0,0 +1,35 @@
+# This Makefile.am is in the public domain
+AM_CPPFLAGS = -I$(top_srcdir)/src/include
+
+if USE_COVERAGE
+  AM_CFLAGS = --coverage -O0
+  XLIB = -lgcov
+endif
+
+lib_LTLIBRARIES = \
+  libgnunetjson.la
+
+libgnunetjson_la_LDFLAGS = \
+  -version-info 0:0:0 \
+  -no-undefined
+libgnunetjson_la_SOURCES = \
+  json.c \
+  json_generator.c \
+  json_helper.c
+libgnunetjson_la_LIBADD = \
+  -lgnunetutil \
+  -ljansson \
+  $(XLIB)
+
+check_PROGRAMS = \
+  test_json
+
+TESTS = \
+  $(check_PROGRAMS)
+
+test_json_SOURCES = \
+  test_json.c
+test_json_LDADD = \
+  libgnunetjson.la \
+  -lgnunetutil \
+  -ljansson
diff --git a/src/json/json.c b/src/json/json.c
new file mode 100644 (file)
index 0000000..aa74bfd
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+  This file is part of GNUnet
+  Copyright (C) 2014, 2015, 2016 GNUnet e.V.
+
+  GNUnet is free software; you can redistribute it and/or modify it under the
+  terms of the GNU General Public License as published by the Free Software
+  Foundation; either version 3, or (at your option) any later version.
+
+  GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY
+  WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+  A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License along with
+  GNUnet; see the file COPYING.  If not, If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file json/json.c
+ * @brief functions to parse JSON snippets
+ * @author Florian Dold
+ * @author Benedikt Mueller
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "gnunet_json_lib.h"
+
+
+/**
+ * Navigate and parse data in a JSON tree.  Tries to parse the @a root
+ * to find all of the values given in the @a spec.  If one of the
+ * entries in @a spec cannot be found or parsed, the name of the JSON
+ * field is returned in @a error_json_name, and the offset of the
+ * entry in @a spec is returned in @a error_line.
+ *
+ * @param root the JSON node to start the navigation at.
+ * @param spec parse specification array
+ * @param[out] error_json_name which JSON field was problematic
+ * @param[out] which index into @a spec did we encounter an error
+ * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
+ */
+int
+GNUNET_JSON_parse (const json_t *root,
+                   struct GNUNET_JSON_Specification *spec,
+                   const char **error_json_name,
+                   unsigned int *error_line)
+{
+  unsigned int i;
+  json_t *pos;
+
+  for (i=0;NULL != spec[i].parser;i++)
+  {
+    if (NULL == spec[i].field)
+      pos = (json_t *) root;
+    else
+      pos = json_object_get (root,
+                             spec[i].field);
+    if ( (NULL == pos) ||
+         (GNUNET_OK !=
+          spec[i].parser (spec[i].cls,
+                          pos,
+                          &spec[i])) )
+    {
+      if (NULL != error_json_name)
+        *error_json_name = spec[i].field;
+      if (NULL != error_line)
+        *error_line = i;
+      GNUNET_JSON_parse_free (spec);
+      return GNUNET_SYSERR;
+    }
+  }
+  return GNUNET_OK; /* all OK! */
+}
+
+
+/**
+ * Frees all elements allocated during a #GNUNET_JSON_parse()
+ * operation.
+ *
+ * @param spec specification of the parse operation
+ */
+void
+GNUNET_JSON_parse_free (struct GNUNET_JSON_Specification *spec)
+{
+  unsigned int i;
+
+  for (i=0;NULL != spec[i].parser;i++)
+    if (NULL != spec[i].cleaner)
+      spec[i].cleaner (spec[i].cls,
+                       &spec[i]);
+}
+
+
+/* end of json.c */
diff --git a/src/json/json_generator.c b/src/json/json_generator.c
new file mode 100644 (file)
index 0000000..4b1ac31
--- /dev/null
@@ -0,0 +1,146 @@
+/*
+  This file is part of GNUnet
+  Copyright (C) 2014, 2015, 2016 GNUnet e.V.
+
+  GNUnet is free software; you can redistribute it and/or modify it under the
+  terms of the GNU General Public License as published by the Free Software
+  Foundation; either version 3, or (at your option) any later version.
+
+  GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY
+  WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+  A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License along with
+  GNUnet; see the file COPYING.  If not, If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file json/json_generator.c
+ * @brief helper functions for generating JSON from GNUnet data structures
+ * @author Sree Harsha Totakura <sreeharsha@totakura.in>
+ */
+#include "platform.h"
+#include "gnunet_util_lib.h"
+#include "gnunet_json_lib.h"
+
+
+/**
+ * Convert binary data to a JSON string
+ * with the base32crockford encoding.
+ *
+ * @param data binary data
+ * @param size size of @a data in bytes
+ * @return json string that encodes @a data
+ */
+json_t *
+GNUNET_JSON_from_data (const void *data,
+                       size_t size)
+{
+  char *buf;
+  json_t *json;
+
+  buf = GNUNET_STRINGS_data_to_string_alloc (data, size);
+  json = json_string (buf);
+  GNUNET_free (buf);
+  return json;
+}
+
+
+/**
+ * Convert absolute timestamp to a json string.
+ *
+ * @param stamp the time stamp
+ * @return a json string with the timestamp in @a stamp
+ */
+json_t *
+GNUNET_JSON_from_time_abs (struct GNUNET_TIME_Absolute stamp)
+{
+  json_t *j;
+  char *mystr;
+  int ret;
+
+  GNUNET_assert (GNUNET_OK ==
+                 GNUNET_TIME_round_abs (&stamp));
+  if (stamp.abs_value_us == GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us)
+    return json_string ("/never/");
+  ret = GNUNET_asprintf (&mystr,
+                         "/Date(%llu)/",
+                         (unsigned long long) (stamp.abs_value_us / (1000LL * 1000LL)));
+  GNUNET_assert (ret > 0);
+  j = json_string (mystr);
+  GNUNET_free (mystr);
+  return j;
+}
+
+
+/**
+ * Convert relative timestamp to a json string.
+ *
+ * @param stamp the time stamp
+ * @return a json string with the timestamp in @a stamp
+ */
+json_t *
+GNUNET_JSON_from_time_rel (struct GNUNET_TIME_Relative stamp)
+{
+  json_t *j;
+  char *mystr;
+  int ret;
+
+  GNUNET_assert (GNUNET_OK ==
+                 GNUNET_TIME_round_rel (&stamp));
+  if (stamp.rel_value_us == GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us)
+    return json_string ("/forever/");
+  ret = GNUNET_asprintf (&mystr,
+                         "/Delay(%llu)/",
+                         (unsigned long long) (stamp.rel_value_us / (1000LL * 1000LL)));
+  GNUNET_assert (ret > 0);
+  j = json_string (mystr);
+  GNUNET_free (mystr);
+  return j;
+}
+
+
+/**
+ * Convert RSA public key to JSON.
+ *
+ * @param pk public key to convert
+ * @return corresponding JSON encoding
+ */
+json_t *
+GNUNET_JSON_from_rsa_public_key (const struct GNUNET_CRYPTO_rsa_PublicKey *pk)
+{
+  char *buf;
+  size_t buf_len;
+  json_t *ret;
+
+  buf_len = GNUNET_CRYPTO_rsa_public_key_encode (pk,
+                                                 &buf);
+  ret = GNUNET_JSON_from_data (buf,
+                               buf_len);
+  GNUNET_free (buf);
+  return ret;
+}
+
+
+/**
+ * Convert RSA signature to JSON.
+ *
+ * @param sig signature to convert
+ * @return corresponding JSON encoding
+ */
+json_t *
+GNUNET_JSON_from_rsa_signature (const struct GNUNET_CRYPTO_rsa_Signature *sig)
+{
+  char *buf;
+  size_t buf_len;
+  json_t *ret;
+
+  buf_len = GNUNET_CRYPTO_rsa_signature_encode (sig,
+                                                &buf);
+  ret = GNUNET_JSON_from_data (buf,
+                               buf_len);
+  GNUNET_free (buf);
+  return ret;
+}
+
+
+/* End of json/json_generator.c */
diff --git a/src/json/json_helper.c b/src/json/json_helper.c
new file mode 100644 (file)
index 0000000..cf84ae9
--- /dev/null
@@ -0,0 +1,864 @@
+/*
+  This file is part of GNUnet
+  Copyright (C) 2014, 2015, 2016 GNUnet e.V.
+
+  GNUnet is free software; you can redistribute it and/or modify it under the
+  terms of the GNU General Public License as published by the Free Software
+  Foundation; either version 3, or (at your option) any later version.
+
+  GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY
+  WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+  A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License along with
+  GNUnet; see the file COPYING.  If not, If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file json/json_helper.c
+ * @brief functions to generate specifciations for JSON parsing
+ * @author Florian Dold
+ * @author Benedikt Mueller
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "gnunet_json_lib.h"
+
+
+/**
+ * End of a parser specification.
+ */
+struct GNUNET_JSON_Specification
+GNUNET_JSON_spec_end ()
+{
+  struct GNUNET_JSON_Specification ret = {
+    .parser = NULL,
+    .cleaner = NULL,
+    .cls = NULL
+  };
+  return ret;
+}
+
+
+/**
+ * Parse given JSON object to fixed size data
+ *
+ * @param cls closure, NULL
+ * @param root the json object representing data
+ * @param[out] spec where to write the data
+ * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
+ */
+static int
+parse_fixed_data (void *cls,
+                  json_t *root,
+                  struct GNUNET_JSON_Specification *spec)
+{
+  const char *enc;
+  unsigned int len;
+
+  if (NULL == (enc = json_string_value (root)))
+  {
+    GNUNET_break_op (0);
+    return GNUNET_SYSERR;
+  }
+  len = strlen (enc);
+  if (((len * 5) / 8) != spec->ptr_size)
+  {
+    GNUNET_break_op (0);
+    return GNUNET_SYSERR;
+  }
+  if (GNUNET_OK !=
+      GNUNET_STRINGS_string_to_data (enc,
+                                     len,
+                                     spec->ptr,
+                                     spec->ptr_size))
+  {
+    GNUNET_break_op (0);
+    return GNUNET_SYSERR;
+  }
+  return GNUNET_OK;
+}
+
+
+/**
+ * Variable size object (in network byte order, encoded using Crockford
+ * Base32hex encoding).
+ *
+ * @param name name of the JSON field
+ * @param[out] obj pointer where to write the data, must have @a size bytes
+ * @param size number of bytes expected in @a obj
+ */
+struct GNUNET_JSON_Specification
+GNUNET_JSON_spec_fixed (const char *name,
+                        void *obj,
+                        size_t size)
+{
+  struct GNUNET_JSON_Specification ret = {
+    .parser = &parse_fixed_data,
+    .cleaner = NULL,
+    .cls = NULL,
+    .field = name,
+    .ptr = obj,
+    .ptr_size = size,
+    .size_ptr = NULL
+  };
+  return ret;
+}
+
+
+/**
+ * Parse given JSON object to variable size data
+ *
+ * @param cls closure, NULL
+ * @param root the json object representing data
+ * @param[out] spec where to write the data
+ * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
+ */
+static int
+parse_variable_data (void *cls,
+                     json_t *root,
+                     struct GNUNET_JSON_Specification *spec)
+{
+  const char *str;
+  size_t size;
+  void *data;
+  int res;
+
+  str = json_string_value (root);
+  if (NULL == str)
+  {
+    GNUNET_break_op (0);
+    return GNUNET_SYSERR;
+  }
+  size = (strlen (str) * 5) / 8;
+  if (size >= 1024)
+  {
+    GNUNET_break_op (0);
+    return GNUNET_SYSERR;
+  }
+  data = GNUNET_malloc (size);
+  res = GNUNET_STRINGS_string_to_data (str,
+                                       strlen (str),
+                                       data,
+                                       size);
+  if (GNUNET_OK != res)
+  {
+    GNUNET_break_op (0);
+    GNUNET_free (data);
+    return GNUNET_SYSERR;
+  }
+  *(void**) spec->ptr = data;
+  *spec->size_ptr = size;
+  return GNUNET_OK;
+}
+
+
+/**
+ * Cleanup data left from parsing variable size data
+ *
+ * @param cls closure, NULL
+ * @param[out] spec where to free the data
+ */
+static void
+clean_variable_data (void *cls,
+                     struct GNUNET_JSON_Specification *spec)
+{
+  if (0 != *spec->size_ptr)
+  {
+    GNUNET_free (*(void **) spec->ptr);
+    *(void**) spec->ptr = NULL;
+    *spec->size_ptr = 0;
+  }
+}
+
+
+/**
+ * Variable size object (in network byte order, encoded using
+ * Crockford Base32hex encoding).
+ *
+ * @param name name of the JSON field
+ * @param[out] obj pointer where to write the data, will be allocated
+ * @param[out] size where to store the number of bytes allocated for @a obj
+ */
+struct GNUNET_JSON_Specification
+GNUNET_JSON_spec_varsize (const char *name,
+                          void **obj,
+                          size_t *size)
+{
+  struct GNUNET_JSON_Specification ret = {
+    .parser = &parse_variable_data,
+    .cleaner = &clean_variable_data,
+    .cls = NULL,
+    .field = name,
+    .ptr = obj,
+    .ptr_size = 0,
+    .size_ptr = size
+  };
+  *obj = NULL;
+  *size = 0;
+  return ret;
+}
+
+
+/**
+ * Parse given JSON object to string.
+ *
+ * @param cls closure, NULL
+ * @param root the json object representing data
+ * @param[out] spec where to write the data
+ * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
+ */
+static int
+parse_string (void *cls,
+              json_t *root,
+              struct GNUNET_JSON_Specification *spec)
+{
+  const char *str;
+
+  str = json_string_value (root);
+  if (NULL == str)
+  {
+    GNUNET_break_op (0);
+    return GNUNET_SYSERR;
+  }
+  *(const char **) spec->ptr = str;
+  return GNUNET_OK;
+}
+
+
+/**
+ * The expected field stores a string.
+ *
+ * @param name name of the JSON field
+ * @param strptr where to store a pointer to the field
+ */
+struct GNUNET_JSON_Specification
+GNUNET_JSON_spec_string (const char *name,
+                         const char **strptr)
+{
+  struct GNUNET_JSON_Specification ret = {
+    .parser = &parse_string,
+    .cleaner = NULL,
+    .cls = NULL,
+    .field = name,
+    .ptr = strptr,
+    .ptr_size = 0,
+    .size_ptr = NULL
+  };
+  return ret;
+}
+
+
+/**
+ * Parse given JSON object to a JSON object. (Yes, trivial.)
+ *
+ * @param cls closure, NULL
+ * @param root the json object representing data
+ * @param[out] spec where to write the data
+ * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
+ */
+static int
+parse_object (void *cls,
+              json_t *root,
+              struct GNUNET_JSON_Specification *spec)
+{
+  if (! (json_is_object (root) || json_is_array (root)) )
+  {
+    GNUNET_break_op (0);
+    return GNUNET_SYSERR;
+  }
+  json_incref (root);
+  *(json_t **) spec->ptr = root;
+  return GNUNET_OK;
+}
+
+
+/**
+ * Cleanup data left from parsing JSON object.
+ *
+ * @param cls closure, NULL
+ * @param[out] spec where to free the data
+ */
+static void
+clean_object (void *cls,
+              struct GNUNET_JSON_Specification *spec)
+{
+  json_t **ptr = (json_t **) spec->ptr;
+  if (NULL != *ptr)
+  {
+    json_decref (*ptr);
+    *ptr = NULL;
+  }
+}
+
+
+/**
+ * JSON object.
+ *
+ * @param name name of the JSON field
+ * @param[out] jsonp where to store the JSON found under @a name
+ */
+struct GNUNET_JSON_Specification
+GNUNET_JSON_spec_json (const char *name,
+                       json_t **jsonp)
+{
+  struct GNUNET_JSON_Specification ret = {
+    .parser = &parse_object,
+    .cleaner = &clean_object,
+    .cls = NULL,
+    .field = name,
+    .ptr = jsonp,
+    .ptr_size = 0,
+    .size_ptr = NULL
+  };
+  return ret;
+}
+
+
+/**
+ * Parse given JSON object to a uint8_t.
+ *
+ * @param cls closure, NULL
+ * @param root the json object representing data
+ * @param[out] spec where to write the data
+ * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
+ */
+static int
+parse_u8 (void *cls,
+          json_t *root,
+          struct GNUNET_JSON_Specification *spec)
+{
+  json_int_t val;
+  uint8_t *up = spec->ptr;
+
+  if (! json_is_integer (root))
+  {
+    GNUNET_break_op (0);
+    return GNUNET_SYSERR;
+  }
+  val = json_integer_value (root);
+  if ( (0 > val) || (val > UINT8_MAX) )
+  {
+    GNUNET_break_op (0);
+    return GNUNET_SYSERR;
+  }
+  *up = (uint8_t) val;
+  return GNUNET_OK;
+}
+
+
+/**
+ * 8-bit integer.
+ *
+ * @param name name of the JSON field
+ * @param[out] u8 where to store the integer found under @a name
+ */
+struct GNUNET_JSON_Specification
+GNUNET_JSON_spec_uint8 (const char *name,
+                        uint8_t *u8)
+{
+  struct GNUNET_JSON_Specification ret = {
+    .parser = &parse_u8,
+    .cleaner = NULL,
+    .cls = NULL,
+    .field = name,
+    .ptr = u8,
+    .ptr_size = sizeof (uint8_t),
+    .size_ptr = NULL
+  };
+  return ret;
+}
+
+
+/**
+ * Parse given JSON object to a uint16_t.
+ *
+ * @param cls closure, NULL
+ * @param root the json object representing data
+ * @param[out] spec where to write the data
+ * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
+ */
+static int
+parse_u16 (void *cls,
+           json_t *root,
+           struct GNUNET_JSON_Specification *spec)
+{
+  json_int_t val;
+  uint16_t *up = spec->ptr;
+
+  if (! json_is_integer (root))
+  {
+    GNUNET_break_op (0);
+    return GNUNET_SYSERR;
+  }
+  val = json_integer_value (root);
+  if ( (0 > val) || (val > UINT16_MAX) )
+  {
+    GNUNET_break_op (0);
+    return GNUNET_SYSERR;
+  }
+  *up = (uint16_t) val;
+  return GNUNET_OK;
+}
+
+
+/**
+ * 16-bit integer.
+ *
+ * @param name name of the JSON field
+ * @param[out] u16 where to store the integer found under @a name
+ */
+struct GNUNET_JSON_Specification
+GNUNET_JSON_spec_uint16 (const char *name,
+                         uint16_t *u16)
+{
+  struct GNUNET_JSON_Specification ret = {
+    .parser = &parse_u16,
+    .cleaner = NULL,
+    .cls = NULL,
+    .field = name,
+    .ptr = u16,
+    .ptr_size = sizeof (uint16_t),
+    .size_ptr = NULL
+  };
+  return ret;
+}
+
+
+/**
+ * Parse given JSON object to a uint32_t.
+ *
+ * @param cls closure, NULL
+ * @param root the json object representing data
+ * @param[out] spec where to write the data
+ * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
+ */
+static int
+parse_u32 (void *cls,
+           json_t *root,
+           struct GNUNET_JSON_Specification *spec)
+{
+  json_int_t val;
+  uint32_t *up = spec->ptr;
+
+  if (! json_is_integer (root))
+  {
+    GNUNET_break_op (0);
+    return GNUNET_SYSERR;
+  }
+  val = json_integer_value (root);
+  if ( (0 > val) || (val > UINT32_MAX) )
+  {
+    GNUNET_break_op (0);
+    return GNUNET_SYSERR;
+  }
+  *up = (uint32_t) val;
+  return GNUNET_OK;
+}
+
+
+/**
+ * 32-bit integer.
+ *
+ * @param name name of the JSON field
+ * @param[out] u32 where to store the integer found under @a name
+ */
+struct GNUNET_JSON_Specification
+GNUNET_JSON_spec_uint32 (const char *name,
+                         uint32_t *u32)
+{
+  struct GNUNET_JSON_Specification ret = {
+    .parser = &parse_u32,
+    .cleaner = NULL,
+    .cls = NULL,
+    .field = name,
+    .ptr = u32,
+    .ptr_size = sizeof (uint32_t),
+    .size_ptr = NULL
+  };
+  return ret;
+}
+
+
+/**
+ * Parse given JSON object to a uint8_t.
+ *
+ * @param cls closure, NULL
+ * @param root the json object representing data
+ * @param[out] spec where to write the data
+ * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
+ */
+static int
+parse_u64 (void *cls,
+           json_t *root,
+           struct GNUNET_JSON_Specification *spec)
+{
+  json_int_t val;
+  uint64_t *up = spec->ptr;
+
+  if (! json_is_integer (root))
+  {
+    GNUNET_break_op (0);
+    return GNUNET_SYSERR;
+  }
+  val = json_integer_value (root);
+  *up = (uint64_t) val;
+  return GNUNET_OK;
+}
+
+
+/**
+ * 64-bit integer.
+ *
+ * @param name name of the JSON field
+ * @param[out] u64 where to store the integer found under @a name
+ */
+struct GNUNET_JSON_Specification
+GNUNET_JSON_spec_uint64 (const char *name,
+                         uint64_t *u64)
+{
+  struct GNUNET_JSON_Specification ret = {
+    .parser = &parse_u64,
+    .cleaner = NULL,
+    .cls = NULL,
+    .field = name,
+    .ptr = u64,
+    .ptr_size = sizeof (uint64_t),
+    .size_ptr = NULL
+  };
+  return ret;
+}
+
+
+/* ************ GNUnet-specific parser specifications ******************* */
+
+/**
+ * Parse given JSON object to absolute time.
+ *
+ * @param cls closure, NULL
+ * @param root the json object representing data
+ * @param[out] spec where to write the data
+ * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
+ */
+static int
+parse_abs_time (void *cls,
+                json_t *root,
+                struct GNUNET_JSON_Specification *spec)
+{
+  struct GNUNET_TIME_Absolute *abs = spec->ptr;
+  const char *val;
+  unsigned long long int tval;
+
+  val = json_string_value (root);
+  if (NULL == val)
+  {
+    GNUNET_break_op (0);
+    return GNUNET_SYSERR;
+  }
+  if ( (0 == strcasecmp (val,
+                         "/forever/")) ||
+       (0 == strcasecmp (val,
+                         "/end of time/")) ||
+       (0 == strcasecmp (val,
+                         "/never/")) )
+  {
+    *abs = GNUNET_TIME_UNIT_FOREVER_ABS;
+    return GNUNET_OK;
+  }
+  if (1 != sscanf (val,
+                   "/Date(%llu)/",
+                   &tval))
+  {
+    GNUNET_break_op (0);
+    return GNUNET_SYSERR;
+  }
+  /* Time is in seconds in JSON, but in microseconds in GNUNET_TIME_Absolute */
+  abs->abs_value_us = tval * 1000LL * 1000LL;
+  if ( (abs->abs_value_us) / 1000LL / 1000LL != tval)
+  {
+    /* Integer overflow */
+    GNUNET_break_op (0);
+    return GNUNET_SYSERR;
+  }
+  return GNUNET_OK;
+}
+
+
+/**
+ * Absolute time.
+ *
+ * @param name name of the JSON field
+ * @param[out] at where to store the absolute time found under @a name
+ */
+struct GNUNET_JSON_Specification
+GNUNET_JSON_spec_absolute_time (const char *name,
+                                struct GNUNET_TIME_Absolute *at)
+{
+  struct GNUNET_JSON_Specification ret = {
+    .parser = &parse_abs_time,
+    .cleaner = NULL,
+    .cls = NULL,
+    .field = name,
+    .ptr = at,
+    .ptr_size = sizeof (uint64_t),
+    .size_ptr = NULL
+  };
+  return ret;
+}
+
+
+/**
+ * Parse given JSON object to relative time.
+ *
+ * @param cls closure, NULL
+ * @param root the json object representing data
+ * @param[out] spec where to write the data
+ * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
+ */
+static int
+parse_rel_time (void *cls,
+                json_t *root,
+                struct GNUNET_JSON_Specification *spec)
+{
+  struct GNUNET_TIME_Relative *rel = spec->ptr;
+  const char *val;
+  unsigned long long int tval;
+
+  val = json_string_value (root);
+  if (NULL == val)
+  {
+    GNUNET_break_op (0);
+    return GNUNET_SYSERR;
+  }
+  if ( (0 == strcasecmp (val,
+                         "/forever/")) )
+  {
+    *rel = GNUNET_TIME_UNIT_FOREVER_REL;
+    return GNUNET_OK;
+  }
+  if (1 != sscanf (val,
+                   "/Delay(%llu)/",
+                   &tval))
+  {
+    GNUNET_break_op (0);
+    return GNUNET_SYSERR;
+  }
+  /* Time is in seconds in JSON, but in microseconds in GNUNET_TIME_Relative */
+  rel->rel_value_us = tval * 1000LL * 1000LL;
+  if ( (rel->rel_value_us) / 1000LL / 1000LL != tval)
+  {
+    /* Integer overflow */
+    GNUNET_break_op (0);
+    return GNUNET_SYSERR;
+  }
+  return GNUNET_OK;
+}
+
+
+/**
+ * Relative time.
+ *
+ * @param name name of the JSON field
+ * @param[out] rt where to store the relative time found under @a name
+ */
+struct GNUNET_JSON_Specification
+GNUNET_JSON_spec_relative_time (const char *name,
+                                struct GNUNET_TIME_Relative *rt)
+{
+  struct GNUNET_JSON_Specification ret = {
+    .parser = &parse_rel_time,
+    .cleaner = NULL,
+    .cls = NULL,
+    .field = name,
+    .ptr = rt,
+    .ptr_size = sizeof (uint64_t),
+    .size_ptr = NULL
+  };
+  return ret;
+}
+
+
+/**
+ * Parse given JSON object to RSA public key.
+ *
+ * @param cls closure, NULL
+ * @param root the json object representing data
+ * @param[out] spec where to write the data
+ * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
+ */
+static int
+parse_rsa_public_key (void *cls,
+                      json_t *root,
+                      struct GNUNET_JSON_Specification *spec)
+{
+  struct GNUNET_CRYPTO_rsa_PublicKey **pk = spec->ptr;
+  const char *enc;
+  char *buf;
+  size_t len;
+  size_t buf_len;
+
+  if (NULL == (enc = json_string_value (root)))
+  {
+    GNUNET_break_op (0);
+    return GNUNET_SYSERR;
+  }
+  len = strlen (enc);
+  buf_len =  (len * 5) / 8;
+  buf = GNUNET_malloc (buf_len);
+  if (GNUNET_OK !=
+      GNUNET_STRINGS_string_to_data (enc,
+                                     len,
+                                     buf,
+                                     buf_len))
+  {
+    GNUNET_break_op (0);
+    GNUNET_free (buf);
+    return GNUNET_SYSERR;
+  }
+  if (NULL == (*pk = GNUNET_CRYPTO_rsa_public_key_decode (buf,
+                                                          buf_len)))
+  {
+    GNUNET_break_op (0);
+    GNUNET_free (buf);
+    return GNUNET_SYSERR;
+  }
+  GNUNET_free (buf);
+  return GNUNET_OK;
+}
+
+
+/**
+ * Cleanup data left from parsing RSA public key.
+ *
+ * @param cls closure, NULL
+ * @param[out] spec where to free the data
+ */
+static void
+clean_rsa_public_key (void *cls,
+                      struct GNUNET_JSON_Specification *spec)
+{
+  struct GNUNET_CRYPTO_rsa_PublicKey **pk = spec->ptr;
+
+  if (NULL != *pk)
+  {
+    GNUNET_CRYPTO_rsa_public_key_free (*pk);
+    *pk = NULL;
+  }
+}
+
+
+/**
+ * Specification for parsing an RSA public key.
+ *
+ * @param name name of the JSON field
+ * @param pk where to store the RSA key found under @a name
+ */
+struct GNUNET_JSON_Specification
+GNUNET_JSON_spec_rsa_public_key (const char *name,
+                                 struct GNUNET_CRYPTO_rsa_PublicKey **pk)
+{
+  struct GNUNET_JSON_Specification ret = {
+    .parser = &parse_rsa_public_key,
+    .cleaner = &clean_rsa_public_key,
+    .cls = NULL,
+    .field = name,
+    .ptr = pk,
+    .ptr_size = 0,
+    .size_ptr = NULL
+  };
+  return ret;
+}
+
+
+/**
+ * Parse given JSON object to RSA signature.
+ *
+ * @param cls closure, NULL
+ * @param root the json object representing data
+ * @param[out] spec where to write the data
+ * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
+ */
+static int
+parse_rsa_signature (void *cls,
+                     json_t *root,
+                     struct GNUNET_JSON_Specification *spec)
+{
+  struct GNUNET_CRYPTO_rsa_Signature **sig = spec->ptr;
+  size_t size;
+  const char *str;
+  int res;
+  void *buf;
+
+  str = json_string_value (root);
+  if (NULL == str)
+  {
+    GNUNET_break_op (0);
+    return GNUNET_SYSERR;
+  }
+  size = (strlen (str) * 5) / 8;
+  buf = GNUNET_malloc (size);
+  res = GNUNET_STRINGS_string_to_data (str,
+                                       strlen (str),
+                                       buf,
+                                       size);
+  if (GNUNET_OK != res)
+  {
+    GNUNET_free (buf);
+    GNUNET_break_op (0);
+    return GNUNET_SYSERR;
+  }
+  if (NULL == (*sig = GNUNET_CRYPTO_rsa_signature_decode (buf,
+                                                          size)))
+  {
+    GNUNET_break_op (0);
+    GNUNET_free (buf);
+    return GNUNET_SYSERR;
+  }
+  GNUNET_free (buf);
+  return GNUNET_OK;
+}
+
+
+/**
+ * Cleanup data left from parsing RSA signature.
+ *
+ * @param cls closure, NULL
+ * @param[out] spec where to free the data
+ */
+static void
+clean_rsa_signature (void *cls,
+                     struct GNUNET_JSON_Specification *spec)
+{
+  struct GNUNET_CRYPTO_rsa_Signature  **sig = spec->ptr;
+
+  if (NULL != *sig)
+  {
+    GNUNET_CRYPTO_rsa_signature_free (*sig);
+    *sig = NULL;
+  }
+}
+
+
+/**
+ * Specification for parsing an RSA signature.
+ *
+ * @param name name of the JSON field
+ * @param sig where to store the RSA signature found under @a name
+ */
+struct GNUNET_JSON_Specification
+GNUNET_JSON_spec_rsa_signature (const char *name,
+                                struct GNUNET_CRYPTO_rsa_Signature **sig)
+{
+  struct GNUNET_JSON_Specification ret = {
+    .parser = &parse_rsa_signature,
+    .cleaner = &clean_rsa_signature,
+    .cls = NULL,
+    .field = name,
+    .ptr = sig,
+    .ptr_size = 0,
+    .size_ptr = NULL
+  };
+  return ret;
+}
+
+
+/* end of json_helper.c */
diff --git a/src/json/test_json.c b/src/json/test_json.c
new file mode 100644 (file)
index 0000000..a334bf5
--- /dev/null
@@ -0,0 +1,217 @@
+/*
+  This file is part of GNUnet
+  (C) 2015, 2016 GNUnet e.V.
+
+  GNUnet is free software; you can redistribute it and/or modify it under the
+  terms of the GNU General Public License as published by the Free Software
+  Foundation; either version 3, or (at your option) any later version.
+
+  GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY
+  WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+  A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License along with
+  GNUnet; see the file COPYING.  If not, If not, see <http://www.gnu.org/licenses/>
+*/
+
+/**
+ * @file json/test_json.c
+ * @brief Tests for JSON conversion functions
+ * @author Christian Grothoff <christian@grothoff.org>
+ */
+#include "platform.h"
+#include "gnunet_util_lib.h"
+#include "gnunet_json_lib.h"
+
+
+/**
+ * Test absolute time conversion from/to JSON.
+ *
+ * @return 0 on success
+ */
+static int
+test_abs_time ()
+{
+  json_t *j;
+  struct GNUNET_TIME_Absolute a1;
+  struct GNUNET_TIME_Absolute a2;
+  struct GNUNET_JSON_Specification s1[] = {
+    GNUNET_JSON_spec_absolute_time (NULL, &a2),
+    GNUNET_JSON_spec_end()
+  };
+  struct GNUNET_JSON_Specification s2[] = {
+    GNUNET_JSON_spec_absolute_time (NULL, &a2),
+    GNUNET_JSON_spec_end()
+  };
+
+  a1 = GNUNET_TIME_absolute_get ();
+  GNUNET_TIME_round_abs (&a1);
+  j = GNUNET_JSON_from_time_abs (a1);
+  GNUNET_assert (NULL != j);
+  GNUNET_assert (GNUNET_OK ==
+                GNUNET_JSON_parse (j, s1, NULL, NULL));
+  GNUNET_assert (a1.abs_value_us ==
+                a2.abs_value_us);
+  json_decref (j);
+
+  a1 = GNUNET_TIME_UNIT_FOREVER_ABS;
+  j = GNUNET_JSON_from_time_abs (a1);
+  GNUNET_assert (NULL != j);
+  GNUNET_assert (GNUNET_OK ==
+                GNUNET_JSON_parse (j, s2, NULL, NULL));
+  GNUNET_assert (a1.abs_value_us ==
+                a2.abs_value_us);
+  json_decref (j);
+  return 0;
+}
+
+
+/**
+ * Test relative time conversion from/to JSON.
+ *
+ * @return 0 on success
+ */
+static int
+test_rel_time ()
+{
+  json_t *j;
+  struct GNUNET_TIME_Relative r1;
+  struct GNUNET_TIME_Relative r2;
+  struct GNUNET_JSON_Specification s1[] = {
+    GNUNET_JSON_spec_relative_time (NULL, &r2),
+    GNUNET_JSON_spec_end()
+  };
+  struct GNUNET_JSON_Specification s2[] = {
+    GNUNET_JSON_spec_relative_time (NULL, &r2),
+    GNUNET_JSON_spec_end()
+  };
+
+  r1 = GNUNET_TIME_UNIT_SECONDS;
+  j = GNUNET_JSON_from_time_rel (r1);
+  GNUNET_assert (NULL != j);
+  GNUNET_assert (GNUNET_OK ==
+                GNUNET_JSON_parse (j, s1, NULL, NULL));
+  GNUNET_assert (r1.rel_value_us ==
+                r2.rel_value_us);
+  json_decref (j);
+
+  r1 = GNUNET_TIME_UNIT_FOREVER_REL;
+  j = GNUNET_JSON_from_time_rel (r1);
+  GNUNET_assert (NULL != j);
+  GNUNET_assert (GNUNET_OK ==
+                GNUNET_JSON_parse (j, s2, NULL, NULL));
+  GNUNET_assert (r1.rel_value_us ==
+                r2.rel_value_us);
+  json_decref (j);
+  return 0;
+}
+
+
+/**
+ * Test raw (binary) conversion from/to JSON.
+ *
+ * @return 0 on success
+ */
+static int
+test_raw ()
+{
+  char blob[256];
+  unsigned int i;
+  json_t *j;
+
+  for (i=0;i<=256;i++)
+  {
+    char blob2[256];
+    struct GNUNET_JSON_Specification spec[] = {
+      GNUNET_JSON_spec_fixed (NULL, blob2, i),
+      GNUNET_JSON_spec_end()
+    };
+
+    memset (blob, i, i);
+    j = GNUNET_JSON_from_data (blob, i);
+    GNUNET_assert (NULL != j);
+    GNUNET_assert (GNUNET_OK ==
+                  GNUNET_JSON_parse (j, spec,
+                                      NULL, NULL));
+    GNUNET_assert (0 ==
+                  memcmp (blob,
+                          blob2,
+                          i));
+  }
+  return 0;
+}
+
+
+/**
+ * Test rsa conversions from/to JSON.
+ *
+ * @return 0 on success
+ */
+static int
+test_rsa ()
+{
+  struct GNUNET_CRYPTO_rsa_PublicKey *pub;
+  struct GNUNET_CRYPTO_rsa_PublicKey *pub2;
+  struct GNUNET_JSON_Specification pspec[] = {
+    GNUNET_JSON_spec_rsa_public_key (NULL, &pub2),
+    GNUNET_JSON_spec_end()
+  };
+  struct GNUNET_CRYPTO_rsa_Signature *sig;
+  struct GNUNET_CRYPTO_rsa_Signature *sig2;
+  struct GNUNET_JSON_Specification sspec[] = {
+    GNUNET_JSON_spec_rsa_signature (NULL, &sig2),
+    GNUNET_JSON_spec_end()
+  };
+  struct GNUNET_CRYPTO_rsa_PrivateKey *priv;
+  char msg[] = "Hello";
+  json_t *jp;
+  json_t *js;
+
+  priv = GNUNET_CRYPTO_rsa_private_key_create (1024);
+  pub = GNUNET_CRYPTO_rsa_private_key_get_public (priv);
+  sig = GNUNET_CRYPTO_rsa_sign (priv,
+                               msg,
+                               sizeof (msg));
+  GNUNET_assert (NULL != (jp = GNUNET_JSON_from_rsa_public_key (pub)));
+  GNUNET_assert (NULL != (js = GNUNET_JSON_from_rsa_signature (sig)));
+  GNUNET_assert (GNUNET_OK ==
+                 GNUNET_JSON_parse (jp, pspec,
+                                    NULL, NULL));
+  GNUNET_assert (GNUNET_OK ==
+                 GNUNET_JSON_parse (js, sspec,
+                                    NULL, NULL));
+  GNUNET_break (0 ==
+               GNUNET_CRYPTO_rsa_signature_cmp (sig,
+                                                sig2));
+  GNUNET_break (0 ==
+               GNUNET_CRYPTO_rsa_public_key_cmp (pub,
+                                                 pub2));
+  GNUNET_CRYPTO_rsa_signature_free (sig);
+  GNUNET_CRYPTO_rsa_signature_free (sig2);
+  GNUNET_CRYPTO_rsa_private_key_free (priv);
+  GNUNET_CRYPTO_rsa_public_key_free (pub);
+  GNUNET_CRYPTO_rsa_public_key_free (pub2);
+  return 0;
+}
+
+
+int
+main(int argc,
+     const char *const argv[])
+{
+  GNUNET_log_setup ("test-json",
+                   "WARNING",
+                   NULL);
+  if (0 != test_abs_time ())
+    return 1;
+  if (0 != test_rel_time ())
+    return 1;
+  if (0 != test_raw ())
+    return 1;
+  if (0 != test_rsa ())
+    return 1;
+  /* FIXME: test EdDSA signature conversion... */
+  return 0;
+}
+
+/* end of test_json.c */
index 4f3eaa7fbbbf9e93ea9eeeedf391c1d086f5226b..654b567f021f99b9afb72d2da7d446080f362875 100644 (file)
@@ -58,6 +58,46 @@ GNUNET_TIME_get_offset ()
 }
 
 
+/**
+ * Round a time value so that it is suitable for transmission
+ * via JSON encodings.
+ *
+ * @param at time to round
+ * @return #GNUNET_OK if time was already rounded, #GNUNET_NO if
+ *         it was just now rounded
+ */
+int
+GNUNET_TIME_round_abs (struct GNUNET_TIME_Absolute *at)
+{
+  if (at->abs_value_us == GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us)
+    return GNUNET_OK;
+  if (0 == at->abs_value_us % 1000000)
+    return GNUNET_OK;
+  at->abs_value_us -= at->abs_value_us % 1000000;
+  return GNUNET_NO;
+}
+
+
+/**
+ * Round a time value so that it is suitable for transmission
+ * via JSON encodings.
+ *
+ * @param rt time to round
+ * @return #GNUNET_OK if time was already rounded, #GNUNET_NO if
+ *         it was just now rounded
+ */
+int
+GNUNET_TIME_round_rel (struct GNUNET_TIME_Relative *rt)
+{
+  if (rt->rel_value_us == GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us)
+    return GNUNET_OK;
+  if (0 == rt->rel_value_us % 1000000)
+    return GNUNET_OK;
+  rt->rel_value_us -= rt->rel_value_us % 1000000;
+  return GNUNET_NO;
+}
+
+
 /**
  * Get the current time (works just as "time", just that we use the
  * unit of time that the cron-jobs use (and is 64 bit)).