Upstream tarball 9963
[amule.git] / src / libs / ec / cpp / ECTag.cpp
blob2176a1518b956cd4e5ebd1a05d5575d1a1ee17b8
1 //
2 // This file is part of the aMule Project.
3 //
4 // Copyright (c) 2004-2008 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
35 /**********************************************************
36 * *
37 * CECTag class *
38 * *
39 **********************************************************/
41 //! Defines the Null tag which may be returned by GetTagByNameSafe.
42 const CECTag CECTag::s_theNullTag;
44 //! Defines the data for the Null tag. Large enough (16 bytes) for GetMD4Data.
45 const uint32 CECTag::s_theNullTagData[4] = { 0, 0, 0, 0 };
47 /**
48 * Creates a new null-valued CECTag instance
50 * @see s_theNullTag
51 * @see s_theNullTagData
52 * @see GetTagByNameSafe
54 CECTag::CECTag() :
55 m_error(0),
56 m_tagData(s_theNullTagData),
57 m_tagName(0),
58 m_dataLen(0),
59 m_dataType(EC_TAGTYPE_UNKNOWN),
60 m_dynamic(false),
61 m_tagList(),
62 m_haschildren(false)
66 /**
67 * Creates a new CECTag instance from the given data
69 * @param name TAG name
70 * @param length length of data buffer
71 * @param data TAG data
72 * @param copy whether to create a copy of the TAG data at \e *data, or should use the provided pointer.
74 * \note When you set \e copy to \b false, the provided data buffer must exist
75 * in the whole lifetime of the packet.
77 CECTag::CECTag(ec_tagname_t name, unsigned int length, const void *data, bool copy) : m_tagName(name), m_dynamic(copy), m_haschildren( false )
79 m_error = 0;
80 m_dataLen = length;
81 if (copy && (data != NULL)) {
82 m_tagData = malloc(m_dataLen);
83 if (m_tagData != NULL) {
84 memcpy((void *)m_tagData, data, m_dataLen);
85 } else {
86 m_dataLen = 0;
87 m_error = 1;
89 } else {
90 m_tagData = data;
92 m_dataType = EC_TAGTYPE_CUSTOM;
95 /**
96 * Creates a new CECTag instance for custom data
98 * @param name TAG name
99 * @param length length of data buffer that will be alloc'ed
100 * @param dataptr pointer to internal TAG data buffer
104 CECTag::CECTag(ec_tagname_t name, unsigned int length, void **dataptr) : m_tagName(name), m_dynamic(true), m_haschildren( false )
106 m_error = 0;
107 m_dataLen = length;
108 m_tagData = malloc(m_dataLen);
109 if ( !m_tagData ) {
110 m_dataLen = 0;
111 m_error = 1;
113 *dataptr = (void *)m_tagData;
114 m_dataType = EC_TAGTYPE_CUSTOM;
118 * Creates a new CECTag instance, which contains an IPv4 address.
120 * This function takes care of the endianness of the port number.
122 * @param name TAG name
123 * @param data The EC_IPv4_t class containing the IPv4 address.
125 * @see GetIPv4Data()
127 CECTag::CECTag(ec_tagname_t name, const EC_IPv4_t& data) : m_tagName(name), m_dynamic(true), m_haschildren( false )
130 m_dataLen = sizeof(EC_IPv4_t);
131 m_tagData = malloc(sizeof(EC_IPv4_t));
132 if (m_tagData != NULL) {
133 RawPokeUInt32( ((EC_IPv4_t *)m_tagData)->m_ip, RawPeekUInt32( data.m_ip ) );
134 ((EC_IPv4_t *)m_tagData)->m_port = ENDIAN_HTONS(data.m_port);
135 m_error = 0;
136 m_dataType = EC_TAGTYPE_IPV4;
137 } else {
138 m_error = 1;
143 * Creates a new CECTag instance, which contains a MD4 hash.
145 * This function takes care to store hash in network byte order.
147 * @param name TAG name
148 * @param data The CMD4Hash class containing the MD4 hash.
150 * @see GetMD4Data()
152 CECTag::CECTag(ec_tagname_t name, const CMD4Hash& data) : m_tagName(name), m_dynamic(true), m_haschildren( false )
155 m_dataLen = 16;
156 m_tagData = malloc(16);
157 if (m_tagData != NULL) {
158 RawPokeUInt64( (char*)m_tagData, RawPeekUInt64( data.GetHash() ) );
159 RawPokeUInt64( (char*)m_tagData + 8, RawPeekUInt64( data.GetHash() + 8 ) );
160 m_error = 0;
161 m_dataType = EC_TAGTYPE_HASH16;
162 } else {
163 m_error = 1;
168 * Creates a new CECTag instance, which contains a string
170 * @param name TAG name
171 * @param data wxString object, it's contents are converted to UTF-8.
173 * @see GetStringDataSTL()
175 CECTag::CECTag(ec_tagname_t name, const std::string& data) : m_tagName(name), m_dynamic(true), m_haschildren( false )
177 ConstructStringTag(name,data);
181 * Creates a new CECTag instance, which contains a string
183 * @param name TAG name
184 * @param data wxString object, it's contents are converted to UTF-8.
186 * @see GetStringData()
188 CECTag::CECTag(ec_tagname_t name, const wxString& data) : m_tagName(name), m_dynamic(true), m_haschildren( false )
190 ConstructStringTag(name, (const char*)unicode2UTF8(data));
192 CECTag::CECTag(ec_tagname_t name, const wxChar* data) : m_tagName(name), m_dynamic(true), m_haschildren( false )
194 ConstructStringTag(name, (const char*)unicode2UTF8(data));
198 * Copy constructor
200 CECTag::CECTag(const CECTag& tag)
202 *this = tag;
206 * Creates a new CECTag instance, which contains an int value.
208 * This takes care of endianness problems with numbers.
210 * @param name TAG name.
211 * @param data number.
213 * @see GetInt()
215 CECTag::CECTag(ec_tagname_t name, bool data) : m_tagName(name), m_dynamic(true)
217 InitInt(data);
219 CECTag::CECTag(ec_tagname_t name, uint8 data) : m_tagName(name), m_dynamic(true)
221 InitInt(data);
223 CECTag::CECTag(ec_tagname_t name, uint16 data) : m_tagName(name), m_dynamic(true)
225 InitInt(data);
227 CECTag::CECTag(ec_tagname_t name, uint32 data) : m_tagName(name), m_dynamic(true)
229 InitInt(data);
231 CECTag::CECTag(ec_tagname_t name, uint64 data) : m_tagName(name), m_dynamic(true)
233 InitInt(data);
236 void CECTag::InitInt(uint64 data)
238 if (data <= 0xFF) {
239 m_dataType = EC_TAGTYPE_UINT8;
240 m_dataLen = 1;
241 } else if (data <= 0xFFFF) {
242 m_dataType = EC_TAGTYPE_UINT16;
243 m_dataLen = 2;
244 } else if (data <= 0xFFFFFFFF) {
245 m_dataType = EC_TAGTYPE_UINT32;
246 m_dataLen = 4;
247 } else {
248 m_dataType = EC_TAGTYPE_UINT64;
249 m_dataLen = 8;
252 m_tagData = malloc(m_dataLen);
254 if (m_tagData != NULL) {
255 switch (m_dataType) {
256 case EC_TAGTYPE_UINT8:
257 PokeUInt8( (void*)m_tagData, (uint8) data );
258 break;
259 case EC_TAGTYPE_UINT16:
260 PokeUInt16( (void*)m_tagData, wxUINT16_SWAP_ALWAYS((uint16) data ));
261 break;
262 case EC_TAGTYPE_UINT32:
263 PokeUInt32( (void*)m_tagData, wxUINT32_SWAP_ALWAYS((uint32) data ));
264 break;
265 case EC_TAGTYPE_UINT64:
266 PokeUInt64( (void*)m_tagData, wxUINT64_SWAP_ALWAYS(data) );
267 break;
268 default:
269 /* WTF?*/
270 EC_ASSERT(0);
271 free((void*)m_tagData);
272 m_error = 1;
273 return;
275 m_error = 0;
276 } else {
277 m_error = 1;
282 * Creates a new CECTag instance, which contains a double precision floating point number
284 * @param name TAG name
285 * @param data double number
287 * @note The actual data is converted to string representation, because we have not found
288 * yet an effective and safe way to transmit floating point numbers.
290 * @see GetDoubleData()
292 CECTag::CECTag(ec_tagname_t name, double data) : m_tagName(name), m_dynamic(true)
294 std::ostringstream double_str;
295 double_str << data;
296 m_dataLen = (ec_taglen_t)strlen(double_str.str().c_str()) + 1;
297 m_tagData = malloc(m_dataLen);
298 if (m_tagData != NULL) {
299 memcpy((void *)m_tagData, double_str.str().c_str(), m_dataLen);
300 m_dataType = EC_TAGTYPE_DOUBLE;
301 m_error = 0;
302 } else {
303 m_error = 1;
308 * Destructor - frees allocated data and deletes child TAGs.
310 CECTag::~CECTag(void)
312 if (m_dynamic) free((void *)m_tagData);
316 * Copy assignment operator.
318 * std::vector uses this, but the compiler-supplied version wouldn't properly
319 * handle m_dynamic and m_tagData. This wouldn't be necessary if m_tagData
320 * was a smart pointer (Hi, Kry!).
322 CECTag& CECTag::operator=(const CECTag& tag)
324 if (&tag != this) {
325 m_state = tag.m_state;
326 m_tagName = tag.m_tagName;
327 m_dynamic = tag.m_dynamic;
328 m_haschildren = tag.m_haschildren;
329 m_error = 0;
330 m_dataLen = tag.m_dataLen;
331 m_dataType = tag.m_dataType;
332 if (m_dataLen != 0) {
333 if (m_dynamic) {
334 m_tagData = malloc(m_dataLen);
335 if (m_tagData != NULL) {
336 memcpy((void *)m_tagData, tag.m_tagData, m_dataLen);
337 } else { // Nice try, but it will crash anyway when out of memory...
338 m_dataLen = 0;
339 m_error = 1;
340 return *this;
342 } else {
343 m_tagData = tag.m_tagData;
345 } else {
346 m_tagData = NULL;
348 m_tagList.clear();
349 if (!tag.m_tagList.empty()) {
350 m_tagList.reserve(tag.m_tagList.size());
351 for (TagList::size_type i=0; i<tag.m_tagList.size(); i++) {
352 m_tagList.push_back(tag.m_tagList[i]);
353 if (m_tagList.back().m_error != 0) {
354 m_error = m_tagList.back().m_error;
355 #ifndef KEEP_PARTIAL_PACKETS
356 m_tagList.pop_back();
357 #endif
358 break;
364 return *this;
368 * Compare operator.
371 bool CECTag::operator==(const CECTag& tag) const
373 return m_dataType == tag.m_dataType
374 && m_tagName == tag.m_tagName
375 && m_dataLen == tag.m_dataLen
376 && (m_dataLen == 0
377 || !memcmp(m_tagData, tag.m_tagData, m_dataLen))
378 && m_tagList == tag.m_tagList;
382 * Add a child tag to this one.
384 * Be very careful that this creates a copy of \e tag. Thus, the following code won't work as expected:
385 * \code
387 * CECPacket *p = new CECPacket(whatever);
388 * CECTag *t1 = new CECTag(whatever);
389 * CECTag *t2 = new CECTag(whatever);
390 * p.AddTag(*t1);
391 * t1.AddTag(*t2); // t2 won't be part of p !!!
393 * \endcode
395 * To get the desired results, the above should be replaced with something like:
397 * \code
399 * CECPacket *p = new CECPacket(whatever);
400 * CECTag *t1 = new CECTag(whatever);
401 * CECTag *t2 = new CECTag(whatever);
402 * t1.AddTag(*t2);
403 * delete t2; // we can safely delete t2 here, because t1 holds a copy
404 * p.AddTag(*t1);
405 * delete t1; // now p holds a copy of both t1 and t2
407 * \endcode
409 * Then why copying? The answer is to enable simplifying the code like this:
411 * \code
413 * CECPacket *p = new CECPacket(whatever);
414 * CECTag t1(whatever);
415 * t1.AddTag(CECTag(whatever)); // t2 is now created on-the-fly
416 * p.AddTag(t1); // now p holds a copy of both t1 and t2
418 * \endcode
420 * @param tag a CECTag class instance to add.
421 * @return \b true on succcess, \b false when an error occured
423 bool CECTag::AddTag(const CECTag& tag, CValueMap* valuemap)
425 if (valuemap) {
426 return valuemap->AddTag(tag, this);
428 // cannot have more than 64k tags
429 wxASSERT(m_tagList.size() < 0xffff);
431 m_tagList.push_back(tag);
432 if (m_tagList.back().m_error == 0) {
433 return true;
434 } else {
435 m_error = m_tagList.back().m_error;
436 #ifndef KEEP_PARTIAL_PACKETS
437 m_tagList.pop_back();
438 #endif
439 return false;
443 void CECTag::AddTag(ec_tagname_t name, uint64_t data, CValueMap* valuemap)
445 if (valuemap) {
446 valuemap->CreateTag(name, data, this);
447 } else {
448 AddTag(CECTag(name, data));
452 void CECTag::AddTag(ec_tagname_t name, const wxString& data, CValueMap* valuemap)
454 if (valuemap) {
455 valuemap->CreateTag(name, data, this);
456 } else {
457 AddTag(CECTag(name, data));
461 bool CECTag::ReadFromSocket(CECSocket& socket)
463 if (m_state == bsName) {
464 ec_tagname_t tmp_tagName;
465 if (!socket.ReadNumber(&tmp_tagName, sizeof(ec_tagname_t))) {
466 m_tagName = 0;
467 return false;
468 } else {
469 m_tagName = tmp_tagName >> 1;
470 m_haschildren = (tmp_tagName & 0x01) ? true : false;
471 m_state = bsType;
475 if (m_state == bsType) {
476 ec_tagtype_t type;
477 if (!socket.ReadNumber(&type, sizeof(ec_tagtype_t))) {
478 m_dataType = EC_TAGTYPE_UNKNOWN;
479 return false;
480 } else {
481 m_dataType = type;
482 if (m_haschildren) {
483 m_state = bsLengthChld;
484 } else {
485 m_state = bsLength;
490 if (m_state == bsLength || m_state == bsLengthChld) {
491 ec_taglen_t tagLen;
492 if (!socket.ReadNumber(&tagLen, sizeof(ec_taglen_t))) {
493 return false;
494 } else {
495 m_dataLen = tagLen;
496 if (m_state == bsLength) {
497 m_state = bsData1;
498 } else {
499 m_state = bsChildCnt;
504 if (m_state == bsChildCnt || m_state == bsChildren) {
505 if (!ReadChildren(socket)) {
506 return false;
510 if (m_state == bsData1) {
511 unsigned int tmp_len = m_dataLen;
512 m_dataLen = 0;
513 m_dataLen = tmp_len - GetTagLen();
514 if (m_dataLen > 0) {
515 m_tagData = malloc(m_dataLen);
516 m_state = bsData2;
517 } else {
518 m_tagData = NULL;
519 m_state = bsFinished;
523 if (m_state == bsData2) {
524 if (m_tagData != NULL) {
525 if (!socket.ReadBuffer((void *)m_tagData, m_dataLen)) {
526 return false;
527 } else {
528 m_state = bsFinished;
530 } else {
531 m_error = 1;
532 return false;
536 return true;
540 bool CECTag::WriteTag(CECSocket& socket) const
542 ec_tagname_t tmp_tagName = (m_tagName << 1) | (m_tagList.empty() ? 0 : 1);
543 ec_tagtype_t type = m_dataType;
544 ec_taglen_t tagLen = GetTagLen();
545 wxASSERT(type != EC_TAGTYPE_UNKNOWN);
547 if (!socket.WriteNumber(&tmp_tagName, sizeof(ec_tagname_t))) return false;
548 if (!socket.WriteNumber(&type, sizeof(ec_tagtype_t))) return false;
549 if (!socket.WriteNumber(&tagLen, sizeof(ec_taglen_t))) return false;
551 if (!m_tagList.empty()) {
552 if (!WriteChildren(socket)) return false;
555 if (m_dataLen > 0) {
556 if (m_tagData != NULL) { // This is here only to make sure everything, it should not be NULL at this point
557 if (!socket.WriteBuffer(m_tagData, m_dataLen)) return false;
561 return true;
564 bool CECTag::ReadChildren(CECSocket& socket)
566 if (m_state == bsChildCnt) {
567 uint16 tmp_tagCount;
568 if (!socket.ReadNumber(&tmp_tagCount, sizeof(uint16))) {
569 return false;
570 } else {
571 m_tagList.clear();
572 if (tmp_tagCount > 0) {
573 m_tagList.reserve(tmp_tagCount);
574 for (int i=0; i<tmp_tagCount; i++) {
575 m_tagList.push_back(CECTag(socket));
577 m_haschildren = true;
578 m_state = bsChildren;
579 } else {
580 m_state = bsData1;
585 if (m_state == bsChildren) {
586 for (unsigned int i=0; i<m_tagList.size(); i++) {
587 CECTag& tag = m_tagList[i];
588 if (!tag.IsOk()) {
589 if (!tag.ReadFromSocket(socket)) {
590 if (tag.m_error != 0) {
591 m_error = tag.m_error;
593 return false;
597 m_state = bsData1;
600 return true;
603 bool CECTag::WriteChildren(CECSocket& socket) const
605 wxASSERT(m_tagList.size() < 0xFFFF);
606 uint16 tmp = (uint16)m_tagList.size();
607 if (!socket.WriteNumber(&tmp, sizeof(tmp))) return false;
608 if (!m_tagList.empty()) {
609 for (TagList::size_type i=0; i<m_tagList.size(); i++) {
610 if (!m_tagList[i].WriteTag(socket)) return false;
613 return true;
617 * Finds the (first) child tag with given name.
619 * @param name TAG name to look for.
620 * @return the tag found, or NULL.
622 const CECTag* CECTag::GetTagByName(ec_tagname_t name) const
624 for (TagList::size_type i=0; i<m_tagList.size(); i++)
625 if (m_tagList[i].m_tagName == name) return &m_tagList[i];
626 return NULL;
630 * Finds the (first) child tag with given name.
632 * @param name TAG name to look for.
633 * @return the tag found, or NULL.
635 CECTag* CECTag::GetTagByName(ec_tagname_t name)
637 for (TagList::size_type i=0; i<m_tagList.size(); i++)
638 if (m_tagList[i].m_tagName == name) return &m_tagList[i];
639 return NULL;
643 * Finds the (first) child tag with given name.
645 * @param name TAG name to look for.
646 * @return the tag found, or a special null-valued tag otherwise.
648 * @see s_theNullTag
650 const CECTag* CECTag::GetTagByNameSafe(ec_tagname_t name) const
652 const CECTag* result = GetTagByName(name);
653 if (result == NULL)
654 result = &s_theNullTag;
655 return result;
659 * Query TAG length that is suitable for the TAGLEN field (i.e.\
660 * without it's own header size).
662 * @return Tag length, containing its childs' length.
664 uint32 CECTag::GetTagLen(void) const
666 uint32 length = m_dataLen;
667 for (TagList::size_type i=0; i<m_tagList.size(); i++) {
668 length += m_tagList[i].GetTagLen();
669 length += sizeof(ec_tagname_t) + sizeof(ec_tagtype_t) + sizeof(ec_taglen_t) + ((m_tagList[i].GetTagCount() > 0) ? 2 : 0);
671 return length;
675 uint64_t CECTag::GetInt() const
677 if (m_tagData == NULL) {
678 // Empty tag - This is NOT an error.
679 EC_ASSERT(m_dataType == EC_TAGTYPE_UNKNOWN);
680 return 0;
683 switch (m_dataType) {
684 case EC_TAGTYPE_UINT8:
685 return PeekUInt8(m_tagData);
686 case EC_TAGTYPE_UINT16:
687 return ENDIAN_NTOHS( RawPeekUInt16( m_tagData ) );
688 case EC_TAGTYPE_UINT32:
689 return ENDIAN_NTOHL( RawPeekUInt32( m_tagData ) );
690 case EC_TAGTYPE_UINT64:
691 return ENDIAN_NTOHLL( RawPeekUInt64( m_tagData ) );
692 case EC_TAGTYPE_UNKNOWN:
693 // Empty tag - This is NOT an error.
694 return 0;
695 default:
696 EC_ASSERT(0);
697 return 0;
702 std::string CECTag::GetStringDataSTL() const
704 if (m_dataType != EC_TAGTYPE_STRING) {
705 EC_ASSERT(m_dataType == EC_TAGTYPE_UNKNOWN);
706 return std::string();
707 } else if (m_tagData == NULL) {
708 EC_ASSERT(false);
709 return std::string();
712 return std::string((const char*)m_tagData);
716 #ifdef USE_WX_EXTENSIONS
717 wxString CECTag::GetStringData() const
719 return UTF82unicode(GetStringDataSTL().c_str());
721 #endif
724 CMD4Hash CECTag::GetMD4Data() const
726 if (m_dataType != EC_TAGTYPE_HASH16) {
727 EC_ASSERT(m_dataType == EC_TAGTYPE_UNKNOWN);
728 return CMD4Hash();
731 EC_ASSERT(m_tagData != NULL);
733 // Doesn't matter if m_tagData is NULL in CMD4Hash(),
734 // that'll just result in an empty hash.
735 return CMD4Hash((const unsigned char *)m_tagData);
740 * Returns an EC_IPv4_t class.
742 * This function takes care of the enadianness of the port number.
744 * @return EC_IPv4_t class.
746 * @see CECTag(ec_tagname_t, const EC_IPv4_t&)
748 EC_IPv4_t CECTag::GetIPv4Data() const
750 EC_IPv4_t p(0, 0);
752 if (m_tagData == NULL) {
753 EC_ASSERT(false);
754 } else if (m_dataType != EC_TAGTYPE_IPV4) {
755 EC_ASSERT(false);
756 } else {
757 RawPokeUInt32( p.m_ip, RawPeekUInt32( ((EC_IPv4_t *)m_tagData)->m_ip ) );
758 p.m_port = ENDIAN_NTOHS(((EC_IPv4_t *)m_tagData)->m_port);
761 return p;
765 * Returns a double value.
767 * @note The returned value is what we get by converting the string form
768 * of the number to a double.
770 * @return The double value of the tag.
772 * @see CECTag(ec_tagname_t, double)
774 double CECTag::GetDoubleData(void) const
776 if (m_dataType != EC_TAGTYPE_DOUBLE) {
777 EC_ASSERT(m_dataType == EC_TAGTYPE_UNKNOWN);
778 return 0;
779 } else if (m_tagData == NULL) {
780 EC_ASSERT(false);
781 return 0;
784 std::istringstream double_str((const char*)m_tagData);
786 double data;
787 double_str >> data;
788 return data;
792 void CECTag::ConstructStringTag(ec_tagname_t /*name*/, const std::string& data)
794 m_dataLen = (ec_taglen_t)strlen(data.c_str()) + 1;
795 m_tagData = malloc(m_dataLen);
796 if (m_tagData != NULL) {
797 memcpy((void *)m_tagData, data.c_str(), m_dataLen);
798 m_error = 0;
799 m_dataType = EC_TAGTYPE_STRING;
800 } else {
801 m_error = 1;
805 void CECTag::SetStringData(const wxString& s)
807 if (IsString()) {
808 free((void *)m_tagData);
809 ConstructStringTag(0, (const char*)unicode2UTF8(s));
813 #if __DEBUG__
814 void CECTag::DebugPrint(int level, bool print_empty) const
816 if (m_dataLen || print_empty) {
817 wxString space;
818 for (int i = level; i--;) space += wxT(" ");
819 wxString s1 = CFormat(wxT("%s%s %d = ")) % space % GetDebugNameECTagNames(m_tagName) % m_dataLen;
820 wxString s2;
821 switch (m_tagName) {
822 case EC_TAG_DETAIL_LEVEL:
823 s2 = GetDebugNameEC_DETAIL_LEVEL(GetInt()); break;
824 case EC_TAG_SEARCH_TYPE:
825 s2 = GetDebugNameEC_SEARCH_TYPE(GetInt()); break;
826 case EC_TAG_STAT_VALUE_TYPE:
827 s2 = GetDebugNameEC_STATTREE_NODE_VALUE_TYPE(GetInt()); break;
828 default:
829 switch (m_dataType) {
830 case EC_TAGTYPE_UINT8:
831 case EC_TAGTYPE_UINT16:
832 case EC_TAGTYPE_UINT32:
833 case EC_TAGTYPE_UINT64:
834 s2 = CFormat(wxT("%d")) % GetInt(); break;
835 case EC_TAGTYPE_STRING:
836 s2 = GetStringData(); break;
837 case EC_TAGTYPE_DOUBLE:
838 s2 = CFormat(wxT("%.1f")) % GetDoubleData(); break;
839 case EC_TAGTYPE_HASH16:
840 s2 = GetMD4Data().Encode(); break;
841 default:
842 s2 = GetDebugNameECTagTypes(m_dataType);
845 DoECLogLine(s1 + s2);
847 for (TagList::const_iterator it = m_tagList.begin(); it != m_tagList.end(); ++it) {
848 it->DebugPrint(level + 1, true);
851 #endif
854 * \fn CMD4Hash CECTag::GetMD4Data(void) const
856 * \brief Returns a CMD4Hash class.
858 * This function takes care of converting from MSB to LSB as necessary.
860 * \return CMD4Hash class.
862 * \sa CECTag(ec_tagname_t, const CMD4Hash&)
866 * \fn CECTag *CECTag::GetTagByIndex(size_t index) const
868 * \brief Finds the indexth child tag.
870 * \param index 0-based index, 0 <= \e index < GetTagCount()
872 * \return The child tag, or NULL if index out of range.
876 * \fn CECTag *CECTag::GetTagByIndexSafe(size_t index) const
878 * \brief Finds the indexth child tag.
880 * \param index 0-based index, 0 <= \e index < GetTagCount()
882 * \return The child tag, or a special null-valued tag if index out of range.
886 * \fn size_t CECTag::GetTagCount(void) const
888 * \brief Returns the number of child tags.
890 * \return The number of child tags.
894 * \fn const void *CECTag::GetTagData(void) const
896 * \brief Returns a pointer to the TAG DATA.
898 * \return A pointer to the TAG DATA. (As specified with the data field of the constructor.)
902 * \fn uint16 CECTag::GetTagDataLen(void) const
904 * \brief Returns the length of the data buffer.
906 * \return The length of the data buffer.
910 * \fn ec_tagname_t CECTag::GetTagName(void) const
912 * \brief Returns TAGNAME.
914 * \return The name of the tag.
918 * \fn wxString CECTag::GetStringData(void) const
920 * \brief Returns the string data of the tag.
922 * Returns a wxString created from TAGDATA. It is automatically
923 * converted from UTF-8 to the internal application encoding.
924 * Should be used with care (only on tags created with the
925 * CECTag(ec_tagname_t, const wxString&) constructor),
926 * becuse it does not perform any check to see if the tag really contains a
927 * string object.
929 * \return The string data of the tag.
931 * \sa CECTag(ec_tagname_t, const wxString&)
935 * \fn uint8 CECTag::GetInt(void) const
937 * \brief Returns the uint8 data of the tag.
939 * This function takes care of the endianness problems with numbers.
941 * \return The uint8 data of the tag.
943 * \sa CECTag(ec_tagname_t, uint8)
947 * \fn uint16 CECTag::GetInt(void) const
949 * \brief Returns the uint16 data of the tag.
951 * This function takes care of the endianness problems with numbers.
953 * \return The uint16 data of the tag.
955 * \sa CECTag(ec_tagname_t, uint16)
959 * \fn uint32 CECTag::GetInt(void) const
961 * \brief Returns the uint32 data of the tag.
963 * This function takes care of the endianness problems with numbers.
965 * \return The uint32 data of the tag.
967 * \sa CECTag(ec_tagname_t, uint32)
971 * \fn uint64 CECTag::GetInt(void) const
973 * \brief Returns the uint64 data of the tag.
975 * This function takes care of the endianness problems with numbers.
977 * \return The uint64 data of the tag.
979 * \sa CECTag(ec_tagname_t, uint64)
981 // File_checked_for_headers