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 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 ///////////////////////////////////////////////////////////////////////////////
36 CTag::CTag(const wxString
& Name
)
45 CTag::CTag(uint8 uName
)
53 CTag::CTag(const CTag
& rTag
)
55 m_uType
= rTag
.m_uType
;
56 m_uName
= rTag
.m_uName
;
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());
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;
89 m_uType
= data
.ReadUInt8();
92 m_uName
= data
.ReadUInt8();
94 uint16 length
= data
.ReadUInt16();
96 m_uName
= data
.ReadUInt8();
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.
109 m_pstrVal
= new wxString(data
.ReadString(bOptUTF8
));
113 m_uVal
= data
.ReadUInt32();
117 m_uVal
= data
.ReadUInt64();
121 m_uVal
= data
.ReadUInt16();
122 m_uType
= TAGTYPE_UINT32
;
126 m_uVal
= data
.ReadUInt8();
127 m_uType
= TAGTYPE_UINT32
;
130 case TAGTYPE_FLOAT32
:
131 //#warning Endianess problem?
132 data
.Read(&m_fVal
, 4);
136 m_hashVal
= new CMD4Hash(data
.ReadHash());
140 printf("***NOTE: %s; Reading BOOL tag\n", __FUNCTION__
);
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
);
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
);
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
;
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
));
180 if (m_uType
== TAGTYPE_BLOB
) {
193 } else if (IsHash()) {
195 } else if (IsBlob() || IsBsob()) {
201 CTag
&CTag::operator=(const CTag
&rhs
)
204 m_uType
= rhs
.m_uType
;
205 m_uName
= rhs
.m_uName
;
209 wxString
*p
= new wxString(rhs
.GetStr());
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());
220 } else if (rhs
.IsBlob()) {
221 m_nSize
= rhs
.GetBlobSize();
222 unsigned char *p
= new unsigned char[rhs
.GetBlobSize()];
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()];
231 memcpy(m_pData
, rhs
.GetBsob(), rhs
.GetBsobSize());
241 #define CHECK_TAG_TYPE(check, expected) \
243 throw CInvalidPacket(wxT(#expected) wxT(" tag expected, but found ") + GetFullInfo()); \
246 uint64
CTag::GetInt() const
248 CHECK_TAG_TYPE(IsInt(), Integer
);
254 const wxString
& CTag::GetStr() const
256 CHECK_TAG_TYPE(IsStr(), String
);
262 float CTag::GetFloat() const
264 CHECK_TAG_TYPE(IsFloat(), Float
);
270 const CMD4Hash
& CTag::GetHash() const
272 CHECK_TAG_TYPE(IsHash(), Hash
);
278 uint32
CTag::GetBlobSize() const
280 CHECK_TAG_TYPE(IsBlob(), Blob
);
286 const byte
* CTag::GetBlob() const
288 CHECK_TAG_TYPE(IsBlob(), Blob
);
294 uint32
CTag::GetBsobSize() const
296 CHECK_TAG_TYPE(IsBsob(), Bsob
);
302 const byte
* CTag::GetBsob() const
304 CHECK_TAG_TYPE(IsBsob(), Bsob
);
309 bool CTag::WriteNewEd2kTag(CFileDataIO
* data
, EUtf8Str eStrEncode
) const
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
;
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;
330 uType
= TAGTYPE_STRING
;
337 if (!m_Name
.IsEmpty()) {
338 data
->WriteUInt8(uType
);
339 data
->WriteString(m_Name
,utf8strNone
);
341 wxASSERT( m_uName
!= 0 );
342 data
->WriteUInt8(uType
| 0x80);
343 data
->WriteUInt8(m_uName
);
349 data
->WriteString(*m_pstrVal
,eStrEncode
);
352 data
->WriteUInt64(m_uVal
);
355 data
->WriteUInt32(m_uVal
);
358 data
->WriteUInt16(m_uVal
);
361 data
->WriteUInt8(m_uVal
);
363 case TAGTYPE_FLOAT32
:
364 //#warning Endianess problem?
365 data
->Write(&m_fVal
, 4);
368 data
->WriteHash(*m_hashVal
);
371 data
->WriteUInt32(m_nSize
);
372 data
->Write(m_pData
, m_nSize
);
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);
381 printf("%s; Unknown tag: type=0x%02X\n", __FUNCTION__
, uType
);
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);
403 printf("%s; Ignored tag with unknown type=0x%02X\n", __FUNCTION__
, m_uType
);
409 wxString
CTag::GetFullInfo() const
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]);
422 strTag
= wxString::Format(wxT("0x%02X"), m_uName
);
425 if (m_uType
== TAGTYPE_STRING
) {
427 strTag
+= *m_pstrVal
;
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
);
447 strTag
+= wxString::Format(wxT("Type=%u"), m_uType
);
452 CTagHash::CTagHash(const wxString
& name
, const CMD4Hash
& value
)
454 m_hashVal
= new CMD4Hash(value
);
455 m_uType
= TAGTYPE_HASH16
;
458 CTagHash::CTagHash(uint8 name
, const CMD4Hash
& value
)
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
++) {
472 // File_checked_for_headers