2 // This file is part of the aMule Project.
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 )
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
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
30 #include "SafeFile.h" // Needed for CFileDataIO
31 #include "MD4Hash.h" // Needed for CMD4Hash
33 #if defined(__SUNPRO_CC)
34 #define __FUNCTION__ __FILE__+__LINE__
37 ///////////////////////////////////////////////////////////////////////////////
40 CTag::CTag(const wxString
& Name
)
49 CTag::CTag(uint8 uName
)
57 CTag::CTag(const CTag
& rTag
)
59 m_uType
= rTag
.m_uType
;
60 m_uName
= rTag
.m_uName
;
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());
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;
93 m_uType
= data
.ReadUInt8();
96 m_uName
= data
.ReadUInt8();
98 uint16 length
= data
.ReadUInt16();
100 m_uName
= data
.ReadUInt8();
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.
113 m_pstrVal
= new wxString(data
.ReadString(bOptUTF8
));
117 m_uVal
= data
.ReadUInt32();
121 m_uVal
= data
.ReadUInt64();
125 m_uVal
= data
.ReadUInt16();
126 m_uType
= TAGTYPE_UINT32
;
130 m_uVal
= data
.ReadUInt8();
131 m_uType
= TAGTYPE_UINT32
;
134 case TAGTYPE_FLOAT32
:
135 //#warning Endianess problem?
136 data
.Read(&m_fVal
, 4);
140 m_hashVal
= new CMD4Hash(data
.ReadHash());
144 printf("***NOTE: %s; Reading BOOL tag\n", __FUNCTION__
);
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
);
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
);
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
;
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
));
184 if (m_uType
== TAGTYPE_BLOB
) {
197 } else if (IsHash()) {
199 } else if (IsBlob() || IsBsob()) {
205 CTag
&CTag::operator=(const CTag
&rhs
)
208 m_uType
= rhs
.m_uType
;
209 m_uName
= rhs
.m_uName
;
213 wxString
*p
= new wxString(rhs
.GetStr());
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());
224 } else if (rhs
.IsBlob()) {
225 m_nSize
= rhs
.GetBlobSize();
226 unsigned char *p
= new unsigned char[rhs
.GetBlobSize()];
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()];
235 memcpy(m_pData
, rhs
.GetBsob(), rhs
.GetBsobSize());
245 #define CHECK_TAG_TYPE(check, expected) \
247 throw CInvalidPacket(wxT(#expected) wxT(" tag expected, but found ") + GetFullInfo()); \
250 uint64
CTag::GetInt() const
252 CHECK_TAG_TYPE(IsInt(), Integer
);
258 const wxString
& CTag::GetStr() const
260 CHECK_TAG_TYPE(IsStr(), String
);
266 float CTag::GetFloat() const
268 CHECK_TAG_TYPE(IsFloat(), Float
);
274 const CMD4Hash
& CTag::GetHash() const
276 CHECK_TAG_TYPE(IsHash(), Hash
);
282 uint32
CTag::GetBlobSize() const
284 CHECK_TAG_TYPE(IsBlob(), Blob
);
290 const byte
* CTag::GetBlob() const
292 CHECK_TAG_TYPE(IsBlob(), Blob
);
298 uint32
CTag::GetBsobSize() const
300 CHECK_TAG_TYPE(IsBsob(), Bsob
);
306 const byte
* CTag::GetBsob() const
308 CHECK_TAG_TYPE(IsBsob(), Bsob
);
313 bool CTag::WriteNewEd2kTag(CFileDataIO
* data
, EUtf8Str eStrEncode
) const
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
;
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;
334 uType
= TAGTYPE_STRING
;
341 if (!m_Name
.IsEmpty()) {
342 data
->WriteUInt8(uType
);
343 data
->WriteString(m_Name
,utf8strNone
);
345 wxASSERT( m_uName
!= 0 );
346 data
->WriteUInt8(uType
| 0x80);
347 data
->WriteUInt8(m_uName
);
353 data
->WriteString(*m_pstrVal
,eStrEncode
);
356 data
->WriteUInt64(m_uVal
);
359 data
->WriteUInt32(m_uVal
);
362 data
->WriteUInt16(m_uVal
);
365 data
->WriteUInt8(m_uVal
);
367 case TAGTYPE_FLOAT32
:
368 //#warning Endianess problem?
369 data
->Write(&m_fVal
, 4);
372 data
->WriteHash(*m_hashVal
);
375 data
->WriteUInt32(m_nSize
);
376 data
->Write(m_pData
, m_nSize
);
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);
385 printf("%s; Unknown tag: type=0x%02X\n", __FUNCTION__
, uType
);
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);
407 printf("%s; Ignored tag with unknown type=0x%02X\n", __FUNCTION__
, m_uType
);
413 wxString
CTag::GetFullInfo() const
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]);
426 strTag
= wxString::Format(wxT("0x%02X"), m_uName
);
429 if (m_uType
== TAGTYPE_STRING
) {
431 strTag
+= *m_pstrVal
;
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
);
451 strTag
+= wxString::Format(wxT("Type=%u"), m_uType
);
456 CTagHash::CTagHash(const wxString
& name
, const CMD4Hash
& value
)
458 m_hashVal
= new CMD4Hash(value
);
459 m_uType
= TAGTYPE_HASH16
;
462 CTagHash::CTagHash(uint8 name
, const CMD4Hash
& value
)
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
++) {
476 // File_checked_for_headers