1//
2// This file is part of the aMule Project.
3//
4// Copyright (c) 2004-2011 aMule Team ( admin@amule.org / http://www.amule.org )
5//
6// Any parts of this program derived from the xMule, lMule or eMule project,
7// or contributed by third-party developers are copyrighted by their
8// respective authors.
9//
10// This program is free software; you can redistribute it and/or modify
11// it under the terms of the GNU General Public License as published by
12// the Free Software Foundation; either version 2 of the License, or
13// (at your option) any later version.
14//
15// This program is distributed in the hope that it will be useful,
16// but WITHOUT ANY WARRANTY; without even the implied warranty of
17// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18// GNU General Public License for more details.
19//
20// You should have received a copy of the GNU General Public License
21// along with this program; if not, write to the Free Software
22// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301, USA
23//
24
25#ifdef __DEBUG__
26#define DEBUG_EC_IMPLEMENTATION
27
28#include <common/Format.h>  // Needed for CFormat
29#endif
30
31#include "ECTag.h"	// Needed for ECTag
32#include "ECSocket.h"	// Needed for CECSocket
33#include "ECSpecialTags.h"	// Needed for CValueMap
34#include "ECID.h"	// Needed for CECID
35
36/**********************************************************
37 *							  *
38 *	CECTag class					  *
39 *							  *
40 **********************************************************/
41
42//! Defines the Null tag which may be returned by GetTagByNameSafe.
43const CECTag CECTag::s_theNullTag;
44
45/**
46 * Creates a new null-valued CECTag instance
47 *
48 * @see s_theNullTag
49 * @see GetTagByNameSafe
50 */
51CECTag::CECTag() :
52	m_tagName(0),
53	m_dataType(EC_TAGTYPE_UNKNOWN),
54	m_dataLen(0),
55	m_tagData(NULL)	// All access functions check m_dataType, so no need to allocate a dummy buffer.
56{
57}
58
59/**
60 * Creates a new CECTag instance from the given data
61 *
62 * @param name	 TAG name
63 * @param length length of data buffer
64 * @param data	 TAG data
65 *
66 */
67CECTag::CECTag(ec_tagname_t name, unsigned int length, const void *data) : m_tagName(name)
68{
69	if (data) {
70		m_dataLen = length;
71		NewData();
72		memcpy(m_tagData, data, m_dataLen);
73	} else {
74		wxASSERT(length == 0);
75		m_dataLen = 0;
76		m_tagData = NULL;
77	}
78	m_dataType = EC_TAGTYPE_CUSTOM;
79}
80
81/**
82 * Creates a new CECTag instance for custom data
83 *
84 * @param name	 	TAG name
85 * @param length 	length of data buffer that will be alloc'ed
86 * @param dataptr	pointer to a void pointer which will be assigned the internal TAG data buffer
87 *
88 * \note TAG data buffer has to be filled with valid data after the ctor
89 */
90CECTag::CECTag(ec_tagname_t name, unsigned int length, void **dataptr)  : m_tagName(name)
91{
92	m_dataLen = length;
93	NewData();
94	*dataptr = m_tagData;
95	m_dataType = EC_TAGTYPE_CUSTOM;
96}
97
98/**
99 * Creates a new CECTag instance, which contains an IPv4 address.
100 *
101 * This function takes care of the endianness of the port number.
102 *
103 * @param name TAG name
104 * @param data The EC_IPv4_t class containing the IPv4 address.
105 *
106 * @see GetIPv4Data()
107 */
108CECTag::CECTag(ec_tagname_t name, const EC_IPv4_t& data) : m_tagName(name)
109{
110
111	m_dataLen = sizeof(EC_IPv4_t);
112	NewData();
113	RawPokeUInt32( ((EC_IPv4_t *)m_tagData)->m_ip, RawPeekUInt32( data.m_ip ) );
114	((EC_IPv4_t *)m_tagData)->m_port = ENDIAN_HTONS(data.m_port);
115	m_dataType = EC_TAGTYPE_IPV4;
116}
117
118/**
119 * Creates a new CECTag instance, which contains a MD4 hash.
120 *
121 * This function takes care to store hash in network byte order.
122 *
123 * @param name TAG name
124 * @param data The CMD4Hash class containing the MD4 hash.
125 *
126 * @see GetMD4Data()
127 */
128CECTag::CECTag(ec_tagname_t name, const CMD4Hash& data) : m_tagName(name)
129{
130	m_dataLen = 16;
131	NewData();
132	RawPokeUInt64( m_tagData,		RawPeekUInt64( data.GetHash() ) );
133	RawPokeUInt64( m_tagData + 8,	RawPeekUInt64( data.GetHash() + 8 ) );
134	m_dataType = EC_TAGTYPE_HASH16;
135}
136
137/**
138 * Creates a new CECTag instance, which contains a string
139 *
140 * @param name TAG name
141 * @param data wxString object, it's contents are converted to UTF-8.
142 *
143 * @see GetStringDataSTL()
144 */
145CECTag::CECTag(ec_tagname_t name, const std::string& data) : m_tagName(name)
146{
147	ConstructStringTag(name, data);
148}
149
150/**
151 * Creates a new CECTag instance, which contains a string
152 *
153 * @param name TAG name
154 * @param data wxString object, it's contents are converted to UTF-8.
155 *
156 * @see GetStringData()
157 */
158CECTag::CECTag(ec_tagname_t name, const wxString& data)
159{
160	ConstructStringTag(name, (const char*)unicode2UTF8(data));
161}
162CECTag::CECTag(ec_tagname_t name, const wxChar* data)
163{
164	ConstructStringTag(name, (const char*)unicode2UTF8(data));
165}
166
167/**
168 * Copy constructor
169 */
170CECTag::CECTag(const CECTag& tag)
171{
172	m_tagData = NULL;
173	*this = tag;
174}
175
176/**
177 * Creates a new CECTag instance, which contains an int value.
178 *
179 * This takes care of endianness problems with numbers.
180 *
181 * @param name TAG name.
182 * @param data number.
183 *
184 * @see GetInt()
185 */
186CECTag::CECTag(ec_tagname_t name, bool data) : m_tagName(name)
187{
188	InitInt(data);
189}
190CECTag::CECTag(ec_tagname_t name, uint8 data) : m_tagName(name)
191{
192	InitInt(data);
193}
194CECTag::CECTag(ec_tagname_t name, uint16 data) : m_tagName(name)
195{
196	InitInt(data);
197}
198CECTag::CECTag(ec_tagname_t name, uint32 data) : m_tagName(name)
199{
200	InitInt(data);
201}
202CECTag::CECTag(ec_tagname_t name, uint64 data) : m_tagName(name)
203{
204	InitInt(data);
205}
206
207void CECTag::InitInt(uint64 data)
208{
209	if (data <= 0xFF) {
210		m_dataType = EC_TAGTYPE_UINT8;
211		m_dataLen = 1;
212	} else if (data <= 0xFFFF) {
213		m_dataType = EC_TAGTYPE_UINT16;
214		m_dataLen = 2;
215	} else if (data <= 0xFFFFFFFF) {
216		m_dataType = EC_TAGTYPE_UINT32;
217		m_dataLen = 4;
218	} else {
219		m_dataType = EC_TAGTYPE_UINT64;
220		m_dataLen = 8;
221	}
222
223	NewData();
224
225	switch (m_dataType) {
226		case EC_TAGTYPE_UINT8:
227			PokeUInt8( m_tagData, (uint8) data );
228			break;
229		case EC_TAGTYPE_UINT16:
230			PokeUInt16( m_tagData, wxUINT16_SWAP_ALWAYS((uint16) data ));
231			break;
232		case EC_TAGTYPE_UINT32:
233			PokeUInt32( m_tagData, wxUINT32_SWAP_ALWAYS((uint32) data ));
234			break;
235		case EC_TAGTYPE_UINT64:
236			PokeUInt64( m_tagData, wxUINT64_SWAP_ALWAYS(data) );
237			break;
238	}
239}
240
241/**
242 * Creates a new CECTag instance, which contains a double precision floating point number
243 *
244 * @param name TAG name
245 * @param data double number
246 *
247 * @note The actual data is converted to string representation, because we have not found
248 * yet an effective and safe way to transmit floating point numbers.
249 *
250 * @see GetDoubleData()
251 */
252CECTag::CECTag(ec_tagname_t name, double data) : m_tagName(name)
253{
254	std::ostringstream double_str;
255	double_str << data;
256	std::string double_string = double_str.str();
257	const char * double_chr = double_string.c_str();
258	m_dataLen = (ec_taglen_t)strlen(double_chr) + 1;
259	NewData();
260	memcpy(m_tagData, double_chr, m_dataLen);
261	m_dataType = EC_TAGTYPE_DOUBLE;
262}
263
264/**
265 * Destructor - frees allocated data and deletes child TAGs.
266 */
267CECTag::~CECTag(void)
268{
269	delete [] m_tagData;
270}
271
272/**
273 * Copy assignment operator.
274 *
275 * std::vector uses this, but the compiler-supplied version wouldn't properly
276 * handle m_dynamic and m_tagData.  This wouldn't be necessary if m_tagData
277 * was a smart pointer (Hi, Kry!).
278 */
279CECTag& CECTag::operator=(const CECTag& tag)
280{
281	if (&tag != this) {
282		m_tagName = tag.m_tagName;
283		m_dataLen = tag.m_dataLen;
284		m_dataType = tag.m_dataType;
285		delete [] m_tagData;
286		if (m_dataLen != 0) {
287			NewData();
288			memcpy(m_tagData, tag.m_tagData, m_dataLen);
289		} else {
290			m_tagData = NULL;
291		}
292		m_tagList.clear();
293		for (const_iterator it = tag.begin(); it != tag.end(); it++) {
294			m_tagList.push_back(*it);
295		}
296	}
297	return *this;
298}
299
300/**
301 * Compare operator.
302 *
303 */
304bool CECTag::operator==(const CECTag& tag) const
305{
306	return	m_dataType == tag.m_dataType
307			&& m_tagName == tag.m_tagName
308			&& m_dataLen == tag.m_dataLen
309			&&	(m_dataLen == 0
310				|| !memcmp(m_tagData, tag.m_tagData, m_dataLen))
311			&& m_tagList == tag.m_tagList;
312}
313
314/**
315 * Add a child tag to this one. The tag argument is reset to an empty tag.
316 *
317 * Be very careful that this method swallows the content of \e tag, leaving \e tag empty.
318 * Thus, the following code won't work as expected:
319 * \code
320 * {
321 *	CECPacket *p = new CECPacket(whatever);
322 *	CECTag *t1 = new CECTag(whatever);
323 *	CECTag *t2 = new CECTag(whatever);
324 *	p->AddTag(*t1);
325 *	t1->AddTag(*t2);	// t2 won't be part of p !!!
326 * }
327 * \endcode
328 *
329 * To get the desired results, the above should be replaced with something like:
330 *
331 * \code
332 * {
333 *	CECPacket *p = new CECPacket(whatever);
334 *	CECTag *t1 = new CECTag(whatever);
335 *	CECTag *t2 = new CECTag(whatever);
336 *	t1->AddTag(*t2);
337 *	delete t2;	// we can safely delete the now empty t2 here, because t1 holds its content
338 *	p->AddTag(*t1);
339 *	delete t1;	// now p holds the content of both t1 and t2
340 * }
341 * \endcode
342 *
343 * Then why copying? The answer is to enable simplifying the code like this:
344 *
345 * \code
346 * {
347 *	CECPacket *p = new CECPacket(whatever);
348 *	CECTag t1(whatever);
349 *	t1.AddTag(CECTag(whatever));	// t2 is now created on-the-fly
350 *	p->AddTag(t1);	// now p holds a copy of both t1 and t2
351 * }
352 * \endcode
353 *
354 * @param tag a CECTag class instance to add.
355 * @return \b true if tag was really added,
356 * \b false when it was omitted through valuemap.
357 */
358bool CECTag::AddTag(const CECTag& tag, CValueMap* valuemap)
359{
360	if (valuemap) {
361		return valuemap->AddTag(tag, this);
362	}
363	// cannot have more than 64k tags
364	wxASSERT(m_tagList.size() < 0xffff);
365
366	// First add an empty tag.
367	m_tagList.push_back(CECEmptyTag());
368	// Then exchange the data. The original tag will be destroyed right after this call anyway.
369	// UGLY - GCC allows a reference to an in place constructed object only to be passed as const.
370	// So pass it the way it wants it and then cheat and cast it back to non-const. :-/
371	CECTag& wtag = const_cast<CECTag&>(tag);
372	wtag.swap(m_tagList.back());
373	return true;
374}
375
376void CECTag::AddTag(ec_tagname_t name, uint64_t data, CValueMap* valuemap)
377{
378	if (valuemap) {
379		valuemap->CreateTag(name, data, this);
380	} else {
381		AddTag(CECTag(name, data));
382	}
383}
384
385void CECTag::AddTag(ec_tagname_t name, const wxString& data, CValueMap* valuemap)
386{
387	if (valuemap) {
388		valuemap->CreateTag(name, data, this);
389	} else {
390		AddTag(CECTag(name, data));
391	}
392}
393
394void CECTag::AddTag(ec_tagname_t name, const CMD4Hash& data, CValueMap* valuemap)
395{
396	if (valuemap) {
397		valuemap->CreateTag(name, data, this);
398	} else {
399		AddTag(CECTag(name, data));
400	}
401}
402
403void CECTag::swap(CECTag& t2)
404{
405	std::swap(m_tagName, t2.m_tagName);
406	std::swap(m_dataType, t2.m_dataType);
407	std::swap(m_dataLen, t2.m_dataLen);
408	std::swap(m_tagData, t2.m_tagData);
409	std::swap(m_tagList, t2.m_tagList);
410}
411
412bool CECTag::ReadFromSocket(CECSocket& socket)
413{
414	ec_tagname_t tmp_tagName;
415	if (!socket.ReadNumber(&tmp_tagName, sizeof(ec_tagname_t))) {
416		return false;
417	}
418	m_tagName = tmp_tagName >> 1;
419	bool hasChildren = (tmp_tagName & 0x01) != 0;
420
421	if (!socket.ReadNumber(&m_dataType, sizeof(ec_tagtype_t))) {
422		return false;
423	}
424
425	if (!socket.ReadNumber(&m_dataLen, sizeof(ec_taglen_t))) {
426		return false;
427	}
428
429	if (hasChildren && !ReadChildren(socket)) {
430		return false;
431	}
432
433	unsigned int tmp_len = m_dataLen;
434	m_dataLen = 0;
435	m_dataLen = tmp_len - GetTagLen();
436	if (m_dataLen > 0) {
437		NewData();
438		if (!socket.ReadBuffer(m_tagData, m_dataLen)) {
439			return false;
440		}
441	} else {
442		m_tagData = NULL;
443	}
444
445	return true;
446}
447
448
449bool CECTag::WriteTag(CECSocket& socket) const
450{
451	ec_tagname_t tmp_tagName = (m_tagName << 1) | (m_tagList.empty() ? 0 : 1);
452	ec_tagtype_t type = m_dataType;
453	ec_taglen_t tagLen = GetTagLen();
454	wxASSERT(type != EC_TAGTYPE_UNKNOWN);
455
456	if (!socket.WriteNumber(&tmp_tagName, sizeof(ec_tagname_t))) return false;
457	if (!socket.WriteNumber(&type, sizeof(ec_tagtype_t))) return false;
458	if (!socket.WriteNumber(&tagLen, sizeof(ec_taglen_t))) return false;
459
460	if (!m_tagList.empty()) {
461		if (!WriteChildren(socket)) return false;
462	}
463
464	if (m_dataLen > 0) {
465		if (m_tagData != NULL) {	// This is here only to make sure everything, it should not be NULL at this point
466			if (!socket.WriteBuffer(m_tagData, m_dataLen)) return false;
467		}
468	}
469
470	return true;
471}
472
473bool CECTag::ReadChildren(CECSocket& socket)
474{
475	uint16 tmp_tagCount;
476	if (!socket.ReadNumber(&tmp_tagCount, sizeof(uint16))) {
477		return false;
478	}
479	m_tagList.clear();
480	for (int i = 0; i < tmp_tagCount; i++) {
481		m_tagList.push_back(CECTag());
482		CECTag& tag = m_tagList.back();
483		if (!tag.ReadFromSocket(socket)) {
484			return false;
485		}
486	}
487	return true;
488}
489
490bool CECTag::WriteChildren(CECSocket& socket) const
491{
492	wxASSERT(m_tagList.size() < 0xFFFF);
493    uint16 tmp = (uint16)m_tagList.size();
494	if (!socket.WriteNumber(&tmp, sizeof(tmp))) return false;
495	for (const_iterator it = begin(); it != end(); it++) {
496		if (!it->WriteTag(socket)) return false;
497	}
498	return true;
499}
500
501/**
502 * Finds the (first) child tag with given name.
503 *
504 * @param name TAG name to look for.
505 * @return the tag found, or NULL.
506 */
507const CECTag* CECTag::GetTagByName(ec_tagname_t name) const
508{
509	for (const_iterator it = begin(); it != end(); it++) {
510		if (it->m_tagName == name) return & *it;
511	}
512	return NULL;
513}
514
515/**
516 * Finds the (first) child tag with given name.
517 *
518 * @param name TAG name to look for.
519 * @return the tag found, or NULL.
520 */
521CECTag* CECTag::GetTagByName(ec_tagname_t name)
522{
523	for (TagList::iterator it = m_tagList.begin(); it != m_tagList.end(); it++) {
524		if (it->m_tagName == name) return & *it;
525	}
526	return NULL;
527}
528
529/**
530 * Finds the (first) child tag with given name.
531 *
532 * @param name TAG name to look for.
533 * @return the tag found, or a special null-valued tag otherwise.
534 *
535 * @see s_theNullTag
536 */
537const CECTag* CECTag::GetTagByNameSafe(ec_tagname_t name) const
538{
539	const CECTag* result = GetTagByName(name);
540	if (result == NULL)
541		result = &s_theNullTag;
542	return result;
543}
544
545/**
546 * Query TAG length that is suitable for the TAGLEN field (i.e.\
547 * without it's own header size).
548 *
549 * @return Tag length, containing its childs' length.
550 */
551uint32 CECTag::GetTagLen(void) const
552{
553	uint32 length = m_dataLen;
554	for (const_iterator it = begin(); it != end(); it++) {
555		length += it->GetTagLen();
556		length += sizeof(ec_tagname_t) + sizeof(ec_tagtype_t) + sizeof(ec_taglen_t) + (it->HasChildTags() ? 2 : 0);
557	}
558	return length;
559}
560
561
562uint64_t CECTag::GetInt() const
563{
564	if (m_tagData == NULL) {
565		// Empty tag - This is NOT an error.
566		EC_ASSERT(m_dataType == EC_TAGTYPE_UNKNOWN);
567		return 0;
568	}
569
570	switch (m_dataType) {
571		case EC_TAGTYPE_UINT8:
572			return PeekUInt8(m_tagData);
573		case EC_TAGTYPE_UINT16:
574			return ENDIAN_NTOHS( RawPeekUInt16( m_tagData ) );
575		case EC_TAGTYPE_UINT32:
576			return ENDIAN_NTOHL( RawPeekUInt32( m_tagData ) );
577		case EC_TAGTYPE_UINT64:
578			return ENDIAN_NTOHLL( RawPeekUInt64( m_tagData ) );
579		case EC_TAGTYPE_UNKNOWN:
580			// Empty tag - This is NOT an error.
581			return 0;
582		default:
583			EC_ASSERT(0);
584			return 0;
585	}
586}
587
588
589std::string CECTag::GetStringDataSTL() const
590{
591	if (m_dataType != EC_TAGTYPE_STRING) {
592		EC_ASSERT(m_dataType == EC_TAGTYPE_UNKNOWN);
593		return std::string();
594	} else if (m_tagData == NULL) {
595		EC_ASSERT(false);
596		return std::string();
597	}
598
599	return std::string(m_tagData);
600}
601
602
603#ifdef USE_WX_EXTENSIONS
604wxString CECTag::GetStringData() const
605{
606	return UTF82unicode(GetStringDataSTL().c_str());
607}
608#endif
609
610
611CMD4Hash CECTag::GetMD4Data() const
612{
613	if (m_dataType != EC_TAGTYPE_HASH16) {
614		EC_ASSERT(m_dataType == EC_TAGTYPE_UNKNOWN);
615		return CMD4Hash();
616	}
617
618	EC_ASSERT(m_tagData != NULL);
619
620	// Doesn't matter if m_tagData is NULL in CMD4Hash(),
621	// that'll just result in an empty hash.
622	return CMD4Hash((const unsigned char *)m_tagData);
623}
624
625
626/**
627 * Returns an EC_IPv4_t class.
628 *
629 * This function takes care of the endianness of the port number.
630 *
631 * @return EC_IPv4_t class.
632 *
633 * @see CECTag(ec_tagname_t, const EC_IPv4_t&)
634 */
635EC_IPv4_t CECTag::GetIPv4Data() const
636{
637	EC_IPv4_t p(0, 0);
638
639	if (m_dataType != EC_TAGTYPE_IPV4) {
640		EC_ASSERT(m_dataType == EC_TAGTYPE_UNKNOWN);
641	} else if (m_tagData == NULL) {
642		EC_ASSERT(false);
643	} else {
644		RawPokeUInt32( p.m_ip, RawPeekUInt32( ((EC_IPv4_t *)m_tagData)->m_ip ) );
645		p.m_port = ENDIAN_NTOHS(((EC_IPv4_t *)m_tagData)->m_port);
646	}
647
648	return p;
649}
650
651/**
652 * Returns a double value.
653 *
654 * @note The returned value is what we get by converting the string form
655 * of the number to a double.
656 *
657 * @return The double value of the tag.
658 *
659 * @see CECTag(ec_tagname_t, double)
660 */
661double CECTag::GetDoubleData(void) const
662{
663	if (m_dataType != EC_TAGTYPE_DOUBLE) {
664		EC_ASSERT(m_dataType == EC_TAGTYPE_UNKNOWN);
665		return 0;
666	} else if (m_tagData == NULL) {
667		EC_ASSERT(false);
668		return 0;
669	}
670
671	std::istringstream double_str(m_tagData);
672
673	double data;
674	double_str >> data;
675	return data;
676}
677
678
679void CECTag::ConstructStringTag(ec_tagname_t name, const std::string& data)
680{
681	m_tagName = name;
682	m_dataLen = (ec_taglen_t)strlen(data.c_str()) + 1;
683	NewData();
684	memcpy(m_tagData, data.c_str(), m_dataLen);
685	m_dataType = EC_TAGTYPE_STRING;
686}
687
688void CECTag::SetStringData(const wxString& s)
689{
690	if (IsString()) {
691		delete [] m_tagData;
692		ConstructStringTag(m_tagName, (const char*)unicode2UTF8(s));
693	}
694}
695
696
697bool CECTag::AssignIfExist(ec_tagname_t tagname, bool *target) const
698{
699	bool ret = false;
700	const CECTag *tag = GetTagByName(tagname);
701	if (tag) {
702		ret = tag->GetInt() > 0;
703		if (target) {
704			*target = ret;
705		}
706	}
707	return ret;
708}
709
710bool CECTag::AssignIfExist(ec_tagname_t tagname, bool &target) const
711{
712	const CECTag *tag = GetTagByName(tagname);
713	if (tag) {
714		target = tag->GetInt() > 0;
715		return true;
716	}
717	return false;
718}
719
720uint8_t CECTag::AssignIfExist(ec_tagname_t tagname, uint8_t *target) const
721{
722	uint8_t ret = 0;
723	const CECTag *tag = GetTagByName(tagname);
724	if (tag) {
725		EC_ASSERT((tag->GetType() == EC_TAGTYPE_UINT8) || (m_dataType == EC_TAGTYPE_UNKNOWN));
726		ret = tag->GetInt();
727		if (target) {
728			*target = ret;
729		}
730	}
731	return ret;
732}
733
734bool CECTag::AssignIfExist(ec_tagname_t tagname, uint8_t &target) const
735{
736	const CECTag *tag = GetTagByName(tagname);
737	if (tag) {
738		EC_ASSERT((tag->GetType() == EC_TAGTYPE_UINT8) || (m_dataType == EC_TAGTYPE_UNKNOWN));
739		target = tag->GetInt();
740		return true;
741	}
742	return false;
743}
744
745uint16_t CECTag::AssignIfExist(ec_tagname_t tagname, uint16_t *target) const
746{
747	uint16_t ret = 0;
748	const CECTag *tag = GetTagByName(tagname);
749	if (tag) {
750		EC_ASSERT(
751			(tag->GetType() == EC_TAGTYPE_UINT16)
752			|| (tag->GetType() == EC_TAGTYPE_UINT8)
753			|| (m_dataType == EC_TAGTYPE_UNKNOWN)
754		);
755		ret = tag->GetInt();
756		if (target) {
757			*target = ret;
758		}
759	}
760	return ret;
761}
762
763bool CECTag::AssignIfExist(ec_tagname_t tagname, uint16_t &target) const
764{
765	const CECTag *tag = GetTagByName(tagname);
766	if (tag) {
767		EC_ASSERT(
768			(tag->GetType() == EC_TAGTYPE_UINT16)
769			|| (tag->GetType() == EC_TAGTYPE_UINT8)
770			|| (m_dataType == EC_TAGTYPE_UNKNOWN)
771		);
772		target = tag->GetInt();
773		return true;
774	}
775	return false;
776}
777
778uint32_t CECTag::AssignIfExist(ec_tagname_t tagname, uint32_t *target) const
779{
780	uint32_t ret = 0;
781	const CECTag *tag = GetTagByName(tagname);
782	if (tag) {
783		EC_ASSERT(
784			(tag->GetType() == EC_TAGTYPE_UINT32)
785			|| (tag->GetType() == EC_TAGTYPE_UINT16)
786			|| (tag->GetType() == EC_TAGTYPE_UINT8)
787			|| (m_dataType == EC_TAGTYPE_UNKNOWN)
788		);
789		ret = tag->GetInt();
790		if (target) {
791			*target = ret;
792		}
793	}
794	return ret;
795}
796
797bool CECTag::AssignIfExist(ec_tagname_t tagname, uint32_t &target) const
798{
799	const CECTag *tag = GetTagByName(tagname);
800	if (tag) {
801		EC_ASSERT(
802			(tag->GetType() == EC_TAGTYPE_UINT32)
803			|| (tag->GetType() == EC_TAGTYPE_UINT16)
804			|| (tag->GetType() == EC_TAGTYPE_UINT8)
805			|| (m_dataType == EC_TAGTYPE_UNKNOWN)
806		);
807		target = tag->GetInt();
808		return true;
809	}
810	return false;
811}
812
813uint64_t CECTag::AssignIfExist(ec_tagname_t tagname, uint64_t *target) const
814{
815	uint64_t ret = 0;
816	const CECTag *tag = GetTagByName(tagname);
817	if (tag) {
818		ret = tag->GetInt();
819		if (target) {
820			*target = ret;
821		}
822	}
823	return ret;
824}
825
826bool CECTag::AssignIfExist(ec_tagname_t tagname, uint64_t &target) const
827{
828	const CECTag *tag = GetTagByName(tagname);
829	if (tag) {
830		target = tag->GetInt();
831		return true;
832	}
833	return false;
834}
835
836time_t CECTag::AssignIfExist(ec_tagname_t tagname, time_t *target) const
837{
838	time_t ret = 0;
839	const CECTag *tag = GetTagByName(tagname);
840	if (tag) {
841		ret = tag->GetInt();
842		if (target) {
843			*target = ret;
844		}
845	}
846	return ret;
847}
848
849bool CECTag::AssignIfExist(ec_tagname_t tagname, time_t &target) const
850{
851	const CECTag *tag = GetTagByName(tagname);
852	if (tag) {
853		target = tag->GetInt();
854		return true;
855	}
856	return false;
857}
858
859double CECTag::AssignIfExist(ec_tagname_t tagname, double *target) const
860{
861	double ret = 0.0;
862	const CECTag *tag = GetTagByName(tagname);
863	if (tag) {
864		ret = tag->GetDoubleData();
865		if (target) {
866			*target = ret;
867		}
868	}
869	return ret;
870}
871
872bool CECTag::AssignIfExist(ec_tagname_t tagname, double &target) const
873{
874	const CECTag *tag = GetTagByName(tagname);
875	if (tag) {
876		target = tag->GetDoubleData();
877		return true;
878	}
879	return false;
880}
881
882float CECTag::AssignIfExist(ec_tagname_t tagname, float *target) const
883{
884	float ret = 0.0;
885	const CECTag *tag = GetTagByName(tagname);
886	if (tag) {
887		ret = tag->GetDoubleData();
888		if (target) {
889			*target = ret;
890		}
891	}
892	return ret;
893}
894
895bool CECTag::AssignIfExist(ec_tagname_t tagname, float &target) const
896{
897	const CECTag *tag = GetTagByName(tagname);
898	if (tag) {
899		target = tag->GetDoubleData();
900		return true;
901	}
902	return false;
903}
904
905CMD4Hash CECTag::AssignIfExist(ec_tagname_t tagname, CMD4Hash *target) const
906{
907	CMD4Hash ret;
908	const CECTag *tag = GetTagByName(tagname);
909	if (tag) {
910		ret = tag->GetMD4Data();
911		if (target) {
912			*target = ret;
913		}
914	}
915	return ret;
916}
917
918bool CECTag::AssignIfExist(ec_tagname_t tagname, CMD4Hash &target) const
919{
920	const CECTag *tag = GetTagByName(tagname);
921	if (tag) {
922		target = tag->GetMD4Data();
923		return true;
924	}
925	return false;
926}
927
928std::string CECTag::AssignIfExist(ec_tagname_t tagname, std::string *target) const
929{
930	std::string ret;
931	const CECTag *tag = GetTagByName(tagname);
932	if (tag) {
933		ret = tag->GetStringDataSTL();
934		if (target) {
935			*target = ret;
936		}
937	}
938	return ret;
939}
940
941bool CECTag::AssignIfExist(ec_tagname_t tagname, std::string &target) const
942{
943	const CECTag *tag = GetTagByName(tagname);
944	if (tag) {
945		target = tag->GetStringDataSTL();
946		return true;
947	}
948	return false;
949}
950
951#ifdef USE_WX_EXTENSIONS
952wxString CECTag::AssignIfExist(ec_tagname_t tagname, wxString *target) const
953{
954	wxString ret;
955	const CECTag *tag = GetTagByName(tagname);
956	if (tag) {
957		ret = tag->GetStringData();
958		if (target) {
959			*target = ret;
960		}
961	}
962	return ret;
963}
964
965bool CECTag::AssignIfExist(ec_tagname_t tagname, wxString &target) const
966{
967	const CECTag *tag = GetTagByName(tagname);
968	if (tag) {
969		target = tag->GetStringData();
970		return true;
971	}
972	return false;
973}
974#endif
975
976
977#ifdef	__DEBUG__
978void CECTag::DebugPrint(int level, bool print_empty) const
979{
980	if (m_dataLen || print_empty) {
981		wxString space;
982		for (int i = level; i--;) space += wxT("  ");
983		wxString s1 = CFormat(wxT("%s%s %d = ")) % space % GetDebugNameECTagNames(m_tagName) % m_dataLen;
984		wxString s2;
985		switch (m_tagName) {
986			case EC_TAG_DETAIL_LEVEL:
987				s2 = GetDebugNameEC_DETAIL_LEVEL(GetInt()); break;
988			case EC_TAG_SEARCH_TYPE:
989				s2 = GetDebugNameEC_SEARCH_TYPE(GetInt()); break;
990			case EC_TAG_STAT_VALUE_TYPE:
991				s2 = GetDebugNameEC_STATTREE_NODE_VALUE_TYPE(GetInt()); break;
992			default:
993				switch (m_dataType) {
994					case EC_TAGTYPE_UINT8:
995					case EC_TAGTYPE_UINT16:
996					case EC_TAGTYPE_UINT32:
997					case EC_TAGTYPE_UINT64:
998						s2 = CFormat(wxT("%d")) % GetInt(); break;
999					case EC_TAGTYPE_STRING:
1000						s2 = GetStringData(); break;
1001					case EC_TAGTYPE_DOUBLE:
1002						s2 = CFormat(wxT("%.1f")) % GetDoubleData(); break;
1003					case EC_TAGTYPE_HASH16:
1004						s2 = GetMD4Data().Encode(); break;
1005					case EC_TAGTYPE_CUSTOM:
1006						if (m_dataLen == 0) {
1007							s2 = wxT("empty");
1008						} else {
1009							// Make a hex dump (limited to maxOutput)
1010							const uint32 maxOutput = 50;
1011							for (uint32 i = 0; i < m_dataLen; i++) {
1012								if (i == maxOutput) {
1013									s2 += wxT("...");
1014									break;
1015								}
1016								s2 += CFormat(wxT("%02X ")) % (unsigned char) m_tagData[i];
1017							}
1018						}
1019						break;
1020					default:
1021						s2 = GetDebugNameECTagTypes(m_dataType);
1022				}
1023		}
1024		DoECLogLine(s1 + s2);
1025	}
1026	for (TagList::const_iterator it = m_tagList.begin(); it != m_tagList.end(); ++it) {
1027		it->DebugPrint(level + 1, true);
1028	}
1029}
1030#endif
1031
1032/*!
1033 * \fn CMD4Hash CECTag::GetMD4Data(void) const
1034 *
1035 * \brief Returns a CMD4Hash class.
1036 *
1037 * This function takes care of converting from MSB to LSB as necessary.
1038 *
1039 * \return CMD4Hash class.
1040 *
1041 * \sa CECTag(ec_tagname_t, const CMD4Hash&)
1042 */
1043
1044/*!
1045 * \fn CECTag *CECTag::GetTagByIndex(size_t index) const
1046 *
1047 * \brief Finds the indexth child tag.
1048 *
1049 * \param index 0-based index, 0 <= \e index < GetTagCount()
1050 *
1051 * \return The child tag, or NULL if index out of range.
1052 */
1053
1054/*!
1055 * \fn CECTag *CECTag::GetTagByIndexSafe(size_t index) const
1056 *
1057 * \brief Finds the indexth child tag.
1058 *
1059 * \param index 0-based index, 0 <= \e index < GetTagCount()
1060 *
1061 * \return The child tag, or a special null-valued tag if index out of range.
1062 */
1063
1064/*!
1065 * \fn size_t CECTag::GetTagCount(void) const
1066 *
1067 * \brief Returns the number of child tags.
1068 *
1069 * \return The number of child tags.
1070 */
1071
1072/*!
1073 * \fn const void *CECTag::GetTagData(void) const
1074 *
1075 * \brief Returns a pointer to the TAG DATA.
1076 *
1077 * \return A pointer to the TAG DATA. (As specified with the data field of the constructor.)
1078*/
1079
1080/*!
1081 * \fn uint16 CECTag::GetTagDataLen(void) const
1082 *
1083 * \brief Returns the length of the data buffer.
1084 *
1085 * \return The length of the data buffer.
1086 */
1087
1088/*!
1089 * \fn ec_tagname_t CECTag::GetTagName(void) const
1090 *
1091 * \brief Returns TAGNAME.
1092 *
1093 * \return The name of the tag.
1094 */
1095
1096/*!
1097 * \fn wxString CECTag::GetStringData(void) const
1098 *
1099 * \brief Returns the string data of the tag.
1100 *
1101 * Returns a wxString created from TAGDATA. It is automatically
1102 * converted from UTF-8 to the internal application encoding.
1103 * Should be used with care (only on tags created with the
1104 * CECTag(ec_tagname_t, const wxString&) constructor),
1105 * becuse it does not perform any check to see if the tag really contains a
1106 * string object.
1107 *
1108 * \return The string data of the tag.
1109 *
1110 * \sa CECTag(ec_tagname_t, const wxString&)
1111 */
1112
1113/*!
1114 * \fn uint8 CECTag::GetInt(void) const
1115 *
1116 * \brief Returns the uint8 data of the tag.
1117 *
1118 * This function takes care of the endianness problems with numbers.
1119 *
1120 * \return The uint8 data of the tag.
1121 *
1122 * \sa CECTag(ec_tagname_t, uint8)
1123 */
1124
1125/*!
1126 * \fn uint16 CECTag::GetInt(void) const
1127 *
1128 * \brief Returns the uint16 data of the tag.
1129 *
1130 * This function takes care of the endianness problems with numbers.
1131 *
1132 * \return The uint16 data of the tag.
1133 *
1134 * \sa CECTag(ec_tagname_t, uint16)
1135 */
1136
1137/*!
1138 * \fn uint32 CECTag::GetInt(void) const
1139 *
1140 * \brief Returns the uint32 data of the tag.
1141 *
1142 * This function takes care of the endianness problems with numbers.
1143 *
1144 * \return The uint32 data of the tag.
1145 *
1146 * \sa CECTag(ec_tagname_t, uint32)
1147 */
1148
1149/*!
1150 * \fn uint64 CECTag::GetInt(void) const
1151 *
1152 * \brief Returns the uint64 data of the tag.
1153 *
1154 * This function takes care of the endianness problems with numbers.
1155 *
1156 * \return The uint64 data of the tag.
1157 *
1158 * \sa CECTag(ec_tagname_t, uint64)
1159 */
1160
1161uint32 CECID::s_IDCounter = 0;
1162
1163// File_checked_for_headers
1164