2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS system libraries
4 * FILE: dll/win32/framedyn/chstring.cpp
5 * PURPOSE: CHString class implementation
6 * PROGRAMMERS: Pierre Schweitzer (pierre@reactos.org)
8 * NOTE: This implementation is BROKEN on PURPOSE
9 * The CHString is a mix between std::string and
10 * UNICODE_STRING. It appears that basically it takes only
11 * the worse from both approaches.
12 * I've copied the behavior and implementation of Windows 2k3 even if
13 * it implies unsafe, wrong or unefficient methods.
14 * Note that the string at m_pchData might not be null terminated!
15 * Also, important note, two (or even more) CHString instances might
16 * have the same m_pchData object! Never forget that while modifying
17 * a string. You might be modifying the string for everyone.
18 * This is why a protected method is being used in the code: CopyBeforeWrite
19 * It copies source first, to ensure we only modify current string
20 * Side note, all the sizes are actually a number of chars. Only the size
21 * for implementation is the number of bytes
22 * Now, you know why this class is deprecated and shouldn't be used
25 /* INCLUDES ******************************************************************/
31 /* PRIVATE FUNCTIONS *********************************************************/
33 // This is the empty string that defaults strings without text
34 // This is unsafe. This string show be LPCWSTR
35 // However we have to assign it to LPWSTR var. So, let's ignore about const,
36 // as MS does. Normally we check in our code that we don't overwrite this string.
37 LPWSTR afxPchNil
= (LPWSTR
)L
"\0";
38 // This is the data that are matching the null string upper
39 CHStringData afxNullData
= {0, 0, 0};
40 // Exception we may throw in case of allocation failure
41 CHeap_Exception
HeapException(CHeap_Exception::E_ALLOCATION_ERROR
);
43 // Our own delete operator
44 // It is here basically because MS guys don't known about set_new_handler()
46 void operator delete(void* ptr
)
48 // In Windows 2k3, they check for ptr being null.
49 // ISO, POSIX and even MSDN explains that it is allowed
50 // to call free with NULL pointer...
57 // Implement our own new operator so that we can throw our own exception in case
58 // of allocation failure.
59 // It could have been done using set_new_handler(), but well. MS guys didn't do it
60 // that way. So, let's mimic.
61 void* operator new(size_t uSize
)
65 Buffer
= malloc(uSize
);
74 // This is a char to wchar string conversion helper
75 int mbstowcsz(LPWSTR lpDest
, LPCSTR lpSrc
, int nLen
)
79 // If we have nothing to convert or if output doesn't exist, return
80 if (nLen
== 0 || lpDest
== 0)
85 // Then, simply convert
86 Conv
= MultiByteToWideChar(CP_ACP
, 0, lpSrc
, -1, lpDest
, nLen
);
87 // In case of conversion success, null terminate the string
96 /* PUBLIC FUNCTIONS **********************************************************/
103 // Set to empty string
104 m_pchData
= afxPchNil
;
110 CHString::CHString(WCHAR ch
, int nRepeat
) throw (CHeap_Exception
)
112 // Allow null initialize, in case something goes wrong
113 m_pchData
= afxPchNil
;
115 // If we have a char to insert
118 // Allocate a buffer big enough
119 AllocBuffer(nRepeat
);
120 // And if possible, repeat char
123 for (int i
= 0; i
< nRepeat
; ++i
)
134 CHString::CHString(LPCWSTR lpsz
) throw (CHeap_Exception
)
136 // Allow null initialize, in case something goes wrong
137 m_pchData
= afxPchNil
;
139 // If we have an input string
143 int Len
= SafeStrlen(lpsz
);
144 // Then, allocate a big enough buffer and copy string
145 // Note that here, we don't null terminate the string...
149 wcsncpy(m_pchData
, lpsz
, Len
);
157 CHString::CHString(LPCWSTR lpch
, int nLength
) throw (CHeap_Exception
)
159 // Allow null initialize, in case something goes wrong
160 m_pchData
= afxPchNil
;
162 // In case we have a string with a len
163 if (lpch
!= 0 && nLength
!= 0)
165 // Just copy the string
166 AllocBuffer(nLength
);
167 wcsncpy(m_pchData
, lpch
, nLength
);
174 CHString::CHString(LPCSTR lpsz
) throw (CHeap_Exception
)
176 // Allow null initialize, in case something goes wrong
177 m_pchData
= afxPchNil
;
179 // If we have input string
183 int Len
= strlen(lpsz
);
186 // Allocate and convert the string
188 mbstowcsz(m_pchData
, lpsz
, Len
+ 1);
189 // Releasing buffer here is to allow to
190 // update the buffer size. We notify we're
191 // done with changing the string: recompute its
201 CHString::CHString(const unsigned char* lpsz
)
205 // And call operator= with const char*, easier
206 *this = (LPCSTR
)lpsz
;
212 CHString::CHString(const CHString
& stringSrc
)
214 // If we have currently no referenced string
215 if (stringSrc
.GetData()->nRefs
< 0)
217 // Ensure we have the null string
218 m_pchData
= afxPchNil
;
219 // And then call, the copy operator with input string
220 *this = stringSrc
.m_pchData
;
224 // Otherwise, just copy the input string
225 m_pchData
= stringSrc
.m_pchData
;
226 // And increment the number of references
227 InterlockedIncrement(&GetData()->nRefs
);
228 // The whole point here is: Am I forget to release the old
229 // data?! MS doesn't release it, but I guess we should...
236 CHString::~CHString()
238 // If we have a string
239 if (GetData() != &afxNullData
)
241 // Check whether it's still in use after we release it
242 if (InterlockedDecrement(&GetData()->nRefs
) == 0)
253 void CHString::AllocBeforeWrite(int nLen
) throw (CHeap_Exception
)
255 // In case we have several strings pointing to our memory zone
256 // Or we need bigger buffer than actual
257 if (GetData()->nRefs
> 1 || nLen
> GetData()->nAllocLength
)
260 // And allocate a new one which is big enough
269 void CHString::AllocBuffer(int nSize
) throw (CHeap_Exception
)
271 // Here we have to allocate a buffer for the string
272 // It actually consists in: CHStringData structure
273 // with a buffer big enough at its end to store the
277 // Null size is easy allocation
280 m_pchData
= afxPchNil
;
284 // We cannot allow negative sizes
287 RaiseException(ERROR_INVALID_PARAMETER
, EXCEPTION_NONCONTINUABLE
, 0, 0);
293 RaiseException(STATUS_INTEGER_OVERFLOW
, EXCEPTION_NONCONTINUABLE
, 0, 0);
296 // Just allocate big enough buffer, using our own operator new
297 Data
= (CHStringData
*)operator new(nSize
* sizeof(WCHAR
) + sizeof(CHStringData
));
298 // In case Data is null, throw an exception
299 // Yes, this is stupid! Our operator new is already supposed to through an exception...
307 Data
->nDataLength
= nSize
;
308 Data
->nAllocLength
= nSize
;
311 // We only return the string
312 // We can find back data with some mathematics
313 m_pchData
= Data
->data();
319 void CHString::AllocCopy(CHString
& dest
, int nCopyLen
, int nCopyIndex
, int nExtraLen
) const throw (CHeap_Exception
)
321 // Once again, we cannot deal with negative lens
324 RaiseException(ERROR_INVALID_PARAMETER
, EXCEPTION_NONCONTINUABLE
, 0, 0);
329 RaiseException(ERROR_INVALID_PARAMETER
, EXCEPTION_NONCONTINUABLE
, 0, 0);
334 RaiseException(ERROR_INVALID_PARAMETER
, EXCEPTION_NONCONTINUABLE
, 0, 0);
337 // In case what we have to copy is null-sized, just set empty string
338 if (nCopyLen
+ nExtraLen
== 0)
340 dest
.m_pchData
= afxPchNil
;
344 // Otherwise, allocate a buffer in new string which is big enough
345 // You can note that we absolutely don't check about any existing
346 // (referenced) buffer in dest. Actually, dest is to be EMPTY string.
347 // The whole point of this function is to initialize a virgin string by
348 // copying data from another. This is needed by Left/Mid/Right
349 dest
.AllocBuffer(nCopyLen
+ nExtraLen
);
350 // And copy our stuff in
351 wcsncpy(dest
.m_pchData
, m_pchData
+ nCopyIndex
, nCopyLen
);
357 BSTR
CHString::AllocSysString() const throw (CHeap_Exception
)
361 // Just allocate the string
362 SysString
= SysAllocStringLen(m_pchData
, GetData()->nDataLength
);
374 void CHString::AssignCopy(int nSrcLen
, LPCWSTR lpszSrcData
) throw (CHeap_Exception
)
376 // Don't allow negative len
379 RaiseException(ERROR_INVALID_PARAMETER
, EXCEPTION_NONCONTINUABLE
, 0, 0);
382 // We will have to modify a string that might be shared, so duplicate it
383 // Ensuring it's big enough to contain our new stuff
384 AllocBeforeWrite(nSrcLen
);
391 // Just copy, write down new size, and ensure it's null terminated
392 wcsncpy(m_pchData
, lpszSrcData
, nSrcLen
);
393 GetData()->nDataLength
= nSrcLen
;
394 m_pchData
[nSrcLen
] = 0;
400 int CHString::Collate(LPCWSTR lpsz
) const
402 // Just call the deprecated function here - no matter we are null terminated
403 // Did you read my statement about how safe is this implementation?
404 return wcscoll(m_pchData
, lpsz
);
410 int CHString::Compare(LPCWSTR lpsz
) const
412 // Just call the deprecated function here - no matter we are null terminated
413 // Did you read my statement about how safe is this implementation?
414 return wcscmp(m_pchData
, lpsz
);
420 int CHString::CompareNoCase(LPCWSTR lpsz
) const
422 // Just call the deprecated function here - no matter we are null terminated
423 // Did you read my statement about how safe is this implementation?
424 return wcsicmp(m_pchData
, lpsz
);
430 void CHString::ConcatInPlace(int nSrcLen
, LPCWSTR lpszSrcData
)
432 // With null length, there's not that much to concat...
438 // Still no negative length
441 RaiseException(ERROR_INVALID_PARAMETER
, EXCEPTION_NONCONTINUABLE
, 0, 0);
444 // Ensure we wouldn't overflow with the concat
445 if (GetData()->nDataLength
+ nSrcLen
> INT_MAX
)
447 RaiseException(STATUS_INTEGER_OVERFLOW
, EXCEPTION_NONCONTINUABLE
, 0, 0);
450 // In case we have to modify a shared string OR if it can't fit into current buffer...
451 if (GetData()->nRefs
> 1 || GetData()->nDataLength
+ nSrcLen
> GetData()->nAllocLength
)
453 // Allocate a new buffer! (without forgetting to release old one)
454 CHStringData
* OldData
= GetData();
456 // You remember about "InPlace" in the function's name?
458 ConcatCopy(GetData()->nDataLength
, m_pchData
, nSrcLen
, lpszSrcData
);
463 // Ensure we don't overflow
464 if (nSrcLen
> INT_MAX
)
466 RaiseException(STATUS_INTEGER_OVERFLOW
, EXCEPTION_NONCONTINUABLE
, 0, 0);
469 // Then, just copy and null terminate
470 wcsncpy(m_pchData
+ GetData()->nDataLength
, lpszSrcData
, nSrcLen
);
471 GetData()->nDataLength
+= nSrcLen
;
472 m_pchData
[GetData()->nDataLength
] = 0;
479 void CHString::ConcatCopy(int nSrc1Len
, LPCWSTR lpszSrc1Data
, int nSrc2Len
, LPCWSTR lpszSrc2Data
) throw (CHeap_Exception
)
483 if (nSrc1Len
< 0 || nSrc2Len
< 0)
485 RaiseException(ERROR_INVALID_PARAMETER
, EXCEPTION_NONCONTINUABLE
, 0, 0);
488 // If both len are null, do nothing
489 TotalLen
= nSrc1Len
+ nSrc2Len
;
495 // Otherwise, allocate a new buffer to hold everything (caller will release previous buffer)
496 AllocBuffer(TotalLen
);
498 wcsncpy(m_pchData
, lpszSrc1Data
, nSrc1Len
);
499 wcsncpy(m_pchData
+ nSrc1Len
, lpszSrc2Data
, nSrc2Len
);
505 void CHString::CopyBeforeWrite() throw (CHeap_Exception
)
509 // First, we need to get reference count
510 // And we also need to save Data for later copy
513 if (Data
->nRefs
<= 1)
515 // If its not used, don't waste time to realloc, it will do the job
519 // Release current data - we are sure it won't be freed upon that point
520 // Thanks to the reference count check previously done
522 // Alloc new buffer and copy old data in it
523 AllocBuffer(Data
->nDataLength
);
524 wcsncpy(m_pchData
, Data
->data(), Data
->nDataLength
);
530 void CHString::Empty()
533 if (GetData()->nDataLength
== 0)
538 // Empty it easily given it's reference count
539 if (GetData()->nRefs
< 0)
545 // Otherwise, just release it
546 // It will set back this instance to afxPchNil
547 // while decreasing reference count
555 int CHString::Find(WCHAR ch
) const
559 // Let's use appropriate helper
560 Found
= wcschr(m_pchData
, ch
);
561 // We have to return a position, so compute it
564 return (Found
- m_pchData
);
567 // Otherwise, return no position
574 int CHString::Find(LPCWSTR lpszSub
) const
578 // Let's use appropriate helper
579 Found
= wcsstr(m_pchData
, lpszSub
);
580 // We have to return a position, so compute it
583 return (Found
- m_pchData
);
586 // Otherwise, return no position
593 int CHString::FindOneOf(LPCWSTR lpszCharSet
) const
597 // Let's use appropriate helper
598 Found
= wcspbrk(m_pchData
, lpszCharSet
);
599 // We have to return a position, so compute it
602 return (Found
- m_pchData
);
605 // Otherwise, return no position
612 void CHString::Format(UINT nFormatID
, ...) throw (CHeap_Exception
)
614 // Deprecated and not implemented any longer - well, this is its implementation
621 void CHString::Format(LPCWSTR lpszFormat
, ...) throw (CHeap_Exception
)
623 // Forward to FormatV
626 va_start(ArgsList
, lpszFormat
);
627 FormatV(lpszFormat
, ArgsList
);
634 void CHString::FormatMessageW(UINT nFormatID
, ...) throw (CHeap_Exception
)
636 // Deprecated and not implemented any longer - well, this is its implementation
643 void CHString::FormatMessageW(LPCWSTR lpszFormat
, ...) throw (CHeap_Exception
)
651 void CHString::FormatV(LPCWSTR lpszFormat
, va_list argList
)
659 void CHString::FreeExtra() throw (CHeap_Exception
)
661 CHStringData
* OldData
;
663 // No extra? Do nothing
664 if (GetData()->nDataLength
== GetData()->nAllocLength
)
671 // Allocate a new one, at the right size (with no place for \0 :-))
672 AllocBuffer(GetData()->nDataLength
);
673 // Copy old and release it
674 wcsncpy(m_pchData
, OldData
->data(), OldData
->nDataLength
);
681 int CHString::GetAllocLength() const
683 return GetData()->nAllocLength
;
689 WCHAR
CHString::GetAt(int nIndex
) const
691 // It's up to you to check the index!
692 return m_pchData
[nIndex
];
698 LPWSTR
CHString::GetBuffer(int nMinBufLength
) throw (CHeap_Exception
)
700 LPWSTR OldBuffer
= m_pchData
;
702 // We'll have to allocate a new buffer if it's not big enough
703 // or if it's shared by several strings
704 if (GetData()->nRefs
> 1 || GetData()->nAllocLength
< nMinBufLength
)
706 CHStringData
* OldData
= GetData();
707 int OldLen
= GetData()->nDataLength
;
709 // Ensure we can hold enough
710 if (OldLen
> nMinBufLength
)
712 nMinBufLength
= OldLen
;
715 // Allocate new buffer
716 AllocBuffer(nMinBufLength
);
718 wcsncpy(m_pchData
, OldBuffer
, OldLen
);
719 GetData()->nDataLength
= OldLen
;
725 // Weirdly, here Windows always returns the old buffer
726 // Which basically exposes a wrong buffer
733 LPWSTR
CHString::GetBufferSetLength(int nNewLength
) throw (CHeap_Exception
)
735 // Get a buffer big enough
736 // We don't care about the return, it will be set in the string
737 (void)GetBuffer(nNewLength
);
738 // Set length, null-terminate and return
739 GetData()->nDataLength
= nNewLength
;
740 m_pchData
[nNewLength
] = 0;
747 CHStringData
* CHString::GetData() const
749 // In case of empty string, return empty data
750 if (m_pchData
== afxPchNil
)
755 // Otherwise, do maths
756 return (CHStringData
*)((ULONG_PTR
)m_pchData
- sizeof(CHStringData
));
762 int CHString::GetLength() const
764 return GetData()->nDataLength
;
770 void CHString::Init()
772 m_pchData
= afxPchNil
;
778 BOOL
CHString::IsEmpty() const
780 return (GetData()->nDataLength
== 0);
786 CHString
CHString::Left(int nCount
) const throw (CHeap_Exception
)
790 // Validate input (we can't get more than what we have ;-))
793 if (nCount
> GetData()->nDataLength
)
795 nCount
= GetData()->nDataLength
;
799 AllocCopy(NewString
, nCount
, 0, 0);
807 int CHString::LoadStringW(UINT nID
) throw (CHeap_Exception
)
809 // Deprecated and not implemented any longer - well, this is its implementation
816 int CHString::LoadStringW(UINT nID
, LPWSTR lpszBuf
, UINT nMaxBuf
) throw (CHeap_Exception
)
818 // Deprecated and not implemented any longer - well, this is its implementation
825 LPWSTR
CHString::LockBuffer()
829 // The purpose here is basically to set the nRefs to max int
830 LockedBuffer
= GetBuffer(0);
831 GetData()->nRefs
= INT_MAX
;
839 void CHString::MakeLower() throw (CHeap_Exception
)
841 // We'll modify string, duplicate it first if needed
844 // Let's use appropriate helper
851 void CHString::MakeReverse() throw (CHeap_Exception
)
853 // We'll modify string, duplicate it first if needed
856 // Let's use appropriate helper
863 void CHString::MakeUpper() throw (CHeap_Exception
)
865 // We'll modify string, duplicate it first if needed
868 // Let's use appropriate helper
875 CHString
CHString::Mid(int nFirst
) const throw (CHeap_Exception
)
877 // Take string from nFirst up to the end
878 return Mid(nFirst
, GetData()->nDataLength
- nFirst
);
884 CHString
CHString::Mid(int nFirst
, int nCount
) const throw (CHeap_Exception
)
888 // Validate sizes first
899 // Ensure we don't go beyond the string
900 if (nFirst
+ nCount
> GetData()->nDataLength
)
902 nCount
= GetData()->nDataLength
- nFirst
;
905 // Also ensure we don't read beyond
906 // Yes, this should have been done before previous check
907 // MS does it that way
908 if (nFirst
> GetData()->nDataLength
)
913 AllocCopy(NewString
, nCount
, nFirst
, 0);
921 void CHString::Release()
923 // If null string, nothing to do
924 if (GetData() == &afxNullData
)
929 // Otherwise, decrement ref count and release if required
930 if (InterlockedDecrement(&GetData()->nRefs
) == 0)
935 // In all cases, caller doesn't want string anymore
936 // So, switch back to empty string
937 m_pchData
= afxPchNil
;
943 void WINAPI
CHString::Release(CHStringData
* pData
)
945 // If empty string, ignore
946 if (pData
== &afxNullData
)
951 // Otherwise, simply and free if needed
952 if (InterlockedDecrement(&pData
->nRefs
) == 0)
961 void CHString::ReleaseBuffer(int nNewLength
) throw (CHeap_Exception
)
965 // We'll modify buffer, so duplicate
968 // If no len provided, get one
969 if (nNewLength
== -1)
971 nNewLength
= wcslen(m_pchData
);
974 // Set appropriate size and null-terminate
976 Data
->nDataLength
= nNewLength
;
977 Data
->data()[nNewLength
] = 0;
983 int CHString::ReverseFind(WCHAR ch
) const
987 // Let's use appropriate helper
988 Last
= wcsrchr(m_pchData
, ch
);
989 // We have to return a position, so compute it
992 return (Last
- m_pchData
);
995 // Otherwise, return no position
1002 CHString
CHString::Right(int nCount
) const throw (CHeap_Exception
)
1006 // Validate input (we can't get more than what we have ;-))
1009 if (nCount
> GetData()->nDataLength
)
1011 nCount
= GetData()->nDataLength
;
1015 AllocCopy(NewString
, nCount
, GetData()->nDataLength
- nCount
, 0);
1023 int CHString::SafeStrlen(LPCWSTR lpsz
)
1025 // Check we have a string and then get its length
1031 // Of course, it's not safe at all in case string is not null-terminated.
1032 // Things that may happen given strings are not to be null-terminated
1034 return (int)wcslen(lpsz
);
1040 void CHString::SetAt(int nIndex
, WCHAR ch
) throw (CHeap_Exception
)
1044 m_pchData
[nIndex
] = ch
;
1050 CHString
CHString::SpanExcluding(LPCWSTR lpszCharSet
) const throw (CHeap_Exception
)
1054 // Get position and then, extract
1055 Count
= wcscspn(m_pchData
, lpszCharSet
);
1062 CHString
CHString::SpanIncluding(LPCWSTR lpszCharSet
) const throw (CHeap_Exception
)
1066 // Get position and then, extract
1067 Count
= wcsspn(m_pchData
, lpszCharSet
);
1074 void CHString::TrimLeft() throw (CHeap_Exception
)
1080 // We'll modify, so copy first
1083 // Start at the begin of the string
1084 CurrentChar
= m_pchData
;
1085 while (*CurrentChar
!= 0)
1087 // Browse string till we find something which is not a space
1088 if (!iswspace(*CurrentChar
))
1096 // Then, calculate new begin (easy) and new length
1098 NewBegin
= (CurrentChar
- m_pchData
);
1099 NewLength
= GetData()->nDataLength
- NewBegin
;
1100 memmove(m_pchData
, CurrentChar
, NewLength
* sizeof(WCHAR
));
1101 GetData()->nDataLength
= NewLength
;
1107 void CHString::TrimRight() throw (CHeap_Exception
)
1112 // We'll modify, so copy first
1115 // Start at the begin of the string -- WHAT?!
1116 // Yes, this algorithm is the same that MS is
1117 // using for its TrimRight.
1118 // It is highly unefficient. It would have been
1119 // easier to start at nDataLength and to get back to
1120 // the begin. Note that it would have been safer as
1121 // well, in case the caller is using non-null-terminated
1122 // strings. But, well...
1123 CurrentChar
= m_pchData
;
1125 while (*CurrentChar
!= 0)
1127 // If not a space, reset what we can trim
1128 if (!iswspace(*CurrentChar
))
1132 // If it is one, and the first of the spaces serie
1133 // Keep its position
1134 else if (CanBeEaten
== 0)
1136 CanBeEaten
= CurrentChar
;
1142 // If nothing to trim, quit
1143 if (CanBeEaten
== 0)
1148 // Otherwise, shorten the string
1149 GetData()->nDataLength
= (CanBeEaten
- m_pchData
);
1155 void CHString::UnlockBuffer()
1157 // Unlock means just put ref back to 1
1158 // It was previously set to MAX_INT
1159 if (GetData() != &afxNullData
)
1161 GetData()->nRefs
= 1;
1168 const CHString
& CHString::operator=(char ch
) throw (CHeap_Exception
)
1177 const CHString
& CHString::operator=(WCHAR ch
) throw (CHeap_Exception
)
1186 const CHString
& CHString::operator=(CHString
*p
) throw (CHeap_Exception
)
1195 const CHString
& CHString::operator=(LPCSTR lpsz
) throw (CHeap_Exception
)
1199 // If we have string, get its len
1209 // Do this call, even with null len, just to get empty string
1210 AllocBeforeWrite(Len
);
1218 mbstowcsz(m_pchData
, lpsz
, Len
+ 1);
1219 // Get new size and so on
1228 const CHString
& CHString::operator=(LPCWSTR lpsz
) throw (CHeap_Exception
)
1232 Len
= SafeStrlen(lpsz
);
1233 AssignCopy(Len
, lpsz
);
1241 const CHString
& CHString::operator=(const CHString
& stringSrc
) throw (CHeap_Exception
)
1243 // Don't copy string on itself
1244 if (&stringSrc
== this)
1249 // In case we don't have a referenced string here,
1250 // or if the other is not referenced, just copy here
1251 if ((GetData()->nRefs
< 0 && GetData() != &afxNullData
) ||
1252 stringSrc
.GetData()->nRefs
< 0)
1254 AssignCopy(stringSrc
.GetData()->nDataLength
, stringSrc
.m_pchData
);
1258 // Otherwise, release current buffer
1260 // And set buffer as stringSrc buffer
1261 // And increase its reference count
1262 m_pchData
= stringSrc
.m_pchData
;
1263 InterlockedIncrement(&GetData()->nRefs
);
1271 const CHString
& CHString::operator=(const unsigned char* lpsz
) throw (CHeap_Exception
)
1273 *this = (LPCSTR
)lpsz
;
1280 const CHString
& CHString::operator+=(char ch
) throw (CHeap_Exception
)
1289 const CHString
& CHString::operator+=(WCHAR ch
) throw (CHeap_Exception
)
1291 ConcatInPlace(1, &ch
);
1298 const CHString
& CHString::operator+=(LPCWSTR lpsz
) throw (CHeap_Exception
)
1302 Len
= SafeStrlen(lpsz
);
1303 ConcatInPlace(Len
, lpsz
);
1311 const CHString
& CHString::operator+=(const CHString
& string
) throw (CHeap_Exception
)
1313 ConcatInPlace(string
.GetData()->nDataLength
, string
.m_pchData
);
1321 WCHAR
CHString::operator[](int nIndex
) const
1323 return m_pchData
[nIndex
];
1329 CHString::operator LPCWSTR() const
1337 CHString WINAPI
operator+(WCHAR ch
, const CHString
& string
) throw (CHeap_Exception
)
1341 // Basically concat in a new string
1342 NewString
.ConcatCopy(1, &ch
, string
.GetData()->nDataLength
, string
.m_pchData
);
1350 CHString WINAPI
operator+(const CHString
& string
, WCHAR ch
) throw (CHeap_Exception
)
1354 // Basically concat in a new string
1355 NewString
.ConcatCopy(string
.GetData()->nDataLength
, string
.m_pchData
, 1, &ch
);
1363 CHString WINAPI
operator+(const CHString
& string
, LPCWSTR lpsz
) throw (CHeap_Exception
)
1368 // Get string length
1369 Len
= CHString::SafeStrlen(lpsz
);
1370 // And concat in new string
1371 NewString
.ConcatCopy(string
.GetData()->nDataLength
, string
.m_pchData
, Len
, lpsz
);
1379 CHString WINAPI
operator+(LPCWSTR lpsz
, const CHString
& string
) throw (CHeap_Exception
)
1384 // Get string length
1385 Len
= CHString::SafeStrlen(lpsz
);
1386 // And concat in new string
1387 NewString
.ConcatCopy(Len
, lpsz
, string
.GetData()->nDataLength
, string
.m_pchData
);
1395 CHString WINAPI
operator+(const CHString
& string1
, const CHString
& string2
) throw (CHeap_Exception
)
1399 // Basically concat in a new string
1400 NewString
.ConcatCopy(string1
.GetData()->nDataLength
, string1
.m_pchData
,
1401 string2
.GetData()->nDataLength
, string2
.m_pchData
);