The BT client starts a download first to process is the Torrent file. The Torrent file uses Bencoding encoding. So the Bencoding encoded parser is the first step. Bencoding is Done as Follows: strings are length-prefixed base ten Followed by A colon and the string. for example / '4: spam /' corresponds to / 'spam /'. Integers are represented by an / 'i /' backed by the number in base 10 Followed by AN / 'E /'. for Example / 'I3E /' Corresponds to 3 and / 'i-3e /' Corresponds To -3. Integers Have No Size Limitation. All Encodings with a Leading Zero, Such AS / 'I03E / ', Are Invalid, Other Than /' i0e / ' / 'L4: Spam4: Eggse /' Corresponds To [/ 'spam /', / 'eggs /']. Dictionaries Are Encoded A / 'D /' Followed by A List of Alternating Keys and Their Corresponding Values Followed by AN / 'E /'. for Example, / 'D3: COW3: MOO4: SPAM4: Eggse /' Corresponds to {/ 'COW /': / 'MOO /', / 'SPAM /': / 'Eggs /'} and / ' 'D4: Spaml1: a1: Bee /' Corresponds to {/ 'SP AM / ': [/' A / ', /' B / ']}. Keys Must Be strings and APPEAR in Sorted Order (sorted as raw strings, not alphaplerics). The following is the VC source code for the Bencoding decoder implemented:
// Bencode.h: Interface for the cbencode class.
//
//
#if! defined (AFX_BENCODE_H___4D0BB462_2AE0_45B3_8BE8_19D51B2DBB2E__INCLUDED_)
#define AFX_BENCODE_H__4D0BB462_2AE0_45B3_8BE8_19D51B2DBB2E__INCLUDED_
#iF _MSC_VER> 1000
#pragma overce
#ENDIF / / 100 m _ _
#pragma Warning (Disable: 4786)
#pragma Warning (Disable: 4355)
#include
#include
#include
Using namespace std;
ENUM BENCODEPARSERRRORCODE
{
ENM_BENCODEERR_NOERR = 0, // No error
ENM_BENCODEERR_ERRSTRING, / / Error string
ENM_BENCODEERR_ERRINT, / / Error integer data
ENM_BENCODEERR_ERRLIST, / / Error list
ENM_BENCODEERR_ERRDICT, / / Error Dictionary
ENM_BENCODEERR_END, // The text ends
ENM_BENCODEERR_UNKNOWN / / unknown error
}
ENUM BENCODEOBJECTTYPE
{
ENUM_BENCODETYPE_ObjectBase = 0,
ENUM_BENCODETYPE_STRING,
Enum_bencodetype_int,
ENUM_BENCODETYPE_LIST,
ENUM_BENCODETYPE_DICT,
}
Class CbencodeObjectBase
{
PUBLIC:
CbencodeObjectBase (BencodeObjectType Type = Enum_Bencodtype_ObjectBase) {m_type = type; clear ();
Virtual ~ cbencodeObjectBase () {};
Void clear () {szpos = null; m_ERROR = enm_bencodeerr_noerr;}
PUBLIC:
BencodeObjectType M_Type; // Object Type
CHAR * SZPOS; // Location in the string
INT Ilen; // Data length of the object
BencodeparsererrorCode M_ERROR; / / Error value
}
Class Cbencodeint: Public CbencodeObjectBase
{
PUBLIC:
Cbencodeint (): cbencodeObjectBase (enum_bencodetype_int) {}
Virtual ~ cbencodeint () {}
PUBLIC:
INT M_IVALUE; / / Total object value
}
Class Cbencodestring: Public CbencodeObjectBase
{
PUBLIC:
Cbencodestring (): cbencodeObjectBase (enum_bencodetype_string) {m_szdata = null;}
Virtual ~ cbencodestring () {}
PUBLIC:
Bool getString (String & Strvalue)
{
IF (m_error == enm_bencodeerr_noerr && m_szdata)
{
Strvalue.Assign (m_szdata, m_ilen);
Return True;
}
Return False;
}
Char * m_szdata;
Int m_ilen;
}
Class Cbencodelist: Public CbencodeObjectBase
{
PUBLIC:
Cbencodelist (): cbencodeObjectBase (enum_bencodettype_list) {}
Virtual ~ cbencodelist () {clear ();
void clear ()
{
List
For (it = m_listobj.begin (); it! = m_listobj.end (); IT) delete (* it);
m_listobj.clear ();
}
PUBLIC:
List
}
Class CbencodeDict: Public CbencodeObjectBase
{
PUBLIC:
Cbencodedict (): cbencodeObjectBase (enum_bencodetype_dict) {}
Virtual ~ cbencodededict () {clear ();
CbencodeObjectBase * getValue (const char * szname)
{
Map
IF (it! = m_mapobj.end ())
Return it-> second;
Return NULL;
}
void clear ()
{
List
For (it = m_listobj.begin (); it! = m_listobj.end (); IT)
Delete (* it);
m_listobj.clear ();
m_mapobj.clear ();
}
PUBLIC:
Map
List
}
Class cbencode
{
PUBLIC:
Bool Readint (Char * Szcurpos, Int & IendPos, List
Bool ReadString (Char * Szcurpos, Int & Iendpos, List
Bool Readlist (Char * Szcurpos, Int & IendPos, List
Bool ReadDict (Char * Szcurpos, Int & IendPos, List
BOOL PARSE (Const Char * Szdata);
CBENCODE ();
Virtual ~ cbencode ();
void clear ()
{
List
For (it = m_listobj.begin (); it! = m_listobj.end (); IT)
Delete (* it);
m_listobj.clear ();
}
PUBLIC:
List
CbencodeObjectBase * m_plastobj; // The last object of the resolution
Char * m_sztxt;
}
#ndif //! defined (AFX_BENCODE_H__4D0BB462_2AE0_45B3_8BE8_19D51B2DBB2E__INCLUDED_)
// Bencode.cpp: Implementation of the cbencode class.//
//
#include "stdafx.h"
#include "bencode.h"
//
// construction / destruction
//
Cbencode :: cbencode ()
{
m_plastobj = NULL;
m_sztxt = NULL;
}
Cbencode :: ~ cbencode ()
{
Clear ();
}
Bool Cbencode :: Parse (Const Char * Szdata)
{
IF (szdata == null || * szdata == NULL)
Return False;
Clear ();
m_sztxt = (char *) szdata;
Char * szcurpos = (char *) SZDATA;
INT IENDPOS;
While (* szcurpos)
{
IF (* szcurpos == 'i')
{
IF (! Readint (szcurpos, iendpos, m_listobj))
Break; // encountered any error to terminate the entire resolution
Szcurpos = IENDPOS;
}
ELSE IF (* szcurpos == 'L')
{
IF (! Readlist (Szcurpos, IENDPOS, M_LISTOBJ))
Break;
Szcurpos = IENDPOS;
}
ELSE IF (* szcurpos == 'd')
{
IF (! readdict (szcurpos, iendpos, m_listobj))
Break;
Szcurpos = IENDPOS;
}
Else
{
IF (! ReadString (Szcurpos, IENDPOS, M_LISTOBJ))
Break;
Szcurpos = IENDPOS;
}
}
IF (* szcurpos == 0 && m_plastobj-> m_error == enm_bencodeerr_noerr)
Return True;
Return False;
}
// Read a string from the current location
Bool Cbencode :: ReadString (Char * Szcurpos, Int & Iendpos, List
{
Char * sztmp = szcurpos;
Cbencodestring * pnewstring = new cbencodestring;
Pnewstring-> szpos = szcurpos;
Char Szlen [20];
INT i = 0;
While (* sztmp> = '0' && * sztmp <= '9')
Szlen [i ] = * (SZTMP );
Szlen [I] = 0;
IF (* sztmp == ':')
{
Ilen = ATOI (Szlen);
IF (Ilen> 0)
{
Pnewstring-> m_szdata = sztmp;
Pnewstring-> m_ilen = Ilen;
SZTMP = Ilen;
}
Else
Pnewstring-> m_ERROR = ENM_BENCODEERR_ERRSTRING;
Else
Pnewstring-> m_ERROR = ENM_BENCODEERR_ERRSTRING;
Listobj.push_back (pnewstring);
IENDPOS = SZTMP-SZCURPOS;
m_plastobj = pnewstring;
M_Plastobj-> Ilen = IendPos;
Return pnewstring-> m_error == enm_bencodeerr_noerr? True: false;
}
// Read a integer data
Bool Cbencode :: Readint (Char * Szcurpos, Int & Iendpos, List
{
Char * sztmp = szcurpos;
Cbencodeint * pnewint = new cbencode;
Pnewint-> szpos = szcurpos;
IF (* sztmp == 'i')
{
SZTMP ;
Char Szlen [20];
INT i = 0;
While (* sztmp> = '0' && * sztmp <= '9')
Szlen [i ] = * (SZTMP );
Szlen [I] = 0;
IF (* sztmp == 'e')
{
PNEWINT-> M_IVALUE = ATOI (SZLEN);
SZTMP;
}
Else
PNEWINT-> M_ERROR = ENM_BENCODEERR_ERRINT;
}
Else
PNEWINT-> M_ERROR = ENM_BENCODEERR_ERRINT;
Listobj.push_back (pnewint);
IENDPOS = SZTMP-SZCURPOS;
m_plastobj = pnewint;
M_Plastobj-> Ilen = IendPos;
Return Pnewint-> m_ERROR == ENM_BENCODEERR_NOERR? TRUE: FALSE;
} // Read a list
Bool Cbencode :: Readlist (Char * Szcurpos, Int & Iendpos, List
{
Char * sztmp = szcurpos;
Cbencodelist * pnewlist = new cbencodelist;
PNewlist-> szpos = szcurpos;
IF (* sztmp == 'L')
{
SZTMP ;
Int ilistendpos;
While (* sztmp! = 'e')
{
IF (* sztmp == 'i')
{
IF (! readint (sztmp, ilistendpos, pnewlist-> m_listobj))
Break; // encountered any error to terminate the entire resolution
Sztmp = ilistendpos;
}
ELSE IF (* sztmp == 'L')
{
IF (! Readlist (sztmp, ilistendpos, pnewlist-> m_listobj)) Break;
Sztmp = ilistendpos;
}
ELSE IF (* sztmp == 'd')
{
IF (! readdict (sztmp, ilistendpos, pnewlist-> m_listobj))
Break;
Sztmp = ilistendpos;
}
Else
{
IF (! readstring (sztmp, ilistendpos, pnewlist-> m_listobj))
Break;
Sztmp = ilistendpos;
}
}
IF (* sztmp! = 'e' || m_plastobj-> m_error! = ENM_BENCODEERR_NOERR)
Pnewlist-> m_error = enm_bencodeerr_errlist;
Else
SZTMP ;
}
Else
Pnewlist-> m_error = enm_bencodeerr_errlist;
Listobj.push_back (pnewlist);
IENDPOS = SZTMP-SZCURPOS;
m_plastobj = pnewlist;
M_Plastobj-> Ilen = IendPos;
Return PNewlist-> m_error == ENM_BENCODEERR_NOERR? TRUE: FALSE;
}
// Read a dictionary
Bool Cbencode :: ReadDict (Char * Szcurpos, Int & Iendpos, List
{
Char * sztmp = szcurpos;
Cbencodedict * pnewdict = new cbencoded
PNewdict-> szpos = szcurpos;
IF (* sztmp == 'd')
{
SZTMP ;
Int ilistendpos;
String strname;
While (* sztmp! = 'e')
{
IF (! readstring (sztmp, ilistendpos, pnewdict-> m_listobj))
Break;
IF (m_plastobj-> m_type! = enum_bencodorepe_string)
Break;
Strname.assign ((cbencodestring *) m_plastobj) -> m_szdata, ((cbencodestring *) m_plastobj) -> m_ilen);
Sztmp = ilistendpos;
IF (* sztmp == 'i')
{
IF (! readint (sztmp, ilistendpos, pnewdict-> m_listobj))
Break; // encountered any error to terminate the entire resolution
Sztmp = ilistendpos;
}
ELSE IF (* sztmp == 'L')
{
IF (! readlist (sztmp, ilistendpos, pnewdict-> m_listobj))
Break;
Sztmp = ilistendpos;
}
ELSE IF (* sztmp == 'd')
{
IF (! ReadDict (SzTMP, ILISTENDPOS, PNEWDICT-> M_LISTOBJ) Break;
Sztmp = ilistendpos;
}
Else
{
IF (! readstring (sztmp, ilistendpos, pnewdict-> m_listobj))
Break;
Sztmp = ilistendpos;
}
PNewDict-> m_mapobj.insert (Pair
}
IF (* sztmp! = 'e' || m_plastobj-> m_error! = ENM_BENCODEERR_NOERR)
PNEWDICT-> M_ERROR = ENM_BENCODEERR_ERRDICT;
Else
SZTMP ;
}
Else
PNEWDICT-> M_ERROR = ENM_BENCODEERR_ERRDICT;
Listobj.push_back (pnewdict);
IENDPOS = SZTMP-SZCURPOS;
m_plastobj = pnewdict;
M_Plastobj-> Ilen = IendPos;
Return PNewdict-> m_error == ENM_BENCODEERR_NOERR? TRUE: FALSE;
}