Upstream tarball 10085
[amule.git] / src / libs / ec / cpp / ECTag.cpp
blobdb6acc5fc388bca5d1e14b3f94da8a478852dd40
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
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 m_dataLen = length;
70 if (data) {
71 NewData();
72 memcpy(m_tagData, data, m_dataLen);
73 } else {
74 m_tagData = NULL;
76 m_dataType = EC_TAGTYPE_CUSTOM;
79 /**
80 * Creates a new CECTag instance for custom data
82 * @param name TAG name
83 * @param length length of data buffer that will be alloc'ed
84 * @param dataptr pointer to a void pointer which will be assigned the internal TAG data buffer
86 * \note TAG data buffer has to be filled with valid data after the ctor
88 CECTag::CECTag(ec_tagname_t name, unsigned int length, void **dataptr) : m_tagName(name)
90 m_dataLen = length;
91 NewData();
92 *dataptr = m_tagData;
93 m_dataType = EC_TAGTYPE_CUSTOM;
96 /**
97 * Creates a new CECTag instance, which contains an IPv4 address.
99 * This function takes care of the endianness of the port number.
101 * @param name TAG name
102 * @param data The EC_IPv4_t class containing the IPv4 address.
104 * @see GetIPv4Data()
106 CECTag::CECTag(ec_tagname_t name, const EC_IPv4_t& data) : m_tagName(name)
109 m_dataLen = sizeof(EC_IPv4_t);
110 NewData();
111 RawPokeUInt32( ((EC_IPv4_t *)m_tagData)->m_ip, RawPeekUInt32( data.m_ip ) );
112 ((EC_IPv4_t *)m_tagData)->m_port = ENDIAN_HTONS(data.m_port);
113 m_dataType = EC_TAGTYPE_IPV4;
117 * Creates a new CECTag instance, which contains a MD4 hash.
119 * This function takes care to store hash in network byte order.
121 * @param name TAG name
122 * @param data The CMD4Hash class containing the MD4 hash.
124 * @see GetMD4Data()
126 CECTag::CECTag(ec_tagname_t name, const CMD4Hash& data) : m_tagName(name)
128 m_dataLen = 16;
129 NewData();
130 RawPokeUInt64( m_tagData, RawPeekUInt64( data.GetHash() ) );
131 RawPokeUInt64( m_tagData + 8, RawPeekUInt64( data.GetHash() + 8 ) );
132 m_dataType = EC_TAGTYPE_HASH16;
136 * Creates a new CECTag instance, which contains a string
138 * @param name TAG name
139 * @param data wxString object, it's contents are converted to UTF-8.
141 * @see GetStringDataSTL()
143 CECTag::CECTag(ec_tagname_t name, const std::string& data) : m_tagName(name)
145 ConstructStringTag(name, data);
149 * Creates a new CECTag instance, which contains a string
151 * @param name TAG name
152 * @param data wxString object, it's contents are converted to UTF-8.
154 * @see GetStringData()
156 CECTag::CECTag(ec_tagname_t name, const wxString& data)
158 ConstructStringTag(name, (const char*)unicode2UTF8(data));
160 CECTag::CECTag(ec_tagname_t name, const wxChar* data)
162 ConstructStringTag(name, (const char*)unicode2UTF8(data));
166 * Copy constructor
168 CECTag::CECTag(const CECTag& tag)
170 m_tagData = NULL;
171 *this = tag;
175 * Creates a new CECTag instance, which contains an int value.
177 * This takes care of endianness problems with numbers.
179 * @param name TAG name.
180 * @param data number.
182 * @see GetInt()
184 CECTag::CECTag(ec_tagname_t name, bool data) : m_tagName(name)
186 InitInt(data);
188 CECTag::CECTag(ec_tagname_t name, uint8 data) : m_tagName(name)
190 InitInt(data);
192 CECTag::CECTag(ec_tagname_t name, uint16 data) : m_tagName(name)
194 InitInt(data);
196 CECTag::CECTag(ec_tagname_t name, uint32 data) : m_tagName(name)
198 InitInt(data);
200 CECTag::CECTag(ec_tagname_t name, uint64 data) : m_tagName(name)
202 InitInt(data);
205 void CECTag::InitInt(uint64 data)
207 if (data <= 0xFF) {
208 m_dataType = EC_TAGTYPE_UINT8;
209 m_dataLen = 1;
210 } else if (data <= 0xFFFF) {
211 m_dataType = EC_TAGTYPE_UINT16;
212 m_dataLen = 2;
213 } else if (data <= 0xFFFFFFFF) {
214 m_dataType = EC_TAGTYPE_UINT32;
215 m_dataLen = 4;
216 } else {
217 m_dataType = EC_TAGTYPE_UINT64;
218 m_dataLen = 8;
221 NewData();
223 switch (m_dataType) {
224 case EC_TAGTYPE_UINT8:
225 PokeUInt8( m_tagData, (uint8) data );
226 break;
227 case EC_TAGTYPE_UINT16:
228 PokeUInt16( m_tagData, wxUINT16_SWAP_ALWAYS((uint16) data ));
229 break;
230 case EC_TAGTYPE_UINT32:
231 PokeUInt32( m_tagData, wxUINT32_SWAP_ALWAYS((uint32) data ));
232 break;
233 case EC_TAGTYPE_UINT64:
234 PokeUInt64( m_tagData, wxUINT64_SWAP_ALWAYS(data) );
235 break;
240 * Creates a new CECTag instance, which contains a double precision floating point number
242 * @param name TAG name
243 * @param data double number
245 * @note The actual data is converted to string representation, because we have not found
246 * yet an effective and safe way to transmit floating point numbers.
248 * @see GetDoubleData()
250 CECTag::CECTag(ec_tagname_t name, double data) : m_tagName(name)
252 std::ostringstream double_str;
253 double_str << data;
254 std::string double_string = double_str.str();
255 const char * double_chr = double_string.c_str();
256 m_dataLen = (ec_taglen_t)strlen(double_chr) + 1;
257 NewData();
258 memcpy(m_tagData, double_chr, m_dataLen);
259 m_dataType = EC_TAGTYPE_DOUBLE;
263 * Destructor - frees allocated data and deletes child TAGs.
265 CECTag::~CECTag(void)
267 delete [] m_tagData;
271 * Copy assignment operator.
273 * std::vector uses this, but the compiler-supplied version wouldn't properly
274 * handle m_dynamic and m_tagData. This wouldn't be necessary if m_tagData
275 * was a smart pointer (Hi, Kry!).
277 CECTag& CECTag::operator=(const CECTag& tag)
279 if (&tag != this) {
280 m_tagName = tag.m_tagName;
281 m_dataLen = tag.m_dataLen;
282 m_dataType = tag.m_dataType;
283 delete [] m_tagData;
284 if (m_dataLen != 0) {
285 NewData();
286 memcpy(m_tagData, tag.m_tagData, m_dataLen);
287 } else {
288 m_tagData = NULL;
290 m_tagList.clear();
291 for (const_iterator it = tag.begin(); it != tag.end(); it++) {
292 m_tagList.push_back(*it);
295 return *this;
299 * Compare operator.
302 bool CECTag::operator==(const CECTag& tag) const
304 return m_dataType == tag.m_dataType
305 && m_tagName == tag.m_tagName
306 && m_dataLen == tag.m_dataLen
307 && (m_dataLen == 0
308 || !memcmp(m_tagData, tag.m_tagData, m_dataLen))
309 && m_tagList == tag.m_tagList;
313 * Add a child tag to this one. The tag argument is reset to an empty tag.
315 * Be very careful that this method swallows the content of \e tag, leaving \e tag empty.
316 * Thus, the following code won't work as expected:
317 * \code
319 * CECPacket *p = new CECPacket(whatever);
320 * CECTag *t1 = new CECTag(whatever);
321 * CECTag *t2 = new CECTag(whatever);
322 * p->AddTag(*t1);
323 * t1->AddTag(*t2); // t2 won't be part of p !!!
325 * \endcode
327 * To get the desired results, the above should be replaced with something like:
329 * \code
331 * CECPacket *p = new CECPacket(whatever);
332 * CECTag *t1 = new CECTag(whatever);
333 * CECTag *t2 = new CECTag(whatever);
334 * t1->AddTag(*t2);
335 * delete t2; // we can safely delete the now empty t2 here, because t1 holds its content
336 * p->AddTag(*t1);
337 * delete t1; // now p holds the content of both t1 and t2
339 * \endcode
341 * Then why copying? The answer is to enable simplifying the code like this:
343 * \code
345 * CECPacket *p = new CECPacket(whatever);
346 * CECTag t1(whatever);
347 * t1.AddTag(CECTag(whatever)); // t2 is now created on-the-fly
348 * p->AddTag(t1); // now p holds a copy of both t1 and t2
350 * \endcode
352 * @param tag a CECTag class instance to add.
353 * @return \b true if tag was really added,
354 * \b false when it was omitted through valuemap.
356 bool CECTag::AddTag(const CECTag& tag, CValueMap* valuemap)
358 if (valuemap) {
359 return valuemap->AddTag(tag, this);
361 // cannot have more than 64k tags
362 wxASSERT(m_tagList.size() < 0xffff);
364 // First add an empty tag.
365 m_tagList.push_back(CECEmptyTag());
366 // Then exchange the data. The original tag will be destroyed right after this call anyway.
367 // UGLY - GCC allows a reference to an in place constructed object only to be passed as const.
368 // So pass it the way it wants it and then cheat and cast it back to non-const. :-/
369 CECTag& wtag = const_cast<CECTag&>(tag);
370 wtag.swap(m_tagList.back());
371 return true;
374 void CECTag::AddTag(ec_tagname_t name, uint64_t data, CValueMap* valuemap)
376 if (valuemap) {
377 valuemap->CreateTag(name, data, this);
378 } else {
379 AddTag(CECTag(name, data));
383 void CECTag::AddTag(ec_tagname_t name, const wxString& data, CValueMap* valuemap)
385 if (valuemap) {
386 valuemap->CreateTag(name, data, this);
387 } else {
388 AddTag(CECTag(name, data));
392 void CECTag::AddTag(ec_tagname_t name, const CMD4Hash& data, CValueMap* valuemap)
394 if (valuemap) {
395 valuemap->CreateTag(name, data, this);
396 } else {
397 AddTag(CECTag(name, data));
401 void CECTag::swap(CECTag& t2)
403 std::swap(m_tagName, t2.m_tagName);
404 std::swap(m_dataType, t2.m_dataType);
405 std::swap(m_dataLen, t2.m_dataLen);
406 std::swap(m_tagData, t2.m_tagData);
407 std::swap(m_tagList, t2.m_tagList);
410 bool CECTag::ReadFromSocket(CECSocket& socket)
412 ec_tagname_t tmp_tagName;
413 if (!socket.ReadNumber(&tmp_tagName, sizeof(ec_tagname_t))) {
414 return false;
416 m_tagName = tmp_tagName >> 1;
417 bool hasChildren = (tmp_tagName & 0x01) != 0;
419 if (!socket.ReadNumber(&m_dataType, sizeof(ec_tagtype_t))) {
420 return false;
423 if (!socket.ReadNumber(&m_dataLen, sizeof(ec_taglen_t))) {
424 return false;
427 if (hasChildren && !ReadChildren(socket)) {
428 return false;
431 unsigned int tmp_len = m_dataLen;
432 m_dataLen = 0;
433 m_dataLen = tmp_len - GetTagLen();
434 if (m_dataLen > 0) {
435 NewData();
436 if (!socket.ReadBuffer(m_tagData, m_dataLen)) {
437 return false;
439 } else {
440 m_tagData = NULL;
443 return true;
447 bool CECTag::WriteTag(CECSocket& socket) const
449 ec_tagname_t tmp_tagName = (m_tagName << 1) | (m_tagList.empty() ? 0 : 1);
450 ec_tagtype_t type = m_dataType;
451 ec_taglen_t tagLen = GetTagLen();
452 wxASSERT(type != EC_TAGTYPE_UNKNOWN);
454 if (!socket.WriteNumber(&tmp_tagName, sizeof(ec_tagname_t))) return false;
455 if (!socket.WriteNumber(&type, sizeof(ec_tagtype_t))) return false;
456 if (!socket.WriteNumber(&tagLen, sizeof(ec_taglen_t))) return false;
458 if (!m_tagList.empty()) {
459 if (!WriteChildren(socket)) return false;
462 if (m_dataLen > 0) {
463 if (m_tagData != NULL) { // This is here only to make sure everything, it should not be NULL at this point
464 if (!socket.WriteBuffer(m_tagData, m_dataLen)) return false;
468 return true;
471 bool CECTag::ReadChildren(CECSocket& socket)
473 uint16 tmp_tagCount;
474 if (!socket.ReadNumber(&tmp_tagCount, sizeof(uint16))) {
475 return false;
477 m_tagList.clear();
478 for (int i = 0; i < tmp_tagCount; i++) {
479 m_tagList.push_back(CECTag());
480 CECTag& tag = m_tagList.back();
481 if (!tag.ReadFromSocket(socket)) {
482 return false;
485 return true;
488 bool CECTag::WriteChildren(CECSocket& socket) const
490 wxASSERT(m_tagList.size() < 0xFFFF);
491 uint16 tmp = (uint16)m_tagList.size();
492 if (!socket.WriteNumber(&tmp, sizeof(tmp))) return false;
493 for (const_iterator it = begin(); it != end(); it++) {
494 if (!it->WriteTag(socket)) return false;
496 return true;
500 * Finds the (first) child tag with given name.
502 * @param name TAG name to look for.
503 * @return the tag found, or NULL.
505 const CECTag* CECTag::GetTagByName(ec_tagname_t name) const
507 for (const_iterator it = begin(); it != end(); it++) {
508 if (it->m_tagName == name) return & *it;
510 return NULL;
514 * Finds the (first) child tag with given name.
516 * @param name TAG name to look for.
517 * @return the tag found, or NULL.
519 CECTag* CECTag::GetTagByName(ec_tagname_t name)
521 for (TagList::iterator it = m_tagList.begin(); it != m_tagList.end(); it++) {
522 if (it->m_tagName == name) return & *it;
524 return NULL;
528 * Finds the (first) child tag with given name.
530 * @param name TAG name to look for.
531 * @return the tag found, or a special null-valued tag otherwise.
533 * @see s_theNullTag
535 const CECTag* CECTag::GetTagByNameSafe(ec_tagname_t name) const
537 const CECTag* result = GetTagByName(name);
538 if (result == NULL)
539 result = &s_theNullTag;
540 return result;
544 * Query TAG length that is suitable for the TAGLEN field (i.e.\
545 * without it's own header size).
547 * @return Tag length, containing its childs' length.
549 uint32 CECTag::GetTagLen(void) const
551 uint32 length = m_dataLen;
552 for (const_iterator it = begin(); it != end(); it++) {
553 length += it->GetTagLen();
554 length += sizeof(ec_tagname_t) + sizeof(ec_tagtype_t) + sizeof(ec_taglen_t) + (it->HasChildTags() ? 2 : 0);
556 return length;
560 uint64_t CECTag::GetInt() const
562 if (m_tagData == NULL) {
563 // Empty tag - This is NOT an error.
564 EC_ASSERT(m_dataType == EC_TAGTYPE_UNKNOWN);
565 return 0;
568 switch (m_dataType) {
569 case EC_TAGTYPE_UINT8:
570 return PeekUInt8(m_tagData);
571 case EC_TAGTYPE_UINT16:
572 return ENDIAN_NTOHS( RawPeekUInt16( m_tagData ) );
573 case EC_TAGTYPE_UINT32:
574 return ENDIAN_NTOHL( RawPeekUInt32( m_tagData ) );
575 case EC_TAGTYPE_UINT64:
576 return ENDIAN_NTOHLL( RawPeekUInt64( m_tagData ) );
577 case EC_TAGTYPE_UNKNOWN:
578 // Empty tag - This is NOT an error.
579 return 0;
580 default:
581 EC_ASSERT(0);
582 return 0;
587 std::string CECTag::GetStringDataSTL() const
589 if (m_dataType != EC_TAGTYPE_STRING) {
590 EC_ASSERT(m_dataType == EC_TAGTYPE_UNKNOWN);
591 return std::string();
592 } else if (m_tagData == NULL) {
593 EC_ASSERT(false);
594 return std::string();
597 return std::string(m_tagData);
601 #ifdef USE_WX_EXTENSIONS
602 wxString CECTag::GetStringData() const
604 return UTF82unicode(GetStringDataSTL().c_str());
606 #endif
609 CMD4Hash CECTag::GetMD4Data() const
611 if (m_dataType != EC_TAGTYPE_HASH16) {
612 EC_ASSERT(m_dataType == EC_TAGTYPE_UNKNOWN);
613 return CMD4Hash();
616 EC_ASSERT(m_tagData != NULL);
618 // Doesn't matter if m_tagData is NULL in CMD4Hash(),
619 // that'll just result in an empty hash.
620 return CMD4Hash((const unsigned char *)m_tagData);
625 * Returns an EC_IPv4_t class.
627 * This function takes care of the endianness of the port number.
629 * @return EC_IPv4_t class.
631 * @see CECTag(ec_tagname_t, const EC_IPv4_t&)
633 EC_IPv4_t CECTag::GetIPv4Data() const
635 EC_IPv4_t p(0, 0);
637 if (m_dataType != EC_TAGTYPE_IPV4) {
638 EC_ASSERT(m_dataType == EC_TAGTYPE_UNKNOWN);
639 } else if (m_tagData == NULL) {
640 EC_ASSERT(false);
641 } else {
642 RawPokeUInt32( p.m_ip, RawPeekUInt32( ((EC_IPv4_t *)m_tagData)->m_ip ) );
643 p.m_port = ENDIAN_NTOHS(((EC_IPv4_t *)m_tagData)->m_port);
646 return p;
650 * Returns a double value.
652 * @note The returned value is what we get by converting the string form
653 * of the number to a double.
655 * @return The double value of the tag.
657 * @see CECTag(ec_tagname_t, double)
659 double CECTag::GetDoubleData(void) const
661 if (m_dataType != EC_TAGTYPE_DOUBLE) {
662 EC_ASSERT(m_dataType == EC_TAGTYPE_UNKNOWN);
663 return 0;
664 } else if (m_tagData == NULL) {
665 EC_ASSERT(false);
666 return 0;
669 std::istringstream double_str(m_tagData);
671 double data;
672 double_str >> data;
673 return data;
677 void CECTag::ConstructStringTag(ec_tagname_t name, const std::string& data)
679 m_tagName = name;
680 m_dataLen = (ec_taglen_t)strlen(data.c_str()) + 1;
681 NewData();
682 memcpy(m_tagData, data.c_str(), m_dataLen);
683 m_dataType = EC_TAGTYPE_STRING;
686 void CECTag::SetStringData(const wxString& s)
688 if (IsString()) {
689 delete [] m_tagData;
690 ConstructStringTag(m_tagName, (const char*)unicode2UTF8(s));
695 bool CECTag::AssignIfExist(ec_tagname_t tagname, bool *target) const
697 bool ret = false;
698 const CECTag *tag = GetTagByName(tagname);
699 if (tag) {
700 ret = tag->GetInt() > 0;
701 if (target) {
702 *target = ret;
705 return ret;
708 uint8_t CECTag::AssignIfExist(ec_tagname_t tagname, uint8_t *target) const
710 uint8_t ret = 0;
711 const CECTag *tag = GetTagByName(tagname);
712 if (tag) {
713 EC_ASSERT((tag->GetType() == EC_TAGTYPE_UINT8) || (m_dataType == EC_TAGTYPE_UNKNOWN));
714 ret = tag->GetInt();
715 if (target) {
716 *target = ret;
719 return ret;
722 uint16_t CECTag::AssignIfExist(ec_tagname_t tagname, uint16_t *target) const
724 uint16_t ret = 0;
725 const CECTag *tag = GetTagByName(tagname);
726 if (tag) {
727 EC_ASSERT(
728 (tag->GetType() == EC_TAGTYPE_UINT16)
729 || (tag->GetType() == EC_TAGTYPE_UINT8)
730 || (m_dataType == EC_TAGTYPE_UNKNOWN)
732 ret = tag->GetInt();
733 if (target) {
734 *target = ret;
737 return ret;
740 uint32_t CECTag::AssignIfExist(ec_tagname_t tagname, uint32_t *target) const
742 uint32_t ret = 0;
743 const CECTag *tag = GetTagByName(tagname);
744 if (tag) {
745 EC_ASSERT(
746 (tag->GetType() == EC_TAGTYPE_UINT32)
747 || (tag->GetType() == EC_TAGTYPE_UINT16)
748 || (tag->GetType() == EC_TAGTYPE_UINT8)
749 || (m_dataType == EC_TAGTYPE_UNKNOWN)
751 ret = tag->GetInt();
752 if (target) {
753 *target = ret;
756 return ret;
759 uint64_t CECTag::AssignIfExist(ec_tagname_t tagname, uint64_t *target) const
761 uint64_t ret = 0;
762 const CECTag *tag = GetTagByName(tagname);
763 if (tag) {
764 ret = tag->GetInt();
765 if (target) {
766 *target = ret;
769 return ret;
772 time_t CECTag::AssignIfExist(ec_tagname_t tagname, time_t *target) const
774 time_t ret = 0;
775 const CECTag *tag = GetTagByName(tagname);
776 if (tag) {
777 ret = tag->GetInt();
778 if (target) {
779 *target = ret;
782 return ret;
785 double CECTag::AssignIfExist(ec_tagname_t tagname, double *target) const
787 double ret = 0.0;
788 const CECTag *tag = GetTagByName(tagname);
789 if (tag) {
790 ret = tag->GetDoubleData();
791 if (target) {
792 *target = ret;
795 return ret;
798 float CECTag::AssignIfExist(ec_tagname_t tagname, float *target) const
800 float ret = 0.0;
801 const CECTag *tag = GetTagByName(tagname);
802 if (tag) {
803 ret = tag->GetDoubleData();
804 if (target) {
805 *target = ret;
808 return ret;
811 CMD4Hash CECTag::AssignIfExist(ec_tagname_t tagname, CMD4Hash *target) const
813 CMD4Hash ret;
814 const CECTag *tag = GetTagByName(tagname);
815 if (tag) {
816 ret = tag->GetMD4Data();
817 if (target) {
818 *target = ret;
821 return ret;
824 std::string CECTag::AssignIfExist(ec_tagname_t tagname, std::string *target) const
826 std::string ret;
827 const CECTag *tag = GetTagByName(tagname);
828 if (tag) {
829 ret = tag->GetStringDataSTL();
830 if (target) {
831 *target = ret;
834 return ret;
837 #ifdef USE_WX_EXTENSIONS
838 wxString CECTag::AssignIfExist(ec_tagname_t tagname, wxString *target) const
840 wxString ret;
841 const CECTag *tag = GetTagByName(tagname);
842 if (tag) {
843 ret = tag->GetStringData();
844 if (target) {
845 *target = ret;
848 return ret;
850 #endif
853 #if __DEBUG__
854 void CECTag::DebugPrint(int level, bool print_empty) const
856 if (m_dataLen || print_empty) {
857 wxString space;
858 for (int i = level; i--;) space += wxT(" ");
859 wxString s1 = CFormat(wxT("%s%s %d = ")) % space % GetDebugNameECTagNames(m_tagName) % m_dataLen;
860 wxString s2;
861 switch (m_tagName) {
862 case EC_TAG_DETAIL_LEVEL:
863 s2 = GetDebugNameEC_DETAIL_LEVEL(GetInt()); break;
864 case EC_TAG_SEARCH_TYPE:
865 s2 = GetDebugNameEC_SEARCH_TYPE(GetInt()); break;
866 case EC_TAG_STAT_VALUE_TYPE:
867 s2 = GetDebugNameEC_STATTREE_NODE_VALUE_TYPE(GetInt()); break;
868 default:
869 switch (m_dataType) {
870 case EC_TAGTYPE_UINT8:
871 case EC_TAGTYPE_UINT16:
872 case EC_TAGTYPE_UINT32:
873 case EC_TAGTYPE_UINT64:
874 s2 = CFormat(wxT("%d")) % GetInt(); break;
875 case EC_TAGTYPE_STRING:
876 s2 = GetStringData(); break;
877 case EC_TAGTYPE_DOUBLE:
878 s2 = CFormat(wxT("%.1f")) % GetDoubleData(); break;
879 case EC_TAGTYPE_HASH16:
880 s2 = GetMD4Data().Encode(); break;
881 case EC_TAGTYPE_CUSTOM:
882 if (m_dataLen == 0) {
883 s2 = wxT("empty");
884 } else {
885 // Make a hex dump (limited to maxOutput)
886 const uint32 maxOutput = 50;
887 for (uint32 i = 0; i < m_dataLen; i++) {
888 if (i == maxOutput) {
889 s2 += wxT("...");
890 break;
892 s2 += CFormat(wxT("%02X ")) % (unsigned char) m_tagData[i];
895 break;
896 default:
897 s2 = GetDebugNameECTagTypes(m_dataType);
900 DoECLogLine(s1 + s2);
902 for (TagList::const_iterator it = m_tagList.begin(); it != m_tagList.end(); ++it) {
903 it->DebugPrint(level + 1, true);
906 #endif
909 * \fn CMD4Hash CECTag::GetMD4Data(void) const
911 * \brief Returns a CMD4Hash class.
913 * This function takes care of converting from MSB to LSB as necessary.
915 * \return CMD4Hash class.
917 * \sa CECTag(ec_tagname_t, const CMD4Hash&)
921 * \fn CECTag *CECTag::GetTagByIndex(size_t index) const
923 * \brief Finds the indexth child tag.
925 * \param index 0-based index, 0 <= \e index < GetTagCount()
927 * \return The child tag, or NULL if index out of range.
931 * \fn CECTag *CECTag::GetTagByIndexSafe(size_t index) const
933 * \brief Finds the indexth child tag.
935 * \param index 0-based index, 0 <= \e index < GetTagCount()
937 * \return The child tag, or a special null-valued tag if index out of range.
941 * \fn size_t CECTag::GetTagCount(void) const
943 * \brief Returns the number of child tags.
945 * \return The number of child tags.
949 * \fn const void *CECTag::GetTagData(void) const
951 * \brief Returns a pointer to the TAG DATA.
953 * \return A pointer to the TAG DATA. (As specified with the data field of the constructor.)
957 * \fn uint16 CECTag::GetTagDataLen(void) const
959 * \brief Returns the length of the data buffer.
961 * \return The length of the data buffer.
965 * \fn ec_tagname_t CECTag::GetTagName(void) const
967 * \brief Returns TAGNAME.
969 * \return The name of the tag.
973 * \fn wxString CECTag::GetStringData(void) const
975 * \brief Returns the string data of the tag.
977 * Returns a wxString created from TAGDATA. It is automatically
978 * converted from UTF-8 to the internal application encoding.
979 * Should be used with care (only on tags created with the
980 * CECTag(ec_tagname_t, const wxString&) constructor),
981 * becuse it does not perform any check to see if the tag really contains a
982 * string object.
984 * \return The string data of the tag.
986 * \sa CECTag(ec_tagname_t, const wxString&)
990 * \fn uint8 CECTag::GetInt(void) const
992 * \brief Returns the uint8 data of the tag.
994 * This function takes care of the endianness problems with numbers.
996 * \return The uint8 data of the tag.
998 * \sa CECTag(ec_tagname_t, uint8)
1002 * \fn uint16 CECTag::GetInt(void) const
1004 * \brief Returns the uint16 data of the tag.
1006 * This function takes care of the endianness problems with numbers.
1008 * \return The uint16 data of the tag.
1010 * \sa CECTag(ec_tagname_t, uint16)
1014 * \fn uint32 CECTag::GetInt(void) const
1016 * \brief Returns the uint32 data of the tag.
1018 * This function takes care of the endianness problems with numbers.
1020 * \return The uint32 data of the tag.
1022 * \sa CECTag(ec_tagname_t, uint32)
1026 * \fn uint64 CECTag::GetInt(void) const
1028 * \brief Returns the uint64 data of the tag.
1030 * This function takes care of the endianness problems with numbers.
1032 * \return The uint64 data of the tag.
1034 * \sa CECTag(ec_tagname_t, uint64)
1037 uint32 CECID::s_IDCounter = 0;
1039 // File_checked_for_headers