电商网站的人员团队建设,官网制作价格,上海专业网站营销,数字化校园建设网站一、项目整体框架图 二、项目整体描述
边缘计算网关项目主要实现了智能家居场景和工业物联网场景下设备的数据采集和控制。 整个项目分为三大层#xff1a;用户接口层、网关层、设备层。 其中用户层通过QT客户端、WEB界面及阿里云提供数据展示和用户接口。 网关使用虚拟机代替… 一、项目整体框架图 二、项目整体描述
边缘计算网关项目主要实现了智能家居场景和工业物联网场景下设备的数据采集和控制。 整个项目分为三大层用户接口层、网关层、设备层。 其中用户层通过QT客户端、WEB界面及阿里云提供数据展示和用户接口。 网关使用虚拟机代替基于Linux系统开发起到数据中转作用向下对接设备向上对接客户端及云。 设备家居设备使用STM32单片机自主开发工业设备使用modbus slave软件模拟。 我在整个项目中开发的模块是设备搜索响应模块 设备搜索模块主要完成局域网内网关搜索及配置下发等功能。首先QT客户端会通过UDP广播发送搜索协议搜索进程检测到协议匹配后会进行相应的回复。客户端获取回复同时会获知网关设备的IP地址和端口接下来设备会基于此IP地址和端口建立TCP服务器QT作为客户端连入建立长连接。TCP连接成功后即可完成后续的配置文件下发及心跳包等功能。
三、各模块功能介绍
WEB模块 移植lighttpd作为网关端服务器实现了网关的内置网页功能。通过浏览器访问网关的IP地址即可登录到网关内置网页界面实现了登录、远程设备信息展示和控制等功能。网页发送http请求后lighttpd会将请求转发给cgi通过自行开发的cgi程序进行解析http请求并做出相应的回复。
QT客户端 使用QT开发了桌面客户端通过MQTT协议实现数据的采集协议使用JSON格式解析完成后刷新到界面上。用户操作界面组件下发协议来控制设备。后面的这块需要根据实际情况来描述主界面使用堆栈窗体来布局通过MQTT协议来实现和网关设备的通信。收到来自设备的JSON数据后通过QJson类反序列化得到实际数据然后刷新到相应的界面上。QT客户端主要完成了设备数据的展示、设备命令的控制及历史数据查询等功能。 阿里云模块 使用阿里云的SDK完成阿里云物模型的对接实现了设备数据上传到阿里云平台通过阿里云的在线调试功能可远程实现设备的控制。
数据上报模块 数据上报模块实现了数据从设备到QT客户端的中转首先设备对应的进程会把采集到的数据刷新到共享内存中上报进程从共享内存中轮询数据点根据上报策略来进行上报。上报前会把数据点信息转换为JSON格式通过MQTT上报给QT客户端。客户端下发的JSON指令解析后根据设备转发给具体的进程完成设备的控制。同时上报模块还需要根据用户的设置修改网关的配置参数如上报模式、mqtt服务器地址等。监控模块 移植mjpg-streamer库实现了摄像头数据的采集以及分发。mjpg-streamer通过UVC接口实现了摄像头的图像帧采集通过修改mjpg-streamer源码将采集到的图像帧缓冲区分别通过http协议和UDP协议发送到了网页和QT客户端在两个客户端上实现了视频流展示。STM32采集模块 stm32采集模块实现了stm32设备的通信对接向上通过串口协议采集单片机的数据并刷新到共享内存以便上报模块进程使用。向下接收来自上报模块的JSON控制指令解析后转换为相应的控制指令后通过串口发送给设实现设备的控制。
modbus采集模块 modbus采集模块实现了modbus工业设备的通信对接向上通过modbusTCP协议采集单片机的数据并刷新到共享内存以便上报模块进程使用。向下接收来自上报模块的JSON控制指令解析后转换为标准的modbusTCP指令后通过网络发送给设备实现设备的控制。
单片机设备模块 单片机模拟了智能家居系统的设备场景分别实现了传感器数据采集上报、设备的远程控制等功能。通过ADC采集XXX传感器并按照上报协议通过串口发送给网关设备。接收来自网关的控制指令通过JSON反序列化后进行相应的设备控制。呼吸灯来表示设备运行状态按键模拟墙壁开关同步模拟灯光控制。用到技术点GPIO、串口通信、串口中断、GPIO中断、硬件定时器、ADC采集等。
四、部分代码展示
1. QT端部分代码展示
dialog.h代码
#ifndef DIALOG_H
#define DIALOG_H#include QDialog
#include QtNetwork#include QMessageBox
// 连接类
#include QTcpSocket
// 文本流类
#include QTextStreamnamespace Ui {
class Dialog;
}class Dialog : public QDialog
{Q_OBJECTpublic:explicit Dialog(QWidget *parent 0);~Dialog();QTimer *getTimer() const;void setTimer(QTimer *value);public slots:void on_pushButton_clicked();void on_pushButton_2_clicked();void tcpReadReadSlot();void sendHeartbeat();private:Ui::Dialog *ui;QUdpSocket *sender;QTimer *timer;//QTcpSocket *tcpSocket;// QTcpSocket *client; // 连接类对象void btnConnClickedSlot(); // 连接按钮点击的槽函数void btnSendClickedSlot(); // 发送按钮点击的槽函数void connectedSlot(); // 连接成功的槽函数void disconnectedSlot(); // 连接失败的槽函数
};#endif // DIALOG_Hdialog.cpp代码
#include dialog.h
#include ui_dialog.h
#include string.h
#include QtNetwork
#include QJsonDocument
#include QJsonObject
#include QFile
#include QDebug
#include QCoreApplication
#include QTcpSocket
#include QTimer
#include QByteArray
#include QTextStream
QTcpSocket tcpSocket;
QHostAddress host;
quint16 port;//QString messageliving!;
Dialog::Dialog(QWidget *parent) :QDialog(parent),ui(new Ui::Dialog)
{ui-setupUi(this);// 始终位于前台setWindowFlags(Qt::WindowStaysOnTopHint);sender new QUdpSocket(this);connect(ui-pushButton,SIGNAL(clicked()),this,SLOT(on_pushButton_clicked()));//tcpSocket new QTcpSocket(this);connect(tcpSocket,SIGNAL(readyRead()),this,SLOT(tcpReadReadSlot()));// 创建定时器每隔1秒发送心跳包timer new QTimer(this);connect(timer, QTimer::timeout, this,Dialog::sendHeartbeat);timer-start(1000); // 1000毫秒为间隔}Dialog::~Dialog()
{delete ui;
}void Dialog::on_pushButton_clicked()
{// qDebug() %d,__LINE__;char buf[256] {};QByteArray datagram coffee;sender-writeDatagram(datagram.data(),datagram.size(),QHostAddress(192.168.50.255),8686);sender-readDatagram(buf,sizeof(buf),host,port);if(strcmp(buf, yes) ! 0){return;}// 尝试连接到主机tcpSocket.connectToHost(host,port);if (tcpSocket.waitForConnected(1000)) // 等待连接成功{// 创建JSON对象QJsonObject json;json[type] 1;// 添加其他键值对// 创建JSON文档QJsonDocument jsonDoc(json);// 将JSON文档转换为字节数组QByteArray jsonData jsonDoc.toJson();// 发送JSON数据tcpSocket.write(jsonData);// 等待数据发送完毕if (tcpSocket.waitForBytesWritten()) {// qDebug() JSON data sent successfully1;} else {qDebug() Failed to send JSON data;}}}void Dialog::on_pushButton_2_clicked()
{// 创建JSON对象QJsonObject json;json[type] 3;// 添加其他键值对// 创建JSON文档QJsonDocument jsonDoc(json);// 将JSON文档转换为字节数组QByteArray jsonData jsonDoc.toJson();// 发送JSON数据tcpSocket.write(jsonData);// 等待数据发送完毕if (tcpSocket.waitForBytesWritten()) {// qDebug() JSON data sent successfully1;} else {qDebug() Failed to send JSON data;}// tcpSocket.write(data); // 发送数据//tcpSocket.write(jsonData);//tcpSocket.waitForBytesWritten(); // 等待数据发送成功// tcpSocket.disconnectFromHost(); // 断开连接}void Dialog::tcpReadReadSlot()
{// /接收服务器端消息QTextStream input(tcpSocket);QString text input.readAll();qDebug() text;//根据接收消息判断有无心跳if(text living){// QMessageBox::information(this,提示,持续心跳中);// QMessageBox::warning(this,提示,type 1无内容);return;}//根据接收消息判断有无点表无则下发if(textno){QFile file(D:/example1.json);// QFile file(filename);// QFile file(QCoreApplication::applicationDirPath()/example.txt);if (!file.open(QIODevice::ReadOnly | QIODevice::Text)){qDebug() Failed to open file: file.errorString();return;}else{// 创建一个数据流QDataStream dataStream(tcpSocket);// 设置数据流版本用于跨平台兼容dataStream.setVersion(QDataStream::Qt_5_0);// 读取文件内容QByteArray fileData file.readAll();qDebug()read all fileData;tcpSocket.write(fileData);qDebug() File sent successfully;// 断开连接// tcpSocket.disconnectFromHost();//tcpSocket.waitForDisconnected();}}// //根据接收消息判断点表是否下发成功if(text succeed){QMessageBox::information(this,提示,点表下发成功);// QMessageBox::warning(this,提示,type 1无内容);return;}}void Dialog::sendHeartbeat()
{// 创建JSON对象QJsonObject json;json[type] 3;// 添加其他键值对// 创建JSON文档QJsonDocument jsonDoc(json);// 将JSON文档转换为字节数组QByteArray jsonData jsonDoc.toJson();// 发送JSON数据tcpSocket.write(jsonData);// 等待数据发送完毕if (tcpSocket.waitForBytesWritten()) {// qDebug() JSON data sent successfully1;} else {qDebug() Failed to send JSON data;}}dialog.ui代码
?xml version1.0 encodingUTF-8?
ui version4.0classDialog/classwidget classQDialog nameDialogproperty namegeometryrectx0/xy0/ywidth486/widthheight325/height/rect/propertyproperty namewindowTitlestringDialog/string/propertylayout classQVBoxLayout nameverticalLayout_2itemlayout classQVBoxLayout nameverticalLayoutitemwidget classQPushButton namepushButtonproperty nametextstring下发点表/string/property/widget/itemitemwidget classQPushButton namepushButton_2property nametextstring心跳/string/property/widget/item/layout/item/layout/widgetlayoutdefault spacing6 margin11/resources/connections/
/ui2. 网关层部分代码展示
dev.c代码
#include stdio.h
#include sys/types.h
#include sys/socket.h
#include netinet/in.h
#include netinet/ip.h
#include arpa/inet.h
#include unistd.h
#include stdlib.h
#include sys/stat.h
#include fcntl.h
#include string.h
#include cJSON.h
#define N 64
void saveToFile(const char *data);
void parseJSON(const char *json);
int main(int argc, char const *argv[])
{int broadfd;//创建一个socket文件描述符broadfd socket(AF_INET, SOCK_DGRAM, 0);if (broadfd 0){perror(sock err);return -1;}//绑定套接字(ipport)struct sockaddr_in addr;addr.sin_family AF_INET;addr.sin_port htons(8686); //端口号addr.sin_addr.s_addr INADDR_ANY;int addrlen sizeof(addr);if (bind(broadfd, (struct sockaddr *)addr, addrlen) 0){perror(bind err);return -1;}ssize_t len;char buf[N] {0};struct sockaddr_in cliaddr, caddr;//接收coffee搜索包bzero(buf, N);len recvfrom(broadfd, buf, N, 0, (struct sockaddr *)cliaddr, addrlen);//判断是否是本公司产品收到的数据是否coffeeif (strcmp(buf, coffee) ! 0){printf(not my coffee\n);return -1;}//回复yes告诉软件我收到了搜索协议并且回复地址sendto(broadfd, yes, 4, 0, (struct sockaddr *)cliaddr, addrlen);//变身为TCP服务器准备接收软件的升级文件int tcpfd socket(AF_INET, SOCK_STREAM, 0);if (tcpfd 0){perror(sock err);return -1;}if (bind(tcpfd, (struct sockaddr *)addr, addrlen) 0){perror(bind err);return -1;}//监听套接字if (listen(tcpfd, 5) 0){perror(listen err);return -1;}//接收客户端的连接printf(wait client connect\n);int clifd;socklen_t len1 sizeof(caddr);clifd accept(tcpfd, (struct sockaddr *)caddr, len1);if (clifd 0){perror(accept err);return -1;}// printf(new cononect coming\n);// printf(tcpfd:%d clifd:%d\n, tcpfd, clifd);// printf(client:ip%s port%d\n, inet_ntoa(caddr.sin_addr),// ntohs(caddr.sin_port));char buf2[3000] {0};char buf3[] no;char buf4[7] living;//size_t recvbyte1;size_t recvbyte;
loop:while (1){recvbyte recv(clifd, buf2, sizeof(buf2), 0);//printf(recvbyte %d\n, recvbyte);if (recvbyte 0){//printf(Received data: %s, buf2);cJSON *root cJSON_Parse(buf2);if (cJSON_HasObjectItem(root,version) ){char buf5[8] succeed;// printf(Failed to parse JSON data.\n);saveToFile(buf2);if (send(clifd, buf5, strlen(buf5), 0) 0){perror(Sending data failed.);}printf(Succeeded in delivering the point table.\n) ;goto loop;// return 0;}cJSON *item cJSON_GetObjectItem(root, type);int type item-valueint;//printf(Type: %d\n, type);if (type 1){if (send(clifd, buf3, strlen(buf3), 0) 0){perror(Sending data failed.);}goto loop;// printf(%d %s, strlen(buf3), buf3);//send(clifd, buf3, sizeof(bud3), 0);//saveToFile(buf2);}else if (type 3){if (send(clifd, buf4, strlen(buf4), 0) 0){perror(Sending data failed.);}// printf(%d %s\n, strlen(buf4), buf4);//send(clifd, buf4, strlen(buf4), 0);goto loop;//saveToFile(buf2);}}}
}void saveToFile(const char *data)
{FILE *file fopen(/text.txt, w);if (file NULL){perror(Failed to open file);exit(1);}fprintf(file, %s, data);fclose(file);
}Makefile代码
#指定生成的文件名
OJB_OUT dev#指定每一个c文件对应的.o文件
OBJS dev.o #指定编译器
CC gcc#指定需要的库和路径
ULDFLAGS cJSON.c -lm###########################################
#以下的内容不需要修改
###########################################
all:$(OJB_OUT)$(OJB_OUT):$(OBJS)$(CC) -o $ $^ $(ULDFLAGS)dep_files : $(foreach f,$(OBJS),.$(f).d)
dep_files : $(wildcard $(dep_files))ifneq ($(dep_files),)include $(dep_files)
endif$(OBJS):%.o:%.c$(CC) -Wp,-MD,.$.d -c $ -o $clean:rm -rf .*.o.d *.o $(OJB_OUT)
cJSON.h代码
/*Copyright (c) 2009 Dave GamblePermission is hereby granted, free of charge, to any person obtaining a copyof this software and associated documentation files (the Software), to dealin the Software without restriction, including without limitation the rightsto use, copy, modify, merge, publish, distribute, sublicense, and/or sellcopies of the Software, and to permit persons to whom the Software isfurnished to do so, subject to the following conditions:The above copyright notice and this permission notice shall be included inall copies or substantial portions of the Software.THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS ORIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THEAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHERLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS INTHE SOFTWARE.
*/#ifndef cJSON__h
#define cJSON__h#include stddef.h#ifdef __cplusplus
extern C
{
#endif/* cJSON Types: */
#define cJSON_False 0
#define cJSON_True 1
#define cJSON_NULL 2
#define cJSON_Number 3
#define cJSON_String 4
#define cJSON_Array 5
#define cJSON_Object 6#define cJSON_IsReference 256
#define cJSON_StringIsConst 512/* The cJSON structure: */
typedef struct cJSON {struct cJSON *next,*prev; /* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */struct cJSON *child; /* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */int type; /* The type of the item, as above. */char *valuestring; /* The items string, if typecJSON_String */int valueint; /* The items number, if typecJSON_Number */double valuedouble; /* The items number, if typecJSON_Number */char *string; /* The items name string, if this item is the child of, or is in the list of subitems of an object. */
} cJSON;typedef struct cJSON_Hooks {void *(*malloc_fn)(size_t sz);void (*free_fn)(void *ptr);
} cJSON_Hooks;/* Supply malloc, realloc and free functions to cJSON */
extern void cJSON_InitHooks(cJSON_Hooks* hooks);/* Supply a block of JSON, and this returns a cJSON object you can interrogate. Call cJSON_Delete when finished. */
extern cJSON *cJSON_Parse(const char *value);
/* Render a cJSON entity to text for transfer/storage. Free the char* when finished. */
extern char *cJSON_Print(cJSON *item);
/* Render a cJSON entity to text for transfer/storage without any formatting. Free the char* when finished. */
extern char *cJSON_PrintUnformatted(cJSON *item);
/* Render a cJSON entity to text using a buffered strategy. prebuffer is a guess at the final size. guessing well reduces reallocation. fmt0 gives unformatted, 1 gives formatted */
extern char *cJSON_PrintBuffered(cJSON *item,int prebuffer,int fmt);
/* Delete a cJSON entity and all subentities. */
extern void cJSON_Delete(cJSON *c);/* Returns the number of items in an array (or object). */
extern int cJSON_GetArraySize(cJSON *array);
/* Retrieve item number item from array array. Returns NULL if unsuccessful. */
extern cJSON *cJSON_GetArrayItem(cJSON *array,int item);
/* Get item string from object. Case insensitive. */
extern cJSON *cJSON_GetObjectItem(cJSON *object,const char *string);
extern int cJSON_HasObjectItem(cJSON *object,const char *string);
/* For analysing failed parses. This returns a pointer to the parse error. Youll probably need to look a few chars back to make sense of it. Defined when cJSON_Parse() returns 0. 0 when cJSON_Parse() succeeds. */
extern const char *cJSON_GetErrorPtr(void);/* These calls create a cJSON item of the appropriate type. */
extern cJSON *cJSON_CreateNull(void);
extern cJSON *cJSON_CreateTrue(void);
extern cJSON *cJSON_CreateFalse(void);
extern cJSON *cJSON_CreateBool(int b);
extern cJSON *cJSON_CreateNumber(double num);
extern cJSON *cJSON_CreateString(const char *string);
extern cJSON *cJSON_CreateArray(void);
extern cJSON *cJSON_CreateObject(void);/* These utilities create an Array of count items. */
extern cJSON *cJSON_CreateIntArray(const int *numbers,int count);
extern cJSON *cJSON_CreateFloatArray(const float *numbers,int count);
extern cJSON *cJSON_CreateDoubleArray(const double *numbers,int count);
extern cJSON *cJSON_CreateStringArray(const char **strings,int count);/* Append item to the specified array/object. */
extern void cJSON_AddItemToArray(cJSON *array, cJSON *item);
extern void cJSON_AddItemToObject(cJSON *object,const char *string,cJSON *item);
extern void cJSON_AddItemToObjectCS(cJSON *object,const char *string,cJSON *item); /* Use this when string is definitely const (i.e. a literal, or as good as), and will definitely survive the cJSON object */
/* Append reference to item to the specified array/object. Use this when you want to add an existing cJSON to a new cJSON, but dont want to corrupt your existing cJSON. */
extern void cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item);
extern void cJSON_AddItemReferenceToObject(cJSON *object,const char *string,cJSON *item);/* Remove/Detatch items from Arrays/Objects. */
extern cJSON *cJSON_DetachItemFromArray(cJSON *array,int which);
extern void cJSON_DeleteItemFromArray(cJSON *array,int which);
extern cJSON *cJSON_DetachItemFromObject(cJSON *object,const char *string);
extern void cJSON_DeleteItemFromObject(cJSON *object,const char *string);/* Update array items. */
extern void cJSON_InsertItemInArray(cJSON *array,int which,cJSON *newitem); /* Shifts pre-existing items to the right. */
extern void cJSON_ReplaceItemInArray(cJSON *array,int which,cJSON *newitem);
extern void cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem);/* Duplicate a cJSON item */
extern cJSON *cJSON_Duplicate(cJSON *item,int recurse);
/* Duplicate will create a new, identical cJSON item to the one you pass, in new memory that will
need to be released. With recurse!0, it will duplicate any children connected to the item.
The item-next and -prev pointers are always zero on return from Duplicate. *//* ParseWithOpts allows you to require (and check) that the JSON is null terminated, and to retrieve the pointer to the final byte parsed. */
extern cJSON *cJSON_ParseWithOpts(const char *value,const char **return_parse_end,int require_null_terminated);extern void cJSON_Minify(char *json);/* Macros for creating things quickly. */
#define cJSON_AddNullToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateNull())
#define cJSON_AddTrueToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateTrue())
#define cJSON_AddFalseToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateFalse())
#define cJSON_AddBoolToObject(object,name,b) cJSON_AddItemToObject(object, name, cJSON_CreateBool(b))
#define cJSON_AddNumberToObject(object,name,n) cJSON_AddItemToObject(object, name, cJSON_CreateNumber(n))
#define cJSON_AddStringToObject(object,name,s) cJSON_AddItemToObject(object, name, cJSON_CreateString(s))/* When assigning an integer value, it needs to be propagated to valuedouble too. */
#define cJSON_SetIntValue(object,val) ((object)?(object)-valueint(object)-valuedouble(val):(val))
#define cJSON_SetNumberValue(object,val) ((object)?(object)-valueint(object)-valuedouble(val):(val))/* Macro for iterating over an array */
#define cJSON_ArrayForEach(pos, head) for(pos (head)-child; pos ! NULL; pos pos-next)#ifdef __cplusplus
}
#endif#endifcJSON.c代码:
/*Copyright (c) 2009 Dave GamblePermission is hereby granted, free of charge, to any person obtaining a copyof this software and associated documentation files (the Software), to dealin the Software without restriction, including without limitation the rightsto use, copy, modify, merge, publish, distribute, sublicense, and/or sellcopies of the Software, and to permit persons to whom the Software isfurnished to do so, subject to the following conditions:The above copyright notice and this permission notice shall be included inall copies or substantial portions of the Software.THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS ORIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THEAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHERLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS INTHE SOFTWARE.
*//* cJSON */
/* JSON parser in C. */#include string.h
#include stdio.h
#include math.h
#include stdlib.h
#include float.h
#include limits.h
#include ctype.h
#include cJSON.hstatic const char *ep;const char *cJSON_GetErrorPtr(void) {return ep;}static int cJSON_strcasecmp(const char *s1,const char *s2)
{if (!s1) return (s1s2)?0:1;if (!s2) return 1;for(; tolower(*s1) tolower(*s2); s1, s2) if(*s1 0) return 0;return tolower(*(const unsigned char *)s1) - tolower(*(const unsigned char *)s2);
}static void *(*cJSON_malloc)(size_t sz) malloc;
static void (*cJSON_free)(void *ptr) free;static char* cJSON_strdup(const char* str)
{size_t len;char* copy;len strlen(str) 1;if (!(copy (char*)cJSON_malloc(len))) return 0;memcpy(copy,str,len);return copy;
}void cJSON_InitHooks(cJSON_Hooks* hooks)
{if (!hooks) { /* Reset hooks */cJSON_malloc malloc;cJSON_free free;return;}cJSON_malloc (hooks-malloc_fn)?hooks-malloc_fn:malloc;cJSON_free (hooks-free_fn)?hooks-free_fn:free;
}/* Internal constructor. */
static cJSON *cJSON_New_Item(void)
{cJSON* node (cJSON*)cJSON_malloc(sizeof(cJSON));if (node) memset(node,0,sizeof(cJSON));return node;
}/* Delete a cJSON structure. */
void cJSON_Delete(cJSON *c)
{cJSON *next;while (c){nextc-next;if (!(c-typecJSON_IsReference) c-child) cJSON_Delete(c-child);if (!(c-typecJSON_IsReference) c-valuestring) cJSON_free(c-valuestring);if (!(c-typecJSON_StringIsConst) c-string) cJSON_free(c-string);cJSON_free(c);cnext;}
}/* Parse the input text to generate a number, and populate the result into item. */
static const char *parse_number(cJSON *item,const char *num)
{double n0,sign1,scale0;int subscale0,signsubscale1;if (*num-) sign-1,num; /* Has sign? */if (*num0) num; /* is zero */if (*num1 *num9) do n(n*10.0)(*num -0); while (*num0 *num9); /* Number? */if (*num. num[1]0 num[1]9) {num; do n(n*10.0)(*num -0),scale--; while (*num0 *num9);} /* Fractional part? */if (*nume || *numE) /* Exponent? */{ num;if (*num) num; else if (*num-) signsubscale-1,num; /* With sign? */while (*num0 *num9) subscale(subscale*10)(*num - 0); /* Number? */}nsign*n*pow(10.0,(scalesubscale*signsubscale)); /* number /- number.fraction * 10^/- exponent */item-valuedoublen;item-valueint(int)n;item-typecJSON_Number;return num;
}static int pow2gt (int x) { --x; x|x1; x|x2; x|x4; x|x8; x|x16; return x1; }typedef struct {char *buffer; int length; int offset; } printbuffer;static char* ensure(printbuffer *p,int needed)
{char *newbuffer;int newsize;if (!p || !p-buffer) return 0;neededp-offset;if (neededp-length) return p-bufferp-offset;newsizepow2gt(needed);newbuffer(char*)cJSON_malloc(newsize);if (!newbuffer) {cJSON_free(p-buffer);p-length0,p-buffer0;return 0;}if (newbuffer) memcpy(newbuffer,p-buffer,p-length);cJSON_free(p-buffer);p-lengthnewsize;p-buffernewbuffer;return newbufferp-offset;
}static int update(printbuffer *p)
{char *str;if (!p || !p-buffer) return 0;strp-bufferp-offset;return p-offsetstrlen(str);
}/* Render the number nicely from the given item into a string. */
static char *print_number(cJSON *item,printbuffer *p)
{char *str0;double ditem-valuedouble;if (d0){if (p) strensure(p,2);else str(char*)cJSON_malloc(2); /* special case for 0. */if (str) strcpy(str,0);}else if (fabs(((double)item-valueint)-d)DBL_EPSILON dINT_MAX dINT_MIN){if (p) strensure(p,21);else str(char*)cJSON_malloc(21); /* 2^641 can be represented in 21 chars. */if (str) sprintf(str,%d,item-valueint);}else{if (p) strensure(p,64);else str(char*)cJSON_malloc(64); /* This is a nice tradeoff. */if (str){if (fpclassify(d) ! FP_ZERO !isnormal(d)) sprintf(str,null);else if (fabs(floor(d)-d)DBL_EPSILON fabs(d)1.0e60) sprintf(str,%.0f,d);else if (fabs(d)1.0e-6 || fabs(d)1.0e9) sprintf(str,%e,d);else sprintf(str,%f,d);}}return str;
}static unsigned parse_hex4(const char *str)
{unsigned h0;if (*str0 *str9) h(*str)-0; else if (*strA *strF) h10(*str)-A; else if (*stra *strf) h10(*str)-a; else return 0;hh4;str;if (*str0 *str9) h(*str)-0; else if (*strA *strF) h10(*str)-A; else if (*stra *strf) h10(*str)-a; else return 0;hh4;str;if (*str0 *str9) h(*str)-0; else if (*strA *strF) h10(*str)-A; else if (*stra *strf) h10(*str)-a; else return 0;hh4;str;if (*str0 *str9) h(*str)-0; else if (*strA *strF) h10(*str)-A; else if (*stra *strf) h10(*str)-a; else return 0;return h;
}/* Parse the input text into an unescaped cstring, and populate item. */
static const unsigned char firstByteMark[7] { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
static const char *parse_string(cJSON *item,const char *str)
{const char *ptrstr1;char *ptr2;char *out;int len0;unsigned uc,uc2;if (*str!\) {epstr;return 0;} /* not a string! */while (*ptr!\ *ptr len) if (*ptr \\) ptr; /* Skip escaped quotes. */out(char*)cJSON_malloc(len1); /* This is how long we need for the string, roughly. */if (!out) return 0;ptrstr1;ptr2out;while (*ptr!\ *ptr){if (*ptr!\\) *ptr2*ptr;else{ptr;switch (*ptr){case b: *ptr2\b; break;case f: *ptr2\f; break;case n: *ptr2\n; break;case r: *ptr2\r; break;case t: *ptr2\t; break;case u: /* transcode utf16 to utf8. */ucparse_hex4(ptr1);ptr4; /* get the unicode char. */if ((uc0xDC00 uc0xDFFF) || uc0) break; /* check for invalid. */if (uc0xD800 uc0xDBFF) /* UTF16 surrogate pairs. */{if (ptr[1]!\\ || ptr[2]!u) break; /* missing second-half of surrogate. */uc2parse_hex4(ptr3);ptr6;if (uc20xDC00 || uc20xDFFF) break; /* invalid second-half of surrogate. */uc0x10000 (((uc0x3FF)10) | (uc20x3FF));}len4;if (uc0x80) len1;else if (uc0x800) len2;else if (uc0x10000) len3; ptr2len;switch (len) {case 4: *--ptr2 ((uc | 0x80) 0xBF); uc 6;case 3: *--ptr2 ((uc | 0x80) 0xBF); uc 6;case 2: *--ptr2 ((uc | 0x80) 0xBF); uc 6;case 1: *--ptr2 (uc | firstByteMark[len]);}ptr2len;break;default: *ptr2*ptr; break;}ptr;}}*ptr20;if (*ptr\) ptr;item-valuestringout;item-typecJSON_String;return ptr;
}/* Render the cstring provided to an escaped version that can be printed. */
static char *print_string_ptr(const char *str,printbuffer *p)
{const char *ptr;char *ptr2,*out;int len0,flag0;unsigned char token;for (ptrstr;*ptr;ptr) flag|((*ptr0 *ptr32)||(*ptr\)||(*ptr\\))?1:0;if (!flag){lenptr-str;if (p) outensure(p,len3);else out(char*)cJSON_malloc(len3);if (!out) return 0;ptr2out;*ptr2\;strcpy(ptr2,str);ptr2[len]\;ptr2[len1]0;return out;}if (!str){if (p) outensure(p,3);else out(char*)cJSON_malloc(3);if (!out) return 0;strcpy(out,\\);return out;}ptrstr;while ((token*ptr) len) {if (strchr(\\\\b\f\n\r\t,token)) len; else if (token32) len5;ptr;}if (p) outensure(p,len3);else out(char*)cJSON_malloc(len3);if (!out) return 0;ptr2out;ptrstr;*ptr2\;while (*ptr){if ((unsigned char)*ptr31 *ptr!\ *ptr!\\) *ptr2*ptr;else{*ptr2\\;switch (token*ptr){case \\: *ptr2\\; break;case \: *ptr2\; break;case \b: *ptr2b; break;case \f: *ptr2f; break;case \n: *ptr2n; break;case \r: *ptr2r; break;case \t: *ptr2t; break;default: sprintf(ptr2,u%04x,token);ptr25; break; /* escape and print */}}}*ptr2\;*ptr20;return out;
}
/* Invote print_string_ptr (which is useful) on an item. */
static char *print_string(cJSON *item,printbuffer *p) {return print_string_ptr(item-valuestring,p);}/* Predeclare these prototypes. */
static const char *parse_value(cJSON *item,const char *value);
static char *print_value(cJSON *item,int depth,int fmt,printbuffer *p);
static const char *parse_array(cJSON *item,const char *value);
static char *print_array(cJSON *item,int depth,int fmt,printbuffer *p);
static const char *parse_object(cJSON *item,const char *value);
static char *print_object(cJSON *item,int depth,int fmt,printbuffer *p);/* Utility to jump whitespace and cr/lf */
static const char *skip(const char *in) {while (in *in (unsigned char)*in32) in; return in;}/* Parse an object - create a new root, and populate. */
cJSON *cJSON_ParseWithOpts(const char *value,const char **return_parse_end,int require_null_terminated)
{const char *end0;cJSON *ccJSON_New_Item();ep0;if (!c) return 0; /* memory fail */endparse_value(c,skip(value));if (!end) {cJSON_Delete(c);return 0;} /* parse failure. ep is set. *//* if we require null-terminated JSON without appended garbage, skip and then check for a null terminator */if (require_null_terminated) {endskip(end);if (*end) {cJSON_Delete(c);epend;return 0;}}if (return_parse_end) *return_parse_endend;return c;
}
/* Default options for cJSON_Parse */
cJSON *cJSON_Parse(const char *value) {return cJSON_ParseWithOpts(value,0,0);}/* Render a cJSON item/entity/structure to text. */
char *cJSON_Print(cJSON *item) {return print_value(item,0,1,0);}
char *cJSON_PrintUnformatted(cJSON *item) {return print_value(item,0,0,0);}char *cJSON_PrintBuffered(cJSON *item,int prebuffer,int fmt)
{printbuffer p;p.buffer(char*)cJSON_malloc(prebuffer);p.lengthprebuffer;p.offset0;return print_value(item,0,fmt,p);return p.buffer;
}/* Parser core - when encountering text, process appropriately. */
static const char *parse_value(cJSON *item,const char *value)
{if (!value) return 0; /* Fail on null. */if (!strncmp(value,null,4)) { item-typecJSON_NULL; return value4; }if (!strncmp(value,false,5)) { item-typecJSON_False; return value5; }if (!strncmp(value,true,4)) { item-typecJSON_True; item-valueint1; return value4; }if (*value\) { return parse_string(item,value); }if (*value- || (*value0 *value9)) { return parse_number(item,value); }if (*value[) { return parse_array(item,value); }if (*value{) { return parse_object(item,value); }epvalue;return 0; /* failure. */
}/* Render a value to text. */
static char *print_value(cJSON *item,int depth,int fmt,printbuffer *p)
{char *out0;if (!item) return 0;if (p){switch ((item-type)255){case cJSON_NULL: {outensure(p,5); if (out) strcpy(out,null); break;}case cJSON_False: {outensure(p,6); if (out) strcpy(out,false); break;}case cJSON_True: {outensure(p,5); if (out) strcpy(out,true); break;}case cJSON_Number: outprint_number(item,p);break;case cJSON_String: outprint_string(item,p);break;case cJSON_Array: outprint_array(item,depth,fmt,p);break;case cJSON_Object: outprint_object(item,depth,fmt,p);break;}}else{switch ((item-type)255){case cJSON_NULL: outcJSON_strdup(null); break;case cJSON_False: outcJSON_strdup(false);break;case cJSON_True: outcJSON_strdup(true); break;case cJSON_Number: outprint_number(item,0);break;case cJSON_String: outprint_string(item,0);break;case cJSON_Array: outprint_array(item,depth,fmt,0);break;case cJSON_Object: outprint_object(item,depth,fmt,0);break;}}return out;
}/* Build an array from input text. */
static const char *parse_array(cJSON *item,const char *value)
{cJSON *child;if (*value![) {epvalue;return 0;} /* not an array! */item-typecJSON_Array;valueskip(value1);if (*value]) return value1; /* empty array. */item-childchildcJSON_New_Item();if (!item-child) return 0; /* memory fail */valueskip(parse_value(child,skip(value))); /* skip any spacing, get the value. */if (!value) return 0;while (*value,){cJSON *new_item;if (!(new_itemcJSON_New_Item())) return 0; /* memory fail */child-nextnew_item;new_item-prevchild;childnew_item;valueskip(parse_value(child,skip(value1)));if (!value) return 0; /* memory fail */}if (*value]) return value1; /* end of array */epvalue;return 0; /* malformed. */
}/* Render an array to text */
static char *print_array(cJSON *item,int depth,int fmt,printbuffer *p)
{char **entries;char *out0,*ptr,*ret;int len5;cJSON *childitem-child;int numentries0,i0,fail0;size_t tmplen0;/* How many entries in the array? */while (child) numentries,childchild-next;/* Explicitly handle numentries0 */if (!numentries){if (p) outensure(p,3);else out(char*)cJSON_malloc(3);if (out) strcpy(out,[]);return out;}if (p){/* Compose the output array. */ip-offset;ptrensure(p,1);if (!ptr) return 0; *ptr[; p-offset;childitem-child;while (child !fail){print_value(child,depth1,fmt,p);p-offsetupdate(p);if (child-next) {lenfmt?2:1;ptrensure(p,len1);if (!ptr) return 0;*ptr,;if(fmt)*ptr ;*ptr0;p-offsetlen;}childchild-next;}ptrensure(p,2);if (!ptr) return 0; *ptr];*ptr0;out(p-buffer)i;}else{/* Allocate an array to hold the values for each */entries(char**)cJSON_malloc(numentries*sizeof(char*));if (!entries) return 0;memset(entries,0,numentries*sizeof(char*));/* Retrieve all the results: */childitem-child;while (child !fail){retprint_value(child,depth1,fmt,0);entries[i]ret;if (ret) lenstrlen(ret)2(fmt?1:0); else fail1;childchild-next;}/* If we didnt fail, try to malloc the output string */if (!fail) out(char*)cJSON_malloc(len);/* If that fails, we fail. */if (!out) fail1;/* Handle failure. */if (fail){for (i0;inumentries;i) if (entries[i]) cJSON_free(entries[i]);cJSON_free(entries);return 0;}/* Compose the output array. */*out[;ptrout1;*ptr0;for (i0;inumentries;i){tmplenstrlen(entries[i]);memcpy(ptr,entries[i],tmplen);ptrtmplen;if (i!numentries-1) {*ptr,;if(fmt)*ptr ;*ptr0;}cJSON_free(entries[i]);}cJSON_free(entries);*ptr];*ptr0;}return out;
}/* Build an object from the text. */
static const char *parse_object(cJSON *item,const char *value)
{cJSON *child;if (*value!{) {epvalue;return 0;} /* not an object! */item-typecJSON_Object;valueskip(value1);if (*value}) return value1; /* empty array. */item-childchildcJSON_New_Item();if (!item-child) return 0;valueskip(parse_string(child,skip(value)));if (!value) return 0;child-stringchild-valuestring;child-valuestring0;if (*value!:) {epvalue;return 0;} /* fail! */valueskip(parse_value(child,skip(value1))); /* skip any spacing, get the value. */if (!value) return 0;while (*value,){cJSON *new_item;if (!(new_itemcJSON_New_Item())) return 0; /* memory fail */child-nextnew_item;new_item-prevchild;childnew_item;valueskip(parse_string(child,skip(value1)));if (!value) return 0;child-stringchild-valuestring;child-valuestring0;if (*value!:) {epvalue;return 0;} /* fail! */valueskip(parse_value(child,skip(value1))); /* skip any spacing, get the value. */if (!value) return 0;}if (*value}) return value1; /* end of array */epvalue;return 0; /* malformed. */
}/* Render an object to text. */
static char *print_object(cJSON *item,int depth,int fmt,printbuffer *p)
{char **entries0,**names0;char *out0,*ptr,*ret,*str;int len7,i0,j;cJSON *childitem-child;int numentries0,fail0;size_t tmplen0;/* Count the number of entries. */while (child) numentries,childchild-next;/* Explicitly handle empty object case */if (!numentries){if (p) outensure(p,fmt?depth4:3);else out(char*)cJSON_malloc(fmt?depth4:3);if (!out) return 0;ptrout;*ptr{;if (fmt) {*ptr\n;for (i0;idepth-1;i) *ptr\t;}*ptr};*ptr0;return out;}if (p){/* Compose the output: */ip-offset;lenfmt?2:1; ptrensure(p,len1); if (!ptr) return 0;*ptr{; if (fmt) *ptr\n; *ptr0; p-offsetlen;childitem-child;depth;while (child){if (fmt){ptrensure(p,depth); if (!ptr) return 0;for (j0;jdepth;j) *ptr\t;p-offsetdepth;}print_string_ptr(child-string,p);p-offsetupdate(p);lenfmt?2:1;ptrensure(p,len); if (!ptr) return 0;*ptr:;if (fmt) *ptr\t;p-offsetlen;print_value(child,depth,fmt,p);p-offsetupdate(p);len(fmt?1:0)(child-next?1:0);ptrensure(p,len1); if (!ptr) return 0;if (child-next) *ptr,;if (fmt) *ptr\n;*ptr0;p-offsetlen;childchild-next;}ptrensure(p,fmt?(depth1):2); if (!ptr) return 0;if (fmt) for (i0;idepth-1;i) *ptr\t;*ptr};*ptr0;out(p-buffer)i;}else{/* Allocate space for the names and the objects */entries(char**)cJSON_malloc(numentries*sizeof(char*));if (!entries) return 0;names(char**)cJSON_malloc(numentries*sizeof(char*));if (!names) {cJSON_free(entries);return 0;}memset(entries,0,sizeof(char*)*numentries);memset(names,0,sizeof(char*)*numentries);/* Collect all the results into our arrays: */childitem-child;depth;if (fmt) lendepth;while (child !fail){names[i]strprint_string_ptr(child-string,0);entries[i]retprint_value(child,depth,fmt,0);if (str ret) lenstrlen(ret)strlen(str)2(fmt?2depth:0); else fail1;childchild-next;}/* Try to allocate the output string */if (!fail) out(char*)cJSON_malloc(len);if (!out) fail1;/* Handle failure */if (fail){for (i0;inumentries;i) {if (names[i]) cJSON_free(names[i]);if (entries[i]) cJSON_free(entries[i]);}cJSON_free(names);cJSON_free(entries);return 0;}/* Compose the output: */*out{;ptrout1;if (fmt)*ptr\n;*ptr0;for (i0;inumentries;i){if (fmt) for (j0;jdepth;j) *ptr\t;tmplenstrlen(names[i]);memcpy(ptr,names[i],tmplen);ptrtmplen;*ptr:;if (fmt) *ptr\t;strcpy(ptr,entries[i]);ptrstrlen(entries[i]);if (i!numentries-1) *ptr,;if (fmt) *ptr\n;*ptr0;cJSON_free(names[i]);cJSON_free(entries[i]);}cJSON_free(names);cJSON_free(entries);if (fmt) for (i0;idepth-1;i) *ptr\t;*ptr};*ptr0;}return out;
}/* Get Array size/item / object item. */
int cJSON_GetArraySize(cJSON *array) {cJSON *carray-child;int i0;while(c)i,cc-next;return i;}
cJSON *cJSON_GetArrayItem(cJSON *array,int item) {cJSON *carray-child; while (c item0) item--,cc-next; return c;}
cJSON *cJSON_GetObjectItem(cJSON *object,const char *string) {cJSON *cobject-child; while (c cJSON_strcasecmp(c-string,string)) cc-next; return c;}
int cJSON_HasObjectItem(cJSON *object,const char *string) {cJSON *cobject-child;while (c ){if(cJSON_strcasecmp(c-string,string)0){return 1;}cc-next;}return 0;
}/* Utility for array list handling. */
static void suffix_object(cJSON *prev,cJSON *item) {prev-nextitem;item-prevprev;}
/* Utility for handling references. */
static cJSON *create_reference(cJSON *item) {cJSON *refcJSON_New_Item();if (!ref) return 0;memcpy(ref,item,sizeof(cJSON));ref-string0;ref-type|cJSON_IsReference;ref-nextref-prev0;return ref;}/* Add item to array/object. */
void cJSON_AddItemToArray(cJSON *array, cJSON *item) {cJSON *carray-child;if (!item) return; if (!c) {array-childitem;} else {while (c c-next) cc-next; suffix_object(c,item);}}
void cJSON_AddItemToObject(cJSON *object,const char *string,cJSON *item) {if (!item) return; if (item-string) cJSON_free(item-string);item-stringcJSON_strdup(string);cJSON_AddItemToArray(object,item);}
void cJSON_AddItemToObjectCS(cJSON *object,const char *string,cJSON *item) {if (!item) return; if (!(item-typecJSON_StringIsConst) item-string) cJSON_free(item-string);item-string(char*)string;item-type|cJSON_StringIsConst;cJSON_AddItemToArray(object,item);}
void cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item) {cJSON_AddItemToArray(array,create_reference(item));}
void cJSON_AddItemReferenceToObject(cJSON *object,const char *string,cJSON *item) {cJSON_AddItemToObject(object,string,create_reference(item));}cJSON *cJSON_DetachItemFromArray(cJSON *array,int which) {cJSON *carray-child;while (c which0) cc-next,which--;if (!c) return 0;if (c-prev) c-prev-nextc-next;if (c-next) c-next-prevc-prev;if (carray-child) array-childc-next;c-prevc-next0;return c;}
void cJSON_DeleteItemFromArray(cJSON *array,int which) {cJSON_Delete(cJSON_DetachItemFromArray(array,which));}
cJSON *cJSON_DetachItemFromObject(cJSON *object,const char *string) {int i0;cJSON *cobject-child;while (c cJSON_strcasecmp(c-string,string)) i,cc-next;if (c) return cJSON_DetachItemFromArray(object,i);return 0;}
void cJSON_DeleteItemFromObject(cJSON *object,const char *string) {cJSON_Delete(cJSON_DetachItemFromObject(object,string));}/* Replace array/object items with new ones. */
void cJSON_InsertItemInArray(cJSON *array,int which,cJSON *newitem) {cJSON *carray-child;while (c which0) cc-next,which--;if (!c) {cJSON_AddItemToArray(array,newitem);return;}newitem-nextc;newitem-prevc-prev;c-prevnewitem;if (carray-child) array-childnewitem; else newitem-prev-nextnewitem;}
void cJSON_ReplaceItemInArray(cJSON *array,int which,cJSON *newitem) {cJSON *carray-child;while (c which0) cc-next,which--;if (!c) return;newitem-nextc-next;newitem-prevc-prev;if (newitem-next) newitem-next-prevnewitem;if (carray-child) array-childnewitem; else newitem-prev-nextnewitem;c-nextc-prev0;cJSON_Delete(c);}
void cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem){int i0;cJSON *cobject-child;while(c cJSON_strcasecmp(c-string,string))i,cc-next;if(c){newitem-stringcJSON_strdup(string);cJSON_ReplaceItemInArray(object,i,newitem);}}/* Create basic types: */
cJSON *cJSON_CreateNull(void) {cJSON *itemcJSON_New_Item();if(item)item-typecJSON_NULL;return item;}
cJSON *cJSON_CreateTrue(void) {cJSON *itemcJSON_New_Item();if(item)item-typecJSON_True;return item;}
cJSON *cJSON_CreateFalse(void) {cJSON *itemcJSON_New_Item();if(item)item-typecJSON_False;return item;}
cJSON *cJSON_CreateBool(int b) {cJSON *itemcJSON_New_Item();if(item)item-typeb?cJSON_True:cJSON_False;return item;}
cJSON *cJSON_CreateNumber(double num) {cJSON *itemcJSON_New_Item();if(item){item-typecJSON_Number;item-valuedoublenum;item-valueint(int)num;}return item;}
cJSON *cJSON_CreateString(const char *string) {cJSON *itemcJSON_New_Item();if(item){item-typecJSON_String;item-valuestringcJSON_strdup(string);}return item;}
cJSON *cJSON_CreateArray(void) {cJSON *itemcJSON_New_Item();if(item)item-typecJSON_Array;return item;}
cJSON *cJSON_CreateObject(void) {cJSON *itemcJSON_New_Item();if(item)item-typecJSON_Object;return item;}/* Create Arrays: */
cJSON *cJSON_CreateIntArray(const int *numbers,int count) {int i;cJSON *n0,*p0,*acJSON_CreateArray();for(i0;a icount;i){ncJSON_CreateNumber(numbers[i]);if(!i)a-childn;else suffix_object(p,n);pn;}return a;}
cJSON *cJSON_CreateFloatArray(const float *numbers,int count) {int i;cJSON *n0,*p0,*acJSON_CreateArray();for(i0;a icount;i){ncJSON_CreateNumber(numbers[i]);if(!i)a-childn;else suffix_object(p,n);pn;}return a;}
cJSON *cJSON_CreateDoubleArray(const double *numbers,int count) {int i;cJSON *n0,*p0,*acJSON_CreateArray();for(i0;a icount;i){ncJSON_CreateNumber(numbers[i]);if(!i)a-childn;else suffix_object(p,n);pn;}return a;}
cJSON *cJSON_CreateStringArray(const char **strings,int count) {int i;cJSON *n0,*p0,*acJSON_CreateArray();for(i0;a icount;i){ncJSON_CreateString(strings[i]);if(!i)a-childn;else suffix_object(p,n);pn;}return a;}/* Duplication */
cJSON *cJSON_Duplicate(cJSON *item,int recurse)
{cJSON *newitem,*cptr,*nptr0,*newchild;/* Bail on bad ptr */if (!item) return 0;/* Create new item */newitemcJSON_New_Item();if (!newitem) return 0;/* Copy over all vars */newitem-typeitem-type(~cJSON_IsReference),newitem-valueintitem-valueint,newitem-valuedoubleitem-valuedouble;if (item-valuestring) {newitem-valuestringcJSON_strdup(item-valuestring); if (!newitem-valuestring) {cJSON_Delete(newitem);return 0;}}if (item-string) {newitem-stringcJSON_strdup(item-string); if (!newitem-string) {cJSON_Delete(newitem);return 0;}}/* If non-recursive, then were done! */if (!recurse) return newitem;/* Walk the -next chain for the child. */cptritem-child;while (cptr){newchildcJSON_Duplicate(cptr,1); /* Duplicate (with recurse) each item in the -next chain */if (!newchild) {cJSON_Delete(newitem);return 0;}if (nptr) {nptr-nextnewchild,newchild-prevnptr;nptrnewchild;} /* If newitem-child already set, then crosswire -prev and -next and move on */else {newitem-childnewchild;nptrnewchild;} /* Set newitem-child and move to it */cptrcptr-next;}return newitem;
}void cJSON_Minify(char *json)
{char *intojson;while (*json){if (*json ) json;else if (*json\t) json; /* Whitespace characters. */else if (*json\r) json;else if (*json\n) json;else if (*json/ json[1]/) while (*json *json!\n) json; /* double-slash comments, to end of line. */else if (*json/ json[1]*) {while (*json !(*json* json[1]/)) json;json2;} /* multiline comments. */else if (*json\){*into*json;while (*json *json!\){if (*json\\) *into*json;*into*json;}*into*json;} /* string literals, which are \ sensitive. */else *into*json; /* All other characters. */}*into0; /* and null-terminate. */
}