├── .gitignore ├── LICENSE ├── Makefile.am ├── README.md ├── configure.ac ├── example ├── Makefile.am └── server.c ├── include ├── Makefile.am ├── cJSON.h └── jsonrpc-c.h └── src ├── Makefile.am ├── cJSON.c └── jsonrpc-c.c /.gitignore: -------------------------------------------------------------------------------- 1 | # Object files 2 | *.o 3 | 4 | # Libraries 5 | *.lib 6 | *.a 7 | 8 | # Shared objects (inc. Windows DLLs) 9 | *.dll 10 | *.so 11 | *.so.* 12 | *.dylib 13 | 14 | # Executables 15 | *.exe 16 | *.out 17 | *.app 18 | 19 | # Generated file by autotools 20 | Makefile 21 | Makefile.in 22 | aclocal.m4 23 | ar-lib 24 | autom4te.cache/ 25 | compile 26 | config.guess 27 | config.h 28 | config.h.in 29 | config.log 30 | config.status 31 | config.sub 32 | configure 33 | depcomp 34 | example/.deps/ 35 | example/Makefile 36 | example/Makefile.in 37 | include/Makefile 38 | include/Makefile.in 39 | install-sh 40 | libtool 41 | ltmain.sh 42 | missing 43 | src/.deps/ 44 | src/Makefile 45 | src/Makefile.in 46 | stamp-h1 47 | 48 | # Editor text 49 | *.swp 50 | *~ 51 | 52 | # Build 53 | *.la 54 | *.lo 55 | *.libs 56 | example/server 57 | 58 | /Build (GNU)/ 59 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012-2024 Henrique Gomes 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | 22 | -------------------------------------------------------------------------------- /Makefile.am: -------------------------------------------------------------------------------- 1 | SUBDIRS=src include example 2 | ACLOCAL_AMFLAGS=-I m4 -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | jsonrpc-c 2 | ========= 3 | 4 | JSON-RPC in C (server only for now) 5 | 6 | What? 7 | ----- 8 | A library for a C program to receive JSON-RPC requests on tcp sockets (no HTTP). 9 | 10 | Free software, MIT license. 11 | 12 | Why? 13 | ---- 14 | I needed a way for an application written in C, running on an embedded Linux system to be configured by 15 | a Java/Swing configuration tool running on a connected laptop. Wanted something simple, human readable, 16 | and saw no need for HTTP. 17 | 18 | How? 19 | ---- 20 | It depends on libev http://software.schmorp.de/pkg/libev.html (was already used on the embedded app) and includes cJSON (from https://github.com/DaveGamble/cJSON). 21 | No further dependencies. 22 | 23 | ### Testing 24 | 25 | Run `autoreconf -i` before `./configure` and `make` 26 | 27 | Test the example server by running it and typing: 28 | 29 | `echo "{\"method\":\"sayHello\"}" | nc localhost 1234` 30 | 31 | or 32 | 33 | `echo "{\"method\": \"add\", \"params\": [3,4], \"id\": \"SOME_IDENTIFIER\" }" | nc localhost 1234` 34 | 35 | or 36 | 37 | `echo "{\"method\":\"exit\"}" | nc localhost 1234` 38 | 39 | Who? 40 | ---- 41 | 42 | @hmngomes -------------------------------------------------------------------------------- /configure.ac: -------------------------------------------------------------------------------- 1 | AC_INIT([jsonrpc-c], [0.1], [jsonrpc-c@farol.pt]) 2 | AC_CONFIG_SRCDIR([src/jsonrpc-c.c]) 3 | 4 | m4_pattern_allow([AM_PROG_AR]) 5 | AM_PROG_AR 6 | LT_INIT 7 | AM_INIT_AUTOMAKE([-Wall -Werror foreign]) 8 | AC_PROG_CC 9 | AM_PROG_CC_C_O 10 | AC_CONFIG_MACRO_DIRS([m4]) 11 | 12 | AC_HEADER_STDBOOL 13 | 14 | #AC_CHECK_LIB([ev], [ev_io_init],[], [AC_MSG_ERROR([libev was not found])]) 15 | #AC_CHECK_LIB([ev],[ev_sleep],[],[AC_MSG_ERROR([libev was not found])]) 16 | 17 | # stollen from lighttpd's configure.ac 18 | AC_MSG_CHECKING([for libev support]) 19 | AC_ARG_WITH([libev], 20 | [AS_HELP_STRING([--with-libev@<:@=PATH@:>@],[Search for libev in PATH/include and PATH/lib])], 21 | [WITH_LIBEV=$withval],[WITH_LIBEV=yes]) 22 | 23 | LIBEV_CFLAGS="-lm" 24 | LIBEV_LIBS="" 25 | 26 | PKG_CHECK_MODULES([LIBEV], [libev], [], [ 27 | # no pkg-config for libev, searching manually: 28 | if test "$WITH_LIBEV" != "yes"; then 29 | LIBEV_CFLAGS="-I$WITH_LIBEV/include" 30 | LIBEV_LIBS="-L$WITH_LIBEV/lib -lev" 31 | else 32 | AC_CHECK_HEADERS([ev.h],[ 33 | AC_CHECK_LIB([ev], [ev_time], [ 34 | LIBEV_LIBS="-lev" 35 | ],[ 36 | AC_MSG_ERROR([libev not found]) 37 | ] 38 | )],[ 39 | AC_MSG_ERROR([libev not found]) 40 | ] 41 | ) 42 | fi 43 | ]) 44 | 45 | AC_SUBST([LIBEV_CFLAGS]) 46 | AC_SUBST([LIBEV_LIBS]) 47 | 48 | AC_MSG_RESULT([ 49 | LIBEV_CFLAGS: ${LIBEV_CFLAGS} 50 | LIBEV_LIBS: ${LIBEV_LIBS} 51 | ]) 52 | 53 | AC_CONFIG_HEADERS([config.h]) 54 | AC_CONFIG_FILES([ 55 | Makefile 56 | include/Makefile 57 | src/Makefile 58 | example/Makefile 59 | ]) 60 | AC_OUTPUT 61 | 62 | -------------------------------------------------------------------------------- /example/Makefile.am: -------------------------------------------------------------------------------- 1 | ####################################### 2 | # The list of executables we are building seperated by spaces 3 | # the 'bin_' indicates that these build products will be installed 4 | # in the $(bindir) directory. For example /usr/bin 5 | #bin_PROGRAMS=exampleProgram 6 | 7 | # Because a.out is only a sample program we don't want it to be installed. 8 | # The 'noinst_' prefix indicates that the following targets are not to be 9 | # installed. 10 | noinst_PROGRAMS=server 11 | 12 | ####################################### 13 | # Build information for each executable. The variable name is derived 14 | # by use the name of the executable with each non alpha-numeric character is 15 | # replaced by '_'. So a.out becomes a_out and the appropriate suffex added. 16 | # '_SOURCES' for example. 17 | 18 | # Sources for the a.out 19 | server_SOURCES= server.c 20 | 21 | # Linker options for a.out 22 | server_LDFLAGS = $(LIBEV_LIBS) $(top_builddir)/src/libjsonrpcc.la 23 | 24 | # Compiler options for a.out 25 | server_CPPFLAGS = $(LIBEV_CFLAGS) -I$(top_srcdir)/include 26 | 27 | -------------------------------------------------------------------------------- /example/server.c: -------------------------------------------------------------------------------- 1 | /* 2 | * server.c 3 | * 4 | * Created on: Oct 9, 2012 5 | * Author: hmng 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include "jsonrpc-c.h" 21 | 22 | #define PORT 1234 // the port users will be connecting to 23 | 24 | struct jrpc_server my_server; 25 | 26 | cJSON* say_hello(jrpc_context *ctx, cJSON *params, cJSON *id) { 27 | return cJSON_CreateString("Hello!"); 28 | } 29 | 30 | cJSON* add(jrpc_context *ctx, cJSON *params, cJSON *id) { 31 | cJSON *a = cJSON_GetArrayItem(params, 0); 32 | cJSON *b = cJSON_GetArrayItem(params, 1); 33 | return cJSON_CreateNumber(a->valueint + b->valueint); 34 | } 35 | 36 | cJSON* notify(jrpc_context *ctx, cJSON *param, cJSON *id) { 37 | return NULL; 38 | } 39 | 40 | cJSON* exit_server(jrpc_context *ctx, cJSON *params, cJSON *id) { 41 | jrpc_server_stop(&my_server); 42 | return cJSON_CreateString("Bye!"); 43 | } 44 | 45 | int main(void) { 46 | jrpc_server_init(&my_server, PORT); 47 | my_server.debug_level = 1; 48 | jrpc_register_procedure(&my_server, say_hello, "sayHello", NULL); 49 | jrpc_register_procedure(&my_server, add, "add", NULL); 50 | jrpc_register_procedure(&my_server, notify, "notify", NULL); 51 | jrpc_register_procedure(&my_server, exit_server, "exit", NULL); 52 | jrpc_server_run(&my_server); 53 | jrpc_server_destroy(&my_server); 54 | return 0; 55 | } 56 | -------------------------------------------------------------------------------- /include/Makefile.am: -------------------------------------------------------------------------------- 1 | # These files will end up in the install include directory 2 | # For example, /usr/include 3 | include_HEADERS = cJSON.h jsonrpc-c.h 4 | -------------------------------------------------------------------------------- /include/cJSON.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2009-2017 Dave Gamble and cJSON contributors 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | THE SOFTWARE. 21 | */ 22 | 23 | #ifndef cJSON__h 24 | #define cJSON__h 25 | 26 | #ifdef __cplusplus 27 | extern "C" 28 | { 29 | #endif 30 | 31 | #if !defined(__WINDOWS__) && (defined(WIN32) || defined(WIN64) || defined(_MSC_VER) || defined(_WIN32)) 32 | #define __WINDOWS__ 33 | #endif 34 | 35 | #ifdef __WINDOWS__ 36 | 37 | /* When compiling for windows, we specify a specific calling convention to avoid issues where we are being called from a project with a different default calling convention. For windows you have 3 define options: 38 | 39 | CJSON_HIDE_SYMBOLS - Define this in the case where you don't want to ever dllexport symbols 40 | CJSON_EXPORT_SYMBOLS - Define this on library build when you want to dllexport symbols (default) 41 | CJSON_IMPORT_SYMBOLS - Define this if you want to dllimport symbol 42 | 43 | For *nix builds that support visibility attribute, you can define similar behavior by 44 | 45 | setting default visibility to hidden by adding 46 | -fvisibility=hidden (for gcc) 47 | or 48 | -xldscope=hidden (for sun cc) 49 | to CFLAGS 50 | 51 | then using the CJSON_API_VISIBILITY flag to "export" the same symbols the way CJSON_EXPORT_SYMBOLS does 52 | 53 | */ 54 | 55 | #define CJSON_CDECL __cdecl 56 | #define CJSON_STDCALL __stdcall 57 | 58 | /* export symbols by default, this is necessary for copy pasting the C and header file */ 59 | #if !defined(CJSON_HIDE_SYMBOLS) && !defined(CJSON_IMPORT_SYMBOLS) && !defined(CJSON_EXPORT_SYMBOLS) 60 | #define CJSON_EXPORT_SYMBOLS 61 | #endif 62 | 63 | #if defined(CJSON_HIDE_SYMBOLS) 64 | #define CJSON_PUBLIC(type) type CJSON_STDCALL 65 | #elif defined(CJSON_EXPORT_SYMBOLS) 66 | #define CJSON_PUBLIC(type) __declspec(dllexport) type CJSON_STDCALL 67 | #elif defined(CJSON_IMPORT_SYMBOLS) 68 | #define CJSON_PUBLIC(type) __declspec(dllimport) type CJSON_STDCALL 69 | #endif 70 | #else /* !__WINDOWS__ */ 71 | #define CJSON_CDECL 72 | #define CJSON_STDCALL 73 | 74 | #if (defined(__GNUC__) || defined(__SUNPRO_CC) || defined (__SUNPRO_C)) && defined(CJSON_API_VISIBILITY) 75 | #define CJSON_PUBLIC(type) __attribute__((visibility("default"))) type 76 | #else 77 | #define CJSON_PUBLIC(type) type 78 | #endif 79 | #endif 80 | 81 | /* project version */ 82 | #define CJSON_VERSION_MAJOR 1 83 | #define CJSON_VERSION_MINOR 7 84 | #define CJSON_VERSION_PATCH 18 85 | 86 | #include 87 | 88 | /* cJSON Types: */ 89 | #define cJSON_Invalid (0) 90 | #define cJSON_False (1 << 0) 91 | #define cJSON_True (1 << 1) 92 | #define cJSON_NULL (1 << 2) 93 | #define cJSON_Number (1 << 3) 94 | #define cJSON_String (1 << 4) 95 | #define cJSON_Array (1 << 5) 96 | #define cJSON_Object (1 << 6) 97 | #define cJSON_Raw (1 << 7) /* raw json */ 98 | 99 | #define cJSON_IsReference 256 100 | #define cJSON_StringIsConst 512 101 | 102 | /* The cJSON structure: */ 103 | typedef struct cJSON 104 | { 105 | /* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */ 106 | struct cJSON *next; 107 | struct cJSON *prev; 108 | /* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */ 109 | struct cJSON *child; 110 | 111 | /* The type of the item, as above. */ 112 | int type; 113 | 114 | /* The item's string, if type==cJSON_String and type == cJSON_Raw */ 115 | char *valuestring; 116 | /* writing to valueint is DEPRECATED, use cJSON_SetNumberValue instead */ 117 | int valueint; 118 | /* The item's number, if type==cJSON_Number */ 119 | double valuedouble; 120 | 121 | /* The item's name string, if this item is the child of, or is in the list of subitems of an object. */ 122 | char *string; 123 | } cJSON; 124 | 125 | typedef struct cJSON_Hooks 126 | { 127 | /* malloc/free are CDECL on Windows regardless of the default calling convention of the compiler, so ensure the hooks allow passing those functions directly. */ 128 | void *(CJSON_CDECL *malloc_fn)(size_t sz); 129 | void (CJSON_CDECL *free_fn)(void *ptr); 130 | } cJSON_Hooks; 131 | 132 | typedef int cJSON_bool; 133 | 134 | /* Limits how deeply nested arrays/objects can be before cJSON rejects to parse them. 135 | * This is to prevent stack overflows. */ 136 | #ifndef CJSON_NESTING_LIMIT 137 | #define CJSON_NESTING_LIMIT 1000 138 | #endif 139 | 140 | /* returns the version of cJSON as a string */ 141 | CJSON_PUBLIC(const char*) cJSON_Version(void); 142 | 143 | /* Supply malloc, realloc and free functions to cJSON */ 144 | CJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks* hooks); 145 | 146 | /* Memory Management: the caller is always responsible to free the results from all variants of cJSON_Parse (with cJSON_Delete) and cJSON_Print (with stdlib free, cJSON_Hooks.free_fn, or cJSON_free as appropriate). The exception is cJSON_PrintPreallocated, where the caller has full responsibility of the buffer. */ 147 | /* Supply a block of JSON, and this returns a cJSON object you can interrogate. */ 148 | CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value); 149 | CJSON_PUBLIC(cJSON *) cJSON_ParseWithLength(const char *value, size_t buffer_length); 150 | /* ParseWithOpts allows you to require (and check) that the JSON is null terminated, and to retrieve the pointer to the final byte parsed. */ 151 | /* If you supply a ptr in return_parse_end and parsing fails, then return_parse_end will contain a pointer to the error so will match cJSON_GetErrorPtr(). */ 152 | CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated); 153 | CJSON_PUBLIC(cJSON *) cJSON_ParseWithLengthOpts(const char *value, size_t buffer_length, const char **return_parse_end, cJSON_bool require_null_terminated); 154 | 155 | /* Render a cJSON entity to text for transfer/storage. */ 156 | CJSON_PUBLIC(char *) cJSON_Print(const cJSON *item); 157 | /* Render a cJSON entity to text for transfer/storage without any formatting. */ 158 | CJSON_PUBLIC(char *) cJSON_PrintUnformatted(const cJSON *item); 159 | /* Render a cJSON entity to text using a buffered strategy. prebuffer is a guess at the final size. guessing well reduces reallocation. fmt=0 gives unformatted, =1 gives formatted */ 160 | CJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_bool fmt); 161 | /* Render a cJSON entity to text using a buffer already allocated in memory with given length. Returns 1 on success and 0 on failure. */ 162 | /* NOTE: cJSON is not always 100% accurate in estimating how much memory it will use, so to be safe allocate 5 bytes more than you actually need */ 163 | CJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length, const cJSON_bool format); 164 | /* Delete a cJSON entity and all subentities. */ 165 | CJSON_PUBLIC(void) cJSON_Delete(cJSON *item); 166 | 167 | /* Returns the number of items in an array (or object). */ 168 | CJSON_PUBLIC(int) cJSON_GetArraySize(const cJSON *array); 169 | /* Retrieve item number "index" from array "array". Returns NULL if unsuccessful. */ 170 | CJSON_PUBLIC(cJSON *) cJSON_GetArrayItem(const cJSON *array, int index); 171 | /* Get item "string" from object. Case insensitive. */ 172 | CJSON_PUBLIC(cJSON *) cJSON_GetObjectItem(const cJSON * const object, const char * const string); 173 | CJSON_PUBLIC(cJSON *) cJSON_GetObjectItemCaseSensitive(const cJSON * const object, const char * const string); 174 | CJSON_PUBLIC(cJSON_bool) cJSON_HasObjectItem(const cJSON *object, const char *string); 175 | /* For analysing failed parses. This returns a pointer to the parse error. You'll probably need to look a few chars back to make sense of it. Defined when cJSON_Parse() returns 0. 0 when cJSON_Parse() succeeds. */ 176 | CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void); 177 | 178 | /* Check item type and return its value */ 179 | CJSON_PUBLIC(char *) cJSON_GetStringValue(const cJSON * const item); 180 | CJSON_PUBLIC(double) cJSON_GetNumberValue(const cJSON * const item); 181 | 182 | /* These functions check the type of an item */ 183 | CJSON_PUBLIC(cJSON_bool) cJSON_IsInvalid(const cJSON * const item); 184 | CJSON_PUBLIC(cJSON_bool) cJSON_IsFalse(const cJSON * const item); 185 | CJSON_PUBLIC(cJSON_bool) cJSON_IsTrue(const cJSON * const item); 186 | CJSON_PUBLIC(cJSON_bool) cJSON_IsBool(const cJSON * const item); 187 | CJSON_PUBLIC(cJSON_bool) cJSON_IsNull(const cJSON * const item); 188 | CJSON_PUBLIC(cJSON_bool) cJSON_IsNumber(const cJSON * const item); 189 | CJSON_PUBLIC(cJSON_bool) cJSON_IsString(const cJSON * const item); 190 | CJSON_PUBLIC(cJSON_bool) cJSON_IsArray(const cJSON * const item); 191 | CJSON_PUBLIC(cJSON_bool) cJSON_IsObject(const cJSON * const item); 192 | CJSON_PUBLIC(cJSON_bool) cJSON_IsRaw(const cJSON * const item); 193 | 194 | /* These calls create a cJSON item of the appropriate type. */ 195 | CJSON_PUBLIC(cJSON *) cJSON_CreateNull(void); 196 | CJSON_PUBLIC(cJSON *) cJSON_CreateTrue(void); 197 | CJSON_PUBLIC(cJSON *) cJSON_CreateFalse(void); 198 | CJSON_PUBLIC(cJSON *) cJSON_CreateBool(cJSON_bool boolean); 199 | CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num); 200 | CJSON_PUBLIC(cJSON *) cJSON_CreateString(const char *string); 201 | /* raw json */ 202 | CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw); 203 | CJSON_PUBLIC(cJSON *) cJSON_CreateArray(void); 204 | CJSON_PUBLIC(cJSON *) cJSON_CreateObject(void); 205 | 206 | /* Create a string where valuestring references a string so 207 | * it will not be freed by cJSON_Delete */ 208 | CJSON_PUBLIC(cJSON *) cJSON_CreateStringReference(const char *string); 209 | /* Create an object/array that only references it's elements so 210 | * they will not be freed by cJSON_Delete */ 211 | CJSON_PUBLIC(cJSON *) cJSON_CreateObjectReference(const cJSON *child); 212 | CJSON_PUBLIC(cJSON *) cJSON_CreateArrayReference(const cJSON *child); 213 | 214 | /* These utilities create an Array of count items. 215 | * The parameter count cannot be greater than the number of elements in the number array, otherwise array access will be out of bounds.*/ 216 | CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count); 217 | CJSON_PUBLIC(cJSON *) cJSON_CreateFloatArray(const float *numbers, int count); 218 | CJSON_PUBLIC(cJSON *) cJSON_CreateDoubleArray(const double *numbers, int count); 219 | CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char *const *strings, int count); 220 | 221 | /* Append item to the specified array/object. */ 222 | CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToArray(cJSON *array, cJSON *item); 223 | CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item); 224 | /* Use this when string is definitely const (i.e. a literal, or as good as), and will definitely survive the cJSON object. 225 | * WARNING: When this function was used, make sure to always check that (item->type & cJSON_StringIsConst) is zero before 226 | * writing to `item->string` */ 227 | CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item); 228 | /* Append reference to item to the specified array/object. Use this when you want to add an existing cJSON to a new cJSON, but don't want to corrupt your existing cJSON. */ 229 | CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item); 230 | CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item); 231 | 232 | /* Remove/Detach items from Arrays/Objects. */ 233 | CJSON_PUBLIC(cJSON *) cJSON_DetachItemViaPointer(cJSON *parent, cJSON * const item); 234 | CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromArray(cJSON *array, int which); 235 | CJSON_PUBLIC(void) cJSON_DeleteItemFromArray(cJSON *array, int which); 236 | CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObject(cJSON *object, const char *string); 237 | CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObjectCaseSensitive(cJSON *object, const char *string); 238 | CJSON_PUBLIC(void) cJSON_DeleteItemFromObject(cJSON *object, const char *string); 239 | CJSON_PUBLIC(void) cJSON_DeleteItemFromObjectCaseSensitive(cJSON *object, const char *string); 240 | 241 | /* Update array items. */ 242 | CJSON_PUBLIC(cJSON_bool) cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem); /* Shifts pre-existing items to the right. */ 243 | CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemViaPointer(cJSON * const parent, cJSON * const item, cJSON * replacement); 244 | CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem); 245 | CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem); 246 | CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInObjectCaseSensitive(cJSON *object,const char *string,cJSON *newitem); 247 | 248 | /* Duplicate a cJSON item */ 249 | CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse); 250 | /* Duplicate will create a new, identical cJSON item to the one you pass, in new memory that will 251 | * need to be released. With recurse!=0, it will duplicate any children connected to the item. 252 | * The item->next and ->prev pointers are always zero on return from Duplicate. */ 253 | /* Recursively compare two cJSON items for equality. If either a or b is NULL or invalid, they will be considered unequal. 254 | * case_sensitive determines if object keys are treated case sensitive (1) or case insensitive (0) */ 255 | CJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON * const a, const cJSON * const b, const cJSON_bool case_sensitive); 256 | 257 | /* Minify a strings, remove blank characters(such as ' ', '\t', '\r', '\n') from strings. 258 | * The input pointer json cannot point to a read-only address area, such as a string constant, 259 | * but should point to a readable and writable address area. */ 260 | CJSON_PUBLIC(void) cJSON_Minify(char *json); 261 | 262 | /* Helper functions for creating and adding items to an object at the same time. 263 | * They return the added item or NULL on failure. */ 264 | CJSON_PUBLIC(cJSON*) cJSON_AddNullToObject(cJSON * const object, const char * const name); 265 | CJSON_PUBLIC(cJSON*) cJSON_AddTrueToObject(cJSON * const object, const char * const name); 266 | CJSON_PUBLIC(cJSON*) cJSON_AddFalseToObject(cJSON * const object, const char * const name); 267 | CJSON_PUBLIC(cJSON*) cJSON_AddBoolToObject(cJSON * const object, const char * const name, const cJSON_bool boolean); 268 | CJSON_PUBLIC(cJSON*) cJSON_AddNumberToObject(cJSON * const object, const char * const name, const double number); 269 | CJSON_PUBLIC(cJSON*) cJSON_AddStringToObject(cJSON * const object, const char * const name, const char * const string); 270 | CJSON_PUBLIC(cJSON*) cJSON_AddRawToObject(cJSON * const object, const char * const name, const char * const raw); 271 | CJSON_PUBLIC(cJSON*) cJSON_AddObjectToObject(cJSON * const object, const char * const name); 272 | CJSON_PUBLIC(cJSON*) cJSON_AddArrayToObject(cJSON * const object, const char * const name); 273 | 274 | /* When assigning an integer value, it needs to be propagated to valuedouble too. */ 275 | #define cJSON_SetIntValue(object, number) ((object) ? (object)->valueint = (object)->valuedouble = (number) : (number)) 276 | /* helper for the cJSON_SetNumberValue macro */ 277 | CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number); 278 | #define cJSON_SetNumberValue(object, number) ((object != NULL) ? cJSON_SetNumberHelper(object, (double)number) : (number)) 279 | /* Change the valuestring of a cJSON_String object, only takes effect when type of object is cJSON_String */ 280 | CJSON_PUBLIC(char*) cJSON_SetValuestring(cJSON *object, const char *valuestring); 281 | 282 | /* If the object is not a boolean type this does nothing and returns cJSON_Invalid else it returns the new type*/ 283 | #define cJSON_SetBoolValue(object, boolValue) ( \ 284 | (object != NULL && ((object)->type & (cJSON_False|cJSON_True))) ? \ 285 | (object)->type=((object)->type &(~(cJSON_False|cJSON_True)))|((boolValue)?cJSON_True:cJSON_False) : \ 286 | cJSON_Invalid\ 287 | ) 288 | 289 | /* Macro for iterating over an array or object */ 290 | #define cJSON_ArrayForEach(element, array) for(element = (array != NULL) ? (array)->child : NULL; element != NULL; element = element->next) 291 | 292 | /* malloc/free objects using the malloc/free functions that have been set with cJSON_InitHooks */ 293 | CJSON_PUBLIC(void *) cJSON_malloc(size_t size); 294 | CJSON_PUBLIC(void) cJSON_free(void *object); 295 | 296 | #ifdef __cplusplus 297 | } 298 | #endif 299 | 300 | #endif 301 | -------------------------------------------------------------------------------- /include/jsonrpc-c.h: -------------------------------------------------------------------------------- 1 | /* 2 | * jsonrpc-c.h 3 | * 4 | * Created on: Oct 11, 2012 5 | * Author: hmng 6 | */ 7 | 8 | #ifndef JSONRPCC_H_ 9 | #define JSONRPCC_H_ 10 | 11 | #include "cJSON.h" 12 | #include 13 | 14 | /* 15 | * 16 | * http://www.jsonrpc.org/specification 17 | * 18 | * code message meaning 19 | * -32700 Parse error Invalid JSON was received by the server. 20 | * An error occurred on the server while parsing the JSON text. 21 | * -32600 Invalid Request The JSON sent is not a valid Request object. 22 | * -32601 Method not found The method does not exist / is not available. 23 | * -32602 Invalid params Invalid method parameter(s). 24 | * -32603 Internal error Internal JSON-RPC error. 25 | * -32000 to -32099 Server error Reserved for implementation-defined server-errors. 26 | */ 27 | 28 | #define JRPC_PARSE_ERROR -32700 29 | #define JRPC_INVALID_REQUEST -32600 30 | #define JRPC_METHOD_NOT_FOUND -32601 31 | #define JRPC_INVALID_PARAMS -32603 32 | #define JRPC_INTERNAL_ERROR -32693 33 | 34 | typedef struct { 35 | void *data; 36 | int error_code; 37 | char * error_message; 38 | } jrpc_context; 39 | 40 | typedef cJSON* (*jrpc_function)(jrpc_context *context, cJSON *params, cJSON* id); 41 | 42 | struct jrpc_procedure { 43 | char * name; 44 | jrpc_function function; 45 | void *data; 46 | }; 47 | 48 | struct jrpc_server { 49 | int port_number; 50 | struct ev_loop *loop; 51 | ev_io listen_watcher; 52 | int procedure_count; 53 | struct jrpc_procedure *procedures; 54 | int debug_level; 55 | }; 56 | 57 | struct jrpc_connection { 58 | struct ev_io io; 59 | int fd; 60 | int pos; 61 | unsigned int buffer_size; 62 | char * buffer; 63 | int debug_level; 64 | }; 65 | 66 | int jrpc_server_init(struct jrpc_server *server, int port_number); 67 | 68 | int jrpc_server_init_with_ev_loop(struct jrpc_server *server, 69 | int port_number, struct ev_loop *loop); 70 | 71 | void jrpc_server_run(struct jrpc_server *server); 72 | 73 | int jrpc_server_stop(struct jrpc_server *server); 74 | 75 | void jrpc_server_destroy(struct jrpc_server *server); 76 | 77 | int jrpc_register_procedure(struct jrpc_server *server, 78 | jrpc_function function_pointer, char *name, void *data); 79 | 80 | int jrpc_deregister_procedure(struct jrpc_server *server, char *name); 81 | 82 | #endif 83 | -------------------------------------------------------------------------------- /src/Makefile.am: -------------------------------------------------------------------------------- 1 | ####################################### 2 | # The list of libraries we are building seperated by spaces. 3 | # The 'lib_' indicates that these build products will be installed 4 | # in the $(libdir) directory. For example /usr/lib 5 | lib_LTLIBRARIES = libjsonrpcc.la 6 | 7 | ####################################### 8 | # Build information for each library 9 | 10 | # Sources for jsonrpcc 11 | libjsonrpcc_la_SOURCES = cJSON.c jsonrpc-c.c 12 | 13 | # Linker options libTestProgram 14 | libjsonrpcc_la_LDFLAGS = -lm 15 | 16 | # Compiler options. Here we are adding the include directory 17 | # to be searched for headers included in the source code. 18 | libjsonrpcc_la_CPPFLAGS = $(LIBEV_CFLAGS) -I$(top_srcdir)/include 19 | 20 | # libev 21 | libjsonrpcc_la_LIBADD = $(LIBEV_LIBS) 22 | 23 | -------------------------------------------------------------------------------- /src/cJSON.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2009-2017 Dave Gamble and cJSON contributors 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | THE SOFTWARE. 21 | */ 22 | 23 | /* cJSON */ 24 | /* JSON parser in C. */ 25 | 26 | /* disable warnings about old C89 functions in MSVC */ 27 | #if !defined(_CRT_SECURE_NO_DEPRECATE) && defined(_MSC_VER) 28 | #define _CRT_SECURE_NO_DEPRECATE 29 | #endif 30 | 31 | #ifdef __GNUC__ 32 | #pragma GCC visibility push(default) 33 | #endif 34 | #if defined(_MSC_VER) 35 | #pragma warning (push) 36 | /* disable warning about single line comments in system headers */ 37 | #pragma warning (disable : 4001) 38 | #endif 39 | 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include 46 | #include 47 | 48 | #ifdef ENABLE_LOCALES 49 | #include 50 | #endif 51 | 52 | #if defined(_MSC_VER) 53 | #pragma warning (pop) 54 | #endif 55 | #ifdef __GNUC__ 56 | #pragma GCC visibility pop 57 | #endif 58 | 59 | #include "cJSON.h" 60 | 61 | /* define our own boolean type */ 62 | #ifdef true 63 | #undef true 64 | #endif 65 | #define true ((cJSON_bool)1) 66 | 67 | #ifdef false 68 | #undef false 69 | #endif 70 | #define false ((cJSON_bool)0) 71 | 72 | /* define isnan and isinf for ANSI C, if in C99 or above, isnan and isinf has been defined in math.h */ 73 | #ifndef isinf 74 | #define isinf(d) (isnan((d - d)) && !isnan(d)) 75 | #endif 76 | #ifndef isnan 77 | #define isnan(d) (d != d) 78 | #endif 79 | 80 | #ifndef NAN 81 | #ifdef _WIN32 82 | #define NAN sqrt(-1.0) 83 | #else 84 | #define NAN 0.0/0.0 85 | #endif 86 | #endif 87 | 88 | typedef struct { 89 | const unsigned char *json; 90 | size_t position; 91 | } error; 92 | static error global_error = { NULL, 0 }; 93 | 94 | CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void) 95 | { 96 | return (const char*) (global_error.json + global_error.position); 97 | } 98 | 99 | CJSON_PUBLIC(char *) cJSON_GetStringValue(const cJSON * const item) 100 | { 101 | if (!cJSON_IsString(item)) 102 | { 103 | return NULL; 104 | } 105 | 106 | return item->valuestring; 107 | } 108 | 109 | CJSON_PUBLIC(double) cJSON_GetNumberValue(const cJSON * const item) 110 | { 111 | if (!cJSON_IsNumber(item)) 112 | { 113 | return (double) NAN; 114 | } 115 | 116 | return item->valuedouble; 117 | } 118 | 119 | /* This is a safeguard to prevent copy-pasters from using incompatible C and header files */ 120 | #if (CJSON_VERSION_MAJOR != 1) || (CJSON_VERSION_MINOR != 7) || (CJSON_VERSION_PATCH != 18) 121 | #error cJSON.h and cJSON.c have different versions. Make sure that both have the same. 122 | #endif 123 | 124 | CJSON_PUBLIC(const char*) cJSON_Version(void) 125 | { 126 | static char version[15]; 127 | sprintf(version, "%i.%i.%i", CJSON_VERSION_MAJOR, CJSON_VERSION_MINOR, CJSON_VERSION_PATCH); 128 | 129 | return version; 130 | } 131 | 132 | /* Case insensitive string comparison, doesn't consider two NULL pointers equal though */ 133 | static int case_insensitive_strcmp(const unsigned char *string1, const unsigned char *string2) 134 | { 135 | if ((string1 == NULL) || (string2 == NULL)) 136 | { 137 | return 1; 138 | } 139 | 140 | if (string1 == string2) 141 | { 142 | return 0; 143 | } 144 | 145 | for(; tolower(*string1) == tolower(*string2); (void)string1++, string2++) 146 | { 147 | if (*string1 == '\0') 148 | { 149 | return 0; 150 | } 151 | } 152 | 153 | return tolower(*string1) - tolower(*string2); 154 | } 155 | 156 | typedef struct internal_hooks 157 | { 158 | void *(CJSON_CDECL *allocate)(size_t size); 159 | void (CJSON_CDECL *deallocate)(void *pointer); 160 | void *(CJSON_CDECL *reallocate)(void *pointer, size_t size); 161 | } internal_hooks; 162 | 163 | #if defined(_MSC_VER) 164 | /* work around MSVC error C2322: '...' address of dllimport '...' is not static */ 165 | static void * CJSON_CDECL internal_malloc(size_t size) 166 | { 167 | return malloc(size); 168 | } 169 | static void CJSON_CDECL internal_free(void *pointer) 170 | { 171 | free(pointer); 172 | } 173 | static void * CJSON_CDECL internal_realloc(void *pointer, size_t size) 174 | { 175 | return realloc(pointer, size); 176 | } 177 | #else 178 | #define internal_malloc malloc 179 | #define internal_free free 180 | #define internal_realloc realloc 181 | #endif 182 | 183 | /* strlen of character literals resolved at compile time */ 184 | #define static_strlen(string_literal) (sizeof(string_literal) - sizeof("")) 185 | 186 | static internal_hooks global_hooks = { internal_malloc, internal_free, internal_realloc }; 187 | 188 | static unsigned char* cJSON_strdup(const unsigned char* string, const internal_hooks * const hooks) 189 | { 190 | size_t length = 0; 191 | unsigned char *copy = NULL; 192 | 193 | if (string == NULL) 194 | { 195 | return NULL; 196 | } 197 | 198 | length = strlen((const char*)string) + sizeof(""); 199 | copy = (unsigned char*)hooks->allocate(length); 200 | if (copy == NULL) 201 | { 202 | return NULL; 203 | } 204 | memcpy(copy, string, length); 205 | 206 | return copy; 207 | } 208 | 209 | CJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks* hooks) 210 | { 211 | if (hooks == NULL) 212 | { 213 | /* Reset hooks */ 214 | global_hooks.allocate = malloc; 215 | global_hooks.deallocate = free; 216 | global_hooks.reallocate = realloc; 217 | return; 218 | } 219 | 220 | global_hooks.allocate = malloc; 221 | if (hooks->malloc_fn != NULL) 222 | { 223 | global_hooks.allocate = hooks->malloc_fn; 224 | } 225 | 226 | global_hooks.deallocate = free; 227 | if (hooks->free_fn != NULL) 228 | { 229 | global_hooks.deallocate = hooks->free_fn; 230 | } 231 | 232 | /* use realloc only if both free and malloc are used */ 233 | global_hooks.reallocate = NULL; 234 | if ((global_hooks.allocate == malloc) && (global_hooks.deallocate == free)) 235 | { 236 | global_hooks.reallocate = realloc; 237 | } 238 | } 239 | 240 | /* Internal constructor. */ 241 | static cJSON *cJSON_New_Item(const internal_hooks * const hooks) 242 | { 243 | cJSON* node = (cJSON*)hooks->allocate(sizeof(cJSON)); 244 | if (node) 245 | { 246 | memset(node, '\0', sizeof(cJSON)); 247 | } 248 | 249 | return node; 250 | } 251 | 252 | /* Delete a cJSON structure. */ 253 | CJSON_PUBLIC(void) cJSON_Delete(cJSON *item) 254 | { 255 | cJSON *next = NULL; 256 | while (item != NULL) 257 | { 258 | next = item->next; 259 | if (!(item->type & cJSON_IsReference) && (item->child != NULL)) 260 | { 261 | cJSON_Delete(item->child); 262 | } 263 | if (!(item->type & cJSON_IsReference) && (item->valuestring != NULL)) 264 | { 265 | global_hooks.deallocate(item->valuestring); 266 | item->valuestring = NULL; 267 | } 268 | if (!(item->type & cJSON_StringIsConst) && (item->string != NULL)) 269 | { 270 | global_hooks.deallocate(item->string); 271 | item->string = NULL; 272 | } 273 | global_hooks.deallocate(item); 274 | item = next; 275 | } 276 | } 277 | 278 | /* get the decimal point character of the current locale */ 279 | static unsigned char get_decimal_point(void) 280 | { 281 | #ifdef ENABLE_LOCALES 282 | struct lconv *lconv = localeconv(); 283 | return (unsigned char) lconv->decimal_point[0]; 284 | #else 285 | return '.'; 286 | #endif 287 | } 288 | 289 | typedef struct 290 | { 291 | const unsigned char *content; 292 | size_t length; 293 | size_t offset; 294 | size_t depth; /* How deeply nested (in arrays/objects) is the input at the current offset. */ 295 | internal_hooks hooks; 296 | } parse_buffer; 297 | 298 | /* check if the given size is left to read in a given parse buffer (starting with 1) */ 299 | #define can_read(buffer, size) ((buffer != NULL) && (((buffer)->offset + size) <= (buffer)->length)) 300 | /* check if the buffer can be accessed at the given index (starting with 0) */ 301 | #define can_access_at_index(buffer, index) ((buffer != NULL) && (((buffer)->offset + index) < (buffer)->length)) 302 | #define cannot_access_at_index(buffer, index) (!can_access_at_index(buffer, index)) 303 | /* get a pointer to the buffer at the position */ 304 | #define buffer_at_offset(buffer) ((buffer)->content + (buffer)->offset) 305 | 306 | /* Parse the input text to generate a number, and populate the result into item. */ 307 | static cJSON_bool parse_number(cJSON * const item, parse_buffer * const input_buffer) 308 | { 309 | double number = 0; 310 | unsigned char *after_end = NULL; 311 | unsigned char number_c_string[64]; 312 | unsigned char decimal_point = get_decimal_point(); 313 | size_t i = 0; 314 | 315 | if ((input_buffer == NULL) || (input_buffer->content == NULL)) 316 | { 317 | return false; 318 | } 319 | 320 | /* copy the number into a temporary buffer and replace '.' with the decimal point 321 | * of the current locale (for strtod) 322 | * This also takes care of '\0' not necessarily being available for marking the end of the input */ 323 | for (i = 0; (i < (sizeof(number_c_string) - 1)) && can_access_at_index(input_buffer, i); i++) 324 | { 325 | switch (buffer_at_offset(input_buffer)[i]) 326 | { 327 | case '0': 328 | case '1': 329 | case '2': 330 | case '3': 331 | case '4': 332 | case '5': 333 | case '6': 334 | case '7': 335 | case '8': 336 | case '9': 337 | case '+': 338 | case '-': 339 | case 'e': 340 | case 'E': 341 | number_c_string[i] = buffer_at_offset(input_buffer)[i]; 342 | break; 343 | 344 | case '.': 345 | number_c_string[i] = decimal_point; 346 | break; 347 | 348 | default: 349 | goto loop_end; 350 | } 351 | } 352 | loop_end: 353 | number_c_string[i] = '\0'; 354 | 355 | number = strtod((const char*)number_c_string, (char**)&after_end); 356 | if (number_c_string == after_end) 357 | { 358 | return false; /* parse_error */ 359 | } 360 | 361 | item->valuedouble = number; 362 | 363 | /* use saturation in case of overflow */ 364 | if (number >= INT_MAX) 365 | { 366 | item->valueint = INT_MAX; 367 | } 368 | else if (number <= (double)INT_MIN) 369 | { 370 | item->valueint = INT_MIN; 371 | } 372 | else 373 | { 374 | item->valueint = (int)number; 375 | } 376 | 377 | item->type = cJSON_Number; 378 | 379 | input_buffer->offset += (size_t)(after_end - number_c_string); 380 | return true; 381 | } 382 | 383 | /* don't ask me, but the original cJSON_SetNumberValue returns an integer or double */ 384 | CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number) 385 | { 386 | if (number >= INT_MAX) 387 | { 388 | object->valueint = INT_MAX; 389 | } 390 | else if (number <= (double)INT_MIN) 391 | { 392 | object->valueint = INT_MIN; 393 | } 394 | else 395 | { 396 | object->valueint = (int)number; 397 | } 398 | 399 | return object->valuedouble = number; 400 | } 401 | 402 | /* Note: when passing a NULL valuestring, cJSON_SetValuestring treats this as an error and return NULL */ 403 | CJSON_PUBLIC(char*) cJSON_SetValuestring(cJSON *object, const char *valuestring) 404 | { 405 | char *copy = NULL; 406 | /* if object's type is not cJSON_String or is cJSON_IsReference, it should not set valuestring */ 407 | if ((object == NULL) || !(object->type & cJSON_String) || (object->type & cJSON_IsReference)) 408 | { 409 | return NULL; 410 | } 411 | /* return NULL if the object is corrupted or valuestring is NULL */ 412 | if (object->valuestring == NULL || valuestring == NULL) 413 | { 414 | return NULL; 415 | } 416 | if (strlen(valuestring) <= strlen(object->valuestring)) 417 | { 418 | strcpy(object->valuestring, valuestring); 419 | return object->valuestring; 420 | } 421 | copy = (char*) cJSON_strdup((const unsigned char*)valuestring, &global_hooks); 422 | if (copy == NULL) 423 | { 424 | return NULL; 425 | } 426 | if (object->valuestring != NULL) 427 | { 428 | cJSON_free(object->valuestring); 429 | } 430 | object->valuestring = copy; 431 | 432 | return copy; 433 | } 434 | 435 | typedef struct 436 | { 437 | unsigned char *buffer; 438 | size_t length; 439 | size_t offset; 440 | size_t depth; /* current nesting depth (for formatted printing) */ 441 | cJSON_bool noalloc; 442 | cJSON_bool format; /* is this print a formatted print */ 443 | internal_hooks hooks; 444 | } printbuffer; 445 | 446 | /* realloc printbuffer if necessary to have at least "needed" bytes more */ 447 | static unsigned char* ensure(printbuffer * const p, size_t needed) 448 | { 449 | unsigned char *newbuffer = NULL; 450 | size_t newsize = 0; 451 | 452 | if ((p == NULL) || (p->buffer == NULL)) 453 | { 454 | return NULL; 455 | } 456 | 457 | if ((p->length > 0) && (p->offset >= p->length)) 458 | { 459 | /* make sure that offset is valid */ 460 | return NULL; 461 | } 462 | 463 | if (needed > INT_MAX) 464 | { 465 | /* sizes bigger than INT_MAX are currently not supported */ 466 | return NULL; 467 | } 468 | 469 | needed += p->offset + 1; 470 | if (needed <= p->length) 471 | { 472 | return p->buffer + p->offset; 473 | } 474 | 475 | if (p->noalloc) { 476 | return NULL; 477 | } 478 | 479 | /* calculate new buffer size */ 480 | if (needed > (INT_MAX / 2)) 481 | { 482 | /* overflow of int, use INT_MAX if possible */ 483 | if (needed <= INT_MAX) 484 | { 485 | newsize = INT_MAX; 486 | } 487 | else 488 | { 489 | return NULL; 490 | } 491 | } 492 | else 493 | { 494 | newsize = needed * 2; 495 | } 496 | 497 | if (p->hooks.reallocate != NULL) 498 | { 499 | /* reallocate with realloc if available */ 500 | newbuffer = (unsigned char*)p->hooks.reallocate(p->buffer, newsize); 501 | if (newbuffer == NULL) 502 | { 503 | p->hooks.deallocate(p->buffer); 504 | p->length = 0; 505 | p->buffer = NULL; 506 | 507 | return NULL; 508 | } 509 | } 510 | else 511 | { 512 | /* otherwise reallocate manually */ 513 | newbuffer = (unsigned char*)p->hooks.allocate(newsize); 514 | if (!newbuffer) 515 | { 516 | p->hooks.deallocate(p->buffer); 517 | p->length = 0; 518 | p->buffer = NULL; 519 | 520 | return NULL; 521 | } 522 | 523 | memcpy(newbuffer, p->buffer, p->offset + 1); 524 | p->hooks.deallocate(p->buffer); 525 | } 526 | p->length = newsize; 527 | p->buffer = newbuffer; 528 | 529 | return newbuffer + p->offset; 530 | } 531 | 532 | /* calculate the new length of the string in a printbuffer and update the offset */ 533 | static void update_offset(printbuffer * const buffer) 534 | { 535 | const unsigned char *buffer_pointer = NULL; 536 | if ((buffer == NULL) || (buffer->buffer == NULL)) 537 | { 538 | return; 539 | } 540 | buffer_pointer = buffer->buffer + buffer->offset; 541 | 542 | buffer->offset += strlen((const char*)buffer_pointer); 543 | } 544 | 545 | /* securely comparison of floating-point variables */ 546 | static cJSON_bool compare_double(double a, double b) 547 | { 548 | double maxVal = fabs(a) > fabs(b) ? fabs(a) : fabs(b); 549 | return (fabs(a - b) <= maxVal * DBL_EPSILON); 550 | } 551 | 552 | /* Render the number nicely from the given item into a string. */ 553 | static cJSON_bool print_number(const cJSON * const item, printbuffer * const output_buffer) 554 | { 555 | unsigned char *output_pointer = NULL; 556 | double d = item->valuedouble; 557 | int length = 0; 558 | size_t i = 0; 559 | unsigned char number_buffer[26] = {0}; /* temporary buffer to print the number into */ 560 | unsigned char decimal_point = get_decimal_point(); 561 | double test = 0.0; 562 | 563 | if (output_buffer == NULL) 564 | { 565 | return false; 566 | } 567 | 568 | /* This checks for NaN and Infinity */ 569 | if (isnan(d) || isinf(d)) 570 | { 571 | length = sprintf((char*)number_buffer, "null"); 572 | } 573 | else if(d == (double)item->valueint) 574 | { 575 | length = sprintf((char*)number_buffer, "%d", item->valueint); 576 | } 577 | else 578 | { 579 | /* Try 15 decimal places of precision to avoid nonsignificant nonzero digits */ 580 | length = sprintf((char*)number_buffer, "%1.15g", d); 581 | 582 | /* Check whether the original double can be recovered */ 583 | if ((sscanf((char*)number_buffer, "%lg", &test) != 1) || !compare_double((double)test, d)) 584 | { 585 | /* If not, print with 17 decimal places of precision */ 586 | length = sprintf((char*)number_buffer, "%1.17g", d); 587 | } 588 | } 589 | 590 | /* sprintf failed or buffer overrun occurred */ 591 | if ((length < 0) || (length > (int)(sizeof(number_buffer) - 1))) 592 | { 593 | return false; 594 | } 595 | 596 | /* reserve appropriate space in the output */ 597 | output_pointer = ensure(output_buffer, (size_t)length + sizeof("")); 598 | if (output_pointer == NULL) 599 | { 600 | return false; 601 | } 602 | 603 | /* copy the printed number to the output and replace locale 604 | * dependent decimal point with '.' */ 605 | for (i = 0; i < ((size_t)length); i++) 606 | { 607 | if (number_buffer[i] == decimal_point) 608 | { 609 | output_pointer[i] = '.'; 610 | continue; 611 | } 612 | 613 | output_pointer[i] = number_buffer[i]; 614 | } 615 | output_pointer[i] = '\0'; 616 | 617 | output_buffer->offset += (size_t)length; 618 | 619 | return true; 620 | } 621 | 622 | /* parse 4 digit hexadecimal number */ 623 | static unsigned parse_hex4(const unsigned char * const input) 624 | { 625 | unsigned int h = 0; 626 | size_t i = 0; 627 | 628 | for (i = 0; i < 4; i++) 629 | { 630 | /* parse digit */ 631 | if ((input[i] >= '0') && (input[i] <= '9')) 632 | { 633 | h += (unsigned int) input[i] - '0'; 634 | } 635 | else if ((input[i] >= 'A') && (input[i] <= 'F')) 636 | { 637 | h += (unsigned int) 10 + input[i] - 'A'; 638 | } 639 | else if ((input[i] >= 'a') && (input[i] <= 'f')) 640 | { 641 | h += (unsigned int) 10 + input[i] - 'a'; 642 | } 643 | else /* invalid */ 644 | { 645 | return 0; 646 | } 647 | 648 | if (i < 3) 649 | { 650 | /* shift left to make place for the next nibble */ 651 | h = h << 4; 652 | } 653 | } 654 | 655 | return h; 656 | } 657 | 658 | /* converts a UTF-16 literal to UTF-8 659 | * A literal can be one or two sequences of the form \uXXXX */ 660 | static unsigned char utf16_literal_to_utf8(const unsigned char * const input_pointer, const unsigned char * const input_end, unsigned char **output_pointer) 661 | { 662 | long unsigned int codepoint = 0; 663 | unsigned int first_code = 0; 664 | const unsigned char *first_sequence = input_pointer; 665 | unsigned char utf8_length = 0; 666 | unsigned char utf8_position = 0; 667 | unsigned char sequence_length = 0; 668 | unsigned char first_byte_mark = 0; 669 | 670 | if ((input_end - first_sequence) < 6) 671 | { 672 | /* input ends unexpectedly */ 673 | goto fail; 674 | } 675 | 676 | /* get the first utf16 sequence */ 677 | first_code = parse_hex4(first_sequence + 2); 678 | 679 | /* check that the code is valid */ 680 | if (((first_code >= 0xDC00) && (first_code <= 0xDFFF))) 681 | { 682 | goto fail; 683 | } 684 | 685 | /* UTF16 surrogate pair */ 686 | if ((first_code >= 0xD800) && (first_code <= 0xDBFF)) 687 | { 688 | const unsigned char *second_sequence = first_sequence + 6; 689 | unsigned int second_code = 0; 690 | sequence_length = 12; /* \uXXXX\uXXXX */ 691 | 692 | if ((input_end - second_sequence) < 6) 693 | { 694 | /* input ends unexpectedly */ 695 | goto fail; 696 | } 697 | 698 | if ((second_sequence[0] != '\\') || (second_sequence[1] != 'u')) 699 | { 700 | /* missing second half of the surrogate pair */ 701 | goto fail; 702 | } 703 | 704 | /* get the second utf16 sequence */ 705 | second_code = parse_hex4(second_sequence + 2); 706 | /* check that the code is valid */ 707 | if ((second_code < 0xDC00) || (second_code > 0xDFFF)) 708 | { 709 | /* invalid second half of the surrogate pair */ 710 | goto fail; 711 | } 712 | 713 | 714 | /* calculate the unicode codepoint from the surrogate pair */ 715 | codepoint = 0x10000 + (((first_code & 0x3FF) << 10) | (second_code & 0x3FF)); 716 | } 717 | else 718 | { 719 | sequence_length = 6; /* \uXXXX */ 720 | codepoint = first_code; 721 | } 722 | 723 | /* encode as UTF-8 724 | * takes at maximum 4 bytes to encode: 725 | * 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */ 726 | if (codepoint < 0x80) 727 | { 728 | /* normal ascii, encoding 0xxxxxxx */ 729 | utf8_length = 1; 730 | } 731 | else if (codepoint < 0x800) 732 | { 733 | /* two bytes, encoding 110xxxxx 10xxxxxx */ 734 | utf8_length = 2; 735 | first_byte_mark = 0xC0; /* 11000000 */ 736 | } 737 | else if (codepoint < 0x10000) 738 | { 739 | /* three bytes, encoding 1110xxxx 10xxxxxx 10xxxxxx */ 740 | utf8_length = 3; 741 | first_byte_mark = 0xE0; /* 11100000 */ 742 | } 743 | else if (codepoint <= 0x10FFFF) 744 | { 745 | /* four bytes, encoding 1110xxxx 10xxxxxx 10xxxxxx 10xxxxxx */ 746 | utf8_length = 4; 747 | first_byte_mark = 0xF0; /* 11110000 */ 748 | } 749 | else 750 | { 751 | /* invalid unicode codepoint */ 752 | goto fail; 753 | } 754 | 755 | /* encode as utf8 */ 756 | for (utf8_position = (unsigned char)(utf8_length - 1); utf8_position > 0; utf8_position--) 757 | { 758 | /* 10xxxxxx */ 759 | (*output_pointer)[utf8_position] = (unsigned char)((codepoint | 0x80) & 0xBF); 760 | codepoint >>= 6; 761 | } 762 | /* encode first byte */ 763 | if (utf8_length > 1) 764 | { 765 | (*output_pointer)[0] = (unsigned char)((codepoint | first_byte_mark) & 0xFF); 766 | } 767 | else 768 | { 769 | (*output_pointer)[0] = (unsigned char)(codepoint & 0x7F); 770 | } 771 | 772 | *output_pointer += utf8_length; 773 | 774 | return sequence_length; 775 | 776 | fail: 777 | return 0; 778 | } 779 | 780 | /* Parse the input text into an unescaped cinput, and populate item. */ 781 | static cJSON_bool parse_string(cJSON * const item, parse_buffer * const input_buffer) 782 | { 783 | const unsigned char *input_pointer = buffer_at_offset(input_buffer) + 1; 784 | const unsigned char *input_end = buffer_at_offset(input_buffer) + 1; 785 | unsigned char *output_pointer = NULL; 786 | unsigned char *output = NULL; 787 | 788 | /* not a string */ 789 | if (buffer_at_offset(input_buffer)[0] != '\"') 790 | { 791 | goto fail; 792 | } 793 | 794 | { 795 | /* calculate approximate size of the output (overestimate) */ 796 | size_t allocation_length = 0; 797 | size_t skipped_bytes = 0; 798 | while (((size_t)(input_end - input_buffer->content) < input_buffer->length) && (*input_end != '\"')) 799 | { 800 | /* is escape sequence */ 801 | if (input_end[0] == '\\') 802 | { 803 | if ((size_t)(input_end + 1 - input_buffer->content) >= input_buffer->length) 804 | { 805 | /* prevent buffer overflow when last input character is a backslash */ 806 | goto fail; 807 | } 808 | skipped_bytes++; 809 | input_end++; 810 | } 811 | input_end++; 812 | } 813 | if (((size_t)(input_end - input_buffer->content) >= input_buffer->length) || (*input_end != '\"')) 814 | { 815 | goto fail; /* string ended unexpectedly */ 816 | } 817 | 818 | /* This is at most how much we need for the output */ 819 | allocation_length = (size_t) (input_end - buffer_at_offset(input_buffer)) - skipped_bytes; 820 | output = (unsigned char*)input_buffer->hooks.allocate(allocation_length + sizeof("")); 821 | if (output == NULL) 822 | { 823 | goto fail; /* allocation failure */ 824 | } 825 | } 826 | 827 | output_pointer = output; 828 | /* loop through the string literal */ 829 | while (input_pointer < input_end) 830 | { 831 | if (*input_pointer != '\\') 832 | { 833 | *output_pointer++ = *input_pointer++; 834 | } 835 | /* escape sequence */ 836 | else 837 | { 838 | unsigned char sequence_length = 2; 839 | if ((input_end - input_pointer) < 1) 840 | { 841 | goto fail; 842 | } 843 | 844 | switch (input_pointer[1]) 845 | { 846 | case 'b': 847 | *output_pointer++ = '\b'; 848 | break; 849 | case 'f': 850 | *output_pointer++ = '\f'; 851 | break; 852 | case 'n': 853 | *output_pointer++ = '\n'; 854 | break; 855 | case 'r': 856 | *output_pointer++ = '\r'; 857 | break; 858 | case 't': 859 | *output_pointer++ = '\t'; 860 | break; 861 | case '\"': 862 | case '\\': 863 | case '/': 864 | *output_pointer++ = input_pointer[1]; 865 | break; 866 | 867 | /* UTF-16 literal */ 868 | case 'u': 869 | sequence_length = utf16_literal_to_utf8(input_pointer, input_end, &output_pointer); 870 | if (sequence_length == 0) 871 | { 872 | /* failed to convert UTF16-literal to UTF-8 */ 873 | goto fail; 874 | } 875 | break; 876 | 877 | default: 878 | goto fail; 879 | } 880 | input_pointer += sequence_length; 881 | } 882 | } 883 | 884 | /* zero terminate the output */ 885 | *output_pointer = '\0'; 886 | 887 | item->type = cJSON_String; 888 | item->valuestring = (char*)output; 889 | 890 | input_buffer->offset = (size_t) (input_end - input_buffer->content); 891 | input_buffer->offset++; 892 | 893 | return true; 894 | 895 | fail: 896 | if (output != NULL) 897 | { 898 | input_buffer->hooks.deallocate(output); 899 | output = NULL; 900 | } 901 | 902 | if (input_pointer != NULL) 903 | { 904 | input_buffer->offset = (size_t)(input_pointer - input_buffer->content); 905 | } 906 | 907 | return false; 908 | } 909 | 910 | /* Render the cstring provided to an escaped version that can be printed. */ 911 | static cJSON_bool print_string_ptr(const unsigned char * const input, printbuffer * const output_buffer) 912 | { 913 | const unsigned char *input_pointer = NULL; 914 | unsigned char *output = NULL; 915 | unsigned char *output_pointer = NULL; 916 | size_t output_length = 0; 917 | /* numbers of additional characters needed for escaping */ 918 | size_t escape_characters = 0; 919 | 920 | if (output_buffer == NULL) 921 | { 922 | return false; 923 | } 924 | 925 | /* empty string */ 926 | if (input == NULL) 927 | { 928 | output = ensure(output_buffer, sizeof("\"\"")); 929 | if (output == NULL) 930 | { 931 | return false; 932 | } 933 | strcpy((char*)output, "\"\""); 934 | 935 | return true; 936 | } 937 | 938 | /* set "flag" to 1 if something needs to be escaped */ 939 | for (input_pointer = input; *input_pointer; input_pointer++) 940 | { 941 | switch (*input_pointer) 942 | { 943 | case '\"': 944 | case '\\': 945 | case '\b': 946 | case '\f': 947 | case '\n': 948 | case '\r': 949 | case '\t': 950 | /* one character escape sequence */ 951 | escape_characters++; 952 | break; 953 | default: 954 | if (*input_pointer < 32) 955 | { 956 | /* UTF-16 escape sequence uXXXX */ 957 | escape_characters += 5; 958 | } 959 | break; 960 | } 961 | } 962 | output_length = (size_t)(input_pointer - input) + escape_characters; 963 | 964 | output = ensure(output_buffer, output_length + sizeof("\"\"")); 965 | if (output == NULL) 966 | { 967 | return false; 968 | } 969 | 970 | /* no characters have to be escaped */ 971 | if (escape_characters == 0) 972 | { 973 | output[0] = '\"'; 974 | memcpy(output + 1, input, output_length); 975 | output[output_length + 1] = '\"'; 976 | output[output_length + 2] = '\0'; 977 | 978 | return true; 979 | } 980 | 981 | output[0] = '\"'; 982 | output_pointer = output + 1; 983 | /* copy the string */ 984 | for (input_pointer = input; *input_pointer != '\0'; (void)input_pointer++, output_pointer++) 985 | { 986 | if ((*input_pointer > 31) && (*input_pointer != '\"') && (*input_pointer != '\\')) 987 | { 988 | /* normal character, copy */ 989 | *output_pointer = *input_pointer; 990 | } 991 | else 992 | { 993 | /* character needs to be escaped */ 994 | *output_pointer++ = '\\'; 995 | switch (*input_pointer) 996 | { 997 | case '\\': 998 | *output_pointer = '\\'; 999 | break; 1000 | case '\"': 1001 | *output_pointer = '\"'; 1002 | break; 1003 | case '\b': 1004 | *output_pointer = 'b'; 1005 | break; 1006 | case '\f': 1007 | *output_pointer = 'f'; 1008 | break; 1009 | case '\n': 1010 | *output_pointer = 'n'; 1011 | break; 1012 | case '\r': 1013 | *output_pointer = 'r'; 1014 | break; 1015 | case '\t': 1016 | *output_pointer = 't'; 1017 | break; 1018 | default: 1019 | /* escape and print as unicode codepoint */ 1020 | sprintf((char*)output_pointer, "u%04x", *input_pointer); 1021 | output_pointer += 4; 1022 | break; 1023 | } 1024 | } 1025 | } 1026 | output[output_length + 1] = '\"'; 1027 | output[output_length + 2] = '\0'; 1028 | 1029 | return true; 1030 | } 1031 | 1032 | /* Invoke print_string_ptr (which is useful) on an item. */ 1033 | static cJSON_bool print_string(const cJSON * const item, printbuffer * const p) 1034 | { 1035 | return print_string_ptr((unsigned char*)item->valuestring, p); 1036 | } 1037 | 1038 | /* Predeclare these prototypes. */ 1039 | static cJSON_bool parse_value(cJSON * const item, parse_buffer * const input_buffer); 1040 | static cJSON_bool print_value(const cJSON * const item, printbuffer * const output_buffer); 1041 | static cJSON_bool parse_array(cJSON * const item, parse_buffer * const input_buffer); 1042 | static cJSON_bool print_array(const cJSON * const item, printbuffer * const output_buffer); 1043 | static cJSON_bool parse_object(cJSON * const item, parse_buffer * const input_buffer); 1044 | static cJSON_bool print_object(const cJSON * const item, printbuffer * const output_buffer); 1045 | 1046 | /* Utility to jump whitespace and cr/lf */ 1047 | static parse_buffer *buffer_skip_whitespace(parse_buffer * const buffer) 1048 | { 1049 | if ((buffer == NULL) || (buffer->content == NULL)) 1050 | { 1051 | return NULL; 1052 | } 1053 | 1054 | if (cannot_access_at_index(buffer, 0)) 1055 | { 1056 | return buffer; 1057 | } 1058 | 1059 | while (can_access_at_index(buffer, 0) && (buffer_at_offset(buffer)[0] <= 32)) 1060 | { 1061 | buffer->offset++; 1062 | } 1063 | 1064 | if (buffer->offset == buffer->length) 1065 | { 1066 | buffer->offset--; 1067 | } 1068 | 1069 | return buffer; 1070 | } 1071 | 1072 | /* skip the UTF-8 BOM (byte order mark) if it is at the beginning of a buffer */ 1073 | static parse_buffer *skip_utf8_bom(parse_buffer * const buffer) 1074 | { 1075 | if ((buffer == NULL) || (buffer->content == NULL) || (buffer->offset != 0)) 1076 | { 1077 | return NULL; 1078 | } 1079 | 1080 | if (can_access_at_index(buffer, 4) && (strncmp((const char*)buffer_at_offset(buffer), "\xEF\xBB\xBF", 3) == 0)) 1081 | { 1082 | buffer->offset += 3; 1083 | } 1084 | 1085 | return buffer; 1086 | } 1087 | 1088 | CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated) 1089 | { 1090 | size_t buffer_length; 1091 | 1092 | if (NULL == value) 1093 | { 1094 | return NULL; 1095 | } 1096 | 1097 | /* Adding null character size due to require_null_terminated. */ 1098 | buffer_length = strlen(value) + sizeof(""); 1099 | 1100 | return cJSON_ParseWithLengthOpts(value, buffer_length, return_parse_end, require_null_terminated); 1101 | } 1102 | 1103 | /* Parse an object - create a new root, and populate. */ 1104 | CJSON_PUBLIC(cJSON *) cJSON_ParseWithLengthOpts(const char *value, size_t buffer_length, const char **return_parse_end, cJSON_bool require_null_terminated) 1105 | { 1106 | parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0 } }; 1107 | cJSON *item = NULL; 1108 | 1109 | /* reset error position */ 1110 | global_error.json = NULL; 1111 | global_error.position = 0; 1112 | 1113 | if (value == NULL || 0 == buffer_length) 1114 | { 1115 | goto fail; 1116 | } 1117 | 1118 | buffer.content = (const unsigned char*)value; 1119 | buffer.length = buffer_length; 1120 | buffer.offset = 0; 1121 | buffer.hooks = global_hooks; 1122 | 1123 | item = cJSON_New_Item(&global_hooks); 1124 | if (item == NULL) /* memory fail */ 1125 | { 1126 | goto fail; 1127 | } 1128 | 1129 | if (!parse_value(item, buffer_skip_whitespace(skip_utf8_bom(&buffer)))) 1130 | { 1131 | /* parse failure. ep is set. */ 1132 | goto fail; 1133 | } 1134 | 1135 | /* if we require null-terminated JSON without appended garbage, skip and then check for a null terminator */ 1136 | if (require_null_terminated) 1137 | { 1138 | buffer_skip_whitespace(&buffer); 1139 | if ((buffer.offset >= buffer.length) || buffer_at_offset(&buffer)[0] != '\0') 1140 | { 1141 | goto fail; 1142 | } 1143 | } 1144 | if (return_parse_end) 1145 | { 1146 | *return_parse_end = (const char*)buffer_at_offset(&buffer); 1147 | } 1148 | 1149 | return item; 1150 | 1151 | fail: 1152 | if (item != NULL) 1153 | { 1154 | cJSON_Delete(item); 1155 | } 1156 | 1157 | if (value != NULL) 1158 | { 1159 | error local_error; 1160 | local_error.json = (const unsigned char*)value; 1161 | local_error.position = 0; 1162 | 1163 | if (buffer.offset < buffer.length) 1164 | { 1165 | local_error.position = buffer.offset; 1166 | } 1167 | else if (buffer.length > 0) 1168 | { 1169 | local_error.position = buffer.length - 1; 1170 | } 1171 | 1172 | if (return_parse_end != NULL) 1173 | { 1174 | *return_parse_end = (const char*)local_error.json + local_error.position; 1175 | } 1176 | 1177 | global_error = local_error; 1178 | } 1179 | 1180 | return NULL; 1181 | } 1182 | 1183 | /* Default options for cJSON_Parse */ 1184 | CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value) 1185 | { 1186 | return cJSON_ParseWithOpts(value, 0, 0); 1187 | } 1188 | 1189 | CJSON_PUBLIC(cJSON *) cJSON_ParseWithLength(const char *value, size_t buffer_length) 1190 | { 1191 | return cJSON_ParseWithLengthOpts(value, buffer_length, 0, 0); 1192 | } 1193 | 1194 | #define cjson_min(a, b) (((a) < (b)) ? (a) : (b)) 1195 | 1196 | static unsigned char *print(const cJSON * const item, cJSON_bool format, const internal_hooks * const hooks) 1197 | { 1198 | static const size_t default_buffer_size = 256; 1199 | printbuffer buffer[1]; 1200 | unsigned char *printed = NULL; 1201 | 1202 | memset(buffer, 0, sizeof(buffer)); 1203 | 1204 | /* create buffer */ 1205 | buffer->buffer = (unsigned char*) hooks->allocate(default_buffer_size); 1206 | buffer->length = default_buffer_size; 1207 | buffer->format = format; 1208 | buffer->hooks = *hooks; 1209 | if (buffer->buffer == NULL) 1210 | { 1211 | goto fail; 1212 | } 1213 | 1214 | /* print the value */ 1215 | if (!print_value(item, buffer)) 1216 | { 1217 | goto fail; 1218 | } 1219 | update_offset(buffer); 1220 | 1221 | /* check if reallocate is available */ 1222 | if (hooks->reallocate != NULL) 1223 | { 1224 | printed = (unsigned char*) hooks->reallocate(buffer->buffer, buffer->offset + 1); 1225 | if (printed == NULL) { 1226 | goto fail; 1227 | } 1228 | buffer->buffer = NULL; 1229 | } 1230 | else /* otherwise copy the JSON over to a new buffer */ 1231 | { 1232 | printed = (unsigned char*) hooks->allocate(buffer->offset + 1); 1233 | if (printed == NULL) 1234 | { 1235 | goto fail; 1236 | } 1237 | memcpy(printed, buffer->buffer, cjson_min(buffer->length, buffer->offset + 1)); 1238 | printed[buffer->offset] = '\0'; /* just to be sure */ 1239 | 1240 | /* free the buffer */ 1241 | hooks->deallocate(buffer->buffer); 1242 | buffer->buffer = NULL; 1243 | } 1244 | 1245 | return printed; 1246 | 1247 | fail: 1248 | if (buffer->buffer != NULL) 1249 | { 1250 | hooks->deallocate(buffer->buffer); 1251 | buffer->buffer = NULL; 1252 | } 1253 | 1254 | if (printed != NULL) 1255 | { 1256 | hooks->deallocate(printed); 1257 | printed = NULL; 1258 | } 1259 | 1260 | return NULL; 1261 | } 1262 | 1263 | /* Render a cJSON item/entity/structure to text. */ 1264 | CJSON_PUBLIC(char *) cJSON_Print(const cJSON *item) 1265 | { 1266 | return (char*)print(item, true, &global_hooks); 1267 | } 1268 | 1269 | CJSON_PUBLIC(char *) cJSON_PrintUnformatted(const cJSON *item) 1270 | { 1271 | return (char*)print(item, false, &global_hooks); 1272 | } 1273 | 1274 | CJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_bool fmt) 1275 | { 1276 | printbuffer p = { 0, 0, 0, 0, 0, 0, { 0, 0, 0 } }; 1277 | 1278 | if (prebuffer < 0) 1279 | { 1280 | return NULL; 1281 | } 1282 | 1283 | p.buffer = (unsigned char*)global_hooks.allocate((size_t)prebuffer); 1284 | if (!p.buffer) 1285 | { 1286 | return NULL; 1287 | } 1288 | 1289 | p.length = (size_t)prebuffer; 1290 | p.offset = 0; 1291 | p.noalloc = false; 1292 | p.format = fmt; 1293 | p.hooks = global_hooks; 1294 | 1295 | if (!print_value(item, &p)) 1296 | { 1297 | global_hooks.deallocate(p.buffer); 1298 | p.buffer = NULL; 1299 | return NULL; 1300 | } 1301 | 1302 | return (char*)p.buffer; 1303 | } 1304 | 1305 | CJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length, const cJSON_bool format) 1306 | { 1307 | printbuffer p = { 0, 0, 0, 0, 0, 0, { 0, 0, 0 } }; 1308 | 1309 | if ((length < 0) || (buffer == NULL)) 1310 | { 1311 | return false; 1312 | } 1313 | 1314 | p.buffer = (unsigned char*)buffer; 1315 | p.length = (size_t)length; 1316 | p.offset = 0; 1317 | p.noalloc = true; 1318 | p.format = format; 1319 | p.hooks = global_hooks; 1320 | 1321 | return print_value(item, &p); 1322 | } 1323 | 1324 | /* Parser core - when encountering text, process appropriately. */ 1325 | static cJSON_bool parse_value(cJSON * const item, parse_buffer * const input_buffer) 1326 | { 1327 | if ((input_buffer == NULL) || (input_buffer->content == NULL)) 1328 | { 1329 | return false; /* no input */ 1330 | } 1331 | 1332 | /* parse the different types of values */ 1333 | /* null */ 1334 | if (can_read(input_buffer, 4) && (strncmp((const char*)buffer_at_offset(input_buffer), "null", 4) == 0)) 1335 | { 1336 | item->type = cJSON_NULL; 1337 | input_buffer->offset += 4; 1338 | return true; 1339 | } 1340 | /* false */ 1341 | if (can_read(input_buffer, 5) && (strncmp((const char*)buffer_at_offset(input_buffer), "false", 5) == 0)) 1342 | { 1343 | item->type = cJSON_False; 1344 | input_buffer->offset += 5; 1345 | return true; 1346 | } 1347 | /* true */ 1348 | if (can_read(input_buffer, 4) && (strncmp((const char*)buffer_at_offset(input_buffer), "true", 4) == 0)) 1349 | { 1350 | item->type = cJSON_True; 1351 | item->valueint = 1; 1352 | input_buffer->offset += 4; 1353 | return true; 1354 | } 1355 | /* string */ 1356 | if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '\"')) 1357 | { 1358 | return parse_string(item, input_buffer); 1359 | } 1360 | /* number */ 1361 | if (can_access_at_index(input_buffer, 0) && ((buffer_at_offset(input_buffer)[0] == '-') || ((buffer_at_offset(input_buffer)[0] >= '0') && (buffer_at_offset(input_buffer)[0] <= '9')))) 1362 | { 1363 | return parse_number(item, input_buffer); 1364 | } 1365 | /* array */ 1366 | if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '[')) 1367 | { 1368 | return parse_array(item, input_buffer); 1369 | } 1370 | /* object */ 1371 | if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '{')) 1372 | { 1373 | return parse_object(item, input_buffer); 1374 | } 1375 | 1376 | return false; 1377 | } 1378 | 1379 | /* Render a value to text. */ 1380 | static cJSON_bool print_value(const cJSON * const item, printbuffer * const output_buffer) 1381 | { 1382 | unsigned char *output = NULL; 1383 | 1384 | if ((item == NULL) || (output_buffer == NULL)) 1385 | { 1386 | return false; 1387 | } 1388 | 1389 | switch ((item->type) & 0xFF) 1390 | { 1391 | case cJSON_NULL: 1392 | output = ensure(output_buffer, 5); 1393 | if (output == NULL) 1394 | { 1395 | return false; 1396 | } 1397 | strcpy((char*)output, "null"); 1398 | return true; 1399 | 1400 | case cJSON_False: 1401 | output = ensure(output_buffer, 6); 1402 | if (output == NULL) 1403 | { 1404 | return false; 1405 | } 1406 | strcpy((char*)output, "false"); 1407 | return true; 1408 | 1409 | case cJSON_True: 1410 | output = ensure(output_buffer, 5); 1411 | if (output == NULL) 1412 | { 1413 | return false; 1414 | } 1415 | strcpy((char*)output, "true"); 1416 | return true; 1417 | 1418 | case cJSON_Number: 1419 | return print_number(item, output_buffer); 1420 | 1421 | case cJSON_Raw: 1422 | { 1423 | size_t raw_length = 0; 1424 | if (item->valuestring == NULL) 1425 | { 1426 | return false; 1427 | } 1428 | 1429 | raw_length = strlen(item->valuestring) + sizeof(""); 1430 | output = ensure(output_buffer, raw_length); 1431 | if (output == NULL) 1432 | { 1433 | return false; 1434 | } 1435 | memcpy(output, item->valuestring, raw_length); 1436 | return true; 1437 | } 1438 | 1439 | case cJSON_String: 1440 | return print_string(item, output_buffer); 1441 | 1442 | case cJSON_Array: 1443 | return print_array(item, output_buffer); 1444 | 1445 | case cJSON_Object: 1446 | return print_object(item, output_buffer); 1447 | 1448 | default: 1449 | return false; 1450 | } 1451 | } 1452 | 1453 | /* Build an array from input text. */ 1454 | static cJSON_bool parse_array(cJSON * const item, parse_buffer * const input_buffer) 1455 | { 1456 | cJSON *head = NULL; /* head of the linked list */ 1457 | cJSON *current_item = NULL; 1458 | 1459 | if (input_buffer->depth >= CJSON_NESTING_LIMIT) 1460 | { 1461 | return false; /* to deeply nested */ 1462 | } 1463 | input_buffer->depth++; 1464 | 1465 | if (buffer_at_offset(input_buffer)[0] != '[') 1466 | { 1467 | /* not an array */ 1468 | goto fail; 1469 | } 1470 | 1471 | input_buffer->offset++; 1472 | buffer_skip_whitespace(input_buffer); 1473 | if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ']')) 1474 | { 1475 | /* empty array */ 1476 | goto success; 1477 | } 1478 | 1479 | /* check if we skipped to the end of the buffer */ 1480 | if (cannot_access_at_index(input_buffer, 0)) 1481 | { 1482 | input_buffer->offset--; 1483 | goto fail; 1484 | } 1485 | 1486 | /* step back to character in front of the first element */ 1487 | input_buffer->offset--; 1488 | /* loop through the comma separated array elements */ 1489 | do 1490 | { 1491 | /* allocate next item */ 1492 | cJSON *new_item = cJSON_New_Item(&(input_buffer->hooks)); 1493 | if (new_item == NULL) 1494 | { 1495 | goto fail; /* allocation failure */ 1496 | } 1497 | 1498 | /* attach next item to list */ 1499 | if (head == NULL) 1500 | { 1501 | /* start the linked list */ 1502 | current_item = head = new_item; 1503 | } 1504 | else 1505 | { 1506 | /* add to the end and advance */ 1507 | current_item->next = new_item; 1508 | new_item->prev = current_item; 1509 | current_item = new_item; 1510 | } 1511 | 1512 | /* parse next value */ 1513 | input_buffer->offset++; 1514 | buffer_skip_whitespace(input_buffer); 1515 | if (!parse_value(current_item, input_buffer)) 1516 | { 1517 | goto fail; /* failed to parse value */ 1518 | } 1519 | buffer_skip_whitespace(input_buffer); 1520 | } 1521 | while (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ',')); 1522 | 1523 | if (cannot_access_at_index(input_buffer, 0) || buffer_at_offset(input_buffer)[0] != ']') 1524 | { 1525 | goto fail; /* expected end of array */ 1526 | } 1527 | 1528 | success: 1529 | input_buffer->depth--; 1530 | 1531 | if (head != NULL) { 1532 | head->prev = current_item; 1533 | } 1534 | 1535 | item->type = cJSON_Array; 1536 | item->child = head; 1537 | 1538 | input_buffer->offset++; 1539 | 1540 | return true; 1541 | 1542 | fail: 1543 | if (head != NULL) 1544 | { 1545 | cJSON_Delete(head); 1546 | } 1547 | 1548 | return false; 1549 | } 1550 | 1551 | /* Render an array to text */ 1552 | static cJSON_bool print_array(const cJSON * const item, printbuffer * const output_buffer) 1553 | { 1554 | unsigned char *output_pointer = NULL; 1555 | size_t length = 0; 1556 | cJSON *current_element = item->child; 1557 | 1558 | if (output_buffer == NULL) 1559 | { 1560 | return false; 1561 | } 1562 | 1563 | /* Compose the output array. */ 1564 | /* opening square bracket */ 1565 | output_pointer = ensure(output_buffer, 1); 1566 | if (output_pointer == NULL) 1567 | { 1568 | return false; 1569 | } 1570 | 1571 | *output_pointer = '['; 1572 | output_buffer->offset++; 1573 | output_buffer->depth++; 1574 | 1575 | while (current_element != NULL) 1576 | { 1577 | if (!print_value(current_element, output_buffer)) 1578 | { 1579 | return false; 1580 | } 1581 | update_offset(output_buffer); 1582 | if (current_element->next) 1583 | { 1584 | length = (size_t) (output_buffer->format ? 2 : 1); 1585 | output_pointer = ensure(output_buffer, length + 1); 1586 | if (output_pointer == NULL) 1587 | { 1588 | return false; 1589 | } 1590 | *output_pointer++ = ','; 1591 | if(output_buffer->format) 1592 | { 1593 | *output_pointer++ = ' '; 1594 | } 1595 | *output_pointer = '\0'; 1596 | output_buffer->offset += length; 1597 | } 1598 | current_element = current_element->next; 1599 | } 1600 | 1601 | output_pointer = ensure(output_buffer, 2); 1602 | if (output_pointer == NULL) 1603 | { 1604 | return false; 1605 | } 1606 | *output_pointer++ = ']'; 1607 | *output_pointer = '\0'; 1608 | output_buffer->depth--; 1609 | 1610 | return true; 1611 | } 1612 | 1613 | /* Build an object from the text. */ 1614 | static cJSON_bool parse_object(cJSON * const item, parse_buffer * const input_buffer) 1615 | { 1616 | cJSON *head = NULL; /* linked list head */ 1617 | cJSON *current_item = NULL; 1618 | 1619 | if (input_buffer->depth >= CJSON_NESTING_LIMIT) 1620 | { 1621 | return false; /* to deeply nested */ 1622 | } 1623 | input_buffer->depth++; 1624 | 1625 | if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != '{')) 1626 | { 1627 | goto fail; /* not an object */ 1628 | } 1629 | 1630 | input_buffer->offset++; 1631 | buffer_skip_whitespace(input_buffer); 1632 | if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '}')) 1633 | { 1634 | goto success; /* empty object */ 1635 | } 1636 | 1637 | /* check if we skipped to the end of the buffer */ 1638 | if (cannot_access_at_index(input_buffer, 0)) 1639 | { 1640 | input_buffer->offset--; 1641 | goto fail; 1642 | } 1643 | 1644 | /* step back to character in front of the first element */ 1645 | input_buffer->offset--; 1646 | /* loop through the comma separated array elements */ 1647 | do 1648 | { 1649 | /* allocate next item */ 1650 | cJSON *new_item = cJSON_New_Item(&(input_buffer->hooks)); 1651 | if (new_item == NULL) 1652 | { 1653 | goto fail; /* allocation failure */ 1654 | } 1655 | 1656 | /* attach next item to list */ 1657 | if (head == NULL) 1658 | { 1659 | /* start the linked list */ 1660 | current_item = head = new_item; 1661 | } 1662 | else 1663 | { 1664 | /* add to the end and advance */ 1665 | current_item->next = new_item; 1666 | new_item->prev = current_item; 1667 | current_item = new_item; 1668 | } 1669 | 1670 | if (cannot_access_at_index(input_buffer, 1)) 1671 | { 1672 | goto fail; /* nothing comes after the comma */ 1673 | } 1674 | 1675 | /* parse the name of the child */ 1676 | input_buffer->offset++; 1677 | buffer_skip_whitespace(input_buffer); 1678 | if (!parse_string(current_item, input_buffer)) 1679 | { 1680 | goto fail; /* failed to parse name */ 1681 | } 1682 | buffer_skip_whitespace(input_buffer); 1683 | 1684 | /* swap valuestring and string, because we parsed the name */ 1685 | current_item->string = current_item->valuestring; 1686 | current_item->valuestring = NULL; 1687 | 1688 | if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != ':')) 1689 | { 1690 | goto fail; /* invalid object */ 1691 | } 1692 | 1693 | /* parse the value */ 1694 | input_buffer->offset++; 1695 | buffer_skip_whitespace(input_buffer); 1696 | if (!parse_value(current_item, input_buffer)) 1697 | { 1698 | goto fail; /* failed to parse value */ 1699 | } 1700 | buffer_skip_whitespace(input_buffer); 1701 | } 1702 | while (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ',')); 1703 | 1704 | if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != '}')) 1705 | { 1706 | goto fail; /* expected end of object */ 1707 | } 1708 | 1709 | success: 1710 | input_buffer->depth--; 1711 | 1712 | if (head != NULL) { 1713 | head->prev = current_item; 1714 | } 1715 | 1716 | item->type = cJSON_Object; 1717 | item->child = head; 1718 | 1719 | input_buffer->offset++; 1720 | return true; 1721 | 1722 | fail: 1723 | if (head != NULL) 1724 | { 1725 | cJSON_Delete(head); 1726 | } 1727 | 1728 | return false; 1729 | } 1730 | 1731 | /* Render an object to text. */ 1732 | static cJSON_bool print_object(const cJSON * const item, printbuffer * const output_buffer) 1733 | { 1734 | unsigned char *output_pointer = NULL; 1735 | size_t length = 0; 1736 | cJSON *current_item = item->child; 1737 | 1738 | if (output_buffer == NULL) 1739 | { 1740 | return false; 1741 | } 1742 | 1743 | /* Compose the output: */ 1744 | length = (size_t) (output_buffer->format ? 2 : 1); /* fmt: {\n */ 1745 | output_pointer = ensure(output_buffer, length + 1); 1746 | if (output_pointer == NULL) 1747 | { 1748 | return false; 1749 | } 1750 | 1751 | *output_pointer++ = '{'; 1752 | output_buffer->depth++; 1753 | if (output_buffer->format) 1754 | { 1755 | *output_pointer++ = '\n'; 1756 | } 1757 | output_buffer->offset += length; 1758 | 1759 | while (current_item) 1760 | { 1761 | if (output_buffer->format) 1762 | { 1763 | size_t i; 1764 | output_pointer = ensure(output_buffer, output_buffer->depth); 1765 | if (output_pointer == NULL) 1766 | { 1767 | return false; 1768 | } 1769 | for (i = 0; i < output_buffer->depth; i++) 1770 | { 1771 | *output_pointer++ = '\t'; 1772 | } 1773 | output_buffer->offset += output_buffer->depth; 1774 | } 1775 | 1776 | /* print key */ 1777 | if (!print_string_ptr((unsigned char*)current_item->string, output_buffer)) 1778 | { 1779 | return false; 1780 | } 1781 | update_offset(output_buffer); 1782 | 1783 | length = (size_t) (output_buffer->format ? 2 : 1); 1784 | output_pointer = ensure(output_buffer, length); 1785 | if (output_pointer == NULL) 1786 | { 1787 | return false; 1788 | } 1789 | *output_pointer++ = ':'; 1790 | if (output_buffer->format) 1791 | { 1792 | *output_pointer++ = '\t'; 1793 | } 1794 | output_buffer->offset += length; 1795 | 1796 | /* print value */ 1797 | if (!print_value(current_item, output_buffer)) 1798 | { 1799 | return false; 1800 | } 1801 | update_offset(output_buffer); 1802 | 1803 | /* print comma if not last */ 1804 | length = ((size_t)(output_buffer->format ? 1 : 0) + (size_t)(current_item->next ? 1 : 0)); 1805 | output_pointer = ensure(output_buffer, length + 1); 1806 | if (output_pointer == NULL) 1807 | { 1808 | return false; 1809 | } 1810 | if (current_item->next) 1811 | { 1812 | *output_pointer++ = ','; 1813 | } 1814 | 1815 | if (output_buffer->format) 1816 | { 1817 | *output_pointer++ = '\n'; 1818 | } 1819 | *output_pointer = '\0'; 1820 | output_buffer->offset += length; 1821 | 1822 | current_item = current_item->next; 1823 | } 1824 | 1825 | output_pointer = ensure(output_buffer, output_buffer->format ? (output_buffer->depth + 1) : 2); 1826 | if (output_pointer == NULL) 1827 | { 1828 | return false; 1829 | } 1830 | if (output_buffer->format) 1831 | { 1832 | size_t i; 1833 | for (i = 0; i < (output_buffer->depth - 1); i++) 1834 | { 1835 | *output_pointer++ = '\t'; 1836 | } 1837 | } 1838 | *output_pointer++ = '}'; 1839 | *output_pointer = '\0'; 1840 | output_buffer->depth--; 1841 | 1842 | return true; 1843 | } 1844 | 1845 | /* Get Array size/item / object item. */ 1846 | CJSON_PUBLIC(int) cJSON_GetArraySize(const cJSON *array) 1847 | { 1848 | cJSON *child = NULL; 1849 | size_t size = 0; 1850 | 1851 | if (array == NULL) 1852 | { 1853 | return 0; 1854 | } 1855 | 1856 | child = array->child; 1857 | 1858 | while(child != NULL) 1859 | { 1860 | size++; 1861 | child = child->next; 1862 | } 1863 | 1864 | /* FIXME: Can overflow here. Cannot be fixed without breaking the API */ 1865 | 1866 | return (int)size; 1867 | } 1868 | 1869 | static cJSON* get_array_item(const cJSON *array, size_t index) 1870 | { 1871 | cJSON *current_child = NULL; 1872 | 1873 | if (array == NULL) 1874 | { 1875 | return NULL; 1876 | } 1877 | 1878 | current_child = array->child; 1879 | while ((current_child != NULL) && (index > 0)) 1880 | { 1881 | index--; 1882 | current_child = current_child->next; 1883 | } 1884 | 1885 | return current_child; 1886 | } 1887 | 1888 | CJSON_PUBLIC(cJSON *) cJSON_GetArrayItem(const cJSON *array, int index) 1889 | { 1890 | if (index < 0) 1891 | { 1892 | return NULL; 1893 | } 1894 | 1895 | return get_array_item(array, (size_t)index); 1896 | } 1897 | 1898 | static cJSON *get_object_item(const cJSON * const object, const char * const name, const cJSON_bool case_sensitive) 1899 | { 1900 | cJSON *current_element = NULL; 1901 | 1902 | if ((object == NULL) || (name == NULL)) 1903 | { 1904 | return NULL; 1905 | } 1906 | 1907 | current_element = object->child; 1908 | if (case_sensitive) 1909 | { 1910 | while ((current_element != NULL) && (current_element->string != NULL) && (strcmp(name, current_element->string) != 0)) 1911 | { 1912 | current_element = current_element->next; 1913 | } 1914 | } 1915 | else 1916 | { 1917 | while ((current_element != NULL) && (case_insensitive_strcmp((const unsigned char*)name, (const unsigned char*)(current_element->string)) != 0)) 1918 | { 1919 | current_element = current_element->next; 1920 | } 1921 | } 1922 | 1923 | if ((current_element == NULL) || (current_element->string == NULL)) { 1924 | return NULL; 1925 | } 1926 | 1927 | return current_element; 1928 | } 1929 | 1930 | CJSON_PUBLIC(cJSON *) cJSON_GetObjectItem(const cJSON * const object, const char * const string) 1931 | { 1932 | return get_object_item(object, string, false); 1933 | } 1934 | 1935 | CJSON_PUBLIC(cJSON *) cJSON_GetObjectItemCaseSensitive(const cJSON * const object, const char * const string) 1936 | { 1937 | return get_object_item(object, string, true); 1938 | } 1939 | 1940 | CJSON_PUBLIC(cJSON_bool) cJSON_HasObjectItem(const cJSON *object, const char *string) 1941 | { 1942 | return cJSON_GetObjectItem(object, string) ? 1 : 0; 1943 | } 1944 | 1945 | /* Utility for array list handling. */ 1946 | static void suffix_object(cJSON *prev, cJSON *item) 1947 | { 1948 | prev->next = item; 1949 | item->prev = prev; 1950 | } 1951 | 1952 | /* Utility for handling references. */ 1953 | static cJSON *create_reference(const cJSON *item, const internal_hooks * const hooks) 1954 | { 1955 | cJSON *reference = NULL; 1956 | if (item == NULL) 1957 | { 1958 | return NULL; 1959 | } 1960 | 1961 | reference = cJSON_New_Item(hooks); 1962 | if (reference == NULL) 1963 | { 1964 | return NULL; 1965 | } 1966 | 1967 | memcpy(reference, item, sizeof(cJSON)); 1968 | reference->string = NULL; 1969 | reference->type |= cJSON_IsReference; 1970 | reference->next = reference->prev = NULL; 1971 | return reference; 1972 | } 1973 | 1974 | static cJSON_bool add_item_to_array(cJSON *array, cJSON *item) 1975 | { 1976 | cJSON *child = NULL; 1977 | 1978 | if ((item == NULL) || (array == NULL) || (array == item)) 1979 | { 1980 | return false; 1981 | } 1982 | 1983 | child = array->child; 1984 | /* 1985 | * To find the last item in array quickly, we use prev in array 1986 | */ 1987 | if (child == NULL) 1988 | { 1989 | /* list is empty, start new one */ 1990 | array->child = item; 1991 | item->prev = item; 1992 | item->next = NULL; 1993 | } 1994 | else 1995 | { 1996 | /* append to the end */ 1997 | if (child->prev) 1998 | { 1999 | suffix_object(child->prev, item); 2000 | array->child->prev = item; 2001 | } 2002 | } 2003 | 2004 | return true; 2005 | } 2006 | 2007 | /* Add item to array/object. */ 2008 | CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToArray(cJSON *array, cJSON *item) 2009 | { 2010 | return add_item_to_array(array, item); 2011 | } 2012 | 2013 | #if defined(__clang__) || (defined(__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5)))) 2014 | #pragma GCC diagnostic push 2015 | #endif 2016 | #ifdef __GNUC__ 2017 | #pragma GCC diagnostic ignored "-Wcast-qual" 2018 | #endif 2019 | /* helper function to cast away const */ 2020 | static void* cast_away_const(const void* string) 2021 | { 2022 | return (void*)string; 2023 | } 2024 | #if defined(__clang__) || (defined(__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5)))) 2025 | #pragma GCC diagnostic pop 2026 | #endif 2027 | 2028 | 2029 | static cJSON_bool add_item_to_object(cJSON * const object, const char * const string, cJSON * const item, const internal_hooks * const hooks, const cJSON_bool constant_key) 2030 | { 2031 | char *new_key = NULL; 2032 | int new_type = cJSON_Invalid; 2033 | 2034 | if ((object == NULL) || (string == NULL) || (item == NULL) || (object == item)) 2035 | { 2036 | return false; 2037 | } 2038 | 2039 | if (constant_key) 2040 | { 2041 | new_key = (char*)cast_away_const(string); 2042 | new_type = item->type | cJSON_StringIsConst; 2043 | } 2044 | else 2045 | { 2046 | new_key = (char*)cJSON_strdup((const unsigned char*)string, hooks); 2047 | if (new_key == NULL) 2048 | { 2049 | return false; 2050 | } 2051 | 2052 | new_type = item->type & ~cJSON_StringIsConst; 2053 | } 2054 | 2055 | if (!(item->type & cJSON_StringIsConst) && (item->string != NULL)) 2056 | { 2057 | hooks->deallocate(item->string); 2058 | } 2059 | 2060 | item->string = new_key; 2061 | item->type = new_type; 2062 | 2063 | return add_item_to_array(object, item); 2064 | } 2065 | 2066 | CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item) 2067 | { 2068 | return add_item_to_object(object, string, item, &global_hooks, false); 2069 | } 2070 | 2071 | /* Add an item to an object with constant string as key */ 2072 | CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item) 2073 | { 2074 | return add_item_to_object(object, string, item, &global_hooks, true); 2075 | } 2076 | 2077 | CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item) 2078 | { 2079 | if (array == NULL) 2080 | { 2081 | return false; 2082 | } 2083 | 2084 | return add_item_to_array(array, create_reference(item, &global_hooks)); 2085 | } 2086 | 2087 | CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item) 2088 | { 2089 | if ((object == NULL) || (string == NULL)) 2090 | { 2091 | return false; 2092 | } 2093 | 2094 | return add_item_to_object(object, string, create_reference(item, &global_hooks), &global_hooks, false); 2095 | } 2096 | 2097 | CJSON_PUBLIC(cJSON*) cJSON_AddNullToObject(cJSON * const object, const char * const name) 2098 | { 2099 | cJSON *null = cJSON_CreateNull(); 2100 | if (add_item_to_object(object, name, null, &global_hooks, false)) 2101 | { 2102 | return null; 2103 | } 2104 | 2105 | cJSON_Delete(null); 2106 | return NULL; 2107 | } 2108 | 2109 | CJSON_PUBLIC(cJSON*) cJSON_AddTrueToObject(cJSON * const object, const char * const name) 2110 | { 2111 | cJSON *true_item = cJSON_CreateTrue(); 2112 | if (add_item_to_object(object, name, true_item, &global_hooks, false)) 2113 | { 2114 | return true_item; 2115 | } 2116 | 2117 | cJSON_Delete(true_item); 2118 | return NULL; 2119 | } 2120 | 2121 | CJSON_PUBLIC(cJSON*) cJSON_AddFalseToObject(cJSON * const object, const char * const name) 2122 | { 2123 | cJSON *false_item = cJSON_CreateFalse(); 2124 | if (add_item_to_object(object, name, false_item, &global_hooks, false)) 2125 | { 2126 | return false_item; 2127 | } 2128 | 2129 | cJSON_Delete(false_item); 2130 | return NULL; 2131 | } 2132 | 2133 | CJSON_PUBLIC(cJSON*) cJSON_AddBoolToObject(cJSON * const object, const char * const name, const cJSON_bool boolean) 2134 | { 2135 | cJSON *bool_item = cJSON_CreateBool(boolean); 2136 | if (add_item_to_object(object, name, bool_item, &global_hooks, false)) 2137 | { 2138 | return bool_item; 2139 | } 2140 | 2141 | cJSON_Delete(bool_item); 2142 | return NULL; 2143 | } 2144 | 2145 | CJSON_PUBLIC(cJSON*) cJSON_AddNumberToObject(cJSON * const object, const char * const name, const double number) 2146 | { 2147 | cJSON *number_item = cJSON_CreateNumber(number); 2148 | if (add_item_to_object(object, name, number_item, &global_hooks, false)) 2149 | { 2150 | return number_item; 2151 | } 2152 | 2153 | cJSON_Delete(number_item); 2154 | return NULL; 2155 | } 2156 | 2157 | CJSON_PUBLIC(cJSON*) cJSON_AddStringToObject(cJSON * const object, const char * const name, const char * const string) 2158 | { 2159 | cJSON *string_item = cJSON_CreateString(string); 2160 | if (add_item_to_object(object, name, string_item, &global_hooks, false)) 2161 | { 2162 | return string_item; 2163 | } 2164 | 2165 | cJSON_Delete(string_item); 2166 | return NULL; 2167 | } 2168 | 2169 | CJSON_PUBLIC(cJSON*) cJSON_AddRawToObject(cJSON * const object, const char * const name, const char * const raw) 2170 | { 2171 | cJSON *raw_item = cJSON_CreateRaw(raw); 2172 | if (add_item_to_object(object, name, raw_item, &global_hooks, false)) 2173 | { 2174 | return raw_item; 2175 | } 2176 | 2177 | cJSON_Delete(raw_item); 2178 | return NULL; 2179 | } 2180 | 2181 | CJSON_PUBLIC(cJSON*) cJSON_AddObjectToObject(cJSON * const object, const char * const name) 2182 | { 2183 | cJSON *object_item = cJSON_CreateObject(); 2184 | if (add_item_to_object(object, name, object_item, &global_hooks, false)) 2185 | { 2186 | return object_item; 2187 | } 2188 | 2189 | cJSON_Delete(object_item); 2190 | return NULL; 2191 | } 2192 | 2193 | CJSON_PUBLIC(cJSON*) cJSON_AddArrayToObject(cJSON * const object, const char * const name) 2194 | { 2195 | cJSON *array = cJSON_CreateArray(); 2196 | if (add_item_to_object(object, name, array, &global_hooks, false)) 2197 | { 2198 | return array; 2199 | } 2200 | 2201 | cJSON_Delete(array); 2202 | return NULL; 2203 | } 2204 | 2205 | CJSON_PUBLIC(cJSON *) cJSON_DetachItemViaPointer(cJSON *parent, cJSON * const item) 2206 | { 2207 | if ((parent == NULL) || (item == NULL)) 2208 | { 2209 | return NULL; 2210 | } 2211 | 2212 | if (item != parent->child) 2213 | { 2214 | /* not the first element */ 2215 | item->prev->next = item->next; 2216 | } 2217 | if (item->next != NULL) 2218 | { 2219 | /* not the last element */ 2220 | item->next->prev = item->prev; 2221 | } 2222 | 2223 | if (item == parent->child) 2224 | { 2225 | /* first element */ 2226 | parent->child = item->next; 2227 | } 2228 | else if (item->next == NULL) 2229 | { 2230 | /* last element */ 2231 | parent->child->prev = item->prev; 2232 | } 2233 | 2234 | /* make sure the detached item doesn't point anywhere anymore */ 2235 | item->prev = NULL; 2236 | item->next = NULL; 2237 | 2238 | return item; 2239 | } 2240 | 2241 | CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromArray(cJSON *array, int which) 2242 | { 2243 | if (which < 0) 2244 | { 2245 | return NULL; 2246 | } 2247 | 2248 | return cJSON_DetachItemViaPointer(array, get_array_item(array, (size_t)which)); 2249 | } 2250 | 2251 | CJSON_PUBLIC(void) cJSON_DeleteItemFromArray(cJSON *array, int which) 2252 | { 2253 | cJSON_Delete(cJSON_DetachItemFromArray(array, which)); 2254 | } 2255 | 2256 | CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObject(cJSON *object, const char *string) 2257 | { 2258 | cJSON *to_detach = cJSON_GetObjectItem(object, string); 2259 | 2260 | return cJSON_DetachItemViaPointer(object, to_detach); 2261 | } 2262 | 2263 | CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObjectCaseSensitive(cJSON *object, const char *string) 2264 | { 2265 | cJSON *to_detach = cJSON_GetObjectItemCaseSensitive(object, string); 2266 | 2267 | return cJSON_DetachItemViaPointer(object, to_detach); 2268 | } 2269 | 2270 | CJSON_PUBLIC(void) cJSON_DeleteItemFromObject(cJSON *object, const char *string) 2271 | { 2272 | cJSON_Delete(cJSON_DetachItemFromObject(object, string)); 2273 | } 2274 | 2275 | CJSON_PUBLIC(void) cJSON_DeleteItemFromObjectCaseSensitive(cJSON *object, const char *string) 2276 | { 2277 | cJSON_Delete(cJSON_DetachItemFromObjectCaseSensitive(object, string)); 2278 | } 2279 | 2280 | /* Replace array/object items with new ones. */ 2281 | CJSON_PUBLIC(cJSON_bool) cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem) 2282 | { 2283 | cJSON *after_inserted = NULL; 2284 | 2285 | if (which < 0 || newitem == NULL) 2286 | { 2287 | return false; 2288 | } 2289 | 2290 | after_inserted = get_array_item(array, (size_t)which); 2291 | if (after_inserted == NULL) 2292 | { 2293 | return add_item_to_array(array, newitem); 2294 | } 2295 | 2296 | if (after_inserted != array->child && after_inserted->prev == NULL) { 2297 | /* return false if after_inserted is a corrupted array item */ 2298 | return false; 2299 | } 2300 | 2301 | newitem->next = after_inserted; 2302 | newitem->prev = after_inserted->prev; 2303 | after_inserted->prev = newitem; 2304 | if (after_inserted == array->child) 2305 | { 2306 | array->child = newitem; 2307 | } 2308 | else 2309 | { 2310 | newitem->prev->next = newitem; 2311 | } 2312 | return true; 2313 | } 2314 | 2315 | CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemViaPointer(cJSON * const parent, cJSON * const item, cJSON * replacement) 2316 | { 2317 | if ((parent == NULL) || (parent->child == NULL) || (replacement == NULL) || (item == NULL)) 2318 | { 2319 | return false; 2320 | } 2321 | 2322 | if (replacement == item) 2323 | { 2324 | return true; 2325 | } 2326 | 2327 | replacement->next = item->next; 2328 | replacement->prev = item->prev; 2329 | 2330 | if (replacement->next != NULL) 2331 | { 2332 | replacement->next->prev = replacement; 2333 | } 2334 | if (parent->child == item) 2335 | { 2336 | if (parent->child->prev == parent->child) 2337 | { 2338 | replacement->prev = replacement; 2339 | } 2340 | parent->child = replacement; 2341 | } 2342 | else 2343 | { /* 2344 | * To find the last item in array quickly, we use prev in array. 2345 | * We can't modify the last item's next pointer where this item was the parent's child 2346 | */ 2347 | if (replacement->prev != NULL) 2348 | { 2349 | replacement->prev->next = replacement; 2350 | } 2351 | if (replacement->next == NULL) 2352 | { 2353 | parent->child->prev = replacement; 2354 | } 2355 | } 2356 | 2357 | item->next = NULL; 2358 | item->prev = NULL; 2359 | cJSON_Delete(item); 2360 | 2361 | return true; 2362 | } 2363 | 2364 | CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem) 2365 | { 2366 | if (which < 0) 2367 | { 2368 | return false; 2369 | } 2370 | 2371 | return cJSON_ReplaceItemViaPointer(array, get_array_item(array, (size_t)which), newitem); 2372 | } 2373 | 2374 | static cJSON_bool replace_item_in_object(cJSON *object, const char *string, cJSON *replacement, cJSON_bool case_sensitive) 2375 | { 2376 | if ((replacement == NULL) || (string == NULL)) 2377 | { 2378 | return false; 2379 | } 2380 | 2381 | /* replace the name in the replacement */ 2382 | if (!(replacement->type & cJSON_StringIsConst) && (replacement->string != NULL)) 2383 | { 2384 | cJSON_free(replacement->string); 2385 | } 2386 | replacement->string = (char*)cJSON_strdup((const unsigned char*)string, &global_hooks); 2387 | if (replacement->string == NULL) 2388 | { 2389 | return false; 2390 | } 2391 | 2392 | replacement->type &= ~cJSON_StringIsConst; 2393 | 2394 | return cJSON_ReplaceItemViaPointer(object, get_object_item(object, string, case_sensitive), replacement); 2395 | } 2396 | 2397 | CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInObject(cJSON *object, const char *string, cJSON *newitem) 2398 | { 2399 | return replace_item_in_object(object, string, newitem, false); 2400 | } 2401 | 2402 | CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInObjectCaseSensitive(cJSON *object, const char *string, cJSON *newitem) 2403 | { 2404 | return replace_item_in_object(object, string, newitem, true); 2405 | } 2406 | 2407 | /* Create basic types: */ 2408 | CJSON_PUBLIC(cJSON *) cJSON_CreateNull(void) 2409 | { 2410 | cJSON *item = cJSON_New_Item(&global_hooks); 2411 | if(item) 2412 | { 2413 | item->type = cJSON_NULL; 2414 | } 2415 | 2416 | return item; 2417 | } 2418 | 2419 | CJSON_PUBLIC(cJSON *) cJSON_CreateTrue(void) 2420 | { 2421 | cJSON *item = cJSON_New_Item(&global_hooks); 2422 | if(item) 2423 | { 2424 | item->type = cJSON_True; 2425 | } 2426 | 2427 | return item; 2428 | } 2429 | 2430 | CJSON_PUBLIC(cJSON *) cJSON_CreateFalse(void) 2431 | { 2432 | cJSON *item = cJSON_New_Item(&global_hooks); 2433 | if(item) 2434 | { 2435 | item->type = cJSON_False; 2436 | } 2437 | 2438 | return item; 2439 | } 2440 | 2441 | CJSON_PUBLIC(cJSON *) cJSON_CreateBool(cJSON_bool boolean) 2442 | { 2443 | cJSON *item = cJSON_New_Item(&global_hooks); 2444 | if(item) 2445 | { 2446 | item->type = boolean ? cJSON_True : cJSON_False; 2447 | } 2448 | 2449 | return item; 2450 | } 2451 | 2452 | CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num) 2453 | { 2454 | cJSON *item = cJSON_New_Item(&global_hooks); 2455 | if(item) 2456 | { 2457 | item->type = cJSON_Number; 2458 | item->valuedouble = num; 2459 | 2460 | /* use saturation in case of overflow */ 2461 | if (num >= INT_MAX) 2462 | { 2463 | item->valueint = INT_MAX; 2464 | } 2465 | else if (num <= (double)INT_MIN) 2466 | { 2467 | item->valueint = INT_MIN; 2468 | } 2469 | else 2470 | { 2471 | item->valueint = (int)num; 2472 | } 2473 | } 2474 | 2475 | return item; 2476 | } 2477 | 2478 | CJSON_PUBLIC(cJSON *) cJSON_CreateString(const char *string) 2479 | { 2480 | cJSON *item = cJSON_New_Item(&global_hooks); 2481 | if(item) 2482 | { 2483 | item->type = cJSON_String; 2484 | item->valuestring = (char*)cJSON_strdup((const unsigned char*)string, &global_hooks); 2485 | if(!item->valuestring) 2486 | { 2487 | cJSON_Delete(item); 2488 | return NULL; 2489 | } 2490 | } 2491 | 2492 | return item; 2493 | } 2494 | 2495 | CJSON_PUBLIC(cJSON *) cJSON_CreateStringReference(const char *string) 2496 | { 2497 | cJSON *item = cJSON_New_Item(&global_hooks); 2498 | if (item != NULL) 2499 | { 2500 | item->type = cJSON_String | cJSON_IsReference; 2501 | item->valuestring = (char*)cast_away_const(string); 2502 | } 2503 | 2504 | return item; 2505 | } 2506 | 2507 | CJSON_PUBLIC(cJSON *) cJSON_CreateObjectReference(const cJSON *child) 2508 | { 2509 | cJSON *item = cJSON_New_Item(&global_hooks); 2510 | if (item != NULL) { 2511 | item->type = cJSON_Object | cJSON_IsReference; 2512 | item->child = (cJSON*)cast_away_const(child); 2513 | } 2514 | 2515 | return item; 2516 | } 2517 | 2518 | CJSON_PUBLIC(cJSON *) cJSON_CreateArrayReference(const cJSON *child) { 2519 | cJSON *item = cJSON_New_Item(&global_hooks); 2520 | if (item != NULL) { 2521 | item->type = cJSON_Array | cJSON_IsReference; 2522 | item->child = (cJSON*)cast_away_const(child); 2523 | } 2524 | 2525 | return item; 2526 | } 2527 | 2528 | CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw) 2529 | { 2530 | cJSON *item = cJSON_New_Item(&global_hooks); 2531 | if(item) 2532 | { 2533 | item->type = cJSON_Raw; 2534 | item->valuestring = (char*)cJSON_strdup((const unsigned char*)raw, &global_hooks); 2535 | if(!item->valuestring) 2536 | { 2537 | cJSON_Delete(item); 2538 | return NULL; 2539 | } 2540 | } 2541 | 2542 | return item; 2543 | } 2544 | 2545 | CJSON_PUBLIC(cJSON *) cJSON_CreateArray(void) 2546 | { 2547 | cJSON *item = cJSON_New_Item(&global_hooks); 2548 | if(item) 2549 | { 2550 | item->type=cJSON_Array; 2551 | } 2552 | 2553 | return item; 2554 | } 2555 | 2556 | CJSON_PUBLIC(cJSON *) cJSON_CreateObject(void) 2557 | { 2558 | cJSON *item = cJSON_New_Item(&global_hooks); 2559 | if (item) 2560 | { 2561 | item->type = cJSON_Object; 2562 | } 2563 | 2564 | return item; 2565 | } 2566 | 2567 | /* Create Arrays: */ 2568 | CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count) 2569 | { 2570 | size_t i = 0; 2571 | cJSON *n = NULL; 2572 | cJSON *p = NULL; 2573 | cJSON *a = NULL; 2574 | 2575 | if ((count < 0) || (numbers == NULL)) 2576 | { 2577 | return NULL; 2578 | } 2579 | 2580 | a = cJSON_CreateArray(); 2581 | 2582 | for(i = 0; a && (i < (size_t)count); i++) 2583 | { 2584 | n = cJSON_CreateNumber(numbers[i]); 2585 | if (!n) 2586 | { 2587 | cJSON_Delete(a); 2588 | return NULL; 2589 | } 2590 | if(!i) 2591 | { 2592 | a->child = n; 2593 | } 2594 | else 2595 | { 2596 | suffix_object(p, n); 2597 | } 2598 | p = n; 2599 | } 2600 | 2601 | if (a && a->child) { 2602 | a->child->prev = n; 2603 | } 2604 | 2605 | return a; 2606 | } 2607 | 2608 | CJSON_PUBLIC(cJSON *) cJSON_CreateFloatArray(const float *numbers, int count) 2609 | { 2610 | size_t i = 0; 2611 | cJSON *n = NULL; 2612 | cJSON *p = NULL; 2613 | cJSON *a = NULL; 2614 | 2615 | if ((count < 0) || (numbers == NULL)) 2616 | { 2617 | return NULL; 2618 | } 2619 | 2620 | a = cJSON_CreateArray(); 2621 | 2622 | for(i = 0; a && (i < (size_t)count); i++) 2623 | { 2624 | n = cJSON_CreateNumber((double)numbers[i]); 2625 | if(!n) 2626 | { 2627 | cJSON_Delete(a); 2628 | return NULL; 2629 | } 2630 | if(!i) 2631 | { 2632 | a->child = n; 2633 | } 2634 | else 2635 | { 2636 | suffix_object(p, n); 2637 | } 2638 | p = n; 2639 | } 2640 | 2641 | if (a && a->child) { 2642 | a->child->prev = n; 2643 | } 2644 | 2645 | return a; 2646 | } 2647 | 2648 | CJSON_PUBLIC(cJSON *) cJSON_CreateDoubleArray(const double *numbers, int count) 2649 | { 2650 | size_t i = 0; 2651 | cJSON *n = NULL; 2652 | cJSON *p = NULL; 2653 | cJSON *a = NULL; 2654 | 2655 | if ((count < 0) || (numbers == NULL)) 2656 | { 2657 | return NULL; 2658 | } 2659 | 2660 | a = cJSON_CreateArray(); 2661 | 2662 | for(i = 0; a && (i < (size_t)count); i++) 2663 | { 2664 | n = cJSON_CreateNumber(numbers[i]); 2665 | if(!n) 2666 | { 2667 | cJSON_Delete(a); 2668 | return NULL; 2669 | } 2670 | if(!i) 2671 | { 2672 | a->child = n; 2673 | } 2674 | else 2675 | { 2676 | suffix_object(p, n); 2677 | } 2678 | p = n; 2679 | } 2680 | 2681 | if (a && a->child) { 2682 | a->child->prev = n; 2683 | } 2684 | 2685 | return a; 2686 | } 2687 | 2688 | CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char *const *strings, int count) 2689 | { 2690 | size_t i = 0; 2691 | cJSON *n = NULL; 2692 | cJSON *p = NULL; 2693 | cJSON *a = NULL; 2694 | 2695 | if ((count < 0) || (strings == NULL)) 2696 | { 2697 | return NULL; 2698 | } 2699 | 2700 | a = cJSON_CreateArray(); 2701 | 2702 | for (i = 0; a && (i < (size_t)count); i++) 2703 | { 2704 | n = cJSON_CreateString(strings[i]); 2705 | if(!n) 2706 | { 2707 | cJSON_Delete(a); 2708 | return NULL; 2709 | } 2710 | if(!i) 2711 | { 2712 | a->child = n; 2713 | } 2714 | else 2715 | { 2716 | suffix_object(p,n); 2717 | } 2718 | p = n; 2719 | } 2720 | 2721 | if (a && a->child) { 2722 | a->child->prev = n; 2723 | } 2724 | 2725 | return a; 2726 | } 2727 | 2728 | /* Duplication */ 2729 | CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse) 2730 | { 2731 | cJSON *newitem = NULL; 2732 | cJSON *child = NULL; 2733 | cJSON *next = NULL; 2734 | cJSON *newchild = NULL; 2735 | 2736 | /* Bail on bad ptr */ 2737 | if (!item) 2738 | { 2739 | goto fail; 2740 | } 2741 | /* Create new item */ 2742 | newitem = cJSON_New_Item(&global_hooks); 2743 | if (!newitem) 2744 | { 2745 | goto fail; 2746 | } 2747 | /* Copy over all vars */ 2748 | newitem->type = item->type & (~cJSON_IsReference); 2749 | newitem->valueint = item->valueint; 2750 | newitem->valuedouble = item->valuedouble; 2751 | if (item->valuestring) 2752 | { 2753 | newitem->valuestring = (char*)cJSON_strdup((unsigned char*)item->valuestring, &global_hooks); 2754 | if (!newitem->valuestring) 2755 | { 2756 | goto fail; 2757 | } 2758 | } 2759 | if (item->string) 2760 | { 2761 | newitem->string = (item->type&cJSON_StringIsConst) ? item->string : (char*)cJSON_strdup((unsigned char*)item->string, &global_hooks); 2762 | if (!newitem->string) 2763 | { 2764 | goto fail; 2765 | } 2766 | } 2767 | /* If non-recursive, then we're done! */ 2768 | if (!recurse) 2769 | { 2770 | return newitem; 2771 | } 2772 | /* Walk the ->next chain for the child. */ 2773 | child = item->child; 2774 | while (child != NULL) 2775 | { 2776 | newchild = cJSON_Duplicate(child, true); /* Duplicate (with recurse) each item in the ->next chain */ 2777 | if (!newchild) 2778 | { 2779 | goto fail; 2780 | } 2781 | if (next != NULL) 2782 | { 2783 | /* If newitem->child already set, then crosswire ->prev and ->next and move on */ 2784 | next->next = newchild; 2785 | newchild->prev = next; 2786 | next = newchild; 2787 | } 2788 | else 2789 | { 2790 | /* Set newitem->child and move to it */ 2791 | newitem->child = newchild; 2792 | next = newchild; 2793 | } 2794 | child = child->next; 2795 | } 2796 | if (newitem && newitem->child) 2797 | { 2798 | newitem->child->prev = newchild; 2799 | } 2800 | 2801 | return newitem; 2802 | 2803 | fail: 2804 | if (newitem != NULL) 2805 | { 2806 | cJSON_Delete(newitem); 2807 | } 2808 | 2809 | return NULL; 2810 | } 2811 | 2812 | static void skip_oneline_comment(char **input) 2813 | { 2814 | *input += static_strlen("//"); 2815 | 2816 | for (; (*input)[0] != '\0'; ++(*input)) 2817 | { 2818 | if ((*input)[0] == '\n') { 2819 | *input += static_strlen("\n"); 2820 | return; 2821 | } 2822 | } 2823 | } 2824 | 2825 | static void skip_multiline_comment(char **input) 2826 | { 2827 | *input += static_strlen("/*"); 2828 | 2829 | for (; (*input)[0] != '\0'; ++(*input)) 2830 | { 2831 | if (((*input)[0] == '*') && ((*input)[1] == '/')) 2832 | { 2833 | *input += static_strlen("*/"); 2834 | return; 2835 | } 2836 | } 2837 | } 2838 | 2839 | static void minify_string(char **input, char **output) { 2840 | (*output)[0] = (*input)[0]; 2841 | *input += static_strlen("\""); 2842 | *output += static_strlen("\""); 2843 | 2844 | 2845 | for (; (*input)[0] != '\0'; (void)++(*input), ++(*output)) { 2846 | (*output)[0] = (*input)[0]; 2847 | 2848 | if ((*input)[0] == '\"') { 2849 | (*output)[0] = '\"'; 2850 | *input += static_strlen("\""); 2851 | *output += static_strlen("\""); 2852 | return; 2853 | } else if (((*input)[0] == '\\') && ((*input)[1] == '\"')) { 2854 | (*output)[1] = (*input)[1]; 2855 | *input += static_strlen("\""); 2856 | *output += static_strlen("\""); 2857 | } 2858 | } 2859 | } 2860 | 2861 | CJSON_PUBLIC(void) cJSON_Minify(char *json) 2862 | { 2863 | char *into = json; 2864 | 2865 | if (json == NULL) 2866 | { 2867 | return; 2868 | } 2869 | 2870 | while (json[0] != '\0') 2871 | { 2872 | switch (json[0]) 2873 | { 2874 | case ' ': 2875 | case '\t': 2876 | case '\r': 2877 | case '\n': 2878 | json++; 2879 | break; 2880 | 2881 | case '/': 2882 | if (json[1] == '/') 2883 | { 2884 | skip_oneline_comment(&json); 2885 | } 2886 | else if (json[1] == '*') 2887 | { 2888 | skip_multiline_comment(&json); 2889 | } else { 2890 | json++; 2891 | } 2892 | break; 2893 | 2894 | case '\"': 2895 | minify_string(&json, (char**)&into); 2896 | break; 2897 | 2898 | default: 2899 | into[0] = json[0]; 2900 | json++; 2901 | into++; 2902 | } 2903 | } 2904 | 2905 | /* and null-terminate. */ 2906 | *into = '\0'; 2907 | } 2908 | 2909 | CJSON_PUBLIC(cJSON_bool) cJSON_IsInvalid(const cJSON * const item) 2910 | { 2911 | if (item == NULL) 2912 | { 2913 | return false; 2914 | } 2915 | 2916 | return (item->type & 0xFF) == cJSON_Invalid; 2917 | } 2918 | 2919 | CJSON_PUBLIC(cJSON_bool) cJSON_IsFalse(const cJSON * const item) 2920 | { 2921 | if (item == NULL) 2922 | { 2923 | return false; 2924 | } 2925 | 2926 | return (item->type & 0xFF) == cJSON_False; 2927 | } 2928 | 2929 | CJSON_PUBLIC(cJSON_bool) cJSON_IsTrue(const cJSON * const item) 2930 | { 2931 | if (item == NULL) 2932 | { 2933 | return false; 2934 | } 2935 | 2936 | return (item->type & 0xff) == cJSON_True; 2937 | } 2938 | 2939 | 2940 | CJSON_PUBLIC(cJSON_bool) cJSON_IsBool(const cJSON * const item) 2941 | { 2942 | if (item == NULL) 2943 | { 2944 | return false; 2945 | } 2946 | 2947 | return (item->type & (cJSON_True | cJSON_False)) != 0; 2948 | } 2949 | CJSON_PUBLIC(cJSON_bool) cJSON_IsNull(const cJSON * const item) 2950 | { 2951 | if (item == NULL) 2952 | { 2953 | return false; 2954 | } 2955 | 2956 | return (item->type & 0xFF) == cJSON_NULL; 2957 | } 2958 | 2959 | CJSON_PUBLIC(cJSON_bool) cJSON_IsNumber(const cJSON * const item) 2960 | { 2961 | if (item == NULL) 2962 | { 2963 | return false; 2964 | } 2965 | 2966 | return (item->type & 0xFF) == cJSON_Number; 2967 | } 2968 | 2969 | CJSON_PUBLIC(cJSON_bool) cJSON_IsString(const cJSON * const item) 2970 | { 2971 | if (item == NULL) 2972 | { 2973 | return false; 2974 | } 2975 | 2976 | return (item->type & 0xFF) == cJSON_String; 2977 | } 2978 | 2979 | CJSON_PUBLIC(cJSON_bool) cJSON_IsArray(const cJSON * const item) 2980 | { 2981 | if (item == NULL) 2982 | { 2983 | return false; 2984 | } 2985 | 2986 | return (item->type & 0xFF) == cJSON_Array; 2987 | } 2988 | 2989 | CJSON_PUBLIC(cJSON_bool) cJSON_IsObject(const cJSON * const item) 2990 | { 2991 | if (item == NULL) 2992 | { 2993 | return false; 2994 | } 2995 | 2996 | return (item->type & 0xFF) == cJSON_Object; 2997 | } 2998 | 2999 | CJSON_PUBLIC(cJSON_bool) cJSON_IsRaw(const cJSON * const item) 3000 | { 3001 | if (item == NULL) 3002 | { 3003 | return false; 3004 | } 3005 | 3006 | return (item->type & 0xFF) == cJSON_Raw; 3007 | } 3008 | 3009 | CJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON * const a, const cJSON * const b, const cJSON_bool case_sensitive) 3010 | { 3011 | if ((a == NULL) || (b == NULL) || ((a->type & 0xFF) != (b->type & 0xFF))) 3012 | { 3013 | return false; 3014 | } 3015 | 3016 | /* check if type is valid */ 3017 | switch (a->type & 0xFF) 3018 | { 3019 | case cJSON_False: 3020 | case cJSON_True: 3021 | case cJSON_NULL: 3022 | case cJSON_Number: 3023 | case cJSON_String: 3024 | case cJSON_Raw: 3025 | case cJSON_Array: 3026 | case cJSON_Object: 3027 | break; 3028 | 3029 | default: 3030 | return false; 3031 | } 3032 | 3033 | /* identical objects are equal */ 3034 | if (a == b) 3035 | { 3036 | return true; 3037 | } 3038 | 3039 | switch (a->type & 0xFF) 3040 | { 3041 | /* in these cases and equal type is enough */ 3042 | case cJSON_False: 3043 | case cJSON_True: 3044 | case cJSON_NULL: 3045 | return true; 3046 | 3047 | case cJSON_Number: 3048 | if (compare_double(a->valuedouble, b->valuedouble)) 3049 | { 3050 | return true; 3051 | } 3052 | return false; 3053 | 3054 | case cJSON_String: 3055 | case cJSON_Raw: 3056 | if ((a->valuestring == NULL) || (b->valuestring == NULL)) 3057 | { 3058 | return false; 3059 | } 3060 | if (strcmp(a->valuestring, b->valuestring) == 0) 3061 | { 3062 | return true; 3063 | } 3064 | 3065 | return false; 3066 | 3067 | case cJSON_Array: 3068 | { 3069 | cJSON *a_element = a->child; 3070 | cJSON *b_element = b->child; 3071 | 3072 | for (; (a_element != NULL) && (b_element != NULL);) 3073 | { 3074 | if (!cJSON_Compare(a_element, b_element, case_sensitive)) 3075 | { 3076 | return false; 3077 | } 3078 | 3079 | a_element = a_element->next; 3080 | b_element = b_element->next; 3081 | } 3082 | 3083 | /* one of the arrays is longer than the other */ 3084 | if (a_element != b_element) { 3085 | return false; 3086 | } 3087 | 3088 | return true; 3089 | } 3090 | 3091 | case cJSON_Object: 3092 | { 3093 | cJSON *a_element = NULL; 3094 | cJSON *b_element = NULL; 3095 | cJSON_ArrayForEach(a_element, a) 3096 | { 3097 | /* TODO This has O(n^2) runtime, which is horrible! */ 3098 | b_element = get_object_item(b, a_element->string, case_sensitive); 3099 | if (b_element == NULL) 3100 | { 3101 | return false; 3102 | } 3103 | 3104 | if (!cJSON_Compare(a_element, b_element, case_sensitive)) 3105 | { 3106 | return false; 3107 | } 3108 | } 3109 | 3110 | /* doing this twice, once on a and b to prevent true comparison if a subset of b 3111 | * TODO: Do this the proper way, this is just a fix for now */ 3112 | cJSON_ArrayForEach(b_element, b) 3113 | { 3114 | a_element = get_object_item(a, b_element->string, case_sensitive); 3115 | if (a_element == NULL) 3116 | { 3117 | return false; 3118 | } 3119 | 3120 | if (!cJSON_Compare(b_element, a_element, case_sensitive)) 3121 | { 3122 | return false; 3123 | } 3124 | } 3125 | 3126 | return true; 3127 | } 3128 | 3129 | default: 3130 | return false; 3131 | } 3132 | } 3133 | 3134 | CJSON_PUBLIC(void *) cJSON_malloc(size_t size) 3135 | { 3136 | return global_hooks.allocate(size); 3137 | } 3138 | 3139 | CJSON_PUBLIC(void) cJSON_free(void *object) 3140 | { 3141 | global_hooks.deallocate(object); 3142 | object = NULL; 3143 | } 3144 | -------------------------------------------------------------------------------- /src/jsonrpc-c.c: -------------------------------------------------------------------------------- 1 | /* 2 | * jsonrpc-c.c 3 | * 4 | * Created on: Oct 11, 2012 5 | * Author: hmng 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | #include "config.h" 20 | #ifdef HAVE_STDBOOL_H 21 | # include 22 | #else 23 | # ifndef HAVE__BOOL 24 | # ifdef __cplusplus 25 | typedef bool _Bool; 26 | # else 27 | # define _Bool signed char 28 | # endif 29 | # endif 30 | # define bool _Bool 31 | # define false 0 32 | # define true 1 33 | # define __bool_true_false_are_defined 1 34 | #endif 35 | 36 | #include "jsonrpc-c.h" 37 | 38 | static int __jrpc_server_start(struct jrpc_server *server); 39 | static void jrpc_procedure_destroy(struct jrpc_procedure *procedure); 40 | 41 | struct ev_loop *loop; 42 | 43 | // get sockaddr, IPv4 or IPv6: 44 | static void *get_in_addr(struct sockaddr *sa) { 45 | if (sa->sa_family == AF_INET) { 46 | return &(((struct sockaddr_in*) sa)->sin_addr); 47 | } 48 | return &(((struct sockaddr_in6*) sa)->sin6_addr); 49 | } 50 | 51 | static int send_response(struct jrpc_connection * conn, char *response) { 52 | ssize_t unused; 53 | int fd = conn->fd; 54 | if (conn->debug_level > 1) 55 | printf("JSON Response:\n%s\n", response); 56 | unused = write(fd, response, strlen(response)); 57 | unused = write(fd, "\n", 1); 58 | return 0; 59 | } 60 | 61 | static int send_error(struct jrpc_connection * conn, int code, char* message, 62 | cJSON * id) { 63 | int return_value = 0; 64 | cJSON *result_root = cJSON_CreateObject(); 65 | cJSON *error_root = cJSON_CreateObject(); 66 | cJSON_AddNumberToObject(error_root, "code", code); 67 | cJSON_AddStringToObject(error_root, "message", message); 68 | cJSON_AddItemToObject(result_root, "error", error_root); 69 | cJSON_AddItemToObject(result_root, "id", id); 70 | char * str_result = cJSON_Print(result_root); 71 | return_value = send_response(conn, str_result); 72 | free(str_result); 73 | cJSON_Delete(result_root); 74 | free(message); 75 | return return_value; 76 | } 77 | 78 | static int send_result(struct jrpc_connection * conn, cJSON * result, 79 | cJSON * id) { 80 | int return_value = 0; 81 | cJSON *result_root = cJSON_CreateObject(); 82 | if (result) 83 | cJSON_AddItemToObject(result_root, "result", result); 84 | cJSON_AddItemToObject(result_root, "id", id); 85 | 86 | char * str_result = cJSON_Print(result_root); 87 | return_value = send_response(conn, str_result); 88 | free(str_result); 89 | cJSON_Delete(result_root); 90 | return return_value; 91 | } 92 | 93 | static int invoke_procedure(struct jrpc_server *server, 94 | struct jrpc_connection * conn, char *name, cJSON *params, cJSON *id) { 95 | cJSON *returned = NULL; 96 | int procedure_found = 0; 97 | jrpc_context ctx; 98 | ctx.error_code = 0; 99 | ctx.error_message = NULL; 100 | int i = server->procedure_count; 101 | while (i--) { 102 | if (!strcmp(server->procedures[i].name, name)) { 103 | procedure_found = 1; 104 | ctx.data = server->procedures[i].data; 105 | returned = server->procedures[i].function(&ctx, params, id); 106 | break; 107 | } 108 | } 109 | if (!procedure_found) 110 | return send_error(conn, JRPC_METHOD_NOT_FOUND, 111 | strdup("Method not found."), id); 112 | else { 113 | if (ctx.error_code) 114 | return send_error(conn, ctx.error_code, ctx.error_message, id); 115 | else { 116 | // notifications have no reply 117 | // the standard indicates that notifications are sent without "id" 118 | // but we leave the decision for clients; by returning NULL we skip the reply 119 | if (returned != NULL) { 120 | return send_result(conn, returned, id); 121 | } else { 122 | return 0; 123 | } 124 | } 125 | } 126 | } 127 | 128 | static int eval_request(struct jrpc_server *server, 129 | struct jrpc_connection * conn, cJSON *root) { 130 | cJSON *method, *params, *id; 131 | method = cJSON_GetObjectItem(root, "method"); 132 | if (method != NULL && method->type == cJSON_String) { 133 | params = cJSON_GetObjectItem(root, "params"); 134 | if (params == NULL|| params->type == cJSON_Array 135 | || params->type == cJSON_Object) { 136 | id = cJSON_GetObjectItem(root, "id"); 137 | if (id == NULL|| id->type == cJSON_String 138 | || id->type == cJSON_Number) { 139 | //We have to copy ID because using it on the reply and deleting the response Object will also delete ID 140 | cJSON * id_copy = NULL; 141 | if (id != NULL) 142 | id_copy = 143 | (id->type == cJSON_String) ? cJSON_CreateString( 144 | id->valuestring) : 145 | cJSON_CreateNumber(id->valueint); 146 | if (server->debug_level) 147 | printf("Method Invoked: %s\n", method->valuestring); 148 | return invoke_procedure(server, conn, method->valuestring, 149 | params, id_copy); 150 | } 151 | } 152 | } 153 | send_error(conn, JRPC_INVALID_REQUEST, 154 | strdup("The JSON sent is not a valid Request object."), NULL); 155 | return -1; 156 | } 157 | 158 | static void close_connection(struct ev_loop *loop, ev_io *w) { 159 | ev_io_stop(loop, w); 160 | close(((struct jrpc_connection *) w)->fd); 161 | free(((struct jrpc_connection *) w)->buffer); 162 | free(((struct jrpc_connection *) w)); 163 | } 164 | 165 | static void connection_cb(struct ev_loop *loop, ev_io *w, int revents) { 166 | struct jrpc_connection *conn; 167 | struct jrpc_server *server = (struct jrpc_server *) w->data; 168 | size_t bytes_read = 0; 169 | //get our 'subclassed' event watcher 170 | conn = (struct jrpc_connection *) w; 171 | int fd = conn->fd; 172 | if (conn->pos == (conn->buffer_size - 1)) { 173 | char * new_buffer = realloc(conn->buffer, conn->buffer_size *= 2); 174 | if (new_buffer == NULL) { 175 | perror("Memory error"); 176 | return close_connection(loop, w); 177 | } 178 | conn->buffer = new_buffer; 179 | memset(conn->buffer + conn->pos, 0, conn->buffer_size - conn->pos); 180 | } 181 | // can not fill the entire buffer, string must be NULL terminated 182 | int max_read_size = conn->buffer_size - conn->pos - 1; 183 | if ((bytes_read = read(fd, conn->buffer + conn->pos, max_read_size)) 184 | == -1) { 185 | perror("read"); 186 | return close_connection(loop, w); 187 | } 188 | if (!bytes_read) { 189 | // client closed the sending half of the connection 190 | if (server->debug_level) 191 | printf("Client closed connection.\n"); 192 | return close_connection(loop, w); 193 | } else { 194 | cJSON *root; 195 | const char *end_ptr = NULL; 196 | conn->pos += bytes_read; 197 | 198 | if ((root = cJSON_ParseWithOpts(conn->buffer, &end_ptr, false)) != NULL) { 199 | if (server->debug_level > 1) { 200 | char * str_result = cJSON_Print(root); 201 | printf("Valid JSON Received:\n%s\n", str_result); 202 | free(str_result); 203 | } 204 | 205 | if (root->type == cJSON_Object) { 206 | eval_request(server, conn, root); 207 | } 208 | //shift processed request, discarding it 209 | memmove(conn->buffer, end_ptr, strlen(end_ptr) + 2); 210 | 211 | conn->pos = strlen(end_ptr); 212 | memset(conn->buffer + conn->pos, 0, 213 | conn->buffer_size - conn->pos - 1); 214 | 215 | cJSON_Delete(root); 216 | } else { 217 | // did we parse the entire buffer? If so, just wait for more. 218 | // else there was an error before the buffer's end 219 | if (end_ptr != (conn->buffer + conn->pos)) { 220 | if (server->debug_level) { 221 | printf("INVALID JSON Received:\n---\n%s\n---\n", 222 | conn->buffer); 223 | } 224 | send_error(conn, JRPC_PARSE_ERROR, 225 | strdup( 226 | "Parse error. Invalid JSON was received by the server."), 227 | NULL); 228 | return close_connection(loop, w); 229 | } 230 | } 231 | } 232 | 233 | } 234 | 235 | static void accept_cb(struct ev_loop *loop, ev_io *w, int revents) { 236 | char s[INET6_ADDRSTRLEN]; 237 | struct jrpc_connection *connection_watcher; 238 | connection_watcher = malloc(sizeof(struct jrpc_connection)); 239 | struct sockaddr_storage their_addr; // connector's address information 240 | socklen_t sin_size; 241 | sin_size = sizeof their_addr; 242 | connection_watcher->fd = accept(w->fd, (struct sockaddr *) &their_addr, 243 | &sin_size); 244 | if (connection_watcher->fd == -1) { 245 | perror("accept"); 246 | free(connection_watcher); 247 | } else { 248 | if (((struct jrpc_server *) w->data)->debug_level) { 249 | inet_ntop(their_addr.ss_family, 250 | get_in_addr((struct sockaddr *) &their_addr), s, sizeof s); 251 | printf("server: got connection from %s\n", s); 252 | } 253 | ev_io_init(&connection_watcher->io, connection_cb, 254 | connection_watcher->fd, EV_READ); 255 | //copy pointer to struct jrpc_server 256 | connection_watcher->io.data = w->data; 257 | connection_watcher->buffer_size = 1500; 258 | connection_watcher->buffer = malloc(1500); 259 | memset(connection_watcher->buffer, 0, 1500); 260 | connection_watcher->pos = 0; 261 | //copy debug_level, struct jrpc_connection has no pointer to struct jrpc_server 262 | connection_watcher->debug_level = 263 | ((struct jrpc_server *) w->data)->debug_level; 264 | ev_io_start(loop, &connection_watcher->io); 265 | } 266 | } 267 | 268 | int jrpc_server_init(struct jrpc_server *server, int port_number) { 269 | loop = EV_DEFAULT; 270 | return jrpc_server_init_with_ev_loop(server, port_number, loop); 271 | } 272 | 273 | int jrpc_server_init_with_ev_loop(struct jrpc_server *server, 274 | int port_number, struct ev_loop *loop) { 275 | memset(server, 0, sizeof(struct jrpc_server)); 276 | server->loop = loop; 277 | server->port_number = port_number; 278 | char * debug_level_env = getenv("JRPC_DEBUG"); 279 | if (debug_level_env == NULL) 280 | server->debug_level = 0; 281 | else { 282 | server->debug_level = strtol(debug_level_env, NULL, 10); 283 | printf("JSONRPC-C Debug level %d\n", server->debug_level); 284 | } 285 | return __jrpc_server_start(server); 286 | } 287 | 288 | static int __jrpc_server_start(struct jrpc_server *server) { 289 | int sockfd; 290 | struct addrinfo hints, *servinfo, *p; 291 | struct sockaddr_in sockaddr; 292 | unsigned int len; 293 | int yes = 1; 294 | int rv; 295 | char PORT[6]; 296 | sprintf(PORT, "%d", server->port_number); 297 | memset(&hints, 0, sizeof hints); 298 | hints.ai_family = AF_UNSPEC; 299 | hints.ai_socktype = SOCK_STREAM; 300 | hints.ai_flags = AI_PASSIVE; // use my IP 301 | 302 | if ((rv = getaddrinfo(NULL, PORT, &hints, &servinfo)) != 0) { 303 | fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv)); 304 | return 1; 305 | } 306 | 307 | // loop through all the results and bind to the first we can 308 | for (p = servinfo; p != NULL; p = p->ai_next) { 309 | if ((sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) 310 | == -1) { 311 | perror("server: socket"); 312 | continue; 313 | } 314 | 315 | if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) 316 | == -1) { 317 | perror("setsockopt"); 318 | return -1; 319 | } 320 | 321 | if (bind(sockfd, p->ai_addr, p->ai_addrlen) == -1) { 322 | close(sockfd); 323 | perror("server: bind"); 324 | continue; 325 | } 326 | 327 | len = sizeof(sockaddr); 328 | if (getsockname(sockfd, (struct sockaddr *) &sockaddr, &len) == -1) { 329 | close(sockfd); 330 | perror("server: getsockname"); 331 | continue; 332 | } 333 | server->port_number = ntohs( sockaddr.sin_port ); 334 | 335 | break; 336 | } 337 | 338 | if (p == NULL) { 339 | fprintf(stderr, "server: failed to bind\n"); 340 | return 2; 341 | } 342 | 343 | freeaddrinfo(servinfo); // all done with this structure 344 | 345 | if (listen(sockfd, 5) == -1) { 346 | perror("listen"); 347 | return -1; 348 | } 349 | if (server->debug_level) 350 | printf("server: waiting for connections...\n"); 351 | 352 | ev_io_init(&server->listen_watcher, accept_cb, sockfd, EV_READ); 353 | server->listen_watcher.data = server; 354 | ev_io_start(server->loop, &server->listen_watcher); 355 | return 0; 356 | } 357 | 358 | // Make the code work with both the old (ev_loop/ev_unloop) 359 | // and new (ev_run/ev_break) versions of libev. 360 | #ifdef EVUNLOOP_ALL 361 | #define EV_RUN ev_loop 362 | #define EV_BREAK ev_unloop 363 | #define EVBREAK_ALL EVUNLOOP_ALL 364 | #else 365 | #define EV_RUN ev_run 366 | #define EV_BREAK ev_break 367 | #endif 368 | 369 | void jrpc_server_run(struct jrpc_server *server){ 370 | EV_RUN(server->loop, 0); 371 | } 372 | 373 | int jrpc_server_stop(struct jrpc_server *server) { 374 | EV_BREAK(server->loop, EVBREAK_ALL); 375 | return 0; 376 | } 377 | 378 | void jrpc_server_destroy(struct jrpc_server *server){ 379 | /* Don't destroy server */ 380 | int i; 381 | for (i = 0; i < server->procedure_count; i++){ 382 | jrpc_procedure_destroy( &(server->procedures[i]) ); 383 | } 384 | free(server->procedures); 385 | } 386 | 387 | static void jrpc_procedure_destroy(struct jrpc_procedure *procedure){ 388 | if (procedure->name){ 389 | free(procedure->name); 390 | procedure->name = NULL; 391 | } 392 | if (procedure->data){ 393 | free(procedure->data); 394 | procedure->data = NULL; 395 | } 396 | } 397 | 398 | int jrpc_register_procedure(struct jrpc_server *server, 399 | jrpc_function function_pointer, char *name, void * data) { 400 | int i = server->procedure_count++; 401 | if (!server->procedures) 402 | server->procedures = malloc(sizeof(struct jrpc_procedure)); 403 | else { 404 | struct jrpc_procedure * ptr = realloc(server->procedures, 405 | sizeof(struct jrpc_procedure) * server->procedure_count); 406 | if (!ptr) 407 | return -1; 408 | server->procedures = ptr; 409 | 410 | } 411 | if ((server->procedures[i].name = strdup(name)) == NULL) 412 | return -1; 413 | server->procedures[i].function = function_pointer; 414 | server->procedures[i].data = data; 415 | return 0; 416 | } 417 | 418 | int jrpc_deregister_procedure(struct jrpc_server *server, char *name) { 419 | /* Search the procedure to deregister */ 420 | int i; 421 | int found = 0; 422 | if (server->procedures){ 423 | for (i = 0; i < server->procedure_count; i++){ 424 | if (found) 425 | server->procedures[i-1] = server->procedures[i]; 426 | else if(!strcmp(name, server->procedures[i].name)){ 427 | found = 1; 428 | jrpc_procedure_destroy( &(server->procedures[i]) ); 429 | } 430 | } 431 | if (found){ 432 | server->procedure_count--; 433 | if (server->procedure_count){ 434 | struct jrpc_procedure * ptr = realloc(server->procedures, 435 | sizeof(struct jrpc_procedure) * server->procedure_count); 436 | if (!ptr){ 437 | perror("realloc"); 438 | return -1; 439 | } 440 | server->procedures = ptr; 441 | }else{ 442 | server->procedures = NULL; 443 | } 444 | } 445 | } else { 446 | fprintf(stderr, "server : procedure '%s' not found\n", name); 447 | return -1; 448 | } 449 | return 0; 450 | } 451 | --------------------------------------------------------------------------------