Upstream tarball 20080603
[amule.git] / src / Tag.cpp
blob0cedbf812735246ef1459ff300a94f7f665ab8dc
1 //
2 // This file is part of the aMule Project.
3 //
4 // Copyright (c) 2003-2008 aMule Team ( admin@amule.org / http://www.amule.org )
5 // Copyright (c) 2002 Merkur ( devs@emule-project.net / http://www.emule-project.net )
6 //
7 // Any parts of this program derived from the xMule, lMule or eMule project,
8 // or contributed by third-party developers are copyrighted by their
9 // respective authors.
11 // This program is free software; you can redistribute it and/or modify
12 // it under the terms of the GNU General Public License as published by
13 // the Free Software Foundation; either version 2 of the License, or
14 // (at your option) any later version.
16 // This program is distributed in the hope that it will be useful,
17 // but WITHOUT ANY WARRANTY; without even the implied warranty of
18 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 // GNU General Public License for more details.
20 //
21 // You should have received a copy of the GNU General Public License
22 // along with this program; if not, write to the Free Software
23 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
27 #include "Tag.h" // Interface declarations
30 #include "SafeFile.h" // Needed for CFileDataIO
31 #include "MD4Hash.h" // Needed for CMD4Hash
33 ///////////////////////////////////////////////////////////////////////////////
34 // CTag
36 CTag::CTag(const wxString& Name)
38 m_uType = 0;
39 m_uName = 0;
40 m_Name = Name;
41 m_uVal = 0;
42 m_nSize = 0;
45 CTag::CTag(uint8 uName)
47 m_uType = 0;
48 m_uName = uName;
49 m_uVal = 0;
50 m_nSize = 0;
53 CTag::CTag(const CTag& rTag)
55 m_uType = rTag.m_uType;
56 m_uName = rTag.m_uName;
57 m_Name = rTag.m_Name;
58 m_nSize = 0;
59 if (rTag.IsStr()) {
60 m_pstrVal = new wxString(rTag.GetStr());
61 } else if (rTag.IsInt()) {
62 m_uVal = rTag.GetInt();
63 } else if (rTag.IsFloat()) {
64 m_fVal = rTag.GetFloat();
65 } else if (rTag.IsHash()) {
66 m_hashVal = new CMD4Hash(rTag.GetHash());
67 } else if (rTag.IsBlob()) {
68 m_nSize = rTag.GetBlobSize();
69 m_pData = new unsigned char[rTag.GetBlobSize()];
70 memcpy(m_pData, rTag.GetBlob(), rTag.GetBlobSize());
71 } else if (rTag.IsBsob()) {
72 m_nSize = rTag.GetBsobSize();
73 m_pData = new unsigned char[rTag.GetBsobSize()];
74 memcpy(m_pData, rTag.GetBsob(), rTag.GetBsobSize());
75 } else {
76 wxASSERT(0);
77 m_uVal = 0;
82 CTag::CTag(const CFileDataIO& data, bool bOptUTF8)
84 // Zero variables to allow for safe deletion
85 m_uType = m_uName = m_nSize = m_uVal = 0;
86 m_pData = NULL;
88 try {
89 m_uType = data.ReadUInt8();
90 if (m_uType & 0x80) {
91 m_uType &= 0x7F;
92 m_uName = data.ReadUInt8();
93 } else {
94 uint16 length = data.ReadUInt16();
95 if (length == 1) {
96 m_uName = data.ReadUInt8();
97 } else {
98 m_uName = 0;
99 m_Name = data.ReadOnlyString(utf8strNone,length);
103 // NOTE: It's very important that we read the *entire* packet data,
104 // even if we do not use each tag. Otherwise we will get in trouble
105 // when the packets are returned in a list - like the search results
106 // from a server. If we cannot do this, then we throw an exception.
107 switch (m_uType) {
108 case TAGTYPE_STRING:
109 m_pstrVal = new wxString(data.ReadString(bOptUTF8));
110 break;
112 case TAGTYPE_UINT32:
113 m_uVal = data.ReadUInt32();
114 break;
116 case TAGTYPE_UINT64:
117 m_uVal = data.ReadUInt64();
118 break;
120 case TAGTYPE_UINT16:
121 m_uVal = data.ReadUInt16();
122 m_uType = TAGTYPE_UINT32;
123 break;
125 case TAGTYPE_UINT8:
126 m_uVal = data.ReadUInt8();
127 m_uType = TAGTYPE_UINT32;
128 break;
130 case TAGTYPE_FLOAT32:
131 //#warning Endianess problem?
132 data.Read(&m_fVal, 4);
133 break;
135 case TAGTYPE_HASH16:
136 m_hashVal = new CMD4Hash(data.ReadHash());
137 break;
139 case TAGTYPE_BOOL:
140 printf("***NOTE: %s; Reading BOOL tag\n", __FUNCTION__);
141 data.ReadUInt8();
142 break;
144 case TAGTYPE_BOOLARRAY: {
145 printf("***NOTE: %s; Reading BOOL Array tag\n", __FUNCTION__);
146 uint16 len = data.ReadUInt16();
148 // 07-Apr-2004: eMule versions prior to 0.42e.29 used the formula "(len+7)/8"!
149 //#warning This seems to be off by one! 8 / 8 + 1 == 2, etc.
150 data.Seek((len / 8) + 1, wxFromCurrent);
151 break;
154 case TAGTYPE_BLOB:
155 // 07-Apr-2004: eMule versions prior to 0.42e.29 handled the "len" as int16!
156 m_nSize = data.ReadUInt32();
158 // Since the length is 32b, this check is needed to avoid
159 // huge allocations in case of bad tags.
160 if (m_nSize > data.GetLength() - data.GetPosition()) {
161 throw CInvalidPacket(wxT("Malformed tag"));
164 m_pData = new unsigned char[m_nSize];
165 data.Read(m_pData, m_nSize);
166 break;
168 default:
169 if (m_uType >= TAGTYPE_STR1 && m_uType <= TAGTYPE_STR16) {
170 uint8 length = m_uType - TAGTYPE_STR1 + 1;
171 m_pstrVal = new wxString(data.ReadOnlyString(bOptUTF8, length));
172 m_uType = TAGTYPE_STRING;
173 } else {
174 // Since we cannot determine the length of this tag, we
175 // simply have to abort reading the file.
176 throw CInvalidPacket(wxString::Format(wxT("Unknown tag type encounted %x, cannot proceed!"),m_uType));
179 } catch (...) {
180 if (m_uType == TAGTYPE_BLOB) {
181 delete[] m_pData;
184 throw;
189 CTag::~CTag()
191 if (IsStr()) {
192 delete m_pstrVal;
193 } else if (IsHash()) {
194 delete m_hashVal;
195 } else if (IsBlob() || IsBsob()) {
196 delete[] m_pData;
201 CTag &CTag::operator=(const CTag &rhs)
203 if (&rhs != this) {
204 m_uType = rhs.m_uType;
205 m_uName = rhs.m_uName;
206 m_Name = rhs.m_Name;
207 m_nSize = 0;
208 if (rhs.IsStr()) {
209 wxString *p = new wxString(rhs.GetStr());
210 delete m_pstrVal;
211 m_pstrVal = p;
212 } else if (rhs.IsInt()) {
213 m_uVal = rhs.GetInt();
214 } else if (rhs.IsFloat()) {
215 m_fVal = rhs.GetFloat();
216 } else if (rhs.IsHash()) {
217 CMD4Hash *p = new CMD4Hash(rhs.GetHash());
218 delete m_hashVal;
219 m_hashVal = p;
220 } else if (rhs.IsBlob()) {
221 m_nSize = rhs.GetBlobSize();
222 unsigned char *p = new unsigned char[rhs.GetBlobSize()];
223 delete [] m_pData;
224 m_pData = p;
225 memcpy(m_pData, rhs.GetBlob(), rhs.GetBlobSize());
226 } else if (rhs.IsBsob()) {
227 m_nSize = rhs.GetBsobSize();
228 unsigned char *p = new unsigned char[rhs.GetBsobSize()];
229 delete [] m_pData;
230 m_pData = p;
231 memcpy(m_pData, rhs.GetBsob(), rhs.GetBsobSize());
232 } else {
233 wxASSERT(0);
234 m_uVal = 0;
237 return *this;
241 #define CHECK_TAG_TYPE(check, expected) \
242 if (!(check)) { \
243 throw CInvalidPacket(wxT(#expected) wxT(" tag expected, but found ") + GetFullInfo()); \
246 uint64 CTag::GetInt() const
248 CHECK_TAG_TYPE(IsInt(), Integer);
250 return m_uVal;
254 const wxString& CTag::GetStr() const
256 CHECK_TAG_TYPE(IsStr(), String);
258 return *m_pstrVal;
262 float CTag::GetFloat() const
264 CHECK_TAG_TYPE(IsFloat(), Float);
266 return m_fVal;
270 const CMD4Hash& CTag::GetHash() const
272 CHECK_TAG_TYPE(IsHash(), Hash);
274 return *m_hashVal;
278 uint32 CTag::GetBlobSize() const
280 CHECK_TAG_TYPE(IsBlob(), Blob);
282 return m_nSize;
286 const byte* CTag::GetBlob() const
288 CHECK_TAG_TYPE(IsBlob(), Blob);
290 return m_pData;
294 uint32 CTag::GetBsobSize() const
296 CHECK_TAG_TYPE(IsBsob(), Bsob);
298 return m_nSize;
302 const byte* CTag::GetBsob() const
304 CHECK_TAG_TYPE(IsBsob(), Bsob);
306 return m_pData;
309 bool CTag::WriteNewEd2kTag(CFileDataIO* data, EUtf8Str eStrEncode) const
312 // Write tag type
313 uint8 uType;
315 if (IsInt()) {
316 if (m_uVal <= 0xFF) {
317 uType = TAGTYPE_UINT8;
318 } else if (m_uVal <= 0xFFFF) {
319 uType = TAGTYPE_UINT16;
320 } else if (m_uVal <= 0xFFFFFFFF) {
321 uType = TAGTYPE_UINT32;
322 } else {
323 uType = TAGTYPE_UINT64;
325 } else if (IsStr()) {
326 uint16 uStrValLen = GetRawSize(*m_pstrVal, eStrEncode);
327 if (uStrValLen >= 1 && uStrValLen <= 16) {
328 uType = TAGTYPE_STR1 + uStrValLen - 1;
329 } else {
330 uType = TAGTYPE_STRING;
332 } else {
333 uType = m_uType;
336 // Write tag name
337 if (!m_Name.IsEmpty()) {
338 data->WriteUInt8(uType);
339 data->WriteString(m_Name,utf8strNone);
340 } else {
341 wxASSERT( m_uName != 0 );
342 data->WriteUInt8(uType | 0x80);
343 data->WriteUInt8(m_uName);
346 // Write tag data
347 switch (uType) {
348 case TAGTYPE_STRING:
349 data->WriteString(*m_pstrVal,eStrEncode);
350 break;
351 case TAGTYPE_UINT64:
352 data->WriteUInt64(m_uVal);
353 break;
354 case TAGTYPE_UINT32:
355 data->WriteUInt32(m_uVal);
356 break;
357 case TAGTYPE_UINT16:
358 data->WriteUInt16(m_uVal);
359 break;
360 case TAGTYPE_UINT8:
361 data->WriteUInt8(m_uVal);
362 break;
363 case TAGTYPE_FLOAT32:
364 //#warning Endianess problem?
365 data->Write(&m_fVal, 4);
366 break;
367 case TAGTYPE_HASH16:
368 data->WriteHash(*m_hashVal);
369 break;
370 case TAGTYPE_BLOB:
371 data->WriteUInt32(m_nSize);
372 data->Write(m_pData, m_nSize);
373 break;
374 default:
375 // See comment on the default: of CTag::CTag(const CFileDataIO& data, bool bOptUTF8)
376 if (uType >= TAGTYPE_STR1 && uType <= TAGTYPE_STR16) {
377 // Sending '0' as len size makes it not write the len on the IO file.
378 // This is because this tag types send the len as their type.
379 data->WriteString(*m_pstrVal,eStrEncode,0);
380 } else {
381 printf("%s; Unknown tag: type=0x%02X\n", __FUNCTION__, uType);
382 wxASSERT(0);
383 return false;
385 break;
388 return true;
391 bool CTag::WriteTagToFile(CFileDataIO* file, EUtf8Str WXUNUSED(eStrEncode), bool restrictive) const
394 // Don't write tags of unknown types, we wouldn't be able to read them in again
395 // and the met file would be corrupted
396 if (!restrictive || (IsStr() || IsInt() || IsFloat() || IsBlob())) {
398 // If this fails, it'll throw.
399 file->WriteTag(*this);
400 return true;
402 } else {
403 printf("%s; Ignored tag with unknown type=0x%02X\n", __FUNCTION__, m_uType);
404 return false;
409 wxString CTag::GetFullInfo() const
411 wxString strTag;
412 if (!m_Name.IsEmpty()) {
413 // Special case: Kad tags, and some ED2k tags ...
414 if (m_Name.Length() == 1) {
415 strTag = wxString::Format(wxT("0x%02X"), m_Name[0]);
416 } else {
417 strTag = wxT('\"');
418 strTag += m_Name;
419 strTag += wxT('\"');
421 } else {
422 strTag = wxString::Format(wxT("0x%02X"), m_uName);
424 strTag += wxT("=");
425 if (m_uType == TAGTYPE_STRING) {
426 strTag += wxT("\"");
427 strTag += *m_pstrVal;
428 strTag += wxT("\"");
429 } else if (m_uType >= TAGTYPE_STR1 && m_uType <= TAGTYPE_STR16) {
430 strTag += wxString::Format(wxT("(Str%u)\""), m_uType - TAGTYPE_STR1 + 1)
431 + *m_pstrVal + wxT("\"");
432 } else if (m_uType == TAGTYPE_UINT64) {
433 strTag += wxString::Format(wxT("(Int64)%") wxLongLongFmtSpec wxT("u"), m_uVal);
434 } else if (m_uType == TAGTYPE_UINT32) {
435 strTag += wxString::Format(wxT("(Int32)%u"), (unsigned)m_uVal);
436 } else if (m_uType == TAGTYPE_UINT16) {
437 strTag += wxString::Format(wxT("(Int16)%u"), (unsigned)m_uVal);
438 } else if (m_uType == TAGTYPE_UINT8) {
439 strTag += wxString::Format(wxT("(Int8)%u"), (unsigned)m_uVal);
440 } else if (m_uType == TAGTYPE_FLOAT32) {
441 strTag += wxString::Format(wxT("(Float32)%f"), m_fVal);
442 } else if (m_uType == TAGTYPE_BLOB) {
443 strTag += wxString::Format(wxT("(Blob)%u"), m_nSize);
444 } else if (m_uType == TAGTYPE_BSOB) {
445 strTag += wxString::Format(wxT("(Bsob)%u"), m_nSize);
446 } else {
447 strTag += wxString::Format(wxT("Type=%u"), m_uType);
449 return strTag;
452 CTagHash::CTagHash(const wxString& name, const CMD4Hash& value)
453 : CTag(name) {
454 m_hashVal = new CMD4Hash(value);
455 m_uType = TAGTYPE_HASH16;
458 CTagHash::CTagHash(uint8 name, const CMD4Hash& value)
459 : CTag(name) {
460 m_hashVal = new CMD4Hash(value);
461 m_uType = TAGTYPE_HASH16;
464 void deleteTagPtrListEntries(TagPtrList* taglist)
466 TagPtrList::const_iterator it;
467 for (it = taglist->begin(); it != taglist->end(); it++) {
468 delete *it;
470 taglist->clear();
472 // File_checked_for_headers