Dump Data by SDR - nmsoccer/sdr GitHub Wiki
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中
使用的代码及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