You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
218 lines
8.1 KiB
218 lines
8.1 KiB
//Author: Tony Wilk
|
|
//Source: https://www.codeproject.com/Articles/887604/jWrite-A-Really-Simple-JSON-Writer-in-C
|
|
//LICENSE: The Code Project Open License (CPOL) 1.02
|
|
//see provided file ICENSE_jReadJWrite.html or https://www.codeproject.com/info/cpol10.aspx
|
|
|
|
//
|
|
// jWrite.h
|
|
//
|
|
// A *really* simple JSON writer in C (C89)
|
|
// - a collection of functions to generate JSON semi-automatically
|
|
//
|
|
// The idea is to simplify writing native C values into a JSON string and
|
|
// to provide some error trapping to ensure that the result is valid JSON.
|
|
//
|
|
// Example:
|
|
// jwOpen( buffer, buflen, JW_OBJECT, JW_PRETTY ); // open root node as object
|
|
// jwObj_string( "key", "value" );
|
|
// jwObj_int( "int", 1 );
|
|
// jwObj_array( "anArray");
|
|
// jwArr_int( 0 );
|
|
// jwArr_int( 1 );
|
|
// jwArr_int( 2 );
|
|
// jwEnd();
|
|
// err= jwClose(); // close root object
|
|
//
|
|
// results in:
|
|
//
|
|
// {
|
|
// "key": "value",
|
|
// "int": 1,
|
|
// "anArray": [
|
|
// 0,
|
|
// 1,
|
|
// 2
|
|
// ]
|
|
// }
|
|
//
|
|
// Note that jWrite handles string quoting and getting commas in the right place.
|
|
// If the sequence of calls is incorrect
|
|
// e.g.
|
|
// jwOpen( buffer, buflen, JW_OBJECT, 1 );
|
|
// jwObj_string( "key", "value" );
|
|
// jwArr_int( 0 );
|
|
// ...
|
|
//
|
|
// then the error code returned from jwClose() would indicate that you attempted to
|
|
// put an array element into an object (instead of a key:value pair)
|
|
// To locate the error, the supplied buffer has the JSON created upto the error point
|
|
// and a call to jwErrorPos() would return the function call at which the error occurred
|
|
// - in this case 3, the 3rd function call "jwArr_int(0)" is not correct at this point.
|
|
//
|
|
// The root JSON type can be JW_OBJECT or JW_ARRAY.
|
|
//
|
|
// For more information on each function, see the prototypes below.
|
|
//
|
|
//
|
|
// GLOBAL vs. Application-Supplied Control Structure
|
|
// -------------------------------------------------
|
|
// jWrite requires a jWriteControl structure to save the internal state.
|
|
// For many applications it is much simpler for this to be a global variable as
|
|
// used by the above examples.
|
|
//
|
|
// To use multiple instances of jWrite, an application has to supply unique instances
|
|
// of jWriteControl structures.
|
|
//
|
|
// This feature is enabled by commenting out the definition of JW_GLOBAL_CONTROL_STRUCT
|
|
//
|
|
// All the jWrite functions then take an additional parameter: a ptr to the structure
|
|
// e.g.
|
|
// struct jWriteControl jwc;
|
|
//
|
|
// jwOpen( &jwc, buffer, buflen, JW_OBJECT, 1 );
|
|
// jwObj_string( &jwc, "key", "value" );
|
|
// jwObj_int( &jwc, "int", 1 );
|
|
// jwObj_array( &jwc, "anArray");
|
|
// jwArr_int( &jwc, 0 );
|
|
// jwArr_int( &jwc, 1 );
|
|
// jwArr_int( &jwc, 2 );
|
|
// jwEnd( &jwc );
|
|
// err= jwClose( &jwc );
|
|
//
|
|
// - which is more flexible, but a pain to type in !
|
|
//
|
|
// TonyWilk, Mar 2015
|
|
//
|
|
//
|
|
#define JW_GLOBAL_CONTROL_STRUCT // <--- comment this out to use applic-supplied jWriteControl
|
|
|
|
#define JWRITE_STACK_DEPTH 32 // max nesting depth of objects/arrays
|
|
|
|
#define JW_COMPACT 0 // output string control for jwOpen()
|
|
#define JW_PRETTY 1 // pretty adds \n and indentation
|
|
|
|
enum jwNodeType{
|
|
JW_OBJECT= 1,
|
|
JW_ARRAY
|
|
};
|
|
|
|
struct jwNodeStack{
|
|
enum jwNodeType nodeType;
|
|
int elementNo;
|
|
};
|
|
|
|
struct jWriteControl{
|
|
char *buffer; // pointer to application's buffer
|
|
unsigned int buflen; // length of buffer
|
|
char *bufp; // current write position in buffer
|
|
char tmpbuf[32]; // local buffer for int/double convertions
|
|
int error; // error code
|
|
int callNo; // API call on which error occurred
|
|
struct jwNodeStack nodeStack[JWRITE_STACK_DEPTH]; // stack of array/object nodes
|
|
int stackpos;
|
|
int isPretty; // 1= pretty output (inserts \n and spaces)
|
|
};
|
|
|
|
// Error Codes
|
|
// -----------
|
|
#define JWRITE_OK 0
|
|
#define JWRITE_BUF_FULL 1 // output buffer full
|
|
#define JWRITE_NOT_ARRAY 2 // tried to write Array value into Object
|
|
#define JWRITE_NOT_OBJECT 3 // tried to write Object key/value into Array
|
|
#define JWRITE_STACK_FULL 4 // array/object nesting > JWRITE_STACK_DEPTH
|
|
#define JWRITE_STACK_EMPTY 5 // stack underflow error (too many 'end's)
|
|
#define JWRITE_NEST_ERROR 6 // nesting error, not all objects closed when jwClose() called
|
|
|
|
|
|
// API functions
|
|
// -------------
|
|
|
|
// Returns '\0'-termianted string describing the error (as returned by jwClose())
|
|
//
|
|
char *jwErrorToString( int err );
|
|
|
|
|
|
#ifdef JW_GLOBAL_CONTROL_STRUCT /* USING GLOBAL g_jWriteControl */
|
|
|
|
// jwOpen
|
|
// - initialises jWrite with the application supplied 'buffer' of length 'buflen'
|
|
// in operation, the buffer will always contain a valid '\0'-terminated string
|
|
// - jWrite will not overrun the buffer (it returns an "output buffer full" error)
|
|
// - rootType is the base JSON type: JW_OBJECT or JW_ARRAY
|
|
// - isPretty controls 'prettifying' the output: JW_PRETTY or JW_COMPACT
|
|
void jwOpen( char *buffer, unsigned int buflen, enum jwNodeType rootType, int isPretty );
|
|
|
|
// jwClose
|
|
// - closes the element opened by jwOpen()
|
|
// - returns error code (0 = JWRITE_OK)
|
|
// - after an error, all following jWrite calls are skipped internally
|
|
// so the error code is for the first error detected
|
|
int jwClose( );
|
|
|
|
// jwErrorPos
|
|
// - if jwClose returned an error, this function returns the number of the jWrite function call
|
|
// which caused that error.
|
|
int jwErrorPos( );
|
|
|
|
// Object insertion functions
|
|
// - used to insert "key":"value" pairs into an object
|
|
//
|
|
void jwObj_string( char *key, char *value );
|
|
void jwObj_int( char *key, int value );
|
|
void jwObj_double( char *key, double value );
|
|
void jwObj_bool( char *key, int oneOrZero );
|
|
void jwObj_null( char *key );
|
|
void jwObj_object( char *key );
|
|
void jwObj_array( char *key );
|
|
|
|
// Array insertion functions
|
|
// - used to insert "value" elements into an array
|
|
//
|
|
void jwArr_string( char *value );
|
|
void jwArr_int( int value );
|
|
void jwArr_double( double value );
|
|
void jwArr_bool( int oneOrZero );
|
|
void jwArr_null( );
|
|
void jwArr_object( );
|
|
void jwArr_array( );
|
|
|
|
// jwEnd
|
|
// - defines the end of an Object or Array definition
|
|
int jwEnd( );
|
|
|
|
|
|
// these 'raw' routines write the JSON value as the contents of rawtext
|
|
// i.e. enclosing quotes are not added
|
|
// - use if your app. supplies its own value->string functions
|
|
//
|
|
void jwObj_raw( char *key, char *rawtext );
|
|
void jwArr_raw( char *rawtext );
|
|
|
|
#else /* JW_GLOBAL_CONTROL_STRUCT not defined */
|
|
// Same API functions with app-supplied control struct option
|
|
//
|
|
void jwOpen( struct jWriteControl *jwc, char *buffer, unsigned int buflen, enum jwNodeType rootType, int isPretty );
|
|
int jwClose( struct jWriteControl *jwc );
|
|
int jwErrorPos( struct jWriteControl *jwc );
|
|
void jwObj_string( struct jWriteControl *jwc, char *key, char *value );
|
|
void jwObj_int( struct jWriteControl *jwc, char *key, int value );
|
|
void jwObj_double( struct jWriteControl *jwc, char *key, double value );
|
|
void jwObj_bool( struct jWriteControl *jwc, char *key, int oneOrZero );
|
|
void jwObj_null( struct jWriteControl *jwc, char *key );
|
|
void jwObj_object( struct jWriteControl *jwc, char *key );
|
|
void jwObj_array( struct jWriteControl *jwc, char *key );
|
|
void jwArr_string( struct jWriteControl *jwc, char *value );
|
|
void jwArr_int( struct jWriteControl *jwc, int value );
|
|
void jwArr_double( struct jWriteControl *jwc, double value );
|
|
void jwArr_bool( struct jWriteControl *jwc, int oneOrZero );
|
|
void jwArr_null( struct jWriteControl *jwc );
|
|
void jwArr_object( struct jWriteControl *jwc );
|
|
void jwArr_array( struct jWriteControl *jwc );
|
|
int jwEnd( struct jWriteControl *jwc );
|
|
void jwObj_raw( struct jWriteControl *jwc, char *key, char *rawtext );
|
|
void jwArr_raw( struct jWriteControl *jwc, char *rawtext );
|
|
|
|
#endif /* JW_GLOBAL_CONTROL_STRUCT */
|
|
|
|
|
|
/* end of jWrite.h */
|
|
|