/*++ Copyright (c) Microsoft Corporation. All rights reserved. Module Name: INFSCAN safestring.h Abstract: Define SafeString<> template SafeString is our alternative to basic_string as basic_string is not thread-safe a basic_string can be obtained from SafeString and vice-versa History: Created July 2001 - JamieHun --*/ #ifndef _INFSCAN_SAFESTRING_H_ #define _INFSCAN_SAFESTRING_H_ #include template > class SafeString_ { typedef SafeString_<_E, _Tr> _Myt; _E* pData; size_t nLen; // // safe ref-counting // long & RefCount(_E* p) { return reinterpret_cast(p)[-1]; } void IncRef(_E* p) { if(p) { InterlockedIncrement(&RefCount(p)); } } void DecRef(_E* p) { if(p && (InterlockedDecrement(&RefCount(p))==0)) { // // if this is the final release, delete // FreeString(p); } } _E* AllocString(size_t len) { // // allocate enough data for the refcount, the data // and terminating NULL // return pointer to data part // LPBYTE data = new BYTE[((len+1)*sizeof(_E)+sizeof(long))]; return reinterpret_cast<_E*>(data+sizeof(long)); } void FreeString(_E* p) { if(p) { // // translate to actual allocated data and delete // delete [] (reinterpret_cast(p)-sizeof(long)); } } void Erase() { // // release data (final release deletes) // DecRef(pData); pData = NULL; nLen = 0; } void Init(const _E* p,size_t len) { // // create a new string given pointer to string and length // if(!len) { Erase(); } else { pData = AllocString(len); RefCount(pData)=1; _Tr::copy(pData,p,len); nLen = len; pData[nLen] = 0; } } void Init(const _E* p) { // // in this case, length is not known and p may be NULL // if(!p) { Erase(); } else { Init(p,_Tr::length(p)); } } void Copy(const _E *p) { // // copy, in the case where length is not known // if(p && p[0]) { _E *old = pData; Init(p); DecRef(old); } else { Erase(); } } void Copy(const _E *p,size_t len) { // // copy in the case where length is known // if(len) { _E *old = pData; Init(p,len); DecRef(old); } else { Erase(); } } void Copy(const _Myt & other) { // // don't need to do byte copy, just add a ref to original string // if(other.nLen) { _E *old = pData; IncRef(other.pData); pData = other.pData; nLen = other.nLen; DecRef(old); } else { Erase(); } } void Copy(const std::basic_string<_E,_Tr> & other) { // // copying from basic string, need to make copy of actual data // in this case // if(other.length()) { _E *old = pData; Init(other.c_str(),other.length()); DecRef(old); } else { Erase(); } } void Concat(const _E *first,size_t flen,const _E *second,size_t slen) { // // concat second to end of first, both lengths known // if(flen && slen) { _E *old = pData; pData = AllocString(flen+slen); RefCount(pData)=1; _Tr::copy(pData,first,flen); _Tr::copy(pData+flen,second,slen); nLen=flen+slen; pData[nLen] = 0; DecRef(old); } else if(flen) { Init(first,flen); } else if(slen) { Init(second,slen); } else { Erase(); } } void Concat(const _E *first,size_t flen,const _E *second) { // // concat second to end of first. // second length not known and pointer may be null // if(second) { Concat(first,flen,second,_Tr::length(second)); } else { Init(first,flen); } } public: SafeString_() { // // Initializer, create empty string // pData = NULL; nLen = 0; } SafeString_(const _E *p) { // // Initializer, given LPCxSTR // pData = NULL; Copy(p); } SafeString_(const _E *p,size_t len) { // // Initializer, given LPCxSTR and length // pData = NULL; Copy(p,len); } SafeString_(const _Myt & other) { // // Initializer, refcount other string // pData = NULL; Copy(other); } SafeString_(const std::basic_string<_E,_Tr> & other) { // // Initializer, copy from basic_string // pData = NULL; Copy(other); } ~SafeString_() { // // destructor, delete(deref) string // Erase(); } _Myt & operator =(const _E *p) { // // assignment // Copy(p); return *this; } _Myt & operator =(const _Myt & other) { // // assignment // Copy(other); return *this; } _Myt & operator =(const std::basic_string<_E,_Tr> & other) { // // assignment // Copy(other); return *this; } _Myt & operator +=(const _E *p) { // // append. If p is NULL, do nothing // if(p) { if(nLen) { Concat(pData,nLen,p); } else { Copy(p); } } return *this; } _Myt & operator +=(const _Myt & other) { // // append // if(other.nLen) { if(nLen) { Concat(pData,nLen,other.c_str(),other.nLen); } else { Copy(other); } } return *this; } _Myt & operator +=(const std::basic_string<_E,_Tr> & other) { // // append // if(other.length()) { if(nLen) { Concat(pData,nLen,other.c_str(),other.length()); } else { Copy(other); } } return *this; } _Myt operator +(const _E *p) const { // // concat into new, or copy (left native) // if(p) { if(nLen) { _Myt n; n.Concat(pData,nLen,p); return n; } else { return _Myt(p); } } else { return *this; } } _Myt operator +(const _Myt & other) const { // // concat into new, or copy (left native) // if(other.nLen) { if(nLen) { _Myt n; n.Concat(pData,nLen,other.c_str(),other.nLen); return n; } else { return other; } } else { return *this; } } _Myt operator +(const std::basic_string<_E,_Tr> & other) const { // // concat into new, or copy (left native) // if(other.length()) { if(nLen) { _Myt n; n.Concat(pData,nLen,other.c_str(),other.length()); return n; } else { return _Myt(other); } } else { return *this; } } friend _Myt operator +(const _E *first,const _Myt & second) { // // concat where left is not native but right is // if(first) { _Myt n; n.Concat(first,_Tr::length(first),second.c_str(),second.length()); return n; } else { return second; } } friend _Myt operator +(const std::basic_string<_E,_Tr> & first,const _Myt & second) { // // concat where left is not native but right is // if(first.length()) { _Myt n; n.Concat(first.c_str(),first.length(),second.c_str(),second.length()); return n; } else { return second; } } int compare(const _Myt & other) const { // // compare this string with another string // (force other string into SafeString if needed) // int sz = min(nLen,other.nLen); if(sz) { int cmp = _Tr::compare(pData,other.pData,sz); if(cmp != 0) { return cmp; } } if(nLenother.nLen) { return 1; } else { return 0; } } bool operator < (const _Myt & other) const { // // specific compare // return compare(other)<0; } bool operator > (const _Myt & other) const { // // specific compare // return compare(other)>0; } bool operator == (const _Myt & other) const { // // specific compare // return compare(other)==0; } operator const _E* () const { // // natively convert to LPCxSTR if needed // (temporary string) // return pData; } const _E & operator[](unsigned int pos) const { // // index into string (unsigned) // return pData[pos]; } const _E & operator[](int pos) const { // // index into string (signed) // return pData[pos]; } bool empty(void) const { // // return true if empty // return nLen==0; } const _E* c_str(void) const { // // explicit conversion to LPCxSTR // (temporary string) // return pData; } size_t length(void) const { // // length of string // return nLen; } _Myt substr(size_t base,size_t len = (size_t)(-1)) const { // // part of string // unless it returns the full string, creates new string // if(base>=nLen) { base = 0; len = 0; } else { len = min(len,nLen-base); } if(len == 0) { // // returns empty string // return SafeString(); } else if(len == nLen) { // // returns full string // return *this; } else { // // returns literal copy of part of string // return SafeString(pData+base,len); } } }; // // ostream/istream helpers // template inline basic_ostream<_E, _Tr>& __cdecl operator<<( basic_ostream<_E, _Tr>& Output, const SafeString_<_E, _Tr>& Str) { size_t i; size_t len = Str.length(); const _E* data = Str.c_str(); for (i = 0; i < len; i++,data++) { if (_Tr::eq_int_type(_Tr::eof(),Output.rdbuf()->sputc(*data))) { break; } } return Output; } // // 3 variations of SafeString // typedef SafeString_ SafeString; typedef SafeString_ SafeStringA; typedef SafeString_ SafeStringW; #endif //!_INFSCAN_SAFESTRING_H_