ReactOS  0.4.14-dev-77-gd9e7c48
chstring.cpp
Go to the documentation of this file.
1 /*
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)
7  *
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
23  */
24 
25 /* INCLUDES ******************************************************************/
26 
27 #include <chstring.h>
28 #define NDEBUG
29 #include <debug.h>
30 
31 /* PRIVATE FUNCTIONS *********************************************************/
32 
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.
38 // This is the data that are matching the null string upper
40 // Exception we may throw in case of allocation failure
42 
43 // Our own delete operator
44 // It is here basically because MS guys don't known about set_new_handler()
45 // See operator new
46 void operator delete(void* ptr)
47 {
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...
51  if (ptr)
52  {
53  free(ptr);
54  }
55 }
56 
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)
62 {
63  void* Buffer;
64 
65  Buffer = malloc(uSize);
66  if (!Buffer)
67  {
68  throw HeapException;
69  }
70 
71  return Buffer;
72 }
73 
74 // This is a char to wchar string conversion helper
75 int mbstowcsz(LPWSTR lpDest, LPCSTR lpSrc, int nLen)
76 {
77  int Conv;
78 
79  // If we have nothing to convert or if output doesn't exist, return
80  if (nLen == 0 || lpDest == 0)
81  {
82  return 0;
83  }
84 
85  // Then, simply convert
86  Conv = MultiByteToWideChar(CP_ACP, 0, lpSrc, -1, lpDest, nLen);
87  // In case of conversion success, null terminate the string
88  if (Conv != 0)
89  {
90  lpDest[nLen] = 0;
91  }
92 
93  return Conv;
94 }
95 
96 /* PUBLIC FUNCTIONS **********************************************************/
97 
98 /*
99  * @implemented
100  */
102 {
103  // Set to empty string
105 }
106 
107 /*
108  * @implemented
109  */
110 CHString::CHString(WCHAR ch, int nRepeat)
111 {
112  // Allow null initialize, in case something goes wrong
114 
115  // If we have a char to insert
116  if (nRepeat >= 1)
117  {
118  // Allocate a buffer big enough
119  AllocBuffer(nRepeat);
120  // And if possible, repeat char
121  if (m_pchData)
122  {
123  for (int i = 0; i < nRepeat; ++i)
124  {
125  m_pchData[i] = ch;
126  }
127  }
128  }
129 }
130 
131 /*
132  * @implemented
133  */
135 {
136  // Allow null initialize, in case something goes wrong
138 
139  // If we have an input string
140  if (lpsz != 0)
141  {
142  // Get its length
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...
146  if (Len)
147  {
148  AllocBuffer(Len);
149  wcsncpy(m_pchData, lpsz, Len);
150  }
151  }
152 }
153 
154 /*
155  * @implemented
156  */
158 {
159  // Allow null initialize, in case something goes wrong
161 
162  // In case we have a string with a len
163  if (lpch != 0 && nLength != 0)
164  {
165  // Just copy the string
167  wcsncpy(m_pchData, lpch, nLength);
168  }
169 }
170 
171 /*
172  * @implemented
173  */
175 {
176  // Allow null initialize, in case something goes wrong
178 
179  // If we have input string
180  if (lpsz != 0)
181  {
182  // Get its length
183  int Len = (int)strlen(lpsz);
184  if (Len)
185  {
186  // Allocate and convert the string
187  AllocBuffer(Len);
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
192  // length, please
193  ReleaseBuffer();
194  }
195  }
196 }
197 
198 /*
199  * @implemented
200  */
201 CHString::CHString(const unsigned char* lpsz)
202 {
203  // Null init
204  Init();
205  // And call operator= with const char*, easier
206  *this = (LPCSTR)lpsz;
207 }
208 
209 /*
210  * @implemented
211  */
212 CHString::CHString(const CHString& stringSrc)
213 {
214  // If we have currently no referenced string
215  if (stringSrc.GetData()->nRefs < 0)
216  {
217  // Ensure we have the null string
219  // And then call, the copy operator with input string
220  *this = stringSrc.m_pchData;
221  }
222  else
223  {
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...
230  }
231 }
232 
233 /*
234  * @implemented
235  */
237 {
238  // If we have a string
239  if (GetData() != &afxNullData)
240  {
241  // Check whether it's still in use after we release it
242  if (InterlockedDecrement(&GetData()->nRefs) == 0)
243  {
244  // If so, delete it
245  delete GetData();
246  }
247  }
248 }
249 
250 /*
251  * @implemented
252  */
254 {
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)
258  {
259  // Just drop current
260  // And allocate a new one which is big enough
261  Release();
262  AllocBuffer(nLen);
263  }
264 }
265 
266 /*
267  * @implemented
268  */
270 {
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
274  // string.
276 
277  // Null size is easy allocation
278  if (nSize == 0)
279  {
281  return;
282  }
283 
284  // We cannot allow negative sizes
285  if (nSize < 0)
286  {
288  }
289 
290  // Nor too big
291  if (nSize > (INT_MAX - (int)sizeof(CHStringData)) / (int)sizeof(WCHAR))
292  {
294  }
295 
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...
300  // Thanks MS
301  if (!Data)
302  {
303  throw HeapException;
304  }
305 
306  Data->nRefs = 1;
307  Data->nDataLength = nSize;
308  Data->nAllocLength = nSize;
309  Data->data()[0] = 0;
310 
311  // We only return the string
312  // We can find back data with some mathematics
313  m_pchData = Data->data();
314 }
315 
316 /*
317  * @implemented
318  */
319 void CHString::AllocCopy(CHString& dest, int nCopyLen, int nCopyIndex, int nExtraLen) const
320 {
321  // Once again, we cannot deal with negative lens
322  if (nCopyLen < 0)
323  {
325  }
326 
327  if (nCopyIndex < 0)
328  {
330  }
331 
332  if (nExtraLen < 0)
333  {
335  }
336 
337  // In case what we have to copy is null-sized, just set empty string
338  if (nCopyLen + nExtraLen == 0)
339  {
340  dest.m_pchData = afxPchNil;
341  return;
342  }
343 
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);
352 }
353 
354 /*
355  * @implemented
356  */
358 {
359  BSTR SysString;
360 
361  // Just allocate the string
362  SysString = SysAllocStringLen(m_pchData, GetData()->nDataLength);
363  if (!SysString)
364  {
365  throw HeapException;
366  }
367 
368  return SysString;
369 }
370 
371 /*
372  * @implemented
373  */
374 void CHString::AssignCopy(int nSrcLen, LPCWSTR lpszSrcData)
375 {
376  // Don't allow negative len
377  if (nSrcLen < 0)
378  {
380  }
381 
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);
385  if (nSrcLen == 0)
386  {
387  Release();
388  return;
389  }
390 
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;
395 }
396 
397 /*
398  * @implemented
399  */
400 int CHString::Collate(LPCWSTR lpsz) const
401 {
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);
405 }
406 
407 /*
408  * @implemented
409  */
410 int CHString::Compare(LPCWSTR lpsz) const
411 {
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);
415 }
416 
417 /*
418  * @implemented
419  */
421 {
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);
425 }
426 
427 /*
428  * @implemented
429  */
430 void CHString::ConcatInPlace(int nSrcLen, LPCWSTR lpszSrcData)
431 {
432  // With null length, there's not that much to concat...
433  if (nSrcLen == 0)
434  {
435  return;
436  }
437 
438  // Still no negative length
439  if (nSrcLen < 0)
440  {
442  }
443 
444  // Ensure we wouldn't overflow with the concat
445  if (GetData()->nDataLength > INT_MAX - nSrcLen)
446  {
448  }
449 
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)
452  {
453  // Allocate a new buffer! (without forgetting to release old one)
454  CHStringData* OldData = GetData();
455 
456  // You remember about "InPlace" in the function's name?
457  // The cake is a lie
458  ConcatCopy(GetData()->nDataLength, m_pchData, nSrcLen, lpszSrcData);
459  Release(OldData);
460  }
461  else
462  {
463  // Ensure we don't overflow
464  if (nSrcLen > INT_MAX - GetData()->nDataLength)
465  {
467  }
468 
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;
473  }
474 }
475 
476 /*
477  * @implemented
478  */
479 void CHString::ConcatCopy(int nSrc1Len, LPCWSTR lpszSrc1Data, int nSrc2Len, LPCWSTR lpszSrc2Data)
480 {
481  int TotalLen;
482 
483  if (nSrc1Len < 0 || nSrc2Len < 0)
484  {
486  }
487 
488  // If both len are null, do nothing
489  TotalLen = nSrc1Len + nSrc2Len;
490  if (TotalLen == 0)
491  {
492  return;
493  }
494 
495  // Otherwise, allocate a new buffer to hold everything (caller will release previous buffer)
496  AllocBuffer(TotalLen);
497  // And concat stuff
498  wcsncpy(m_pchData, lpszSrc1Data, nSrc1Len);
499  wcsncpy(m_pchData + nSrc1Len, lpszSrc2Data, nSrc2Len);
500 }
501 
502 /*
503  * @implemented
504  */
506 {
508 
509  // First, we need to get reference count
510  // And we also need to save Data for later copy
511  Data = GetData();
512 
513  if (Data->nRefs <= 1)
514  {
515  // If its not used, don't waste time to realloc, it will do the job
516  return;
517  }
518 
519  // Release current data - we are sure it won't be freed upon that point
520  // Thanks to the reference count check previously done
521  Release();
522  // Alloc new buffer and copy old data in it
523  AllocBuffer(Data->nDataLength);
524  wcsncpy(m_pchData, Data->data(), Data->nDataLength);
525 }
526 
527 /*
528  * @implemented
529  */
531 {
532  // Already empty
533  if (GetData()->nDataLength == 0)
534  {
535  return;
536  }
537 
538  // Empty it easily given it's reference count
539  if (GetData()->nRefs < 0)
540  {
541  *this = afxPchNil;
542  }
543  else
544  {
545  // Otherwise, just release it
546  // It will set back this instance to afxPchNil
547  // while decreasing reference count
548  Release();
549  }
550 }
551 
552 /*
553  * @implemented
554  */
555 int CHString::Find(WCHAR ch) const
556 {
557  WCHAR *Found;
558 
559  // Let's use appropriate helper
560  Found = wcschr(m_pchData, ch);
561  // We have to return a position, so compute it
562  if (Found)
563  {
564  return (Found - m_pchData);
565  }
566 
567  // Otherwise, return no position
568  return -1;
569 }
570 
571 /*
572  * @implemented
573  */
574 int CHString::Find(LPCWSTR lpszSub) const
575 {
576  WCHAR *Found;
577 
578  // Let's use appropriate helper
579  Found = wcsstr(m_pchData, lpszSub);
580  // We have to return a position, so compute it
581  if (Found)
582  {
583  return (Found - m_pchData);
584  }
585 
586  // Otherwise, return no position
587  return -1;
588 }
589 
590 /*
591  * @implemented
592  */
593 int CHString::FindOneOf(LPCWSTR lpszCharSet) const
594 {
595  WCHAR *Found;
596 
597  // Let's use appropriate helper
598  Found = wcspbrk(m_pchData, lpszCharSet);
599  // We have to return a position, so compute it
600  if (Found)
601  {
602  return (Found - m_pchData);
603  }
604 
605  // Otherwise, return no position
606  return -1;
607 }
608 
609 /*
610  * @implemented
611  */
612 void CHString::Format(UINT nFormatID, ...)
613 {
614  // Deprecated and not implemented any longer - well, this is its implementation
615  return;
616 }
617 
618 /*
619  * @implemented
620  */
621 void CHString::Format(LPCWSTR lpszFormat, ...)
622 {
623  // Forward to FormatV
624  va_list ArgsList;
625 
626  va_start(ArgsList, lpszFormat);
627  FormatV(lpszFormat, ArgsList);
628  va_end(ArgsList);
629 }
630 
631 /*
632  * @implemented
633  */
634 void CHString::FormatMessageW(UINT nFormatID, ...)
635 {
636  // Deprecated and not implemented any longer - well, this is its implementation
637  return;
638 }
639 
640 /*
641  * @unimplemented
642  */
643 void CHString::FormatMessageW(LPCWSTR lpszFormat, ...)
644 {
646 }
647 
648 /*
649  * @unimplemented
650  */
651 void CHString::FormatV(LPCWSTR lpszFormat, va_list argList)
652 {
654 }
655 
656 /*
657  * @implemented
658  */
660 {
661  CHStringData* OldData;
662 
663  // No extra? Do nothing
664  if (GetData()->nDataLength == GetData()->nAllocLength)
665  {
666  return;
667  }
668 
669  // Get old buffer
670  OldData = GetData();
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);
675  Release(OldData);
676 }
677 
678 /*
679  * @implemented
680  */
682 {
683  return GetData()->nAllocLength;
684 }
685 
686 /*
687  * @implemented
688  */
689 WCHAR CHString::GetAt(int nIndex) const
690 {
691  // It's up to you to check the index!
692  return m_pchData[nIndex];
693 }
694 
695 /*
696  * @implemented
697  */
698 LPWSTR CHString::GetBuffer(int nMinBufLength)
699 {
700  LPWSTR OldBuffer = m_pchData;
701 
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)
705  {
706  CHStringData* OldData = GetData();
707  int OldLen = GetData()->nDataLength;
708 
709  // Ensure we can hold enough
710  if (OldLen > nMinBufLength)
711  {
712  nMinBufLength = OldLen;
713  }
714 
715  // Allocate new buffer
716  AllocBuffer(nMinBufLength);
717  // Copy contents
718  wcsncpy(m_pchData, OldBuffer, OldLen);
719  GetData()->nDataLength = OldLen;
720 
721  // Release old
722  Release(OldData);
723  }
724 
725  // Weirdly, here Windows always returns the old buffer
726  // Which basically exposes a wrong buffer
727  return OldBuffer;
728 }
729 
730 /*
731  * @implemented
732  */
734 {
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;
741  return m_pchData;
742 }
743 
744 /*
745  * @implemented
746  */
748 {
749  // In case of empty string, return empty data
750  if (m_pchData == afxPchNil)
751  {
752  return &afxNullData;
753  }
754 
755  // Otherwise, do maths
756  return (CHStringData*)((ULONG_PTR)m_pchData - sizeof(CHStringData));
757 }
758 
759 /*
760  * @implemented
761  */
763 {
764  return GetData()->nDataLength;
765 }
766 
767 /*
768  * @implemented
769  */
771 {
773 }
774 
775 /*
776  * @implemented
777  */
779 {
780  return (GetData()->nDataLength == 0);
781 }
782 
783 /*
784  * @implemented
785  */
786 CHString CHString::Left(int nCount) const
787 {
788  CHString NewString;
789 
790  // Validate input (we can't get more than what we have ;-))
791  if (nCount)
792  {
793  if (nCount > GetData()->nDataLength)
794  {
795  nCount = GetData()->nDataLength;
796  }
797  }
798 
799  AllocCopy(NewString, nCount, 0, 0);
800 
801  return NewString;
802 }
803 
804 /*
805  * @implemented
806  */
808 {
809  // Deprecated and not implemented any longer - well, this is its implementation
810  return 0;
811 }
812 
813 /*
814  * @implemented
815  */
816 int CHString::LoadStringW(UINT nID, LPWSTR lpszBuf, UINT nMaxBuf)
817 {
818  // Deprecated and not implemented any longer - well, this is its implementation
819  return 0;
820 }
821 
822 /*
823  * @implemented
824  */
826 {
827  LPWSTR LockedBuffer;
828 
829  // The purpose here is basically to set the nRefs to max int
830  LockedBuffer = GetBuffer(0);
831  GetData()->nRefs = INT_MAX;
832 
833  return LockedBuffer;
834 }
835 
836 /*
837  * @implemented
838  */
840 {
841  // We'll modify string, duplicate it first if needed
842  CopyBeforeWrite();
843 
844  // Let's use appropriate helper
846 }
847 
848 /*
849  * @implemented
850  */
852 {
853  // We'll modify string, duplicate it first if needed
854  CopyBeforeWrite();
855 
856  // Let's use appropriate helper
858 }
859 
860 /*
861  * @implemented
862  */
864 {
865  // We'll modify string, duplicate it first if needed
866  CopyBeforeWrite();
867 
868  // Let's use appropriate helper
870 }
871 
872 /*
873  * @implemented
874  */
875 CHString CHString::Mid(int nFirst) const
876 {
877  // Take string from nFirst up to the end
878  return Mid(nFirst, GetData()->nDataLength - nFirst);
879 }
880 
881 /*
882  * @implemented
883  */
884 CHString CHString::Mid(int nFirst, int nCount) const
885 {
886  CHString NewString;
887 
888  // Validate sizes first
889  if (nFirst < 0)
890  {
891  nFirst = 0;
892  }
893 
894  if (nCount < 0)
895  {
896  nCount = 0;
897  }
898 
899  // Ensure we don't go beyond the string
900  if (nFirst + nCount > GetData()->nDataLength)
901  {
902  nCount = GetData()->nDataLength - nFirst;
903  }
904 
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)
909  {
910  nCount = 0;
911  }
912 
913  AllocCopy(NewString, nCount, nFirst, 0);
914 
915  return NewString;
916 }
917 
918 /*
919  * @implemented
920  */
922 {
923  // If null string, nothing to do
924  if (GetData() == &afxNullData)
925  {
926  return;
927  }
928 
929  // Otherwise, decrement ref count and release if required
930  if (InterlockedDecrement(&GetData()->nRefs) == 0)
931  {
932  delete GetData();
933  }
934 
935  // In all cases, caller doesn't want string anymore
936  // So, switch back to empty string
938 }
939 
940 /*
941  * @implemented
942  */
944 {
945  // If empty string, ignore
946  if (pData == &afxNullData)
947  {
948  return;
949  }
950 
951  // Otherwise, simply and free if needed
952  if (InterlockedDecrement(&pData->nRefs) == 0)
953  {
954  delete pData;
955  }
956 }
957 
958 /*
959  * @implemented
960  */
961 void CHString::ReleaseBuffer(int nNewLength)
962 {
964 
965  // We'll modify buffer, so duplicate
966  CopyBeforeWrite();
967 
968  // If no len provided, get one
969  if (nNewLength == -1)
970  {
971  nNewLength = (int)wcslen(m_pchData);
972  }
973 
974  // Set appropriate size and null-terminate
975  Data = GetData();
976  Data->nDataLength = nNewLength;
977  Data->data()[nNewLength] = 0;
978 }
979 
980 /*
981  * @implemented
982  */
984 {
985  WCHAR *Last;
986 
987  // Let's use appropriate helper
988  Last = wcsrchr(m_pchData, ch);
989  // We have to return a position, so compute it
990  if (Last)
991  {
992  return (Last - m_pchData);
993  }
994 
995  // Otherwise, return no position
996  return -1;
997 }
998 
999 /*
1000  * @implemented
1001  */
1002 CHString CHString::Right(int nCount) const
1003 {
1004  CHString NewString;
1005 
1006  // Validate input (we can't get more than what we have ;-))
1007  if (nCount >= 0)
1008  {
1009  if (nCount > GetData()->nDataLength)
1010  {
1011  nCount = GetData()->nDataLength;
1012  }
1013  }
1014 
1015  AllocCopy(NewString, nCount, GetData()->nDataLength - nCount, 0);
1016 
1017  return NewString;
1018 }
1019 
1020 /*
1021  * @implemented
1022  */
1024 {
1025  // Check we have a string and then get its length
1026  if (lpsz == 0)
1027  {
1028  return 0;
1029  }
1030 
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
1033  // in this class...
1034  return (int)wcslen(lpsz);
1035 }
1036 
1037 /*
1038  * @implemented
1039  */
1040 void CHString::SetAt(int nIndex, WCHAR ch)
1041 {
1042  CopyBeforeWrite();
1043 
1044  m_pchData[nIndex] = ch;
1045 }
1046 
1047 /*
1048  * @implemented
1049  */
1051 {
1052  int Count;
1053 
1054  // Get position and then, extract
1055  Count = (int)wcscspn(m_pchData, lpszCharSet);
1056  return Left(Count);
1057 }
1058 
1059 /*
1060  * @implemented
1061  */
1063 {
1064  int Count;
1065 
1066  // Get position and then, extract
1067  Count = (int)wcsspn(m_pchData, lpszCharSet);
1068  return Left(Count);
1069 }
1070 
1071 /*
1072  * @implemented
1073  */
1075 {
1076  int NewBegin;
1077  int NewLength;
1078  WCHAR *CurrentChar;
1079 
1080  // We'll modify, so copy first
1081  CopyBeforeWrite();
1082 
1083  // Start at the begin of the string
1084  CurrentChar = m_pchData;
1085  while (*CurrentChar != 0)
1086  {
1087  // Browse string till we find something which is not a space
1088  if (!iswspace(*CurrentChar))
1089  {
1090  break;
1091  }
1092 
1093  CurrentChar++;
1094  }
1095 
1096  // Then, calculate new begin (easy) and new length
1097  // And move memory
1098  NewBegin = (CurrentChar - m_pchData);
1099  NewLength = GetData()->nDataLength - NewBegin;
1100  memmove(m_pchData, CurrentChar, NewLength * sizeof(WCHAR));
1102 }
1103 
1104 /*
1105  * @implemented
1106  */
1108 {
1109  WCHAR *CurrentChar;
1110  WCHAR *CanBeEaten;
1111 
1112  // We'll modify, so copy first
1113  CopyBeforeWrite();
1114 
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;
1124  CanBeEaten = 0;
1125  while (*CurrentChar != 0)
1126  {
1127  // If not a space, reset what we can trim
1128  if (!iswspace(*CurrentChar))
1129  {
1130  CanBeEaten = 0;
1131  }
1132  // If it is one, and the first of the spaces serie
1133  // Keep its position
1134  else if (CanBeEaten == 0)
1135  {
1136  CanBeEaten = CurrentChar;
1137  }
1138 
1139  CurrentChar++;
1140  }
1141 
1142  // If nothing to trim, quit
1143  if (CanBeEaten == 0)
1144  {
1145  return;
1146  }
1147 
1148  // Otherwise, shorten the string
1149  GetData()->nDataLength = (CanBeEaten - m_pchData);
1150 }
1151 
1152 /*
1153  * @implemented
1154  */
1156 {
1157  // Unlock means just put ref back to 1
1158  // It was previously set to MAX_INT
1159  if (GetData() != &afxNullData)
1160  {
1161  GetData()->nRefs = 1;
1162  }
1163 }
1164 
1165 /*
1166  * @implemented
1167  */
1169 {
1170  *this = (WCHAR)ch;
1171  return *this;
1172 }
1173 
1174 /*
1175  * @implemented
1176  */
1178 {
1179  AssignCopy(1, &ch);
1180  return *this;
1181 }
1182 
1183 /*
1184  * @implemented
1185  */
1187 {
1188  *this = *p;
1189  return *this;
1190 }
1191 
1192 /*
1193  * @implemented
1194  */
1196 {
1197  int Len;
1198 
1199  // If we have string, get its len
1200  if (lpsz != 0)
1201  {
1202  Len = (int)strlen(lpsz);
1203  }
1204  else
1205  {
1206  Len = 0;
1207  }
1208 
1209  // Do this call, even with null len, just to get empty string
1211  if (Len == 0)
1212  {
1213  Release();
1214  return *this;
1215  }
1216 
1217  // Convert and copy
1218  mbstowcsz(m_pchData, lpsz, Len + 1);
1219  // Get new size and so on
1220  ReleaseBuffer();
1221 
1222  return *this;
1223 }
1224 
1225 /*
1226  * @implemented
1227  */
1229 {
1230  int Len;
1231 
1232  Len = SafeStrlen(lpsz);
1233  AssignCopy(Len, lpsz);
1234 
1235  return *this;
1236 }
1237 
1238 /*
1239  * @implemented
1240  */
1241 const CHString& CHString::operator=(const CHString& stringSrc)
1242 {
1243  // Don't copy string on itself
1244  if (&stringSrc == this)
1245  {
1246  return *this;
1247  }
1248 
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)
1253  {
1254  AssignCopy(stringSrc.GetData()->nDataLength, stringSrc.m_pchData);
1255  return *this;
1256  }
1257 
1258  // Otherwise, release current buffer
1259  Release();
1260  // And set buffer as stringSrc buffer
1261  // And increase its reference count
1262  m_pchData = stringSrc.m_pchData;
1263  InterlockedIncrement(&GetData()->nRefs);
1264 
1265  return *this;
1266 }
1267 
1268 /*
1269  * @implemented
1270  */
1271 const CHString& CHString::operator=(const unsigned char* lpsz)
1272 {
1273  *this = (LPCSTR)lpsz;
1274  return *this;
1275 }
1276 
1277 /*
1278  * @implemented
1279  */
1281 {
1282  *this += (WCHAR)ch;
1283  return *this;
1284 }
1285 
1286 /*
1287  * @implemented
1288  */
1290 {
1291  ConcatInPlace(1, &ch);
1292  return *this;
1293 }
1294 
1295 /*
1296  * @implemented
1297  */
1299 {
1300  int Len;
1301 
1302  Len = SafeStrlen(lpsz);
1303  ConcatInPlace(Len, lpsz);
1304 
1305  return *this;
1306 }
1307 
1308 /*
1309  * @implemented
1310  */
1312 {
1313  ConcatInPlace(string.GetData()->nDataLength, string.m_pchData);
1314 
1315  return *this;
1316 }
1317 
1318 /*
1319  * @implemented
1320  */
1321 WCHAR CHString::operator[](int nIndex) const
1322 {
1323  return m_pchData[nIndex];
1324 }
1325 
1326 /*
1327  * @implemented
1328  */
1330 {
1331  return m_pchData;
1332 }
1333 
1334 /*
1335  * @implemented
1336  */
1338 {
1339  CHString NewString;
1340 
1341  // Basically concat in a new string
1342  NewString.ConcatCopy(1, &ch, string.GetData()->nDataLength, string.m_pchData);
1343 
1344  return NewString;
1345 }
1346 
1347 /*
1348  * @implemented
1349  */
1351 {
1352  CHString NewString;
1353 
1354  // Basically concat in a new string
1355  NewString.ConcatCopy(string.GetData()->nDataLength, string.m_pchData, 1, &ch);
1356 
1357  return NewString;
1358 }
1359 
1360 /*
1361  * @implemented
1362  */
1364 {
1365  int Len;
1366  CHString NewString;
1367 
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);
1372 
1373  return NewString;
1374 }
1375 
1376 /*
1377  * @implemented
1378  */
1380 {
1381  int Len;
1382  CHString NewString;
1383 
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);
1388 
1389  return NewString;
1390 }
1391 
1392 /*
1393  * @implemented
1394  */
1396 {
1397  CHString NewString;
1398 
1399  // Basically concat in a new string
1400  NewString.ConcatCopy(string1.GetData()->nDataLength, string1.m_pchData,
1401  string2.GetData()->nDataLength, string2.m_pchData);
1402 
1403  return NewString;
1404 }
#define ERROR_INVALID_PARAMETER
Definition: compat.h:91
_CRTIMP wchar_t *__cdecl _wcsrev(_Inout_z_ wchar_t *_Str)
CHStringData * GetData() const
Definition: chstring.cpp:747
#define memmove(s1, s2, n)
Definition: mkisofs.h:881
void ConcatInPlace(int nSrcLen, LPCWSTR lpszSrcData)
Definition: chstring.cpp:430
void UnlockBuffer()
Definition: chstring.cpp:1155
struct png_info_def **typedef void(__cdecl typeof(png_destroy_read_struct))(struct png_struct_def **
Definition: typeof.h:49
#define INT_MAX
Definition: limits.h:40
void Format(UINT nFormatID,...)
Definition: chstring.cpp:612
const WCHAR * LPCWSTR
Definition: xmlstorage.h:185
BSTR WINAPI SysAllocStringLen(const OLECHAR *str, unsigned int len)
Definition: oleaut.c:342
void Init()
Definition: chstring.cpp:770
_Check_return_ _CRTIMP int __cdecl wcscoll(_In_z_ const wchar_t *_Str1, _In_z_ const wchar_t *_Str2)
ACPI_SIZE strlen(const char *String)
Definition: utclib.c:269
void AllocBeforeWrite(int nLen)
Definition: chstring.cpp:253
_CONST_RETURN wchar_t *__cdecl wcsstr(_In_z_ const wchar_t *_Str, _In_z_ const wchar_t *_SubStr)
void Empty()
Definition: chstring.cpp:530
#define CP_ACP
Definition: compat.h:99
static CHAR string2[MAX_PATH]
Definition: automation.c:468
_Check_return_ _CRTIMP size_t __cdecl wcscspn(_In_z_ const wchar_t *_Str, _In_z_ const wchar_t *_Control)
#define free
Definition: debug_ros.c:5
CHeap_Exception HeapException(CHeap_Exception::E_ALLOCATION_ERROR)
int nAllocLength
Definition: chstring.h:13
*nSize LPSTR _Inout_ LPDWORD nSize
Definition: winbase.h:2024
CHString Left(int nCount) const
Definition: chstring.cpp:786
void ReleaseBuffer(int nNewLength=-1)
Definition: chstring.cpp:961
_In_ DWORD nLength
Definition: wincon.h:461
int nDataLength
Definition: chstring.h:12
operator
#define EXCEPTION_NONCONTINUABLE
Definition: rtltypes.h:150
static CHAR string1[MAX_PATH]
Definition: asmname.c:32
_Inout_ __drv_aliasesMem PSLIST_ENTRY _Inout_ PSLIST_ENTRY _In_ ULONG Count
Definition: exfuncs.h:1015
void ConcatCopy(int nSrc1Len, LPCWSTR lpszSrc1Data, int nSrc2Len, LPCWSTR lpszSrc2Data)
Definition: chstring.cpp:479
OLECHAR * BSTR
Definition: compat.h:1934
int LoadStringW(UINT nID)
Definition: chstring.cpp:807
void AssignCopy(int nSrcLen, LPCWSTR lpszSrcData)
Definition: chstring.cpp:374
void TrimLeft()
Definition: chstring.cpp:1074
LPWSTR afxPchNil
Definition: chstring.cpp:37
void MakeUpper()
Definition: chstring.cpp:863
static USHORT USHORT * NewLength
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
#define va_end(ap)
Definition: acmsvcex.h:90
#define STATUS_INTEGER_OVERFLOW
Definition: ntstatus.h:371
unsigned int BOOL
Definition: ntddk_ex.h:94
CHString Right(int nCount) const
Definition: chstring.cpp:1002
WCHAR * data()
Definition: chstring.h:15
static PVOID ptr
Definition: dispmode.c:27
const CHString & operator+=(char ch)
Definition: chstring.cpp:1280
LPWSTR LockBuffer()
Definition: chstring.cpp:825
_In_ LPGUID _In_ PVOID Data
Definition: classpnp.h:778
LPWSTR m_pchData
Definition: chstring.h:95
char * va_list
Definition: acmsvcex.h:78
_Check_return_ _CRTIMP _CONST_RETURN wchar_t *__cdecl wcsrchr(_In_z_ const wchar_t *_Str, _In_ wchar_t _Ch)
Definition: bufpool.h:45
return Found
Definition: dirsup.c:1270
const char * LPCSTR
Definition: xmlstorage.h:183
_CRTIMP wchar_t *__cdecl _wcsupr(_Inout_z_ wchar_t *_String)
void AllocCopy(CHString &dest, int nCopyLen, int nCopyIndex, int nExtraLen) const
Definition: chstring.cpp:319
void FormatV(LPCWSTR lpszFormat, va_list argList)
Definition: chstring.cpp:651
void MakeLower()
Definition: chstring.cpp:839
LPWSTR GetBufferSetLength(int nNewLength)
Definition: chstring.cpp:733
CHStringData afxNullData
Definition: chstring.cpp:39
long nRefs
Definition: chstring.h:11
_CONST_RETURN wchar_t *__cdecl wcschr(_In_z_ const wchar_t *_Str, wchar_t _Ch)
__wchar_t WCHAR
Definition: xmlstorage.h:180
void SetAt(int nIndex, WCHAR ch)
Definition: chstring.cpp:1040
void AllocBuffer(int nLen)
Definition: chstring.cpp:269
CHString SpanIncluding(LPCWSTR lpszCharSet) const
Definition: chstring.cpp:1062
int Find(WCHAR ch) const
Definition: chstring.cpp:555
#define WINAPI
Definition: msvc.h:8
#define Len
Definition: deflate.h:82
int mbstowcsz(LPWSTR lpDest, LPCSTR lpSrc, int nLen)
Definition: chstring.cpp:75
#define iswspace(_c)
Definition: ctype.h:669
CHString WINAPI operator+(WCHAR ch, const CHString &string)
Definition: chstring.cpp:1337
void Release()
Definition: chstring.cpp:921
static const WCHAR L[]
Definition: oid.c:1250
void FreeExtra()
Definition: chstring.cpp:659
#define InterlockedDecrement
Definition: armddk.h:52
void MakeReverse()
Definition: chstring.cpp:851
LPWSTR GetBuffer(int nMinBufLength)
Definition: chstring.cpp:698
int ReverseFind(WCHAR ch) const
Definition: chstring.cpp:983
int GetLength() const
Definition: chstring.cpp:762
#define wcsicmp
Definition: string.h:1152
int Collate(LPCWSTR lpsz) const
Definition: chstring.cpp:400
int Compare(LPCWSTR lpsz) const
Definition: chstring.cpp:410
_CRTIMP wchar_t *__cdecl _wcslwr(_Inout_z_ wchar_t *_String)
_Check_return_ _CRTIMP int __cdecl wcscmp(_In_z_ const wchar_t *_Str1, _In_z_ const wchar_t *_Str2)
#define InterlockedIncrement
Definition: armddk.h:53
_CRTIMP wchar_t *__cdecl wcsncpy(wchar_t *_Dest, const wchar_t *_Source, size_t _Count)
VOID WINAPI RaiseException(IN DWORD dwExceptionCode, IN DWORD dwExceptionFlags, IN DWORD nNumberOfArguments, IN CONST ULONG_PTR *lpArguments OPTIONAL)
Definition: except.c:693
static BYTE * GetData(BYTE *pData, ULONG *pLength)
Definition: assembly.c:113
_Check_return_ _CRTIMP _CONST_RETURN wchar_t *__cdecl wcspbrk(_In_z_ const wchar_t *_Str, _In_z_ const wchar_t *_Control)
#define va_start(ap, A)
Definition: acmsvcex.h:91
unsigned int UINT
Definition: ndis.h:50
#define MultiByteToWideChar
Definition: compat.h:100
CHString Mid(int nFirst) const
Definition: chstring.cpp:875
void FormatMessageW(UINT nFormatID,...)
Definition: chstring.cpp:634
const CHString & operator=(char ch)
Definition: chstring.cpp:1168
int CompareNoCase(LPCWSTR lpsz) const
Definition: chstring.cpp:420
CHString SpanExcluding(LPCWSTR lpszCharSet) const
Definition: chstring.cpp:1050
WCHAR GetAt(int nIndex) const
Definition: chstring.cpp:689
#define UNIMPLEMENTED
Definition: debug.h:114
#define ULONG_PTR
Definition: config.h:101
#define malloc
Definition: debug_ros.c:4
BOOL IsEmpty() const
Definition: chstring.cpp:778
static char * dest
Definition: rtl.c:135
BSTR AllocSysString() const
Definition: chstring.cpp:357
GLfloat GLfloat p
Definition: glext.h:8902
WCHAR * LPWSTR
Definition: xmlstorage.h:184
TW_UINT32 TW_UINT16 TW_UINT16 TW_MEMREF pData
Definition: twain.h:1827
IN BOOLEAN OUT PSTR Buffer
Definition: progress.h:34
void CopyBeforeWrite()
Definition: chstring.cpp:505
WCHAR operator[](int nIndex) const
Definition: chstring.cpp:1321
static int WINAPI SafeStrlen(LPCWSTR lpsz)
Definition: chstring.cpp:1023
_Check_return_ _CRTIMP size_t __cdecl wcsspn(_In_z_ const wchar_t *_Str, _In_z_ const wchar_t *_Control)
size_t __cdecl wcslen(_In_z_ const wchar_t *_Str)
int FindOneOf(LPCWSTR lpszCharSet) const
Definition: chstring.cpp:593
int GetAllocLength() const
Definition: chstring.cpp:681
unsigned int(__cdecl typeof(jpeg_read_scanlines))(struct jpeg_decompress_struct *
Definition: typeof.h:31
void TrimRight()
Definition: chstring.cpp:1107