ReactOS  0.4.15-dev-2720-g5ee0925
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  */
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(reinterpret_cast<LPWSTR>(m_pchData),
150  reinterpret_cast<LPCWSTR>(lpsz),
151  Len);
152  }
153  }
154 }
155 
156 /*
157  * @implemented
158  */
160 {
161  // Allow null initialize, in case something goes wrong
163 
164  // In case we have a string with a len
165  if (lpch != 0 && nLength != 0)
166  {
167  // Just copy the string
169  wcsncpy(reinterpret_cast<LPWSTR>(m_pchData),
170  reinterpret_cast<LPCWSTR>(lpch),
171  nLength);
172  }
173 }
174 
175 /*
176  * @implemented
177  */
179 {
180  // Allow null initialize, in case something goes wrong
182 
183  // If we have input string
184  if (lpsz != 0)
185  {
186  // Get its length
187  int Len = (int)strlen(lpsz);
188  if (Len)
189  {
190  // Allocate and convert the string
191  AllocBuffer(Len);
192  mbstowcsz(reinterpret_cast<LPWSTR>(m_pchData), lpsz, Len + 1);
193  // Releasing buffer here is to allow to
194  // update the buffer size. We notify we're
195  // done with changing the string: recompute its
196  // length, please
197  ReleaseBuffer();
198  }
199  }
200 }
201 
202 /*
203  * @implemented
204  */
205 CHString::CHString(const unsigned char* lpsz)
206 {
207  // Null init
208  Init();
209  // And call operator= with const char*, easier
210  *this = (LPCSTR)lpsz;
211 }
212 
213 /*
214  * @implemented
215  */
216 CHString::CHString(const CHString& stringSrc)
217 {
218  // If we have currently no referenced string
219  if (stringSrc.GetData()->nRefs < 0)
220  {
221  // Ensure we have the null string
223  // And then call, the copy operator with input string
224  *this = stringSrc.m_pchData;
225  }
226  else
227  {
228  // Otherwise, just copy the input string
229  m_pchData = stringSrc.m_pchData;
230  // And increment the number of references
231  InterlockedIncrement(&GetData()->nRefs);
232  // The whole point here is: Am I forget to release the old
233  // data?! MS doesn't release it, but I guess we should...
234  }
235 }
236 
237 /*
238  * @implemented
239  */
241 {
242  // If we have a string
243  if (GetData() != &afxNullData)
244  {
245  // Check whether it's still in use after we release it
246  if (InterlockedDecrement(&GetData()->nRefs) == 0)
247  {
248  // If so, delete it
249  delete GetData();
250  }
251  }
252 }
253 
254 /*
255  * @implemented
256  */
258 {
259  // In case we have several strings pointing to our memory zone
260  // Or we need bigger buffer than actual
261  if (GetData()->nRefs > 1 || nLen > GetData()->nAllocLength)
262  {
263  // Just drop current
264  // And allocate a new one which is big enough
265  Release();
266  AllocBuffer(nLen);
267  }
268 }
269 
270 /*
271  * @implemented
272  */
274 {
275  // Here we have to allocate a buffer for the string
276  // It actually consists in: CHStringData structure
277  // with a buffer big enough at its end to store the
278  // string.
280 
281  // Null size is easy allocation
282  if (nSize == 0)
283  {
285  return;
286  }
287 
288  // We cannot allow negative sizes
289  if (nSize < 0)
290  {
292  }
293 
294  // Nor too big
295  if (nSize > (INT_MAX - (int)sizeof(CHStringData)) / (int)sizeof(WCHAR))
296  {
298  }
299 
300  // Just allocate big enough buffer, using our own operator new
301  Data = (CHStringData *)operator new(nSize * sizeof(WCHAR) + sizeof(CHStringData));
302  // In case Data is null, throw an exception
303  // Yes, this is stupid! Our operator new is already supposed to through an exception...
304  // Thanks MS
305  if (!Data)
306  {
307  throw HeapException;
308  }
309 
310  Data->nRefs = 1;
311  Data->nDataLength = nSize;
312  Data->nAllocLength = nSize;
313  Data->data()[0] = 0;
314 
315  // We only return the string
316  // We can find back data with some mathematics
317  m_pchData = Data->data();
318 }
319 
320 /*
321  * @implemented
322  */
323 void CHString::AllocCopy(CHString& dest, int nCopyLen, int nCopyIndex, int nExtraLen) const
324 {
325  // Once again, we cannot deal with negative lens
326  if (nCopyLen < 0)
327  {
329  }
330 
331  if (nCopyIndex < 0)
332  {
334  }
335 
336  if (nExtraLen < 0)
337  {
339  }
340 
341  // In case what we have to copy is null-sized, just set empty string
342  if (nCopyLen + nExtraLen == 0)
343  {
344  dest.m_pchData = afxPchNil;
345  return;
346  }
347 
348  // Otherwise, allocate a buffer in new string which is big enough
349  // You can note that we absolutely don't check about any existing
350  // (referenced) buffer in dest. Actually, dest is to be EMPTY string.
351  // The whole point of this function is to initialize a virgin string by
352  // copying data from another. This is needed by Left/Mid/Right
353  dest.AllocBuffer(nCopyLen + nExtraLen);
354  // And copy our stuff in
355  wcsncpy(reinterpret_cast<LPWSTR>(dest.m_pchData),
356  reinterpret_cast<LPWSTR>(m_pchData + nCopyIndex),
357  nCopyLen);
358 }
359 
360 /*
361  * @implemented
362  */
364 {
365  BSTR SysString;
366 
367  // Just allocate the string
368  SysString = SysAllocStringLen(reinterpret_cast<LPWSTR>(m_pchData), GetData()->nDataLength);
369  if (!SysString)
370  {
371  throw HeapException;
372  }
373 
374  return reinterpret_cast<CHSTRING_LPWSTR>(SysString);
375 }
376 
377 /*
378  * @implemented
379  */
380 void CHString::AssignCopy(int nSrcLen, CHSTRING_LPCWSTR lpszSrcData)
381 {
382  // Don't allow negative len
383  if (nSrcLen < 0)
384  {
386  }
387 
388  // We will have to modify a string that might be shared, so duplicate it
389  // Ensuring it's big enough to contain our new stuff
390  AllocBeforeWrite(nSrcLen);
391  if (nSrcLen == 0)
392  {
393  Release();
394  return;
395  }
396 
397  // Just copy, write down new size, and ensure it's null terminated
398  wcsncpy(reinterpret_cast<LPWSTR>(m_pchData),
399  reinterpret_cast<LPCWSTR>(lpszSrcData), nSrcLen);
400  GetData()->nDataLength = nSrcLen;
401  m_pchData[nSrcLen] = 0;
402 }
403 
404 /*
405  * @implemented
406  */
408 {
409  // Just call the deprecated function here - no matter we are null terminated
410  // Did you read my statement about how safe is this implementation?
411  return wcscoll(reinterpret_cast<LPCWSTR>(m_pchData), reinterpret_cast<LPCWSTR>(lpsz));
412 }
413 
414 /*
415  * @implemented
416  */
418 {
419  // Just call the deprecated function here - no matter we are null terminated
420  // Did you read my statement about how safe is this implementation?
421  return wcscmp(reinterpret_cast<LPCWSTR>(m_pchData), reinterpret_cast<LPCWSTR>(lpsz));
422 }
423 
424 /*
425  * @implemented
426  */
428 {
429  // Just call the deprecated function here - no matter we are null terminated
430  // Did you read my statement about how safe is this implementation?
431  return wcsicmp(reinterpret_cast<LPCWSTR>(m_pchData), reinterpret_cast<LPCWSTR>(lpsz));
432 }
433 
434 /*
435  * @implemented
436  */
437 void CHString::ConcatInPlace(int nSrcLen, CHSTRING_LPCWSTR lpszSrcData)
438 {
439  // With null length, there's not that much to concat...
440  if (nSrcLen == 0)
441  {
442  return;
443  }
444 
445  // Still no negative length
446  if (nSrcLen < 0)
447  {
449  }
450 
451  // Ensure we wouldn't overflow with the concat
452  if (GetData()->nDataLength > INT_MAX - nSrcLen)
453  {
455  }
456 
457  // In case we have to modify a shared string OR if it can't fit into current buffer...
458  if (GetData()->nRefs > 1 || GetData()->nDataLength + nSrcLen > GetData()->nAllocLength)
459  {
460  // Allocate a new buffer! (without forgetting to release old one)
461  CHStringData* OldData = GetData();
462 
463  // You remember about "InPlace" in the function's name?
464  // The cake is a lie
465  ConcatCopy(GetData()->nDataLength, m_pchData, nSrcLen, lpszSrcData);
466  Release(OldData);
467  }
468  else
469  {
470  // Ensure we don't overflow
471  if (nSrcLen > INT_MAX - GetData()->nDataLength)
472  {
474  }
475 
476  // Then, just copy and null terminate
477  wcsncpy(reinterpret_cast<LPWSTR>(m_pchData + GetData()->nDataLength),
478  reinterpret_cast<LPCWSTR>(lpszSrcData),
479  nSrcLen);
480  GetData()->nDataLength += nSrcLen;
481  m_pchData[GetData()->nDataLength] = 0;
482  }
483 }
484 
485 /*
486  * @implemented
487  */
489  int nSrc1Len, CHSTRING_LPCWSTR lpszSrc1Data,
490  int nSrc2Len, CHSTRING_LPCWSTR lpszSrc2Data)
491 {
492  int TotalLen;
493 
494  if (nSrc1Len < 0 || nSrc2Len < 0)
495  {
497  }
498 
499  // If both len are null, do nothing
500  TotalLen = nSrc1Len + nSrc2Len;
501  if (TotalLen == 0)
502  {
503  return;
504  }
505 
506  // Otherwise, allocate a new buffer to hold everything (caller will release previous buffer)
507  AllocBuffer(TotalLen);
508  // And concat stuff
509  wcsncpy(reinterpret_cast<LPWSTR>(m_pchData),
510  reinterpret_cast<LPCWSTR>(lpszSrc1Data),
511  nSrc1Len);
512  wcsncpy(reinterpret_cast<LPWSTR>(m_pchData + nSrc1Len),
513  reinterpret_cast<LPCWSTR>(lpszSrc2Data),
514  nSrc2Len);
515 }
516 
517 /*
518  * @implemented
519  */
521 {
523 
524  // First, we need to get reference count
525  // And we also need to save Data for later copy
526  Data = GetData();
527 
528  if (Data->nRefs <= 1)
529  {
530  // If its not used, don't waste time to realloc, it will do the job
531  return;
532  }
533 
534  // Release current data - we are sure it won't be freed upon that point
535  // Thanks to the reference count check previously done
536  Release();
537  // Alloc new buffer and copy old data in it
538  AllocBuffer(Data->nDataLength);
539  wcsncpy(reinterpret_cast<LPWSTR>(m_pchData),
540  reinterpret_cast<LPCWSTR>(Data->data()),
541  Data->nDataLength);
542 }
543 
544 /*
545  * @implemented
546  */
548 {
549  // Already empty
550  if (GetData()->nDataLength == 0)
551  {
552  return;
553  }
554 
555  // Empty it easily given it's reference count
556  if (GetData()->nRefs < 0)
557  {
558  *this = afxPchNil;
559  }
560  else
561  {
562  // Otherwise, just release it
563  // It will set back this instance to afxPchNil
564  // while decreasing reference count
565  Release();
566  }
567 }
568 
569 /*
570  * @implemented
571  */
573 {
575 
576  // Let's use appropriate helper
577  Found = reinterpret_cast<CHSTRING_LPCWSTR>(wcschr(reinterpret_cast<LPCWSTR>(m_pchData), ch));
578  // We have to return a position, so compute it
579  if (Found)
580  {
581  return (Found - m_pchData);
582  }
583 
584  // Otherwise, return no position
585  return -1;
586 }
587 
588 /*
589  * @implemented
590  */
592 {
594 
595  // Let's use appropriate helper
596  Found = reinterpret_cast<CHSTRING_LPCWSTR>(wcsstr(reinterpret_cast<LPCWSTR>(m_pchData), reinterpret_cast<LPCWSTR>(lpszSub)));
597  // We have to return a position, so compute it
598  if (Found)
599  {
600  return (Found - m_pchData);
601  }
602 
603  // Otherwise, return no position
604  return -1;
605 }
606 
607 /*
608  * @implemented
609  */
610 int CHString::FindOneOf(CHSTRING_LPCWSTR lpszCharSet) const
611 {
613 
614  // Let's use appropriate helper
615  Found = reinterpret_cast<CHSTRING_LPCWSTR>(wcspbrk(reinterpret_cast<LPCWSTR>(m_pchData), reinterpret_cast<LPCWSTR>(lpszCharSet)));
616  // We have to return a position, so compute it
617  if (Found)
618  {
619  return (Found - m_pchData);
620  }
621 
622  // Otherwise, return no position
623  return -1;
624 }
625 
626 /*
627  * @implemented
628  */
629 void CHString::Format(UINT nFormatID, ...)
630 {
631  // Deprecated and not implemented any longer - well, this is its implementation
632  return;
633 }
634 
635 /*
636  * @implemented
637  */
638 void CHString::Format(CHSTRING_LPCWSTR lpszFormat, ...)
639 {
640  // Forward to FormatV
641  va_list ArgsList;
642 
643  va_start(ArgsList, lpszFormat);
644  FormatV(lpszFormat, ArgsList);
645  va_end(ArgsList);
646 }
647 
648 /*
649  * @implemented
650  */
651 void CHString::FormatMessageW(UINT nFormatID, ...)
652 {
653  // Deprecated and not implemented any longer - well, this is its implementation
654  return;
655 }
656 
657 /*
658  * @unimplemented
659  */
661 {
663 }
664 
665 /*
666  * @unimplemented
667  */
668 void CHString::FormatV(CHSTRING_LPCWSTR lpszFormat, va_list argList)
669 {
671 }
672 
673 /*
674  * @implemented
675  */
677 {
678  CHStringData* OldData;
679 
680  // No extra? Do nothing
681  if (GetData()->nDataLength == GetData()->nAllocLength)
682  {
683  return;
684  }
685 
686  // Get old buffer
687  OldData = GetData();
688  // Allocate a new one, at the right size (with no place for \0 :-))
689  AllocBuffer(GetData()->nDataLength);
690  // Copy old and release it
691  wcsncpy(reinterpret_cast<LPWSTR>(m_pchData), reinterpret_cast<LPCWSTR>(OldData->data()), OldData->nDataLength);
692  Release(OldData);
693 }
694 
695 /*
696  * @implemented
697  */
699 {
700  return GetData()->nAllocLength;
701 }
702 
703 /*
704  * @implemented
705  */
707 {
708  // It's up to you to check the index!
709  return m_pchData[nIndex];
710 }
711 
712 /*
713  * @implemented
714  */
716 {
717  CHSTRING_LPWSTR OldBuffer = m_pchData;
718 
719  // We'll have to allocate a new buffer if it's not big enough
720  // or if it's shared by several strings
721  if (GetData()->nRefs > 1 || GetData()->nAllocLength < nMinBufLength)
722  {
723  CHStringData* OldData = GetData();
724  int OldLen = GetData()->nDataLength;
725 
726  // Ensure we can hold enough
727  if (OldLen > nMinBufLength)
728  {
729  nMinBufLength = OldLen;
730  }
731 
732  // Allocate new buffer
733  AllocBuffer(nMinBufLength);
734  // Copy contents
735  wcsncpy(reinterpret_cast<LPWSTR>(m_pchData), reinterpret_cast<LPCWSTR>(OldBuffer), OldLen);
736  GetData()->nDataLength = OldLen;
737 
738  // Release old
739  Release(OldData);
740  }
741 
742  // Weirdly, here Windows always returns the old buffer
743  // Which basically exposes a wrong buffer
744  return OldBuffer;
745 }
746 
747 /*
748  * @implemented
749  */
751 {
752  // Get a buffer big enough
753  // We don't care about the return, it will be set in the string
754  (void)GetBuffer(nNewLength);
755  // Set length, null-terminate and return
756  GetData()->nDataLength = nNewLength;
757  m_pchData[nNewLength] = 0;
758  return m_pchData;
759 }
760 
761 /*
762  * @implemented
763  */
765 {
766  // In case of empty string, return empty data
767  if (m_pchData == afxPchNil)
768  {
769  return &afxNullData;
770  }
771 
772  // Otherwise, do maths
773  return (CHStringData*)((ULONG_PTR)m_pchData - sizeof(CHStringData));
774 }
775 
776 /*
777  * @implemented
778  */
780 {
781  return GetData()->nDataLength;
782 }
783 
784 /*
785  * @implemented
786  */
788 {
790 }
791 
792 /*
793  * @implemented
794  */
796 {
797  return (GetData()->nDataLength == 0);
798 }
799 
800 /*
801  * @implemented
802  */
803 CHString CHString::Left(int nCount) const
804 {
805  CHString NewString;
806 
807  // Validate input (we can't get more than what we have ;-))
808  if (nCount)
809  {
810  if (nCount > GetData()->nDataLength)
811  {
812  nCount = GetData()->nDataLength;
813  }
814  }
815 
816  AllocCopy(NewString, nCount, 0, 0);
817 
818  return NewString;
819 }
820 
821 /*
822  * @implemented
823  */
825 {
826  // Deprecated and not implemented any longer - well, this is its implementation
827  return 0;
828 }
829 
830 /*
831  * @implemented
832  */
833 int CHString::LoadStringW(UINT nID, CHSTRING_LPWSTR lpszBuf, UINT nMaxBuf)
834 {
835  // Deprecated and not implemented any longer - well, this is its implementation
836  return 0;
837 }
838 
839 /*
840  * @implemented
841  */
843 {
844  CHSTRING_LPWSTR LockedBuffer;
845 
846  // The purpose here is basically to set the nRefs to max int
847  LockedBuffer = GetBuffer(0);
848  GetData()->nRefs = INT_MAX;
849 
850  return LockedBuffer;
851 }
852 
853 /*
854  * @implemented
855  */
857 {
858  // We'll modify string, duplicate it first if needed
859  CopyBeforeWrite();
860 
861  // Let's use appropriate helper
862  _wcslwr(reinterpret_cast<LPWSTR>(m_pchData));
863 }
864 
865 /*
866  * @implemented
867  */
869 {
870  // We'll modify string, duplicate it first if needed
871  CopyBeforeWrite();
872 
873  // Let's use appropriate helper
874  _wcsrev(reinterpret_cast<LPWSTR>(m_pchData));
875 }
876 
877 /*
878  * @implemented
879  */
881 {
882  // We'll modify string, duplicate it first if needed
883  CopyBeforeWrite();
884 
885  // Let's use appropriate helper
886  _wcsupr(reinterpret_cast<LPWSTR>(m_pchData));
887 }
888 
889 /*
890  * @implemented
891  */
892 CHString CHString::Mid(int nFirst) const
893 {
894  // Take string from nFirst up to the end
895  return Mid(nFirst, GetData()->nDataLength - nFirst);
896 }
897 
898 /*
899  * @implemented
900  */
901 CHString CHString::Mid(int nFirst, int nCount) const
902 {
903  CHString NewString;
904 
905  // Validate sizes first
906  if (nFirst < 0)
907  {
908  nFirst = 0;
909  }
910 
911  if (nCount < 0)
912  {
913  nCount = 0;
914  }
915 
916  // Ensure we don't go beyond the string
917  if (nFirst + nCount > GetData()->nDataLength)
918  {
919  nCount = GetData()->nDataLength - nFirst;
920  }
921 
922  // Also ensure we don't read beyond
923  // Yes, this should have been done before previous check
924  // MS does it that way
925  if (nFirst > GetData()->nDataLength)
926  {
927  nCount = 0;
928  }
929 
930  AllocCopy(NewString, nCount, nFirst, 0);
931 
932  return NewString;
933 }
934 
935 /*
936  * @implemented
937  */
939 {
940  // If null string, nothing to do
941  if (GetData() == &afxNullData)
942  {
943  return;
944  }
945 
946  // Otherwise, decrement ref count and release if required
947  if (InterlockedDecrement(&GetData()->nRefs) == 0)
948  {
949  delete GetData();
950  }
951 
952  // In all cases, caller doesn't want string anymore
953  // So, switch back to empty string
955 }
956 
957 /*
958  * @implemented
959  */
961 {
962  // If empty string, ignore
963  if (pData == &afxNullData)
964  {
965  return;
966  }
967 
968  // Otherwise, simply and free if needed
969  if (InterlockedDecrement(&pData->nRefs) == 0)
970  {
971  delete pData;
972  }
973 }
974 
975 /*
976  * @implemented
977  */
978 void CHString::ReleaseBuffer(int nNewLength)
979 {
981 
982  // We'll modify buffer, so duplicate
983  CopyBeforeWrite();
984 
985  // If no len provided, get one
986  if (nNewLength == -1)
987  {
988  nNewLength = (int)wcslen(reinterpret_cast<LPCWSTR>(m_pchData));
989  }
990 
991  // Set appropriate size and null-terminate
992  Data = GetData();
993  Data->nDataLength = nNewLength;
994  Data->data()[nNewLength] = 0;
995 }
996 
997 /*
998  * @implemented
999  */
1001 {
1002  CHSTRING_WCHAR *Last;
1003 
1004  // Let's use appropriate helper
1005  Last = reinterpret_cast<CHSTRING_WCHAR*>(wcsrchr(reinterpret_cast<LPCWSTR>(m_pchData), ch));
1006  // We have to return a position, so compute it
1007  if (Last)
1008  {
1009  return (Last - m_pchData);
1010  }
1011 
1012  // Otherwise, return no position
1013  return -1;
1014 }
1015 
1016 /*
1017  * @implemented
1018  */
1019 CHString CHString::Right(int nCount) const
1020 {
1021  CHString NewString;
1022 
1023  // Validate input (we can't get more than what we have ;-))
1024  if (nCount >= 0)
1025  {
1026  if (nCount > GetData()->nDataLength)
1027  {
1028  nCount = GetData()->nDataLength;
1029  }
1030  }
1031 
1032  AllocCopy(NewString, nCount, GetData()->nDataLength - nCount, 0);
1033 
1034  return NewString;
1035 }
1036 
1037 /*
1038  * @implemented
1039  */
1041 {
1042  // Check we have a string and then get its length
1043  if (lpsz == 0)
1044  {
1045  return 0;
1046  }
1047 
1048  // Of course, it's not safe at all in case string is not null-terminated.
1049  // Things that may happen given strings are not to be null-terminated
1050  // in this class...
1051  return (int)wcslen(reinterpret_cast<LPCWSTR>(lpsz));
1052 }
1053 
1054 /*
1055  * @implemented
1056  */
1057 void CHString::SetAt(int nIndex, CHSTRING_WCHAR ch)
1058 {
1059  CopyBeforeWrite();
1060 
1061  m_pchData[nIndex] = ch;
1062 }
1063 
1064 /*
1065  * @implemented
1066  */
1068 {
1069  int Count;
1070 
1071  // Get position and then, extract
1072  Count = (int)wcscspn(reinterpret_cast<LPCWSTR>(m_pchData), reinterpret_cast<LPCWSTR>(lpszCharSet));
1073  return Left(Count);
1074 }
1075 
1076 /*
1077  * @implemented
1078  */
1080 {
1081  int Count;
1082 
1083  // Get position and then, extract
1084  Count = (int)wcsspn(reinterpret_cast<LPCWSTR>(m_pchData), reinterpret_cast<LPCWSTR>(lpszCharSet));
1085  return Left(Count);
1086 }
1087 
1088 /*
1089  * @implemented
1090  */
1092 {
1093  int NewBegin;
1094  int NewLength;
1095  CHSTRING_WCHAR *CurrentChar;
1096 
1097  // We'll modify, so copy first
1098  CopyBeforeWrite();
1099 
1100  // Start at the begin of the string
1101  CurrentChar = m_pchData;
1102  while (*CurrentChar != 0)
1103  {
1104  // Browse string till we find something which is not a space
1105  if (!iswspace(*CurrentChar))
1106  {
1107  break;
1108  }
1109 
1110  CurrentChar++;
1111  }
1112 
1113  // Then, calculate new begin (easy) and new length
1114  // And move memory
1115  NewBegin = (CurrentChar - m_pchData);
1116  NewLength = GetData()->nDataLength - NewBegin;
1117  memmove(m_pchData, CurrentChar, NewLength * sizeof(CHSTRING_WCHAR));
1119 }
1120 
1121 /*
1122  * @implemented
1123  */
1125 {
1126  CHSTRING_WCHAR *CurrentChar;
1127  CHSTRING_WCHAR *CanBeEaten;
1128 
1129  // We'll modify, so copy first
1130  CopyBeforeWrite();
1131 
1132  // Start at the begin of the string -- WHAT?!
1133  // Yes, this algorithm is the same that MS is
1134  // using for its TrimRight.
1135  // It is highly unefficient. It would have been
1136  // easier to start at nDataLength and to get back to
1137  // the begin. Note that it would have been safer as
1138  // well, in case the caller is using non-null-terminated
1139  // strings. But, well...
1140  CurrentChar = m_pchData;
1141  CanBeEaten = 0;
1142  while (*CurrentChar != 0)
1143  {
1144  // If not a space, reset what we can trim
1145  if (!iswspace(*CurrentChar))
1146  {
1147  CanBeEaten = 0;
1148  }
1149  // If it is one, and the first of the spaces serie
1150  // Keep its position
1151  else if (CanBeEaten == 0)
1152  {
1153  CanBeEaten = CurrentChar;
1154  }
1155 
1156  CurrentChar++;
1157  }
1158 
1159  // If nothing to trim, quit
1160  if (CanBeEaten == 0)
1161  {
1162  return;
1163  }
1164 
1165  // Otherwise, shorten the string
1166  GetData()->nDataLength = (CanBeEaten - m_pchData);
1167 }
1168 
1169 /*
1170  * @implemented
1171  */
1173 {
1174  // Unlock means just put ref back to 1
1175  // It was previously set to MAX_INT
1176  if (GetData() != &afxNullData)
1177  {
1178  GetData()->nRefs = 1;
1179  }
1180 }
1181 
1182 /*
1183  * @implemented
1184  */
1186 {
1187  *this = (CHSTRING_WCHAR)ch;
1188  return *this;
1189 }
1190 
1191 /*
1192  * @implemented
1193  */
1195 {
1196  AssignCopy(1, &ch);
1197  return *this;
1198 }
1199 
1200 /*
1201  * @implemented
1202  */
1204 {
1205  *this = *p;
1206  return *this;
1207 }
1208 
1209 /*
1210  * @implemented
1211  */
1213 {
1214  int Len;
1215 
1216  // If we have string, get its len
1217  if (lpsz != 0)
1218  {
1219  Len = (int)strlen(lpsz);
1220  }
1221  else
1222  {
1223  Len = 0;
1224  }
1225 
1226  // Do this call, even with null len, just to get empty string
1228  if (Len == 0)
1229  {
1230  Release();
1231  return *this;
1232  }
1233 
1234  // Convert and copy
1235  mbstowcsz(reinterpret_cast<LPWSTR>(m_pchData), lpsz, Len + 1);
1236  // Get new size and so on
1237  ReleaseBuffer();
1238 
1239  return *this;
1240 }
1241 
1242 /*
1243  * @implemented
1244  */
1246 {
1247  int Len;
1248 
1249  Len = SafeStrlen(lpsz);
1250  AssignCopy(Len, lpsz);
1251 
1252  return *this;
1253 }
1254 
1255 /*
1256  * @implemented
1257  */
1258 const CHString& CHString::operator=(const CHString& stringSrc)
1259 {
1260  // Don't copy string on itself
1261  if (&stringSrc == this)
1262  {
1263  return *this;
1264  }
1265 
1266  // In case we don't have a referenced string here,
1267  // or if the other is not referenced, just copy here
1268  if ((GetData()->nRefs < 0 && GetData() != &afxNullData) ||
1269  stringSrc.GetData()->nRefs < 0)
1270  {
1271  AssignCopy(stringSrc.GetData()->nDataLength, stringSrc.m_pchData);
1272  return *this;
1273  }
1274 
1275  // Otherwise, release current buffer
1276  Release();
1277  // And set buffer as stringSrc buffer
1278  // And increase its reference count
1279  m_pchData = stringSrc.m_pchData;
1280  InterlockedIncrement(&GetData()->nRefs);
1281 
1282  return *this;
1283 }
1284 
1285 /*
1286  * @implemented
1287  */
1288 const CHString& CHString::operator=(const unsigned char* lpsz)
1289 {
1290  *this = (LPCSTR)lpsz;
1291  return *this;
1292 }
1293 
1294 /*
1295  * @implemented
1296  */
1298 {
1299  *this += (CHSTRING_WCHAR)ch;
1300  return *this;
1301 }
1302 
1303 /*
1304  * @implemented
1305  */
1307 {
1308  ConcatInPlace(1, &ch);
1309  return *this;
1310 }
1311 
1312 /*
1313  * @implemented
1314  */
1316 {
1317  int Len;
1318 
1319  Len = SafeStrlen(lpsz);
1320  ConcatInPlace(Len, lpsz);
1321 
1322  return *this;
1323 }
1324 
1325 /*
1326  * @implemented
1327  */
1329 {
1330  ConcatInPlace(string.GetData()->nDataLength, string.m_pchData);
1331 
1332  return *this;
1333 }
1334 
1335 /*
1336  * @implemented
1337  */
1339 {
1340  return m_pchData[nIndex];
1341 }
1342 
1343 /*
1344  * @implemented
1345  */
1347 {
1348  return m_pchData;
1349 }
1350 
1351 /*
1352  * @implemented
1353  */
1355 {
1356  CHString NewString;
1357 
1358  // Basically concat in a new string
1359  NewString.ConcatCopy(1, &ch, string.GetData()->nDataLength, string.m_pchData);
1360 
1361  return NewString;
1362 }
1363 
1364 /*
1365  * @implemented
1366  */
1368 {
1369  CHString NewString;
1370 
1371  // Basically concat in a new string
1372  NewString.ConcatCopy(string.GetData()->nDataLength, string.m_pchData, 1, &ch);
1373 
1374  return NewString;
1375 }
1376 
1377 /*
1378  * @implemented
1379  */
1381 {
1382  int Len;
1383  CHString NewString;
1384 
1385  // Get string length
1386  Len = CHString::SafeStrlen(lpsz);
1387  // And concat in new string
1388  NewString.ConcatCopy(string.GetData()->nDataLength, string.m_pchData, Len, lpsz);
1389 
1390  return NewString;
1391 }
1392 
1393 /*
1394  * @implemented
1395  */
1397 {
1398  int Len;
1399  CHString NewString;
1400 
1401  // Get string length
1402  Len = CHString::SafeStrlen(lpsz);
1403  // And concat in new string
1404  NewString.ConcatCopy(Len, lpsz, string.GetData()->nDataLength, string.m_pchData);
1405 
1406  return NewString;
1407 }
1408 
1409 /*
1410  * @implemented
1411  */
1413 {
1414  CHString NewString;
1415 
1416  // Basically concat in a new string
1417  NewString.ConcatCopy(string1.GetData()->nDataLength, string1.m_pchData,
1418  string2.GetData()->nDataLength, string2.m_pchData);
1419 
1420  return NewString;
1421 }
#define ERROR_INVALID_PARAMETER
Definition: compat.h:101
_CRTIMP wchar_t *__cdecl _wcsrev(_Inout_z_ wchar_t *_Str)
CHStringData * GetData() const
Definition: chstring.cpp:764
#define memmove(s1, s2, n)
Definition: mkisofs.h:881
void UnlockBuffer()
Definition: chstring.cpp:1172
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:629
BSTR WINAPI SysAllocStringLen(const OLECHAR *str, unsigned int len)
Definition: oleaut.c:339
int ReverseFind(CHSTRING_WCHAR ch) const
Definition: chstring.cpp:1000
void Init()
Definition: chstring.cpp:787
int CompareNoCase(CHSTRING_LPCWSTR lpsz) const
Definition: chstring.cpp:427
_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
IN BOOLEAN OUT PSTR Buffer
Definition: progress.h:34
void AllocBeforeWrite(int nLen)
Definition: chstring.cpp:257
_CONST_RETURN wchar_t *__cdecl wcsstr(_In_z_ const wchar_t *_Str, _In_z_ const wchar_t *_SubStr)
void Empty()
Definition: chstring.cpp:547
#define CP_ACP
Definition: compat.h:109
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)
_Must_inspect_result_ _In_ WDFDEVICE _In_ PWDF_DEVICE_PROPERTY_DATA _In_ DEVPROPTYPE _In_ ULONG _In_opt_ PVOID Data
Definition: wdfdevice.h:4527
#define free
Definition: debug_ros.c:5
CHeap_Exception HeapException(CHeap_Exception::E_ALLOCATION_ERROR)
int nAllocLength
Definition: chstring.h:23
*nSize LPSTR _Inout_ LPDWORD nSize
Definition: winbase.h:2053
CHString Left(int nCount) const
Definition: chstring.cpp:803
void ReleaseBuffer(int nNewLength=-1)
Definition: chstring.cpp:978
_In_ DWORD nLength
Definition: wincon.h:473
int nDataLength
Definition: chstring.h:22
CHString SpanIncluding(CHSTRING_LPCWSTR lpszCharSet) const
Definition: chstring.cpp:1079
operator
#define EXCEPTION_NONCONTINUABLE
Definition: rtltypes.h:154
static CHAR string1[MAX_PATH]
Definition: asmname.c:32
CHSTRING_WCHAR * CHSTRING_LPWSTR
Definition: chstring.h:15
OLECHAR * BSTR
Definition: compat.h:2152
int LoadStringW(UINT nID)
Definition: chstring.cpp:824
void TrimLeft()
Definition: chstring.cpp:1091
CHSTRING_WCHAR operator[](int nIndex) const
Definition: chstring.cpp:1338
int Compare(CHSTRING_LPCWSTR lpsz) const
Definition: chstring.cpp:417
void MakeUpper()
Definition: chstring.cpp:880
static USHORT USHORT * NewLength
CHSTRING_WCHAR * data()
Definition: chstring.h:25
#define va_end(ap)
Definition: acmsvcex.h:90
CHSTRING_LPWSTR m_pchData
Definition: chstring.h:147
#define STATUS_INTEGER_OVERFLOW
Definition: ntstatus.h:385
unsigned int BOOL
Definition: ntddk_ex.h:94
CHString Right(int nCount) const
Definition: chstring.cpp:1019
static PVOID ptr
Definition: dispmode.c:27
int FindOneOf(CHSTRING_LPCWSTR lpszCharSet) const
Definition: chstring.cpp:610
const CHString & operator+=(char ch)
Definition: chstring.cpp:1297
char * va_list
Definition: acmsvcex.h:78
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:323
void MakeLower()
Definition: chstring.cpp:856
CHStringData afxNullData
Definition: chstring.cpp:39
long nRefs
Definition: chstring.h:21
CHSTRING_LPWSTR LockBuffer()
Definition: chstring.cpp:842
CHSTRING_LPWSTR GetBufferSetLength(int nNewLength)
Definition: chstring.cpp:750
void AssignCopy(int nSrcLen, CHSTRING_LPCWSTR lpszSrcData)
Definition: chstring.cpp:380
int Count
Definition: noreturn.cpp:7
int Find(CHSTRING_WCHAR ch) const
Definition: chstring.cpp:572
void ConcatCopy(int nSrc1Len, CHSTRING_LPCWSTR lpszSrc1Data, int nSrc2Len, CHSTRING_LPCWSTR lpszSrc2Data)
Definition: chstring.cpp:488
_CONST_RETURN wchar_t *__cdecl wcschr(_In_z_ const wchar_t *_Str, wchar_t _Ch)
__wchar_t WCHAR
Definition: xmlstorage.h:180
void AllocBuffer(int nLen)
Definition: chstring.cpp:273
#define WINAPI
Definition: msvc.h:6
#define Len
Definition: deflate.h:82
va_start(ap, x)
int mbstowcsz(LPWSTR lpDest, LPCSTR lpSrc, int nLen)
Definition: chstring.cpp:75
int Collate(CHSTRING_LPCWSTR lpsz) const
Definition: chstring.cpp:407
#define iswspace(_c)
Definition: ctype.h:669
#define wcsicmp
Definition: compat.h:15
void Release()
Definition: chstring.cpp:938
void FreeExtra()
Definition: chstring.cpp:676
#define InterlockedDecrement
Definition: armddk.h:52
void FormatV(CHSTRING_LPCWSTR lpszFormat, va_list argList)
Definition: chstring.cpp:668
CHSTRING_WCHAR GetAt(int nIndex) const
Definition: chstring.cpp:706
void MakeReverse()
Definition: chstring.cpp:868
#define wcsrchr
Definition: compat.h:16
int GetLength() const
Definition: chstring.cpp:779
CHSTRING_WCHAR afxPchNil[1]
Definition: chstring.cpp:37
void ConcatInPlace(int nSrcLen, CHSTRING_LPCWSTR lpszSrcData)
Definition: chstring.cpp:437
CHSTRING_LPWSTR AllocSysString() const
Definition: chstring.cpp:363
_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:700
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
unsigned short CHSTRING_WCHAR
Definition: chstring.h:13
static BYTE * GetData(BYTE *pData, ULONG *pLength)
Definition: assembly.c:114
_Check_return_ _CRTIMP _CONST_RETURN wchar_t *__cdecl wcspbrk(_In_z_ const wchar_t *_Str, _In_z_ const wchar_t *_Control)
unsigned int UINT
Definition: ndis.h:50
CHString WINAPI operator+(CHSTRING_WCHAR ch, const CHString &string)
Definition: chstring.cpp:1354
_CRTIMP size_t __cdecl wcslen(_In_z_ const wchar_t *_Str)
#define MultiByteToWideChar
Definition: compat.h:110
CHString Mid(int nFirst) const
Definition: chstring.cpp:892
void FormatMessageW(UINT nFormatID,...)
Definition: chstring.cpp:651
const CHString & operator=(char ch)
Definition: chstring.cpp:1185
#define UNIMPLEMENTED
Definition: debug.h:115
#define ULONG_PTR
Definition: config.h:101
static int WINAPI SafeStrlen(CHSTRING_LPCWSTR lpsz)
Definition: chstring.cpp:1040
#define malloc
Definition: debug_ros.c:4
BOOL IsEmpty() const
Definition: chstring.cpp:795
static char * dest
Definition: rtl.c:135
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
void CopyBeforeWrite()
Definition: chstring.cpp:520
CHSTRING_LPWSTR GetBuffer(int nMinBufLength)
Definition: chstring.cpp:715
_Check_return_ _CRTIMP size_t __cdecl wcsspn(_In_z_ const wchar_t *_Str, _In_z_ const wchar_t *_Control)
const CHSTRING_WCHAR * CHSTRING_LPCWSTR
Definition: chstring.h:14
void SetAt(int nIndex, CHSTRING_WCHAR ch)
Definition: chstring.cpp:1057
CHString SpanExcluding(CHSTRING_LPCWSTR lpszCharSet) const
Definition: chstring.cpp:1067
int GetAllocLength() const
Definition: chstring.cpp:698
unsigned int(__cdecl typeof(jpeg_read_scanlines))(struct jpeg_decompress_struct *
Definition: typeof.h:31
void TrimRight()
Definition: chstring.cpp:1124