赞
踩
概述:
本方法定义了一种数据结构,可用于描述任意的树形二进制协议,并配合一个特定的处理算法,可实现一种通用的,由该种树形二进制协议定义的比特流解析与填充的处理,该数据结构的定义如下:
/* 以下结构用于定义一个协议节点的描述信息。 */
struct _proto_bits_info;
typedef struct _proto_unit_des {
const char * name; /* 用于描述一个协议节点的名称。 */
size_t staticSize; /* 用于描述一个协议节点的大小,单位是比特,对于可变长编码(如UTF8)的协议节点,或长度不固定的复合型(即由子协议组成的)协议节点,该值为0。 */
uint32_t isCondition; /* 用于描述该协议节点是否为另一个或多个协议节点的条件节点(如定义长度或标记位的协议节点),如果是,则该值为相关协议节点的个数,因此该值的类型为整型而非布尔型。 */
const struct _proto_unit_des *condition; /* 用于描述该协议节点是否与一个条件节点相关,如果是,则该指针指向其条件节点的描述。 */
list_obj subDesList; /* 用于记录该协议节点的所有下级子协议节点,该值的类型可以是任意集合类型,本实现采用的是list。 */
size_t (*SizeInBit) (const struct _proto_bits_info * protoInfo); /* 一个可适配的,计算该协议节点大小的函数,单位为比特, 用于计算可变长编码或长度不固定的复合型(即该协议节点的 staticSize 为 0 的)协议节点的大小,当该协议节点的 staticSize 不为 0 时则返回 staticSize 的值。 */
size_t (*Length) (const struct _proto_bits_info * protoInfo); /* 一个可适配的,计算该协议节点长度(即个数)的函数,当该函数返回值为 0 时,即表示该协议节点不存在(此时,该协议节点必然与一个条件节点相关,且它的条件节点的值不满足该协议节点的存在条件)。 */
size_t (*TotalSize) (const struct _proto_bits_info * protoInfo); /* 一个可适配的,计算该协议节点总大小的函数,单位为比特,若该协议节点的 staticSize 不为 0,则简单返回该协议节点的 staticSize 乘以该协议节点的 Length 函数的返回值,否则,逐个的累加该协议节点的 SizeInBit 函数的返回值,累加的次数由该协议节点的 Length 函数的返回值指定。 */
} proto_unit_des;
/* 以下结构用于定义某段比特流的具体含义。 */
typedef struct _proto_bits_info {
const proto_unit_des * protoDes; /* 该段比特流对应的协议描述。 */
uint8_t * buffer; /* 该段比特流对应的缓冲区起始地址。 */
offset_t itemNum; /* 该段比特流对应的协议描述的下标(即,当对应 protoDes 的 Length 函数返回值大于0时,该值指示了这段比特流的编号),从 0 开始。 */
offset_t dataOffset; /* 该段比特流的数据偏移位,单位为比特。 */
offset_t condOffset; /* 该段比特流的条件段(即,当对应 protoDes 的 condition 不为 0 时,该 condition 对应的比特段)的偏移位,单位为比特。 */
void * subDesNode; /* 用于协议描述树的编历,禁止直接访问。 */
offset_t subItemNum; /* 用于协议描述树的编历,禁止直接访问。 */
} proto_bits_info;
处理比特流的算法:
1)使用 proto_unit_des 定义目标二进制协议的协议描述树;
2)定义以下的数据结构用于回溯条件段:
typedef struct {
const proto_unit_des *protoDes; /* 该条件段对应的协议描述,该协议描述的 isCondition 的值必然大于 0。*/
offset_t dataOffset; /* 该条件段的数据偏移位。 */
size_t refCount; /* 该条件段的引用计数。 */
} cond_proto_bits_info;
3)定义以下的数据结构用于记录处理过程中的上下文:
typedef struct {
uint8_t * dataBuf; /* 待处理比特流的缓冲区地址。 */
size_t dataSize; /* 待处理比特流的缓冲区大小。 */
offset_t dataOffset; /* 当前待处理数据的偏移位,初始值为 0。 */
list_obj condBacktrace; /* 条件段的集合,该集合中的每一个元素都为步骤2定义的数据结构,本实现采用的集合类型为 list。 */
list_obj protoInfoStack; /* 缓存 proto_bits_info 的栈,本实现采用的栈类型为 list。 */
} protocol_parser_ctx;
4)定义以下的函数用于从一个 proto_bits_info 的实例中创建一个步骤2)定义的 cond_proto_bits_info 的实例,并压入步骤3)定义的上下文中的 condBacktrace:
static void condition_backtrace_set(
list_obj * backtrace, const proto_bits_info * protoInfo)
{
cond_proto_bits_info_obj condObj = {0};
if ( operator_new(&cond_proto_bits_info_des, &condObj) ) {
cond_proto_bits_info * condInfo = (cond_proto_bits_info *) condObj._ctx;
condInfo->protoDes = protoInfo->protoDes;
condInfo->dataOffset = protoInfo->dataOffset;
condInfo->refCount = 0;
backtrace->_cls->PushFront(backtrace->_ctx, &condObj);
}
}
5)定义以下的函数用于从步骤3)定义的上下文中的 condBacktrace 中查找条件段的偏移位,并且删除无用的元素:
static offset_t condition_backtrace_get(
list_obj * backtrace, const proto_unit_des * protoDes, bool ref)
{
if ( backtrace->_cls->GetItemCount(backtrace->_ctx) ) {
void * condNode = backtrace->_cls->GetItem(backtrace->_ctx, 0);
cond_proto_bits_info * condInfo = 0;
cond_proto_bits_info_obj condObj = {0};
do {
backtrace->_cls->GetItemValue(condNode, &condObj);
condInfo = (cond_proto_bits_info *) condObj._ctx;
if (condInfo->protoDes == protoDes) {
offset_t condOffset = condInfo->dataOffset;
if (ref) {
if ( protoDes->isCondition == ++(condInfo->refCount) ) {
backtrace->_cls->SwapAndDropItem(
backtrace->_ctx, condNode
);
}
}
return condOffset;
}
condNode = backtrace->_cls->GetItem(backtrace->_ctx, condNode);
} while (condNode);
}
return 0;
}
6)定义以下的函数用于初始化一个 proto_bits_info 的实例:
static const proto_unit_des * protocol_parser_set_proto_bits_info(
protocol_parser_ctx * ctx,
proto_bits_info * protoInfo,
proto_unit_des_obj * protoDesObj,
offset_t itemNum,
bool refCond)
{
proto_unit_des * protoDes = (proto_unit_des *) protoDesObj->_ctx;
protoInfo->protoDes = protoDes;
protoInfo->buffer = ctx->dataBuf;
protoInfo->itemNum = itemNum;
protoInfo->dataOffset = ctx->dataOffset;
if (protoDes->condition) {
protoInfo->condOffset = condition_backtrace_get(
&ctx->condBacktrace, protoDes->condition, refCond
);
}
else
protoInfo->condOffset = 0;
return protoDes;
}
7)定义以下的函数用于创建 proto_bits_info 的实例,并压入步骤3)定义的上下文中的 protoInfoStack (若过程中的 proto_bits_info 实例的协议节点是一个条件协议节点,则会执行步骤4)定义的函数):
static void protocol_parser_push_proto_unit_des(
protocol_parser_ctx * ctx, proto_unit_des_obj * protoDesObj, offset_t itemNum)
{
proto_unit_des_obj desObj = *protoDesObj;
proto_bits_info_obj protoObj = {0};
proto_bits_info * protoInfo = 0;
const proto_unit_des * protoDes = 0;
do {
if ( !operator_new(&proto_bits_info_des, &protoObj) )
break;
if (protoInfo) {
itemNum = 0; /* protoInfo->subItemNum is always 0, so set itemNum
to 0 instead of protoInfo->subItemNum. */
protoInfo->subDesNode = protoDes->subDesList._cls->GetItem(
protoDes->subDesList._ctx, 0
);
protoDes->subDesList._cls->GetItemValue(
protoInfo->subDesNode, &desObj
);
}
protoInfo = (proto_bits_info *) protoObj._ctx;
protoDes = protocol_parser_set_proto_bits_info(
ctx, protoInfo, &desObj, itemNum, REF_CONDITION
);
if (protoDes->isCondition)
condition_backtrace_set(&ctx->condBacktrace, protoInfo);
ctx->protoInfoStack._cls->PushFront(
ctx->protoInfoStack._ctx, &protoObj
);
} while ( protoDes->subDesList._cls->GetItemCount(
protoDes->subDesList._ctx
) );
}
8)定义以下的函数用于初始化步骤3)定义的上下文:
static void protocol_parser_reset(protocol_parser_ctx * ctx) {
ctx->dataOffset = 0;
ctx->condBacktrace._cls->Clear(ctx->condBacktrace._ctx);
ctx->protoInfoStack._cls->Clear(ctx->protoInfoStack._ctx);
}
static bool protocol_parser_begin_parse(
ctx_t ctx, uint8_t * buffer, size_t bufSize, proto_unit_des_obj * protoDesObj)
{
if (ctx && buffer && bufSize && protoDesObj &&
protoDesObj->_cls && protoDesObj->_ctx)
{
protocol_parser_ctx * parserCtx = (protocol_parser_ctx *) ctx;
parserCtx->dataBuf = buffer;
parserCtx->dataSize = bufSize;
protocol_parser_reset(parserCtx);
protocol_parser_push_proto_unit_des(parserCtx, protoDesObj, 0);
return true;
}
return false;
}
9)定义以下的函数用于从步骤3)定义的上下文中解析出一个 proto_bits_info 的实例:
static bool protocol_parser_parse(ctx_t ctx, proto_bits_info * out_protoInfo) {
if (ctx) {
protocol_parser_ctx * parserCtx = (protocol_parser_ctx *) ctx;
list_obj * protoInfoStack = &(parserCtx->protoInfoStack);
void * protoNode = protoInfoStack->_cls->GetItem(
protoInfoStack->_ctx, 0
);
if (protoNode) {
proto_bits_info * protoInfo = 0;
const proto_unit_des * protoDes = 0;
proto_bits_info_obj protoObj = {0};
proto_unit_des_obj subDesObj = {0};
proto_bits_info subProtoInfo = {0};
const proto_unit_des * subDes = 0;
protoInfoStack->_cls->GetItemValue(protoNode, &protoObj);
protoInfo = (proto_bits_info *) protoObj._ctx;
protoDes = protoInfo->protoDes;
while (protoInfo->subDesNode) {
protoInfo->subDesNode = protoDes->subDesList._cls->GetItem(
protoDes->subDesList._ctx, protoInfo->subDesNode
);
if (!protoInfo->subDesNode) {
if ( ++(protoInfo->subItemNum) >= \
protoDes->Length(protoInfo) )
{
protoInfo->subItemNum = 0;
break;
}
protoInfo->subDesNode = protoDes->subDesList._cls->GetItem(
protoDes->subDesList._ctx, 0
);
}
protoDes->subDesList._cls->GetItemValue(
protoInfo->subDesNode, &subDesObj
);
subDes = protocol_parser_set_proto_bits_info(
parserCtx,
&subProtoInfo,
&subDesObj,
protoInfo->subItemNum,
PEEK_CONDITION
);
if ( subDes->Length(&subProtoInfo) ) {
protocol_parser_push_proto_unit_des(
parserCtx, &subDesObj, protoInfo->subItemNum
);
break;
}
if (subDes->condition) {
condition_backtrace_get(
&(parserCtx->condBacktrace),
subDes->condition,
REF_CONDITION
);
}
}
protoInfoStack->_cls->PopFront(
protoInfoStack->_ctx, &protoObj
);
protoInfo = (proto_bits_info *) protoObj._ctx;
protoDes = protoInfo->protoDes;
if (protoDes->staticSize) {
parserCtx->dataOffset = \
protoInfo->dataOffset + protoDes->TotalSize(protoInfo);
}
if (parserCtx->dataOffset <= parserCtx->dataSize * 8) {
*out_protoInfo = *protoInfo;
operator_delete(&protoObj);
return true;
}
operator_delete(&protoObj);
protocol_parser_reset(parserCtx);
}
}
return false;
}
10)循环执行步骤9)定义的函数,直至返回 false 。
如果是解析比特流,则即可获得一个 proto_bits_info 的序列;
如果是填充比特流,则每获得一个 proto_bits_info 的实例,根据其信息填充相关的数据到缓冲区中。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。