ANSI C中的超輕量級JSON解析器
JSON(JavaScript物件表示法)是一種輕量級的資料交換格式。人類易於閱讀和書寫。機器很容易解析和生成。它基於JavaScript程式語言標準ECMA-262第三版(1999年12月)的子集 。JSON是一種完全獨立於語言的文字格式,但是使用C語言家族(包括C,C ++,C#,Java,JavaScript,Perl,Python等)的程式設計師熟悉的約定。這些屬性使JSON成為理想的資料交換語言。
cJSON旨在成為您可以完成工作的最簡單的解析器。它是資源只有一個C的標頭檔案和C檔案,所以方便移植。它可以為你各種需要的json字串處理,包括打包、解析、修改、刪除、新增等。在這裡將一探究竟。
在這裡將著重敘述json的打包和解析,更多處理玩法,見文章末尾連結。
開始cJSON
cJSON合併到您的專案
因為整個庫只有一個C檔案和一個標頭檔案,所以您只需複製cJSON.h並複製cJSON.c到專案源並開始使用它。
cJSON用ANSI C(C89)編寫,以便支援儘可能多的平臺和編譯器。
下載:
https://github.com/DaveGamble/cJSON/releases
Cjson結構體
/* The cJSON structure: */ typedef struct cJSON { struct cJSON *next; struct cJSON *prev; struct cJSON *child; int type; char *valuestring; int valueint; double valuedouble; char *string; } cJSON;
結構體項解析:
next 和prev :Cjson結構體作為一個雙向連表的環,可以通過 next 和prev 指標進行連表遍歷
child:可以是cJSON_Array、cJSON_Object型別資料
type:當前項的型別
valuestring:內容儲存,當型別是cJSON_String和cJSON_Raw
valueint:內容儲存,整型,可以是cJSON_False、cJSON_True資料
valuedouble:內容儲存,浮點型,當型別是cJSON_Number
string:鍵名
資料型別
l cJSON_Invalid表示一個不包含任何值的無效專案。如果將專案設定為全零位元組,則將自動具有此型別。
l cJSON_False表示一個false布林值。您也可以使用來檢查布林值cJSON_IsBool
l cJSON_True表示一個true布林值。您也可以使用來檢查布林值cJSON_IsBool
l cJSON_NULL表示一個null值
l cJSON_Number 表示一個數字值。該值儲存為double in valuedouble和in valueint。如果數字超出整數範圍,INT_MAX或INT_MIN用於valueint
l cJSON_String表示一個字串值。它以零終止字串的形式儲存在中valuestring
l cJSON_Array表示一個陣列值。這是通過指向表示陣列中值child的cJSON專案的連結列表來實現的。使用next和將元素連結在一起prev,其中第一個元素具有prev.next == NULL和最後一個元素next == NULL
l cJSON_Object 表示一個物件值。物件的儲存方式與陣列相同,唯一的區別是物件中的項將其鍵儲存在中string
l cJSON_Raw表示以JSON字元儲存的零終止形式的任何JSON valuestring。例如,可以使用它來避免一遍又一遍地列印相同的靜態JSON以節省效能。解析時,cJSON永遠不會建立此型別。另請注意,cJSON不會檢查其是否為有效JSON。
型別
#define cJSON_Invalid (0) #define cJSON_False (1 << 0) #define cJSON_True (1 << 1) #define cJSON_NULL (1 << 2) #define cJSON_Number (1 << 3) #define cJSON_String (1 << 4) #define cJSON_Array (1 << 5) #define cJSON_Object (1 << 6) #define cJSON_Raw (1 << 7) /* raw json */
型別判斷
cJSON_IsInvalid(const cJSON * const item); cJSON_IsFalse(const cJSON * const item); cJSON_IsTrue(const cJSON * const item); cJSON_IsBool(const cJSON * const item); cJSON_IsNull(const cJSON * const item); cJSON_IsNumber(const cJSON * const item); cJSON_IsString(const cJSON * const item); cJSON_IsArray(const cJSON * const item); cJSON_IsObject(const cJSON * const item); cJSON_IsRaw(const cJSON * const item);
注意
建立cjson物件後,處理完需要進行記憶體釋放:
如果是cjson裡的物件,請使用cJSON_Delete()
如果不是物件:cJSON_free()或free()
零字元
cJSON不支援包含零字元'\0'或的字串\u0000。對於當前的API,這是不可能的,因為字串以零結尾。
字元編碼
cJSON僅支援UTF-8編碼的輸入。但是在大多數情況下,它不會拒絕無效的UTF-8作為輸入,而只是將其原樣傳播。只要輸入不包含無效的UTF-8,輸出將始終是有效的UTF-8。
C標準
cJSON用ANSI C(或C89,C90)編寫。如果您的編譯器或C庫未遵循此標準,則不能保證正確的行為。
注意:ANSI C不是C ++,因此不應使用C ++編譯器進行編譯。您可以使用C編譯器對其進行編譯,然後將其與C ++程式碼連結。儘管可以使用C ++編譯器進行編譯,但是不能保證正確的行為。
浮點數字
double除IEEE754雙精度浮點數外,cJSON不正式支援任何實現。它可能仍然可以與其他實現一起使用,但是這些實現的錯誤將被視為無效。
目前,cJSON支援的浮點文字的最大長度為63個字元。
陣列和物件的深層巢狀
cJSON不支援巢狀太深的陣列和物件,因為這會導致堆疊溢位。為了防止這種CJSON_NESTING_LIMIT情況,預設情況下,cJSON將深度限制為1000,但是可以在編譯時進行更改。
格式化輸出
按標準的格式輸出json字串,輸出完後一定要記得釋放記憶體
程式碼
1 #include <stdio.h> 2 #include "cJSON.h" 3 #include "cJSON.c" 4 void main(){ 5 //待解析字串 6 char *json_str="{\"key1\":\"dongxiaodong\",\"key2\":1998,\"key3\":55778}"; 7 8 //輸出原字串 9 printf("原字串:%s\r\n",json_str); 10 11 //解析成json物件 12 cJSON * json_obj = cJSON_Parse(json_str); 13 14 //格式輸出 15 char *json_print_str=NULL; 16 json_print_str=cJSON_Print(json_obj); 17 printf("\r\n輸出內容:\r\n\r\n%s\r\n",json_print_str); 18 19 //釋放資源 20 free(json_print_str); 21 22 //釋放資源 23 cJSON_Delete(json_obj); 24 }
json打包
cJSON_CreateObject函式可建立一個根資料項,在此之後就可以新增各種資料型別的子節點了,使用完成後需要通過cJSON_Delete()釋放記憶體。
建立一層級的json
程式碼:
1 #include <stdio.h> 2 #include "cJSON.h" 3 #include "cJSON.c" 4 void main(){ 5 cJSON *root_obj = NULL;//根,json物件 6 char *out_str = NULL; //輸出結果 7 root_obj =cJSON_CreateObject();//建立 8 //新增一個字串,引數(根物件,鍵,值) 9 cJSON_AddStringToObject(root_obj, "key1", "dongxiaodong"); 10 //新增一個整型,引數(根物件,鍵,值) 11 cJSON_AddNumberToObject(root_obj, "key2",1998); 12 //新增一個浮點型,引數(根物件,鍵,值) 13 cJSON_AddNumberToObject(root_obj, "key3",22.33); 14 //新增一個bool型別,引數(根物件,鍵,值) 15 //bool值可以是0/1或false/true 16 cJSON_AddBoolToObject(root_obj, "key4",0); 17 //將json物件打包成字串 18 out_str = cJSON_PrintUnformatted(root_obj); 19 //銷燬json物件,釋放記憶體 20 cJSON_Delete(root_obj); 21 //輸出值:{"key1":"dongxiaodong","key2":1998,"key3":22.33,"key4":false} 22 printf("%s",out_str); 23 }
型別建立函式還有:
cJSON_AddNullToObject(cJSON * const object, const char * const name);
cJSON_AddTrueToObject(cJSON * const object, const char * const name);
cJSON_AddFalseToObject(cJSON * const object, const char * const name);
cJSON_AddBoolToObject(cJSON * const object, const char * const name, const cJSON_bool boolean);
cJSON_AddNumberToObject(cJSON * const object, const char * const name, const double number);
cJSON_AddStringToObject(cJSON * const object, const char * const name, const char * const string);
cJSON_AddRawToObject(cJSON * const object, const char * const name, const char * const raw);
cJSON_AddObjectToObject(cJSON * const object, const char * const name);
cJSON_AddArrayToObject(cJSON * const object, const char * const name);
建立多層級的json
程式碼:
1 #include <stdio.h> 2 #include "cJSON.h" 3 #include "cJSON.c" 4 void main(){ 5 cJSON *root_obj = NULL;//根,json物件 6 cJSON *item_obj = NULL;//二級json物件 7 char *out_str = NULL; //輸出結果 8 9 root_obj =cJSON_CreateObject();//建立 10 //新增一個字串,引數(根物件,鍵,值) 11 cJSON_AddStringToObject(root_obj, "key1", "dongxiaodong"); 12 //新增一個整型,引數(根物件,鍵,值) 13 cJSON_AddNumberToObject(root_obj, "key2",1998); 14 15 //建立一個子json物件 16 item_obj= cJSON_AddObjectToObject(root_obj,"myson"); 17 //向孩子物件中新增內容 18 cJSON_AddStringToObject(item_obj, "sonkey1", "東小東"); 19 cJSON_AddNumberToObject(item_obj, "sonkey2",2020); 20 21 //將json物件打包成字串 22 out_str = cJSON_PrintUnformatted(root_obj); 23 //銷燬json物件,釋放記憶體 24 cJSON_Delete(root_obj); 25 //輸出值:{"key1":"dongxiaodong","key2":1998,"myson":{"sonkey1":"東小東","sonkey2":2020}} 26 printf("%s",out_str); 27 }
建立多層json(陣列形式)
程式碼
1 #include <stdio.h> 2 #include "cJSON.h" 3 #include "cJSON.c" 4 void main(){ 5 cJSON *root_obj = NULL;//根,json物件 6 cJSON *item_obj = NULL;//陣列物件 7 char *out_str = NULL; //輸出結果 8 9 root_obj =cJSON_CreateObject();//建立 10 //新增一個字串,引數(根物件,鍵,值) 11 cJSON_AddStringToObject(root_obj, "key1", "dongxiaodong"); 12 //新增一個整型,引數(根物件,鍵,值) 13 cJSON_AddNumberToObject(root_obj, "key2",1998); 14 15 //建立一個子陣列物件 16 item_obj= cJSON_AddArrayToObject(root_obj,"myson"); 17 //向陣列物件中新增內容 18 cJSON_AddItemToArray(item_obj,cJSON_CreateTrue()); 19 cJSON_AddItemToArray(item_obj,cJSON_CreateNumber(22)); 20 21 //將json物件打包成字串 22 out_str = cJSON_PrintUnformatted(root_obj); 23 //銷燬json物件,釋放記憶體 24 cJSON_Delete(root_obj); 25 //輸出值:{"key1":"dongxiaodong","key2":1998,"myson":[true,22]} 26 printf("%s",out_str); 27 }
建立的物件還可以是下面這些
cJSON_CreateNull(void);
cJSON_CreateTrue(void);
cJSON_CreateFalse(void);
cJSON_CreateBool(cJSON_bool boolean);
cJSON_CreateNumber(double num);
cJSON_CreateString(const char *string);
cJSON_CreateRaw(const char *raw);
cJSON_CreateArray(void);
cJSON_CreateObject(void);
建立混合json
程式碼
1 #include <stdio.h> 2 #include "cJSON.h" 3 #include "cJSON.c" 4 void main(){ 5 cJSON *root_obj = NULL;//根,json物件 6 cJSON *son_obj=NULL; 7 cJSON *item_obj = NULL;//陣列物件 8 char *out_str = NULL; //輸出結果 9 10 //根物件 11 root_obj =cJSON_CreateObject();//建立 12 //新增一個字串,引數(根物件,鍵,值) 13 cJSON_AddStringToObject(root_obj, "key1", "dongxiaodong"); 14 //新增一個整型,引數(根物件,鍵,值) 15 cJSON_AddNumberToObject(root_obj, "key2",1998); 16 17 //建立一個子陣列物件 18 item_obj= cJSON_AddArrayToObject(root_obj,"myson"); 19 //向陣列物件中新增內容 20 cJSON_AddItemToArray(item_obj,cJSON_CreateTrue()); 21 cJSON_AddItemToArray(item_obj,cJSON_CreateNumber(22)); 22 23 //子物件 24 son_obj =cJSON_CreateObject();//建立 25 //新增一個字串,引數(根物件,鍵,值) 26 cJSON_AddStringToObject(son_obj, "son1", "dongxiaodong"); 27 //新增一個整型,引數(根物件,鍵,值) 28 cJSON_AddNumberToObject(son_obj, "son2",1998); 29 cJSON_AddItemToArray(item_obj,son_obj); 30 31 //將json物件打包成字串 32 out_str = cJSON_PrintUnformatted(root_obj); 33 //銷燬json物件,釋放記憶體 34 cJSON_Delete(root_obj); 35 //輸出值:{"key1":"dongxiaodong","key2":1998,"myson":[true,22,{"son1":"dongxiaodong","son2":1998}]} 36 printf("%s",out_str); 37 }
json解析
解析一層級的json
程式碼:
1 #include <stdio.h> 2 #include "cJSON.h" 3 #include "cJSON.c" 4 void main(){ 5 //待解析字串 6 char *json_str="{\"key1\":\"dongxiaodong\",\"key2\":1998,\"key3\":22.33,\"key4\":true}"; 7 //解析成json物件 8 cJSON * json_obj = cJSON_Parse(json_str); 9 10 //項儲存 11 cJSON *item=NULL; 12 13 //輸出原字串 14 printf("原字串:%s\r\n",json_str); 15 16 //獲取string型別 17 item=cJSON_GetObjectItem(json_obj,"key1"); 18 printf("\r\nkey1:%s\r\n",item->valuestring); 19 cJSON_Delete(item);//釋放資源 20 21 //獲取數字 22 item=cJSON_GetObjectItem(json_obj,"key2"); 23 printf("\r\nkey2:%d\r\n",item->valueint); 24 cJSON_Delete(item);//釋放資源 25 26 //獲取數字 27 item=cJSON_GetObjectItem(json_obj,"key3"); 28 printf("\r\nkey3:%f\r\n",item->valuedouble); 29 cJSON_Delete(item);//釋放資源 30 31 //獲取bool 32 item=cJSON_GetObjectItem(json_obj,"key4"); 33 printf("\r\nkey4:%d\r\n",item->valueint); 34 cJSON_Delete(item);//釋放資源 35 36 //是否資源 37 cJSON_Delete(json_obj); 38 }
解析多層級的json
程式碼
1 #include <stdio.h> 2 #include "cJSON.h" 3 #include "cJSON.c" 4 void main(){ 5 //待解析字串 6 char *json_str="{\"key1\":\"dongxiaodong\",\"key2\":1998,\"myson\":{\"sonkey1\":\"東小東\",\"sonkey2\":2020}}"; 7 //解析成json物件 8 cJSON * json_obj = cJSON_Parse(json_str); 9 10 //項儲存 11 cJSON *item=NULL; 12 //內部項儲存 13 cJSON * item_item=NULL; 14 15 //輸出原字串 16 printf("原字串:%s\r\n",json_str); 17 18 //獲取string型別 19 item=cJSON_GetObjectItem(json_obj,"key1"); 20 printf("\r\nkey1:%s\r\n",item->valuestring); 21 cJSON_Delete(item);//釋放資源 22 23 //獲取數字 24 item=cJSON_GetObjectItem(json_obj,"key2"); 25 printf("\r\nkey2:%d\r\n",item->valueint); 26 cJSON_Delete(item);//釋放資源 27 28 //子串 29 item=cJSON_GetObjectItem(json_obj,"myson"); 30 item_item=cJSON_GetObjectItem(item,"sonkey1"); 31 printf("\r\nmyson(sonkey1):%s\r\n",item_item->valuestring); 32 cJSON_Delete(item_item);//釋放資源 33 34 item_item=cJSON_GetObjectItem(item,"sonkey2"); 35 printf("\r\nmyson(sonkey2):%d\r\n",item_item->valueint); 36 cJSON_Delete(item_item);//釋放資源 37 38 cJSON_Delete(item);//釋放資源 39 40 //釋放資源 41 cJSON_Delete(json_obj); 42 }
解析多層json(陣列形式)
程式碼
1 #include <stdio.h> 2 #include "cJSON.h" 3 #include "cJSON.c" 4 void main(){ 5 //待解析字串 6 char *json_str="{\"key1\":\"dongxiaodong\",\"key2\":1998,\"myson\":[true,113]}"; 7 //解析成json物件 8 cJSON * json_obj = cJSON_Parse(json_str); 9 10 //項儲存 11 cJSON *item=NULL; 12 //內部項儲存 13 cJSON * item_item=NULL; 14 15 //輸出原字串 16 printf("原字串:%s\r\n",json_str); 17 18 //獲取string型別 19 item=cJSON_GetObjectItem(json_obj,"key1"); 20 printf("\r\nkey1:%s\r\n",item->valuestring); 21 cJSON_Delete(item);//釋放資源 22 23 //獲取數字 24 item=cJSON_GetObjectItem(json_obj,"key2"); 25 printf("\r\nkey2:%d\r\n",item->valueint); 26 cJSON_Delete(item);//釋放資源 27 28 //獲取子串 29 item=cJSON_GetObjectItem(json_obj,"myson"); 30 31 //輸出陣列大小 32 printf("\r\n陣列大小:%d\r\n",cJSON_GetArraySize(item)); 33 34 //輸出項1內容 35 item_item=cJSON_GetArrayItem(item,0); 36 printf("\r\nmyson(0):%d\r\n",item_item->valueint); 37 //cJSON_Delete(item_item);//釋放資源 38 39 //輸出項2內容 40 item_item=cJSON_GetArrayItem(item,1); 41 printf("\r\nmyson(1):%d\r\n",item_item->valueint); 42 cJSON_Delete(item_item);//釋放資源 43 44 cJSON_Delete(item);//釋放資源 45 46 //釋放資源 47 cJSON_Delete(json_obj); 48 }
解析混合json
程式碼
1 #include <stdio.h> 2 #include "cJSON.h" 3 #include "cJSON.c" 4 void main(){ 5 //待解析字串 6 char *json_str="{\"key1\":\"dongxiaodong\",\"key2\":1998,\"myson\":[true,22,{\"son1\":\"dongxiaodong\",\"son2\":1998}]}"; 7 //解析成json物件 8 cJSON * json_obj = cJSON_Parse(json_str); 9 10 //項儲存 11 cJSON *item=NULL; 12 //內部項儲存 13 cJSON * item_item=NULL; 14 15 //輸出原字串 16 printf("原字串:%s\r\n",json_str); 17 18 //獲取string型別 19 item=cJSON_GetObjectItem(json_obj,"key1"); 20 printf("\r\nkey1:%s\r\n",item->valuestring); 21 cJSON_Delete(item);//釋放資源 22 23 //獲取數字 24 item=cJSON_GetObjectItem(json_obj,"key2"); 25 printf("\r\nkey2:%d\r\n",item->valueint); 26 cJSON_Delete(item);//釋放資源 27 28 //獲取子串 29 item=cJSON_GetObjectItem(json_obj,"myson"); 30 31 //輸出陣列大小 32 printf("\r\n陣列大小:%d\r\n",cJSON_GetArraySize(item)); 33 34 //輸出項1內容 35 item_item=cJSON_GetArrayItem(item,0); 36 printf("\r\nmyson(0):%d\r\n",item_item->valueint); 37 //cJSON_Delete(item_item);//釋放資源 38 39 //輸出項2內容 40 item_item=cJSON_GetArrayItem(item,1); 41 printf("\r\nmyson(1):%d\r\n",item_item->valueint); 42 cJSON_Delete(item_item);//釋放資源 43 44 //項3內容 45 item_item=cJSON_GetArrayItem(item,2); 46 cJSON *item_item_son=NULL; 47 48 item_item_son =cJSON_GetObjectItem(item_item,"son1"); 49 printf("\r\nmyson(2)(son1):%s\r\n",item_item_son->valuestring); 50 cJSON_Delete(item_item_son);//釋放資源 51 52 item_item_son =cJSON_GetObjectItem(item_item,"son2"); 53 printf("\r\nmyson(2)(son2):%d\r\n",item_item_son->valueint); 54 cJSON_Delete(item_item_son);//釋放資源 55 cJSON_Delete(item_item);//釋放資源 56 57 cJSON_Delete(item);//釋放資源 58 59 //釋放資源 60 cJSON_Delete(json_obj); 61 }
附件:
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 13 85 86 #include <stddef.h> 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(cJSON *item); 180 CJSON_PUBLIC(double) cJSON_GetNumberValue(cJSON *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 adress 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 /* Macro for iterating over an array or object */ 283 #define cJSON_ArrayForEach(element, array) for(element = (array != NULL) ? (array)->child : NULL; element != NULL; element = element->next) 284 285 /* malloc/free objects using the malloc/free functions that have been set with cJSON_InitHooks */ 286 CJSON_PUBLIC(void *) cJSON_malloc(size_t size); 287 CJSON_PUBLIC(void) cJSON_free(void *object); 288 289 #ifdef __cplusplus 290 } 291 #endif 292 293 #endif
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 <string.h> 41 #include <stdio.h> 42 #include <math.h> 43 #include <stdlib.h> 44 #include <limits.h> 45 #include <ctype.h> 46 #include <float.h> 47 48 #ifdef ENABLE_LOCALES 49 #include <locale.h> 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 #define NAN 0.0/0.0 82 #endif 83 84 typedef struct { 85 const unsigned char *json; 86 size_t position; 87 } error; 88 static error global_error = { NULL, 0 }; 89 90 CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void) 91 { 92 return (const char*) (global_error.json + global_error.position); 93 } 94 95 CJSON_PUBLIC(char *) cJSON_GetStringValue(cJSON *item) 96 { 97 if (!cJSON_IsString(item)) 98 { 99 return NULL; 100 } 101 102 return item->valuestring; 103 } 104 105 CJSON_PUBLIC(double) cJSON_GetNumberValue(cJSON *item) 106 { 107 if (!cJSON_IsNumber(item)) 108 { 109 return NAN; 110 } 111 112 return item->valuedouble; 113 } 114 115 /* This is a safeguard to prevent copy-pasters from using incompatible C and header files */ 116 #if (CJSON_VERSION_MAJOR != 1) || (CJSON_VERSION_MINOR != 7) || (CJSON_VERSION_PATCH != 13) 117 #error cJSON.h and cJSON.c have different versions. Make sure that both have the same. 118 #endif 119 120 CJSON_PUBLIC(const char*) cJSON_Version(void) 121 { 122 static char version[15]; 123 sprintf(version, "%i.%i.%i", CJSON_VERSION_MAJOR, CJSON_VERSION_MINOR, CJSON_VERSION_PATCH); 124 125 return version; 126 } 127 128 /* Case insensitive string comparison, doesn't consider two NULL pointers equal though */ 129 static int case_insensitive_strcmp(const unsigned char *string1, const unsigned char *string2) 130 { 131 if ((string1 == NULL) || (string2 == NULL)) 132 { 133 return 1; 134 } 135 136 if (string1 == string2) 137 { 138 return 0; 139 } 140 141 for(; tolower(*string1) == tolower(*string2); (void)string1++, string2++) 142 { 143 if (*string1 == '\0') 144 { 145 return 0; 146 } 147 } 148 149 return tolower(*string1) - tolower(*string2); 150 } 151 152 typedef struct internal_hooks 153 { 154 void *(CJSON_CDECL *allocate)(size_t size); 155 void (CJSON_CDECL *deallocate)(void *pointer); 156 void *(CJSON_CDECL *reallocate)(void *pointer, size_t size); 157 } internal_hooks; 158 159 #if defined(_MSC_VER) 160 /* work around MSVC error C2322: '...' address of dllimport '...' is not static */ 161 static void * CJSON_CDECL internal_malloc(size_t size) 162 { 163 return malloc(size); 164 } 165 static void CJSON_CDECL internal_free(void *pointer) 166 { 167 free(pointer); 168 } 169 static void * CJSON_CDECL internal_realloc(void *pointer, size_t size) 170 { 171 return realloc(pointer, size); 172 } 173 #else 174 #define internal_malloc malloc 175 #define internal_free free 176 #define internal_realloc realloc 177 #endif 178 179 /* strlen of character literals resolved at compile time */ 180 #define static_strlen(string_literal) (sizeof(string_literal) - sizeof("")) 181 182 static internal_hooks global_hooks = { internal_malloc, internal_free, internal_realloc }; 183 184 static unsigned char* cJSON_strdup(const unsigned char* string, const internal_hooks * const hooks) 185 { 186 size_t length = 0; 187 unsigned char *copy = NULL; 188 189 if (string == NULL) 190 { 191 return NULL; 192 } 193 194 length = strlen((const char*)string) + sizeof(""); 195 copy = (unsigned char*)hooks->allocate(length); 196 if (copy == NULL) 197 { 198 return NULL; 199 } 200 memcpy(copy, string, length); 201 202 return copy; 203 } 204 205 CJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks* hooks) 206 { 207 if (hooks == NULL) 208 { 209 /* Reset hooks */ 210 global_hooks.allocate = malloc; 211 global_hooks.deallocate = free; 212 global_hooks.reallocate = realloc; 213 return; 214 } 215 216 global_hooks.allocate = malloc; 217 if (hooks->malloc_fn != NULL) 218 { 219 global_hooks.allocate = hooks->malloc_fn; 220 } 221 222 global_hooks.deallocate = free; 223 if (hooks->free_fn != NULL) 224 { 225 global_hooks.deallocate = hooks->free_fn; 226 } 227 228 /* use realloc only if both free and malloc are used */ 229 global_hooks.reallocate = NULL; 230 if ((global_hooks.allocate == malloc) && (global_hooks.deallocate == free)) 231 { 232 global_hooks.reallocate = realloc; 233 } 234 } 235 236 /* Internal constructor. */ 237 static cJSON *cJSON_New_Item(const internal_hooks * const hooks) 238 { 239 cJSON* node = (cJSON*)hooks->allocate(sizeof(cJSON)); 240 if (node) 241 { 242 memset(node, '\0', sizeof(cJSON)); 243 } 244 245 return node; 246 } 247 248 /* Delete a cJSON structure. */ 249 CJSON_PUBLIC(void) cJSON_Delete(cJSON *item) 250 { 251 cJSON *next = NULL; 252 while (item != NULL) 253 { 254 next = item->next; 255 if (!(item->type & cJSON_IsReference) && (item->child != NULL)) 256 { 257 cJSON_Delete(item->child); 258 } 259 if (!(item->type & cJSON_IsReference) && (item->valuestring != NULL)) 260 { 261 global_hooks.deallocate(item->valuestring); 262 } 263 if (!(item->type & cJSON_StringIsConst) && (item->string != NULL)) 264 { 265 global_hooks.deallocate(item->string); 266 } 267 global_hooks.deallocate(item); 268 item = next; 269 } 270 } 271 272 /* get the decimal point character of the current locale */ 273 static unsigned char get_decimal_point(void) 274 { 275 #ifdef ENABLE_LOCALES 276 struct lconv *lconv = localeconv(); 277 return (unsigned char) lconv->decimal_point[0]; 278 #else 279 return '.'; 280 #endif 281 } 282 283 typedef struct 284 { 285 const unsigned char *content; 286 size_t length; 287 size_t offset; 288 size_t depth; /* How deeply nested (in arrays/objects) is the input at the current offset. */ 289 internal_hooks hooks; 290 } parse_buffer; 291 292 /* check if the given size is left to read in a given parse buffer (starting with 1) */ 293 #define can_read(buffer, size) ((buffer != NULL) && (((buffer)->offset + size) <= (buffer)->length)) 294 /* check if the buffer can be accessed at the given index (starting with 0) */ 295 #define can_access_at_index(buffer, index) ((buffer != NULL) && (((buffer)->offset + index) < (buffer)->length)) 296 #define cannot_access_at_index(buffer, index) (!can_access_at_index(buffer, index)) 297 /* get a pointer to the buffer at the position */ 298 #define buffer_at_offset(buffer) ((buffer)->content + (buffer)->offset) 299 300 /* Parse the input text to generate a number, and populate the result into item. */ 301 static cJSON_bool parse_number(cJSON * const item, parse_buffer * const input_buffer) 302 { 303 double number = 0; 304 unsigned char *after_end = NULL; 305 unsigned char number_c_string[64]; 306 unsigned char decimal_point = get_decimal_point(); 307 size_t i = 0; 308 309 if ((input_buffer == NULL) || (input_buffer->content == NULL)) 310 { 311 return false; 312 } 313 314 /* copy the number into a temporary buffer and replace '.' with the decimal point 315 * of the current locale (for strtod) 316 * This also takes care of '\0' not necessarily being available for marking the end of the input */ 317 for (i = 0; (i < (sizeof(number_c_string) - 1)) && can_access_at_index(input_buffer, i); i++) 318 { 319 switch (buffer_at_offset(input_buffer)[i]) 320 { 321 case '0': 322 case '1': 323 case '2': 324 case '3': 325 case '4': 326 case '5': 327 case '6': 328 case '7': 329 case '8': 330 case '9': 331 case '+': 332 case '-': 333 case 'e': 334 case 'E': 335 number_c_string[i] = buffer_at_offset(input_buffer)[i]; 336 break; 337 338 case '.': 339 number_c_string[i] = decimal_point; 340 break; 341 342 default: 343 goto loop_end; 344 } 345 } 346 loop_end: 347 number_c_string[i] = '\0'; 348 349 number = strtod((const char*)number_c_string, (char**)&after_end); 350 if (number_c_string == after_end) 351 { 352 return false; /* parse_error */ 353 } 354 355 item->valuedouble = number; 356 357 /* use saturation in case of overflow */ 358 if (number >= INT_MAX) 359 { 360 item->valueint = INT_MAX; 361 } 362 else if (number <= (double)INT_MIN) 363 { 364 item->valueint = INT_MIN; 365 } 366 else 367 { 368 item->valueint = (int)number; 369 } 370 371 item->type = cJSON_Number; 372 373 input_buffer->offset += (size_t)(after_end - number_c_string); 374 return true; 375 } 376 377 /* don't ask me, but the original cJSON_SetNumberValue returns an integer or double */ 378 CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number) 379 { 380 if (number >= INT_MAX) 381 { 382 object->valueint = INT_MAX; 383 } 384 else if (number <= (double)INT_MIN) 385 { 386 object->valueint = INT_MIN; 387 } 388 else 389 { 390 object->valueint = (int)number; 391 } 392 393 return object->valuedouble = number; 394 } 395 396 CJSON_PUBLIC(char*) cJSON_SetValuestring(cJSON *object, const char *valuestring) 397 { 398 char *copy = NULL; 399 /* if object's type is not cJSON_String or is cJSON_IsReference, it should not set valuestring */ 400 if (!(object->type & cJSON_String) || (object->type & cJSON_IsReference)) 401 { 402 return NULL; 403 } 404 if (strlen(valuestring) <= strlen(object->valuestring)) 405 { 406 strcpy(object->valuestring, valuestring); 407 return object->valuestring; 408 } 409 copy = (char*) cJSON_strdup((const unsigned char*)valuestring, &global_hooks); 410 if (copy == NULL) 411 { 412 return NULL; 413 } 414 if (object->valuestring != NULL) 415 { 416 cJSON_free(object->valuestring); 417 } 418 object->valuestring = copy; 419 420 return copy; 421 } 422 423 typedef struct 424 { 425 unsigned char *buffer; 426 size_t length; 427 size_t offset; 428 size_t depth; /* current nesting depth (for formatted printing) */ 429 cJSON_bool noalloc; 430 cJSON_bool format; /* is this print a formatted print */ 431 internal_hooks hooks; 432 } printbuffer; 433 434 /* realloc printbuffer if necessary to have at least "needed" bytes more */ 435 static unsigned char* ensure(printbuffer * const p, size_t needed) 436 { 437 unsigned char *newbuffer = NULL; 438 size_t newsize = 0; 439 440 if ((p == NULL) || (p->buffer == NULL)) 441 { 442 return NULL; 443 } 444 445 if ((p->length > 0) && (p->offset >= p->length)) 446 { 447 /* make sure that offset is valid */ 448 return NULL; 449 } 450 451 if (needed > INT_MAX) 452 { 453 /* sizes bigger than INT_MAX are currently not supported */ 454 return NULL; 455 } 456 457 needed += p->offset + 1; 458 if (needed <= p->length) 459 { 460 return p->buffer + p->offset; 461 } 462 463 if (p->noalloc) { 464 return NULL; 465 } 466 467 /* calculate new buffer size */ 468 if (needed > (INT_MAX / 2)) 469 { 470 /* overflow of int, use INT_MAX if possible */ 471 if (needed <= INT_MAX) 472 { 473 newsize = INT_MAX; 474 } 475 else 476 { 477 return NULL; 478 } 479 } 480 else 481 { 482 newsize = needed * 2; 483 } 484 485 if (p->hooks.reallocate != NULL) 486 { 487 /* reallocate with realloc if available */ 488 newbuffer = (unsigned char*)p->hooks.reallocate(p->buffer, newsize); 489 if (newbuffer == NULL) 490 { 491 p->hooks.deallocate(p->buffer); 492 p->length = 0; 493 p->buffer = NULL; 494 495 return NULL; 496 } 497 } 498 else 499 { 500 /* otherwise reallocate manually */ 501 newbuffer = (unsigned char*)p->hooks.allocate(newsize); 502 if (!newbuffer) 503 { 504 p->hooks.deallocate(p->buffer); 505 p->length = 0; 506 p->buffer = NULL; 507 508 return NULL; 509 } 510 if (newbuffer) 511 { 512 memcpy(newbuffer, p->buffer, p->offset + 1); 513 } 514 p->hooks.deallocate(p->buffer); 515 } 516 p->length = newsize; 517 p->buffer = newbuffer; 518 519 return newbuffer + p->offset; 520 } 521 522 /* calculate the new length of the string in a printbuffer and update the offset */ 523 static void update_offset(printbuffer * const buffer) 524 { 525 const unsigned char *buffer_pointer = NULL; 526 if ((buffer == NULL) || (buffer->buffer == NULL)) 527 { 528 return; 529 } 530 buffer_pointer = buffer->buffer + buffer->offset; 531 532 buffer->offset += strlen((const char*)buffer_pointer); 533 } 534 535 /* securely comparison of floating-point variables */ 536 static cJSON_bool compare_double(double a, double b) 537 { 538 double maxVal = fabs(a) > fabs(b) ? fabs(a) : fabs(b); 539 return (fabs(a - b) <= maxVal * DBL_EPSILON); 540 } 541 542 /* Render the number nicely from the given item into a string. */ 543 static cJSON_bool print_number(const cJSON * const item, printbuffer * const output_buffer) 544 { 545 unsigned char *output_pointer = NULL; 546 double d = item->valuedouble; 547 int length = 0; 548 size_t i = 0; 549 unsigned char number_buffer[26] = {0}; /* temporary buffer to print the number into */ 550 unsigned char decimal_point = get_decimal_point(); 551 double test = 0.0; 552 553 if (output_buffer == NULL) 554 { 555 return false; 556 } 557 558 /* This checks for NaN and Infinity */ 559 if (isnan(d) || isinf(d)) 560 { 561 length = sprintf((char*)number_buffer, "null"); 562 } 563 else 564 { 565 /* Try 15 decimal places of precision to avoid nonsignificant nonzero digits */ 566 length = sprintf((char*)number_buffer, "%1.15g", d); 567 568 /* Check whether the original double can be recovered */ 569 if ((sscanf((char*)number_buffer, "%lg", &test) != 1) || !compare_double((double)test, d)) 570 { 571 /* If not, print with 17 decimal places of precision */ 572 length = sprintf((char*)number_buffer, "%1.17g", d); 573 } 574 } 575 576 /* sprintf failed or buffer overrun occurred */ 577 if ((length < 0) || (length > (int)(sizeof(number_buffer) - 1))) 578 { 579 return false; 580 } 581 582 /* reserve appropriate space in the output */ 583 output_pointer = ensure(output_buffer, (size_t)length + sizeof("")); 584 if (output_pointer == NULL) 585 { 586 return false; 587 } 588 589 /* copy the printed number to the output and replace locale 590 * dependent decimal point with '.' */ 591 for (i = 0; i < ((size_t)length); i++) 592 { 593 if (number_buffer[i] == decimal_point) 594 { 595 output_pointer[i] = '.'; 596 continue; 597 } 598 599 output_pointer[i] = number_buffer[i]; 600 } 601 output_pointer[i] = '\0'; 602 603 output_buffer->offset += (size_t)length; 604 605 return true; 606 } 607 608 /* parse 4 digit hexadecimal number */ 609 static unsigned parse_hex4(const unsigned char * const input) 610 { 611 unsigned int h = 0; 612 size_t i = 0; 613 614 for (i = 0; i < 4; i++) 615 { 616 /* parse digit */ 617 if ((input[i] >= '0') && (input[i] <= '9')) 618 { 619 h += (unsigned int) input[i] - '0'; 620 } 621 else if ((input[i] >= 'A') && (input[i] <= 'F')) 622 { 623 h += (unsigned int) 10 + input[i] - 'A'; 624 } 625 else if ((input[i] >= 'a') && (input[i] <= 'f')) 626 { 627 h += (unsigned int) 10 + input[i] - 'a'; 628 } 629 else /* invalid */ 630 { 631 return 0; 632 } 633 634 if (i < 3) 635 { 636 /* shift left to make place for the next nibble */ 637 h = h << 4; 638 } 639 } 640 641 return h; 642 } 643 644 /* converts a UTF-16 literal to UTF-8 645 * A literal can be one or two sequences of the form \uXXXX */ 646 static unsigned char utf16_literal_to_utf8(const unsigned char * const input_pointer, const unsigned char * const input_end, unsigned char **output_pointer) 647 { 648 long unsigned int codepoint = 0; 649 unsigned int first_code = 0; 650 const unsigned char *first_sequence = input_pointer; 651 unsigned char utf8_length = 0; 652 unsigned char utf8_position = 0; 653 unsigned char sequence_length = 0; 654 unsigned char first_byte_mark = 0; 655 656 if ((input_end - first_sequence) < 6) 657 { 658 /* input ends unexpectedly */ 659 goto fail; 660 } 661 662 /* get the first utf16 sequence */ 663 first_code = parse_hex4(first_sequence + 2); 664 665 /* check that the code is valid */ 666 if (((first_code >= 0xDC00) && (first_code <= 0xDFFF))) 667 { 668 goto fail; 669 } 670 671 /* UTF16 surrogate pair */ 672 if ((first_code >= 0xD800) && (first_code <= 0xDBFF)) 673 { 674 const unsigned char *second_sequence = first_sequence + 6; 675 unsigned int second_code = 0; 676 sequence_length = 12; /* \uXXXX\uXXXX */ 677 678 if ((input_end - second_sequence) < 6) 679 { 680 /* input ends unexpectedly */ 681 goto fail; 682 } 683 684 if ((second_sequence[0] != '\\') || (second_sequence[1] != 'u')) 685 { 686 /* missing second half of the surrogate pair */ 687 goto fail; 688 } 689 690 /* get the second utf16 sequence */ 691 second_code = parse_hex4(second_sequence + 2); 692 /* check that the code is valid */ 693 if ((second_code < 0xDC00) || (second_code > 0xDFFF)) 694 { 695 /* invalid second half of the surrogate pair */ 696 goto fail; 697 } 698 699 700 /* calculate the unicode codepoint from the surrogate pair */ 701 codepoint = 0x10000 + (((first_code & 0x3FF) << 10) | (second_code & 0x3FF)); 702 } 703 else 704 { 705 sequence_length = 6; /* \uXXXX */ 706 codepoint = first_code; 707 } 708 709 /* encode as UTF-8 710 * takes at maximum 4 bytes to encode: 711 * 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */ 712 if (codepoint < 0x80) 713 { 714 /* normal ascii, encoding 0xxxxxxx */ 715 utf8_length = 1; 716 } 717 else if (codepoint < 0x800) 718 { 719 /* two bytes, encoding 110xxxxx 10xxxxxx */ 720 utf8_length = 2; 721 first_byte_mark = 0xC0; /* 11000000 */ 722 } 723 else if (codepoint < 0x10000) 724 { 725 /* three bytes, encoding 1110xxxx 10xxxxxx 10xxxxxx */ 726 utf8_length = 3; 727 first_byte_mark = 0xE0; /* 11100000 */ 728 } 729 else if (codepoint <= 0x10FFFF) 730 { 731 /* four bytes, encoding 1110xxxx 10xxxxxx 10xxxxxx 10xxxxxx */ 732 utf8_length = 4; 733 first_byte_mark = 0xF0; /* 11110000 */ 734 } 735 else 736 { 737 /* invalid unicode codepoint */ 738 goto fail; 739 } 740 741 /* encode as utf8 */ 742 for (utf8_position = (unsigned char)(utf8_length - 1); utf8_position > 0; utf8_position--) 743 { 744 /* 10xxxxxx */ 745 (*output_pointer)[utf8_position] = (unsigned char)((codepoint | 0x80) & 0xBF); 746 codepoint >>= 6; 747 } 748 /* encode first byte */ 749 if (utf8_length > 1) 750 { 751 (*output_pointer)[0] = (unsigned char)((codepoint | first_byte_mark) & 0xFF); 752 } 753 else 754 { 755 (*output_pointer)[0] = (unsigned char)(codepoint & 0x7F); 756 } 757 758 *output_pointer += utf8_length; 759 760 return sequence_length; 761 762 fail: 763 return 0; 764 } 765 766 /* Parse the input text into an unescaped cinput, and populate item. */ 767 static cJSON_bool parse_string(cJSON * const item, parse_buffer * const input_buffer) 768 { 769 const unsigned char *input_pointer = buffer_at_offset(input_buffer) + 1; 770 const unsigned char *input_end = buffer_at_offset(input_buffer) + 1; 771 unsigned char *output_pointer = NULL; 772 unsigned char *output = NULL; 773 774 /* not a string */ 775 if (buffer_at_offset(input_buffer)[0] != '\"') 776 { 777 goto fail; 778 } 779 780 { 781 /* calculate approximate size of the output (overestimate) */ 782 size_t allocation_length = 0; 783 size_t skipped_bytes = 0; 784 while (((size_t)(input_end - input_buffer->content) < input_buffer->length) && (*input_end != '\"')) 785 { 786 /* is escape sequence */ 787 if (input_end[0] == '\\') 788 { 789 if ((size_t)(input_end + 1 - input_buffer->content) >= input_buffer->length) 790 { 791 /* prevent buffer overflow when last input character is a backslash */ 792 goto fail; 793 } 794 skipped_bytes++; 795 input_end++; 796 } 797 input_end++; 798 } 799 if (((size_t)(input_end - input_buffer->content) >= input_buffer->length) || (*input_end != '\"')) 800 { 801 goto fail; /* string ended unexpectedly */ 802 } 803 804 /* This is at most how much we need for the output */ 805 allocation_length = (size_t) (input_end - buffer_at_offset(input_buffer)) - skipped_bytes; 806 output = (unsigned char*)input_buffer->hooks.allocate(allocation_length + sizeof("")); 807 if (output == NULL) 808 { 809 goto fail; /* allocation failure */ 810 } 811 } 812 813 output_pointer = output; 814 /* loop through the string literal */ 815 while (input_pointer < input_end) 816 { 817 if (*input_pointer != '\\') 818 { 819 *output_pointer++ = *input_pointer++; 820 } 821 /* escape sequence */ 822 else 823 { 824 unsigned char sequence_length = 2; 825 if ((input_end - input_pointer) < 1) 826 { 827 goto fail; 828 } 829 830 switch (input_pointer[1]) 831 { 832 case 'b': 833 *output_pointer++ = '\b'; 834 break; 835 case 'f': 836 *output_pointer++ = '\f'; 837 break; 838 case 'n': 839 *output_pointer++ = '\n'; 840 break; 841 case 'r': 842 *output_pointer++ = '\r'; 843 break; 844 case 't': 845 *output_pointer++ = '\t'; 846 break; 847 case '\"': 848 case '\\': 849 case '/': 850 *output_pointer++ = input_pointer[1]; 851 break; 852 853 /* UTF-16 literal */ 854 case 'u': 855 sequence_length = utf16_literal_to_utf8(input_pointer, input_end, &output_pointer); 856 if (sequence_length == 0) 857 { 858 /* failed to convert UTF16-literal to UTF-8 */ 859 goto fail; 860 } 861 break; 862 863 default: 864 goto fail; 865 } 866 input_pointer += sequence_length; 867 } 868 } 869 870 /* zero terminate the output */ 871 *output_pointer = '\0'; 872 873 item->type = cJSON_String; 874 item->valuestring = (char*)output; 875 876 input_buffer->offset = (size_t) (input_end - input_buffer->content); 877 input_buffer->offset++; 878 879 return true; 880 881 fail: 882 if (output != NULL) 883 { 884 input_buffer->hooks.deallocate(output); 885 } 886 887 if (input_pointer != NULL) 888 { 889 input_buffer->offset = (size_t)(input_pointer - input_buffer->content); 890 } 891 892 return false; 893 } 894 895 /* Render the cstring provided to an escaped version that can be printed. */ 896 static cJSON_bool print_string_ptr(const unsigned char * const input, printbuffer * const output_buffer) 897 { 898 const unsigned char *input_pointer = NULL; 899 unsigned char *output = NULL; 900 unsigned char *output_pointer = NULL; 901 size_t output_length = 0; 902 /* numbers of additional characters needed for escaping */ 903 size_t escape_characters = 0; 904 905 if (output_buffer == NULL) 906 { 907 return false; 908 } 909 910 /* empty string */ 911 if (input == NULL) 912 { 913 output = ensure(output_buffer, sizeof("\"\"")); 914 if (output == NULL) 915 { 916 return false; 917 } 918 strcpy((char*)output, "\"\""); 919 920 return true; 921 } 922 923 /* set "flag" to 1 if something needs to be escaped */ 924 for (input_pointer = input; *input_pointer; input_pointer++) 925 { 926 switch (*input_pointer) 927 { 928 case '\"': 929 case '\\': 930 case '\b': 931 case '\f': 932 case '\n': 933 case '\r': 934 case '\t': 935 /* one character escape sequence */ 936 escape_characters++; 937 break; 938 default: 939 if (*input_pointer < 32) 940 { 941 /* UTF-16 escape sequence uXXXX */ 942 escape_characters += 5; 943 } 944 break; 945 } 946 } 947 output_length = (size_t)(input_pointer - input) + escape_characters; 948 949 output = ensure(output_buffer, output_length + sizeof("\"\"")); 950 if (output == NULL) 951 { 952 return false; 953 } 954 955 /* no characters have to be escaped */ 956 if (escape_characters == 0) 957 { 958 output[0] = '\"'; 959 memcpy(output + 1, input, output_length); 960 output[output_length + 1] = '\"'; 961 output[output_length + 2] = '\0'; 962 963 return true; 964 } 965 966 output[0] = '\"'; 967 output_pointer = output + 1; 968 /* copy the string */ 969 for (input_pointer = input; *input_pointer != '\0'; (void)input_pointer++, output_pointer++) 970 { 971 if ((*input_pointer > 31) && (*input_pointer != '\"') && (*input_pointer != '\\')) 972 { 973 /* normal character, copy */ 974 *output_pointer = *input_pointer; 975 } 976 else 977 { 978 /* character needs to be escaped */ 979 *output_pointer++ = '\\'; 980 switch (*input_pointer) 981 { 982 case '\\': 983 *output_pointer = '\\'; 984 break; 985 case '\"': 986 *output_pointer = '\"'; 987 break; 988 case '\b': 989 *output_pointer = 'b'; 990 break; 991 case '\f': 992 *output_pointer = 'f'; 993 break; 994 case '\n': 995 *output_pointer = 'n'; 996 break; 997 case '\r': 998 *output_pointer = 'r'; 999 break; 1000 case '\t': 1001 *output_pointer = 't'; 1002 break; 1003 default: 1004 /* escape and print as unicode codepoint */ 1005 sprintf((char*)output_pointer, "u%04x", *input_pointer); 1006 output_pointer += 4; 1007 break; 1008 } 1009 } 1010 } 1011 output[output_length + 1] = '\"'; 1012 output[output_length + 2] = '\0'; 1013 1014 return true; 1015 } 1016 1017 /* Invoke print_string_ptr (which is useful) on an item. */ 1018 static cJSON_bool print_string(const cJSON * const item, printbuffer * const p) 1019 { 1020 return print_string_ptr((unsigned char*)item->valuestring, p); 1021 } 1022 1023 /* Predeclare these prototypes. */ 1024 static cJSON_bool parse_value(cJSON * const item, parse_buffer * const input_buffer); 1025 static cJSON_bool print_value(const cJSON * const item, printbuffer * const output_buffer); 1026 static cJSON_bool parse_array(cJSON * const item, parse_buffer * const input_buffer); 1027 static cJSON_bool print_array(const cJSON * const item, printbuffer * const output_buffer); 1028 static cJSON_bool parse_object(cJSON * const item, parse_buffer * const input_buffer); 1029 static cJSON_bool print_object(const cJSON * const item, printbuffer * const output_buffer); 1030 1031 /* Utility to jump whitespace and cr/lf */ 1032 static parse_buffer *buffer_skip_whitespace(parse_buffer * const buffer) 1033 { 1034 if ((buffer == NULL) || (buffer->content == NULL)) 1035 { 1036 return NULL; 1037 } 1038 1039 if (cannot_access_at_index(buffer, 0)) 1040 { 1041 return buffer; 1042 } 1043 1044 while (can_access_at_index(buffer, 0) && (buffer_at_offset(buffer)[0] <= 32)) 1045 { 1046 buffer->offset++; 1047 } 1048 1049 if (buffer->offset == buffer->length) 1050 { 1051 buffer->offset--; 1052 } 1053 1054 return buffer; 1055 } 1056 1057 /* skip the UTF-8 BOM (byte order mark) if it is at the beginning of a buffer */ 1058 static parse_buffer *skip_utf8_bom(parse_buffer * const buffer) 1059 { 1060 if ((buffer == NULL) || (buffer->content == NULL) || (buffer->offset != 0)) 1061 { 1062 return NULL; 1063 } 1064 1065 if (can_access_at_index(buffer, 4) && (strncmp((const char*)buffer_at_offset(buffer), "\xEF\xBB\xBF", 3) == 0)) 1066 { 1067 buffer->offset += 3; 1068 } 1069 1070 return buffer; 1071 } 1072 1073 CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated) 1074 { 1075 size_t buffer_length; 1076 1077 if (NULL == value) 1078 { 1079 return NULL; 1080 } 1081 1082 /* Adding null character size due to require_null_terminated. */ 1083 buffer_length = strlen(value) + sizeof(""); 1084 1085 return cJSON_ParseWithLengthOpts(value, buffer_length, return_parse_end, require_null_terminated); 1086 } 1087 1088 /* Parse an object - create a new root, and populate. */ 1089 CJSON_PUBLIC(cJSON *) cJSON_ParseWithLengthOpts(const char *value, size_t buffer_length, const char **return_parse_end, cJSON_bool require_null_terminated) 1090 { 1091 parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0 } }; 1092 cJSON *item = NULL; 1093 1094 /* reset error position */ 1095 global_error.json = NULL; 1096 global_error.position = 0; 1097 1098 if (value == NULL || 0 == buffer_length) 1099 { 1100 goto fail; 1101 } 1102 1103 buffer.content = (const unsigned char*)value; 1104 buffer.length = buffer_length; 1105 buffer.offset = 0; 1106 buffer.hooks = global_hooks; 1107 1108 item = cJSON_New_Item(&global_hooks); 1109 if (item == NULL) /* memory fail */ 1110 { 1111 goto fail; 1112 } 1113 1114 if (!parse_value(item, buffer_skip_whitespace(skip_utf8_bom(&buffer)))) 1115 { 1116 /* parse failure. ep is set. */ 1117 goto fail; 1118 } 1119 1120 /* if we require null-terminated JSON without appended garbage, skip and then check for a null terminator */ 1121 if (require_null_terminated) 1122 { 1123 buffer_skip_whitespace(&buffer); 1124 if ((buffer.offset >= buffer.length) || buffer_at_offset(&buffer)[0] != '\0') 1125 { 1126 goto fail; 1127 } 1128 } 1129 if (return_parse_end) 1130 { 1131 *return_parse_end = (const char*)buffer_at_offset(&buffer); 1132 } 1133 1134 return item; 1135 1136 fail: 1137 if (item != NULL) 1138 { 1139 cJSON_Delete(item); 1140 } 1141 1142 if (value != NULL) 1143 { 1144 error local_error; 1145 local_error.json = (const unsigned char*)value; 1146 local_error.position = 0; 1147 1148 if (buffer.offset < buffer.length) 1149 { 1150 local_error.position = buffer.offset; 1151 } 1152 else if (buffer.length > 0) 1153 { 1154 local_error.position = buffer.length - 1; 1155 } 1156 1157 if (return_parse_end != NULL) 1158 { 1159 *return_parse_end = (const char*)local_error.json + local_error.position; 1160 } 1161 1162 global_error = local_error; 1163 } 1164 1165 return NULL; 1166 } 1167 1168 /* Default options for cJSON_Parse */ 1169 CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value) 1170 { 1171 return cJSON_ParseWithOpts(value, 0, 0); 1172 } 1173 1174 CJSON_PUBLIC(cJSON *) cJSON_ParseWithLength(const char *value, size_t buffer_length) 1175 { 1176 return cJSON_ParseWithLengthOpts(value, buffer_length, 0, 0); 1177 } 1178 1179 #define cjson_min(a, b) (((a) < (b)) ? (a) : (b)) 1180 1181 static unsigned char *print(const cJSON * const item, cJSON_bool format, const internal_hooks * const hooks) 1182 { 1183 static const size_t default_buffer_size = 256; 1184 printbuffer buffer[1]; 1185 unsigned char *printed = NULL; 1186 1187 memset(buffer, 0, sizeof(buffer)); 1188 1189 /* create buffer */ 1190 buffer->buffer = (unsigned char*) hooks->allocate(default_buffer_size); 1191 buffer->length = default_buffer_size; 1192 buffer->format = format; 1193 buffer->hooks = *hooks; 1194 if (buffer->buffer == NULL) 1195 { 1196 goto fail; 1197 } 1198 1199 /* print the value */ 1200 if (!print_value(item, buffer)) 1201 { 1202 goto fail; 1203 } 1204 update_offset(buffer); 1205 1206 /* check if reallocate is available */ 1207 if (hooks->reallocate != NULL) 1208 { 1209 printed = (unsigned char*) hooks->reallocate(buffer->buffer, buffer->offset + 1); 1210 if (printed == NULL) { 1211 goto fail; 1212 } 1213 buffer->buffer = NULL; 1214 } 1215 else /* otherwise copy the JSON over to a new buffer */ 1216 { 1217 printed = (unsigned char*) hooks->allocate(buffer->offset + 1); 1218 if (printed == NULL) 1219 { 1220 goto fail; 1221 } 1222 memcpy(printed, buffer->buffer, cjson_min(buffer->length, buffer->offset + 1)); 1223 printed[buffer->offset] = '\0'; /* just to be sure */ 1224 1225 /* free the buffer */ 1226 hooks->deallocate(buffer->buffer); 1227 } 1228 1229 return printed; 1230 1231 fail: 1232 if (buffer->buffer != NULL) 1233 { 1234 hooks->deallocate(buffer->buffer); 1235 } 1236 1237 if (printed != NULL) 1238 { 1239 hooks->deallocate(printed); 1240 } 1241 1242 return NULL; 1243 } 1244 1245 /* Render a cJSON item/entity/structure to text. */ 1246 CJSON_PUBLIC(char *) cJSON_Print(const cJSON *item) 1247 { 1248 return (char*)print(item, true, &global_hooks); 1249 } 1250 1251 CJSON_PUBLIC(char *) cJSON_PrintUnformatted(const cJSON *item) 1252 { 1253 return (char*)print(item, false, &global_hooks); 1254 } 1255 1256 CJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_bool fmt) 1257 { 1258 printbuffer p = { 0, 0, 0, 0, 0, 0, { 0, 0, 0 } }; 1259 1260 if (prebuffer < 0) 1261 { 1262 return NULL; 1263 } 1264 1265 p.buffer = (unsigned char*)global_hooks.allocate((size_t)prebuffer); 1266 if (!p.buffer) 1267 { 1268 return NULL; 1269 } 1270 1271 p.length = (size_t)prebuffer; 1272 p.offset = 0; 1273 p.noalloc = false; 1274 p.format = fmt; 1275 p.hooks = global_hooks; 1276 1277 if (!print_value(item, &p)) 1278 { 1279 global_hooks.deallocate(p.buffer); 1280 return NULL; 1281 } 1282 1283 return (char*)p.buffer; 1284 } 1285 1286 CJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length, const cJSON_bool format) 1287 { 1288 printbuffer p = { 0, 0, 0, 0, 0, 0, { 0, 0, 0 } }; 1289 1290 if ((length < 0) || (buffer == NULL)) 1291 { 1292 return false; 1293 } 1294 1295 p.buffer = (unsigned char*)buffer; 1296 p.length = (size_t)length; 1297 p.offset = 0; 1298 p.noalloc = true; 1299 p.format = format; 1300 p.hooks = global_hooks; 1301 1302 return print_value(item, &p); 1303 } 1304 1305 /* Parser core - when encountering text, process appropriately. */ 1306 static cJSON_bool parse_value(cJSON * const item, parse_buffer * const input_buffer) 1307 { 1308 if ((input_buffer == NULL) || (input_buffer->content == NULL)) 1309 { 1310 return false; /* no input */ 1311 } 1312 1313 /* parse the different types of values */ 1314 /* null */ 1315 if (can_read(input_buffer, 4) && (strncmp((const char*)buffer_at_offset(input_buffer), "null", 4) == 0)) 1316 { 1317 item->type = cJSON_NULL; 1318 input_buffer->offset += 4; 1319 return true; 1320 } 1321 /* false */ 1322 if (can_read(input_buffer, 5) && (strncmp((const char*)buffer_at_offset(input_buffer), "false", 5) == 0)) 1323 { 1324 item->type = cJSON_False; 1325 input_buffer->offset += 5; 1326 return true; 1327 } 1328 /* true */ 1329 if (can_read(input_buffer, 4) && (strncmp((const char*)buffer_at_offset(input_buffer), "true", 4) == 0)) 1330 { 1331 item->type = cJSON_True; 1332 item->valueint = 1; 1333 input_buffer->offset += 4; 1334 return true; 1335 } 1336 /* string */ 1337 if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '\"')) 1338 { 1339 return parse_string(item, input_buffer); 1340 } 1341 /* number */ 1342 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')))) 1343 { 1344 return parse_number(item, input_buffer); 1345 } 1346 /* array */ 1347 if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '[')) 1348 { 1349 return parse_array(item, input_buffer); 1350 } 1351 /* object */ 1352 if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '{')) 1353 { 1354 return parse_object(item, input_buffer); 1355 } 1356 1357 return false; 1358 } 1359 1360 /* Render a value to text. */ 1361 static cJSON_bool print_value(const cJSON * const item, printbuffer * const output_buffer) 1362 { 1363 unsigned char *output = NULL; 1364 1365 if ((item == NULL) || (output_buffer == NULL)) 1366 { 1367 return false; 1368 } 1369 1370 switch ((item->type) & 0xFF) 1371 { 1372 case cJSON_NULL: 1373 output = ensure(output_buffer, 5); 1374 if (output == NULL) 1375 { 1376 return false; 1377 } 1378 strcpy((char*)output, "null"); 1379 return true; 1380 1381 case cJSON_False: 1382 output = ensure(output_buffer, 6); 1383 if (output == NULL) 1384 { 1385 return false; 1386 } 1387 strcpy((char*)output, "false"); 1388 return true; 1389 1390 case cJSON_True: 1391 output = ensure(output_buffer, 5); 1392 if (output == NULL) 1393 { 1394 return false; 1395 } 1396 strcpy((char*)output, "true"); 1397 return true; 1398 1399 case cJSON_Number: 1400 return print_number(item, output_buffer); 1401 1402 case cJSON_Raw: 1403 { 1404 size_t raw_length = 0; 1405 if (item->valuestring == NULL) 1406 { 1407 return false; 1408 } 1409 1410 raw_length = strlen(item->valuestring) + sizeof(""); 1411 output = ensure(output_buffer, raw_length); 1412 if (output == NULL) 1413 { 1414 return false; 1415 } 1416 memcpy(output, item->valuestring, raw_length); 1417 return true; 1418 } 1419 1420 case cJSON_String: 1421 return print_string(item, output_buffer); 1422 1423 case cJSON_Array: 1424 return print_array(item, output_buffer); 1425 1426 case cJSON_Object: 1427 return print_object(item, output_buffer); 1428 1429 default: 1430 return false; 1431 } 1432 } 1433 1434 /* Build an array from input text. */ 1435 static cJSON_bool parse_array(cJSON * const item, parse_buffer * const input_buffer) 1436 { 1437 cJSON *head = NULL; /* head of the linked list */ 1438 cJSON *current_item = NULL; 1439 1440 if (input_buffer->depth >= CJSON_NESTING_LIMIT) 1441 { 1442 return false; /* to deeply nested */ 1443 } 1444 input_buffer->depth++; 1445 1446 if (buffer_at_offset(input_buffer)[0] != '[') 1447 { 1448 /* not an array */ 1449 goto fail; 1450 } 1451 1452 input_buffer->offset++; 1453 buffer_skip_whitespace(input_buffer); 1454 if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ']')) 1455 { 1456 /* empty array */ 1457 goto success; 1458 } 1459 1460 /* check if we skipped to the end of the buffer */ 1461 if (cannot_access_at_index(input_buffer, 0)) 1462 { 1463 input_buffer->offset--; 1464 goto fail; 1465 } 1466 1467 /* step back to character in front of the first element */ 1468 input_buffer->offset--; 1469 /* loop through the comma separated array elements */ 1470 do 1471 { 1472 /* allocate next item */ 1473 cJSON *new_item = cJSON_New_Item(&(input_buffer->hooks)); 1474 if (new_item == NULL) 1475 { 1476 goto fail; /* allocation failure */ 1477 } 1478 1479 /* attach next item to list */ 1480 if (head == NULL) 1481 { 1482 /* start the linked list */ 1483 current_item = head = new_item; 1484 } 1485 else 1486 { 1487 /* add to the end and advance */ 1488 current_item->next = new_item; 1489 new_item->prev = current_item; 1490 current_item = new_item; 1491 } 1492 1493 /* parse next value */ 1494 input_buffer->offset++; 1495 buffer_skip_whitespace(input_buffer); 1496 if (!parse_value(current_item, input_buffer)) 1497 { 1498 goto fail; /* failed to parse value */ 1499 } 1500 buffer_skip_whitespace(input_buffer); 1501 } 1502 while (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ',')); 1503 1504 if (cannot_access_at_index(input_buffer, 0) || buffer_at_offset(input_buffer)[0] != ']') 1505 { 1506 goto fail; /* expected end of array */ 1507 } 1508 1509 success: 1510 input_buffer->depth--; 1511 1512 item->type = cJSON_Array; 1513 item->child = head; 1514 1515 input_buffer->offset++; 1516 1517 return true; 1518 1519 fail: 1520 if (head != NULL) 1521 { 1522 cJSON_Delete(head); 1523 } 1524 1525 return false; 1526 } 1527 1528 /* Render an array to text */ 1529 static cJSON_bool print_array(const cJSON * const item, printbuffer * const output_buffer) 1530 { 1531 unsigned char *output_pointer = NULL; 1532 size_t length = 0; 1533 cJSON *current_element = item->child; 1534 1535 if (output_buffer == NULL) 1536 { 1537 return false; 1538 } 1539 1540 /* Compose the output array. */ 1541 /* opening square bracket */ 1542 output_pointer = ensure(output_buffer, 1); 1543 if (output_pointer == NULL) 1544 { 1545 return false; 1546 } 1547 1548 *output_pointer = '['; 1549 output_buffer->offset++; 1550 output_buffer->depth++; 1551 1552 while (current_element != NULL) 1553 { 1554 if (!print_value(current_element, output_buffer)) 1555 { 1556 return false; 1557 } 1558 update_offset(output_buffer); 1559 if (current_element->next) 1560 { 1561 length = (size_t) (output_buffer->format ? 2 : 1); 1562 output_pointer = ensure(output_buffer, length + 1); 1563 if (output_pointer == NULL) 1564 { 1565 return false; 1566 } 1567 *output_pointer++ = ','; 1568 if(output_buffer->format) 1569 { 1570 *output_pointer++ = ' '; 1571 } 1572 *output_pointer = '\0'; 1573 output_buffer->offset += length; 1574 } 1575 current_element = current_element->next; 1576 } 1577 1578 output_pointer = ensure(output_buffer, 2); 1579 if (output_pointer == NULL) 1580 { 1581 return false; 1582 } 1583 *output_pointer++ = ']'; 1584 *output_pointer = '\0'; 1585 output_buffer->depth--; 1586 1587 return true; 1588 } 1589 1590 /* Build an object from the text. */ 1591 static cJSON_bool parse_object(cJSON * const item, parse_buffer * const input_buffer) 1592 { 1593 cJSON *head = NULL; /* linked list head */ 1594 cJSON *current_item = NULL; 1595 1596 if (input_buffer->depth >= CJSON_NESTING_LIMIT) 1597 { 1598 return false; /* to deeply nested */ 1599 } 1600 input_buffer->depth++; 1601 1602 if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != '{')) 1603 { 1604 goto fail; /* not an object */ 1605 } 1606 1607 input_buffer->offset++; 1608 buffer_skip_whitespace(input_buffer); 1609 if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '}')) 1610 { 1611 goto success; /* empty object */ 1612 } 1613 1614 /* check if we skipped to the end of the buffer */ 1615 if (cannot_access_at_index(input_buffer, 0)) 1616 { 1617 input_buffer->offset--; 1618 goto fail; 1619 } 1620 1621 /* step back to character in front of the first element */ 1622 input_buffer->offset--; 1623 /* loop through the comma separated array elements */ 1624 do 1625 { 1626 /* allocate next item */ 1627 cJSON *new_item = cJSON_New_Item(&(input_buffer->hooks)); 1628 if (new_item == NULL) 1629 { 1630 goto fail; /* allocation failure */ 1631 } 1632 1633 /* attach next item to list */ 1634 if (head == NULL) 1635 { 1636 /* start the linked list */ 1637 current_item = head = new_item; 1638 } 1639 else 1640 { 1641 /* add to the end and advance */ 1642 current_item->next = new_item; 1643 new_item->prev = current_item; 1644 current_item = new_item; 1645 } 1646 1647 /* parse the name of the child */ 1648 input_buffer->offset++; 1649 buffer_skip_whitespace(input_buffer); 1650 if (!parse_string(current_item, input_buffer)) 1651 { 1652 goto fail; /* failed to parse name */ 1653 } 1654 buffer_skip_whitespace(input_buffer); 1655 1656 /* swap valuestring and string, because we parsed the name */ 1657 current_item->string = current_item->valuestring; 1658 current_item->valuestring = NULL; 1659 1660 if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != ':')) 1661 { 1662 goto fail; /* invalid object */ 1663 } 1664 1665 /* parse the value */ 1666 input_buffer->offset++; 1667 buffer_skip_whitespace(input_buffer); 1668 if (!parse_value(current_item, input_buffer)) 1669 { 1670 goto fail; /* failed to parse value */ 1671 } 1672 buffer_skip_whitespace(input_buffer); 1673 } 1674 while (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ',')); 1675 1676 if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != '}')) 1677 { 1678 goto fail; /* expected end of object */ 1679 } 1680 1681 success: 1682 input_buffer->depth--; 1683 1684 item->type = cJSON_Object; 1685 item->child = head; 1686 1687 input_buffer->offset++; 1688 return true; 1689 1690 fail: 1691 if (head != NULL) 1692 { 1693 cJSON_Delete(head); 1694 } 1695 1696 return false; 1697 } 1698 1699 /* Render an object to text. */ 1700 static cJSON_bool print_object(const cJSON * const item, printbuffer * const output_buffer) 1701 { 1702 unsigned char *output_pointer = NULL; 1703 size_t length = 0; 1704 cJSON *current_item = item->child; 1705 1706 if (output_buffer == NULL) 1707 { 1708 return false; 1709 } 1710 1711 /* Compose the output: */ 1712 length = (size_t) (output_buffer->format ? 2 : 1); /* fmt: {\n */ 1713 output_pointer = ensure(output_buffer, length + 1); 1714 if (output_pointer == NULL) 1715 { 1716 return false; 1717 } 1718 1719 *output_pointer++ = '{'; 1720 output_buffer->depth++; 1721 if (output_buffer->format) 1722 { 1723 *output_pointer++ = '\n'; 1724 } 1725 output_buffer->offset += length; 1726 1727 while (current_item) 1728 { 1729 if (output_buffer->format) 1730 { 1731 size_t i; 1732 output_pointer = ensure(output_buffer, output_buffer->depth); 1733 if (output_pointer == NULL) 1734 { 1735 return false; 1736 } 1737 for (i = 0; i < output_buffer->depth; i++) 1738 { 1739 *output_pointer++ = '\t'; 1740 } 1741 output_buffer->offset += output_buffer->depth; 1742 } 1743 1744 /* print key */ 1745 if (!print_string_ptr((unsigned char*)current_item->string, output_buffer)) 1746 { 1747 return false; 1748 } 1749 update_offset(output_buffer); 1750 1751 length = (size_t) (output_buffer->format ? 2 : 1); 1752 output_pointer = ensure(output_buffer, length); 1753 if (output_pointer == NULL) 1754 { 1755 return false; 1756 } 1757 *output_pointer++ = ':'; 1758 if (output_buffer->format) 1759 { 1760 *output_pointer++ = '\t'; 1761 } 1762 output_buffer->offset += length; 1763 1764 /* print value */ 1765 if (!print_value(current_item, output_buffer)) 1766 { 1767 return false; 1768 } 1769 update_offset(output_buffer); 1770 1771 /* print comma if not last */ 1772 length = ((size_t)(output_buffer->format ? 1 : 0) + (size_t)(current_item->next ? 1 : 0)); 1773 output_pointer = ensure(output_buffer, length + 1); 1774 if (output_pointer == NULL) 1775 { 1776 return false; 1777 } 1778 if (current_item->next) 1779 { 1780 *output_pointer++ = ','; 1781 } 1782 1783 if (output_buffer->format) 1784 { 1785 *output_pointer++ = '\n'; 1786 } 1787 *output_pointer = '\0'; 1788 output_buffer->offset += length; 1789 1790 current_item = current_item->next; 1791 } 1792 1793 output_pointer = ensure(output_buffer, output_buffer->format ? (output_buffer->depth + 1) : 2); 1794 if (output_pointer == NULL) 1795 { 1796 return false; 1797 } 1798 if (output_buffer->format) 1799 { 1800 size_t i; 1801 for (i = 0; i < (output_buffer->depth - 1); i++) 1802 { 1803 *output_pointer++ = '\t'; 1804 } 1805 } 1806 *output_pointer++ = '}'; 1807 *output_pointer = '\0'; 1808 output_buffer->depth--; 1809 1810 return true; 1811 } 1812 1813 /* Get Array size/item / object item. */ 1814 CJSON_PUBLIC(int) cJSON_GetArraySize(const cJSON *array) 1815 { 1816 cJSON *child = NULL; 1817 size_t size = 0; 1818 1819 if (array == NULL) 1820 { 1821 return 0; 1822 } 1823 1824 child = array->child; 1825 1826 while(child != NULL) 1827 { 1828 size++; 1829 child = child->next; 1830 } 1831 1832 /* FIXME: Can overflow here. Cannot be fixed without breaking the API */ 1833 1834 return (int)size; 1835 } 1836 1837 static cJSON* get_array_item(const cJSON *array, size_t index) 1838 { 1839 cJSON *current_child = NULL; 1840 1841 if (array == NULL) 1842 { 1843 return NULL; 1844 } 1845 1846 current_child = array->child; 1847 while ((current_child != NULL) && (index > 0)) 1848 { 1849 index--; 1850 current_child = current_child->next; 1851 } 1852 1853 return current_child; 1854 } 1855 1856 CJSON_PUBLIC(cJSON *) cJSON_GetArrayItem(const cJSON *array, int index) 1857 { 1858 if (index < 0) 1859 { 1860 return NULL; 1861 } 1862 1863 return get_array_item(array, (size_t)index); 1864 } 1865 1866 static cJSON *get_object_item(const cJSON * const object, const char * const name, const cJSON_bool case_sensitive) 1867 { 1868 cJSON *current_element = NULL; 1869 1870 if ((object == NULL) || (name == NULL)) 1871 { 1872 return NULL; 1873 } 1874 1875 current_element = object->child; 1876 if (case_sensitive) 1877 { 1878 while ((current_element != NULL) && (current_element->string != NULL) && (strcmp(name, current_element->string) != 0)) 1879 { 1880 current_element = current_element->next; 1881 } 1882 } 1883 else 1884 { 1885 while ((current_element != NULL) && (case_insensitive_strcmp((const unsigned char*)name, (const unsigned char*)(current_element->string)) != 0)) 1886 { 1887 current_element = current_element->next; 1888 } 1889 } 1890 1891 if ((current_element == NULL) || (current_element->string == NULL)) { 1892 return NULL; 1893 } 1894 1895 return current_element; 1896 } 1897 1898 CJSON_PUBLIC(cJSON *) cJSON_GetObjectItem(const cJSON * const object, const char * const string) 1899 { 1900 return get_object_item(object, string, false); 1901 } 1902 1903 CJSON_PUBLIC(cJSON *) cJSON_GetObjectItemCaseSensitive(const cJSON * const object, const char * const string) 1904 { 1905 return get_object_item(object, string, true); 1906 } 1907 1908 CJSON_PUBLIC(cJSON_bool) cJSON_HasObjectItem(const cJSON *object, const char *string) 1909 { 1910 return cJSON_GetObjectItem(object, string) ? 1 : 0; 1911 } 1912 1913 /* Utility for array list handling. */ 1914 static void suffix_object(cJSON *prev, cJSON *item) 1915 { 1916 prev->next = item; 1917 item->prev = prev; 1918 } 1919 1920 /* Utility for handling references. */ 1921 static cJSON *create_reference(const cJSON *item, const internal_hooks * const hooks) 1922 { 1923 cJSON *reference = NULL; 1924 if (item == NULL) 1925 { 1926 return NULL; 1927 } 1928 1929 reference = cJSON_New_Item(hooks); 1930 if (reference == NULL) 1931 { 1932 return NULL; 1933 } 1934 1935 memcpy(reference, item, sizeof(cJSON)); 1936 reference->string = NULL; 1937 reference->type |= cJSON_IsReference; 1938 reference->next = reference->prev = NULL; 1939 return reference; 1940 } 1941 1942 static cJSON_bool add_item_to_array(cJSON *array, cJSON *item) 1943 { 1944 cJSON *child = NULL; 1945 1946 if ((item == NULL) || (array == NULL) || (array == item)) 1947 { 1948 return false; 1949 } 1950 1951 child = array->child; 1952 /* 1953 * To find the last item in array quickly, we use prev in array 1954 */ 1955 if (child == NULL) 1956 { 1957 /* list is empty, start new one */ 1958 array->child = item; 1959 item->prev = item; 1960 item->next = NULL; 1961 } 1962 else 1963 { 1964 /* append to the end */ 1965 if (child->prev) 1966 { 1967 suffix_object(child->prev, item); 1968 array->child->prev = item; 1969 } 1970 else 1971 { 1972 while (child->next) 1973 { 1974 child = child->next; 1975 } 1976 suffix_object(child, item); 1977 array->child->prev = item; 1978 } 1979 } 1980 1981 return true; 1982 } 1983 1984 /* Add item to array/object. */ 1985 CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToArray(cJSON *array, cJSON *item) 1986 { 1987 return add_item_to_array(array, item); 1988 } 1989 1990 #if defined(__clang__) || (defined(__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5)))) 1991 #pragma GCC diagnostic push 1992 #endif 1993 #ifdef __GNUC__ 1994 #pragma GCC diagnostic ignored "-Wcast-qual" 1995 #endif 1996 /* helper function to cast away const */ 1997 static void* cast_away_const(const void* string) 1998 { 1999 return (void*)string; 2000 } 2001 #if defined(__clang__) || (defined(__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5)))) 2002 #pragma GCC diagnostic pop 2003 #endif 2004 2005 2006 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) 2007 { 2008 char *new_key = NULL; 2009 int new_type = cJSON_Invalid; 2010 2011 if ((object == NULL) || (string == NULL) || (item == NULL) || (object == item)) 2012 { 2013 return false; 2014 } 2015 2016 if (constant_key) 2017 { 2018 new_key = (char*)cast_away_const(string); 2019 new_type = item->type | cJSON_StringIsConst; 2020 } 2021 else 2022 { 2023 new_key = (char*)cJSON_strdup((const unsigned char*)string, hooks); 2024 if (new_key == NULL) 2025 { 2026 return false; 2027 } 2028 2029 new_type = item->type & ~cJSON_StringIsConst; 2030 } 2031 2032 if (!(item->type & cJSON_StringIsConst) && (item->string != NULL)) 2033 { 2034 hooks->deallocate(item->string); 2035 } 2036 2037 item->string = new_key; 2038 item->type = new_type; 2039 2040 return add_item_to_array(object, item); 2041 } 2042 2043 CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item) 2044 { 2045 return add_item_to_object(object, string, item, &global_hooks, false); 2046 } 2047 2048 /* Add an item to an object with constant string as key */ 2049 CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item) 2050 { 2051 return add_item_to_object(object, string, item, &global_hooks, true); 2052 } 2053 2054 CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item) 2055 { 2056 if (array == NULL) 2057 { 2058 return false; 2059 } 2060 2061 return add_item_to_array(array, create_reference(item, &global_hooks)); 2062 } 2063 2064 CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item) 2065 { 2066 if ((object == NULL) || (string == NULL)) 2067 { 2068 return false; 2069 } 2070 2071 return add_item_to_object(object, string, create_reference(item, &global_hooks), &global_hooks, false); 2072 } 2073 2074 CJSON_PUBLIC(cJSON*) cJSON_AddNullToObject(cJSON * const object, const char * const name) 2075 { 2076 cJSON *null = cJSON_CreateNull(); 2077 if (add_item_to_object(object, name, null, &global_hooks, false)) 2078 { 2079 return null; 2080 } 2081 2082 cJSON_Delete(null); 2083 return NULL; 2084 } 2085 2086 CJSON_PUBLIC(cJSON*) cJSON_AddTrueToObject(cJSON * const object, const char * const name) 2087 { 2088 cJSON *true_item = cJSON_CreateTrue(); 2089 if (add_item_to_object(object, name, true_item, &global_hooks, false)) 2090 { 2091 return true_item; 2092 } 2093 2094 cJSON_Delete(true_item); 2095 return NULL; 2096 } 2097 2098 CJSON_PUBLIC(cJSON*) cJSON_AddFalseToObject(cJSON * const object, const char * const name) 2099 { 2100 cJSON *false_item = cJSON_CreateFalse(); 2101 if (add_item_to_object(object, name, false_item, &global_hooks, false)) 2102 { 2103 return false_item; 2104 } 2105 2106 cJSON_Delete(false_item); 2107 return NULL; 2108 } 2109 2110 CJSON_PUBLIC(cJSON*) cJSON_AddBoolToObject(cJSON * const object, const char * const name, const cJSON_bool boolean) 2111 { 2112 cJSON *bool_item = cJSON_CreateBool(boolean); 2113 if (add_item_to_object(object, name, bool_item, &global_hooks, false)) 2114 { 2115 return bool_item; 2116 } 2117 2118 cJSON_Delete(bool_item); 2119 return NULL; 2120 } 2121 2122 CJSON_PUBLIC(cJSON*) cJSON_AddNumberToObject(cJSON * const object, const char * const name, const double number) 2123 { 2124 cJSON *number_item = cJSON_CreateNumber(number); 2125 if (add_item_to_object(object, name, number_item, &global_hooks, false)) 2126 { 2127 return number_item; 2128 } 2129 2130 cJSON_Delete(number_item); 2131 return NULL; 2132 } 2133 2134 CJSON_PUBLIC(cJSON*) cJSON_AddStringToObject(cJSON * const object, const char * const name, const char * const string) 2135 { 2136 cJSON *string_item = cJSON_CreateString(string); 2137 if (add_item_to_object(object, name, string_item, &global_hooks, false)) 2138 { 2139 return string_item; 2140 } 2141 2142 cJSON_Delete(string_item); 2143 return NULL; 2144 } 2145 2146 CJSON_PUBLIC(cJSON*) cJSON_AddRawToObject(cJSON * const object, const char * const name, const char * const raw) 2147 { 2148 cJSON *raw_item = cJSON_CreateRaw(raw); 2149 if (add_item_to_object(object, name, raw_item, &global_hooks, false)) 2150 { 2151 return raw_item; 2152 } 2153 2154 cJSON_Delete(raw_item); 2155 return NULL; 2156 } 2157 2158 CJSON_PUBLIC(cJSON*) cJSON_AddObjectToObject(cJSON * const object, const char * const name) 2159 { 2160 cJSON *object_item = cJSON_CreateObject(); 2161 if (add_item_to_object(object, name, object_item, &global_hooks, false)) 2162 { 2163 return object_item; 2164 } 2165 2166 cJSON_Delete(object_item); 2167 return NULL; 2168 } 2169 2170 CJSON_PUBLIC(cJSON*) cJSON_AddArrayToObject(cJSON * const object, const char * const name) 2171 { 2172 cJSON *array = cJSON_CreateArray(); 2173 if (add_item_to_object(object, name, array, &global_hooks, false)) 2174 { 2175 return array; 2176 } 2177 2178 cJSON_Delete(array); 2179 return NULL; 2180 } 2181 2182 CJSON_PUBLIC(cJSON *) cJSON_DetachItemViaPointer(cJSON *parent, cJSON * const item) 2183 { 2184 if ((parent == NULL) || (item == NULL)) 2185 { 2186 return NULL; 2187 } 2188 2189 if (item != parent->child) 2190 { 2191 /* not the first element */ 2192 item->prev->next = item->next; 2193 } 2194 if (item->next != NULL) 2195 { 2196 /* not the last element */ 2197 item->next->prev = item->prev; 2198 } 2199 2200 if (item == parent->child) 2201 { 2202 /* first element */ 2203 parent->child = item->next; 2204 } 2205 /* make sure the detached item doesn't point anywhere anymore */ 2206 item->prev = NULL; 2207 item->next = NULL; 2208 2209 return item; 2210 } 2211 2212 CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromArray(cJSON *array, int which) 2213 { 2214 if (which < 0) 2215 { 2216 return NULL; 2217 } 2218 2219 return cJSON_DetachItemViaPointer(array, get_array_item(array, (size_t)which)); 2220 } 2221 2222 CJSON_PUBLIC(void) cJSON_DeleteItemFromArray(cJSON *array, int which) 2223 { 2224 cJSON_Delete(cJSON_DetachItemFromArray(array, which)); 2225 } 2226 2227 CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObject(cJSON *object, const char *string) 2228 { 2229 cJSON *to_detach = cJSON_GetObjectItem(object, string); 2230 2231 return cJSON_DetachItemViaPointer(object, to_detach); 2232 } 2233 2234 CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObjectCaseSensitive(cJSON *object, const char *string) 2235 { 2236 cJSON *to_detach = cJSON_GetObjectItemCaseSensitive(object, string); 2237 2238 return cJSON_DetachItemViaPointer(object, to_detach); 2239 } 2240 2241 CJSON_PUBLIC(void) cJSON_DeleteItemFromObject(cJSON *object, const char *string) 2242 { 2243 cJSON_Delete(cJSON_DetachItemFromObject(object, string)); 2244 } 2245 2246 CJSON_PUBLIC(void) cJSON_DeleteItemFromObjectCaseSensitive(cJSON *object, const char *string) 2247 { 2248 cJSON_Delete(cJSON_DetachItemFromObjectCaseSensitive(object, string)); 2249 } 2250 2251 /* Replace array/object items with new ones. */ 2252 CJSON_PUBLIC(cJSON_bool) cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem) 2253 { 2254 cJSON *after_inserted = NULL; 2255 2256 if (which < 0) 2257 { 2258 return false; 2259 } 2260 2261 after_inserted = get_array_item(array, (size_t)which); 2262 if (after_inserted == NULL) 2263 { 2264 return add_item_to_array(array, newitem); 2265 } 2266 2267 newitem->next = after_inserted; 2268 newitem->prev = after_inserted->prev; 2269 after_inserted->prev = newitem; 2270 if (after_inserted == array->child) 2271 { 2272 array->child = newitem; 2273 } 2274 else 2275 { 2276 newitem->prev->next = newitem; 2277 } 2278 return true; 2279 } 2280 2281 CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemViaPointer(cJSON * const parent, cJSON * const item, cJSON * replacement) 2282 { 2283 if ((parent == NULL) || (replacement == NULL) || (item == NULL)) 2284 { 2285 return false; 2286 } 2287 2288 if (replacement == item) 2289 { 2290 return true; 2291 } 2292 2293 replacement->next = item->next; 2294 replacement->prev = item->prev; 2295 2296 if (replacement->next != NULL) 2297 { 2298 replacement->next->prev = replacement; 2299 } 2300 if (parent->child == item) 2301 { 2302 parent->child = replacement; 2303 } 2304 else 2305 { /* 2306 * To find the last item in array quickly, we use prev in array. 2307 * We can't modify the last item's next pointer where this item was the parent's child 2308 */ 2309 if (replacement->prev != NULL) 2310 { 2311 replacement->prev->next = replacement; 2312 } 2313 } 2314 2315 item->next = NULL; 2316 item->prev = NULL; 2317 cJSON_Delete(item); 2318 2319 return true; 2320 } 2321 2322 CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem) 2323 { 2324 if (which < 0) 2325 { 2326 return false; 2327 } 2328 2329 return cJSON_ReplaceItemViaPointer(array, get_array_item(array, (size_t)which), newitem); 2330 } 2331 2332 static cJSON_bool replace_item_in_object(cJSON *object, const char *string, cJSON *replacement, cJSON_bool case_sensitive) 2333 { 2334 if ((replacement == NULL) || (string == NULL)) 2335 { 2336 return false; 2337 } 2338 2339 /* replace the name in the replacement */ 2340 if (!(replacement->type & cJSON_StringIsConst) && (replacement->string != NULL)) 2341 { 2342 cJSON_free(replacement->string); 2343 } 2344 replacement->string = (char*)cJSON_strdup((const unsigned char*)string, &global_hooks); 2345 replacement->type &= ~cJSON_StringIsConst; 2346 2347 return cJSON_ReplaceItemViaPointer(object, get_object_item(object, string, case_sensitive), replacement); 2348 } 2349 2350 CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInObject(cJSON *object, const char *string, cJSON *newitem) 2351 { 2352 return replace_item_in_object(object, string, newitem, false); 2353 } 2354 2355 CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInObjectCaseSensitive(cJSON *object, const char *string, cJSON *newitem) 2356 { 2357 return replace_item_in_object(object, string, newitem, true); 2358 } 2359 2360 /* Create basic types: */ 2361 CJSON_PUBLIC(cJSON *) cJSON_CreateNull(void) 2362 { 2363 cJSON *item = cJSON_New_Item(&global_hooks); 2364 if(item) 2365 { 2366 item->type = cJSON_NULL; 2367 } 2368 2369 return item; 2370 } 2371 2372 CJSON_PUBLIC(cJSON *) cJSON_CreateTrue(void) 2373 { 2374 cJSON *item = cJSON_New_Item(&global_hooks); 2375 if(item) 2376 { 2377 item->type = cJSON_True; 2378 } 2379 2380 return item; 2381 } 2382 2383 CJSON_PUBLIC(cJSON *) cJSON_CreateFalse(void) 2384 { 2385 cJSON *item = cJSON_New_Item(&global_hooks); 2386 if(item) 2387 { 2388 item->type = cJSON_False; 2389 } 2390 2391 return item; 2392 } 2393 2394 CJSON_PUBLIC(cJSON *) cJSON_CreateBool(cJSON_bool boolean) 2395 { 2396 cJSON *item = cJSON_New_Item(&global_hooks); 2397 if(item) 2398 { 2399 item->type = boolean ? cJSON_True : cJSON_False; 2400 } 2401 2402 return item; 2403 } 2404 2405 CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num) 2406 { 2407 cJSON *item = cJSON_New_Item(&global_hooks); 2408 if(item) 2409 { 2410 item->type = cJSON_Number; 2411 item->valuedouble = num; 2412 2413 /* use saturation in case of overflow */ 2414 if (num >= INT_MAX) 2415 { 2416 item->valueint = INT_MAX; 2417 } 2418 else if (num <= (double)INT_MIN) 2419 { 2420 item->valueint = INT_MIN; 2421 } 2422 else 2423 { 2424 item->valueint = (int)num; 2425 } 2426 } 2427 2428 return item; 2429 } 2430 2431 CJSON_PUBLIC(cJSON *) cJSON_CreateString(const char *string) 2432 { 2433 cJSON *item = cJSON_New_Item(&global_hooks); 2434 if(item) 2435 { 2436 item->type = cJSON_String; 2437 item->valuestring = (char*)cJSON_strdup((const unsigned char*)string, &global_hooks); 2438 if(!item->valuestring) 2439 { 2440 cJSON_Delete(item); 2441 return NULL; 2442 } 2443 } 2444 2445 return item; 2446 } 2447 2448 CJSON_PUBLIC(cJSON *) cJSON_CreateStringReference(const char *string) 2449 { 2450 cJSON *item = cJSON_New_Item(&global_hooks); 2451 if (item != NULL) 2452 { 2453 item->type = cJSON_String | cJSON_IsReference; 2454 item->valuestring = (char*)cast_away_const(string); 2455 } 2456 2457 return item; 2458 } 2459 2460 CJSON_PUBLIC(cJSON *) cJSON_CreateObjectReference(const cJSON *child) 2461 { 2462 cJSON *item = cJSON_New_Item(&global_hooks); 2463 if (item != NULL) { 2464 item->type = cJSON_Object | cJSON_IsReference; 2465 item->child = (cJSON*)cast_away_const(child); 2466 } 2467 2468 return item; 2469 } 2470 2471 CJSON_PUBLIC(cJSON *) cJSON_CreateArrayReference(const cJSON *child) { 2472 cJSON *item = cJSON_New_Item(&global_hooks); 2473 if (item != NULL) { 2474 item->type = cJSON_Array | cJSON_IsReference; 2475 item->child = (cJSON*)cast_away_const(child); 2476 } 2477 2478 return item; 2479 } 2480 2481 CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw) 2482 { 2483 cJSON *item = cJSON_New_Item(&global_hooks); 2484 if(item) 2485 { 2486 item->type = cJSON_Raw; 2487 item->valuestring = (char*)cJSON_strdup((const unsigned char*)raw, &global_hooks); 2488 if(!item->valuestring) 2489 { 2490 cJSON_Delete(item); 2491 return NULL; 2492 } 2493 } 2494 2495 return item; 2496 } 2497 2498 CJSON_PUBLIC(cJSON *) cJSON_CreateArray(void) 2499 { 2500 cJSON *item = cJSON_New_Item(&global_hooks); 2501 if(item) 2502 { 2503 item->type=cJSON_Array; 2504 } 2505 2506 return item; 2507 } 2508 2509 CJSON_PUBLIC(cJSON *) cJSON_CreateObject(void) 2510 { 2511 cJSON *item = cJSON_New_Item(&global_hooks); 2512 if (item) 2513 { 2514 item->type = cJSON_Object; 2515 } 2516 2517 return item; 2518 } 2519 2520 /* Create Arrays: */ 2521 CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count) 2522 { 2523 size_t i = 0; 2524 cJSON *n = NULL; 2525 cJSON *p = NULL; 2526 cJSON *a = NULL; 2527 2528 if ((count < 0) || (numbers == NULL)) 2529 { 2530 return NULL; 2531 } 2532 2533 a = cJSON_CreateArray(); 2534 for(i = 0; a && (i < (size_t)count); i++) 2535 { 2536 n = cJSON_CreateNumber(numbers[i]); 2537 if (!n) 2538 { 2539 cJSON_Delete(a); 2540 return NULL; 2541 } 2542 if(!i) 2543 { 2544 a->child = n; 2545 } 2546 else 2547 { 2548 suffix_object(p, n); 2549 } 2550 p = n; 2551 } 2552 2553 return a; 2554 } 2555 2556 CJSON_PUBLIC(cJSON *) cJSON_CreateFloatArray(const float *numbers, int count) 2557 { 2558 size_t i = 0; 2559 cJSON *n = NULL; 2560 cJSON *p = NULL; 2561 cJSON *a = NULL; 2562 2563 if ((count < 0) || (numbers == NULL)) 2564 { 2565 return NULL; 2566 } 2567 2568 a = cJSON_CreateArray(); 2569 2570 for(i = 0; a && (i < (size_t)count); i++) 2571 { 2572 n = cJSON_CreateNumber((double)numbers[i]); 2573 if(!n) 2574 { 2575 cJSON_Delete(a); 2576 return NULL; 2577 } 2578 if(!i) 2579 { 2580 a->child = n; 2581 } 2582 else 2583 { 2584 suffix_object(p, n); 2585 } 2586 p = n; 2587 } 2588 2589 return a; 2590 } 2591 2592 CJSON_PUBLIC(cJSON *) cJSON_CreateDoubleArray(const double *numbers, int count) 2593 { 2594 size_t i = 0; 2595 cJSON *n = NULL; 2596 cJSON *p = NULL; 2597 cJSON *a = NULL; 2598 2599 if ((count < 0) || (numbers == NULL)) 2600 { 2601 return NULL; 2602 } 2603 2604 a = cJSON_CreateArray(); 2605 2606 for(i = 0;a && (i < (size_t)count); i++) 2607 { 2608 n = cJSON_CreateNumber(numbers[i]); 2609 if(!n) 2610 { 2611 cJSON_Delete(a); 2612 return NULL; 2613 } 2614 if(!i) 2615 { 2616 a->child = n; 2617 } 2618 else 2619 { 2620 suffix_object(p, n); 2621 } 2622 p = n; 2623 } 2624 2625 return a; 2626 } 2627 2628 CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char *const *strings, int count) 2629 { 2630 size_t i = 0; 2631 cJSON *n = NULL; 2632 cJSON *p = NULL; 2633 cJSON *a = NULL; 2634 2635 if ((count < 0) || (strings == NULL)) 2636 { 2637 return NULL; 2638 } 2639 2640 a = cJSON_CreateArray(); 2641 2642 for (i = 0; a && (i < (size_t)count); i++) 2643 { 2644 n = cJSON_CreateString(strings[i]); 2645 if(!n) 2646 { 2647 cJSON_Delete(a); 2648 return NULL; 2649 } 2650 if(!i) 2651 { 2652 a->child = n; 2653 } 2654 else 2655 { 2656 suffix_object(p,n); 2657 } 2658 p = n; 2659 } 2660 2661 return a; 2662 } 2663 2664 /* Duplication */ 2665 CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse) 2666 { 2667 cJSON *newitem = NULL; 2668 cJSON *child = NULL; 2669 cJSON *next = NULL; 2670 cJSON *newchild = NULL; 2671 2672 /* Bail on bad ptr */ 2673 if (!item) 2674 { 2675 goto fail; 2676 } 2677 /* Create new item */ 2678 newitem = cJSON_New_Item(&global_hooks); 2679 if (!newitem) 2680 { 2681 goto fail; 2682 } 2683 /* Copy over all vars */ 2684 newitem->type = item->type & (~cJSON_IsReference); 2685 newitem->valueint = item->valueint; 2686 newitem->valuedouble = item->valuedouble; 2687 if (item->valuestring) 2688 { 2689 newitem->valuestring = (char*)cJSON_strdup((unsigned char*)item->valuestring, &global_hooks); 2690 if (!newitem->valuestring) 2691 { 2692 goto fail; 2693 } 2694 } 2695 if (item->string) 2696 { 2697 newitem->string = (item->type&cJSON_StringIsConst) ? item->string : (char*)cJSON_strdup((unsigned char*)item->string, &global_hooks); 2698 if (!newitem->string) 2699 { 2700 goto fail; 2701 } 2702 } 2703 /* If non-recursive, then we're done! */ 2704 if (!recurse) 2705 { 2706 return newitem; 2707 } 2708 /* Walk the ->next chain for the child. */ 2709 child = item->child; 2710 while (child != NULL) 2711 { 2712 newchild = cJSON_Duplicate(child, true); /* Duplicate (with recurse) each item in the ->next chain */ 2713 if (!newchild) 2714 { 2715 goto fail; 2716 } 2717 if (next != NULL) 2718 { 2719 /* If newitem->child already set, then crosswire ->prev and ->next and move on */ 2720 next->next = newchild; 2721 newchild->prev = next; 2722 next = newchild; 2723 } 2724 else 2725 { 2726 /* Set newitem->child and move to it */ 2727 newitem->child = newchild; 2728 next = newchild; 2729 } 2730 child = child->next; 2731 } 2732 2733 return newitem; 2734 2735 fail: 2736 if (newitem != NULL) 2737 { 2738 cJSON_Delete(newitem); 2739 } 2740 2741 return NULL; 2742 } 2743 2744 static void skip_oneline_comment(char **input) 2745 { 2746 *input += static_strlen("//"); 2747 2748 for (; (*input)[0] != '\0'; ++(*input)) 2749 { 2750 if ((*input)[0] == '\n') { 2751 *input += static_strlen("\n"); 2752 return; 2753 } 2754 } 2755 } 2756 2757 static void skip_multiline_comment(char **input) 2758 { 2759 *input += static_strlen("/*"); 2760 2761 for (; (*input)[0] != '\0'; ++(*input)) 2762 { 2763 if (((*input)[0] == '*') && ((*input)[1] == '/')) 2764 { 2765 *input += static_strlen("*/"); 2766 return; 2767 } 2768 } 2769 } 2770 2771 static void minify_string(char **input, char **output) { 2772 (*output)[0] = (*input)[0]; 2773 *input += static_strlen("\""); 2774 *output += static_strlen("\""); 2775 2776 2777 for (; (*input)[0] != '\0'; (void)++(*input), ++(*output)) { 2778 (*output)[0] = (*input)[0]; 2779 2780 if ((*input)[0] == '\"') { 2781 (*output)[0] = '\"'; 2782 *input += static_strlen("\""); 2783 *output += static_strlen("\""); 2784 return; 2785 } else if (((*input)[0] == '\\') && ((*input)[1] == '\"')) { 2786 (*output)[1] = (*input)[1]; 2787 *input += static_strlen("\""); 2788 *output += static_strlen("\""); 2789 } 2790 } 2791 } 2792 2793 CJSON_PUBLIC(void) cJSON_Minify(char *json) 2794 { 2795 char *into = json; 2796 2797 if (json == NULL) 2798 { 2799 return; 2800 } 2801 2802 while (json[0] != '\0') 2803 { 2804 switch (json[0]) 2805 { 2806 case ' ': 2807 case '\t': 2808 case '\r': 2809 case '\n': 2810 json++; 2811 break; 2812 2813 case '/': 2814 if (json[1] == '/') 2815 { 2816 skip_oneline_comment(&json); 2817 } 2818 else if (json[1] == '*') 2819 { 2820 skip_multiline_comment(&json); 2821 } else { 2822 json++; 2823 } 2824 break; 2825 2826 case '\"': 2827 minify_string(&json, (char**)&into); 2828 break; 2829 2830 default: 2831 into[0] = json[0]; 2832 json++; 2833 into++; 2834 } 2835 } 2836 2837 /* and null-terminate. */ 2838 *into = '\0'; 2839 } 2840 2841 CJSON_PUBLIC(cJSON_bool) cJSON_IsInvalid(const cJSON * const item) 2842 { 2843 if (item == NULL) 2844 { 2845 return false; 2846 } 2847 2848 return (item->type & 0xFF) == cJSON_Invalid; 2849 } 2850 2851 CJSON_PUBLIC(cJSON_bool) cJSON_IsFalse(const cJSON * const item) 2852 { 2853 if (item == NULL) 2854 { 2855 return false; 2856 } 2857 2858 return (item->type & 0xFF) == cJSON_False; 2859 } 2860 2861 CJSON_PUBLIC(cJSON_bool) cJSON_IsTrue(const cJSON * const item) 2862 { 2863 if (item == NULL) 2864 { 2865 return false; 2866 } 2867 2868 return (item->type & 0xff) == cJSON_True; 2869 } 2870 2871 2872 CJSON_PUBLIC(cJSON_bool) cJSON_IsBool(const cJSON * const item) 2873 { 2874 if (item == NULL) 2875 { 2876 return false; 2877 } 2878 2879 return (item->type & (cJSON_True | cJSON_False)) != 0; 2880 } 2881 CJSON_PUBLIC(cJSON_bool) cJSON_IsNull(const cJSON * const item) 2882 { 2883 if (item == NULL) 2884 { 2885 return false; 2886 } 2887 2888 return (item->type & 0xFF) == cJSON_NULL; 2889 } 2890 2891 CJSON_PUBLIC(cJSON_bool) cJSON_IsNumber(const cJSON * const item) 2892 { 2893 if (item == NULL) 2894 { 2895 return false; 2896 } 2897 2898 return (item->type & 0xFF) == cJSON_Number; 2899 } 2900 2901 CJSON_PUBLIC(cJSON_bool) cJSON_IsString(const cJSON * const item) 2902 { 2903 if (item == NULL) 2904 { 2905 return false; 2906 } 2907 2908 return (item->type & 0xFF) == cJSON_String; 2909 } 2910 2911 CJSON_PUBLIC(cJSON_bool) cJSON_IsArray(const cJSON * const item) 2912 { 2913 if (item == NULL) 2914 { 2915 return false; 2916 } 2917 2918 return (item->type & 0xFF) == cJSON_Array; 2919 } 2920 2921 CJSON_PUBLIC(cJSON_bool) cJSON_IsObject(const cJSON * const item) 2922 { 2923 if (item == NULL) 2924 { 2925 return false; 2926 } 2927 2928 return (item->type & 0xFF) == cJSON_Object; 2929 } 2930 2931 CJSON_PUBLIC(cJSON_bool) cJSON_IsRaw(const cJSON * const item) 2932 { 2933 if (item == NULL) 2934 { 2935 return false; 2936 } 2937 2938 return (item->type & 0xFF) == cJSON_Raw; 2939 } 2940 2941 CJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON * const a, const cJSON * const b, const cJSON_bool case_sensitive) 2942 { 2943 if ((a == NULL) || (b == NULL) || ((a->type & 0xFF) != (b->type & 0xFF)) || cJSON_IsInvalid(a)) 2944 { 2945 return false; 2946 } 2947 2948 /* check if type is valid */ 2949 switch (a->type & 0xFF) 2950 { 2951 case cJSON_False: 2952 case cJSON_True: 2953 case cJSON_NULL: 2954 case cJSON_Number: 2955 case cJSON_String: 2956 case cJSON_Raw: 2957 case cJSON_Array: 2958 case cJSON_Object: 2959 break; 2960 2961 default: 2962 return false; 2963 } 2964 2965 /* identical objects are equal */ 2966 if (a == b) 2967 { 2968 return true; 2969 } 2970 2971 switch (a->type & 0xFF) 2972 { 2973 /* in these cases and equal type is enough */ 2974 case cJSON_False: 2975 case cJSON_True: 2976 case cJSON_NULL: 2977 return true; 2978 2979 case cJSON_Number: 2980 if (compare_double(a->valuedouble, b->valuedouble)) 2981 { 2982 return true; 2983 } 2984 return false; 2985 2986 case cJSON_String: 2987 case cJSON_Raw: 2988 if ((a->valuestring == NULL) || (b->valuestring == NULL)) 2989 { 2990 return false; 2991 } 2992 if (strcmp(a->valuestring, b->valuestring) == 0) 2993 { 2994 return true; 2995 } 2996 2997 return false; 2998 2999 case cJSON_Array: 3000 { 3001 cJSON *a_element = a->child; 3002 cJSON *b_element = b->child; 3003 3004 for (; (a_element != NULL) && (b_element != NULL);) 3005 { 3006 if (!cJSON_Compare(a_element, b_element, case_sensitive)) 3007 { 3008 return false; 3009 } 3010 3011 a_element = a_element->next; 3012 b_element = b_element->next; 3013 } 3014 3015 /* one of the arrays is longer than the other */ 3016 if (a_element != b_element) { 3017 return false; 3018 } 3019 3020 return true; 3021 } 3022 3023 case cJSON_Object: 3024 { 3025 cJSON *a_element = NULL; 3026 cJSON *b_element = NULL; 3027 cJSON_ArrayForEach(a_element, a) 3028 { 3029 /* TODO This has O(n^2) runtime, which is horrible! */ 3030 b_element = get_object_item(b, a_element->string, case_sensitive); 3031 if (b_element == NULL) 3032 { 3033 return false; 3034 } 3035 3036 if (!cJSON_Compare(a_element, b_element, case_sensitive)) 3037 { 3038 return false; 3039 } 3040 } 3041 3042 /* doing this twice, once on a and b to prevent true comparison if a subset of b 3043 * TODO: Do this the proper way, this is just a fix for now */ 3044 cJSON_ArrayForEach(b_element, b) 3045 { 3046 a_element = get_object_item(a, b_element->string, case_sensitive); 3047 if (a_element == NULL) 3048 { 3049 return false; 3050 } 3051 3052 if (!cJSON_Compare(b_element, a_element, case_sensitive)) 3053 { 3054 return false; 3055 } 3056 } 3057 3058 return true; 3059 } 3060 3061 default: 3062 return false; 3063 } 3064 } 3065 3066 CJSON_PUBLIC(void *) cJSON_malloc(size_t size) 3067 { 3068 return global_hooks.allocate(size); 3069 } 3070 3071 CJSON_PUBLIC(void) cJSON_free(void *object) 3072 { 3073 global_hooks.deallocate(object); 3074 }
參考:
https://blog.csdn.net/shizhe0123/article/details/94742514