Code: Select all
#ifndef __TORRENT_FILE_H
#define __TORRENT_FILE_H
#include <wx/wfstream.h>
#include <wxMap.h>
struct SHA_buf
{
SHA_buf( ) { memset(buf, 0 , 20); }
SHA_buf( BYTE const * const b ) { memcpy(buf, b , 20); }
SHA_buf( const SHA_buf& s ) { memcpy(buf, s.buf, 20); }
BYTE buf[20];
};
class TorrentPiece
{
public:
typedef enum eTorrentKind
{
torrent_none,
torrent_string,
torrent_integer,
torrent_dictionary,
torrent_list,
torrent_sha1,
} eTorrentKind;
TorrentPiece( eTorrentKind kind = torrent_none );
TorrentPiece( const TorrentPiece& p );
virtual ~TorrentPiece( ) { }
virtual bool bDecode( wxInputStream& input_stream ) = 0;
virtual void bEncode( wxOutputStream& output_stream ) const = 0;
virtual void display_nice( wxOutputStream& output ) const = 0;
bool IsKindOf( eTorrentKind kind ) const { return torrent_kind == kind; }
bool IsOk( ) const { return m_bOK; }
protected:
bool m_bOK;
private:
eTorrentKind torrent_kind;
};
WX_DECLARE_STRING_MAP (TorrentPiece*, string_string );
WX_DECLARE_BASEARRAY (TorrentPiece*, torrent_listing );
WX_DECLARE_BASEARRAY (SHA_buf , SHA_pieces );
class TorrentSHA1 : public TorrentPiece
{
public:
TorrentSHA1( );
TorrentSHA1( wxInputStream& input_stream );
TorrentSHA1( const TorrentSHA1& l );
virtual ~TorrentSHA1( ) { }
virtual bool bDecode( wxInputStream& input_stream );
virtual void bEncode( wxOutputStream& output_stream ) const;
virtual void display_nice( wxOutputStream& output ) const;
const SHA_pieces& GetValue( ) const { return value; }
private:
SHA_pieces value;
};
class TorrentInteger : public TorrentPiece
{
public:
TorrentInteger( );
TorrentInteger( wxInputStream& input_stream );
TorrentInteger( double l );
TorrentInteger( const TorrentInteger& l );
virtual ~TorrentInteger( ) { }
operator double( ) const { return GetValue(); }
virtual bool bDecode( wxInputStream& input_stream );
virtual void bEncode( wxOutputStream& output_stream ) const;
virtual void display_nice( wxOutputStream& output ) const;
double GetValue( ) const { return value; }
private:
double value;
};
class TorrentString : public TorrentPiece
{
public:
TorrentString( );
TorrentString( wxInputStream& input_stream );
TorrentString( const wxString& str );
TorrentString( const TorrentString& l );
virtual ~TorrentString( ) { }
operator wxString() const { return GetValue(); }
bool operator ==( const wxString& s ) const { return GetValue() == s; }
virtual bool bDecode( wxInputStream& input_stream );
virtual void bEncode( wxOutputStream& output_stream ) const;
virtual void display_nice( wxOutputStream& output ) const;
const wxString& GetValue( ) const { return value; }
double length() const { return GetValue().length(); }
private:
wxString value;
};
class TorrentDictionary : public TorrentPiece
{
public:
TorrentDictionary( );
TorrentDictionary( wxInputStream& input_stream );
TorrentDictionary( const TorrentDictionary& l );
virtual ~TorrentDictionary( );
virtual bool bDecode( wxInputStream& input_stream );
virtual void bEncode( wxOutputStream& output_stream ) const;
virtual void display_nice( wxOutputStream& output ) const;
const string_string& GetValue( ) const { return value; }
private:
string_string value;
};
class TorrentList : public TorrentPiece
{
public:
TorrentList( );
TorrentList( wxInputStream& input_stream );
TorrentList( const TorrentList& l );
virtual ~TorrentList( );
virtual bool bDecode( wxInputStream& input_stream );
virtual void bEncode( wxOutputStream& output_stream ) const;
virtual void display_nice( wxOutputStream& output ) const;
const torrent_listing& GetValue( ) const { return value; }
private:
torrent_listing value;
};
class TorrentFile
{
public:
TorrentFile( ) : piece(NULL) { }
TorrentFile( const wxString& file_name );
TorrentFile( wxInputStream& input_stream ) : piece(NULL) { bDecode(input_stream); }
~TorrentFile( ) { wxDELETE(piece); }
bool bDecode( wxInputStream& input_stream );
void bEncode( wxOutputStream& output_stream ) const;
void display_nice( wxOutputStream& output ) const { piece->display_nice(output); }
void display_nice( const wxString& filename ) const { wxFileOutputStream output(filename); piece->display_nice(output); }
wxString GetInfoHash( ) const;
wxString GetAnnounceURL( ) const;
wxString GetName( ) const;
wxString GetError( ) const;
double GetTotalLength( ) const;
double GetTotalFiles( ) const;
bool IsOk() const { return piece != NULL && piece->IsOk(); }
private:
TorrentPiece * findInTorrent( const wxString& key, TorrentPiece const * const mPiece = NULL ) const;
TorrentPiece * piece;
};
#endif // __TORRENT_FILE_H
Code: Select all
#include "stdwx.h"
#include "TorrentFile.h"
#include <encryption/wxSHA1.h>
#include <wx/variant.h>
#include <wx/mstream.h>
size_t inspring = 0;
wxOutputStream& operator <<(wxOutputStream& o_stream, const wxString& s)
{
o_stream.Write( s.mbc_str(), strlen(s.mbc_str()) );
return o_stream;
}
wxOutputStream& operator <<(wxOutputStream& o_stream, long s)
{
wxString c( wxVariant(s).GetString() );
o_stream.Write( c.mbc_str(), strlen(c.mbc_str()) );
return o_stream;
}
TorrentPiece * getNextPiece( wxInputStream& input_stream )
{
TorrentPiece * piece;
char c = input_stream.Peek();
switch( c )
{
case 'd': // dictionary
input_stream.GetC();
piece = new TorrentDictionary(input_stream);
break;
case 'i': // integer
input_stream.GetC();
piece = new TorrentInteger(input_stream);
break;
case 'l': // list
input_stream.GetC();
piece = new TorrentList(input_stream);
break;
default: // string
piece = new TorrentString(input_stream);
break;
}
if ( piece && !piece->IsOk() )
wxDELETE(piece);
return piece;
}
bool shouldStopToRead( wxInputStream& input_stream )
{
return ( input_stream.Eof() || input_stream.Peek() == 'e' );
}
//////////////////////////////////////////////////////////////////////////
// TorrentPiece
TorrentPiece::TorrentPiece( eTorrentKind kind )
: torrent_kind(kind),
m_bOK(false)
{
wxASSERT(torrent_kind != torrent_none);
}
TorrentPiece::TorrentPiece( const TorrentPiece& p )
: torrent_kind(p.torrent_kind),
m_bOK(p.m_bOK)
{
wxASSERT(torrent_kind != torrent_none);
}
//////////////////////////////////////////////////////////////////////////
// TorrentSHA1
TorrentSHA1::TorrentSHA1( )
: TorrentPiece(torrent_sha1)
{
}
TorrentSHA1::TorrentSHA1( wxInputStream& input_stream )
: TorrentPiece(torrent_sha1)
{
bDecode(input_stream);
}
TorrentSHA1::TorrentSHA1( const TorrentSHA1& l )
: TorrentPiece(l),
value(l.value)
{
}
bool TorrentSHA1::bDecode( wxInputStream& input_stream )
{ // get the amount of data in it...
wxString amount;
do
{
char c = input_stream.GetC();
if ( c == ':' )
break;
if ( !wxIsdigit(c) )
return false;
amount << wxString(&c, wxConvLibc, sizeof(char));
} while( !shouldStopToRead(input_stream) );
long am = wxVariant(amount).GetLong();
wxASSERT( am % 20 == 0 ); // check if there is the certain amount of data in this segment
BYTE buf[20];
for ( int i = 0; i < am; i += 20 )
{
input_stream.Read( buf, 20 );
value.push_back( buf );
}
m_bOK = true;
return true;
}
void TorrentSHA1::bEncode( wxOutputStream& output_stream ) const
{
if ( !IsOk() )
return;
output_stream << (value.size() * 20) << wxT(":");
for ( SHA_pieces::const_iterator ci = value.begin(); ci != value.end(); ci++ )
{
// directly write to outputstream.
output_stream.Write( (*ci).buf, 20 );
}
}
void TorrentSHA1::display_nice( wxOutputStream& output ) const
{
if ( !IsOk() )
return;
for ( SHA_pieces::const_iterator ci = value.begin(); ci != value.end(); ci++ )
{
BYTE const * const tmp = (*ci).buf;
output << wxT("* ");
for ( int i = 0; i < 20; i++ )
{
output << wxString::Format( wxT("%02X"), tmp[i] );
if ( (i+1) % 4 == 0 )
output << wxT(" ");
}
output << wxT(",\n") << wxString( wxT(' '), inspring );
}
}
//////////////////////////////////////////////////////////////////////////
// TorrentList
TorrentList::TorrentList( )
: TorrentPiece(torrent_list)
{
}
TorrentList::TorrentList( wxInputStream& input_stream )
: TorrentPiece(torrent_list)
{
bDecode(input_stream);
}
TorrentList::TorrentList( const TorrentList& l )
: TorrentPiece(l),
value(l.value)
{ }
TorrentList::~TorrentList( )
{
for ( torrent_listing::const_iterator ci = value.begin(); ci != value.end(); ci++ )
{
TorrentPiece * piece = *ci;
wxDELETE(piece);
}
value.clear();
}
bool TorrentList::bDecode( wxInputStream& input_stream )
{
while ( !shouldStopToRead(input_stream) )
{
TorrentPiece * piece = getNextPiece(input_stream);
if ( piece == NULL || !piece->IsOk() )
{
wxDELETE(piece);
return false;
}
value.push_back( piece );
}
// eat 1 'e'
input_stream.GetC();
m_bOK = true;
return true;
}
void TorrentList::bEncode( wxOutputStream& output_stream ) const
{
if ( !IsOk() )
return;
output_stream << wxT("l");
for ( torrent_listing::const_iterator ci = value.begin(); ci != value.end(); ci++ )
{
(*ci)->bEncode(output_stream);
}
output_stream << wxT("e");
}
void TorrentList::display_nice( wxOutputStream& output ) const
{
if ( !IsOk() )
return;
output << wxT("[\n");
inspring += 1;
for ( torrent_listing::const_iterator ci = value.begin(); ci != value.end(); ci++ )
{
TorrentPiece * piece = *ci;
output << wxString(wxT(' '), inspring);
piece->display_nice(output);
output << wxT(",\n");
}
inspring -= 1;
output << wxString(wxT(' '), inspring) << wxT("]");
}
//////////////////////////////////////////////////////////////////////////
// TorrentDictionary
TorrentDictionary::TorrentDictionary( )
: TorrentPiece(torrent_dictionary)
{
}
TorrentDictionary::TorrentDictionary( wxInputStream& input_stream )
: TorrentPiece(torrent_dictionary)
{
bDecode(input_stream);
}
TorrentDictionary::TorrentDictionary( const TorrentDictionary& l )
: TorrentPiece(l),
value(l.value)
{ }
TorrentDictionary::~TorrentDictionary( )
{
for ( string_string::iterator ci = value.begin(); ci != value.end(); ci++ )
{
TorrentPiece * piece = (*ci).second;
wxDELETE(piece);
}
value.clear();
}
bool TorrentDictionary::bDecode( wxInputStream& input_stream )
{
do
{
TorrentString key(input_stream);
if ( !key.IsOk() )
return false;
TorrentPiece * piece = NULL;
if ( key == wxT("pieces") )
{
// Now modify the piece[info][pieces]-string value to TorrentSHA1 values...
piece = new TorrentSHA1(input_stream);
}
else
{
piece = getNextPiece(input_stream);
}
if ( piece == NULL || !piece->IsOk() )
{
wxDELETE(piece);
return false;
}
value[key] = piece;
} while( !shouldStopToRead(input_stream) );
// eat 1 'e'
input_stream.GetC();
m_bOK = true;
return true;
}
void TorrentDictionary::bEncode( wxOutputStream& output_stream ) const
{
if ( !IsOk() )
return;
output_stream << wxT("d");
for ( string_string::const_iterator ci = value.begin(); ci != value.end(); ci++ )
{
TorrentString((*ci).first).bEncode(output_stream);
(*ci).second-> bEncode(output_stream);
}
output_stream << wxT("e");
}
void TorrentDictionary::display_nice( wxOutputStream& output ) const
{
if ( !IsOk() )
return;
// write the first of the string
output << wxT("{\n");
inspring += 1;
for ( string_string::const_iterator ci = value.begin(); ci != value.end(); ci++ )
{
// write the key-value.
const TorrentString val = TorrentString((*ci).first);
TorrentPiece const * const piece = (*ci).second;
output << wxString(wxT(' '), inspring);
val.display_nice(output);
inspring += (*ci).first.length() + 2 /* "x2 */ + 3;
output << wxT(" : ");
piece->display_nice(output);
inspring -= ((*ci).first.length() + 2 /* "x2 */ + 3);
output << wxT(",\n");
}
inspring -= 1;
output << wxString(wxT(' '), inspring) << wxT("}");
}
//////////////////////////////////////////////////////////////////////////
// TorrentInteger
TorrentInteger::TorrentInteger( )
: TorrentPiece(torrent_integer)
{
}
TorrentInteger::TorrentInteger( double l )
: TorrentPiece(torrent_integer),
value(l)
{
m_bOK = true;
}
TorrentInteger::TorrentInteger( wxInputStream& input_stream )
: TorrentPiece(torrent_integer)
{
bDecode(input_stream);
}
TorrentInteger::TorrentInteger( const TorrentInteger& l )
: TorrentPiece(l),
value(l.value)
{ }
bool TorrentInteger::bDecode( wxInputStream& input_stream )
{
wxString integer;
while( !shouldStopToRead(input_stream) )
{
char c = input_stream.GetC();
if ( !wxIsdigit(c) )
return false;
integer << wxString(&c, wxConvLibc, sizeof(char));
}
// remove the 'e'
input_stream.GetC();
value = wxVariant(integer).GetLong();
m_bOK = true;
return true;
}
void TorrentInteger::bEncode( wxOutputStream& output_stream ) const
{
if ( !IsOk() )
return;
output_stream << wxT("i") << wxString::Format(wxT("%.f"),value) << wxT("e");
}
void TorrentInteger::display_nice( wxOutputStream& output ) const
{
if ( !IsOk() )
return;
output << wxString::Format( wxT("%.f"), value );
}
//////////////////////////////////////////////////////////////////////////
// TorrentString
TorrentString::TorrentString( )
: TorrentPiece(torrent_string)
{
}
TorrentString::TorrentString( wxInputStream& input_stream )
: TorrentPiece(torrent_string)
{
bDecode(input_stream);
}
TorrentString::TorrentString( const wxString& str )
: TorrentPiece(torrent_string),
value(str)
{
m_bOK = true;
}
TorrentString::TorrentString( const TorrentString& l )
: TorrentPiece(l),
value(l.value)
{ }
bool TorrentString::bDecode( wxInputStream& input_stream )
{
wxString amount;
do
{
char c = input_stream.GetC();
if ( c == ':' )
break;
else if( !wxIsdigit(c) )
return false;
amount << wxString(&c, wxConvLibc, sizeof(char));
} while( !input_stream.Eof() );
// lees nu 'amount' bytes in.
double am = wxVariant(amount).GetLong();
char * t = new char[ am ];
input_stream.Read( t, am );
value = wxString(t, wxConvLibc, am);
wxDELETEA(t);
m_bOK = true;
return true;
}
void TorrentString::bEncode( wxOutputStream& output_stream ) const
{
if ( !IsOk() )
return;
output_stream << strlen(value.mbc_str().data()) << wxT(":") << value;
}
void TorrentString::display_nice( wxOutputStream& output ) const
{
if ( !IsOk() )
return;
output << wxString::Format( wxT("\"%s\""), value.c_str() );
}
//////////////////////////////////////////////////////////////////////////
// TorrentFile
TorrentFile::TorrentFile( const wxString& file_name )
: piece(NULL)
{
if ( wxFileExists(file_name) )
{
wxFileInputStream input_stream(file_name);
bDecode(input_stream);
}
}
bool TorrentFile::bDecode( wxInputStream& input_stream )
{
return (piece = getNextPiece(input_stream)) != NULL;
}
void TorrentFile::bEncode( wxOutputStream& output_stream ) const
{
piece->bEncode(output_stream);
}
wxString TorrentFile::GetInfoHash( ) const
{
TorrentPiece * piece = findInTorrent( wxT("info") );
if ( piece == NULL )
return wxEmptyString;
wxMemoryOutputStream out_stream;
piece->bEncode( out_stream );
BYTE * len = new BYTE[out_stream.GetLength()];
out_stream.CopyTo(len, out_stream.GetLength());
wxSHA1 h;
wxString retVal;
if ( h.HashBuffer(len, out_stream.GetLength()) )
{
for ( int i = 0; i < 20; i++ )
{
retVal << wxString::Format( wxT("%%%02X"), h.GetHash()[i] );
}
}
wxDELETEA(len);
return retVal;
}
TorrentPiece * TorrentFile::findInTorrent( const wxString& key, TorrentPiece const * const mPiece /* = NULL */ ) const
{
TorrentPiece const * working_piece = mPiece == NULL ? piece : mPiece;
if ( working_piece == NULL || !working_piece->IsKindOf(TorrentPiece::torrent_dictionary) )
return NULL;
TorrentDictionary const * dict = reinterpret_cast<TorrentDictionary const *>(working_piece);
string_string::const_iterator ci = dict->GetValue().find(key);
return ci == dict->GetValue().end() ? NULL : (*ci).second;
}
double TorrentFile::GetTotalLength( ) const
{
TorrentPiece * dict = findInTorrent(wxT("info"));
if ( dict == NULL ) return 0;
TorrentList * lijst = reinterpret_cast<TorrentList*>(findInTorrent( wxT("files"), dict ));
if ( lijst == NULL )
{
TorrentInteger * integer = reinterpret_cast<TorrentInteger*>(findInTorrent( wxT("length"), dict ));
if ( integer == NULL )
return 0;
else
return integer->operator double();
}
double total_size(0);
for ( torrent_listing::const_iterator ci = lijst->GetValue().begin(); ci != lijst->GetValue().end(); ci++ )
{
TorrentInteger * filesize = reinterpret_cast<TorrentInteger*>(findInTorrent( wxT("length"), *ci ));
if ( filesize )
total_size += filesize->GetValue();
}
return total_size;
}
wxString TorrentFile::GetName( ) const
{
TorrentPiece * dict = findInTorrent(wxT("info"));
if ( dict == NULL ) return wxEmptyString;
TorrentPiece * piece = findInTorrent(wxT("name"), dict);
if ( piece == NULL )
return wxEmptyString;
else
return *(reinterpret_cast<TorrentString*>(piece));
}
wxString TorrentFile::GetAnnounceURL( ) const
{
TorrentPiece * piece = findInTorrent( wxT("announce") );
if ( piece == NULL )
return wxEmptyString;
else
return *(reinterpret_cast<TorrentString*>(piece));
}
double TorrentFile::GetTotalFiles( ) const
{
TorrentPiece * dict = findInTorrent(wxT("info"));
if ( dict == NULL ) return 0;
TorrentList * lijst = reinterpret_cast<TorrentList*>(findInTorrent(wxT("files"), dict));
if ( lijst == NULL )
return findInTorrent(wxT("length"), dict) == NULL ? 0 : 1;
return lijst->GetValue().size();
}
wxString TorrentFile::GetError( ) const
{
TorrentPiece * piece = findInTorrent( wxT("failure reason") );
if ( piece == NULL || !piece->IsOk() ) return wxEmptyString;
return *(reinterpret_cast<TorrentString*>(piece));
}
I think someone can put this to some good use I am sure :p.
Questions: [email protected]
Flames: /dev/null
Peace, out.