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
29 #include <common/Format.h> // Needed for WXLONGLONGFMTSPEC
31 #include "SafeFile.h" // Needed for CFileDataIO
32 #include "MD4Hash.h" // Needed for CMD4Hash
35 #define __FUNCTION__ __FILE__+__LINE__
38 ///////////////////////////////////////////////////////////////////////////////
41 CTag::CTag(const wxString
& Name
)
50 CTag::CTag(uint8 uName
)
58 CTag::CTag(const CTag
& rTag
)
60 m_uType
= rTag
.m_uType
;
61 m_uName
= rTag
.m_uName
;
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());
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;
94 m_uType
= data
.ReadUInt8();
97 m_uName
= data
.ReadUInt8();
99 uint16 length
= data
.ReadUInt16();
101 m_uName
= data
.ReadUInt8();
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.
114 m_pstrVal
= new wxString(data
.ReadString(bOptUTF8
));
118 m_uVal
= data
.ReadUInt32();
122 m_uVal
= data
.ReadUInt64();
126 m_uVal
= data
.ReadUInt16();
127 m_uType
= TAGTYPE_UINT32
;
131 m_uVal
= data
.ReadUInt8();
132 m_uType
= TAGTYPE_UINT32
;
135 case TAGTYPE_FLOAT32
:
136 //#warning Endianess problem?
137 data
.Read(&m_fVal
, 4);
141 m_hashVal
= new CMD4Hash(data
.ReadHash());
145 printf("***NOTE: %s; Reading BOOL tag\n", __FUNCTION__
);
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
);
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
);
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
;
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
);
185 if (m_uType
== TAGTYPE_BLOB
) {
198 } else if (IsHash()) {
200 } else if (IsBlob() || IsBsob()) {
206 CTag
&CTag::operator=(const CTag
&rhs
)
209 m_uType
= rhs
.m_uType
;
210 m_uName
= rhs
.m_uName
;
214 wxString
*p
= new wxString(rhs
.GetStr());
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());
225 } else if (rhs
.IsBlob()) {
226 m_nSize
= rhs
.GetBlobSize();
227 unsigned char *p
= new unsigned char[rhs
.GetBlobSize()];
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()];
236 memcpy(m_pData
, rhs
.GetBsob(), rhs
.GetBsobSize());
246 #define CHECK_TAG_TYPE(check, expected) \
248 throw CInvalidPacket(wxT(#expected) wxT(" tag expected, but found ") + GetFullInfo()); \
251 uint64
CTag::GetInt() const
253 CHECK_TAG_TYPE(IsInt(), Integer
);
259 const wxString
& CTag::GetStr() const
261 CHECK_TAG_TYPE(IsStr(), String
);
267 float CTag::GetFloat() const
269 CHECK_TAG_TYPE(IsFloat(), Float
);
275 const CMD4Hash
& CTag::GetHash() const
277 CHECK_TAG_TYPE(IsHash(), Hash
);
283 uint32
CTag::GetBlobSize() const
285 CHECK_TAG_TYPE(IsBlob(), Blob
);
291 const byte
* CTag::GetBlob() const
293 CHECK_TAG_TYPE(IsBlob(), Blob
);
299 uint32
CTag::GetBsobSize() const
301 CHECK_TAG_TYPE(IsBsob(), Bsob
);
307 const byte
* CTag::GetBsob() const
309 CHECK_TAG_TYPE(IsBsob(), Bsob
);
314 bool CTag::WriteNewEd2kTag(CFileDataIO
* data
, EUtf8Str eStrEncode
) const
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
;
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;
335 uType
= TAGTYPE_STRING
;
342 if (!m_Name
.IsEmpty()) {
343 data
->WriteUInt8(uType
);
344 data
->WriteString(m_Name
,utf8strNone
);
346 wxASSERT( m_uName
!= 0 );
347 data
->WriteUInt8(uType
| 0x80);
348 data
->WriteUInt8(m_uName
);
354 data
->WriteString(*m_pstrVal
,eStrEncode
);
357 data
->WriteUInt64(m_uVal
);
360 data
->WriteUInt32(m_uVal
);
363 data
->WriteUInt16(m_uVal
);
366 data
->WriteUInt8(m_uVal
);
368 case TAGTYPE_FLOAT32
:
369 //#warning Endianess problem?
370 data
->Write(&m_fVal
, 4);
373 data
->WriteHash(*m_hashVal
);
376 data
->WriteUInt32(m_nSize
);
377 data
->Write(m_pData
, m_nSize
);
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);
386 printf("%s; Unknown tag: type=0x%02X\n", __FUNCTION__
, uType
);
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);
408 printf("%s; Ignored tag with unknown type=0x%02X\n", __FUNCTION__
, m_uType
);
414 wxString
CTag::GetFullInfo() const
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];
427 strTag
= CFormat(wxT("0x%02X")) % m_uName
;
430 if (m_uType
== TAGTYPE_STRING
) {
432 strTag
+= *m_pstrVal
;
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
;
452 strTag
+= CFormat(wxT("Type=%u")) % m_uType
;
457 CTagHash::CTagHash(const wxString
& name
, const CMD4Hash
& value
)
459 m_hashVal
= new CMD4Hash(value
);
460 m_uType
= TAGTYPE_HASH16
;
463 CTagHash::CTagHash(uint8 name
, const CMD4Hash
& value
)
465 m_hashVal
= new CMD4Hash(value
);
466 m_uType
= TAGTYPE_HASH16
;
469 void deleteTagPtrListEntries(TagPtrList
* taglist
)
471 DeleteContents(*taglist
);
473 // File_checked_for_headers