2 // This file is part of the aMule Project.
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 )
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
29 #include <common/Format.h> // Needed for WXLONGLONGFMTSPEC
31 #include "SafeFile.h" // Needed for CFileDataIO
32 #include "MD4Hash.h" // Needed for CMD4Hash
33 #include "CompilerSpecific.h" // Needed for __FUNCTION__
36 ///////////////////////////////////////////////////////////////////////////////
39 CTag::CTag(const wxString
& Name
)
48 CTag::CTag(uint8 uName
)
56 CTag::CTag(const CTag
& rTag
)
58 m_uType
= rTag
.m_uType
;
59 m_uName
= rTag
.m_uName
;
63 m_pstrVal
= new wxString(rTag
.GetStr());
64 } else if (rTag
.IsInt()) {
65 m_uVal
= rTag
.GetInt();
66 } else if (rTag
.IsFloat()) {
67 m_fVal
= rTag
.GetFloat();
68 } else if (rTag
.IsHash()) {
69 m_hashVal
= new CMD4Hash(rTag
.GetHash());
70 } else if (rTag
.IsBlob()) {
71 m_nSize
= rTag
.GetBlobSize();
72 m_pData
= new unsigned char[rTag
.GetBlobSize()];
73 memcpy(m_pData
, rTag
.GetBlob(), rTag
.GetBlobSize());
74 } else if (rTag
.IsBsob()) {
75 m_nSize
= rTag
.GetBsobSize();
76 m_pData
= new unsigned char[rTag
.GetBsobSize()];
77 memcpy(m_pData
, rTag
.GetBsob(), rTag
.GetBsobSize());
85 CTag::CTag(const CFileDataIO
& data
, bool bOptUTF8
)
87 // Zero variables to allow for safe deletion
88 m_uType
= m_uName
= m_nSize
= m_uVal
= 0;
92 m_uType
= data
.ReadUInt8();
95 m_uName
= data
.ReadUInt8();
97 uint16 length
= data
.ReadUInt16();
99 m_uName
= data
.ReadUInt8();
102 m_Name
= data
.ReadOnlyString(utf8strNone
,length
);
106 // NOTE: It's very important that we read the *entire* packet data,
107 // even if we do not use each tag. Otherwise we will get in trouble
108 // when the packets are returned in a list - like the search results
109 // from a server. If we cannot do this, then we throw an exception.
112 m_pstrVal
= new wxString(data
.ReadString(bOptUTF8
));
116 m_uVal
= data
.ReadUInt32();
120 m_uVal
= data
.ReadUInt64();
124 m_uVal
= data
.ReadUInt16();
125 m_uType
= TAGTYPE_UINT32
;
129 m_uVal
= data
.ReadUInt8();
130 m_uType
= TAGTYPE_UINT32
;
133 case TAGTYPE_FLOAT32
:
134 //#warning Endianess problem?
135 data
.Read(&m_fVal
, 4);
139 m_hashVal
= new CMD4Hash(data
.ReadHash());
143 printf("***NOTE: %s; Reading BOOL tag\n", __FUNCTION__
);
147 case TAGTYPE_BOOLARRAY
: {
148 printf("***NOTE: %s; Reading BOOL Array tag\n", __FUNCTION__
);
149 uint16 len
= data
.ReadUInt16();
151 // 07-Apr-2004: eMule versions prior to 0.42e.29 used the formula "(len+7)/8"!
152 //#warning This seems to be off by one! 8 / 8 + 1 == 2, etc.
153 data
.Seek((len
/ 8) + 1, wxFromCurrent
);
158 // 07-Apr-2004: eMule versions prior to 0.42e.29 handled the "len" as int16!
159 m_nSize
= data
.ReadUInt32();
161 // Since the length is 32b, this check is needed to avoid
162 // huge allocations in case of bad tags.
163 if (m_nSize
> data
.GetLength() - data
.GetPosition()) {
164 throw CInvalidPacket(wxT("Malformed tag"));
167 m_pData
= new unsigned char[m_nSize
];
168 data
.Read(m_pData
, m_nSize
);
172 if (m_uType
>= TAGTYPE_STR1
&& m_uType
<= TAGTYPE_STR16
) {
173 uint8 length
= m_uType
- TAGTYPE_STR1
+ 1;
174 m_pstrVal
= new wxString(data
.ReadOnlyString(bOptUTF8
, length
));
175 m_uType
= TAGTYPE_STRING
;
177 // Since we cannot determine the length of this tag, we
178 // simply have to abort reading the file.
179 throw CInvalidPacket(CFormat(wxT("Unknown tag type encounted %x, cannot proceed!")) % m_uType
);
183 if (m_uType
== TAGTYPE_BLOB
) {
196 } else if (IsHash()) {
198 } else if (IsBlob() || IsBsob()) {
204 CTag
&CTag::operator=(const CTag
&rhs
)
207 m_uType
= rhs
.m_uType
;
208 m_uName
= rhs
.m_uName
;
212 wxString
*p
= new wxString(rhs
.GetStr());
215 } else if (rhs
.IsInt()) {
216 m_uVal
= rhs
.GetInt();
217 } else if (rhs
.IsFloat()) {
218 m_fVal
= rhs
.GetFloat();
219 } else if (rhs
.IsHash()) {
220 CMD4Hash
*p
= new CMD4Hash(rhs
.GetHash());
223 } else if (rhs
.IsBlob()) {
224 m_nSize
= rhs
.GetBlobSize();
225 unsigned char *p
= new unsigned char[rhs
.GetBlobSize()];
228 memcpy(m_pData
, rhs
.GetBlob(), rhs
.GetBlobSize());
229 } else if (rhs
.IsBsob()) {
230 m_nSize
= rhs
.GetBsobSize();
231 unsigned char *p
= new unsigned char[rhs
.GetBsobSize()];
234 memcpy(m_pData
, rhs
.GetBsob(), rhs
.GetBsobSize());
244 #define CHECK_TAG_TYPE(check, expected) \
246 throw CInvalidPacket(wxT(#expected) wxT(" tag expected, but found ") + GetFullInfo()); \
249 uint64
CTag::GetInt() const
251 CHECK_TAG_TYPE(IsInt(), Integer
);
257 const wxString
& CTag::GetStr() const
259 CHECK_TAG_TYPE(IsStr(), String
);
265 float CTag::GetFloat() const
267 CHECK_TAG_TYPE(IsFloat(), Float
);
273 const CMD4Hash
& CTag::GetHash() const
275 CHECK_TAG_TYPE(IsHash(), Hash
);
281 uint32
CTag::GetBlobSize() const
283 CHECK_TAG_TYPE(IsBlob(), Blob
);
289 const uint8_t* CTag::GetBlob() const
291 CHECK_TAG_TYPE(IsBlob(), Blob
);
297 uint32
CTag::GetBsobSize() const
299 CHECK_TAG_TYPE(IsBsob(), Bsob
);
305 const uint8_t* CTag::GetBsob() const
307 CHECK_TAG_TYPE(IsBsob(), Bsob
);
312 bool CTag::WriteNewEd2kTag(CFileDataIO
* data
, EUtf8Str eStrEncode
) const
319 if (m_uVal
<= 0xFF) {
320 uType
= TAGTYPE_UINT8
;
321 } else if (m_uVal
<= 0xFFFF) {
322 uType
= TAGTYPE_UINT16
;
323 } else if (m_uVal
<= 0xFFFFFFFF) {
324 uType
= TAGTYPE_UINT32
;
326 uType
= TAGTYPE_UINT64
;
328 } else if (IsStr()) {
329 uint16 uStrValLen
= GetRawSize(*m_pstrVal
, eStrEncode
);
330 if (uStrValLen
>= 1 && uStrValLen
<= 16) {
331 uType
= TAGTYPE_STR1
+ uStrValLen
- 1;
333 uType
= TAGTYPE_STRING
;
340 if (!m_Name
.IsEmpty()) {
341 data
->WriteUInt8(uType
);
342 data
->WriteString(m_Name
,utf8strNone
);
344 wxASSERT( m_uName
!= 0 );
345 data
->WriteUInt8(uType
| 0x80);
346 data
->WriteUInt8(m_uName
);
352 data
->WriteString(*m_pstrVal
,eStrEncode
);
355 data
->WriteUInt64(m_uVal
);
358 data
->WriteUInt32(m_uVal
);
361 data
->WriteUInt16(m_uVal
);
364 data
->WriteUInt8(m_uVal
);
366 case TAGTYPE_FLOAT32
:
367 //#warning Endianess problem?
368 data
->Write(&m_fVal
, 4);
371 data
->WriteHash(*m_hashVal
);
374 data
->WriteUInt32(m_nSize
);
375 data
->Write(m_pData
, m_nSize
);
378 // See comment on the default: of CTag::CTag(const CFileDataIO& data, bool bOptUTF8)
379 if (uType
>= TAGTYPE_STR1
&& uType
<= TAGTYPE_STR16
) {
380 // Sending '0' as len size makes it not write the len on the IO file.
381 // This is because this tag types send the len as their type.
382 data
->WriteString(*m_pstrVal
,eStrEncode
,0);
384 printf("%s; Unknown tag: type=0x%02X\n", __FUNCTION__
, uType
);
394 bool CTag::WriteTagToFile(CFileDataIO
* file
, EUtf8Str
WXUNUSED(eStrEncode
), bool restrictive
) const
397 // Don't write tags of unknown types, we wouldn't be able to read them in again
398 // and the met file would be corrupted
399 if (!restrictive
|| (IsStr() || IsInt() || IsFloat() || IsBlob())) {
401 // If this fails, it'll throw.
402 file
->WriteTag(*this);
406 printf("%s; Ignored tag with unknown type=0x%02X\n", __FUNCTION__
, m_uType
);
412 wxString
CTag::GetFullInfo() const
415 if (!m_Name
.IsEmpty()) {
416 // Special case: Kad tags, and some ED2k tags ...
417 if (m_Name
.Length() == 1) {
418 strTag
= CFormat(wxT("0x%02X")) % (unsigned)m_Name
[0];
425 strTag
= CFormat(wxT("0x%02X")) % m_uName
;
428 if (m_uType
== TAGTYPE_STRING
) {
430 strTag
+= *m_pstrVal
;
432 } else if (m_uType
>= TAGTYPE_STR1
&& m_uType
<= TAGTYPE_STR16
) {
433 strTag
+= CFormat(wxT("(Str%u)\"")) % (m_uType
- TAGTYPE_STR1
+ 1)
434 + *m_pstrVal
+ wxT("\"");
435 } else if (m_uType
== TAGTYPE_UINT64
) {
436 strTag
+= CFormat(wxT("(Int64)%u")) % m_uVal
;
437 } else if (m_uType
== TAGTYPE_UINT32
) {
438 strTag
+= CFormat(wxT("(Int32)%u")) % m_uVal
;
439 } else if (m_uType
== TAGTYPE_UINT16
) {
440 strTag
+= CFormat(wxT("(Int16)%u")) % m_uVal
;
441 } else if (m_uType
== TAGTYPE_UINT8
) {
442 strTag
+= CFormat(wxT("(Int8)%u")) % m_uVal
;
443 } else if (m_uType
== TAGTYPE_FLOAT32
) {
444 strTag
+= CFormat(wxT("(Float32)%f")) % m_fVal
;
445 } else if (m_uType
== TAGTYPE_BLOB
) {
446 strTag
+= CFormat(wxT("(Blob)%u")) % m_nSize
;
447 } else if (m_uType
== TAGTYPE_BSOB
) {
448 strTag
+= CFormat(wxT("(Bsob)%u")) % m_nSize
;
450 strTag
+= CFormat(wxT("Type=%u")) % m_uType
;
455 CTagHash::CTagHash(const wxString
& name
, const CMD4Hash
& value
)
457 m_hashVal
= new CMD4Hash(value
);
458 m_uType
= TAGTYPE_HASH16
;
461 CTagHash::CTagHash(uint8 name
, const CMD4Hash
& value
)
463 m_hashVal
= new CMD4Hash(value
);
464 m_uType
= TAGTYPE_HASH16
;
467 void deleteTagPtrListEntries(TagPtrList
* taglist
)
469 DeleteContents(*taglist
);
471 // File_checked_for_headers