/** rjp Copyright (C) 2018-2020 rexy712 This program 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 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 General Public License along with this program. If not, see . */ /* * Control how rjp_to_json outputs */ typedef enum RJP_format_flag{ RJP_FORMAT_NONE = 0, RJP_FORMAT_KEY_SPACES = 1, RJP_FORMAT_NEWLINES = 2, RJP_FORMAT_TABBED_LINES = RJP_FORMAT_NEWLINES | 4, RJP_FORMAT_COMMA_SPACES = 8, RJP_FORMAT_PRETTY = RJP_FORMAT_KEY_SPACES | RJP_FORMAT_NEWLINES | RJP_FORMAT_TABBED_LINES }RJP_format_flag; /* * Control what extensions are allowed in rjp_parse */ typedef enum RJP_parse_flag{ RJP_PARSE_NO_EXT = 0, RJP_PARSE_ALLOW_COMMENTS = 1, RJP_PARSE_ALLOW_TRAILING_COMMA = 2, RJP_PARSE_ALL_EXT = RJP_PARSE_ALLOW_COMMENTS | RJP_PARSE_ALLOW_TRAILING_COMMA }RJP_parse_flag; /* * Different data types allowed in JSON. Used to determine * what type a given RJP_value holds. */ typedef enum RJP_data_type{ rjp_json_object = 1, rjp_json_ordered_object = 3, rjp_json_string = 2, rjp_json_integer = 4, rjp_json_dfloat = 8, rjp_json_boolean = 16, rjp_json_array = 32, rjp_json_null = 64 }RJP_data_type; /* * Represent a C string @member value: NULL terminated C string @member length: Length of value excluding NULL terminator */ typedef struct RJP_string{ char* value; RJP_index length; }RJP_string; /* * Used to iterate over object members * Members should NOT be accessed directly by user */ typedef struct RJP_object_iterator{ union{ struct RJP_object_iterator_impl* it; RJP_value* current; }; RJP_data_type type; }RJP_object_iterator; /* * Used to iterate over array elements * Members should NOT be accessed directly by user */ typedef struct RJP_array_iterator{ RJP_value* current; }RJP_array_iterator; /* * Information needed by rjp_parse_cback @member read: callback to read JSON string from. required to retun number of bytes read. @member data: data to be passed to read callback function */ typedef struct RJP_parse_callback{ int(*read)(char*,int,void*); void* data; }RJP_parse_callback; /* * Retains enough information from a parse run to construct an error message and where the error occurred. @member parsestate: internal use only @member errcode: enumeration of what the error was @member row: what row of the input contained the error @member column: where in the row that the error occurred */ typedef struct RJP_parse_error{ void* parsestate; int errcode; int row, column; }RJP_parse_error; /***************** NON OBJECT OPERATIONS *******************/ /* * Allocate heap space for rjp to use. Use if the memory is to be freed * by rjp @param nbytes: number of bytes to allocate @returns: pointer to newly allocated memory */ void* rjp_alloc(RJP_index nbytes); /* * Allocate heap space for rjp and initialize to 0. @param num: number of elements to allocate @param nbytes: number of bytes per element @returns: pointer to newly allocated memory */ void* rjp_calloc(RJP_index num, RJP_index nbytes); /* * Free memory allocated by rjp_alloc or rjp_calloc @param dest: memory to free */ void rjp_free(void* dest); /* * copy input string and add json escape sequences @param dest: output buffer @param src: source string @returns: length of string in dest excluding NULL terminator */ RJP_index rjp_escape_strcpy(char* dest, const char* src); /* * length of string after escaping @param src: string to measure @returns: length of escaped string excluding NULL terminator */ RJP_index rjp_escape_strlen(const char* str); /* * copy input string and add json escape sequences @param src: source string @returns: newly allocated string copy */ RJP_string rjp_escape(const char* src); /***************** GENERIC OPERATIONS *******************/ /* * Convert C string of json data into RJP's format using no extensions and without error reporting. @param str: input JSON @returns: pointer to root value or NULL on failure */ RJP_value* rjp_simple_parse(const char* str); /* * Convert C string consisting of json data into RJP's format @param str: input JSON @param flags: RJP_parse_flags OR'd together @returns: pointer to root value or NULL on failure */ RJP_value* rjp_parse(const char* str, int flags, RJP_parse_error* err); /* * Read json data in using a user supplied callback and convert * it to RJP's format @param flags: RJP_parse_flags OR'd together @param cbacks: RJP_parse_callback with function/data used for reading @returns: pointer to root value or NULL on failure */ RJP_value* rjp_parse_cback(int flags, RJP_parse_callback* cbacks, RJP_parse_error* err); /* * Allocate a string representing the error stored in RJP_parse_error structure @param err: pointer to error to stringify @returns: rjp_alloc'd pointer to string describing the error. Must be freed with rjp_free */ char* rjp_parse_error_to_string(const RJP_parse_error* err); /* * Cleanup a RJP_parse_error structure when finished Note: DO NOT call if rjp_parse* was successful. Error will contain garbage data and will cause a segfault. @param err: pointer to error which needs cleanup */ void rjp_delete_parse_error(RJP_parse_error* err); /* * Convert RJP's representation to rjp_alloc'd JSON string @param root: RJP_value to print out @param pretty: RJP_format_flag on how to print @returns: rjp_alloc'd string with JSON data or NULL on error */ char* rjp_to_json(const RJP_value* root, int pretty); /* * Create new RJP_value of null type @returns: are you stupid? */ RJP_value* rjp_new_null(void); /* * Create new RJP_value of int type @param val: really? @returns: are you stupid? */ RJP_value* rjp_new_int(RJP_int val); /* * Create new RJP_value of float type @param val: really? @returns: are you stupid? */ RJP_value* rjp_new_float(RJP_float val); /* * Create new RJP_value of bool type @param val: really? @returns: are you stupid? */ RJP_value* rjp_new_bool(RJP_bool val); /* * Create new RJP_value of string type, coping val @param val: really? @param length: c'mon @returns: are you stupid? */ RJP_value* rjp_new_string(const char* val, RJP_index length); /* * Create new RJP_value of string type, stealing value of val @param val: really? @param length: c'mon @returns: are you stupid? */ RJP_value* rjp_new_string_steal(char* val, RJP_index length); /* * Create new RJP_value of object type @returns: are you stupid? */ RJP_value* rjp_new_object(void); /* * Create new RJP_value of ordered object type @returns: are you stupid? */ RJP_value* rjp_new_ordered_object(void); /* * Create new RJP_value of array type @returns: are you stupid? */ RJP_value* rjp_new_array(void); /* * Deallocate RJP_value and all its members/elements @param root: RJP_value to free */ void rjp_free_value(RJP_value* root); /* * Deep copy RJP_value. When dest is not null, cleanup * and then fill the object pointed to by dest. * Otherwise allocate a new value. @param dest: value to copy to or NULL @param src: value to copy from @returns: pointer to dest or newly allocated copy of src */ RJP_value* rjp_copy_value(RJP_value* dest, const RJP_value* src); /* * Steal resources from src and use them to populate dest * No copy is performed. @param dest: value to copy to @param src: value to copy from @returns: poniter to dest */ RJP_value* rjp_move_value(RJP_value* dest, RJP_value* src); /* * change an RJP_value to null type @param v: RJP_value to set @returns: pointer to v */ RJP_value* rjp_set_null(RJP_value* v); /* * change an RJP_value to int type @param v: RJP_value to set @param val: really? @returns: pointer to v */ RJP_value* rjp_set_int(RJP_value* v, RJP_int val); /* * change an RJP_value to float type @param v: RJP_value to set @param val: really? @returns: pointer to v */ RJP_value* rjp_set_float(RJP_value* v, RJP_float val); /* * change an RJP_value to bool type @param v: RJP_value to set @param val: really? @returns: pointer to v */ RJP_value* rjp_set_bool(RJP_value* v, RJP_bool val); /* * change an RJP_value to string type, copying source @param v: RJP_value to set @param val: string to copy @param length: length of val @returns: pointer to v */ RJP_value* rjp_set_string(RJP_value* v, const char* val, RJP_index length); /* * change an RJP_value to string type, stealing source @param v: RJP_value to set @param val: string to steal @param length: length of val @returns: pointer to v */ RJP_value* rjp_set_string_steal(RJP_value* v, char* val, RJP_index length); /* * change an RJP_value to object type @param v: RJP_value to set @returns: pointer to v */ RJP_value* rjp_set_object(RJP_value* v); /* * change an RJP_value to ordered object type @param v: RJP_value to set @returns: pointer to v */ RJP_value* rjp_set_ordered_object(RJP_value* v); /* * change an RJP_value to array type @param v: RJP_value to set @returns: pointer to v */ RJP_value* rjp_set_array(RJP_value* v); /* * Retrieve float value in value @param value: RJP_value to query @returns: duh */ RJP_float rjp_get_float(const RJP_value* value); /* * Retrieve int value in value @param value: RJP_value to query @returns: duh */ RJP_int rjp_get_int(const RJP_value* value); /* * Retrieve bool value in value @param value: RJP_value to query @returns: duh */ RJP_bool rjp_get_bool(const RJP_value* value); /* * Retrieve string value in value @param value: RJP_value to query @returns: RJP_string pointer with value and length inside */ RJP_string* rjp_get_string(RJP_value* value); /* * Retrieve float value in value @param value: RJP_value to query @returns: RJP_string pointer with value and length inside */ const RJP_string* rjp_get_cstring(const RJP_value* value); /***************** OBJECT/ARRAY SHARED OPERATIONS *******************/ /* * Get pointer to parent of value @param element: value to query @returns: pointer to parent of element */ RJP_value* rjp_value_parent(const RJP_value* element); /* * Return type of value @param value: value to query @returns: seek help if you can't figure this out */ RJP_data_type rjp_value_type(const RJP_value* value); /***************** OBJECT OPERATIONS *******************/ /* * create a member in an object @param dest: object to add to @param key: key to copy value of @param keylen: length of key @returns: pointer to new member */ RJP_value* rjp_new_member(RJP_value* dest, const char* key, RJP_index keylen); /* * create a member in an object, stealing key @param dest: object to add to @param key: key to steal value from @param keylen: length of key @returns: pointer to new member */ RJP_value* rjp_new_member_steal_key(RJP_value* dest, char* key, RJP_index keylen); /* * move a value into a new member in an object @param dest: object to add to @param key: key to copy value of @param keylen: length of key @param src: value to move from @returns: pointer to new member */ RJP_value* rjp_add_member(RJP_value* dest, const char* key, RJP_index keylen, RJP_value* src); /* * move a value into a new meber in an object, stealing key @param dest: object to add to @param key: key to steal value from @param keylen: length of key @param src: value to move from @returns: pointer to new member */ RJP_value* rjp_add_member_steal_key(RJP_value* dest, char* key, RJP_index keylen, RJP_value* src); /* * Remove member without freeing @param obj: object to remove from @param key: key to search for @returns: pointer to former member */ RJP_value* rjp_remove_member_by_key(RJP_value* obj, const char* key); /* * Remove member without freeing @param obj: object to remove from @param member: pointer to object's member @returns: pointer to former member */ RJP_value* rjp_remove_member(RJP_value* obj, RJP_value* member); /* * Remove and free member @param obj: object to remove from @param key: key to search for */ void rjp_free_member_by_key(RJP_value* obj, const char* key); /* * Remove and free member @param obj: object to remove from @param member: pointer to object's member */ void rjp_free_member(RJP_value* obj, RJP_value* member); /* * set existing object member's key. Steal's value of parameter. * key must be allocated using rjp_alloc/rjp_calloc @param dest: member to set key of @param key: key to steal value of @param keylen: length of key */ void rjp_set_key_steal(RJP_value* dest, char* key, RJP_index keylen); /* * set existing object member's key. Copies key parameter @param dest: member to set key of @param key: key to copy value of @param keylen: length of key */ void rjp_set_key(RJP_value* dest, const char* key, RJP_index keylen); /* * Return number of members in the object @param object: object to query @returns: dear god please help me */ RJP_index rjp_num_members(const RJP_value* object); /* * Return the object member's key @param member: object member to query @returns: object member's key/length pair */ const RJP_string* rjp_member_key(const RJP_value* member); /* * Search for an object member with given key @param object: object to search within @param search: key to search for @returns: pointer to member with given key or NULL if not found */ RJP_value* rjp_search_member(const RJP_value* object, const char* search); /* * Convert unordered object to ordered object @param object: object to convert @returns: pointer to object */ RJP_value* rjp_object_to_ordered(RJP_value* object); /* * Convert ordered object to unordered object @param object: object to convert @returns: pointer to object */ RJP_value* rjp_object_to_unordered(RJP_value* object); /***************** OBJECT ITERATOR OPERATIONS *******************/ /* * Initialize object iterator to iterate over given object @param iter: iterator to initialize @param object: object to iterate over */ void rjp_init_object_iterator(RJP_object_iterator* iter, const RJP_value* object); /* * Delete object iterator @param it: iterator to delete */ void rjp_delete_object_iterator(RJP_object_iterator* it); /* * Get current value in iterator @param it: iterator to query @returns: pointer to current value in iterator */ RJP_value* rjp_object_iterator_current(const RJP_object_iterator* it); /* * Advance iterator to next value and return it @param it: iterator to query @returns: pointer to next value in iterator */ RJP_value* rjp_object_iterator_next(RJP_object_iterator* it); /* * View next value in iterator without advancing @param it: iterator to query @returns: pointer to next value in iterator */ RJP_value* rjp_object_iterator_peek(const RJP_object_iterator* it); /***************** ARRAY OPERATIONS *******************/ /* * create an element in an array @param dest: array to add element to @returns: pointer to new element */ RJP_value* rjp_new_element(RJP_value* dest); /* * create an element in an array and steal value in src @param arr: array to add element to @param src: value to steal contents of @returns: pointer to new element */ RJP_value* rjp_add_element(RJP_value* dest, RJP_value* src); /* * remove element from array without freeing it @param arr: array to remove element from @param elem: element to remove @returns: pointer to former element */ RJP_value* rjp_remove_element(RJP_value* arr, RJP_value* elem); /* * remove and free element from array @param arr: array to remove element from @param elem: element to free */ void rjp_free_element(RJP_value* arr, RJP_value* elem); /* * Get number of element in array @param src: array to query @returns: don't be gay */ RJP_index rjp_num_elements(const RJP_value* arr); /***************** ARRAY ITERATOR OPERATIONS *******************/ /* * Initialize object iterator to iterate over given object @param iter: iterator to initialize @param array: array to iterate over @returns: you're bein gay */ void rjp_init_array_iterator(RJP_array_iterator* iter, const RJP_value* array); /* * Delete array iterator @param iter: iterator to delete */ void rjp_delete_array_iterator(RJP_array_iterator* iter); /* * Get current value in iterator @param it: iterator to query @returns: pointer to current value in iterator */ RJP_value* rjp_array_iterator_current(const RJP_array_iterator* it); /* * Advance iterator to next value and return it @param it: iterator to query @returns: pointer to next value in iterator */ RJP_value* rjp_array_iterator_next(RJP_array_iterator* it); /* * View next value in iterator without advancing @param it: iterator to query @returns: pointer to next value in iterator */ RJP_value* rjp_array_iterator_peek(const RJP_array_iterator* it);