本文中的程序是用来将不同类型的 B 编码数据信息解析为对应类型的信息并进行输出的,
编程环境为 vs2010, 语言为: C++
经过调试已经能够正常运行,但是输出的信息以及类之间的结构还需要进一步的调整
该头文件中将B编码中不同类型抽象为类来进行表示,基类为 AnyType 对应的是用来表示所有类型的类。
在其中定义了 B编码中所有类型抽象的类中,所需要的方法。
其余的 StringType ,IntegerType , DictType , ListType 分别对应的是 B 编码中的 字符串类型(strings),整型类型(integers)
字典类型(Dict Type) 和列表类型(List Type)
这些不同的类型均继承自同一个父类 : AnyType 并通过虚函数来实现了父类中定义的方法,
这里通过虚函数来设定是为了在调用方法的时候,可以通过父类指针变量来动态绑定对应子类的方法进行调用。
不同的类型中存放数值的变量也是不同的:
整型类型中用于存放变量的是 int 整型
字符串类型中用来存放变量的是 string 字符串类型
列表类型中用来存放的是 vector> 它是一个可以指向任何一种类型(整型,字符串,列表,字典)的指针
所构成的列表(向量) ; 这一定义刚好满足了list 类型 l....e 中间可以存放任何类型的合法 B 编码的设定。
字典类型中用来存放的变量类型是 map> 它是{键值对}散列表类型,因为我们在前几篇文章中知道,
字典类型的关键字一定是 strings 字符串类型,所以 map 中的 key 的类型必定是 StringType * 也就是我们之前设定的字符串类型
的指针(在这里使用指针是为了节省空间,不然需要额外的一部分空间来将数据类型存放至散列中);
而对于 dict 字典类型而言,它的值类型同列表一样: 可以是任意的合法的B 编码类型即可,所以使用 AnyType指针,即指向任意类型的指针来指向具体的值的类型。
在下面的 torrentParser.cpp 源文件中给出了头文件中仅仅声明没有实现的方法的实现
-
// torrentParser.cpp
-
-
#include <cstdio>
-
#include <vector>
-
#include <map>
-
#include <cstring>
-
#include <iostream>
-
-
#include "parser_utils.h" // contains all common util method
-
#include "torrentParser.h"
-
-
using namespace std ;
-
-
-
bool IntegerType::parser( string &content )
-
{
-
if ( content.empty () )
-
return false ;
-
-
if ( content[0] != 'i' )
-
return false ;
-
-
size_t pos = content.find('e' , 0) ;
-
-
if ( pos == string::npos )
-
return false ;
-
-
string s_value = content.substr(1, pos-1) ;
-
-
parserUtils::string_to_int(s_value , _value ) ;
-
-
content = content.erase ( 0 , pos+1 ) ;
-
-
return true ;
-
}
-
-
-
bool StringType::parser( string & content )
-
{
-
//cout <<"content " << content << endl ;
-
-
if ( content.empty () )
-
return false ;
-
-
if ( content.size () < 3 )
-
return false ;
-
-
size_t pos = content.find(':' , 0 ) ;
-
-
if ( pos == string::npos )
-
return false ;
-
-
int count = 0 ;
-
-
parserUtils::string_to_int( content.substr( 0 ,pos) , count ) ;
-
-
//printf ("count = %d pos = %d \n" , count , pos ) ;
-
-
_value = content.substr( pos+1 , count ) ;
-
-
content = content.erase(0 , pos+1+count ) ;
-
-
//cout << _value << endl ;
-
-
// cout << "content 2 : " << content << endl ;
-
-
return true ;
-
}
-
-
bool ListType::parser ( string &content )
-
{
-
if ( content.empty () )
-
return false ;
-
-
if ( content[0] != 'l' )
-
return false ;
-
-
content = content.erase(0,1) ; // delete 'l'
-
-
while ( !content.empty () )
-
{
-
AnyType * anyType = NULL ;
-
-
if ( content[0] == 'l' )
-
anyType = new ListType () ;
-
else if ( content[0] == 'i' )
-
anyType = new IntegerType ();
-
else if ( content[0] == 'd' )
-
anyType = new DictType () ;
-
else
-
anyType = new StringType () ;
-
-
anyType->parser( content ) ;
-
// call this method will parse the content into
-
// the right value and store it into the _value of
-
// anyType
-
-
_list_values.push_back(anyType) ;
-
-
if ( content[0] == 'e' )
-
{
-
// arrived the end of the list
-
-
content = content.erase (0,1) ;
-
break ;
-
}
-
} // while
-
-
return true ;
-
}
-
-
bool DictType::parser ( string &content )
-
{
-
-
if ( content[0] != 'd' )
-
return false ;
-
if ( content.size () < 3 )
-
return false ;
-
-
content = content.erase ( 0 , 1 ) ; // delete 'd'
-
-
while ( !content.empty () )
-
{
-
StringType *key = new StringType () ;
-
key->parser (content) ;
-
// extract the key : string from dict <key>:<value>
-
-
if ( content.empty () )
-
break ;
-
-
AnyType *anyType = NULL ; // value is type of list
-
// we not sure what and how many type list will store
-
-
if ( content[0] =='i' ) // type of integer
-
anyType = new IntegerType () ;
-
else if ( content[0] == 'l' ) // type of list
-
anyType = new ListType () ;
-
else if ( content[0] == 'd' ) // type of dict
-
anyType = new DictType () ;
-
-
else // type of string , begin with an integer
-
anyType = new StringType () ;
-
-
if ( anyType == NULL ) // contents is empty now
-
return false ;
-
-
anyType->parser(content) ;
-
-
_map_values[key] = anyType ;
-
-
if ( content[0] == 'e' )
-
{
-
// end of the dict : <d>....<e>
-
content = content.erase(0 , 1) ;
-
break ;
-
}
-
}
-
return true ;
-
}
下面的代码是 parser_utils.h
在该头文件中定义了一个包含着全局所需要的公共方法的类,并且在类中以静态方法的方式给出了所有所需公共方法的实现
-
//parser_utils.h
-
-
#ifndef PARSER_UTILS_H
-
#define PARSER_UTILS_H
-
#include <string>
-
-
class parserUtils
-
{
-
public :
-
static void string_to_int( std::string value ,int & integer )
-
{
-
int result = 0 ;
-
int temp = 0 ;
-
-
for ( int i = 0 ; i < value.size() ; i++ )
-
{
-
temp = value[i]-'0' ; // get the number
-
result = result *10 ;
-
result += temp ;
-
-
//printf ("result %d i = %d temp %d , pow(10 , %d ) = %d \n\n" , result , i , temp , i ,(int)(pow(10 , i ))) ;
-
}
-
-
integer = result ;
-
}
-
-
} ;
-
-
#endif // parser_utils.h
下面的代码是调用所有方法的主函数所在的文件
-
#include <cstdio>
-
#include <string>
-
#include <cstdlib>
-
#include <iostream>
-
-
#include "parser_utils.h"
-
#include "torrentParser.h"
-
-
-
using namespace std ;
-
-
int main ( void )
-
{
-
int result ;
-
string content ;
-
IntegerType integerType ;
-
StringType stringType ;
-
ListType listType ;
-
DictType dictType ;
-
-
-
cin >>content ;
-
-
//integerType.parser(content) ;
-
//stringType.parser (content) ;
-
// listType.parser(content) ;
-
dictType.parser(content) ;
-
-
//cout<< stringType._value <<endl ;
-
-
dictType.showValue() ;
-
-
system("pause") ;
-
return 0 ;
-
}
运行程序输入一个 dict 字典类型的 B编码信息:
d12:inuyasha1027li32167e22:this_is_a_test_of_dicteee
运行程序输出结果为:
在这里请注意,在解析 .torrent 文件的时候是直接从.torrent 文件中进行读取信息的。
而这里是使用 cin 和手动输入数据,所以在你输入的数据中空格会被计算机默认为结束输入的标志。
我曾经输入 this is a test of dict ,结果被计算机认为是空格的时候输入结束导致很多信息没有被读入。
end
阅读(1363) | 评论(0) | 转发(0) |