簡(jiǎn)單Tlv序列化和反序列化

#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>

typedef struct tagKamiTlv
{
    struct tagKamiTlv *next;
    struct tagKamiTlv *prev;
    struct tagKamiTlv *child;
    struct tagKamiTlv *parent;

    unsigned short type;
    unsigned short length;
    int obj_type;
    char *value;
} KamiTlv_S;

typedef struct
{
    unsigned char *buffer;
    size_t length;
    size_t offset;
} KamiTlvPrintBuffer;

#define KamiTlv_Invalid (0)
#define KamiTlv_Tlv (1 << 0)
#define KamiTlv_Object (1 << 1)
#define KamiTlv_Array (1 << 2)

unsigned short little2bigs(unsigned short num)
{
    unsigned short swapped = (num >> 8) | (num << 8);
    return swapped;
}

//大端轉(zhuǎn)小端
unsigned short big2littles(unsigned short be)
{
    unsigned short swapped = (be << 8) | (be >> 8);
    return swapped;
}

#define htons little2bigs
#define ntohs big2littles

void Kami_Tlv_Delete(KamiTlv_S *pstTlv);
int Kami_Tlv_PrintValue(KamiTlv_S *pstItem, KamiTlvPrintBuffer *output_buffer);

KamiTlv_S *Kami_Tlv_CreateObject()
{
    KamiTlv_S *pstTlv = (KamiTlv_S *)malloc(sizeof(KamiTlv_S));
    if (!pstTlv)
    {
        return NULL;
    }
    memset(pstTlv, 0, sizeof(KamiTlv_S));
    pstTlv->obj_type = KamiTlv_Object;
    return pstTlv;
}

KamiTlv_S *Kami_Tlv_CreateArray(unsigned short usType)
{
    KamiTlv_S *pstTlv = (KamiTlv_S *)malloc(sizeof(KamiTlv_S));
    if (!pstTlv)
    {
        return NULL;
    }
    memset(pstTlv, 0, sizeof(KamiTlv_S));
    pstTlv->obj_type = KamiTlv_Array;
    pstTlv->type = usType;
    return pstTlv;
}

KamiTlv_S *Kami_Tlv_CreateTlv(unsigned short usType, unsigned short usLength, void *pValue)
{
    KamiTlv_S *pstTlv = Kami_Tlv_CreateObject();
    if (pstTlv)
    {
        pstTlv->type = usType;
        pstTlv->length = usLength;
        if (usLength)
        {
            pstTlv->value = (char *)malloc(usLength);
            if (!pstTlv->value)
            {
                Kami_Tlv_Delete(pstTlv);
                return NULL;
            }
            memcpy(pstTlv->value, pValue, usLength);
        }
        pstTlv->obj_type = KamiTlv_Tlv;
    }

    return pstTlv;
}

void Kami_Tlv_Delete(KamiTlv_S *pstTlv)
{
    KamiTlv_S *pstNext = NULL;
    while (pstTlv != NULL)
    {
        pstNext = pstTlv->next;
        if (pstTlv->child != NULL)
        {
            Kami_Tlv_Delete(pstTlv->child);
        }
        if (pstTlv->value != NULL)
        {
            printf("free %s\n", pstTlv->value);
            free(pstTlv->value);
        }
        free(pstTlv);
        pstTlv = pstNext;
    }
}

int Kami_Tlv_AddItemToObject(KamiTlv_S *pstTlv, KamiTlv_S *pstItem)
{
    KamiTlv_S *pstChild = pstTlv->child;

    pstItem->parent = pstTlv;

    if (pstChild == NULL)
    {
        pstTlv->child = pstItem;
        pstItem->prev = pstItem;
        pstItem->next = NULL;
    }
    else
    {
        if (pstChild->prev)
        {
            pstChild->prev->next = pstItem;
            pstItem->prev = pstChild->prev;
            pstTlv->child->prev = pstItem;
        }
    }

    unsigned short usIncLength = 0;

    if (pstItem->obj_type == KamiTlv_Tlv || pstItem->obj_type == KamiTlv_Array)
    {
        usIncLength = (sizeof(unsigned short) * 2 + pstItem->length);
    }
    else if (pstItem->obj_type == KamiTlv_Object)
    {
        usIncLength = pstItem->length;
    }

    

    while (pstTlv)
    {
        KamiTlv_S *pstParent = pstTlv->parent;
        
        pstTlv->length += usIncLength;

        pstTlv = pstParent;
    }

    return 0;
}

int Kami_Tlv_AddTlvToObject(KamiTlv_S *pstTlv, unsigned short usType, unsigned short usLength, void *pValue)
{
    KamiTlv_S *pstItem = Kami_Tlv_CreateTlv(usType, usLength, pValue);
    if (!pstItem)
    {
        return -1;
    }

    if (0 == Kami_Tlv_AddItemToObject(pstTlv, pstItem))
    {
        return 0;
    }

    Kami_Tlv_Delete(pstItem);
    return -1;
}

void Kami_Tlv_UpdateOffset(KamiTlvPrintBuffer *buffer, KamiTlv_S *pstItem)
{
    switch ((pstItem->obj_type) & 0xFF)
    {
    case KamiTlv_Tlv:
        buffer->offset += (sizeof(unsigned short) * 2 + pstItem->length);
        break;
    case KamiTlv_Array:
        break;
    case KamiTlv_Object:

    default:
        return;
    }
    return;
}

static unsigned char *Kami_Tlv_Ensure(KamiTlvPrintBuffer *const p, size_t needed)
{
    unsigned char *newbuffer = NULL;
    size_t newsize = 0;

    if ((p == NULL) || (p->buffer == NULL))
    {
        return NULL;
    }

    if ((p->length > 0) && (p->offset >= p->length))
    {
        return NULL;
    }

    if (needed > INT_MAX)
    {
        return NULL;
    }

    needed += p->offset + 1;
    if (needed <= p->length)
    {
        return p->buffer + p->offset;
    }

    if (needed > (INT_MAX / 2))
    {
        if (needed <= INT_MAX)
        {
            newsize = INT_MAX;
        }
        else
        {
            return NULL;
        }
    }
    else
    {
        newsize = needed * 2;
    }

    newbuffer = (unsigned char *)realloc(p->buffer, newsize);
    if (newbuffer == NULL)
    {
        free(p->buffer);
        p->length = 0;
        p->buffer = NULL;

        return NULL;
    }

    p->length = newsize;
    p->buffer = newbuffer;

    return newbuffer + p->offset;
}

int Kami_Tlv_PrintTlv(KamiTlv_S *input, KamiTlvPrintBuffer *const output_buffer)
{
    unsigned char *output = NULL;
    if (!input)
    {
        return -1;
    }

    output = Kami_Tlv_Ensure(output_buffer, input->length + sizeof(unsigned short) * 2);

    if (output == NULL)
    {
        return -1;
    }

    *((unsigned short *)output) = htons(input->type);
    *((unsigned short *)(output + sizeof(unsigned short))) = htons(input->length);

    memcpy(output + 2 * sizeof(unsigned short), input->value, input->length);

    output_buffer->offset += (input->length + sizeof(unsigned short) * 2);

    return 0;
}

int Kami_Tlv_PrintObject(KamiTlv_S *item, KamiTlvPrintBuffer *const output_buffer)
{
    unsigned char *output_pointer = NULL;
    size_t length = 0;
    KamiTlv_S *current_item = item->child;

    if (output_buffer == NULL)
    {
        return -1;
    }

    while (current_item)
    {

        if (Kami_Tlv_PrintValue(current_item, output_buffer))
        {
            return -1;
        }

        current_item = current_item->next;
    }

    return 0;
}

int Kami_Tlv_PrintArray(KamiTlv_S *item, KamiTlvPrintBuffer *const output_buffer)
{
    unsigned char *output_pointer = NULL;
    size_t length = 0;
    KamiTlv_S *current_item = item->child;

    if (output_buffer == NULL)
    {
        return -1;
    }

    output_pointer = Kami_Tlv_Ensure(output_buffer, sizeof(unsigned short) * 2);
    if (output_pointer == NULL)
    {
        return -1;
    }
    *((unsigned short *)output_pointer) = htons(item->type);
    *((unsigned short *)(output_pointer + sizeof(unsigned short))) = htons(item->length);

    output_buffer->offset += sizeof(unsigned short) * 2;

    while (current_item)
    {


        if (Kami_Tlv_PrintValue(current_item, output_buffer))
        {
            return -1;
        }

        current_item = current_item->next;
    }

    return 0;
}

int Kami_Tlv_PrintValue(KamiTlv_S *pstItem, KamiTlvPrintBuffer *output_buffer)
{
    unsigned char *output = NULL;

    if ((pstItem == NULL) || (output_buffer == NULL))
    {
        return -1;
    }

    switch ((pstItem->obj_type) & 0xFF)
    {
    case KamiTlv_Tlv:
        return Kami_Tlv_PrintTlv(pstItem, output_buffer);
    case KamiTlv_Array:
        return Kami_Tlv_PrintArray(pstItem, output_buffer);
    case KamiTlv_Object:
        return Kami_Tlv_PrintObject(pstItem, output_buffer);

    default:
        return -1;
    }
}

unsigned char *Kami_Tlv_Print(KamiTlv_S *pstTlv)
{
    static const size_t default_buffer_size = 256;
    KamiTlvPrintBuffer buffer[1];
    unsigned char *printed = NULL;
    memset(buffer, 0, sizeof(buffer));

    buffer->buffer = (unsigned char *)malloc(default_buffer_size);
    buffer->length = default_buffer_size;

    if (buffer->buffer == NULL)
    {
        goto fail;
    }

    if (Kami_Tlv_PrintValue(pstTlv, buffer))
    {
        goto fail;
    }


    printed = (unsigned char *)realloc(buffer->buffer, buffer->offset + 1);
    if (printed == NULL)
    {
        goto fail;
    }
    buffer->buffer = NULL;

    return printed;

fail:
    if (buffer->buffer != NULL)
    {
        free(buffer->buffer);
    }

    if (printed != NULL)
    {
        free(printed);
    }

    return NULL;
}

KamiTlv_S *Kami_Tlv_ParseObject(void *pTlvData, int iLength)
{
    if (!pTlvData || iLength < sizeof(unsigned short) * 2)
    {
        return NULL;
    }
    KamiTlv_S *pstRoot = Kami_Tlv_CreateObject();
    if (!pstRoot)
    {
        return NULL;
    }

    int iOffset = 0;
    char *pcTmp = (char *)pTlvData;

    while (iLength - iOffset > 2 * sizeof(unsigned short))
    {
        unsigned short *pusType = (unsigned short *)(pcTmp + iOffset);
        iOffset += sizeof(unsigned short);
        unsigned short *pusLength = (unsigned short *)(pcTmp + iOffset);
        iOffset += sizeof(unsigned short);
        void *pValue = (void *)(pcTmp + iOffset);
        if (Kami_Tlv_AddTlvToObject(pstRoot, ntohs(*pusType), ntohs(*pusLength), pValue))
        {
            Kami_Tlv_Delete(pstRoot);
            pstRoot = NULL;
            break;
        }
        iOffset += ntohs(*pusLength);
    }

    return pstRoot;

}

KamiTlv_S *Kami_Tlv_GetObjectItem(KamiTlv_S *pstObject, unsigned short usType)
{
    KamiTlv_S *pstNext = NULL;
    KamiTlv_S *pstChild = pstObject->child;
    while (pstChild != NULL)
    {
        pstNext = pstChild->next;
        if (pstChild->type == usType)
        {
            break;
        }
        pstChild = pstNext;
    }

    return pstChild;
}

KamiTlv_S *Kami_Tlv_GetObjectItemIndex(KamiTlv_S *pstObject, int iIndex)
{
    KamiTlv_S *pstChild = NULL;
    if (!pstObject)
    {
        return NULL;
    }
    pstChild = pstObject->child;
    while (pstChild != NULL && iIndex > 0)
    {
        iIndex--;
        pstChild = pstChild->next;
    }

    return pstChild;
}

int Kami_Tlv_GetObjectNumber(KamiTlv_S *pstObject)
{
    KamiTlv_S *pstChild = NULL;
    int iIndex = 0;

    if (!pstObject)
    {
        return NULL;
    }
    pstChild = pstObject->child;
    while (pstChild != NULL)
    {
        iIndex++;
        pstChild = pstChild->next;
    }

    return iIndex;
}

int Kami_Tlv_ObjectLength(KamiTlv_S *pstObject)
{
    return pstObject->length;
}

int main()
{
    KamiTlv_S *pstRoot = Kami_Tlv_CreateObject();
    KamiTlv_S *pstArr1 = Kami_Tlv_CreateArray(16);
    Kami_Tlv_AddTlvToObject(pstArr1, 1, 2, (void *)"a");
    Kami_Tlv_AddTlvToObject(pstArr1, 2, 2, (void *)"b");
    
    KamiTlv_S *pstArr2 = Kami_Tlv_CreateArray(17);
    Kami_Tlv_AddTlvToObject(pstArr2, 1, 2, (void *)"c");
    Kami_Tlv_AddTlvToObject(pstArr2, 2, 2, (void *)"d");

    KamiTlv_S *pstArr3 = Kami_Tlv_CreateArray(18);
    Kami_Tlv_AddTlvToObject(pstArr3, 1, 2, (void *)"e");
    Kami_Tlv_AddTlvToObject(pstArr3, 2, 2, (void *)"f");

    Kami_Tlv_AddItemToObject(pstRoot, pstArr1);
    Kami_Tlv_AddItemToObject(pstArr1, pstArr2);
    Kami_Tlv_AddItemToObject(pstArr2, pstArr3);
    
    


    unsigned char *pr = Kami_Tlv_Print(pstRoot);
    int length = Kami_Tlv_ObjectLength(pstRoot);

    Kami_Tlv_Delete(pstRoot);

    KamiTlv_S *pstParsed1 = Kami_Tlv_ParseObject(pr, length);
    for (int i = 0; i < Kami_Tlv_GetObjectNumber(pstParsed1); i++)
    {
        KamiTlv_S *pstTmp = Kami_Tlv_GetObjectItemIndex(pstParsed1, i);
        printf("type: %d, length: %d\n", pstTmp->type, pstTmp->length);
    }
    KamiTlv_S *pstItem16 = Kami_Tlv_GetObjectItem(pstParsed1, 16);
    KamiTlv_S *pstParsed2 = Kami_Tlv_ParseObject(pstItem16->value, pstItem16->length);
    for (int i = 0; i < Kami_Tlv_GetObjectNumber(pstParsed2); i++)
    {
        KamiTlv_S *pstTmp = Kami_Tlv_GetObjectItemIndex(pstParsed2, i);
        printf("type: %d, length: %d\n", pstTmp->type, pstTmp->length);
    }
    KamiTlv_S *pstItem17 = Kami_Tlv_GetObjectItem(pstParsed2, 17);
    KamiTlv_S *pstParsed3 = Kami_Tlv_ParseObject(pstItem17->value, pstItem17->length);
    for (int i = 0; i < Kami_Tlv_GetObjectNumber(pstParsed3); i++)
    {
        KamiTlv_S *pstTmp = Kami_Tlv_GetObjectItemIndex(pstParsed3, i);
        printf("type: %d, length: %d\n", pstTmp->type, pstTmp->length);
    }
    KamiTlv_S *pstItem18 = Kami_Tlv_GetObjectItem(pstParsed3, 18);
    KamiTlv_S *pstParsed4 = Kami_Tlv_ParseObject(pstItem18->value, pstItem18->length);
    for (int i = 0; i < Kami_Tlv_GetObjectNumber(pstParsed4); i++)
    {
        KamiTlv_S *pstTmp = Kami_Tlv_GetObjectItemIndex(pstParsed4, i);
        printf("type: %d, length: %d\n", pstTmp->type, pstTmp->length);
    }

    return 0;
}

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子忆畅,更是在濱河造成了極大的恐慌,老刑警劉巖蕾管,帶你破解...
    沈念sama閱讀 211,123評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件齿拂,死亡現(xiàn)場(chǎng)離奇詭異步鉴,居然都是意外死亡古劲,警方通過(guò)查閱死者的電腦和手機(jī)创葡,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,031評(píng)論 2 384
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)绢慢,“玉大人,你說(shuō)我怎么就攤上這事洛波∫扔撸” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 156,723評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵蹬挤,是天一觀的道長(zhǎng)缚窿。 經(jīng)常有香客問(wèn)我,道長(zhǎng)焰扳,這世上最難降的妖魔是什么倦零? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,357評(píng)論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮吨悍,結(jié)果婚禮上扫茅,老公的妹妹穿的比我還像新娘。我一直安慰自己育瓜,他們只是感情好葫隙,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,412評(píng)論 5 384
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著躏仇,像睡著了一般恋脚。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上焰手,一...
    開(kāi)封第一講書(shū)人閱讀 49,760評(píng)論 1 289
  • 那天糟描,我揣著相機(jī)與錄音,去河邊找鬼书妻。 笑死船响,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播灿意,決...
    沈念sama閱讀 38,904評(píng)論 3 405
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼估灿,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了缤剧?” 一聲冷哼從身側(cè)響起馅袁,我...
    開(kāi)封第一講書(shū)人閱讀 37,672評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎荒辕,沒(méi)想到半個(gè)月后汗销,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,118評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡抵窒,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,456評(píng)論 2 325
  • 正文 我和宋清朗相戀三年弛针,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片李皇。...
    茶點(diǎn)故事閱讀 38,599評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡削茁,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出掉房,到底是詐尸還是另有隱情茧跋,我是刑警寧澤,帶...
    沈念sama閱讀 34,264評(píng)論 4 328
  • 正文 年R本政府宣布卓囚,位于F島的核電站瘾杭,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏哪亿。R本人自食惡果不足惜粥烁,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,857評(píng)論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望蝇棉。 院中可真熱鬧讨阻,春花似錦、人聲如沸银萍。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,731評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)贴唇。三九已至搀绣,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間戳气,已是汗流浹背链患。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,956評(píng)論 1 264
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留瓶您,地道東北人麻捻。 一個(gè)月前我還...
    沈念sama閱讀 46,286評(píng)論 2 360
  • 正文 我出身青樓纲仍,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親贸毕。 傳聞我的和親對(duì)象是個(gè)殘疾皇子郑叠,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,465評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容