google 的 protobuf 项目,底层的二进制格式设计很精简,格式的详细描述参考下面的链接:
[url]http://code.google.com/apis/protocolbuffers/docs/encoding.html[/url]
下载链接
[url]http://spjson.googlecode.com/files/spjson-0.3.src.tar.gz[/url]
暂时是作为 spjson 的一部分。
这个格式被 google 才称为 wire format ,实质是一个用于保存 key/value 对的二进制格式。
key 被称为 fieldNumber 。
value 分为几种类型:varint,64bit,32bit,Length-delimited 。
varint 是指变长整数,实质上可能对应 int8,int16,int32,int64 和他们的有符号类型。varint 对于保存小整数有非常好的压缩效果,对于 <= 128 的整数只需要一个字节。具体的算法可以参考上面的链接。
64bit 和 32bit 按我的理解主要可能是用于映射 double 和 float 。因为整数本身已经全部可以通过 varint 来解决了。 把 double 和 float 按 little-endian byte order 进行保存。
Length-delimited 用于保存字符串和二进制数据。二进制数据可能是另外一个 protobuf ,这样就可以实现支持内嵌复杂类型的功能。
实现用典型的 codec 的方式来实现,一个 encoder 和一个 decoder 。
[code]
class SP_ProtoBufEncoder
{
public:
SP_ProtoBufEncoder( int initLen = 0 );
~SP_ProtoBufEncoder();
int addVarint( int fieldNumber, uint64_t value );
int addDouble( int fieldNumber, double value );
int addFloat( int fieldNumber, float value );
int addBinary( int fieldNumber, const char * buffer, int len );
const char * getBuffer();
int getSize();
};
class SP_ProtoBufDecoder
{
public:
SP_ProtoBufDecoder( const char * buffer, int len );
~SP_ProtoBufDecoder();
bool getNext( KeyValPair_t * pair );
bool find( int fieldNumber, KeyValPair_t * pair, int index = 0 );
};
[/code]
encoder 对于不同的类型,提供了对应的 add 方法。在任何时候,都可以调用 encoder 的 getBuffer 和 getSize 获取当前已经生成的 buffer 。
decoder 提供 getNext 和 find 两个方法。getNext 用于遍历 protobuf 的所有字段。find 方法用于根据 fieldNumber 来获取对应的字段。定义了一个辅助数据结构 KeyValPair_t 来简化这个两个方法的参数。find 方法内部使用二分查找法来加速。
[url]http://code.google.com/apis/protocolbuffers/docs/encoding.html[/url]
下载链接
[url]http://spjson.googlecode.com/files/spjson-0.3.src.tar.gz[/url]
暂时是作为 spjson 的一部分。
这个格式被 google 才称为 wire format ,实质是一个用于保存 key/value 对的二进制格式。
key 被称为 fieldNumber 。
value 分为几种类型:varint,64bit,32bit,Length-delimited 。
varint 是指变长整数,实质上可能对应 int8,int16,int32,int64 和他们的有符号类型。varint 对于保存小整数有非常好的压缩效果,对于 <= 128 的整数只需要一个字节。具体的算法可以参考上面的链接。
64bit 和 32bit 按我的理解主要可能是用于映射 double 和 float 。因为整数本身已经全部可以通过 varint 来解决了。 把 double 和 float 按 little-endian byte order 进行保存。
Length-delimited 用于保存字符串和二进制数据。二进制数据可能是另外一个 protobuf ,这样就可以实现支持内嵌复杂类型的功能。
实现用典型的 codec 的方式来实现,一个 encoder 和一个 decoder 。
[code]
class SP_ProtoBufEncoder
{
public:
SP_ProtoBufEncoder( int initLen = 0 );
~SP_ProtoBufEncoder();
int addVarint( int fieldNumber, uint64_t value );
int addDouble( int fieldNumber, double value );
int addFloat( int fieldNumber, float value );
int addBinary( int fieldNumber, const char * buffer, int len );
const char * getBuffer();
int getSize();
};
class SP_ProtoBufDecoder
{
public:
SP_ProtoBufDecoder( const char * buffer, int len );
~SP_ProtoBufDecoder();
bool getNext( KeyValPair_t * pair );
bool find( int fieldNumber, KeyValPair_t * pair, int index = 0 );
};
[/code]
encoder 对于不同的类型,提供了对应的 add 方法。在任何时候,都可以调用 encoder 的 getBuffer 和 getSize 获取当前已经生成的 buffer 。
decoder 提供 getNext 和 find 两个方法。getNext 用于遍历 protobuf 的所有字段。find 方法用于根据 fieldNumber 来获取对应的字段。定义了一个辅助数据结构 KeyValPair_t 来简化这个两个方法的参数。find 方法内部使用二分查找法来加速。