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