Ben编码的基本规则

B编码中有4种类型:字符串、整型、列表、字典。

字符串

字符串的编码格式为:<字符串的长度>:<字符串>,其中<>括号中的内容为必需。例如,有一个字符串spam,则经过B编码后为4:spam。

整型

整型的编码格式为:i<十进制的整型数>e,即B编码中的整数以i作为起始符,以e作为终结符,i为integer的第一个字母,e为end的第一个字母。例如,整数3,经过B编码后为i3e,整数−3的B编码为i−3e,整数0的B编码为i0e。

注意i03e不是合法的B编码,因为03不是十进制整数,而是八进制整数。

列表

列表的编码格式为:l<任何合法的类型>e,列表以l为起始符,以e为终结符,中间可以为任何合法的经过B编码的类型,l为list的第一个字母。例如,列表l4:spam4:eggse表示两个字符串,一个是spam,一个是eggs。

字典

字典的编码格式为:d<关键字><值>e,字典以d为起始符,以e为终结符,关键字是一个经过B编码的字符串,值可以是任何合法的B编码类型,在d和e之间可以出现多个关键字和值对,d是dictionary的第一个字母。例如,d4:spaml3:aaa3:bbbee,它是一个字典,该字典的关键字是spam,值是一个列表(以l开始,以e结束),列表中有两个字符串aaa和bbb。

又如:d9:publisher3:bob17:publisher-webpage15:www.example.come,它也是一个字典,第一个关键字是publisher,对应的值为bob,第二个关键字是publisher-webpage,对应的值是www.example.com

对Ben编码的四种基本类型的封装

Ø 定义Ben编码类型的基类

四种基本类型(字符串、整型、列表、字典)均从此基类派生

class __declspec(dllexport) BCODE_TYPE_BASE

: public std::enable_shared_from_this<BCODE_TYPE_BASE>

{

public:

virtual int type() = ;

virtual void add_child(std::shared_ptr<BCODE_TYPE_BASE> child)

{}

virtual void add_child(BCODE_TYPE_MAP_PAIR_ child) 

{}

};

Ø 字符串类型定义

class __declspec(dllexport) BCODE_TYPE_STRING

: public BCODE_TYPE_BASE

{

public:

virtual int type() { return BCODE_STRING;}

void append(char* pStr)

{

strBuf_.append(pStr);

}

std::string& to_string() { return strBuf_;}

protected:

std::string strBuf_;

};

Ø 整型类型定义

class __declspec(dllexport) BCODE_TYPE_INTEGER

: public BCODE_TYPE_BASE

{

public:

virtual int type() { return BCODE_INTEGER;}

LONGLONG& value() { return llNumer_;}

void value(LONGLONG llNum) { llNumer_ = llNum;}

protected:

LONGLONG llNumer_;

};

Ø 列表类型定义

typedef std::vector<std::shared_ptr<BCODE_TYPE_BASE>> BCODE_TYPE_LIST_;

class __declspec(dllexport) BCODE_TYPE_LIST 

: public BCODE_TYPE_BASE

{

public:

virtual int type() { return BCODE_LIST;}

void add_child(std::shared_ptr<BCODE_TYPE_BASE> child)

{

push_back(child);

}

inline std::shared_ptr<BCODE_TYPE_BASE> at(size_t index) 

{

if (index <  || index > list_.size()) return NULL;

return list_[index];

}

inline void remove(size_t index)

{

if (index <  || index > list_.size()) return;

list_.erase(list_.begin() + index);

}

inline void push_back(std::shared_ptr<BCODE_TYPE_BASE> data) 

{ list_.push_back(data);}

inline std::vector<std::shared_ptr<BCODE_TYPE_BASE>>& list()

{ return list_;}

protected:

BCODE_TYPE_LIST_ list_;

};

Ø 字典类型定义

_ptr<BCODE_T

typedef std::map<std::shared_ptr<BCODE_TYPE_STRING>,std::shared_ptr<BCODE_TYPE_BASE>> BCODE_TYPE_MAP_; 

class __declspec(dllexport) BCODE_TYPE_DICTIONARY 

: public BCODE_TYPE_BASE 

{ 

public: 

virtual int type() { return BCODE_DICTIONARY;} 

void add_child(BCODE_TYPE_MAP_PAIR_ child) 

{ 

insert(child.first,child.second); 

} 

inline void insert(std::shared_ptr<BCODE_TYPE_STRING> key, 

std::shared_ptr<BCODE_TYPE_BASE> value) 

{ 

map_.insert(BCODE_TYPE_MAP_PAIR_(key,value)); 

} 

BCODE_TYPE_MAP_PAIR_ find(std::shared

YPE_STRING> key)

{

BCODE_TYPE_MAP_::iterator iter = map_.find(key);

if (iter == map_.end())

return BCODE_TYPE_MAP_PAIR_(NULL,NULL);

return BCODE_TYPE_MAP_PAIR_(iter->first,iter->second);

}

protected:

BCODE_TYPE_MAP_ map_;

};

解析Bencode编码文件

我们从*.torrent文件中读取Ben编码的数据内容。参照Ben编码规则,我们将数据分类型读取保存到列表中即可。核心算法如下:

int BenCoder::parser( FILE* fp,std::shared_ptr<BCODE_TYPE_BASE> parent)

{

if (fp == NULL) return -;

char ch,szBuf[] = {};

// 分析BenCode编码文件

while()

{

// 默认每次读取1个字符

if (getChar(fp,&ch) == -)

break;

// 分类处理字符串、整型、列表、字典

// 以数字开头则为字符串类型

if (is_digit(ch))

{

memset(szBuf,,);

*szBuf = ch;

// 读取字符串的长度信息,读取到‘:’停止

if (read_until(fp,':',szBuf + ,) == -)

return -;

LONGLONG llNumber = _atoi64(szBuf);

LTM::DbgPrint("Type[String] Length[%s]",szBuf);

// 读取字符串内容

memset(szBuf,,);

std::shared_ptr<BCODE_TYPE_STRING> bString(new BCODE_TYPE_STRING);

// 若读取的字符串内容超过1024则分段读取,反之则一次读取成功

while (llNumber > )

{

if (llNumber < )

{

if (getChars(fp,szBuf,llNumber,) == -)

{

return -;

}

llNumber = ;

bString->append(szBuf);

LTM::DbgPrint(" Content[%s]\n",szBuf);

}

else

{

if (getChars(fp,szBuf,,) == -)

{

return -;

}

llNumber = llNumber - ;

bString->append(szBuf);

LTM::DbgPrint("->[%s]\n",szBuf);

}

}

if (parent)

{

// 若父结点为字典类型,则读取字符串类型时

if (parent->type() == BCODE_DICTIONARY)

{

// 若KEY为空,则表明之前未读取字符串做为关键值,此次读取的字符串应该为KEY

if (key_ == NULL)

key_ = bString;

// KEY不为空,则表明之前已经读取字符串做为关键值,此次读取的字符串应该为VALUE

else

{

parent->add_child(BCODE_TYPE_MAP_PAIR_(key_,bString));

key_ = NULL;

}

}

else if (parent->type() == BCODE_LIST)

parent->add_child(bString);

else

data_list_.push_back(bString);

}

else

data_list_.push_back(bString);

}

else if (is_letter(ch))

{

// 整型

if (ch == 'i' || ch == 'I')

{

memset(szBuf,,);

if (read_until(fp,'e',szBuf,) == -)

return -;

LONGLONG llNumber = _atoi64(szBuf);

std::shared_ptr<BCODE_TYPE_INTEGER> bInteger(new BCODE_TYPE_INTEGER);

bInteger->value(llNumber);

if (parent)

{

if (parent->type() == BCODE_DICTIONARY)

{

parent->add_child(BCODE_TYPE_MAP_PAIR_(key_,bInteger));

key_ = NULL;

}

else if (parent->type() == BCODE_LIST)

parent->add_child(bInteger);

else

data_list_.push_back(bInteger);

}

else

data_list_.push_back(bInteger);

LTM::DbgPrint("Type[Integer] Value[%s]\n",szBuf);

}

// 列表

else if (ch == 'l' || ch == 'L')

{

LTM::DbgPrint("Type[List]\n");

std::shared_ptr<BCODE_TYPE_LIST> bList(new BCODE_TYPE_LIST);

if (parent)

{

if (parent->type() == BCODE_DICTIONARY)

{

parent->add_child(BCODE_TYPE_MAP_PAIR_(key_,bList));

key_ = NULL;

}

else if (parent->type() == BCODE_LIST)

parent->add_child(bList);

else

data_list_.push_back(bList);

}

else

data_list_.push_back(bList);

parser(fp,bList);

}

// 字典

else if (ch == 'd' || ch == 'D')

{

LTM::DbgPrint("Type[Dictionary]\n");

std::shared_ptr<BCODE_TYPE_DICTIONARY> bMap(new BCODE_TYPE_DICTIONARY);

if (parent)

{

if (parent->type() == BCODE_DICTIONARY)

{

parent->add_child(BCODE_TYPE_MAP_PAIR_(key_,bMap));

key_ = NULL;

}

else if (parent->type() == BCODE_LIST)

parent->add_child(bMap);

else

data_list_.push_back(bMap);

}

else

data_list_.push_back(bMap);

parser(fp,bMap);

}

else if (ch == 'e')

{

LTM::DbgPrint("end when read of 'e'\n");

break;

}

// 未知

else

{

LTM::DbgPrint("It has a unknow type when parser BCode File!\n");

}

}

else

{

LTM::DbgPrint("It has a unknow error when parser BCode File!\n");

}

}

return ;

}

源代码下载

最后附上完整代码的下载地址:http://download.csdn.net/detail/ltm5180/8001439

工程为DLL工程,对Ben编码文件的读取操作全部封装到BenCoder类中,使用示例:

BenCoder* coder = BenCoder::getInstance();

if (coder)

{

coder->SetstrFilepath("E:\\WorkSpaces\\proj\\BTLoader\\trunk\\Win32\\Debug\\ 0035.torrent");

coder->load();

}

BenCoder::freeInstance(coder);

Bencode编码解析的C++实现的更多相关文章

  1. 小记 js unicode 编码解析

    原文:小记 js unicode 编码解析 var str = "\\u6211\\u662Funicode\\u7F16\\u7801"; 关于这样的数据转换为中文问题,常用的两 ...

  2. Python解析xml文件遇到的编码解析的问题

    使用python对xml文件进行解析的时候,假设xml文件的头文件是utf-8格式的编码,那么解析是ok的,但假设是其它格式将会出现例如以下异常: xml.parsers.expat.ExpatErr ...

  3. HTTP1.1中CHUNKED编码解析(转载)

    HTTP1.1中CHUNKED编码解析 一般HTTP通信时,会使用Content-Length头信息性来通知用户代理(通常意义上是浏览器)服务器发送的文档内容长度,该头信息定义于HTTP1.0协议RF ...

  4. XCTF练习题---CRYPTO---混合编码解析

    XCTF练习题---CRYPTO---混合编码解析 flag:cyberpeace{welcometoattackanddefenceworld} 解题步骤: 1.观察题目,下载附件进行查看 2.看到 ...

  5. 中国天气网 JSON接口的城市编码解析及结果

    最近在弄一个Android应用,其中一个功能是天气情况展示,准备使用google的天气API服务(http://www.google.com/ig/api?hl=zh-cn&weather=, ...

  6. js小记 unicode 编码解析

    var str = "\\u6211\\u662Funicode\\u7F16\\u7801"; // 关于这样的数据转换为中文问题,常用的两种方法. // 1. eval 解析 ...

  7. Spring第七弹—依赖注入之注解方式注入及编码解析@Resource原理

        注入依赖对象可以采用手工装配或自动装配,在实际应用中建议使用手工装配,因为自动装配会产生未知情况,开发人员无法预见最终的装配结果. 手工装配依赖对象  手工装配依赖对象,在这种方式中又有两种编 ...

  8. HTTP1.1中CHUNKED编码解析

    一般HTTP通信时,会使用Content-Length头信息性来通知用户代理(通常意义上是浏览器)服务器发送的文档内容长度,该头信息定义于HTTP1.0协议RFC  1945  10.4章节中.浏览器 ...

  9. Java Web中的编码解析

    在springmvc工程web.xml中配置中文编码 <!-- 配置请求过滤器,编码格式设为UTF-8,避免中文乱码--> <filter> <filter-name&g ...

随机推荐

  1. 《30天自制操作系统》读书笔记(3) 引入C语言

    这一次的学习相当曲折, 主要是因为粗心, Makefile里面的错误导致了文件生成出现各种奇奇怪怪的问题, 弄得心力交瘁, 因此制作过程还是尽量按着作者的路子来吧. 作者提供的源码的注释在中文系统下是 ...

  2. jQuery的选择器中的通配符[id^='code'] 【转】

    JQuery 1.选择器 (1)通配符: $("input[id^='code']");//id属性以code开始的所有input标签 $("input[id$='cod ...

  3. Delphi GDI或图像处理的博客

    http://blog.csdn.net/w1028489713/article/category/1918251

  4. 国内大学毕业论文LaTeX模板集合

    国内大学毕业论文LaTeX模板集合 薛瑞尼的清华大学学位论文LaTeX模板http://sourceforge.net/projects/thuthesis/ 北大论文文档 LaTeX 模板 pkut ...

  5. android sudio 记录

    1. KVM is not installed on this machine (/dev/kvm is missing) 原文网址:http://askubuntu.com/questions/56 ...

  6. 一个ASPX页面的生命周期?

    大家都知道客户端请求一个ASPX页面,通过iis中接收,会被的interinfo.exe进程截取,判断其扩展名,再把请求转交给ASPNET_ISAPI.DLL,通过isapi扩展进入相应的管道处理,转 ...

  7. Windows打印管理解决方案

    需求 从需求出发,我们的目的是在电脑上提供一个虚拟打印机,然后让用户选择这个虚拟机打印时产生的中间文件被拦截下来,之后进行进一步处理后在执行真实的打印. Windows打印体系 首先附上查找Windo ...

  8. 1001 Sum Problem [ACM刷题]

    这一段时间一直都在刷OJ,这里建一个博客合集,用以记录和分享算法学习的进程. github传送门:https://github.com/haoyuanliu/Online_Judge/tree/mas ...

  9. Runtime.getRuntime().addShutdownHook(shutdownHook);

    今天在阅读Tomcat源码的时候,catalina这个类中使用了下边的代码,不是很了解,所以google了一下,然后测试下方法,Tomcat中的相关代码如下: Runtime.getRuntime() ...

  10. android开发4:Android布局管理器1(线性布局,相对布局RelativeLayout-案例)

    控件类概述 View 可视化控件的基类 属性名称 对应方法 描述 android:background setBackgroundResource(int) 设置背景 android:clickabl ...