3b43c456cb7c0da8b78e44adb015e58a31ca5b1c
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...
58 void __cdecl
operator delete(void* ptr
, unsigned int)
60 // In Windows 2k3, they check for ptr being null.
61 // ISO, POSIX and even MSDN explains that it is allowed
62 // to call free with NULL pointer...
70 // Implement our own new operator so that we can throw our own exception in case
71 // of allocation failure.
72 // It could have been done using set_new_handler(), but well. MS guys didn't do it
73 // that way. So, let's mimic.
74 void* operator new(size_t uSize
)
78 Buffer
= malloc(uSize
);
87 // This is a char to wchar string conversion helper
88 int mbstowcsz(LPWSTR lpDest
, LPCSTR lpSrc
, int nLen
)
92 // If we have nothing to convert or if output doesn't exist, return
93 if (nLen
== 0 || lpDest
== 0)
98 // Then, simply convert
99 Conv
= MultiByteToWideChar(CP_ACP
, 0, lpSrc
, -1, lpDest
, nLen
);
100 // In case of conversion success, null terminate the string
109 /* PUBLIC FUNCTIONS **********************************************************/
116 // Set to empty string
117 m_pchData
= afxPchNil
;
123 CHString::CHString(WCHAR ch
, int nRepeat
) throw (CHeap_Exception
)
125 // Allow null initialize, in case something goes wrong
126 m_pchData
= afxPchNil
;
128 // If we have a char to insert
131 // Allocate a buffer big enough
132 AllocBuffer(nRepeat
);
133 // And if possible, repeat char
136 for (int i
= 0; i
< nRepeat
; ++i
)
147 CHString::CHString(LPCWSTR lpsz
) throw (CHeap_Exception
)
149 // Allow null initialize, in case something goes wrong
150 m_pchData
= afxPchNil
;
152 // If we have an input string
156 int Len
= SafeStrlen(lpsz
);
157 // Then, allocate a big enough buffer and copy string
158 // Note that here, we don't null terminate the string...
162 wcsncpy(m_pchData
, lpsz
, Len
);
170 CHString::CHString(LPCWSTR lpch
, int nLength
) throw (CHeap_Exception
)
172 // Allow null initialize, in case something goes wrong
173 m_pchData
= afxPchNil
;
175 // In case we have a string with a len
176 if (lpch
!= 0 && nLength
!= 0)
178 // Just copy the string
179 AllocBuffer(nLength
);
180 wcsncpy(m_pchData
, lpch
, nLength
);
187 CHString::CHString(LPCSTR lpsz
) throw (CHeap_Exception
)
189 // Allow null initialize, in case something goes wrong
190 m_pchData
= afxPchNil
;
192 // If we have input string
196 int Len
= (int)strlen(lpsz
);
199 // Allocate and convert the string
201 mbstowcsz(m_pchData
, lpsz
, Len
+ 1);
202 // Releasing buffer here is to allow to
203 // update the buffer size. We notify we're
204 // done with changing the string: recompute its
214 CHString::CHString(const unsigned char* lpsz
)
218 // And call operator= with const char*, easier
219 *this = (LPCSTR
)lpsz
;
225 CHString::CHString(const CHString
& stringSrc
)
227 // If we have currently no referenced string
228 if (stringSrc
.GetData()->nRefs
< 0)
230 // Ensure we have the null string
231 m_pchData
= afxPchNil
;
232 // And then call, the copy operator with input string
233 *this = stringSrc
.m_pchData
;
237 // Otherwise, just copy the input string
238 m_pchData
= stringSrc
.m_pchData
;
239 // And increment the number of references
240 InterlockedIncrement(&GetData()->nRefs
);
241 // The whole point here is: Am I forget to release the old
242 // data?! MS doesn't release it, but I guess we should...
249 CHString::~CHString()
251 // If we have a string
252 if (GetData() != &afxNullData
)
254 // Check whether it's still in use after we release it
255 if (InterlockedDecrement(&GetData()->nRefs
) == 0)
266 void CHString::AllocBeforeWrite(int nLen
) throw (CHeap_Exception
)
268 // In case we have several strings pointing to our memory zone
269 // Or we need bigger buffer than actual
270 if (GetData()->nRefs
> 1 || nLen
> GetData()->nAllocLength
)
273 // And allocate a new one which is big enough
282 void CHString::AllocBuffer(int nSize
) throw (CHeap_Exception
)
284 // Here we have to allocate a buffer for the string
285 // It actually consists in: CHStringData structure
286 // with a buffer big enough at its end to store the
290 // Null size is easy allocation
293 m_pchData
= afxPchNil
;
297 // We cannot allow negative sizes
300 RaiseException(ERROR_INVALID_PARAMETER
, EXCEPTION_NONCONTINUABLE
, 0, 0);
306 RaiseException(STATUS_INTEGER_OVERFLOW
, EXCEPTION_NONCONTINUABLE
, 0, 0);
309 // Just allocate big enough buffer, using our own operator new
310 Data
= (CHStringData
*)operator new(nSize
* sizeof(WCHAR
) + sizeof(CHStringData
));
311 // In case Data is null, throw an exception
312 // Yes, this is stupid! Our operator new is already supposed to through an exception...
320 Data
->nDataLength
= nSize
;
321 Data
->nAllocLength
= nSize
;
324 // We only return the string
325 // We can find back data with some mathematics
326 m_pchData
= Data
->data();
332 void CHString::AllocCopy(CHString
& dest
, int nCopyLen
, int nCopyIndex
, int nExtraLen
) const throw (CHeap_Exception
)
334 // Once again, we cannot deal with negative lens
337 RaiseException(ERROR_INVALID_PARAMETER
, EXCEPTION_NONCONTINUABLE
, 0, 0);
342 RaiseException(ERROR_INVALID_PARAMETER
, EXCEPTION_NONCONTINUABLE
, 0, 0);
347 RaiseException(ERROR_INVALID_PARAMETER
, EXCEPTION_NONCONTINUABLE
, 0, 0);
350 // In case what we have to copy is null-sized, just set empty string
351 if (nCopyLen
+ nExtraLen
== 0)
353 dest
.m_pchData
= afxPchNil
;
357 // Otherwise, allocate a buffer in new string which is big enough
358 // You can note that we absolutely don't check about any existing
359 // (referenced) buffer in dest. Actually, dest is to be EMPTY string.
360 // The whole point of this function is to initialize a virgin string by
361 // copying data from another. This is needed by Left/Mid/Right
362 dest
.AllocBuffer(nCopyLen
+ nExtraLen
);
363 // And copy our stuff in
364 wcsncpy(dest
.m_pchData
, m_pchData
+ nCopyIndex
, nCopyLen
);
370 BSTR
CHString::AllocSysString() const throw (CHeap_Exception
)
374 // Just allocate the string
375 SysString
= SysAllocStringLen(m_pchData
, GetData()->nDataLength
);
387 void CHString::AssignCopy(int nSrcLen
, LPCWSTR lpszSrcData
) throw (CHeap_Exception
)
389 // Don't allow negative len
392 RaiseException(ERROR_INVALID_PARAMETER
, EXCEPTION_NONCONTINUABLE
, 0, 0);
395 // We will have to modify a string that might be shared, so duplicate it
396 // Ensuring it's big enough to contain our new stuff
397 AllocBeforeWrite(nSrcLen
);
404 // Just copy, write down new size, and ensure it's null terminated
405 wcsncpy(m_pchData
, lpszSrcData
, nSrcLen
);
406 GetData()->nDataLength
= nSrcLen
;
407 m_pchData
[nSrcLen
] = 0;
413 int CHString::Collate(LPCWSTR lpsz
) const
415 // Just call the deprecated function here - no matter we are null terminated
416 // Did you read my statement about how safe is this implementation?
417 return wcscoll(m_pchData
, lpsz
);
423 int CHString::Compare(LPCWSTR lpsz
) const
425 // Just call the deprecated function here - no matter we are null terminated
426 // Did you read my statement about how safe is this implementation?
427 return wcscmp(m_pchData
, lpsz
);
433 int CHString::CompareNoCase(LPCWSTR lpsz
) const
435 // Just call the deprecated function here - no matter we are null terminated
436 // Did you read my statement about how safe is this implementation?
437 return wcsicmp(m_pchData
, lpsz
);
443 void CHString::ConcatInPlace(int nSrcLen
, LPCWSTR lpszSrcData
)
445 // With null length, there's not that much to concat...
451 // Still no negative length
454 RaiseException(ERROR_INVALID_PARAMETER
, EXCEPTION_NONCONTINUABLE
, 0, 0);
457 // Ensure we wouldn't overflow with the concat
458 if (GetData()->nDataLength
+ nSrcLen
> INT_MAX
)
460 RaiseException(STATUS_INTEGER_OVERFLOW
, EXCEPTION_NONCONTINUABLE
, 0, 0);
463 // In case we have to modify a shared string OR if it can't fit into current buffer...
464 if (GetData()->nRefs
> 1 || GetData()->nDataLength
+ nSrcLen
> GetData()->nAllocLength
)
466 // Allocate a new buffer! (without forgetting to release old one)
467 CHStringData
* OldData
= GetData();
469 // You remember about "InPlace" in the function's name?
471 ConcatCopy(GetData()->nDataLength
, m_pchData
, nSrcLen
, lpszSrcData
);
476 // Ensure we don't overflow
477 if (nSrcLen
> INT_MAX
)
479 RaiseException(STATUS_INTEGER_OVERFLOW
, EXCEPTION_NONCONTINUABLE
, 0, 0);
482 // Then, just copy and null terminate
483 wcsncpy(m_pchData
+ GetData()->nDataLength
, lpszSrcData
, nSrcLen
);
484 GetData()->nDataLength
+= nSrcLen
;
485 m_pchData
[GetData()->nDataLength
] = 0;
492 void CHString::ConcatCopy(int nSrc1Len
, LPCWSTR lpszSrc1Data
, int nSrc2Len
, LPCWSTR lpszSrc2Data
) throw (CHeap_Exception
)
496 if (nSrc1Len
< 0 || nSrc2Len
< 0)
498 RaiseException(ERROR_INVALID_PARAMETER
, EXCEPTION_NONCONTINUABLE
, 0, 0);
501 // If both len are null, do nothing
502 TotalLen
= nSrc1Len
+ nSrc2Len
;
508 // Otherwise, allocate a new buffer to hold everything (caller will release previous buffer)
509 AllocBuffer(TotalLen
);
511 wcsncpy(m_pchData
, lpszSrc1Data
, nSrc1Len
);
512 wcsncpy(m_pchData
+ nSrc1Len
, lpszSrc2Data
, nSrc2Len
);
518 void CHString::CopyBeforeWrite() throw (CHeap_Exception
)
522 // First, we need to get reference count
523 // And we also need to save Data for later copy
526 if (Data
->nRefs
<= 1)
528 // If its not used, don't waste time to realloc, it will do the job
532 // Release current data - we are sure it won't be freed upon that point
533 // Thanks to the reference count check previously done
535 // Alloc new buffer and copy old data in it
536 AllocBuffer(Data
->nDataLength
);
537 wcsncpy(m_pchData
, Data
->data(), Data
->nDataLength
);
543 void CHString::Empty()
546 if (GetData()->nDataLength
== 0)
551 // Empty it easily given it's reference count
552 if (GetData()->nRefs
< 0)
558 // Otherwise, just release it
559 // It will set back this instance to afxPchNil
560 // while decreasing reference count
568 int CHString::Find(WCHAR ch
) const
572 // Let's use appropriate helper
573 Found
= wcschr(m_pchData
, ch
);
574 // We have to return a position, so compute it
577 return (Found
- m_pchData
);
580 // Otherwise, return no position
587 int CHString::Find(LPCWSTR lpszSub
) const
591 // Let's use appropriate helper
592 Found
= wcsstr(m_pchData
, lpszSub
);
593 // We have to return a position, so compute it
596 return (Found
- m_pchData
);
599 // Otherwise, return no position
606 int CHString::FindOneOf(LPCWSTR lpszCharSet
) const
610 // Let's use appropriate helper
611 Found
= wcspbrk(m_pchData
, lpszCharSet
);
612 // We have to return a position, so compute it
615 return (Found
- m_pchData
);
618 // Otherwise, return no position
625 void CHString::Format(UINT nFormatID
, ...) throw (CHeap_Exception
)
627 // Deprecated and not implemented any longer - well, this is its implementation
634 void CHString::Format(LPCWSTR lpszFormat
, ...) throw (CHeap_Exception
)
636 // Forward to FormatV
639 va_start(ArgsList
, lpszFormat
);
640 FormatV(lpszFormat
, ArgsList
);
647 void CHString::FormatMessageW(UINT nFormatID
, ...) throw (CHeap_Exception
)
649 // Deprecated and not implemented any longer - well, this is its implementation
656 void CHString::FormatMessageW(LPCWSTR lpszFormat
, ...) throw (CHeap_Exception
)
664 void CHString::FormatV(LPCWSTR lpszFormat
, va_list argList
)
672 void CHString::FreeExtra() throw (CHeap_Exception
)
674 CHStringData
* OldData
;
676 // No extra? Do nothing
677 if (GetData()->nDataLength
== GetData()->nAllocLength
)
684 // Allocate a new one, at the right size (with no place for \0 :-))
685 AllocBuffer(GetData()->nDataLength
);
686 // Copy old and release it
687 wcsncpy(m_pchData
, OldData
->data(), OldData
->nDataLength
);
694 int CHString::GetAllocLength() const
696 return GetData()->nAllocLength
;
702 WCHAR
CHString::GetAt(int nIndex
) const
704 // It's up to you to check the index!
705 return m_pchData
[nIndex
];
711 LPWSTR
CHString::GetBuffer(int nMinBufLength
) throw (CHeap_Exception
)
713 LPWSTR OldBuffer
= m_pchData
;
715 // We'll have to allocate a new buffer if it's not big enough
716 // or if it's shared by several strings
717 if (GetData()->nRefs
> 1 || GetData()->nAllocLength
< nMinBufLength
)
719 CHStringData
* OldData
= GetData();
720 int OldLen
= GetData()->nDataLength
;
722 // Ensure we can hold enough
723 if (OldLen
> nMinBufLength
)
725 nMinBufLength
= OldLen
;
728 // Allocate new buffer
729 AllocBuffer(nMinBufLength
);
731 wcsncpy(m_pchData
, OldBuffer
, OldLen
);
732 GetData()->nDataLength
= OldLen
;
738 // Weirdly, here Windows always returns the old buffer
739 // Which basically exposes a wrong buffer
746 LPWSTR
CHString::GetBufferSetLength(int nNewLength
) throw (CHeap_Exception
)
748 // Get a buffer big enough
749 // We don't care about the return, it will be set in the string
750 (void)GetBuffer(nNewLength
);
751 // Set length, null-terminate and return
752 GetData()->nDataLength
= nNewLength
;
753 m_pchData
[nNewLength
] = 0;
760 CHStringData
* CHString::GetData() const
762 // In case of empty string, return empty data
763 if (m_pchData
== afxPchNil
)
768 // Otherwise, do maths
769 return (CHStringData
*)((ULONG_PTR
)m_pchData
- sizeof(CHStringData
));
775 int CHString::GetLength() const
777 return GetData()->nDataLength
;
783 void CHString::Init()
785 m_pchData
= afxPchNil
;
791 BOOL
CHString::IsEmpty() const
793 return (GetData()->nDataLength
== 0);
799 CHString
CHString::Left(int nCount
) const throw (CHeap_Exception
)
803 // Validate input (we can't get more than what we have ;-))
806 if (nCount
> GetData()->nDataLength
)
808 nCount
= GetData()->nDataLength
;
812 AllocCopy(NewString
, nCount
, 0, 0);
820 int CHString::LoadStringW(UINT nID
) throw (CHeap_Exception
)
822 // Deprecated and not implemented any longer - well, this is its implementation
829 int CHString::LoadStringW(UINT nID
, LPWSTR lpszBuf
, UINT nMaxBuf
) throw (CHeap_Exception
)
831 // Deprecated and not implemented any longer - well, this is its implementation
838 LPWSTR
CHString::LockBuffer()
842 // The purpose here is basically to set the nRefs to max int
843 LockedBuffer
= GetBuffer(0);
844 GetData()->nRefs
= INT_MAX
;
852 void CHString::MakeLower() throw (CHeap_Exception
)
854 // We'll modify string, duplicate it first if needed
857 // Let's use appropriate helper
864 void CHString::MakeReverse() throw (CHeap_Exception
)
866 // We'll modify string, duplicate it first if needed
869 // Let's use appropriate helper
876 void CHString::MakeUpper() throw (CHeap_Exception
)
878 // We'll modify string, duplicate it first if needed
881 // Let's use appropriate helper
888 CHString
CHString::Mid(int nFirst
) const throw (CHeap_Exception
)
890 // Take string from nFirst up to the end
891 return Mid(nFirst
, GetData()->nDataLength
- nFirst
);
897 CHString
CHString::Mid(int nFirst
, int nCount
) const throw (CHeap_Exception
)
901 // Validate sizes first
912 // Ensure we don't go beyond the string
913 if (nFirst
+ nCount
> GetData()->nDataLength
)
915 nCount
= GetData()->nDataLength
- nFirst
;
918 // Also ensure we don't read beyond
919 // Yes, this should have been done before previous check
920 // MS does it that way
921 if (nFirst
> GetData()->nDataLength
)
926 AllocCopy(NewString
, nCount
, nFirst
, 0);
934 void CHString::Release()
936 // If null string, nothing to do
937 if (GetData() == &afxNullData
)
942 // Otherwise, decrement ref count and release if required
943 if (InterlockedDecrement(&GetData()->nRefs
) == 0)
948 // In all cases, caller doesn't want string anymore
949 // So, switch back to empty string
950 m_pchData
= afxPchNil
;
956 void WINAPI
CHString::Release(CHStringData
* pData
)
958 // If empty string, ignore
959 if (pData
== &afxNullData
)
964 // Otherwise, simply and free if needed
965 if (InterlockedDecrement(&pData
->nRefs
) == 0)
974 void CHString::ReleaseBuffer(int nNewLength
) throw (CHeap_Exception
)
978 // We'll modify buffer, so duplicate
981 // If no len provided, get one
982 if (nNewLength
== -1)
984 nNewLength
= (int)wcslen(m_pchData
);
987 // Set appropriate size and null-terminate
989 Data
->nDataLength
= nNewLength
;
990 Data
->data()[nNewLength
] = 0;
996 int CHString::ReverseFind(WCHAR ch
) const
1000 // Let's use appropriate helper
1001 Last
= wcsrchr(m_pchData
, ch
);
1002 // We have to return a position, so compute it
1005 return (Last
- m_pchData
);
1008 // Otherwise, return no position
1015 CHString
CHString::Right(int nCount
) const throw (CHeap_Exception
)
1019 // Validate input (we can't get more than what we have ;-))
1022 if (nCount
> GetData()->nDataLength
)
1024 nCount
= GetData()->nDataLength
;
1028 AllocCopy(NewString
, nCount
, GetData()->nDataLength
- nCount
, 0);
1036 int CHString::SafeStrlen(LPCWSTR lpsz
)
1038 // Check we have a string and then get its length
1044 // Of course, it's not safe at all in case string is not null-terminated.
1045 // Things that may happen given strings are not to be null-terminated
1047 return (int)wcslen(lpsz
);
1053 void CHString::SetAt(int nIndex
, WCHAR ch
) throw (CHeap_Exception
)
1057 m_pchData
[nIndex
] = ch
;
1063 CHString
CHString::SpanExcluding(LPCWSTR lpszCharSet
) const throw (CHeap_Exception
)
1067 // Get position and then, extract
1068 Count
= (int)wcscspn(m_pchData
, lpszCharSet
);
1075 CHString
CHString::SpanIncluding(LPCWSTR lpszCharSet
) const throw (CHeap_Exception
)
1079 // Get position and then, extract
1080 Count
= (int)wcsspn(m_pchData
, lpszCharSet
);
1087 void CHString::TrimLeft() throw (CHeap_Exception
)
1093 // We'll modify, so copy first
1096 // Start at the begin of the string
1097 CurrentChar
= m_pchData
;
1098 while (*CurrentChar
!= 0)
1100 // Browse string till we find something which is not a space
1101 if (!iswspace(*CurrentChar
))
1109 // Then, calculate new begin (easy) and new length
1111 NewBegin
= (CurrentChar
- m_pchData
);
1112 NewLength
= GetData()->nDataLength
- NewBegin
;
1113 memmove(m_pchData
, CurrentChar
, NewLength
* sizeof(WCHAR
));
1114 GetData()->nDataLength
= NewLength
;
1120 void CHString::TrimRight() throw (CHeap_Exception
)
1125 // We'll modify, so copy first
1128 // Start at the begin of the string -- WHAT?!
1129 // Yes, this algorithm is the same that MS is
1130 // using for its TrimRight.
1131 // It is highly unefficient. It would have been
1132 // easier to start at nDataLength and to get back to
1133 // the begin. Note that it would have been safer as
1134 // well, in case the caller is using non-null-terminated
1135 // strings. But, well...
1136 CurrentChar
= m_pchData
;
1138 while (*CurrentChar
!= 0)
1140 // If not a space, reset what we can trim
1141 if (!iswspace(*CurrentChar
))
1145 // If it is one, and the first of the spaces serie
1146 // Keep its position
1147 else if (CanBeEaten
== 0)
1149 CanBeEaten
= CurrentChar
;
1155 // If nothing to trim, quit
1156 if (CanBeEaten
== 0)
1161 // Otherwise, shorten the string
1162 GetData()->nDataLength
= (CanBeEaten
- m_pchData
);
1168 void CHString::UnlockBuffer()
1170 // Unlock means just put ref back to 1
1171 // It was previously set to MAX_INT
1172 if (GetData() != &afxNullData
)
1174 GetData()->nRefs
= 1;
1181 const CHString
& CHString::operator=(char ch
) throw (CHeap_Exception
)
1190 const CHString
& CHString::operator=(WCHAR ch
) throw (CHeap_Exception
)
1199 const CHString
& CHString::operator=(CHString
*p
) throw (CHeap_Exception
)
1208 const CHString
& CHString::operator=(LPCSTR lpsz
) throw (CHeap_Exception
)
1212 // If we have string, get its len
1215 Len
= (int)strlen(lpsz
);
1222 // Do this call, even with null len, just to get empty string
1223 AllocBeforeWrite(Len
);
1231 mbstowcsz(m_pchData
, lpsz
, Len
+ 1);
1232 // Get new size and so on
1241 const CHString
& CHString::operator=(LPCWSTR lpsz
) throw (CHeap_Exception
)
1245 Len
= SafeStrlen(lpsz
);
1246 AssignCopy(Len
, lpsz
);
1254 const CHString
& CHString::operator=(const CHString
& stringSrc
) throw (CHeap_Exception
)
1256 // Don't copy string on itself
1257 if (&stringSrc
== this)
1262 // In case we don't have a referenced string here,
1263 // or if the other is not referenced, just copy here
1264 if ((GetData()->nRefs
< 0 && GetData() != &afxNullData
) ||
1265 stringSrc
.GetData()->nRefs
< 0)
1267 AssignCopy(stringSrc
.GetData()->nDataLength
, stringSrc
.m_pchData
);
1271 // Otherwise, release current buffer
1273 // And set buffer as stringSrc buffer
1274 // And increase its reference count
1275 m_pchData
= stringSrc
.m_pchData
;
1276 InterlockedIncrement(&GetData()->nRefs
);
1284 const CHString
& CHString::operator=(const unsigned char* lpsz
) throw (CHeap_Exception
)
1286 *this = (LPCSTR
)lpsz
;
1293 const CHString
& CHString::operator+=(char ch
) throw (CHeap_Exception
)
1302 const CHString
& CHString::operator+=(WCHAR ch
) throw (CHeap_Exception
)
1304 ConcatInPlace(1, &ch
);
1311 const CHString
& CHString::operator+=(LPCWSTR lpsz
) throw (CHeap_Exception
)
1315 Len
= SafeStrlen(lpsz
);
1316 ConcatInPlace(Len
, lpsz
);
1324 const CHString
& CHString::operator+=(const CHString
& string
) throw (CHeap_Exception
)
1326 ConcatInPlace(string
.GetData()->nDataLength
, string
.m_pchData
);
1334 WCHAR
CHString::operator[](int nIndex
) const
1336 return m_pchData
[nIndex
];
1342 CHString::operator LPCWSTR() const
1350 CHString WINAPI
operator+(WCHAR ch
, const CHString
& string
) throw (CHeap_Exception
)
1354 // Basically concat in a new string
1355 NewString
.ConcatCopy(1, &ch
, string
.GetData()->nDataLength
, string
.m_pchData
);
1363 CHString WINAPI
operator+(const CHString
& string
, WCHAR ch
) throw (CHeap_Exception
)
1367 // Basically concat in a new string
1368 NewString
.ConcatCopy(string
.GetData()->nDataLength
, string
.m_pchData
, 1, &ch
);
1376 CHString WINAPI
operator+(const CHString
& string
, LPCWSTR lpsz
) throw (CHeap_Exception
)
1381 // Get string length
1382 Len
= CHString::SafeStrlen(lpsz
);
1383 // And concat in new string
1384 NewString
.ConcatCopy(string
.GetData()->nDataLength
, string
.m_pchData
, Len
, lpsz
);
1392 CHString WINAPI
operator+(LPCWSTR lpsz
, const CHString
& string
) throw (CHeap_Exception
)
1397 // Get string length
1398 Len
= CHString::SafeStrlen(lpsz
);
1399 // And concat in new string
1400 NewString
.ConcatCopy(Len
, lpsz
, string
.GetData()->nDataLength
, string
.m_pchData
);
1408 CHString WINAPI
operator+(const CHString
& string1
, const CHString
& string2
) throw (CHeap_Exception
)
1412 // Basically concat in a new string
1413 NewString
.ConcatCopy(string1
.GetData()->nDataLength
, string1
.m_pchData
,
1414 string2
.GetData()->nDataLength
, string2
.m_pchData
);