Upstream tarball 9828
[amule.git] / src / Tag.cpp
blob8c7a93db4ed280ea84aa6292c47e8e29cf008157
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-2008 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 #if defined(__SUNPRO_CC)
34 #define __FUNCTION__ __FILE__+__LINE__
35 #endif
37 ///////////////////////////////////////////////////////////////////////////////
38 // CTag
40 CTag::CTag(const wxString& Name)
42 m_uType = 0;
43 m_uName = 0;
44 m_Name = Name;
45 m_uVal = 0;
46 m_nSize = 0;
49 CTag::CTag(uint8 uName)
51 m_uType = 0;
52 m_uName = uName;
53 m_uVal = 0;
54 m_nSize = 0;
57 CTag::CTag(const CTag& rTag)
59 m_uType = rTag.m_uType;
60 m_uName = rTag.m_uName;
61 m_Name = rTag.m_Name;
62 m_nSize = 0;
63 if (rTag.IsStr()) {
64 m_pstrVal = new wxString(rTag.GetStr());
65 } else if (rTag.IsInt()) {
66 m_uVal = rTag.GetInt();
67 } else if (rTag.IsFloat()) {
68 m_fVal = rTag.GetFloat();
69 } else if (rTag.IsHash()) {
70 m_hashVal = new CMD4Hash(rTag.GetHash());
71 } else if (rTag.IsBlob()) {
72 m_nSize = rTag.GetBlobSize();
73 m_pData = new unsigned char[rTag.GetBlobSize()];
74 memcpy(m_pData, rTag.GetBlob(), rTag.GetBlobSize());
75 } else if (rTag.IsBsob()) {
76 m_nSize = rTag.GetBsobSize();
77 m_pData = new unsigned char[rTag.GetBsobSize()];
78 memcpy(m_pData, rTag.GetBsob(), rTag.GetBsobSize());
79 } else {
80 wxFAIL;
81 m_uVal = 0;
86 CTag::CTag(const CFileDataIO& data, bool bOptUTF8)
88 // Zero variables to allow for safe deletion
89 m_uType = m_uName = m_nSize = m_uVal = 0;
90 m_pData = NULL;
92 try {
93 m_uType = data.ReadUInt8();
94 if (m_uType & 0x80) {
95 m_uType &= 0x7F;
96 m_uName = data.ReadUInt8();
97 } else {
98 uint16 length = data.ReadUInt16();
99 if (length == 1) {
100 m_uName = data.ReadUInt8();
101 } else {
102 m_uName = 0;
103 m_Name = data.ReadOnlyString(utf8strNone,length);
107 // NOTE: It's very important that we read the *entire* packet data,
108 // even if we do not use each tag. Otherwise we will get in trouble
109 // when the packets are returned in a list - like the search results
110 // from a server. If we cannot do this, then we throw an exception.
111 switch (m_uType) {
112 case TAGTYPE_STRING:
113 m_pstrVal = new wxString(data.ReadString(bOptUTF8));
114 break;
116 case TAGTYPE_UINT32:
117 m_uVal = data.ReadUInt32();
118 break;
120 case TAGTYPE_UINT64:
121 m_uVal = data.ReadUInt64();
122 break;
124 case TAGTYPE_UINT16:
125 m_uVal = data.ReadUInt16();
126 m_uType = TAGTYPE_UINT32;
127 break;
129 case TAGTYPE_UINT8:
130 m_uVal = data.ReadUInt8();
131 m_uType = TAGTYPE_UINT32;
132 break;
134 case TAGTYPE_FLOAT32:
135 //#warning Endianess problem?
136 data.Read(&m_fVal, 4);
137 break;
139 case TAGTYPE_HASH16:
140 m_hashVal = new CMD4Hash(data.ReadHash());
141 break;
143 case TAGTYPE_BOOL:
144 printf("***NOTE: %s; Reading BOOL tag\n", __FUNCTION__);
145 data.ReadUInt8();
146 break;
148 case TAGTYPE_BOOLARRAY: {
149 printf("***NOTE: %s; Reading BOOL Array tag\n", __FUNCTION__);
150 uint16 len = data.ReadUInt16();
152 // 07-Apr-2004: eMule versions prior to 0.42e.29 used the formula "(len+7)/8"!
153 //#warning This seems to be off by one! 8 / 8 + 1 == 2, etc.
154 data.Seek((len / 8) + 1, wxFromCurrent);
155 break;
158 case TAGTYPE_BLOB:
159 // 07-Apr-2004: eMule versions prior to 0.42e.29 handled the "len" as int16!
160 m_nSize = data.ReadUInt32();
162 // Since the length is 32b, this check is needed to avoid
163 // huge allocations in case of bad tags.
164 if (m_nSize > data.GetLength() - data.GetPosition()) {
165 throw CInvalidPacket(wxT("Malformed tag"));
168 m_pData = new unsigned char[m_nSize];
169 data.Read(m_pData, m_nSize);
170 break;
172 default:
173 if (m_uType >= TAGTYPE_STR1 && m_uType <= TAGTYPE_STR16) {
174 uint8 length = m_uType - TAGTYPE_STR1 + 1;
175 m_pstrVal = new wxString(data.ReadOnlyString(bOptUTF8, length));
176 m_uType = TAGTYPE_STRING;
177 } else {
178 // Since we cannot determine the length of this tag, we
179 // simply have to abort reading the file.
180 throw CInvalidPacket(wxString::Format(wxT("Unknown tag type encounted %x, cannot proceed!"),m_uType));
183 } catch (...) {
184 if (m_uType == TAGTYPE_BLOB) {
185 delete[] m_pData;
188 throw;
193 CTag::~CTag()
195 if (IsStr()) {
196 delete m_pstrVal;
197 } else if (IsHash()) {
198 delete m_hashVal;
199 } else if (IsBlob() || IsBsob()) {
200 delete[] m_pData;
205 CTag &CTag::operator=(const CTag &rhs)
207 if (&rhs != this) {
208 m_uType = rhs.m_uType;
209 m_uName = rhs.m_uName;
210 m_Name = rhs.m_Name;
211 m_nSize = 0;
212 if (rhs.IsStr()) {
213 wxString *p = new wxString(rhs.GetStr());
214 delete m_pstrVal;
215 m_pstrVal = p;
216 } else if (rhs.IsInt()) {
217 m_uVal = rhs.GetInt();
218 } else if (rhs.IsFloat()) {
219 m_fVal = rhs.GetFloat();
220 } else if (rhs.IsHash()) {
221 CMD4Hash *p = new CMD4Hash(rhs.GetHash());
222 delete m_hashVal;
223 m_hashVal = p;
224 } else if (rhs.IsBlob()) {
225 m_nSize = rhs.GetBlobSize();
226 unsigned char *p = new unsigned char[rhs.GetBlobSize()];
227 delete [] m_pData;
228 m_pData = p;
229 memcpy(m_pData, rhs.GetBlob(), rhs.GetBlobSize());
230 } else if (rhs.IsBsob()) {
231 m_nSize = rhs.GetBsobSize();
232 unsigned char *p = new unsigned char[rhs.GetBsobSize()];
233 delete [] m_pData;
234 m_pData = p;
235 memcpy(m_pData, rhs.GetBsob(), rhs.GetBsobSize());
236 } else {
237 wxFAIL;
238 m_uVal = 0;
241 return *this;
245 #define CHECK_TAG_TYPE(check, expected) \
246 if (!(check)) { \
247 throw CInvalidPacket(wxT(#expected) wxT(" tag expected, but found ") + GetFullInfo()); \
250 uint64 CTag::GetInt() const
252 CHECK_TAG_TYPE(IsInt(), Integer);
254 return m_uVal;
258 const wxString& CTag::GetStr() const
260 CHECK_TAG_TYPE(IsStr(), String);
262 return *m_pstrVal;
266 float CTag::GetFloat() const
268 CHECK_TAG_TYPE(IsFloat(), Float);
270 return m_fVal;
274 const CMD4Hash& CTag::GetHash() const
276 CHECK_TAG_TYPE(IsHash(), Hash);
278 return *m_hashVal;
282 uint32 CTag::GetBlobSize() const
284 CHECK_TAG_TYPE(IsBlob(), Blob);
286 return m_nSize;
290 const byte* CTag::GetBlob() const
292 CHECK_TAG_TYPE(IsBlob(), Blob);
294 return m_pData;
298 uint32 CTag::GetBsobSize() const
300 CHECK_TAG_TYPE(IsBsob(), Bsob);
302 return m_nSize;
306 const byte* CTag::GetBsob() const
308 CHECK_TAG_TYPE(IsBsob(), Bsob);
310 return m_pData;
313 bool CTag::WriteNewEd2kTag(CFileDataIO* data, EUtf8Str eStrEncode) const
316 // Write tag type
317 uint8 uType;
319 if (IsInt()) {
320 if (m_uVal <= 0xFF) {
321 uType = TAGTYPE_UINT8;
322 } else if (m_uVal <= 0xFFFF) {
323 uType = TAGTYPE_UINT16;
324 } else if (m_uVal <= 0xFFFFFFFF) {
325 uType = TAGTYPE_UINT32;
326 } else {
327 uType = TAGTYPE_UINT64;
329 } else if (IsStr()) {
330 uint16 uStrValLen = GetRawSize(*m_pstrVal, eStrEncode);
331 if (uStrValLen >= 1 && uStrValLen <= 16) {
332 uType = TAGTYPE_STR1 + uStrValLen - 1;
333 } else {
334 uType = TAGTYPE_STRING;
336 } else {
337 uType = m_uType;
340 // Write tag name
341 if (!m_Name.IsEmpty()) {
342 data->WriteUInt8(uType);
343 data->WriteString(m_Name,utf8strNone);
344 } else {
345 wxASSERT( m_uName != 0 );
346 data->WriteUInt8(uType | 0x80);
347 data->WriteUInt8(m_uName);
350 // Write tag data
351 switch (uType) {
352 case TAGTYPE_STRING:
353 data->WriteString(*m_pstrVal,eStrEncode);
354 break;
355 case TAGTYPE_UINT64:
356 data->WriteUInt64(m_uVal);
357 break;
358 case TAGTYPE_UINT32:
359 data->WriteUInt32(m_uVal);
360 break;
361 case TAGTYPE_UINT16:
362 data->WriteUInt16(m_uVal);
363 break;
364 case TAGTYPE_UINT8:
365 data->WriteUInt8(m_uVal);
366 break;
367 case TAGTYPE_FLOAT32:
368 //#warning Endianess problem?
369 data->Write(&m_fVal, 4);
370 break;
371 case TAGTYPE_HASH16:
372 data->WriteHash(*m_hashVal);
373 break;
374 case TAGTYPE_BLOB:
375 data->WriteUInt32(m_nSize);
376 data->Write(m_pData, m_nSize);
377 break;
378 default:
379 // See comment on the default: of CTag::CTag(const CFileDataIO& data, bool bOptUTF8)
380 if (uType >= TAGTYPE_STR1 && uType <= TAGTYPE_STR16) {
381 // Sending '0' as len size makes it not write the len on the IO file.
382 // This is because this tag types send the len as their type.
383 data->WriteString(*m_pstrVal,eStrEncode,0);
384 } else {
385 printf("%s; Unknown tag: type=0x%02X\n", __FUNCTION__, uType);
386 wxFAIL;
387 return false;
389 break;
392 return true;
395 bool CTag::WriteTagToFile(CFileDataIO* file, EUtf8Str WXUNUSED(eStrEncode), bool restrictive) const
398 // Don't write tags of unknown types, we wouldn't be able to read them in again
399 // and the met file would be corrupted
400 if (!restrictive || (IsStr() || IsInt() || IsFloat() || IsBlob())) {
402 // If this fails, it'll throw.
403 file->WriteTag(*this);
404 return true;
406 } else {
407 printf("%s; Ignored tag with unknown type=0x%02X\n", __FUNCTION__, m_uType);
408 return false;
413 wxString CTag::GetFullInfo() const
415 wxString strTag;
416 if (!m_Name.IsEmpty()) {
417 // Special case: Kad tags, and some ED2k tags ...
418 if (m_Name.Length() == 1) {
419 strTag = wxString::Format(wxT("0x%02X"), m_Name[0]);
420 } else {
421 strTag = wxT('\"');
422 strTag += m_Name;
423 strTag += wxT('\"');
425 } else {
426 strTag = wxString::Format(wxT("0x%02X"), m_uName);
428 strTag += wxT("=");
429 if (m_uType == TAGTYPE_STRING) {
430 strTag += wxT("\"");
431 strTag += *m_pstrVal;
432 strTag += wxT("\"");
433 } else if (m_uType >= TAGTYPE_STR1 && m_uType <= TAGTYPE_STR16) {
434 strTag += wxString::Format(wxT("(Str%u)\""), m_uType - TAGTYPE_STR1 + 1)
435 + *m_pstrVal + wxT("\"");
436 } else if (m_uType == TAGTYPE_UINT64) {
437 strTag += wxString::Format(wxT("(Int64)%") wxLongLongFmtSpec wxT("u"), m_uVal);
438 } else if (m_uType == TAGTYPE_UINT32) {
439 strTag += wxString::Format(wxT("(Int32)%u"), (unsigned)m_uVal);
440 } else if (m_uType == TAGTYPE_UINT16) {
441 strTag += wxString::Format(wxT("(Int16)%u"), (unsigned)m_uVal);
442 } else if (m_uType == TAGTYPE_UINT8) {
443 strTag += wxString::Format(wxT("(Int8)%u"), (unsigned)m_uVal);
444 } else if (m_uType == TAGTYPE_FLOAT32) {
445 strTag += wxString::Format(wxT("(Float32)%f"), m_fVal);
446 } else if (m_uType == TAGTYPE_BLOB) {
447 strTag += wxString::Format(wxT("(Blob)%u"), m_nSize);
448 } else if (m_uType == TAGTYPE_BSOB) {
449 strTag += wxString::Format(wxT("(Bsob)%u"), m_nSize);
450 } else {
451 strTag += wxString::Format(wxT("Type=%u"), m_uType);
453 return strTag;
456 CTagHash::CTagHash(const wxString& name, const CMD4Hash& value)
457 : CTag(name) {
458 m_hashVal = new CMD4Hash(value);
459 m_uType = TAGTYPE_HASH16;
462 CTagHash::CTagHash(uint8 name, const CMD4Hash& value)
463 : CTag(name) {
464 m_hashVal = new CMD4Hash(value);
465 m_uType = TAGTYPE_HASH16;
468 void deleteTagPtrListEntries(TagPtrList* taglist)
470 TagPtrList::const_iterator it;
471 for (it = taglist->begin(); it != taglist->end(); it++) {
472 delete *it;
474 taglist->clear();
476 // File_checked_for_headers