You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
506 lines
12 KiB
506 lines
12 KiB
/*++
|
|
|
|
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 <string>
|
|
|
|
template<class _E,
|
|
class _Tr = std::char_traits<_E> >
|
|
class SafeString_ {
|
|
|
|
typedef SafeString_<_E, _Tr> _Myt;
|
|
_E* pData;
|
|
size_t nLen;
|
|
|
|
//
|
|
// safe ref-counting
|
|
//
|
|
long & RefCount(_E* p) {
|
|
return reinterpret_cast<long*>(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<BYTE*>(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(nLen<other.nLen) {
|
|
return -1;
|
|
} else if(nLen>other.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<class _E, class _Tr> 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_<TCHAR> SafeString;
|
|
typedef SafeString_<CHAR> SafeStringA;
|
|
typedef SafeString_<WCHAR> SafeStringW;
|
|
|
|
#endif //!_INFSCAN_SAFESTRING_H_
|
|
|