The second step is to analyze the Torrent file. With the Bencoding encoding parser parsing the Torrent file is of course a task that is easy. The implementation package CTORRENTPARSER, the main task of completing: 1. Judging whether the Torrent file is effective 2. Get the following important Information: Tracker Server List File List Partition Size Partition Sub-block SHA1 Architecture 3. Others Some of the secondary information such as publisher, release date, comment, etc. 4. Calculate Infohash MetaInfo Files Are Bencoded Dictionaries with the Following Keys:
Announce The Url of the Tracker.
Info this Maps to a Dictionary, with keys described Below.
The name key maps to a string which is the sugester name to save the file (or directory) as. It is purely advisory.
piece length maps to the number of bytes in each piece the file is split into. For the purposes of transfer, files are split into fixed-size pieces which are all the same length except for possibly the last one which may be truncated. Piece length IS Almost Always a Power of TWO, MOST Commonly 218 = 256 k (Bittorrent Prior To Version 3.2 Uses 220 = 1 m as default).
.................. ..
TheRe IS Also A Key Length OR a Key Files, But Not Both or Neither. If Length Is Present The Download Represents A Single File, OtherWise IT Repesents a Set of Files Which Go In A Directory Structure.
In The Single File Case, Length Maps to The Length of The File in bytes.
For the purposes of the other keys, the multi-file case is treated as only having a single file by concatenating the files in the order they appear in the files list. The files list is the value files maps to, and is a list of Dictionaries Containing The Following Keys:
length The length of the file, in bytes. path A list of strings corresponding to subdirectory names, the last of which is the actual file name (a zero length list is an error case). In the single file case, the name key is The name of a file, in The Muliple File, It's The name of a directory. The following is the VC source code for the Torrent file parser: // TorrentParser.h: interface for the ctorrentparser Class.
//
//
#if! defined (AFX_TORRENTPARSER_H__7E67DA03_B65C_427F_A241_24230BCD6D54__INCluded_)
#define AFX_TORRENTPARSER_H__7E67DA03_B65C_427F_A241_24230BCD6D54__included_
#iF _MSC_VER> 1000
#pragma overce
#ENDIF / / 100 m _ _
// Torrent file parser
#include "bencode.h"
#include "cyfile.h"
#include "cyhash.h"
Class CTORRENTPARSER
{
PUBLIC:
Class CfileInfo
{
PUBLIC:
String strfilename; // file relative path
Double dbfilelen; // file length
}
Class cpiecesha1
{
PUBLIC:
String getString ();
Bool isempty ();
Byte Btdata [20];
}
CtorrentParser ();
Virtual ~ ctorrentParser ();
Void clear ();
Bool Parse (const char * szfilename);
Bool isvalid ();
CbencodeObjectBase * getValue (const char * szname);
PUBLIC:
Bool getInfo ();
List
List
String m_strname; // Recommended default file name or path name
INT m_ipiecelength; // Each block length
Cpiecesha1 M_Infohash; // Info Field SHA1
CPIECESHA1 * m_ppiecesha1; // block array pointer
INT m_ipiececount; // block number
INT M_ICREATIONDATE; / / Creation Date
String m_strcomment; // Note
String m_strpublisher; // Publisher
String m_strpublisherurl; // Publisher URL
String m_StrcreatedBy; // Creating a tool
Private:
String m_strfilename;
Ccyfile M_CYFILE;
Cbencode M_Bencode;
Cbencodedict * m_prootdict; // Analyze the root node
}
#ENDIF /! Defined (AFX_TORRENTPARSER_H__7E67DA03_B65C_427F_A241_24230BCD6D54__inCluded_)
// TorrentParser.cpp: Implementation of the ctorrentParser Class.//
//
#include "stdafx.h"
#include "torrentparser.h"
//
// construction / destruction
//
CTORRENTPARSER :: CTORRENTPARSER ()
{
m_prootdict = NULL;
}
CTorrentParser :: ~ ctorrentparser ()
{
Clear ();
}
Bool CTORRENTPARSER :: Parse (const char * szfilename)
{
Clear ();
IF (SZFileName)
m_strfilename = szfilename;
IF (! m_cyfile.isexist (m_strfilename.c_str ()))))
Return False;
IF (m_cyfile.openfile (m_strfilename.c_str ()) // Open file
{
BYTE * PDATA = m_cyfile.getdata (); // Read file data
m_cyfile.closefile ();
m_bencode.parse (const char *) PDATA);
// Get the root node
List
For (it = m_bencode.m_listobj.begin (); it! = m_bencode.m_listobj.end (); IT)
{
IF ((* it) -> m_type == enum_bencodetype_dict)
{
m_prootdict = (cbencodededict *) (* it);
Break;
}
}
Cbencodestring * petValue ("announce"); "Announce").
Cbencodedict * pebinfo = (cbeencodededict *) getValue ("info");
IF (peobannounce && pebinfo)
True;
}
Return False;
}
Void CTorrentParser :: clear ()
{
m_bencode.clear ();
m_prootdict = NULL;
m_cyfile.releasedata ();
}
/ / Check if a valid Torrent file
Bool CTorrentParser :: Isvalid ()
{
/ / Check if there is an Announce and Info field
CbencodeObjectBase * peobannounce = getValue ("Announce");
CbencodeObjectBase * peobinfo = getValue ("info");
IF (peobannounce && pebinfo)
Return True;
Return False;
}
CbencodeObjectBase * CtorrentParser :: getValue (const char * szname)
{
IF (m_prootdict)
Return m_prootdict-> getValue (szname);
Return NULL;
}
// Start getting information
Bool CTorrentParser :: getInfo ()
{
String Strvalue;
Cbencodestring * petValue ("Announce"); cbencodedict * pebinfo = (cbencodededict *) getValue ("info");
IF (peobannounce && pebinfo)
{
// Get the default TRACKER server
IF (Peobannounce-> getString (Strvalue))
M_Listannounce.push_back (strval);
// Get a list of spare Tracker
Cbencodelist * peobannouncelist = (cbeencodelist *) getValue ("Announce-list");
IF (PeobannounceList && PeobannounceList-> m_type == enum_bencodtype_list)
{
List
For (it = peobannouncelist-> m_listobj.begin (); it! = peobannouncelist-> m_listobj.end (); IT)
{
IF ((* it) -> m_type == enum_bencodetype_list)
{
Cbencodelist * peobannouncelist2 = (cbencodelist *) (* it);
IF (peobannouncelist2-> m_listobj.begin ()! = peobannouncelist2-> m_listobj.end ())
{
IF ((cbencodestring *) (* peobannouncelist2-> m_listobj.begin ())) -> getString (Strigue))
M_Listannounce.push_back (strval);
}
}
}
}
Cbencodestring * peobtmp;
Cbencodeint * peobint
// Get the date of creation
m_ICREATIONDATE = 0;
Peobint = (cbeencodeint *) getValue ("CREATION DATE");
IF (peobint && peobint-> m_type == enum_bencodetype_int)
M_ICREATIONDATE = (int) peobint-> m_fvalue;
// get comments
PeobTMP = (cbencodestring *) getValue ("comment");
IF (peobtmp)
PeobTMP-> getString (m_strcomment);
// Get a creation tool
PeobTMP = (cbencodestring *) getValue ("createDby");
IF (peobtmp)
Peobtmp-> getString (m_strcreatedby);
// Get the publisher
PeobTMP = (cbeencodestring *) getValue ("Publisher");
IF (peobtmp)
PeobTMP-> GetString (m_strpublisher);
PeobTMP = (cbencodestring *) getValue ("Publisher-URL");
IF (peobtmp)
PeobTMP-> getString (m_strpublisherurl); // calculate infohash
IF (peobinfo-> m_error == enm_bencodeerr_noerr)
{
Ccyhash CH;
Byte szsha1 [21];
IF (ch.gethash (cagg_sha1, (byte *) peobinfo-> szpos, peobinfo-> len, szsha1))
Memcpy (m_infohash.btdata, szsha1, 20);
Else
MEMSET (M_Infohash.btdata, 0, 20);
// Get the recommended default file name or path name
PeobTMP = (cbeencodestring *) peobinfo-> getValue ("name");
IF (peobtmp)
PeobTMP-> getString (m_strname);
// If you don't get a publisher, try again
IF (m_strpublisher.empty ())
{
PeobTMP = (cbeencodestring *) peobinfo-> getValue ("Publisher");
IF (peobtmp)
PeobTMP-> GetString (m_strpublisher);
PeobTMP = (cbeencodestring *) peobinfo-> getValue ("Publisher-URL");
IF (peobtmp)
PeobTMP-> getString (m_strpublisherurl);
}
// Get a block length
m_ipiecelength = 0;
Peobint = (cbeencodeint *) peobinfo-> getValue ("Piece Length");
IF (peobint && peobint-> m_type == enum_bencodetype_int)
m_ipiecelength = (int) peobint-> m_fvalue;
// Get the SHA1 array of PIECE and its Piece
PeobTMP = (cbeencodestring *) peobinfo-> getValue ("PIECES");
IF (peobtmp-> m_type_string && peobtmp-> m_error == enm_bencodeerr_noerr && peobtmp-> m_szdata)
{
m_ppiecesha1 = (cpiecesha1 *) peobtmp-> m_szdata;
m_ipiececount = peobtmp-> m_ilen / 20;
}
// Get a list of files
CfileInfo Fi;
Peobint = (cbencodeint *) Peobinfo-> getValue ("Length");
IF (peobint && peobint-> m_type == enum_bencodetype_int)
{
Fi.dbfilelen = (double) peobint-> m_fvalue;
FI.STRFILENAME = m_strname;
IF (fi.strfilename.size ()> 0 && fi.dbfilelen> 0)
m_listfile.push_back (fi);
}
Else
{
Cbencodelist * peoblist = (cbeencodelist *) peobinfo-> getValue ("files"); if (peoblist && peoblist-> m_type == enum_bencodetype_list)
{
List
For (it = peoblist -> m_listobj.begin (); it! = peoblist -> m_listobj.end (); IT)
{
IF ((* it) -> m_type == enum_bencodetype_dict)
{
Fi.dbfilelen = 0;
FI.STRFILENAME = ""
Peobint = (cbeencodeint *) (* it)) -> GetValue ("Length");
IF (peobint && peobint-> m_type == enum_bencodetype_int)
Fi.dbfilelen = (double) peobint-> m_fvalue;
Cbencodelist * peobpathlist = (cbeencodelist *) ((cbeencodededict *) (* it)) -> getValue ("PATH");
IF (peobpathlist && peobpathlist-> m_type == enum_bencodetype_list)
{
List
For (it2 = peobpathlist-> m_listobj.begin (); it2! = peobpathlist-> m_listobj.end (); IT2)
{
IF ((cbencodestring *) -> getString (Strigue))
FI.STRFILENAME = "//" Strvalue;
Else
{
FI.STRFILENAME = ""
Break;
}
}
}
IF (fi.strfilename.size ()> 0 && fi.dbfilelen> 0)
m_listfile.push_back (fi);
}
}
}
}
/ / Check if the main information is properly obtained, if you return success
IF (m_listannounce.size () == 0 ||
m_listfile.size () == 0 ||
m_infohash.isempty () ||
m_ipiececount == 0 ||
m_ipiecelength == 0 ||
m_ppiecesha1 == NULL)
Return False;
Return True;
}
}
Return False;
}
// Check if cpiecesha1 is empty
Bool CTorrentParser :: Cpiecesha1 :: ISEMPTY ()
{
Cpiecesha1 PSTMP;
Memset (pstmp.btdata, 0, sizeof (pstmp));
IF (Memcmp (Pstmp.Btdata, BTData, Sizeof (PSTMP)) == 0)
Return True;
Return False;
}
String CTORRENTPARSER :: Cpiecesha1 :: getString () {
Char SZ [100];
Char * sztmp = sz;
Byte bt;
For (int i = 0; i { Bt = btdata [i]; IF ((bt> = 'a' && bt <= 'z') || (bt> = 'a' && bt <= 'z') || (bt> = '0' && bt <= '9')))) { Sprintf (SZTMP, "% C", BT); SZTMP = 1; } Else { Sprintf (SZTMP, "%%% 02x", BT); SZTMP = 3; } } * sztmp = 0; Return SZ; } A small tool that parses Torrent files can see the test effect.