387 lines
12 KiB
C
Executable File
387 lines
12 KiB
C
Executable File
/***************************************************************************
|
|
* Copyright (C) 2007 by Rui Maciel *
|
|
* rui.maciel@gmail.com *
|
|
* *
|
|
* This program is free software; you can redistribute it and/or modify *
|
|
* it under the terms of the GNU Library General Public License as *
|
|
* published by the Free Software Foundation; either version 2 of the *
|
|
* License, or (at your option) any later version. *
|
|
* *
|
|
* This program 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 Library General Public *
|
|
* License along with this program; if not, write to the *
|
|
* Free Software Foundation, Inc., *
|
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
|
***************************************************************************/
|
|
|
|
/** @file json.h A small library that helps deal with JSON-encoded information
|
|
\ingroup JSON
|
|
|
|
\note error handling is only in a very rudimentary form.
|
|
\author Rui Maciel rui_maciel@users.sourceforge.net
|
|
\author Sven Herzberg
|
|
\version v1.5
|
|
*/
|
|
|
|
#include <stdint.h>
|
|
#include <stdio.h>
|
|
|
|
#ifndef JSON_H
|
|
#define JSON_H
|
|
|
|
#ifdef __cplusplus
|
|
extern "C"
|
|
{
|
|
#endif
|
|
|
|
#define JSON_MAX_STRING_LENGTH SIZE_MAX-1
|
|
|
|
enum LEX_VALUE
|
|
{ LEX_MORE = 0,
|
|
LEX_INVALID_CHARACTER,
|
|
LEX_TRUE,
|
|
LEX_FALSE,
|
|
LEX_NULL,
|
|
LEX_BEGIN_OBJECT,
|
|
LEX_END_OBJECT,
|
|
LEX_BEGIN_ARRAY,
|
|
LEX_END_ARRAY,
|
|
LEX_NAME_SEPARATOR,
|
|
LEX_VALUE_SEPARATOR,
|
|
LEX_STRING,
|
|
LEX_NUMBER,
|
|
LEX_ERROR,
|
|
LEX_MEMORY
|
|
};
|
|
|
|
|
|
/* rc_string part */
|
|
|
|
#define RSTRING_INCSTEP 5
|
|
#define RSTRING_DEFAULT 8
|
|
|
|
|
|
enum rui_string_error_codes
|
|
{ RS_MEMORY, RS_OK = 1, RS_UNKNOWN };
|
|
|
|
typedef enum rui_string_error_codes rstring_code;
|
|
|
|
|
|
/**
|
|
The descriptions of the json_value node type
|
|
**/
|
|
typedef enum json_value_type
|
|
{ JSON_STRING = 0,
|
|
JSON_NUMBER,
|
|
JSON_OBJECT,
|
|
JSON_ARRAY,
|
|
JSON_TRUE,
|
|
JSON_FALSE,
|
|
JSON_NULL
|
|
}json_type_e;
|
|
|
|
/**
|
|
String implementation
|
|
**/
|
|
struct rui_cstring
|
|
{
|
|
char *text; /*<! char c-string */
|
|
size_t length; /*<! put in place to avoid strlen() calls */
|
|
size_t max; /*<! usable memory allocated to text minus the space for the nul character */
|
|
};
|
|
|
|
typedef struct rui_cstring rcstring;
|
|
|
|
/**
|
|
The error messages produced by the JSON parsers
|
|
**/
|
|
typedef enum json_error
|
|
{
|
|
JSON_OK = 1, /*!< everything went smoothly */
|
|
JSON_INCOMPLETE_DOCUMENT, /*!< the parsed document didn't ended */
|
|
JSON_WAITING_FOR_EOF, /*!< A complete JSON document tree was already finished but needs to get to EOF. Other characters beyond whitespaces produce errors */
|
|
JSON_MALFORMED_DOCUMENT, /* the JSON document which was fed to this parser is malformed */
|
|
JSON_INCOMPATIBLE_TYPE, /*!< the currently parsed type does not belong here */
|
|
JSON_MEMORY, /*!< an error occurred when allocating memory */
|
|
JSON_ILLEGAL_CHARACTER, /*!< the currently parsed character does not belong here */
|
|
JSON_BAD_TREE_STRUCTURE, /*!< the document tree structure is malformed */
|
|
JSON_MAXIMUM_LENGTH, /*!< the parsed string reached the maximum allowed size */
|
|
JSON_UNKNOWN_PROBLEM /*!< some random, unaccounted problem occurred */
|
|
}json_err_e;
|
|
|
|
|
|
/**
|
|
The JSON document tree node, which is a basic JSON type
|
|
**/
|
|
typedef struct json_value
|
|
{
|
|
enum json_value_type type; /*!< the type of node */
|
|
char *text; /*!< The text stored by the node. It stores UTF-8 strings and is used exclusively by the JSON_STRING and JSON_NUMBER node types */
|
|
|
|
/* FIFO queue data */
|
|
struct json_value *next; /*!< The pointer pointing to the next element in the FIFO sibling list */
|
|
struct json_value *previous; /*!< The pointer pointing to the previous element in the FIFO sibling list */
|
|
struct json_value *parent; /*!< The pointer pointing to the parent node in the document tree */
|
|
struct json_value *child; /*!< The pointer pointing to the first child node in the document tree */
|
|
struct json_value *child_end; /*!< The pointer pointing to the last child node in the document tree */
|
|
} json_t;
|
|
|
|
|
|
/**
|
|
The structure holding all information needed to resume parsing
|
|
**/
|
|
struct json_parsing_info
|
|
{
|
|
unsigned int state; /*!< the state where the parsing was left on the last parser run */
|
|
unsigned int lex_state;
|
|
rcstring *lex_text;
|
|
const char *p;
|
|
int string_length_limit_reached; /*!< flag informing if the string limit length defined by JSON_MAX_STRING_LENGTH was reached */
|
|
size_t line; // current document line
|
|
json_t *cursor; /*!< pointers to nodes belonging to the document tree which aid the document parsing */
|
|
};
|
|
|
|
|
|
/**
|
|
The structure which holds the pointers to the functions that will be called by the saxy parser whenever their evens are triggered
|
|
**/
|
|
struct json_saxy_functions
|
|
{
|
|
int (*open_object) (void);
|
|
int (*close_object) (void);
|
|
int (*open_array) (void);
|
|
int (*close_array) (void);
|
|
int (*new_string) (char *text);
|
|
int (*new_number) (char *text);
|
|
int (*new_true) (void);
|
|
int (*new_false) (void);
|
|
int (*new_null) (void);
|
|
int (*label_value_separator) (void);
|
|
int (*sibling_separator) (void);
|
|
};
|
|
|
|
|
|
/**
|
|
The structure holding the information needed for json_saxy_parse to resume parsing
|
|
**/
|
|
struct json_saxy_parser_status
|
|
{
|
|
unsigned int state; /*!< current parser state */
|
|
int string_length_limit_reached; /*!< flag informing if the string limit length defined by JSON_MAX_STRING_LENGTH was reached */
|
|
rcstring *temp; /*!< temporary string which will be used to build up parsed strings between parser runs. */
|
|
};
|
|
|
|
|
|
/**
|
|
Buils a json_t document by parsing an open file stream
|
|
@param file a pointer to an object controlling a stream, returned by fopen()
|
|
@param document a reference to a json_t pointer, set to NULL, which will store the parsed document
|
|
@return a json_error error code according to how the parsing operation went.
|
|
**/
|
|
enum json_error json_stream_parse (FILE * file, json_t ** document);
|
|
|
|
|
|
/**
|
|
Creates a new JSON value and defines it's type
|
|
@param type the value's type
|
|
@return a pointer to the newly created value structure
|
|
**/
|
|
json_t *json_new_value (const enum json_value_type type);
|
|
|
|
|
|
/**
|
|
Creates a new JSON string and defines it's text
|
|
@param text the value's text
|
|
@return a pointer to the newly created JSON string value
|
|
**/
|
|
json_t *json_new_string (const char *text);
|
|
|
|
|
|
/**
|
|
Creates a new JSON number and defines it's text. The user is responsible for the number string's correctness
|
|
@param text the value's number
|
|
@return a pointer to the newly created JSON string value
|
|
**/
|
|
json_t *json_new_number (const char *text);
|
|
|
|
|
|
/**
|
|
Creates a new JSON object
|
|
@return a pointer to the newly created JSON object value
|
|
**/
|
|
json_t *json_new_object (void);
|
|
|
|
|
|
/**
|
|
Creates a new JSON array
|
|
@return a pointer to the newly created JSON array value
|
|
**/
|
|
json_t *json_new_array (void);
|
|
|
|
|
|
/**
|
|
Creates a new JSON null
|
|
@return a pointer to the newly created JSON null value
|
|
**/
|
|
json_t *json_new_null (void);
|
|
|
|
|
|
/**
|
|
Creates a new JSON true
|
|
@return a pointer to the newly created JSON true value
|
|
**/
|
|
json_t *json_new_true (void);
|
|
|
|
|
|
/**
|
|
Creates a new JSON false
|
|
@return a pointer to the newly created JSON false value
|
|
**/
|
|
json_t *json_new_false (void);
|
|
|
|
|
|
/**
|
|
Frees the memory appointed to the value fed as the parameter, as well as all the child nodes
|
|
@param value the root node of the tree being freed
|
|
**/
|
|
void json_free_value (json_t ** value);
|
|
|
|
|
|
/**
|
|
Inserts a child node into a parent node, as well as performs some document tree integrity checks.
|
|
@param parent the parent node
|
|
@param child the node being added as a child to parent
|
|
@return the error code corresponding to the operation result
|
|
**/
|
|
enum json_error json_insert_child (json_t * parent, json_t * child);
|
|
json_t * json_new_child (json_type_e type, const char *text_value);
|
|
|
|
enum json_error json_copy_label (json_t *root, json_t *srcparent);
|
|
|
|
/**
|
|
Inserts a label:value pair into a parent node, as well as performs some document tree integrity checks.
|
|
@param parent the parent node
|
|
@param text_label a char string which serves as the label in the label:value pair
|
|
@param value the value in the label:value pair
|
|
@return the error code corresponding to the operation result
|
|
**/
|
|
enum json_error json_insert_pair_into_object (json_t * parent, const char *text_label, json_t * value);
|
|
|
|
/**
|
|
Produces a JSON markup text document from a document tree
|
|
@param root The document's root node
|
|
@param text a pointer to a char string that will hold the JSON document text.
|
|
@return a json_error code describing how the operation went
|
|
**/
|
|
enum json_error json_tree_to_buffer (json_t *root, rcstring **prcbuf);
|
|
|
|
|
|
/**
|
|
Produces a JSON markup text document from a document tree
|
|
@param root The document's root node
|
|
@param text a pointer to a char string that will hold the JSON document text.
|
|
@return a json_error code describing how the operation went
|
|
**/
|
|
enum json_error json_tree_to_string (json_t * root, char **text);
|
|
|
|
|
|
/**
|
|
Produces a JSON markup text document from a json_t document tree to a text stream
|
|
@param file a opened file stream
|
|
@param root The document's root node
|
|
@return a json_error code describing how the operation went
|
|
**/
|
|
enum json_error json_stream_output (FILE * file, json_t * root);
|
|
|
|
|
|
/**
|
|
Strips all JSON white spaces from the text string
|
|
@param text a char string holding a JSON document or document snippet
|
|
**/
|
|
void json_strip_white_spaces (char *text);
|
|
|
|
|
|
/**
|
|
Formats a JSON markup text contained in the given string
|
|
@param text a JSON formatted document
|
|
@return a pointer to a char string holding the formated document
|
|
**/
|
|
char *json_format_string (const char *text);
|
|
|
|
|
|
/**
|
|
Outputs a new UTF8 c-string which replaces all characters that must be escaped with their respective escaped versions
|
|
@param text an UTF8 char text string
|
|
@return an UTF-8 c-string holding the same text string but with escaped characters
|
|
**/
|
|
char *json_escape (const char *text);
|
|
|
|
|
|
/**
|
|
* Outputs a new UTF-8 c-string which has all escaped characters replaced by
|
|
* their unescaped, UTF-8 encoded variants.
|
|
*
|
|
* @param test a UTF-8 c-string
|
|
* @return a newly allocated UTF-8 c-string; free with free()
|
|
*/
|
|
char *json_unescape (const char *text);
|
|
|
|
|
|
/**
|
|
This function takes care of the tedious task of initializing any instance of
|
|
struct json_parsing_info
|
|
@param jpi a pointer to a struct json_parsing_info instance
|
|
**/
|
|
void json_jpi_init (struct json_parsing_info *jpi);
|
|
|
|
|
|
/**
|
|
Produces a document tree sequentially from a JSON markup text fragment
|
|
@param info the information necessary to resume parsing any incomplete document
|
|
@param buffer a null-terminated c-string containing a JSON document fragment
|
|
@return a code describing how the operation ended up
|
|
**/
|
|
enum json_error json_parse_fragment (struct json_parsing_info *info, const char *buffer);
|
|
|
|
|
|
/**
|
|
Produces a document tree from a JSON markup text string that contains a complete document
|
|
@param root a reference to a pointer to a json_t type. The function allocates memory to the passed pointer and sets up the value
|
|
@param text a c-string containing a complete JSON text document
|
|
@return a pointer to the new document tree or NULL if some error occurred
|
|
**/
|
|
enum json_error json_parse_document (json_t ** root, const char *text);
|
|
|
|
|
|
/**
|
|
Function to perform a SAX-like parsing of any JSON document or document fragment that is passed to it
|
|
@param jsps a structure holding the status information of the current parser
|
|
@param jsf a structure holding the function pointers to the event functions
|
|
@param c the character to be parsed
|
|
@return a json_error code informing how the parsing went
|
|
**/
|
|
enum json_error json_saxy_parse (struct json_saxy_parser_status *jsps, struct json_saxy_functions *jsf, char c);
|
|
|
|
|
|
/**
|
|
Searches through the object's children for a label holding the text text_label
|
|
@param object a json_value of type JSON_OBJECT
|
|
@param text_label the c-string to search for through the object's child labels
|
|
@return a pointer to the first label holding a text equal to text_label or NULL if there is no such label or if object has no children
|
|
**/
|
|
json_t * json_find_first_label (const json_t * object, const char *text_label);
|
|
char * json_find_first_value (const json_t * object, const char *text_label);
|
|
|
|
char * json_find_value (const json_t * object, const char *parameter);
|
|
json_t * json_find_label (const json_t * object, const char *text_label);
|
|
rstring_code rcs_catc (rcstring * pre, const char c);
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|
|
#endif
|