边缘计算网关

 一、项目整体框架图

0e5752bf6a917e83641fde6f1cdddf7f.png

二、项目整体描述

边缘计算网关项目主要实现了智能家居场景和工业物联网场景下设备的数据采集和控制。
整个项目分为三大层:用户接口层、网关层、设备层。
其中用户层通过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 <QTextStream>namespace 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_H

dialog.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 message="living!";
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(text=="no"){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 version="1.0" encoding="UTF-8"?>
<ui version="4.0"><class>Dialog</class><widget class="QDialog" name="Dialog"><property name="geometry"><rect><x>0</x><y>0</y><width>486</width><height>325</height></rect></property><property name="windowTitle"><string>Dialog</string></property><layout class="QVBoxLayout" name="verticalLayout_2"><item><layout class="QVBoxLayout" name="verticalLayout"><item><widget class="QPushButton" name="pushButton"><property name="text"><string>下发点表</string></property></widget></item><item><widget class="QPushButton" name="pushButton_2"><property name="text"><string>心跳</string></property></widget></item></layout></item></layout></widget><layoutdefault spacing="6" margin="11"/><resources/><connections/>
</ui>

2. 网关层部分代码展示:

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;}//绑定套接字(ip+port)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);//判断是否是本公司产品:收到的数据是否"coffee"if (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 recvbyte=1;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 item's string, if type==cJSON_String */int valueint;				/* The item's number, if type==cJSON_Number */double valuedouble;			/* The item's number, if type==cJSON_Number */char *string;				/* The item's 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. fmt=0 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. 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. */
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 don't 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#endif

cJSON.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.h"static const char *ep;const char *cJSON_GetErrorPtr(void) {return ep;}static int cJSON_strcasecmp(const char *s1,const char *s2)
{if (!s1) return (s1==s2)?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){next=c->next;if (!(c->type&cJSON_IsReference) && c->child) cJSON_Delete(c->child);if (!(c->type&cJSON_IsReference) && c->valuestring) cJSON_free(c->valuestring);if (!(c->type&cJSON_StringIsConst) && c->string) cJSON_free(c->string);cJSON_free(c);c=next;}
}/* 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 n=0,sign=1,scale=0;int subscale=0,signsubscale=1;if (*num=='-') sign=-1,num++;	/* Has sign? */if (*num=='0') num++;			/* is zero */if (*num>='1' && *num<='9')	do	n=(n*10.0)+(*num++ -'0');	while (*num>='0' && *num<='9');	/* Number? */if (*num=='.' && num[1]>='0' && num[1]<='9') {num++;		do	n=(n*10.0)+(*num++ -'0'),scale--; while (*num>='0' && *num<='9');}	/* Fractional part? */if (*num=='e' || *num=='E')		/* Exponent? */{	num++;if (*num=='+') num++;	else if (*num=='-') signsubscale=-1,num++;		/* With sign? */while (*num>='0' && *num<='9') subscale=(subscale*10)+(*num++ - '0');	/* Number? */}n=sign*n*pow(10.0,(scale+subscale*signsubscale));	/* number = +/- number.fraction * 10^+/- exponent */item->valuedouble=n;item->valueint=(int)n;item->type=cJSON_Number;return num;
}static int pow2gt (int x)	{	--x;	x|=x>>1;	x|=x>>2;	x|=x>>4;	x|=x>>8;	x|=x>>16;	return x+1;	}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;needed+=p->offset;if (needed<=p->length) return p->buffer+p->offset;newsize=pow2gt(needed);newbuffer=(char*)cJSON_malloc(newsize);if (!newbuffer) {cJSON_free(p->buffer);p->length=0,p->buffer=0;return 0;}if (newbuffer) memcpy(newbuffer,p->buffer,p->length);cJSON_free(p->buffer);p->length=newsize;p->buffer=newbuffer;return newbuffer+p->offset;
}static int update(printbuffer *p)
{char *str;if (!p || !p->buffer) return 0;str=p->buffer+p->offset;return p->offset+strlen(str);
}/* Render the number nicely from the given item into a string. */
static char *print_number(cJSON *item,printbuffer *p)
{char *str=0;double d=item->valuedouble;if (d==0){if (p)	str=ensure(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 && d<=INT_MAX && d>=INT_MIN){if (p)	str=ensure(p,21);else	str=(char*)cJSON_malloc(21);	/* 2^64+1 can be represented in 21 chars. */if (str)	sprintf(str,"%d",item->valueint);}else{if (p)	str=ensure(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 h=0;if (*str>='0' && *str<='9') h+=(*str)-'0'; else if (*str>='A' && *str<='F') h+=10+(*str)-'A'; else if (*str>='a' && *str<='f') h+=10+(*str)-'a'; else return 0;h=h<<4;str++;if (*str>='0' && *str<='9') h+=(*str)-'0'; else if (*str>='A' && *str<='F') h+=10+(*str)-'A'; else if (*str>='a' && *str<='f') h+=10+(*str)-'a'; else return 0;h=h<<4;str++;if (*str>='0' && *str<='9') h+=(*str)-'0'; else if (*str>='A' && *str<='F') h+=10+(*str)-'A'; else if (*str>='a' && *str<='f') h+=10+(*str)-'a'; else return 0;h=h<<4;str++;if (*str>='0' && *str<='9') h+=(*str)-'0'; else if (*str>='A' && *str<='F') h+=10+(*str)-'A'; else if (*str>='a' && *str<='f') h+=10+(*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 *ptr=str+1;char *ptr2;char *out;int len=0;unsigned uc,uc2;if (*str!='\"') {ep=str;return 0;}	/* not a string! */while (*ptr!='\"' && *ptr && ++len) if (*ptr++ == '\\') ptr++;	/* Skip escaped quotes. */out=(char*)cJSON_malloc(len+1);	/* This is how long we need for the string, roughly. */if (!out) return 0;ptr=str+1;ptr2=out;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. */uc=parse_hex4(ptr+1);ptr+=4;	/* get the unicode char. */if ((uc>=0xDC00 && uc<=0xDFFF) || uc==0)	break;	/* check for invalid.	*/if (uc>=0xD800 && uc<=0xDBFF)	/* UTF16 surrogate pairs.	*/{if (ptr[1]!='\\' || ptr[2]!='u')	break;	/* missing second-half of surrogate.	*/uc2=parse_hex4(ptr+3);ptr+=6;if (uc2<0xDC00 || uc2>0xDFFF)		break;	/* invalid second-half of surrogate.	*/uc=0x10000 + (((uc&0x3FF)<<10) | (uc2&0x3FF));}len=4;if (uc<0x80) len=1;else if (uc<0x800) len=2;else if (uc<0x10000) len=3; ptr2+=len;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]);}ptr2+=len;break;default:  *ptr2++=*ptr; break;}ptr++;}}*ptr2=0;if (*ptr=='\"') ptr++;item->valuestring=out;item->type=cJSON_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 len=0,flag=0;unsigned char token;for (ptr=str;*ptr;ptr++) flag|=((*ptr>0 && *ptr<32)||(*ptr=='\"')||(*ptr=='\\'))?1:0;if (!flag){len=ptr-str;if (p) out=ensure(p,len+3);else		out=(char*)cJSON_malloc(len+3);if (!out) return 0;ptr2=out;*ptr2++='\"';strcpy(ptr2,str);ptr2[len]='\"';ptr2[len+1]=0;return out;}if (!str){if (p)	out=ensure(p,3);else	out=(char*)cJSON_malloc(3);if (!out) return 0;strcpy(out,"\"\"");return out;}ptr=str;while ((token=*ptr) && ++len) {if (strchr("\"\\\b\f\n\r\t",token)) len++; else if (token<32) len+=5;ptr++;}if (p)	out=ensure(p,len+3);else	out=(char*)cJSON_malloc(len+3);if (!out) return 0;ptr2=out;ptr=str;*ptr2++='\"';while (*ptr){if ((unsigned char)*ptr>31 && *ptr!='\"' && *ptr!='\\') *ptr2++=*ptr++;else{*ptr2++='\\';switch (token=*ptr++){case '\\':	*ptr2++='\\';	break;case '\"':	*ptr2++='\"';	break;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;default: sprintf(ptr2,"u%04x",token);ptr2+=5;	break;	/* escape and print */}}}*ptr2++='\"';*ptr2++=0;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)*in<=32) 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 *end=0;cJSON *c=cJSON_New_Item();ep=0;if (!c) return 0;       /* memory fail */end=parse_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) {end=skip(end);if (*end) {cJSON_Delete(c);ep=end;return 0;}}if (return_parse_end) *return_parse_end=end;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.length=prebuffer;p.offset=0;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->type=cJSON_NULL;  return value+4; }if (!strncmp(value,"false",5))	{ item->type=cJSON_False; return value+5; }if (!strncmp(value,"true",4))	{ item->type=cJSON_True; item->valueint=1;	return value+4; }if (*value=='\"')				{ return parse_string(item,value); }if (*value=='-' || (*value>='0' && *value<='9'))	{ return parse_number(item,value); }if (*value=='[')				{ return parse_array(item,value); }if (*value=='{')				{ return parse_object(item,value); }ep=value;return 0;	/* failure. */
}/* Render a value to text. */
static char *print_value(cJSON *item,int depth,int fmt,printbuffer *p)
{char *out=0;if (!item) return 0;if (p){switch ((item->type)&255){case cJSON_NULL:	{out=ensure(p,5);	if (out) strcpy(out,"null");	break;}case cJSON_False:	{out=ensure(p,6);	if (out) strcpy(out,"false");	break;}case cJSON_True:	{out=ensure(p,5);	if (out) strcpy(out,"true");	break;}case cJSON_Number:	out=print_number(item,p);break;case cJSON_String:	out=print_string(item,p);break;case cJSON_Array:	out=print_array(item,depth,fmt,p);break;case cJSON_Object:	out=print_object(item,depth,fmt,p);break;}}else{switch ((item->type)&255){case cJSON_NULL:	out=cJSON_strdup("null");	break;case cJSON_False:	out=cJSON_strdup("false");break;case cJSON_True:	out=cJSON_strdup("true"); break;case cJSON_Number:	out=print_number(item,0);break;case cJSON_String:	out=print_string(item,0);break;case cJSON_Array:	out=print_array(item,depth,fmt,0);break;case cJSON_Object:	out=print_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!='[')	{ep=value;return 0;}	/* not an array! */item->type=cJSON_Array;value=skip(value+1);if (*value==']') return value+1;	/* empty array. */item->child=child=cJSON_New_Item();if (!item->child) return 0;		 /* memory fail */value=skip(parse_value(child,skip(value)));	/* skip any spacing, get the value. */if (!value) return 0;while (*value==','){cJSON *new_item;if (!(new_item=cJSON_New_Item())) return 0; 	/* memory fail */child->next=new_item;new_item->prev=child;child=new_item;value=skip(parse_value(child,skip(value+1)));if (!value) return 0;	/* memory fail */}if (*value==']') return value+1;	/* end of array */ep=value;return 0;	/* malformed. */
}/* Render an array to text */
static char *print_array(cJSON *item,int depth,int fmt,printbuffer *p)
{char **entries;char *out=0,*ptr,*ret;int len=5;cJSON *child=item->child;int numentries=0,i=0,fail=0;size_t tmplen=0;/* How many entries in the array? */while (child) numentries++,child=child->next;/* Explicitly handle numentries==0 */if (!numentries){if (p)	out=ensure(p,3);else	out=(char*)cJSON_malloc(3);if (out) strcpy(out,"[]");return out;}if (p){/* Compose the output array. */i=p->offset;ptr=ensure(p,1);if (!ptr) return 0;	*ptr='[';	p->offset++;child=item->child;while (child && !fail){print_value(child,depth+1,fmt,p);p->offset=update(p);if (child->next) {len=fmt?2:1;ptr=ensure(p,len+1);if (!ptr) return 0;*ptr++=',';if(fmt)*ptr++=' ';*ptr=0;p->offset+=len;}child=child->next;}ptr=ensure(p,2);if (!ptr) return 0;	*ptr++=']';*ptr=0;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: */child=item->child;while (child && !fail){ret=print_value(child,depth+1,fmt,0);entries[i++]=ret;if (ret) len+=strlen(ret)+2+(fmt?1:0); else fail=1;child=child->next;}/* If we didn't fail, try to malloc the output string */if (!fail)	out=(char*)cJSON_malloc(len);/* If that fails, we fail. */if (!out) fail=1;/* Handle failure. */if (fail){for (i=0;i<numentries;i++) if (entries[i]) cJSON_free(entries[i]);cJSON_free(entries);return 0;}/* Compose the output array. */*out='[';ptr=out+1;*ptr=0;for (i=0;i<numentries;i++){tmplen=strlen(entries[i]);memcpy(ptr,entries[i],tmplen);ptr+=tmplen;if (i!=numentries-1) {*ptr++=',';if(fmt)*ptr++=' ';*ptr=0;}cJSON_free(entries[i]);}cJSON_free(entries);*ptr++=']';*ptr++=0;}return out;	
}/* Build an object from the text. */
static const char *parse_object(cJSON *item,const char *value)
{cJSON *child;if (*value!='{')	{ep=value;return 0;}	/* not an object! */item->type=cJSON_Object;value=skip(value+1);if (*value=='}') return value+1;	/* empty array. */item->child=child=cJSON_New_Item();if (!item->child) return 0;value=skip(parse_string(child,skip(value)));if (!value) return 0;child->string=child->valuestring;child->valuestring=0;if (*value!=':') {ep=value;return 0;}	/* fail! */value=skip(parse_value(child,skip(value+1)));	/* skip any spacing, get the value. */if (!value) return 0;while (*value==','){cJSON *new_item;if (!(new_item=cJSON_New_Item()))	return 0; /* memory fail */child->next=new_item;new_item->prev=child;child=new_item;value=skip(parse_string(child,skip(value+1)));if (!value) return 0;child->string=child->valuestring;child->valuestring=0;if (*value!=':') {ep=value;return 0;}	/* fail! */value=skip(parse_value(child,skip(value+1)));	/* skip any spacing, get the value. */if (!value) return 0;}if (*value=='}') return value+1;	/* end of array */ep=value;return 0;	/* malformed. */
}/* Render an object to text. */
static char *print_object(cJSON *item,int depth,int fmt,printbuffer *p)
{char **entries=0,**names=0;char *out=0,*ptr,*ret,*str;int len=7,i=0,j;cJSON *child=item->child;int numentries=0,fail=0;size_t tmplen=0;/* Count the number of entries. */while (child) numentries++,child=child->next;/* Explicitly handle empty object case */if (!numentries){if (p) out=ensure(p,fmt?depth+4:3);else	out=(char*)cJSON_malloc(fmt?depth+4:3);if (!out)	return 0;ptr=out;*ptr++='{';if (fmt) {*ptr++='\n';for (i=0;i<depth-1;i++) *ptr++='\t';}*ptr++='}';*ptr++=0;return out;}if (p){/* Compose the output: */i=p->offset;len=fmt?2:1;	ptr=ensure(p,len+1);	if (!ptr) return 0;*ptr++='{';	if (fmt) *ptr++='\n';	*ptr=0;	p->offset+=len;child=item->child;depth++;while (child){if (fmt){ptr=ensure(p,depth);	if (!ptr) return 0;for (j=0;j<depth;j++) *ptr++='\t';p->offset+=depth;}print_string_ptr(child->string,p);p->offset=update(p);len=fmt?2:1;ptr=ensure(p,len);	if (!ptr) return 0;*ptr++=':';if (fmt) *ptr++='\t';p->offset+=len;print_value(child,depth,fmt,p);p->offset=update(p);len=(fmt?1:0)+(child->next?1:0);ptr=ensure(p,len+1); if (!ptr) return 0;if (child->next) *ptr++=',';if (fmt) *ptr++='\n';*ptr=0;p->offset+=len;child=child->next;}ptr=ensure(p,fmt?(depth+1):2);	 if (!ptr) return 0;if (fmt)	for (i=0;i<depth-1;i++) *ptr++='\t';*ptr++='}';*ptr=0;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: */child=item->child;depth++;if (fmt) len+=depth;while (child && !fail){names[i]=str=print_string_ptr(child->string,0);entries[i++]=ret=print_value(child,depth,fmt,0);if (str && ret) len+=strlen(ret)+strlen(str)+2+(fmt?2+depth:0); else fail=1;child=child->next;}/* Try to allocate the output string */if (!fail)	out=(char*)cJSON_malloc(len);if (!out) fail=1;/* Handle failure */if (fail){for (i=0;i<numentries;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='{';ptr=out+1;if (fmt)*ptr++='\n';*ptr=0;for (i=0;i<numentries;i++){if (fmt) for (j=0;j<depth;j++) *ptr++='\t';tmplen=strlen(names[i]);memcpy(ptr,names[i],tmplen);ptr+=tmplen;*ptr++=':';if (fmt) *ptr++='\t';strcpy(ptr,entries[i]);ptr+=strlen(entries[i]);if (i!=numentries-1) *ptr++=',';if (fmt) *ptr++='\n';*ptr=0;cJSON_free(names[i]);cJSON_free(entries[i]);}cJSON_free(names);cJSON_free(entries);if (fmt) for (i=0;i<depth-1;i++) *ptr++='\t';*ptr++='}';*ptr++=0;}return out;	
}/* Get Array size/item / object item. */
int    cJSON_GetArraySize(cJSON *array)							{cJSON *c=array->child;int i=0;while(c)i++,c=c->next;return i;}
cJSON *cJSON_GetArrayItem(cJSON *array,int item)				{cJSON *c=array->child;  while (c && item>0) item--,c=c->next; return c;}
cJSON *cJSON_GetObjectItem(cJSON *object,const char *string)	{cJSON *c=object->child; while (c && cJSON_strcasecmp(c->string,string)) c=c->next; return c;}
int cJSON_HasObjectItem(cJSON *object,const char *string)	{cJSON *c=object->child;while (c ){if(cJSON_strcasecmp(c->string,string)==0){return 1;}c=c->next;}return 0;
}/* Utility for array list handling. */
static void suffix_object(cJSON *prev,cJSON *item) {prev->next=item;item->prev=prev;}
/* Utility for handling references. */
static cJSON *create_reference(cJSON *item) {cJSON *ref=cJSON_New_Item();if (!ref) return 0;memcpy(ref,item,sizeof(cJSON));ref->string=0;ref->type|=cJSON_IsReference;ref->next=ref->prev=0;return ref;}/* Add item to array/object. */
void   cJSON_AddItemToArray(cJSON *array, cJSON *item)						{cJSON *c=array->child;if (!item) return; if (!c) {array->child=item;} else {while (c && c->next) c=c->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->string=cJSON_strdup(string);cJSON_AddItemToArray(object,item);}
void   cJSON_AddItemToObjectCS(cJSON *object,const char *string,cJSON *item)	{if (!item) return; if (!(item->type&cJSON_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 *c=array->child;while (c && which>0) c=c->next,which--;if (!c) return 0;if (c->prev) c->prev->next=c->next;if (c->next) c->next->prev=c->prev;if (c==array->child) array->child=c->next;c->prev=c->next=0;return c;}
void   cJSON_DeleteItemFromArray(cJSON *array,int which)			{cJSON_Delete(cJSON_DetachItemFromArray(array,which));}
cJSON *cJSON_DetachItemFromObject(cJSON *object,const char *string) {int i=0;cJSON *c=object->child;while (c && cJSON_strcasecmp(c->string,string)) i++,c=c->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 *c=array->child;while (c && which>0) c=c->next,which--;if (!c) {cJSON_AddItemToArray(array,newitem);return;}newitem->next=c;newitem->prev=c->prev;c->prev=newitem;if (c==array->child) array->child=newitem; else newitem->prev->next=newitem;}
void   cJSON_ReplaceItemInArray(cJSON *array,int which,cJSON *newitem)		{cJSON *c=array->child;while (c && which>0) c=c->next,which--;if (!c) return;newitem->next=c->next;newitem->prev=c->prev;if (newitem->next) newitem->next->prev=newitem;if (c==array->child) array->child=newitem; else newitem->prev->next=newitem;c->next=c->prev=0;cJSON_Delete(c);}
void   cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem){int i=0;cJSON *c=object->child;while(c && cJSON_strcasecmp(c->string,string))i++,c=c->next;if(c){newitem->string=cJSON_strdup(string);cJSON_ReplaceItemInArray(object,i,newitem);}}/* Create basic types: */
cJSON *cJSON_CreateNull(void)					{cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_NULL;return item;}
cJSON *cJSON_CreateTrue(void)					{cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_True;return item;}
cJSON *cJSON_CreateFalse(void)					{cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_False;return item;}
cJSON *cJSON_CreateBool(int b)					{cJSON *item=cJSON_New_Item();if(item)item->type=b?cJSON_True:cJSON_False;return item;}
cJSON *cJSON_CreateNumber(double num)			{cJSON *item=cJSON_New_Item();if(item){item->type=cJSON_Number;item->valuedouble=num;item->valueint=(int)num;}return item;}
cJSON *cJSON_CreateString(const char *string)	{cJSON *item=cJSON_New_Item();if(item){item->type=cJSON_String;item->valuestring=cJSON_strdup(string);}return item;}
cJSON *cJSON_CreateArray(void)					{cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_Array;return item;}
cJSON *cJSON_CreateObject(void)					{cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_Object;return item;}/* Create Arrays: */
cJSON *cJSON_CreateIntArray(const int *numbers,int count)		{int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && i<count;i++){n=cJSON_CreateNumber(numbers[i]);if(!i)a->child=n;else suffix_object(p,n);p=n;}return a;}
cJSON *cJSON_CreateFloatArray(const float *numbers,int count)	{int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && i<count;i++){n=cJSON_CreateNumber(numbers[i]);if(!i)a->child=n;else suffix_object(p,n);p=n;}return a;}
cJSON *cJSON_CreateDoubleArray(const double *numbers,int count)	{int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && i<count;i++){n=cJSON_CreateNumber(numbers[i]);if(!i)a->child=n;else suffix_object(p,n);p=n;}return a;}
cJSON *cJSON_CreateStringArray(const char **strings,int count)	{int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && i<count;i++){n=cJSON_CreateString(strings[i]);if(!i)a->child=n;else suffix_object(p,n);p=n;}return a;}/* Duplication */
cJSON *cJSON_Duplicate(cJSON *item,int recurse)
{cJSON *newitem,*cptr,*nptr=0,*newchild;/* Bail on bad ptr */if (!item) return 0;/* Create new item */newitem=cJSON_New_Item();if (!newitem) return 0;/* Copy over all vars */newitem->type=item->type&(~cJSON_IsReference),newitem->valueint=item->valueint,newitem->valuedouble=item->valuedouble;if (item->valuestring)	{newitem->valuestring=cJSON_strdup(item->valuestring);	if (!newitem->valuestring)	{cJSON_Delete(newitem);return 0;}}if (item->string)		{newitem->string=cJSON_strdup(item->string);			if (!newitem->string)		{cJSON_Delete(newitem);return 0;}}/* If non-recursive, then we're done! */if (!recurse) return newitem;/* Walk the ->next chain for the child. */cptr=item->child;while (cptr){newchild=cJSON_Duplicate(cptr,1);		/* Duplicate (with recurse) each item in the ->next chain */if (!newchild) {cJSON_Delete(newitem);return 0;}if (nptr)	{nptr->next=newchild,newchild->prev=nptr;nptr=newchild;}	/* If newitem->child already set, then crosswire ->prev and ->next and move on */else		{newitem->child=newchild;nptr=newchild;}					/* Set newitem->child and move to it */cptr=cptr->next;}return newitem;
}void cJSON_Minify(char *json)
{char *into=json;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++;json+=2;}	/* 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. */}*into=0;	/* and null-terminate. */
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/93885.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Django之十二:模板的继承+用户列表

模板的继承 新建layout.html&#xff1a; {% load static %} <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>Title</title><link rel"stylesheet" href"{% static plugins…

231003-四步MacOS-iPadOS设置无线竖屏随航SideCar

Step 0&#xff1a;MacOS到iPad无线竖屏随航显示&#xff0c;最终效果 Step 1&#xff1a; 下载 Better Display Step 2&#xff1a;在设置中新建虚拟屏幕&#xff0c;创建虚拟屏幕 Step 3&#xff1a;进行如下设置 Step 4&#xff1a;注意事项 ⚠️ 设置后的虚拟屏幕与Sideca…

nodejs+vue晓海网上订餐系统elementui

管理员功能需求 管理员登陆后&#xff0c;主要模块包括首页、个人中心、用户管理、菜单信息管理等功能。 第三章 系统分析 10 3.1需求分析 10 3.2可行性分析 10 3.2.1技术可行性&#xff1a;技术背景 10 3.2.2经济可行性 11 3.2.3操作可行性&#xff1a; 11 3.3性能分析 11 3.4…

IntelliJ IDEA配置Cplex12.6.3详细步骤

Cplex12.6.3版IntelliJ IDEA配置详细步骤 一、Cplex12.6.3版下载地址二、Cplex安装步骤三、IDEA配置CPLEX3.1 添加CPLEX安装目录的cplex.jar包到项目文件中3.2 将CPLEX的x64_win64文件夹添加到IDEA的VM options中 四、检查IDEA中Cplex是否安装成功卸载Cplex 一、Cplex12.6.3版下…

我用PYQT5做的第一个实用的上位机项目(三)

基本的程序框架&#xff1a; 因为自己不是专业的程序员&#xff0c;只是一个搞电气控制的“票友”&#xff0c;所以尽量减少手动输入 代码量&#xff0c;能在Qt Dsigner里面完成的组态就不要放在代码里面完成。 在框架的建设方面&#xff0c;尽量做到集中和整合&#xff0c;位…

科技+智慧+颜值,智慧公厕黑科技提升城市形象

现代社会的科技和智慧正以惊人的速度渗透到我们生活的各个方面&#xff0c;包括公共设施。而作为城市形象的重要组成部分之一&#xff0c;公厕也在不断创新中迎来了智慧的时代。 在传统的公厕中&#xff0c;一些问题一直困扰着我们&#xff0c;比如厕位的占用情况、空气质量的…

Git多账号管理通过ssh 公钥的方式,git,gitlab,gitee

按照目前国内访问git&#xff0c;如果不科学上网&#xff0c;我们很大可能访问会超时。基于这个&#xff0c;所以我现在的git 配置已经增加到了3个了 一个公司gitlab&#xff0c;一个git&#xff0c;一个gitee. 以下基于这个环境&#xff0c;我们来说明下如何创建配置ssh公钥。…

UE中制作棋盘格材质效果

在UE中通过这个小技巧制作棋盘格材质效果&#xff0c;可以快速预览UV拉伸情况&#xff0c;方便调试导入的模型。 1.操作步骤 1.1 首先新建材质&#xff0c;Shading Model&#xff08;着色模式&#xff09;设置为Unlit&#xff08;无光照&#xff09;&#xff1a; 1.2 我们…

前端相关题目随笔

Vh虽然获取到了视口高度&#xff0c;但是vh会随着屏幕的、大小变化&#xff0c;所以当减去一个数字之后&#xff0c;就会显示错误。 生成id 如果没有设置id&#xff0c;则可以通过new Date.getTime()获取一个时间&#xff0c;作为一个单独的id&#xff0c;也可以通过下载uuid生…

JavaScript系列从入门到精通系列第十二篇:JavaScript中对象的简介和对象的基本操作以及JavaScript中的属性值和属性名

文章目录 前言 一&#xff1a;对象分类 1&#xff1a;内建对象 2&#xff1a;宿主对象 3&#xff1a;自建对象 二&#xff1a;对象的基本操作 1&#xff1a;创建对象 2&#xff1a;向对象中添加属性 3&#xff1a;读取对象中的属性 4&#xff1a;修改对象中的属性 三…

机器学习7:逻辑回归

一、说明 逻辑回归模型是处理分类问题的最常见机器学习模型之一。二项式逻辑回归只是逻辑回归模型的一种类型。它指的是两个变量的分类&#xff0c;其中概率用于确定二元结果&#xff0c;因此“二项式”中的“bi”。结果为真或假 — 0 或 1。 二项式逻辑回归的一个例子是预测人…

【PickerView案例12-info_plist-PCH文件介绍 Objective-C语言】

一、给大家介绍一下我们项目的一些文件: 1.这个呢,是项目的基础文件: 一些类啊: 一些图片啊: 还有加载图片, 最主要,就是这个东西:info.plist:文件 info.plist: 2.那,需要大家了解一点,关于它的历史啊: 我们现在用的时候,都是从xcode6.4开始的, 或者说,直…

Python 数据分析与挖掘(一)

Python 数据分析与挖掘&#xff08;数据探索&#xff09; 数据探索 1.1 需要掌握的工具&#xff08;库&#xff09; 1.1.1 Nump库 Numpy 提供多维数组对象和各种派生对象&#xff08;类矩阵&#xff09;&#xff0c;利用应用程序接口可以实现大量且繁琐的数据运算。可以构建…

Linux 5种网络模型

[参考]&#xff1a;《黑马程序员Redis》https://www.bilibili.com/video/BV1cr4y1671t/?p166&share_sourcecopy_web&vd_source9e65300ccca322aeb367bb1eb677b0fc [参考]&#xff1a;《操作系统》 [参考]&#xff1a;《UNIX网络编程》 为了避免用户应用导致冲突甚至内…

基于SSM的奶茶店管理系统

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SSM 前端&#xff1a;采用JSP技术开发 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#x…

WebSocket实战之三遇上PAC

一、前言 前两天销售数据实时刷新功能开发测试完成&#xff0c;开开心心部署到生产环境&#xff0c;然后直接懵逼傻眼了&#xff0c;竟然连接不上WebSocket服务端&#xff0c;浏览器端请求头报 Provisional headers are shown 信息&#xff0c;然后采用一系列操作排查问题。 …

89、Redis 的 value 所支持的数据类型(String、List、Set、Zset、Hash)---->Zset 相关命令

本次讲解要点&#xff1a; ** Set相关命令&#xff1a;是指value中的数据类型** 启动redis服务器&#xff1a; 打开小黑窗&#xff1a; C:\Users\JH>e: E:>cd E:\install\Redis6.0\Redis-x64-6.0.14\bin E:\install\Redis6.0\Redis-x64-6.0.14\bin>redis-server.exe …

创建型设计模式 原型模式 建造者模式 创建者模式对比

创建型设计模式 单例 工厂模式 看这一篇就够了_软工菜鸡的博客-CSDN博客 4.3 原型模式 4.3.1 概述 用一个已经创建的实例作为原型&#xff0c;通过复制该原型对象来创建一个和原型对象相同的新对象。 4.3.2 结构 原型模式包含如下角色&#xff1a; 抽象原型类&#xff1a;规定了…

excel中将一个sheet表根据条件分成多个sheet表

有如下excel表&#xff0c;要求&#xff1a;按月份将每月的情况放在一个sheet中。 目测有6个月&#xff0c;就应该有6个sheet&#xff0c;每个sheet中体现本月的情况。 一、首先增加一个辅助列&#xff0c;月份&#xff0c;使用month函数即可。 填充此列所有。然后复制【月份】…

力扣练习——链表在线OJ

目录 提示&#xff1a; 一、移除链表元素 题目&#xff1a; 解答&#xff1a; 二、反转链表 题目&#xff1a; 解答&#xff1a; 三、找到链表的中间结点 题目&#xff1a; 解答&#xff1a; 四、合并两个有序链表&#xff08;经典&#xff09; 题目&#xff1a; 解…