/*
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 Affero General Public License as published
by the Free Software Foundation, either version 3 of the License,
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
Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. 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;