Updated Spanish translation by tHatdUde
[amule.git] / src / Tag.cpp
blob460a203fd4d6f0a1907b02a2a09e1f5be2c342cf
1 //
2 // This file is part of the aMule Project.
3 //
4 // Copyright (c) 2003-2011 aMule Team ( admin@amule.org / http://www.amule.org )
5 // Copyright (c) 2002-2011 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.
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
29 #include <common/Format.h> // Needed for WXLONGLONGFMTSPEC
31 #include "SafeFile.h" // Needed for CFileDataIO
32 #include "MD4Hash.h" // Needed for CMD4Hash
34 #ifdef __SUNPRO_CC
35 #define __FUNCTION__ __FILE__+__LINE__
36 #endif
38 ///////////////////////////////////////////////////////////////////////////////
39 // CTag
41 CTag::CTag(const wxString& Name)
43 m_uType = 0;
44 m_uName = 0;
45 m_Name = Name;
46 m_uVal = 0;
47 m_nSize = 0;
50 CTag::CTag(uint8 uName)
52 m_uType = 0;
53 m_uName = uName;
54 m_uVal = 0;
55 m_nSize = 0;
58 CTag::CTag(const CTag& rTag)
60 m_uType = rTag.m_uType;
61 m_uName = rTag.m_uName;
62 m_Name = rTag.m_Name;
63 m_nSize = 0;
64 if (rTag.IsStr()) {
65 m_pstrVal = new wxString(rTag.GetStr());
66 } else if (rTag.IsInt()) {
67 m_uVal = rTag.GetInt();
68 } else if (rTag.IsFloat()) {
69 m_fVal = rTag.GetFloat();
70 } else if (rTag.IsHash()) {
71 m_hashVal = new CMD4Hash(rTag.GetHash());
72 } else if (rTag.IsBlob()) {
73 m_nSize = rTag.GetBlobSize();
74 m_pData = new unsigned char[rTag.GetBlobSize()];
75 memcpy(m_pData, rTag.GetBlob(), rTag.GetBlobSize());
76 } else if (rTag.IsBsob()) {
77 m_nSize = rTag.GetBsobSize();
78 m_pData = new unsigned char[rTag.GetBsobSize()];
79 memcpy(m_pData, rTag.GetBsob(), rTag.GetBsobSize());
80 } else {
81 wxFAIL;
82 m_uVal = 0;
87 CTag::CTag(const CFileDataIO& data, bool bOptUTF8)
89 // Zero variables to allow for safe deletion
90 m_uType = m_uName = m_nSize = m_uVal = 0;
91 m_pData = NULL;
93 try {
94 m_uType = data.ReadUInt8();
95 if (m_uType & 0x80) {
96 m_uType &= 0x7F;
97 m_uName = data.ReadUInt8();
98 } else {
99 uint16 length = data.ReadUInt16();
100 if (length == 1) {
101 m_uName = data.ReadUInt8();
102 } else {
103 m_uName = 0;
104 m_Name = data.ReadOnlyString(utf8strNone,length);
108 // NOTE: It's very important that we read the *entire* packet data,
109 // even if we do not use each tag. Otherwise we will get in trouble
110 // when the packets are returned in a list - like the search results
111 // from a server. If we cannot do this, then we throw an exception.
112 switch (m_uType) {
113 case TAGTYPE_STRING:
114 m_pstrVal = new wxString(data.ReadString(bOptUTF8));
115 break;
117 case TAGTYPE_UINT32:
118 m_uVal = data.ReadUInt32();
119 break;
121 case TAGTYPE_UINT64:
122 m_uVal = data.ReadUInt64();
123 break;
125 case TAGTYPE_UINT16:
126 m_uVal = data.ReadUInt16();
127 m_uType = TAGTYPE_UINT32;
128 break;
130 case TAGTYPE_UINT8:
131 m_uVal = data.ReadUInt8();
132 m_uType = TAGTYPE_UINT32;
133 break;
135 case TAGTYPE_FLOAT32:
136 //#warning Endianess problem?
137 data.Read(&m_fVal, 4);
138 break;
140 case TAGTYPE_HASH16:
141 m_hashVal = new CMD4Hash(data.ReadHash());
142 break;
144 case TAGTYPE_BOOL:
145 printf("***NOTE: %s; Reading BOOL tag\n", __FUNCTION__);
146 data.ReadUInt8();
147 break;
149 case TAGTYPE_BOOLARRAY: {
150 printf("***NOTE: %s; Reading BOOL Array tag\n", __FUNCTION__);
151 uint16 len = data.ReadUInt16();
153 // 07-Apr-2004: eMule versions prior to 0.42e.29 used the formula "(len+7)/8"!
154 //#warning This seems to be off by one! 8 / 8 + 1 == 2, etc.
155 data.Seek((len / 8) + 1, wxFromCurrent);
156 break;
159 case TAGTYPE_BLOB:
160 // 07-Apr-2004: eMule versions prior to 0.42e.29 handled the "len" as int16!
161 m_nSize = data.ReadUInt32();
163 // Since the length is 32b, this check is needed to avoid
164 // huge allocations in case of bad tags.
165 if (m_nSize > data.GetLength() - data.GetPosition()) {
166 throw CInvalidPacket(wxT("Malformed tag"));
169 m_pData = new unsigned char[m_nSize];
170 data.Read(m_pData, m_nSize);
171 break;
173 default:
174 if (m_uType >= TAGTYPE_STR1 && m_uType <= TAGTYPE_STR16) {
175 uint8 length = m_uType - TAGTYPE_STR1 + 1;
176 m_pstrVal = new wxString(data.ReadOnlyString(bOptUTF8, length));
177 m_uType = TAGTYPE_STRING;
178 } else {
179 // Since we cannot determine the length of this tag, we
180 // simply have to abort reading the file.
181 throw CInvalidPacket(CFormat(wxT("Unknown tag type encounted %x, cannot proceed!")) % m_uType);
184 } catch (...) {
185 if (m_uType == TAGTYPE_BLOB) {
186 delete[] m_pData;
189 throw;
194 CTag::~CTag()
196 if (IsStr()) {
197 delete m_pstrVal;
198 } else if (IsHash()) {
199 delete m_hashVal;
200 } else if (IsBlob() || IsBsob()) {
201 delete[] m_pData;
206 CTag &CTag::operator=(const CTag &rhs)
208 if (&rhs != this) {
209 m_uType = rhs.m_uType;
210 m_uName = rhs.m_uName;
211 m_Name = rhs.m_Name;
212 m_nSize = 0;
213 if (rhs.IsStr()) {
214 wxString *p = new wxString(rhs.GetStr());
215 delete m_pstrVal;
216 m_pstrVal = p;
217 } else if (rhs.IsInt()) {
218 m_uVal = rhs.GetInt();
219 } else if (rhs.IsFloat()) {
220 m_fVal = rhs.GetFloat();
221 } else if (rhs.IsHash()) {
222 CMD4Hash *p = new CMD4Hash(rhs.GetHash());
223 delete m_hashVal;
224 m_hashVal = p;
225 } else if (rhs.IsBlob()) {
226 m_nSize = rhs.GetBlobSize();
227 unsigned char *p = new unsigned char[rhs.GetBlobSize()];
228 delete [] m_pData;
229 m_pData = p;
230 memcpy(m_pData, rhs.GetBlob(), rhs.GetBlobSize());
231 } else if (rhs.IsBsob()) {
232 m_nSize = rhs.GetBsobSize();
233 unsigned char *p = new unsigned char[rhs.GetBsobSize()];
234 delete [] m_pData;
235 m_pData = p;
236 memcpy(m_pData, rhs.GetBsob(), rhs.GetBsobSize());
237 } else {
238 wxFAIL;
239 m_uVal = 0;
242 return *this;
246 #define CHECK_TAG_TYPE(check, expected) \
247 if (!(check)) { \
248 throw CInvalidPacket(wxT(#expected) wxT(" tag expected, but found ") + GetFullInfo()); \
251 uint64 CTag::GetInt() const
253 CHECK_TAG_TYPE(IsInt(), Integer);
255 return m_uVal;
259 const wxString& CTag::GetStr() const
261 CHECK_TAG_TYPE(IsStr(), String);
263 return *m_pstrVal;
267 float CTag::GetFloat() const
269 CHECK_TAG_TYPE(IsFloat(), Float);
271 return m_fVal;
275 const CMD4Hash& CTag::GetHash() const
277 CHECK_TAG_TYPE(IsHash(), Hash);
279 return *m_hashVal;
283 uint32 CTag::GetBlobSize() const
285 CHECK_TAG_TYPE(IsBlob(), Blob);
287 return m_nSize;
291 const byte* CTag::GetBlob() const
293 CHECK_TAG_TYPE(IsBlob(), Blob);
295 return m_pData;
299 uint32 CTag::GetBsobSize() const
301 CHECK_TAG_TYPE(IsBsob(), Bsob);
303 return m_nSize;
307 const byte* CTag::GetBsob() const
309 CHECK_TAG_TYPE(IsBsob(), Bsob);
311 return m_pData;
314 bool CTag::WriteNewEd2kTag(CFileDataIO* data, EUtf8Str eStrEncode) const
317 // Write tag type
318 uint8 uType;
320 if (IsInt()) {
321 if (m_uVal <= 0xFF) {
322 uType = TAGTYPE_UINT8;
323 } else if (m_uVal <= 0xFFFF) {
324 uType = TAGTYPE_UINT16;
325 } else if (m_uVal <= 0xFFFFFFFF) {
326 uType = TAGTYPE_UINT32;
327 } else {
328 uType = TAGTYPE_UINT64;
330 } else if (IsStr()) {
331 uint16 uStrValLen = GetRawSize(*m_pstrVal, eStrEncode);
332 if (uStrValLen >= 1 && uStrValLen <= 16) {
333 uType = TAGTYPE_STR1 + uStrValLen - 1;
334 } else {
335 uType = TAGTYPE_STRING;
337 } else {
338 uType = m_uType;
341 // Write tag name
342 if (!m_Name.IsEmpty()) {
343 data->WriteUInt8(uType);
344 data->WriteString(m_Name,utf8strNone);
345 } else {
346 wxASSERT( m_uName != 0 );
347 data->WriteUInt8(uType | 0x80);
348 data->WriteUInt8(m_uName);
351 // Write tag data
352 switch (uType) {
353 case TAGTYPE_STRING:
354 data->WriteString(*m_pstrVal,eStrEncode);
355 break;
356 case TAGTYPE_UINT64:
357 data->WriteUInt64(m_uVal);
358 break;
359 case TAGTYPE_UINT32:
360 data->WriteUInt32(m_uVal);
361 break;
362 case TAGTYPE_UINT16:
363 data->WriteUInt16(m_uVal);
364 break;
365 case TAGTYPE_UINT8:
366 data->WriteUInt8(m_uVal);
367 break;
368 case TAGTYPE_FLOAT32:
369 //#warning Endianess problem?
370 data->Write(&m_fVal, 4);
371 break;
372 case TAGTYPE_HASH16:
373 data->WriteHash(*m_hashVal);
374 break;
375 case TAGTYPE_BLOB:
376 data->WriteUInt32(m_nSize);
377 data->Write(m_pData, m_nSize);
378 break;
379 default:
380 // See comment on the default: of CTag::CTag(const CFileDataIO& data, bool bOptUTF8)
381 if (uType >= TAGTYPE_STR1 && uType <= TAGTYPE_STR16) {
382 // Sending '0' as len size makes it not write the len on the IO file.
383 // This is because this tag types send the len as their type.
384 data->WriteString(*m_pstrVal,eStrEncode,0);
385 } else {
386 printf("%s; Unknown tag: type=0x%02X\n", __FUNCTION__, uType);
387 wxFAIL;
388 return false;
390 break;
393 return true;
396 bool CTag::WriteTagToFile(CFileDataIO* file, EUtf8Str WXUNUSED(eStrEncode), bool restrictive) const
399 // Don't write tags of unknown types, we wouldn't be able to read them in again
400 // and the met file would be corrupted
401 if (!restrictive || (IsStr() || IsInt() || IsFloat() || IsBlob())) {
403 // If this fails, it'll throw.
404 file->WriteTag(*this);
405 return true;
407 } else {
408 printf("%s; Ignored tag with unknown type=0x%02X\n", __FUNCTION__, m_uType);
409 return false;
414 wxString CTag::GetFullInfo() const
416 wxString strTag;
417 if (!m_Name.IsEmpty()) {
418 // Special case: Kad tags, and some ED2k tags ...
419 if (m_Name.Length() == 1) {
420 strTag = CFormat(wxT("0x%02X")) % (unsigned)m_Name[0];
421 } else {
422 strTag = wxT('\"');
423 strTag += m_Name;
424 strTag += wxT('\"');
426 } else {
427 strTag = CFormat(wxT("0x%02X")) % m_uName;
429 strTag += wxT("=");
430 if (m_uType == TAGTYPE_STRING) {
431 strTag += wxT("\"");
432 strTag += *m_pstrVal;
433 strTag += wxT("\"");
434 } else if (m_uType >= TAGTYPE_STR1 && m_uType <= TAGTYPE_STR16) {
435 strTag += CFormat(wxT("(Str%u)\"")) % (m_uType - TAGTYPE_STR1 + 1)
436 + *m_pstrVal + wxT("\"");
437 } else if (m_uType == TAGTYPE_UINT64) {
438 strTag += CFormat(wxT("(Int64)%u")) % m_uVal;
439 } else if (m_uType == TAGTYPE_UINT32) {
440 strTag += CFormat(wxT("(Int32)%u")) % m_uVal;
441 } else if (m_uType == TAGTYPE_UINT16) {
442 strTag += CFormat(wxT("(Int16)%u")) % m_uVal;
443 } else if (m_uType == TAGTYPE_UINT8) {
444 strTag += CFormat(wxT("(Int8)%u")) % m_uVal;
445 } else if (m_uType == TAGTYPE_FLOAT32) {
446 strTag += CFormat(wxT("(Float32)%f")) % m_fVal;
447 } else if (m_uType == TAGTYPE_BLOB) {
448 strTag += CFormat(wxT("(Blob)%u")) % m_nSize;
449 } else if (m_uType == TAGTYPE_BSOB) {
450 strTag += CFormat(wxT("(Bsob)%u")) % m_nSize;
451 } else {
452 strTag += CFormat(wxT("Type=%u")) % m_uType;
454 return strTag;
457 CTagHash::CTagHash(const wxString& name, const CMD4Hash& value)
458 : CTag(name) {
459 m_hashVal = new CMD4Hash(value);
460 m_uType = TAGTYPE_HASH16;
463 CTagHash::CTagHash(uint8 name, const CMD4Hash& value)
464 : CTag(name) {
465 m_hashVal = new CMD4Hash(value);
466 m_uType = TAGTYPE_HASH16;
469 void deleteTagPtrListEntries(TagPtrList* taglist)
471 DeleteContents(*taglist);
473 // File_checked_for_headers