Fixed some build warnings in release mode
[amule.git] / src / libs / ec / cpp / ECTag.cpp
blob225d250f87f8f19530b9990e3993dffd04a107ce
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.
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
25 #ifdef __DEBUG__
26 #define DEBUG_EC_IMPLEMENTATION
28 #include <common/Format.h> // Needed for CFormat
29 #endif
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
36 /**********************************************************
37 * *
38 * CECTag class *
39 * *
40 **********************************************************/
42 //! Defines the Null tag which may be returned by GetTagByNameSafe.
43 const CECTag CECTag::s_theNullTag;
45 /**
46 * Creates a new null-valued CECTag instance
48 * @see s_theNullTag
49 * @see GetTagByNameSafe
51 CECTag::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.
59 /**
60 * Creates a new CECTag instance from the given data
62 * @param name TAG name
63 * @param length length of data buffer
64 * @param data TAG data
67 CECTag::CECTag(ec_tagname_t name, unsigned int length, const void *data) : m_tagName(name)
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;
78 m_dataType = EC_TAGTYPE_CUSTOM;
81 /**
82 * Creates a new CECTag instance for custom data
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
88 * \note TAG data buffer has to be filled with valid data after the ctor
90 CECTag::CECTag(ec_tagname_t name, unsigned int length, void **dataptr) : m_tagName(name)
92 m_dataLen = length;
93 NewData();
94 *dataptr = m_tagData;
95 m_dataType = EC_TAGTYPE_CUSTOM;
98 /**
99 * Creates a new CECTag instance, which contains an IPv4 address.
101 * This function takes care of the endianness of the port number.
103 * @param name TAG name
104 * @param data The EC_IPv4_t class containing the IPv4 address.
106 * @see GetIPv4Data()
108 CECTag::CECTag(ec_tagname_t name, const EC_IPv4_t& data) : m_tagName(name)
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;
119 * Creates a new CECTag instance, which contains a MD4 hash.
121 * This function takes care to store hash in network byte order.
123 * @param name TAG name
124 * @param data The CMD4Hash class containing the MD4 hash.
126 * @see GetMD4Data()
128 CECTag::CECTag(ec_tagname_t name, const CMD4Hash& data) : m_tagName(name)
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;
138 * Creates a new CECTag instance, which contains a string
140 * @param name TAG name
141 * @param data wxString object, it's contents are converted to UTF-8.
143 * @see GetStringDataSTL()
145 CECTag::CECTag(ec_tagname_t name, const std::string& data) : m_tagName(name)
147 ConstructStringTag(name, data);
151 * Creates a new CECTag instance, which contains a string
153 * @param name TAG name
154 * @param data wxString object, it's contents are converted to UTF-8.
156 * @see GetStringData()
158 CECTag::CECTag(ec_tagname_t name, const wxString& data)
160 ConstructStringTag(name, (const char*)unicode2UTF8(data));
162 CECTag::CECTag(ec_tagname_t name, const wxChar* data)
164 ConstructStringTag(name, (const char*)unicode2UTF8(data));
168 * Copy constructor
170 CECTag::CECTag(const CECTag& tag)
172 m_tagData = NULL;
173 *this = tag;
177 * Creates a new CECTag instance, which contains an int value.
179 * This takes care of endianness problems with numbers.
181 * @param name TAG name.
182 * @param data number.
184 * @see GetInt()
186 CECTag::CECTag(ec_tagname_t name, bool data) : m_tagName(name)
188 InitInt(data);
190 CECTag::CECTag(ec_tagname_t name, uint8 data) : m_tagName(name)
192 InitInt(data);
194 CECTag::CECTag(ec_tagname_t name, uint16 data) : m_tagName(name)
196 InitInt(data);
198 CECTag::CECTag(ec_tagname_t name, uint32 data) : m_tagName(name)
200 InitInt(data);
202 CECTag::CECTag(ec_tagname_t name, uint64 data) : m_tagName(name)
204 InitInt(data);
207 void CECTag::InitInt(uint64 data)
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;
223 NewData();
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;
242 * Creates a new CECTag instance, which contains a double precision floating point number
244 * @param name TAG name
245 * @param data double number
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.
250 * @see GetDoubleData()
252 CECTag::CECTag(ec_tagname_t name, double data) : m_tagName(name)
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;
265 * Destructor - frees allocated data and deletes child TAGs.
267 CECTag::~CECTag(void)
269 delete [] m_tagData;
273 * Copy assignment operator.
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!).
279 CECTag& CECTag::operator=(const CECTag& tag)
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;
292 m_tagList.clear();
293 for (const_iterator it = tag.begin(); it != tag.end(); it++) {
294 m_tagList.push_back(*it);
297 return *this;
301 * Compare operator.
304 bool CECTag::operator==(const CECTag& tag) const
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;
315 * Add a child tag to this one. The tag argument is reset to an empty tag.
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
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 !!!
327 * \endcode
329 * To get the desired results, the above should be replaced with something like:
331 * \code
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
341 * \endcode
343 * Then why copying? The answer is to enable simplifying the code like this:
345 * \code
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
352 * \endcode
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.
358 bool CECTag::AddTag(const CECTag& tag, CValueMap* valuemap)
360 if (valuemap) {
361 return valuemap->AddTag(tag, this);
363 // cannot have more than 64k tags
364 wxASSERT(m_tagList.size() < 0xffff);
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;
376 void CECTag::AddTag(ec_tagname_t name, uint64_t data, CValueMap* valuemap)
378 if (valuemap) {
379 valuemap->CreateTag(name, data, this);
380 } else {
381 AddTag(CECTag(name, data));
385 void CECTag::AddTag(ec_tagname_t name, const wxString& data, CValueMap* valuemap)
387 if (valuemap) {
388 valuemap->CreateTag(name, data, this);
389 } else {
390 AddTag(CECTag(name, data));
394 void CECTag::AddTag(ec_tagname_t name, const CMD4Hash& data, CValueMap* valuemap)
396 if (valuemap) {
397 valuemap->CreateTag(name, data, this);
398 } else {
399 AddTag(CECTag(name, data));
403 void CECTag::swap(CECTag& t2)
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);
412 bool CECTag::ReadFromSocket(CECSocket& socket)
414 ec_tagname_t tmp_tagName;
415 if (!socket.ReadNumber(&tmp_tagName, sizeof(ec_tagname_t))) {
416 return false;
418 m_tagName = tmp_tagName >> 1;
419 bool hasChildren = (tmp_tagName & 0x01) != 0;
421 if (!socket.ReadNumber(&m_dataType, sizeof(ec_tagtype_t))) {
422 return false;
425 if (!socket.ReadNumber(&m_dataLen, sizeof(ec_taglen_t))) {
426 return false;
429 if (hasChildren && !ReadChildren(socket)) {
430 return false;
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;
441 } else {
442 m_tagData = NULL;
445 return true;
449 bool CECTag::WriteTag(CECSocket& socket) const
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);
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;
460 if (!m_tagList.empty()) {
461 if (!WriteChildren(socket)) return false;
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;
470 return true;
473 bool CECTag::ReadChildren(CECSocket& socket)
475 uint16 tmp_tagCount;
476 if (!socket.ReadNumber(&tmp_tagCount, sizeof(uint16))) {
477 return false;
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;
487 return true;
490 bool CECTag::WriteChildren(CECSocket& socket) const
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;
498 return true;
502 * Finds the (first) child tag with given name.
504 * @param name TAG name to look for.
505 * @return the tag found, or NULL.
507 const CECTag* CECTag::GetTagByName(ec_tagname_t name) const
509 for (const_iterator it = begin(); it != end(); it++) {
510 if (it->m_tagName == name) return & *it;
512 return NULL;
516 * Finds the (first) child tag with given name.
518 * @param name TAG name to look for.
519 * @return the tag found, or NULL.
521 CECTag* CECTag::GetTagByName(ec_tagname_t name)
523 for (TagList::iterator it = m_tagList.begin(); it != m_tagList.end(); it++) {
524 if (it->m_tagName == name) return & *it;
526 return NULL;
530 * Finds the (first) child tag with given name.
532 * @param name TAG name to look for.
533 * @return the tag found, or a special null-valued tag otherwise.
535 * @see s_theNullTag
537 const CECTag* CECTag::GetTagByNameSafe(ec_tagname_t name) const
539 const CECTag* result = GetTagByName(name);
540 if (result == NULL)
541 result = &s_theNullTag;
542 return result;
546 * Query TAG length that is suitable for the TAGLEN field (i.e.\
547 * without it's own header size).
549 * @return Tag length, containing its childs' length.
551 uint32 CECTag::GetTagLen(void) const
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);
558 return length;
562 uint64_t CECTag::GetInt() const
564 if (m_tagData == NULL) {
565 // Empty tag - This is NOT an error.
566 EC_ASSERT(m_dataType == EC_TAGTYPE_UNKNOWN);
567 return 0;
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;
589 std::string CECTag::GetStringDataSTL() const
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();
599 return std::string(m_tagData);
603 #ifdef USE_WX_EXTENSIONS
604 wxString CECTag::GetStringData() const
606 return UTF82unicode(GetStringDataSTL().c_str());
608 #endif
611 CMD4Hash CECTag::GetMD4Data() const
613 if (m_dataType != EC_TAGTYPE_HASH16) {
614 EC_ASSERT(m_dataType == EC_TAGTYPE_UNKNOWN);
615 return CMD4Hash();
618 EC_ASSERT(m_tagData != NULL);
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);
627 * Returns an EC_IPv4_t class.
629 * This function takes care of the endianness of the port number.
631 * @return EC_IPv4_t class.
633 * @see CECTag(ec_tagname_t, const EC_IPv4_t&)
635 EC_IPv4_t CECTag::GetIPv4Data() const
637 EC_IPv4_t p(0, 0);
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);
648 return p;
652 * Returns a double value.
654 * @note The returned value is what we get by converting the string form
655 * of the number to a double.
657 * @return The double value of the tag.
659 * @see CECTag(ec_tagname_t, double)
661 double CECTag::GetDoubleData(void) const
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;
671 std::istringstream double_str(m_tagData);
673 double data;
674 double_str >> data;
675 return data;
679 void CECTag::ConstructStringTag(ec_tagname_t name, const std::string& data)
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;
688 void CECTag::SetStringData(const wxString& s)
690 if (IsString()) {
691 delete [] m_tagData;
692 ConstructStringTag(m_tagName, (const char*)unicode2UTF8(s));
697 bool CECTag::AssignIfExist(ec_tagname_t tagname, bool *target) const
699 bool ret = false;
700 const CECTag *tag = GetTagByName(tagname);
701 if (tag) {
702 ret = tag->GetInt() > 0;
703 if (target) {
704 *target = ret;
707 return ret;
710 bool CECTag::AssignIfExist(ec_tagname_t tagname, bool &target) const
712 const CECTag *tag = GetTagByName(tagname);
713 if (tag) {
714 target = tag->GetInt() > 0;
715 return true;
717 return false;
720 uint8_t CECTag::AssignIfExist(ec_tagname_t tagname, uint8_t *target) const
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;
731 return ret;
734 bool CECTag::AssignIfExist(ec_tagname_t tagname, uint8_t &target) const
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;
742 return false;
745 uint16_t CECTag::AssignIfExist(ec_tagname_t tagname, uint16_t *target) const
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)
755 ret = tag->GetInt();
756 if (target) {
757 *target = ret;
760 return ret;
763 bool CECTag::AssignIfExist(ec_tagname_t tagname, uint16_t &target) const
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)
772 target = tag->GetInt();
773 return true;
775 return false;
778 uint32_t CECTag::AssignIfExist(ec_tagname_t tagname, uint32_t *target) const
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)
789 ret = tag->GetInt();
790 if (target) {
791 *target = ret;
794 return ret;
797 bool CECTag::AssignIfExist(ec_tagname_t tagname, uint32_t &target) const
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)
807 target = tag->GetInt();
808 return true;
810 return false;
813 uint64_t CECTag::AssignIfExist(ec_tagname_t tagname, uint64_t *target) const
815 uint64_t ret = 0;
816 const CECTag *tag = GetTagByName(tagname);
817 if (tag) {
818 ret = tag->GetInt();
819 if (target) {
820 *target = ret;
823 return ret;
826 bool CECTag::AssignIfExist(ec_tagname_t tagname, uint64_t &target) const
828 const CECTag *tag = GetTagByName(tagname);
829 if (tag) {
830 target = tag->GetInt();
831 return true;
833 return false;
836 time_t CECTag::AssignIfExist(ec_tagname_t tagname, time_t *target) const
838 time_t ret = 0;
839 const CECTag *tag = GetTagByName(tagname);
840 if (tag) {
841 ret = tag->GetInt();
842 if (target) {
843 *target = ret;
846 return ret;
849 bool CECTag::AssignIfExist(ec_tagname_t tagname, time_t &target) const
851 const CECTag *tag = GetTagByName(tagname);
852 if (tag) {
853 target = tag->GetInt();
854 return true;
856 return false;
859 double CECTag::AssignIfExist(ec_tagname_t tagname, double *target) const
861 double ret = 0.0;
862 const CECTag *tag = GetTagByName(tagname);
863 if (tag) {
864 ret = tag->GetDoubleData();
865 if (target) {
866 *target = ret;
869 return ret;
872 bool CECTag::AssignIfExist(ec_tagname_t tagname, double &target) const
874 const CECTag *tag = GetTagByName(tagname);
875 if (tag) {
876 target = tag->GetDoubleData();
877 return true;
879 return false;
882 float CECTag::AssignIfExist(ec_tagname_t tagname, float *target) const
884 float ret = 0.0;
885 const CECTag *tag = GetTagByName(tagname);
886 if (tag) {
887 ret = tag->GetDoubleData();
888 if (target) {
889 *target = ret;
892 return ret;
895 bool CECTag::AssignIfExist(ec_tagname_t tagname, float &target) const
897 const CECTag *tag = GetTagByName(tagname);
898 if (tag) {
899 target = tag->GetDoubleData();
900 return true;
902 return false;
905 CMD4Hash CECTag::AssignIfExist(ec_tagname_t tagname, CMD4Hash *target) const
907 CMD4Hash ret;
908 const CECTag *tag = GetTagByName(tagname);
909 if (tag) {
910 ret = tag->GetMD4Data();
911 if (target) {
912 *target = ret;
915 return ret;
918 bool CECTag::AssignIfExist(ec_tagname_t tagname, CMD4Hash &target) const
920 const CECTag *tag = GetTagByName(tagname);
921 if (tag) {
922 target = tag->GetMD4Data();
923 return true;
925 return false;
928 std::string CECTag::AssignIfExist(ec_tagname_t tagname, std::string *target) const
930 std::string ret;
931 const CECTag *tag = GetTagByName(tagname);
932 if (tag) {
933 ret = tag->GetStringDataSTL();
934 if (target) {
935 *target = ret;
938 return ret;
941 bool CECTag::AssignIfExist(ec_tagname_t tagname, std::string &target) const
943 const CECTag *tag = GetTagByName(tagname);
944 if (tag) {
945 target = tag->GetStringDataSTL();
946 return true;
948 return false;
951 #ifdef USE_WX_EXTENSIONS
952 wxString CECTag::AssignIfExist(ec_tagname_t tagname, wxString *target) const
954 wxString ret;
955 const CECTag *tag = GetTagByName(tagname);
956 if (tag) {
957 ret = tag->GetStringData();
958 if (target) {
959 *target = ret;
962 return ret;
965 bool CECTag::AssignIfExist(ec_tagname_t tagname, wxString &target) const
967 const CECTag *tag = GetTagByName(tagname);
968 if (tag) {
969 target = tag->GetStringData();
970 return true;
972 return false;
974 #endif
977 #ifdef __DEBUG__
978 void CECTag::DebugPrint(int level, bool print_empty) const
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;
1016 s2 += CFormat(wxT("%02X ")) % (unsigned char) m_tagData[i];
1019 break;
1020 default:
1021 s2 = GetDebugNameECTagTypes(m_dataType);
1024 DoECLogLine(s1 + s2);
1026 for (TagList::const_iterator it = m_tagList.begin(); it != m_tagList.end(); ++it) {
1027 it->DebugPrint(level + 1, true);
1030 #endif
1033 * \fn CMD4Hash CECTag::GetMD4Data(void) const
1035 * \brief Returns a CMD4Hash class.
1037 * This function takes care of converting from MSB to LSB as necessary.
1039 * \return CMD4Hash class.
1041 * \sa CECTag(ec_tagname_t, const CMD4Hash&)
1045 * \fn CECTag *CECTag::GetTagByIndex(size_t index) const
1047 * \brief Finds the indexth child tag.
1049 * \param index 0-based index, 0 <= \e index < GetTagCount()
1051 * \return The child tag, or NULL if index out of range.
1055 * \fn CECTag *CECTag::GetTagByIndexSafe(size_t index) const
1057 * \brief Finds the indexth child tag.
1059 * \param index 0-based index, 0 <= \e index < GetTagCount()
1061 * \return The child tag, or a special null-valued tag if index out of range.
1065 * \fn size_t CECTag::GetTagCount(void) const
1067 * \brief Returns the number of child tags.
1069 * \return The number of child tags.
1073 * \fn const void *CECTag::GetTagData(void) const
1075 * \brief Returns a pointer to the TAG DATA.
1077 * \return A pointer to the TAG DATA. (As specified with the data field of the constructor.)
1081 * \fn uint16 CECTag::GetTagDataLen(void) const
1083 * \brief Returns the length of the data buffer.
1085 * \return The length of the data buffer.
1089 * \fn ec_tagname_t CECTag::GetTagName(void) const
1091 * \brief Returns TAGNAME.
1093 * \return The name of the tag.
1097 * \fn wxString CECTag::GetStringData(void) const
1099 * \brief Returns the string data of the tag.
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.
1108 * \return The string data of the tag.
1110 * \sa CECTag(ec_tagname_t, const wxString&)
1114 * \fn uint8 CECTag::GetInt(void) const
1116 * \brief Returns the uint8 data of the tag.
1118 * This function takes care of the endianness problems with numbers.
1120 * \return The uint8 data of the tag.
1122 * \sa CECTag(ec_tagname_t, uint8)
1126 * \fn uint16 CECTag::GetInt(void) const
1128 * \brief Returns the uint16 data of the tag.
1130 * This function takes care of the endianness problems with numbers.
1132 * \return The uint16 data of the tag.
1134 * \sa CECTag(ec_tagname_t, uint16)
1138 * \fn uint32 CECTag::GetInt(void) const
1140 * \brief Returns the uint32 data of the tag.
1142 * This function takes care of the endianness problems with numbers.
1144 * \return The uint32 data of the tag.
1146 * \sa CECTag(ec_tagname_t, uint32)
1150 * \fn uint64 CECTag::GetInt(void) const
1152 * \brief Returns the uint64 data of the tag.
1154 * This function takes care of the endianness problems with numbers.
1156 * \return The uint64 data of the tag.
1158 * \sa CECTag(ec_tagname_t, uint64)
1161 uint32 CECID::s_IDCounter = 0;
1163 // File_checked_for_headers