|
reSIProcate/rutil
9694
|
00001 #ifndef RESIP_Data_hxx 00002 #define RESIP_Data_hxx 00003 00004 #ifdef HAVE_CONFIG_H 00005 #include "config.h" 00006 #endif 00007 00008 #include <iostream> 00009 #include <string> 00010 #include <bitset> 00011 #include <cassert> 00012 00013 #include "rutil/compat.hxx" 00014 #include "rutil/DataStream.hxx" 00015 #include "rutil/HeapInstanceCounter.hxx" 00016 #include "rutil/HashMap.hxx" 00017 00018 #ifndef RESIP_DATA_LOCAL_SIZE 00019 #define RESIP_DATA_LOCAL_SIZE 16 00020 #endif 00021 00022 class TestData; 00023 namespace resip 00024 { 00025 00038 template <int S> 00039 struct DataLocalSize 00040 { 00041 explicit DataLocalSize(size_t) {} 00042 }; 00043 00044 // .bwc. Pack class Data; has to come before doxygen block though. 00045 #pragma pack(4) 00046 00086 class Data 00087 { 00088 public: 00089 RESIP_HeapCount(Data); 00090 00091 typedef UInt32 size_type; 00092 00093 inline Data() 00094 : mBuf(mPreBuffer), 00095 mSize(0), 00096 mCapacity(LocalAlloc), 00097 mShareEnum(Borrow) 00098 { 00099 mBuf[mSize] = 0; 00100 } 00101 00105 class PreallocateType 00106 { 00107 friend class Data; 00108 explicit PreallocateType(int); 00109 }; 00113 static const PreallocateType Preallocate; 00114 00125 Data(size_type capacity, const PreallocateType&); 00126 00127 //#define DEPRECATED_PREALLOC 00128 #ifdef DEPRECATED_PREALLOC 00129 00148 Data(size_type capacity, bool foo); 00149 #endif 00150 00158 Data(const char* str); 00159 00165 Data(const char* buffer, size_type length); 00166 00172 Data(const unsigned char* buffer, size_type length); 00173 00174 Data(const Data& data); 00175 00176 #ifdef RESIP_HAS_RVALUE_REFS 00177 Data(Data &&data); 00178 #endif 00179 00182 explicit Data(const std::string& str); 00183 00190 explicit Data(int value); 00191 00198 explicit Data(unsigned long value); 00199 00206 explicit Data(unsigned int value); 00207 00214 explicit Data(UInt64 value); 00215 00216 #ifndef RESIP_FIXED_POINT 00217 enum DoubleDigitPrecision 00218 { 00219 ZeroDigitPrecision = 0, OneDigitPrecision, 00220 TwoDigitPrecision, ThreeDigitPrecision, 00221 FourDigitPrecision, FiveDigitPrecision, 00222 SixDigitPrecision, SevenDigitPrecision, 00223 EightDigitPrecision, NineDigitPrecision, 00224 TenDigitPrecision, MaxDigitPrecision 00225 }; 00235 explicit Data(double value, 00236 Data::DoubleDigitPrecision precision = FourDigitPrecision); 00237 #endif 00238 00243 explicit Data(bool value); 00244 00249 explicit Data(char c); 00250 00254 enum ShareEnum 00255 { 00260 Borrow=0, 00261 00266 Share=1, 00267 00272 Take=2 00273 }; 00274 00281 Data(ShareEnum, const char* buffer, size_type length); 00282 00291 Data(ShareEnum, const char* buffer); 00292 00306 Data(ShareEnum, const Data& staticData); // Cannot call with 'Take' 00307 00308 inline ~Data() 00309 { 00310 if (mShareEnum == Take) 00311 { 00312 delete[] mBuf; 00313 } 00314 } 00315 00327 Data& setBuf(ShareEnum se, const char *buf, size_type length); 00328 00333 Data& setBuf(ShareEnum se, const char *str) 00334 { 00335 return setBuf(se, str, (size_type)strlen(str)); 00336 }; 00337 00338 00346 Data& takeBuf(Data& other); 00347 00358 Data& copy(const char *buf, size_type length); 00359 00375 char* getBuf(size_type length); 00376 00381 template<class T> 00382 static Data from(const T& x) 00383 { 00384 Data d; 00385 { 00386 DataStream s(d); 00387 s << x; 00388 } 00389 return d; 00390 } 00391 00392 friend bool operator==(const Data& lhs, const Data& rhs); 00393 friend bool operator==(const Data& lhs, const char* rhs); 00394 00395 friend bool operator<(const Data& lhs, const Data& rhs); 00396 friend bool operator<(const Data& lhs, const char* rhs); 00397 friend bool operator<(const char* lhs, const Data& rhs); 00398 00399 Data& operator=(const Data& data) 00400 { 00401 if (&data==this) 00402 return *this; 00403 return copy(data.mBuf,data.mSize); 00404 } 00405 00406 #ifdef RESIP_HAS_RVALUE_REFS 00407 Data& operator=(Data &&data); 00408 #endif 00409 00418 Data& operator=(const char* str) 00419 { 00420 return copy(str, (size_type)strlen(str)); 00421 } 00422 00426 Data operator+(const Data& rhs) const; 00427 00434 Data operator+(const char* str) const; 00435 00439 Data operator+(char c) const; 00440 00444 inline Data& operator+=(const Data& rhs) 00445 { 00446 return append(rhs.data(), rhs.size()); 00447 } 00448 00456 inline Data& operator+=(const char* str) 00457 { 00458 assert(str); 00459 return append(str, (size_type)strlen(str)); 00460 } 00461 00462 00466 inline Data& operator+=(char c) 00467 { 00468 return append(&c, 1); 00469 } 00470 00471 00478 Data& operator^=(const Data& rhs); 00479 00484 inline char& operator[](size_type p) 00485 { 00486 assert(p < mSize); 00487 own(); 00488 return mBuf[p]; 00489 } 00490 00494 inline char operator[](size_type p) const 00495 { 00496 assert(p < mSize); 00497 return mBuf[p]; 00498 } 00499 00503 char& at(size_type p); 00504 00510 void reserve(size_type capacity); 00511 00516 Data& append(const char* str, size_type len); 00517 00529 size_type truncate(size_type len); 00530 00538 Data& truncate2(size_type len); 00539 00543 bool empty() const { return mSize == 0; } 00544 00551 size_type size() const { return mSize; } 00552 00560 inline const char* data() const 00561 { 00562 return mBuf; 00563 } 00564 00577 const char* c_str() const; 00578 00582 inline const char* begin() const 00583 { 00584 return mBuf; 00585 } 00586 00590 inline const char* end() const 00591 { 00592 return mBuf + mSize; 00593 } 00594 00595 typedef enum 00596 { 00597 BINARY, 00598 BASE64, 00599 HEX 00600 } EncodingType; 00601 00607 Data md5(EncodingType type=HEX) const; 00608 00614 Data& lowercase(); 00615 00621 Data& uppercase(); 00622 00637 Data& schemeLowercase(); 00638 00643 Data hex() const; 00644 00652 Data escaped() const; 00653 00665 Data charEncoded() const; 00666 00681 Data charUnencoded() const; 00682 00686 Data urlEncoded() const; 00687 00691 Data urlDecoded() const; 00692 00696 EncodeStream& urlEncode(EncodeStream& s) const; 00697 00701 EncodeStream& urlDecode(EncodeStream& s) const; 00702 00706 Data xmlCharDataEncode() const; 00707 00711 Data xmlCharDataDecode() const; 00712 00716 EncodeStream& xmlCharDataEncode(EncodeStream& s) const; 00717 00721 EncodeStream& xmlCharDataDecode(EncodeStream& s) const; 00722 00728 Data trunc(size_type trunc) const; 00729 00735 Data& clear() { return truncate2(0); }; 00736 00743 int convertInt() const; 00744 unsigned long convertUnsignedLong() const; 00745 00751 size_t convertSize() const; 00752 00753 #ifndef RESIP_FIXED_POINT 00754 00761 double convertDouble() const; 00762 #endif 00763 00769 UInt64 convertUInt64() const; 00770 00777 bool prefix(const Data& pre) const; 00778 00785 bool postfix(const Data& post) const; 00786 00793 Data substr(size_type first, size_type count = Data::npos) const; 00794 00804 size_type find(const Data& match, size_type start = 0) const; 00805 00810 int replace(const Data& match, const Data& target, int max=INT_MAX); 00811 00815 static const Data Empty; 00816 00820 static const size_type npos; 00821 00827 static bool init(DataLocalSize<RESIP_DATA_LOCAL_SIZE> arg); 00828 00834 Data base64decode() const; 00835 00841 Data base64encode(bool useUrlSafe=false) const; 00842 00850 static size_t rawHash(const unsigned char* c, size_t size); 00851 00855 size_t hash() const; 00856 00864 static size_t rawCaseInsensitiveHash(const unsigned char* c, size_t size); 00865 00875 static size_t rawCaseInsensitiveTokenHash(const unsigned char* c, size_t size); 00876 00881 size_t caseInsensitivehash() const; 00882 00889 size_t caseInsensitiveTokenHash() const; 00890 00891 inline bool caseInsensitiveTokenCompare(const Data& rhs) const 00892 { 00893 if(mSize==rhs.mSize) 00894 { 00895 return sizeEqualCaseInsensitiveTokenCompare(rhs); 00896 } 00897 return false; 00898 } 00899 00900 bool sizeEqualCaseInsensitiveTokenCompare(const Data& rhs) const; 00901 00907 static std::bitset<256> toBitset(const resip::Data& chars); 00908 00923 template<class Predicate> EncodeStream& 00924 escapeToStream(EncodeStream& str, 00925 Predicate shouldEscape) const; 00926 00935 std::ostream& escapeToStream(std::ostream& str, 00936 const std::bitset<256>& shouldEscape) const; 00937 00938 private: 00942 Data(const char* buffer, size_type length, bool); 00943 00948 void own() const; 00949 00953 void resize(size_type newSize, bool copy); 00954 00955 static bool isHex(unsigned char c); 00956 00960 enum {LocalAlloc = RESIP_DATA_LOCAL_SIZE }; 00961 00962 char* mBuf; 00963 size_type mSize; 00964 size_type mCapacity; 00965 char mPreBuffer[LocalAlloc]; 00966 // Null terminator for mPreBuffer when mSize==LocalAlloc lands here; this 00967 // is ok, because Borrow==0. 00968 // Note: we could use a char here, and expand mPreBuffer by 3 bytes, but 00969 // this imposes a performance penalty since it requires operating on a 00970 // memory location smaller than a word (requires masking and such). 00971 size_type mShareEnum; 00972 00973 friend std::ostream& operator<<(std::ostream& strm, const Data& d); 00974 #ifndef RESIP_USE_STL_STREAMS 00975 friend EncodeStream& operator<<(EncodeStream& strm, const Data& d); 00976 #endif 00977 friend class ParseBuffer; 00978 friend class DataBuffer; 00979 friend class DataStream; 00980 friend class oDataStream; 00981 friend class ::TestData; 00982 friend class MD5Buffer; 00983 }; 00984 // reset alignment to default 00985 #pragma pack() 00986 00987 00988 class DataHelper { 00989 public: 00990 static const bool isCharHex[256]; 00991 }; 00992 00993 static bool invokeDataInit = Data::init(DataLocalSize<RESIP_DATA_LOCAL_SIZE>(0)); 00994 00995 inline bool Data::isHex(unsigned char c) 00996 { 00997 return DataHelper::isCharHex[c]; 00998 } 00999 01000 inline bool isEqualNoCase(const Data& left, const Data& right) 01001 { 01002 return ( (left.size() == right.size()) && 01003 (strncasecmp(left.data(), right.data(), left.size()) == 0) ); 01004 } 01005 01006 inline bool isTokenEqualNoCase(const Data& left, const Data& right) 01007 { 01008 return left.caseInsensitiveTokenCompare(right); 01009 } 01010 01011 inline bool isLessThanNoCase(const Data& left, const Data& right) 01012 { 01013 size_t minsize = resipMin( left.size(), right.size() ); 01014 int res = strncasecmp(left.data(), right.data(), minsize); 01015 01016 if (res < 0) 01017 { 01018 return true; 01019 } 01020 else if (res > 0) 01021 { 01022 return false; 01023 } 01024 else 01025 { 01026 return left.size() < right.size(); 01027 } 01028 } 01029 01030 template<class Predicate> EncodeStream& 01031 Data::escapeToStream(EncodeStream& str, Predicate shouldEscape) const 01032 { 01033 static char hex[] = "0123456789ABCDEF"; 01034 01035 if (empty()) 01036 { 01037 return str; 01038 } 01039 01040 const unsigned char* p = (unsigned char*)mBuf; 01041 const unsigned char* e = (unsigned char*)mBuf + mSize; 01042 01043 while (p < e) 01044 { 01045 // ?abr? Why is this special cased? Removing this code 01046 // does not change the behavior of this method. 01047 if (*p == '%' 01048 && e - p > 2 01049 && isHex(*(p+1)) 01050 && isHex(*(p+2))) 01051 { 01052 str.write((char*)p, 3); 01053 p+=3; 01054 } 01055 else if (shouldEscape[*p]) 01056 { 01057 int hi = (*p & 0xF0)>>4; 01058 int low = (*p & 0x0F); 01059 01060 str << '%' << hex[hi] << hex[low]; 01061 p++; 01062 } 01063 else 01064 { 01065 str.put(*p++); 01066 } 01067 } 01068 return str; 01069 } 01070 01071 inline bool operator!=(const Data& lhs, const Data& rhs) { return !(lhs == rhs); } 01072 inline bool operator>(const Data& lhs, const Data& rhs) { return rhs < lhs; } 01073 inline bool operator<=(const Data& lhs, const Data& rhs) { return !(rhs < lhs); } 01074 inline bool operator>=(const Data& lhs, const Data& rhs) { return !(lhs < rhs); } 01075 inline bool operator!=(const Data& lhs, const char* rhs) { return !(lhs == rhs); } 01076 inline bool operator>(const Data& lhs, const char* rhs) { return rhs < lhs; } 01077 inline bool operator<=(const Data& lhs, const char* rhs) { return !(rhs < lhs); } 01078 inline bool operator>=(const Data& lhs, const char* rhs) { return !(lhs < rhs); } 01079 inline bool operator==(const char* lhs, const Data& rhs) { return rhs == lhs; } 01080 inline bool operator!=(const char* lhs, const Data& rhs) { return !(rhs == lhs); } 01081 inline bool operator>(const char* lhs, const Data& rhs) { return rhs < lhs; } 01082 inline bool operator<=(const char* lhs, const Data& rhs) { return !(rhs < lhs); } 01083 inline bool operator>=(const char* lhs, const Data& rhs) { return !(lhs < rhs); } 01084 #ifndef RESIP_USE_STL_STREAMS 01085 EncodeStream& operator<<(EncodeStream& strm, const Data& d); 01086 #endif 01087 inline std::ostream& operator<<(std::ostream& strm, const Data& d) 01088 { 01089 return strm.write(d.mBuf, d.mSize); 01090 } 01091 01092 01093 inline Data 01094 operator+(const char* c, const Data& d) 01095 { 01096 return Data(c) + d; 01097 } 01098 01099 } 01100 01101 HashValue(resip::Data); 01102 01103 #endif 01104 01105 /* ==================================================================== 01106 * The Vovida Software License, Version 1.0 01107 * 01108 * Copyright (c) 2000 Vovida Networks, Inc. All rights reserved. 01109 * 01110 * Redistribution and use in source and binary forms, with or without 01111 * modification, are permitted provided that the following conditions 01112 * are met: 01113 * 01114 * 1. Redistributions of source code must retain the above copyright 01115 * notice, this list of conditions and the following disclaimer. 01116 * 01117 * 2. Redistributions in binary form must reproduce the above copyright 01118 * notice, this list of conditions and the following disclaimer in 01119 * the documentation and/or other materials provided with the 01120 * distribution. 01121 * 01122 * 3. The names "VOCAL", "Vovida Open Communication Application Library", 01123 * and "Vovida Open Communication Application Library (VOCAL)" must 01124 * not be used to endorse or promote products derived from this 01125 * software without prior written permission. For written 01126 * permission, please contact vocal@vovida.org. 01127 * 01128 * 4. Products derived from this software may not be called "VOCAL", nor 01129 * may "VOCAL" appear in their name, without prior written 01130 * permission of Vovida Networks, Inc. 01131 * 01132 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED 01133 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 01134 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND 01135 * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL VOVIDA 01136 * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES 01137 * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL, 01138 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 01139 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 01140 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 01141 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 01142 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE 01143 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH 01144 * DAMAGE. 01145 * 01146 * ==================================================================== 01147 * 01148 * This software consists of voluntary contributions made by Vovida 01149 * Networks, Inc. and many individuals on behalf of Vovida Networks, 01150 * Inc. For more information on Vovida Networks, Inc., please see 01151 * <http://www.vovida.org/>. 01152 * 01153 * vi: set shiftwidth=3 expandtab: 01154 */
1.7.5.1