Torrent file parser

xiaoxiao2021-03-06  39

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 m_listannounce; // Tracker server list

List m_listfile; // file 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 :: item.

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 :: item.

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 :: item.

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 :: item2;

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.

转载请注明原文地址:https://www.9cbs.com/read-70825.html

New Post(0)