Chinaunix首页 | 论坛 | 博客
  • 博客访问: 584644
  • 博文数量: 104
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 1559
  • 用 户 组: 普通用户
  • 注册时间: 2014-08-21 00:58
个人简介

锻炼精神,首先要锻炼肉体

文章分类

全部博文(104)

文章存档

2018年(1)

2016年(1)

2015年(101)

2014年(1)

我的朋友

分类: C/C++

2015-04-10 23:10:43

本文中的程序是用来将不同类型的 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指针,即指向任意类型的指针来指向具体的值的类型。

点击(此处)折叠或打开

  1. //torrentParser.h

  2. #ifndef TORRENT_PARSER_H
  3. #define TORRENT_PARSER_H

  4. #include <string>
  5. #include <map>
  6. #include <vector>

  7. using namespace std ;

  8. // torrentParser.h

  9. class AnyType
  10. {
  11. public :
  12.     virtual ~AnyType () {}
  13.     virtual void showValue () {}
  14.     virtual bool parser ( std::string &content) = 0 ;
  15. } ;

  16. class IntegerType : public AnyType
  17. {
  18. public :
  19.     virtual ~IntegerType () {}
  20.     virtual bool parser ( std::string &content ) ;
  21.     virtual void showValue ()
  22.     {
  23.         cout << "integer type value : "<< _value << endl ;
  24.     }
  25.     int _value ;
  26. } ;

  27. class StringType : public AnyType
  28. {
  29. public :
  30.     virtual ~StringType () {}
  31.     virtual bool parser( std::string & content ) ;
  32.         
  33.     string _value ;

  34.     virtual void showValue ()
  35.     {
  36.         cout <<"string type value : "<< _value << endl ;
  37.     }
  38. } ;


  39. class ListType : public AnyType
  40. {
  41. public :
  42.     virtual ~ListType ()
  43.     {
  44.         for ( std::vector<AnyType*>::iterator it = _list_values.begin() ;
  45.             it != _list_values.end () ; it++ )
  46.         {
  47.             delete *it ;
  48.         }

  49.         _list_values.clear() ;
  50.     }

  51.     virtual bool parser ( std::string &content ) ;

  52.     virtual void showValue ()
  53.     {
  54.         cout <<" listType show values " << endl ;

  55.         for ( vector<AnyType*>::iterator it = _list_values.begin() ; it != _list_values.end() ; it++ )
  56.         {
  57.             (*it)->showValue() ;
  58.         }
  59.     }
  60.     std::vector<AnyType*> _list_values ;
  61. } ;


  62. class DictType : public AnyType
  63. {
  64. public :
  65.     virtual ~DictType ()
  66.     {
  67.         for ( std::map<StringType*, AnyType *>::iterator it = _map_values.begin() ;
  68.             it != _map_values.end () ; it++ )
  69.         {
  70.             delete it->first ;
  71.             delete it->second ;
  72.         }
  73.             
  74.         _map_values.clear () ;
  75.     }


  76.     virtual bool parser ( std::string &content ) ;

  77.     virtual void showValue ()
  78.     {
  79.         cout << " dict type show values " << endl ;

  80.         for ( map<StringType *, AnyType *>::iterator it = _map_values.begin() ;
  81.             it != _map_values.end () ; it++ )
  82.         {
  83.             StringType *it1 = it->first ;
  84.             AnyType *it2 = it->second ;

  85.             cout<<"key : " ;
  86.             it1->showValue() ;
  87.             cout<<endl ;

  88.             cout <<"value :" ;
  89.             it2->showValue() ;
  90.             cout<< endl ;
  91.         }

  92.     }

  93.     map<StringType * , AnyType *> _map_values ;
  94. } ;

  95. #endif // torrentParser.h
在下面的 torrentParser.cpp 源文件中给出了头文件中仅仅声明没有实现的方法的实现

点击(此处)折叠或打开

  1. // torrentParser.cpp

  2. #include <cstdio>
  3. #include <vector>
  4. #include <map>
  5. #include <cstring>
  6. #include <iostream>

  7. #include "parser_utils.h" // contains all common util method
  8. #include "torrentParser.h"

  9. using namespace std ;

  10.  
  11. bool IntegerType::parser( string &content )
  12. {
  13.     if ( content.empty () )
  14.         return false ;

  15.     if ( content[0] != 'i' )
  16.         return false ;

  17.     size_t pos = content.find('e' , 0) ;
  18.     
  19.     if ( pos == string::npos )
  20.         return false ;

  21.     string s_value = content.substr(1, pos-1) ;
  22.     
  23.     parserUtils::string_to_int(s_value , _value ) ;

  24.     content = content.erase ( 0 , pos+1 ) ;

  25.     return true ;
  26. }
  27.  

  28. bool StringType::parser( string & content )
  29. {
  30.     //cout <<"content " << content << endl ;

  31.     if ( content.empty () )
  32.         return false ;

  33.     if ( content.size () < 3 )
  34.         return false ;

  35.     size_t pos = content.find(':' , 0 ) ;
  36.         
  37.     if ( pos == string::npos )
  38.         return false ;

  39.     int count = 0 ;

  40.     parserUtils::string_to_int( content.substr( 0 ,pos) , count ) ;
  41.         
  42.     //printf ("count = %d pos = %d \n" , count , pos ) ;
  43.     
  44.     _value = content.substr( pos+1 , count ) ;

  45.     content = content.erase(0 , pos+1+count ) ;

  46.     //cout << _value << endl ;

  47. //    cout << "content 2 : " << content << endl ;

  48.     return true ;
  49. }

  50. bool ListType::parser ( string &content )
  51. {
  52.     if ( content.empty () )
  53.         return false ;

  54.     if ( content[0] != 'l' )
  55.         return false ;

  56.     content = content.erase(0,1) ; // delete 'l'

  57.     while ( !content.empty () )
  58.     {
  59.         AnyType * anyType = NULL ;
  60.             
  61.         if ( content[0] == 'l' )
  62.             anyType = new ListType () ;
  63.         else if ( content[0] == 'i' )
  64.             anyType = new IntegerType ();
  65.         else if ( content[0] == 'd' )
  66.             anyType = new DictType () ;
  67.         else
  68.             anyType = new StringType () ;

  69.         anyType->parser( content ) ;
  70.         // call this method will parse the content into
  71.         // the right value and store it into the _value of
  72.         // anyType

  73.         _list_values.push_back(anyType) ;

  74.         if ( content[0] == 'e' )
  75.         {
  76.             // arrived the end of the list

  77.             content = content.erase (0,1) ;
  78.             break ;
  79.         }
  80.     } // while

  81.     return true ;
  82. }

  83. bool DictType::parser ( string &content )
  84. {
  85.     
  86.     if ( content[0] != 'd' )
  87.         return false ;
  88.     if ( content.size () < 3 )
  89.         return false ;

  90.     content = content.erase ( 0 , 1 ) ; // delete 'd'

  91.     while ( !content.empty () )
  92.     {
  93.         StringType *key = new StringType () ;
  94.         key->parser (content) ;
  95.         // extract the key : string from dict <key>:<value>
  96.         
  97.         if ( content.empty () )
  98.             break ;

  99.         AnyType *anyType = NULL ; // value is type of list
  100.         // we not sure what and how many type list will store

  101.         if ( content[0] =='i' ) // type of integer
  102.             anyType = new IntegerType () ;
  103.         else if ( content[0] == 'l' ) // type of list
  104.             anyType = new ListType () ;
  105.         else if ( content[0] == 'd' ) // type of dict
  106.             anyType = new DictType () ;

  107.         else // type of string , begin with an integer
  108.             anyType = new StringType () ;
  109.         
  110.         if ( anyType == NULL ) // contents is empty now
  111.             return false ;

  112.         anyType->parser(content) ;

  113.         _map_values[key] = anyType ;

  114.         if ( content[0] == 'e' )
  115.         {
  116.             // end of the dict : <d>....<e>
  117.             content = content.erase(0 , 1) ;
  118.             break ;
  119.         }
  120.     }
  121.     return true ;
  122. }
下面的代码是 parser_utils.h 
在该头文件中定义了一个包含着全局所需要的公共方法的类,并且在类中以静态方法的方式给出了所有所需公共方法的实现

点击(此处)折叠或打开

  1. //parser_utils.h

  2. #ifndef PARSER_UTILS_H
  3. #define PARSER_UTILS_H
  4. #include <string>

  5. class parserUtils
  6. {
  7. public :
  8.     static void string_to_int( std::string value ,int & integer )
  9.     {
  10.         int result = 0 ;
  11.         int temp = 0 ;

  12.         for ( int i = 0 ; i < value.size() ; i++ )
  13.         {
  14.             temp = value[i]-'0' ; // get the number
  15.             result = result *10 ;
  16.             result += temp ;
  17.     
  18.             //printf ("result %d i = %d temp %d , pow(10 , %d ) = %d \n\n" , result , i , temp , i ,(int)(pow(10 , i ))) ;
  19.         }

  20.         integer = result ;
  21.     }

  22. } ;

  23. #endif // parser_utils.h
下面的代码是调用所有方法的主函数所在的文件

点击(此处)折叠或打开

  1. #include <cstdio>
  2. #include <string>
  3. #include <cstdlib>
  4. #include <iostream>

  5. #include "parser_utils.h"
  6. #include "torrentParser.h"


  7. using namespace std ;

  8. int main ( void )
  9. {
  10.     int result ;
  11.     string content ;
  12.     IntegerType integerType ;
  13.     StringType stringType ;
  14.     ListType listType ;
  15.     DictType dictType ;


  16.     cin >>content ;
  17.     
  18.      //integerType.parser(content) ;
  19.     //stringType.parser (content) ;
  20.    // listType.parser(content) ;
  21.     dictType.parser(content) ;
  22.     
  23.     //cout<< stringType._value <<endl ;
  24.     
  25.     dictType.showValue() ;

  26.     system("pause") ;
  27.     return 0 ;
  28. }
运行程序输入一个 dict 字典类型的 B编码信息:
d12:inuyasha1027li32167e22:this_is_a_test_of_dicteee
运行程序输出结果为:

在这里请注意,在解析 .torrent 文件的时候是直接从.torrent 文件中进行读取信息的。

而这里是使用 cin 和手动输入数据,所以在你输入的数据中空格会被计算机默认为结束输入的标志。
我曾经输入 this is a test of dict ,结果被计算机认为是空格的时候输入结束导致很多信息没有被读入。

end
阅读(1378) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~