單片機Json框架的實現

背景

月初寫了一個簡單的單片機json生成框架,目的是想爲藍牙開發板封裝一套協議。加班了小一個月,終於有時間喘口氣搞搞自己的東西了….回過頭來看,發現很多不足之處,抽空進行了一些重構。主要修改了以下幾個方面:
1.修改了基本的數據結構,統一抽象爲 JsonPair 與 JsonObject,方便解析;
2.重新定義了內存管理模塊,將結構存儲與數據存儲分開管理,這樣方便根據不同的MCU進行相應調整;
3.重新實現了相應的方法

基本結構

上一篇文章中定義的結構比較混亂,雖然可以較爲容易地實現json的生成,但是解析時就會使程序變得異常混亂,所以我將json結構重新抽取爲
JsonPair和JsonObject,json數組就是若干JsonObject組成。

typedef struct _JsonPair{

        char *key;
        char *value;
        int keyLength;
        int valueLength;

        struct _JsonObject **obj;
        int jsonObjLength;

        int valueType;

        struct _JsonPair *next;
        //struct _JsonPair *prev;

        //char* (* setPair)(struct _JsonPair *this, char *key, char *value);
        //char* (* getValue)(struct _JsonPair *this, char *key);
} JsonPair;

typedef struct _JsonObject{
        struct _JsonPair *jsonPair;
        struct _JsonPair *lastJsonPair;
        struct _JsonObject *next;
        int length;
} JsonObject;

其中JsonPair即爲json鍵值對,可以存儲的值爲字符串或者json數組,定義valueType用來區分jsonPair中存儲內容的類型。struct _JsonObject *obj是一個jsonObject 的數組。同時JsonPair又可以串成一個鏈表。
我們還定義了JsonObject,裏面用來存儲jsonPair的鏈表,兩個解構是遞歸定義的。

下圖爲基本結構
這裏寫圖片描述

內存管理

單片機上對內存的操作比較麻煩,我們可以直接使用數組作爲內存。這樣做的好處是內存地址是連續的,我們知道結構體中的地址也是連續的,也就是說我們可以直接把結構體的首地址指向一片足夠大的內存,這樣結構體變可存值了。定義結構體時應當注意內存對齊。此處我們優化了內存管理結構,將“存儲結構的內存”和“存儲數據的內存”分離開來,根據情況分別爲其分配空間。

char memStructure[MEM_SIZE_STRUCTURE];
char memJsonData[MEM_SIZE_JSONDATA];
char memJsonParse[MEM_SIZE_JSONPARSEDATA];
/******************************************
*Structure Memory Manager
*******************************************/
char *structureBasePtr = memStructure;
char *structureCurrPtr = memStructure;
int structureMemCnt = 0;

//malloc jsonPair
JsonPair *jsonPairMalloc(){
        void *ptr = structureCurrPtr;
        int size = sizeof(JsonPair);
      structureMemCnt += size;
        if(structureMemCnt > MEM_SIZE_STRUCTURE)
                return NULL;
        structureCurrPtr = structureCurrPtr + structureMemCnt;

        return (JsonPair *)ptr;
}

//malloc jsonObj
JsonObject *jsonObjectMalloc(){
        void *ptr = structureCurrPtr;
        int size = sizeof(JsonObject);
      structureMemCnt += size;
      if(structureMemCnt > MEM_SIZE_STRUCTURE)
                return NULL;
        structureCurrPtr = structureCurrPtr + structureMemCnt;
        return (JsonObject *)ptr;
}

char *structureMemFree(){
        memset(memJsonData, 0, MEM_SIZE_STRUCTURE);
        structureBasePtr = memJsonData;
        structureCurrPtr = memJsonData;
      structureMemCnt = 0;
        return structureBasePtr;
}

/******************************************
*Data Memory Manager
*******************************************/
char *dataBasePtr = memJsonData;
char *dataCurrPtr = memJsonData;
int dataMemIndex = 0;

//malloc json data memory
char *dataMemMalloc(int size){
        char *ptr = dataCurrPtr;
        dataCurrPtr = dataCurrPtr + size;
        return ptr;
}

//free json data memory
char *dataMemFree(){
        memset(dataBasePtr, 0, MEM_SIZE_JSONDATA);
        dataBasePtr = dataBasePtr;
      dataCurrPtr = dataBasePtr;
      dataMemIndex = 0;
        return dataBasePtr;
}
/******************************************
*Data Memory Manager
*******************************************/
char *memJsonParseFree(){
        memset(dataBasePtr, 0, MEM_SIZE_JSONDATA);
}

目前還不能支持多任務操作系統進行任務間切換,除非爲不同任務定義不同的存儲空間,否則只能順序轉換。

json生成與解析

有了上面的示意圖我們即可知道,json生成其實相當於創建一棵樹,然後將其順序轉換爲字符串。json的解析就是將字符串按照一定順序取出,然後創建一棵樹。

生成json

/****************************************
*  generate json 
*****************************************/
JsonObject *createJsonObject(){

        JsonObject *ptr = jsonObjectMalloc();
        //json-pair header
        ptr->jsonPair = NULL;
        //json-pair rear
        ptr->lastJsonPair = NULL;
        ptr->length = 0;
        return ptr;
}

//add a normal key-value pair
JsonObject *addJsonPair(JsonObject *rootObject, char *key, char *value){

        JsonPair *jsonPair = jsonPairMalloc();
        jsonPair->key = key;
        jsonPair->keyLength = strlen(key);
        jsonPair->value = value;
        jsonPair->valueLength = strlen(value);
        jsonPair->valueType = VALUE_TYPE_NORMALPAIR;

        if(rootObject->jsonPair == NULL){
                rootObject->jsonPair = jsonPair;
                rootObject->lastJsonPair = jsonPair;
                //jsonPair->prev = NULL;
                jsonPair->next = NULL;
        }else{
                //jsonPair->prev = rootObject->lastJsonPair;
                jsonPair->next = NULL;
                rootObject->lastJsonPair->next = jsonPair;
                rootObject->lastJsonPair = jsonPair;
        }

        rootObject->length++;

        return rootObject;
}

//get json key-value as string
char *generateJsonPairString(char *mem, int *index, JsonPair *jsonPair){
        char *str = NULL;

        mem[(*index)++] = '"';
        memcpy(mem+(*index), jsonPair->key, jsonPair->keyLength);
        *index = *index + jsonPair->keyLength;
        mem[(*index)++] = '"';   

        mem[(*index)++] = ':';

        memcpy(mem+(*index), jsonPair->value, jsonPair->valueLength);
        *index = *index + jsonPair->valueLength;

        mem[(*index)] = '\0';
        str = mem;
        return str;
}

//add a json object array's address
JsonObject *addJsonObjects(JsonObject *rootObject, char *key, JsonObject **childObject){

        JsonPair *jsonPair = jsonPairMalloc();
        jsonPair->key = key;
        jsonPair->keyLength = strlen(key);
        jsonPair->obj = childObject;
        //(*jsonPair->obj)->length = arrayLength;
        jsonPair->valueType = VALUE_TYPE_JSONARRAY;

        if(rootObject->jsonPair == NULL){

                rootObject->jsonPair = jsonPair;
                rootObject->lastJsonPair = jsonPair;
                //jsonPair->prev = NULL;
                jsonPair->next = NULL;
        }else{
                //jsonPair->prev = rootObject->lastJsonPair;
                jsonPair->next = NULL;
                rootObject->lastJsonPair->next = jsonPair;
                rootObject->lastJsonPair = jsonPair;
        }

        rootObject->length++;

        return rootObject;
}

//get json array as string
char *generateJsonArrayString(char *mem, int *index, JsonPair *jsonPair){   //JsonObject *jsonObject

        char *str = NULL;
        int i = 0, j = 0;
        int length = 0;

        mem[(*index)++] = '"';
        memcpy(mem+(*index), jsonPair->key, jsonPair->keyLength);
        *index = *index + jsonPair->keyLength;
        mem[(*index)++] = '"';   
        mem[(*index)++] = ':';
        mem[(*index)++] = '[';

        JsonPair *jsonPairHead;
        JsonObject **jsonObject = jsonPair->obj;
        JsonObject *jsonObjectCurr;     

        jsonObjectCurr = jsonObject[0];
        for(j=0; j<jsonPair->jsonObjLength; j++){

            jsonPairHead = jsonObjectCurr->jsonPair;

            mem[(*index)++] = '{';
            while(jsonPairHead != NULL){

                    //JsonPair *innerJsonPair = (*jsonPairHead->obj)->jsonPair;

                    if(jsonPairHead->valueType == VALUE_TYPE_NORMALPAIR){
                            //handle normal json pair
                            generateJsonPairString(mem, index, jsonPairHead);
                    }else if(jsonPairHead->valueType == VALUE_TYPE_JSONARRAY){
                            //handle json array pair
                            generateJsonArrayString(mem, index, jsonPairHead);
                    }
                    jsonPairHead = jsonPairHead->next;


                    mem[(*index)++] = ',';
            }
            mem[(*index)-1] = '}';
            mem[(*index)++] = ',';

            jsonObjectCurr = jsonObjectCurr->next;
        }
        mem[(*index)-1] = ']';
        mem[(*index)] = '\0';

        str = mem;
      return str;
}

//json generate function
char *generateJsonObjectString(char *mem, int *index, JsonObject *jsonObject){

        char *str = NULL;
        int i;
        int length = jsonObject->length;
        JsonPair *jsonPairPtr = jsonObject->jsonPair;

        mem[(*index)++] = '{';
        for(i=0; i<length; i++){
                if(jsonPairPtr->valueType == VALUE_TYPE_NORMALPAIR){
                        generateJsonPairString(mem, index, jsonPairPtr);
                }else if(jsonPairPtr->valueType == VALUE_TYPE_JSONOBJ){

                }else if(jsonPairPtr->valueType == VALUE_TYPE_JSONARRAY){
                        generateJsonArrayString(mem, index, jsonPairPtr);
                }
                jsonPairPtr = jsonPairPtr->next;
                mem[(*index)++] = ',';
        }
        mem[(*index)-1] = '}';
        mem[(*index)] = '\0';

        return mem;
}

解析json

JsonObject *parseJsonObject(JsonObject *rootJsonObject, char *mem, char* jsonObjectStr, int *index){

        int innerIndex = 0;
        int keyValueIndex = 0;
        int keyLength = 0;
        int valueLength = 0;
        int i = 0;
        int startKeyValueFlag = 0;
        int mesureKeyLengthFlag = 0;

        char *keyStr = NULL;
        char *valueStr = NULL;

        int type = -1;

        int arrayLength = 0;

        rootJsonObject->jsonPair = NULL;
        rootJsonObject->lastJsonPair = NULL;
        rootJsonObject->length = 0;
        rootJsonObject->next = NULL;

        while(jsonObjectStr[i] != '\0'){

                if(jsonObjectStr[i] == '"' && startKeyValueFlag == 0){
                        startKeyValueFlag = 1;
                }

                if(startKeyValueFlag){  //start to parse key-value pair

                        mesureKeyLengthFlag = 1;
                        keyValueIndex = 0;
                        keyLength = 0;
                        valueLength = 0;
                        while(jsonObjectStr[i+keyValueIndex] != ',' && jsonObjectStr[i+keyValueIndex] != '}'){

                                if(jsonObjectStr[i+keyValueIndex] == '"'){  //measure length of key
                                        keyValueIndex++;
                                }

                                if(jsonObjectStr[i+keyValueIndex] == ':'){  //measure length of value
                                        mesureKeyLengthFlag = 0;
                                }

                                if(mesureKeyLengthFlag){
                                     keyLength++;
                                }else{
                                     valueLength++;                     
                                }
                                keyValueIndex++;
                        }
                        valueLength = valueLength - 1; //skip ','

                        innerIndex = i;

                        //fetch key string
                        keyLength = keyLength;
                        keyStr = copyString(mem+(*index), &jsonObjectStr[i+1], keyLength);
                        *index += (keyLength+2);

                        //fetch value string  
                        valueStr = copyString(mem+(*index), &jsonObjectStr[i+keyLength+3],valueLength);
                        *index += (valueLength+1);       //avoid other string rewrite the value's last '\0'         

                        type = getStringType(valueStr);

                        //create a jsonPair and add this jsonPair to the rootJsonObject
                        JsonPair *jsonPair = jsonPairMalloc();
                        jsonPair->key = keyStr;
                        jsonPair->keyLength = strlen(keyStr);
                        jsonPair->next = NULL;
                        if(type == VALUE_TYPE_NORMALPAIR){
                                jsonPair->value = valueStr;
                        }else if(type == VALUE_TYPE_JSONOBJ){

                        }else if(type == VALUE_TYPE_JSONARRAY){
                                //TODO
                                //JsonObject *jsonObject = 
                        }
                        jsonPair->valueType = type;

                        if(rootJsonObject->jsonPair == NULL){
                                rootJsonObject->jsonPair = jsonPair;
                                rootJsonObject->lastJsonPair = rootJsonObject->jsonPair;
                        }else{
                                rootJsonObject->lastJsonPair->next = jsonPair;
                                rootJsonObject->lastJsonPair = rootJsonObject->lastJsonPair->next;
                        }

                        i += keyValueIndex;
                        startKeyValueFlag = 0;
                }else{
                        i++;
                }
        }

        return mem;
}

測試

生成json

char* testNewJsonGenerateUtil(){

        dataMemIndex = 0;

        JsonObject *rootJsonObject = createJsonObject();

        //add key-value pair
        addJsonPair(rootJsonObject, "key1", "value1");
        addJsonPair(rootJsonObject, "key2", "value2");
        addJsonPair(rootJsonObject, "key3", "value3");

        //add json array
        JsonObject *jsonObject0 = createJsonObject();
        addJsonPair(jsonObject0, "key40", "value40");
        addJsonPair(jsonObject0, "key50", "value50");

        JsonObject *jsonObject1 = createJsonObject();
        addJsonPair(jsonObject1, "key41", "value41");
        addJsonPair(jsonObject1, "key51", "value51");   
        jsonObject0->next = jsonObject1;

        addJsonObjects(rootJsonObject, "key_arr1", &jsonObject0);
        rootJsonObject->lastJsonPair->jsonObjLength = 2;


        //generate json string
        char *str = generateJsonObjectString(dataBasePtr, &dataMemIndex, rootJsonObject);

        //clear memory
        //structureMemFree();
        //dataMemFree();
        printf("json string: \n");
        printf(str);

        return str;
}

解析生成的json(目前不能解析數組)

void testNewJsonParseUtil(char *jsonStr){

        JsonObject *rootJsonObject = createJsonObject();

        int index = 0;
        char *str = parseJsonObject(rootJsonObject, memJsonParse, jsonStr, &index);

        printf("\n\njson data:\n");
        printf(rootJsonObject->jsonPair->key);
        printf("\n");
        printf(rootJsonObject->jsonPair->value);

        printf("\n");
        printf(rootJsonObject->jsonPair->next->key);
        printf("\n");
        printf(rootJsonObject->jsonPair->next->value);

        printf("\n");
        printf(rootJsonObject->jsonPair->next->next->key);
        printf("\n");
        printf(rootJsonObject->jsonPair->next->next->value);

        printf("\n\n");

        //clear memory
        //structureMemFree();
        //memJsonParseFree();
        //dataMemFree();
}

這裏寫圖片描述

目前還沒有處理換行等一些問題,有時間了繼續完善。

代碼託管地址:
https://git.oschina.net/vonchenchen/Embed_C_JSON_Utils.git

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章