Dump Data by SDR - nmsoccer/sdr GitHub Wiki

使用SDR导出结构体数据

接口

sdr的导出数据接口

  • int sdr_dump_struct(sdr_data_res_t *pres , char *type_name , char *struct_data , FILE *fp);
    • @pres:成功加载的sdr描述符指针
    • @type_name:将要dump的数据结构名.注意是在xml里定义,而不是生成的.h里的结构名
    • @struct_data:内存里的结构体起始地址
    • @fp:dump出的文件句柄
    • @return: -1 failed; 0 success

该接口会将内存里的定义结构导出到指定的文件或者tty中

EXAMPLE

使用的代码及xml文件均放置于demo/dump_data/目录下

协议

制定的dump.xml文件基本延用demo.xml,并做了一些修改。具体如下:

<?xml version="1.0" encoding="utf8" ?>
<!--
基本格式如下 
 -->

<!--  VERSION -->
<macro name="PROTO_VERSION" value="1" />

<!--  技能 -->
<macro name="Q_SKILL" value="1" />
<macro name="W_SKILL" value="2" />
<macro name="E_SKILL" value="3" />
<macro name="R_SKILL" value="4" />
<union name="skill_data" >
    <entry name="qskill" type="char" id="Q_SKILL" />
    <entry name="wskill" type="uint" id="W_SKILL" />
    <entry name="eskill" type="uchar" id="E_SKILL" count="12"/>
    <entry name="rskill" type="short" id="R_SKILL" />
</union>
<struct name="skill_info">
    <entry name="type" type="char" />
    <entry name="data" type="skill_data" select="type" />
</struct>

<!-- 技能列表 -->
<macro name="MAX_SKILL_COUNT" value="32" />
<struct name="skill_list">    
    <entry name="skill_count" type="char" />        
    <entry name="info_list" type="skill_info" count="MAX_SKILL_COUNT" refer="skill_count" />    
</struct>

<struct name="item">
  <entry name="resid" type="int" />
  <entry name="count" type="int" />
  <entry name="instid" type="long long" />
  <entry name="grid" type="char" />
</struct>

<!--  玩家信息 -->
<macro name="MAX_NAME_LEN" value="32" />
<macro name="MAX_ITEM_COUNT" value="4" />
<struct name="user_info" version="1">
    <entry name="sex" type="char" desc="性别" />
    <entry name="name_len" type="char" />
    <entry name="user_name" type="char" count="MAX_NAME_LEN" refer="name_len" desc="姓名"/>
    <entry name="age" type="short" desc="年龄" />
    <entry name="flags" type="uchar" count="10" />
    <entry name="height" type="float" desc="height" />
    <entry name="skill" type="skill_list" desc="技能列表" />
    <entry name="money" type="long long" version="2" desc="金钱" />
    <entry name="gold" type="ulong" version="3" desc="金币" />
    <entry name="item_list" type="item" count="MAX_ITEM_COUNT" />
    <entry name="desc" type="char" count="MAX_NAME_LEN" />
    <entry name="lat" type="double" desc="latitude" />
    <entry name="lng" type="double" desc="longtitude" />
</struct>

代码

在使用conv2sdr.sh处理dump.xml后,我们会得到dump.sdr和dump.h文件,然后使用dump.c里的代码如下:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sdr/sdr.h>
#include "dump.h"

#define MAX_BUFF_LEN (10*1024)
#define SDR_PROTO_FILE "./dump.sdr"
#define OUT_XML "./dump_out.xml"

...

int main(int argc , char **argv)
{
    sdr_data_res_t *pres;
    char buff[MAX_BUFF_LEN] = {0};
    user_info_t src_user;
    user_info_t dst_user;
    int len = 0;
    int version = -1;
    int ret = -1;
    int i = 0;
    FILE *fp = fopen(OUT_XML , "w+");
    if(!fp)
    {
      printf("open %s failed!\n" , OUT_XML);
      return -1;
    }
    //init
    /***设置值start*/
    memset(&src_user , 0 , sizeof(src_user));
    memset(&dst_user , 0 , sizeof(dst_user));
    srand(time(NULL));

    src_user.age = 32;
    src_user.gold = 5000;
    src_user.money = 1289;
    src_user.sex = 1;
    src_user.name_len = strlen("cs_f**k_suomei");
    strncpy(src_user.user_name , "cs_f**k_suomei" , sizeof(src_user.user_name));
    src_user.height = 1.73;
    src_user.lat = 38.65777;
    src_user.lng = 104.08296;

    src_user.flags[0] = 177;
    src_user.flags[1] = 3;
    src_user.skill.skill_count = 2;
    src_user.skill.info_list[0].type = Q_SKILL;
    src_user.skill.info_list[0].data.qskill = 111;

    src_user.skill.info_list[1].type = E_SKILL;
    strncpy(src_user.skill.info_list[1].data.eskill , "wear" , sizeof(src_user.skill.info_list[1].data.eskill));

    for(i=0; i<MAX_ITEM_COUNT; i++)
    {
       src_user.item_list[i].resid = 4000+i;
       src_user.item_list[i].count = i*2;
       src_user.item_list[i].instid = 10000+i;
       src_user.item_list[i].grid = i;
    } 
    strncpy(src_user.desc , "hello world!" , sizeof(src_user.desc));
    strcpy(&src_user.desc[strlen(src_user.desc)+2] , "日了狗");
    /***设置值end*/

    printf("1) orignal==========================\n\n");
    print_user_info(&src_user);
    print_user_info(&dst_user);

    //sdr
    pres = sdr_load_bin(SDR_PROTO_FILE , NULL);
    if(!pres)
    {
    	printf("load %s failed!\n" , SDR_PROTO_FILE);
    	return -1;
    }

    ...
    //test dump
    ret = sdr_dump_struct(pres , "user_info" , (char *)&src_user , fp);
    printf("sdr_dump_struct ret:%d\n" , ret);
    
    //free
    sdr_free_bin(pres);
    return 0;
}

我们在main函数里定义了user_info这个结构,并对里面的成员赋予了各种初值。在代码末尾调用了sdr_dump_struct导出结构内容,并将内容打印到dump_out.xml文件里

编译

gcc -g dump.c -lsdr -o dump

结果

如果成功执行,得到的dump_out.xml内容如下:

<?xml version="1.0" encoding="utf8" ?>
<!-- Created by sdr on 2018-12-29 20:53:44  -->
<!-- @https://github.com/nmsoccer/sdr --> 

<struct name="" type="user_info">
    <entry name="sex" type="char" value="1" />
    <entry name="name_len" type="char" value="14" />
    <entry name="user_name" type="char[]"  size="14" value="'c''s''_''f''*''*''k''_''s''u''o''m''e''i'" />
    <entry name="age" type="short" value="32" />
    <entry name="flags" type="unsigned char[]"  size="10" value="'0xB1''0x3''0x0''0x0''0x0''0x0''0x0''0x0''0x0''0x0'" />
    <entry name="height" type="float" value="1.730000" />
    <struct name="skill" type="skill_list">
        <entry name="skill_count" type="char" value="2" />
        <struct name="info_list" type="skill_info">
            <entry name="type" type="char" value="1" />
            <union name="data" type="skill_data">
                <entry name="qskill" type="char" value="111" />
            </union>
        </struct>
        <struct name="info_list" type="skill_info">
            <entry name="type" type="char" value="3" />
            <union name="data" type="skill_data">
                <entry name="eskill" type="unsigned char[]"  size="12" value="'w''e''a''r''0x0''0x0''0x0''0x0''0x0''0x0''0x0''0x0'" />
            </union>
        </struct>
    </struct>
    <entry name="money" type="long long" value="1289" />
    <entry name="gold" type="unsigned long" value="5000" />
    <struct name="item_list" type="item">
        <entry name="resid" type="int" value="4000" />
        <entry name="count" type="int" value="0" />
        <entry name="instid" type="long long" value="10000" />
        <entry name="grid" type="char" value="0" />
    </struct>
    <struct name="item_list" type="item">
        <entry name="resid" type="int" value="4001" />
        <entry name="count" type="int" value="2" />
        <entry name="instid" type="long long" value="10001" />
        <entry name="grid" type="char" value="1" />
    </struct>
    <struct name="item_list" type="item">
        <entry name="resid" type="int" value="4002" />
        <entry name="count" type="int" value="4" />
        <entry name="instid" type="long long" value="10002" />
        <entry name="grid" type="char" value="2" />
    </struct>
    <struct name="item_list" type="item">
        <entry name="resid" type="int" value="4003" />
        <entry name="count" type="int" value="6" />
        <entry name="instid" type="long long" value="10003" />
        <entry name="grid" type="char" value="3" />
    </struct>
    <entry name="desc" type="char[]"  size="32" value="'h''e''l''l''o'' ''w''o''r''l''d''!''0x0''0x0''0xE6''0x97''0xA5''0xE4''0xBA''0x86''0xE7''0x8B''0x97''0x0''0x0''0x0''0x0''0x0''0x0''0x0''0x0''0x0'" />
    <entry name="lat" type="double" value="38.657770" />
    <entry name="lng" type="double" value="104.082960" />
</struct>

<version name="dump_max" value="3" />

我们可以看到结构成员被依次打印,每个子成员都会有缩进,dump暗含了以下规则:

  • 每个entry都包含了name标签,其值为子成员名
  • 每个entry都包含了value标签,其值为该子成员的内存值
  • 每个entry都包含了type标签, 其值为该子成员类型
  • 如果类型是数组且有refer成员,则打印refer指定数量的成员。如果没有refer则打印数组全部成员
  • 字符型数组(char,uchar类型)的数组会进行特殊处理。每个字节都会被放入''中,且该字节如果可以显示则打印字符,否则打印其16进制数(以0x开头)
  • 数组将会有额外的size标签,其值为该数组的长度
  • 最后会有version标签,其值为该结构体的最大version
⚠️ **GitHub.com Fallback** ⚠️