Updated init script.
[dtbartle/bnbt.git] / bencode.cpp
1 /***\r
2 *\r
3 * BNBT Beta 8.0 - A C++ BitTorrent Tracker\r
4 * Copyright (C) 2003-2004 Trevor Hogan\r
5 *\r
6 * CBTT variations (C) 2003-2005 Harold Feit\r
7 *\r
8 * This library is free software; you can redistribute it and/or\r
9 * modify it under the terms of the GNU Lesser General Public\r
10 * License as published by the Free Software Foundation; either\r
11 * version 2.1 of the License, or (at your option) any later version.\r
12 *\r
13 * This library is distributed in the hope that it will be useful,\r
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\r
16 * Lesser General Public License for more details.\r
17 *\r
18 * You should have received a copy of the GNU Lesser General Public\r
19 * License along with this library; if not, write to the Free Software\r
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\r
21 *\r
22 ***/\r
23 \r
24 #include "bnbt.h"\r
25 #include "atom.h"\r
26 #include "bencode.h"\r
27 #include "util.h"\r
28 \r
29 string EncodeInt( const CAtomInt &x )\r
30 {\r
31         char pBuf[128];\r
32 \r
33         memset( pBuf, 0, sizeof( char ) * 128 );\r
34 \r
35         sprintf( pBuf, "%d", x.getValue( ) );\r
36 \r
37         string strDest;\r
38 \r
39         strDest += "i";\r
40         strDest += pBuf;\r
41         strDest += "e";\r
42 \r
43         return strDest;\r
44 }\r
45 \r
46 string EncodeLong( const CAtomLong &x )\r
47 {\r
48         char pBuf[128];\r
49 \r
50         memset( pBuf, 0, sizeof( char ) * 128 );\r
51 \r
52 #if defined( WIN32 )\r
53         sprintf( pBuf, "%I64d", x.getValue( ) );\r
54 #elif defined( __FREEBSD__ )\r
55         sprintf( pBuf, "%qd", x.getValue( ) );\r
56 #else\r
57         sprintf( pBuf, "%lld", x.getValue( ) );\r
58 #endif\r
59 \r
60         string strDest;\r
61 \r
62         strDest += "i";\r
63         strDest += pBuf;\r
64         strDest += "e";\r
65 \r
66         return strDest;\r
67 }\r
68 \r
69 string EncodeString( const CAtomString &x )\r
70 {\r
71         char pBuf[128];\r
72 \r
73         memset( pBuf, 0, sizeof( char ) * 128 );\r
74 \r
75         sprintf( pBuf, "%u", (unsigned int)x.getValue( ).size( ) );\r
76 \r
77         string strDest;\r
78 \r
79         strDest += pBuf;\r
80         strDest += ":";\r
81         strDest += x.getValue( );\r
82 \r
83         return strDest;\r
84 }\r
85 \r
86 string EncodeList( const CAtomList &x )\r
87 {\r
88         vector<CAtom *> *pv = x.getValuePtr( );\r
89 \r
90         string strDest;\r
91 \r
92         strDest += "l";\r
93 \r
94         for( vector<CAtom *> :: iterator i = pv->begin( ); i != pv->end( ); i++ )\r
95         {\r
96                 if( dynamic_cast<CAtomInt *>( *i ) )\r
97                         strDest += EncodeInt( *dynamic_cast<CAtomInt *>( *i ) );\r
98                 else if( dynamic_cast<CAtomLong *>( *i ) )\r
99                         strDest += EncodeLong( *dynamic_cast<CAtomLong *>( *i ) );\r
100                 else if( dynamic_cast<CAtomString *>( *i ) )\r
101                         strDest += EncodeString( *dynamic_cast<CAtomString *>( *i ) );\r
102                 else if( dynamic_cast<CAtomList *>( *i ) )\r
103                         strDest += EncodeList( *dynamic_cast<CAtomList *>( *i ) );\r
104                 else if( dynamic_cast<CAtomDicti *>( *i ) )\r
105                         strDest += EncodeDicti( *dynamic_cast<CAtomDicti *>( *i ) );\r
106         }\r
107 \r
108         strDest += "e";\r
109 \r
110         return strDest;\r
111 }\r
112 \r
113 string EncodeDicti( const CAtomDicti &x )\r
114 {\r
115         map<string, CAtom *> *pmapDicti = x.getValuePtr( );\r
116 \r
117         string strDest;\r
118 \r
119         strDest += "d";\r
120 \r
121         for( map<string, CAtom *> :: iterator i = pmapDicti->begin( ); i != pmapDicti->end( ); i++ )\r
122         {\r
123                 strDest += EncodeString( CAtomString( (*i).first ) );\r
124 \r
125                 if( dynamic_cast<CAtomInt *>( (*i).second ) )\r
126                         strDest += EncodeInt( *dynamic_cast<CAtomInt *>( (*i).second ) );\r
127                 else if( dynamic_cast<CAtomLong *>( (*i).second ) )\r
128                         strDest += EncodeLong( *dynamic_cast<CAtomLong *>( (*i).second ) );\r
129                 else if( dynamic_cast<CAtomString *>( (*i).second ) )\r
130                         strDest += EncodeString( *dynamic_cast<CAtomString *>( (*i).second ) );\r
131                 else if( dynamic_cast<CAtomList *>( (*i).second ) )\r
132                         strDest += EncodeList( *dynamic_cast<CAtomList *>( (*i).second ) );\r
133                 else if( dynamic_cast<CAtomDicti *>( (*i).second ) )\r
134                         strDest += EncodeDicti( *dynamic_cast<CAtomDicti *>( (*i).second ) );\r
135         }\r
136 \r
137         strDest += "e";\r
138 \r
139         return strDest;\r
140 }\r
141 \r
142 string Encode( CAtom *pAtom )\r
143 {\r
144         if( dynamic_cast<CAtomInt *>( pAtom ) )\r
145                 return EncodeInt( *dynamic_cast<CAtomInt *>( pAtom ) );\r
146         else if( dynamic_cast<CAtomLong *>( pAtom ) )\r
147                 return EncodeLong( *dynamic_cast<CAtomLong *>( pAtom ) );\r
148         else if( dynamic_cast<CAtomString *>( pAtom ) )\r
149                 return EncodeString( *dynamic_cast<CAtomString *>( pAtom ) );\r
150         else if( dynamic_cast<CAtomList *>( pAtom ) )\r
151                 return EncodeList( *dynamic_cast<CAtomList *>( pAtom ) );\r
152         else if( dynamic_cast<CAtomDicti *>( pAtom ) )\r
153                 return EncodeDicti( *dynamic_cast<CAtomDicti *>( pAtom ) );\r
154 \r
155         return string( );\r
156 }\r
157 \r
158 /*\r
159 \r
160 CAtomInt *DecodeInt( const string &x, unsigned long iStart )\r
161 {\r
162         string :: size_type iEnd = x.find( "e" );\r
163 \r
164         if( iEnd == string :: npos )\r
165         {\r
166                 UTIL_LogPrint( "error decoding int - couldn't find \"e\", halting decode\n" );\r
167 \r
168                 return NULL;\r
169         }\r
170 \r
171         return new CAtomInt( atoi( x.substr( iStart + 1, iEnd - iStart - 1 ).c_str( ) ) );\r
172 }\r
173 \r
174 */\r
175 \r
176 CAtomLong *DecodeLong( const string &x, unsigned long iStart )\r
177 {\r
178         string :: size_type iEnd = x.find( "e", iStart );\r
179 \r
180         if( iEnd == string :: npos )\r
181         {\r
182                 UTIL_LogPrint( "error decoding long - couldn't find \"e\", halting decode\n" );\r
183 \r
184                 return NULL;\r
185         }\r
186 \r
187         int64 i;\r
188 \r
189 #if defined( WIN32 )\r
190         sscanf( x.substr( iStart + 1, iEnd - iStart - 1 ).c_str( ), "%I64d", &i );\r
191 #elif defined( __FREEBSD__ )\r
192         sscanf( x.substr( iStart + 1, iEnd - iStart - 1 ).c_str( ), "%qd", &i );\r
193 #else\r
194         sscanf( x.substr( iStart + 1, iEnd - iStart - 1 ).c_str( ), "%lld", &i );\r
195 #endif\r
196 \r
197         return new CAtomLong( i );\r
198 }\r
199 \r
200 CAtomString *DecodeString( const string &x, unsigned long iStart )\r
201 {\r
202         string :: size_type iSplit = x.find_first_not_of( "1234567890", iStart );\r
203 \r
204         if( iSplit == string :: npos )\r
205         {\r
206                 UTIL_LogPrint( "error decoding string - couldn't find \":\", halting decode\n" );\r
207 \r
208                 return NULL;\r
209         }\r
210 \r
211         return new CAtomString( x.substr( iSplit + 1, atoi( x.substr( iStart, iSplit - iStart ).c_str( ) ) ) );\r
212 }\r
213 \r
214 CAtomList *DecodeList( const string &x, unsigned long iStart )\r
215 {\r
216         unsigned long i = iStart + 1;\r
217 \r
218         CAtomList *pList = new CAtomList( );\r
219 \r
220         while( i < x.size( ) && x[i] != 'e' )\r
221         {\r
222                 CAtom *pAtom = Decode( x, i );\r
223 \r
224                 if( pAtom )\r
225                 {\r
226                         i += pAtom->EncodedLength( );\r
227 \r
228                         pList->addItem( pAtom );\r
229                 }\r
230                 else\r
231                 {\r
232                         UTIL_LogPrint( "error decoding list - error decoding list item, discarding list\n" );\r
233 \r
234                         delete pList;\r
235 \r
236                         return NULL;\r
237                 }\r
238         }\r
239 \r
240         return pList;\r
241 }\r
242 \r
243 CAtomDicti *DecodeDicti( const string &x, unsigned long iStart )\r
244 {\r
245         unsigned long i = iStart + 1;\r
246 \r
247         CAtomDicti *pDicti = new CAtomDicti( );\r
248 \r
249         while( i < x.size( ) && x[i] != 'e' )\r
250         {\r
251                 CAtom *pKey = Decode( x, i );\r
252 \r
253                 if( pKey && dynamic_cast<CAtomString *>( pKey ) )\r
254                 {\r
255                         i += pKey->EncodedLength( );\r
256 \r
257                         string strKey = pKey->toString( );\r
258 \r
259                         delete pKey;\r
260 \r
261                         if( i < x.size( ) )\r
262                         {\r
263                                 CAtom *pValue = Decode( x, i );\r
264 \r
265                                 if( pValue )\r
266                                 {\r
267                                         i += pValue->EncodedLength( );\r
268 \r
269                                         pDicti->setItem( strKey, pValue );\r
270                                 }\r
271                                 else\r
272                                 {\r
273                                         UTIL_LogPrint( "error decoding dictionary - error decoding value, discarding dictionary\n" );\r
274 \r
275                                         delete pDicti;\r
276 \r
277                                         return NULL;\r
278                                 }\r
279                         }\r
280                 }\r
281                 else\r
282                 {\r
283                         UTIL_LogPrint( "error decoding dictionary - error decoding key, discarding dictionary\n" );\r
284 \r
285                         delete pDicti;\r
286 \r
287                         return NULL;\r
288                 }\r
289         }\r
290 \r
291         return pDicti;\r
292 }\r
293 \r
294 CAtom *Decode( const string &x, unsigned long iStart )\r
295 {\r
296         if( iStart < x.size( ) )\r
297         {\r
298                 if( x[iStart] == 'i' )\r
299                         return DecodeLong( x, iStart );\r
300                 else if( isdigit( x[iStart] ) )\r
301                         return DecodeString( x, iStart );\r
302                 else if( x[iStart] == 'l' )\r
303                         return DecodeList( x, iStart );\r
304                 else if( x[iStart] == 'd' )\r
305                         return DecodeDicti( x, iStart );\r
306 \r
307                 string temp = x.substr( iStart );\r
308 \r
309                 UTIL_LogPrint( "error decoding - found unexpected character %u, halting decode\n", (unsigned char)x[iStart] );\r
310         }\r
311         else\r
312                 UTIL_LogPrint( "error decoding - out of range\n" );\r
313 \r
314         return NULL;\r
315 }\r
316 \r
317 CAtom *DecodeFile( const char *szFile )\r
318 {\r
319         FILE *pFile = NULL;\r
320 \r
321         if( ( pFile = fopen( szFile, "rb" ) ) == NULL )\r
322         {\r
323                 UTIL_LogPrint( "warning - unable to open %s for reading\n", szFile );\r
324 \r
325                 return NULL;\r
326         }\r
327 \r
328         fseek( pFile, 0, SEEK_END );\r
329         unsigned long ulFileSize = ftell( pFile );\r
330         fseek( pFile, 0, SEEK_SET );\r
331         char *pData = (char *)malloc( sizeof( char ) * ulFileSize );\r
332         memset( pData, 0, sizeof( char ) * ulFileSize );\r
333         fread( (void *)pData, sizeof( char ), ulFileSize, pFile );\r
334         fclose( pFile );\r
335         string strFile( pData, ulFileSize );\r
336         free( pData );\r
337 \r
338         return Decode( strFile );\r
339 }\r