[RXCE]
[reactos.git] / reactos / sdk / lib / atl / atlsimpstr.h
1 #ifndef __ATLSIMPSTR_H__
2 #define __ATLSIMPSTR_H__
3
4 #pragma once
5
6 #include <atlcore.h>
7 #include <atlexcept.h>
8
9 namespace ATL
10 {
11 struct CStringData;
12
13 // Pure virtual interface
14 class IAtlStringMgr
15 {
16 public:
17
18 virtual ~IAtlStringMgr() {}
19
20 virtual _Ret_maybenull_ _Post_writable_byte_size_(sizeof(CStringData) + nAllocLength*nCharSize)
21 CStringData* Allocate(
22 _In_ int nAllocLength,
23 _In_ int nCharSize
24 ) = 0;
25
26 virtual void Free(
27 _Inout_ CStringData* pData
28 ) = 0;
29
30 virtual _Ret_maybenull_ _Post_writable_byte_size_(sizeof(CStringData) + nAllocLength*nCharSize)
31 CStringData* Reallocate(
32 _Inout_ CStringData* pData,
33 _In_ int nAllocLength,
34 _In_ int nCharSize
35 ) = 0;
36
37 virtual CStringData* GetNilString(void) = 0;
38 virtual IAtlStringMgr* Clone(void) = 0;
39 };
40
41
42 struct CStringData
43 {
44 IAtlStringMgr* pStringMgr;
45 int nAllocLength;
46 int nDataLength;
47 long nRefs;
48
49 void* data() throw()
50 {
51 return (this + 1);
52 }
53
54 void AddRef() throw()
55 {
56 ATLASSERT(nRefs > 0);
57 _InterlockedIncrement(&nRefs);
58 }
59
60 void Release() throw()
61 {
62 ATLASSERT(nRefs != 0);
63
64 if (_InterlockedDecrement(&nRefs) <= 0)
65 {
66 pStringMgr->Free(this);
67 }
68 }
69
70 bool IsLocked() const throw()
71 {
72 return (nRefs < 0);
73 }
74
75 bool IsShared() const throw()
76 {
77 return (nRefs > 1);
78 }
79 };
80
81 class CNilStringData :
82 public CStringData
83 {
84 public:
85 CNilStringData() throw()
86 {
87 pStringMgr = NULL;
88 nRefs = 2;
89 nDataLength = 0;
90 nAllocLength = 0;
91 achNil[0] = 0;
92 achNil[1] = 0;
93 }
94
95 void SetManager(_In_ IAtlStringMgr* pMgr) throw()
96 {
97 ATLASSERT(pStringMgr == NULL);
98 pStringMgr = pMgr;
99 }
100
101 public:
102 wchar_t achNil[2];
103 };
104
105
106 template< typename BaseType = char >
107 class ChTraitsBase
108 {
109 public:
110 typedef char XCHAR;
111 typedef LPSTR PXSTR;
112 typedef LPCSTR PCXSTR;
113 typedef wchar_t YCHAR;
114 typedef LPWSTR PYSTR;
115 typedef LPCWSTR PCYSTR;
116 };
117
118 template<>
119 class ChTraitsBase<wchar_t>
120 {
121 public:
122 typedef wchar_t XCHAR;
123 typedef LPWSTR PXSTR;
124 typedef LPCWSTR PCXSTR;
125 typedef char YCHAR;
126 typedef LPSTR PYSTR;
127 typedef LPCSTR PCYSTR;
128 };
129
130 template< typename BaseType, bool t_bMFCDLL = false>
131 class CSimpleStringT
132 {
133 public:
134 typedef typename ChTraitsBase<BaseType>::XCHAR XCHAR;
135 typedef typename ChTraitsBase<BaseType>::PXSTR PXSTR;
136 typedef typename ChTraitsBase<BaseType>::PCXSTR PCXSTR;
137 typedef typename ChTraitsBase<BaseType>::YCHAR YCHAR;
138 typedef typename ChTraitsBase<BaseType>::PYSTR PYSTR;
139 typedef typename ChTraitsBase<BaseType>::PCYSTR PCYSTR;
140
141 private:
142 PXSTR m_pszData;
143
144 public:
145 explicit CSimpleStringT(_Inout_ IAtlStringMgr* pStringMgr)
146 {
147 CStringData* pData = pStringMgr->GetNilString();
148 Attach(pData);
149 }
150
151 CSimpleStringT(_In_ const CSimpleStringT& strSrc)
152 {
153 CStringData* pSrcData = strSrc.GetData();
154 CStringData* pNewData = CloneData(pSrcData);
155 Attach(pNewData);
156 }
157
158 CSimpleStringT(
159 _In_z_ PCXSTR pszSrc,
160 _Inout_ IAtlStringMgr* pStringMgr)
161 {
162 int nLength = StringLength(pszSrc);
163 CStringData* pData = pStringMgr->Allocate(nLength, sizeof(XCHAR));
164 if (pData == NULL)
165 {
166 throw; // ThrowMemoryException();
167 }
168 Attach(pData);
169 SetLength(nLength);
170 CopyChars(m_pszData, nLength, pszSrc, nLength);
171 }
172
173 CSimpleStringT(
174 _In_count_(nLength) const XCHAR* pchSrc,
175 _In_ int nLength,
176 _Inout_ IAtlStringMgr* pStringMgr)
177 {
178 if (pchSrc == NULL && nLength != 0)
179 throw;
180
181 CStringData* pData = pStringMgr->Allocate(nLength, sizeof(XCHAR));
182 if (pData == NULL)
183 {
184 throw; // ThrowMemoryException();
185 }
186 Attach(pData);
187 SetLength(nLength);
188 CopyChars(m_pszData, nLength, pchSrc, nLength);
189 }
190
191 ~CSimpleStringT() throw()
192 {
193 CStringData* pData = GetData();
194 pData->Release();
195 }
196
197 CSimpleStringT& operator=(_In_opt_z_ PCXSTR pszSrc)
198 {
199 SetString(pszSrc);
200 return *this;
201 }
202
203 CSimpleStringT& operator=(_In_ const CSimpleStringT& strSrc)
204 {
205 CStringData* pData = GetData();
206 CStringData* pNewData = strSrc.GetData();
207
208 if (pNewData != pData)
209 {
210 if (!pData->IsLocked() && (pNewData->pStringMgr == pData->pStringMgr))
211 {
212 pNewData = CloneData(pNewData);
213 pData->Release();
214 Attach(pNewData);
215 }
216 else
217 {
218 SetString(strSrc.GetString(), strSrc.GetLength());
219 }
220 }
221
222 return *this;
223 }
224
225 CSimpleStringT& operator+=(_In_ const CSimpleStringT& strSrc)
226 {
227 Append(strSrc);
228 return *this;
229 }
230
231 CSimpleStringT& operator+=(_In_z_ PCXSTR pszSrc)
232 {
233 Append(pszSrc);
234 return *this;
235 }
236
237 CSimpleStringT& operator+=(XCHAR ch)
238 {
239 Append(&ch, 1);
240 return *this;
241 }
242
243 operator PCXSTR() const throw()
244 {
245 return m_pszData;
246 }
247
248 void Empty() throw()
249 {
250 CStringData* pOldData = GetData();
251 IAtlStringMgr* pStringMgr = pOldData->pStringMgr;
252 if (pOldData->nDataLength == 0) return;
253
254 if (pOldData->IsLocked())
255 {
256 SetLength(0);
257 }
258 else
259 {
260 pOldData->Release();
261 CStringData* pNewData = pStringMgr->GetNilString();
262 Attach(pNewData);
263 }
264 }
265
266 void Append(
267 _In_count_(nLength) PCXSTR pszSrc,
268 _In_ int nLength)
269 {
270 UINT_PTR nOffset = pszSrc - GetString();
271
272 int nOldLength = GetLength();
273 if (nOldLength < 0)
274 nOldLength = 0;
275
276 ATLASSERT(nLength >= 0);
277
278 #if 0 // FIXME: See comment for StringLengthN below.
279 nLength = StringLengthN(pszSrc, nLength);
280 if (!(INT_MAX - nLength >= nOldLength))
281 throw;
282 #endif
283
284 int nNewLength = nOldLength + nLength;
285 PXSTR pszBuffer = GetBuffer(nNewLength);
286 if (nOffset <= (UINT_PTR)nOldLength)
287 {
288 pszSrc = pszBuffer + nOffset;
289 }
290 CopyChars(pszBuffer + nOldLength, nLength, pszSrc, nLength);
291 ReleaseBufferSetLength(nNewLength);
292 }
293
294 void Append(_In_z_ PCXSTR pszSrc)
295 {
296 Append(pszSrc, StringLength(pszSrc));
297 }
298
299 void Append(_In_ const CSimpleStringT& strSrc)
300 {
301 Append(strSrc.GetString(), strSrc.GetLength());
302 }
303
304 void SetString(_In_opt_z_ PCXSTR pszSrc)
305 {
306 SetString(pszSrc, StringLength(pszSrc));
307 }
308
309 void SetString(_In_reads_opt_(nLength) PCXSTR pszSrc,
310 _In_ int nLength)
311 {
312 if (nLength == 0)
313 {
314 Empty();
315 }
316 else
317 {
318 UINT nOldLength = GetLength();
319 UINT_PTR nOffset = pszSrc - GetString();
320
321 PXSTR pszBuffer = GetBuffer(nLength);
322 if (nOffset <= nOldLength)
323 {
324 CopyCharsOverlapped(pszBuffer, GetAllocLength(),
325 pszBuffer + nOffset, nLength);
326 }
327 else
328 {
329 CopyChars(pszBuffer, GetAllocLength(), pszSrc, nLength);
330 }
331 ReleaseBufferSetLength(nLength);
332 }
333 }
334
335 PXSTR GetBuffer()
336 {
337 CStringData* pData = GetData();
338 if (pData->IsShared())
339 {
340 // We should fork here
341 Fork(pData->nDataLength);
342 }
343
344 return m_pszData;
345 }
346
347 _Ret_notnull_ _Post_writable_size_(nMinBufferLength + 1) PXSTR GetBuffer(_In_ int nMinBufferLength)
348 {
349 return PrepareWrite(nMinBufferLength);
350 }
351
352 int GetAllocLength() const throw()
353 {
354 return GetData()->nAllocLength;
355 }
356
357 int GetLength() const throw()
358 {
359 return GetData()->nDataLength;
360 }
361
362 PCXSTR GetString() const throw()
363 {
364 return m_pszData;
365 }
366
367 void ReleaseBufferSetLength(_In_ int nNewLength)
368 {
369 ATLASSERT(nNewLength >= 0);
370 SetLength(nNewLength);
371 }
372
373 void ReleaseBuffer(_In_ int nNewLength = -1)
374 {
375 if (nNewLength < 0)
376 nNewLength = StringLength(m_pszData);
377 ReleaseBufferSetLength(nNewLength);
378 }
379
380 bool IsEmpty() const throw()
381 {
382 return (GetLength() == 0);
383 }
384
385 CStringData* GetData() const throw()
386 {
387 return (reinterpret_cast<CStringData*>(m_pszData) - 1);
388 }
389
390 IAtlStringMgr* GetManager() const throw()
391 {
392 IAtlStringMgr* pStringMgr = GetData()->pStringMgr;
393 return (pStringMgr ? pStringMgr->Clone() : NULL);
394 }
395
396 public:
397 friend CSimpleStringT operator+(
398 _In_ const CSimpleStringT& str1,
399 _In_ const CSimpleStringT& str2)
400 {
401 CSimpleStringT s(str1.GetManager());
402 Concatenate(s, str1, str1.GetLength(), str2, str2.GetLength());
403 return s;
404 }
405
406 friend CSimpleStringT operator+(
407 _In_ const CSimpleStringT& str1,
408 _In_z_ PCXSTR psz2)
409 {
410 CSimpleStringT s(str1.GetManager());
411 Concatenate(s, str1, str1.GetLength(), psz2, StringLength(psz2));
412 return s;
413 }
414
415 friend CSimpleStringT operator+(
416 _In_z_ PCXSTR psz1,
417 _In_ const CSimpleStringT& str2)
418 {
419 CSimpleStringT s(str2.GetManager());
420 Concatenate(s, psz1, StringLength(psz1), str2, str2.GetLength());
421 return s;
422 }
423
424 static void __cdecl CopyChars(
425 _Out_writes_to_(nDestLen, nChars) XCHAR* pchDest,
426 _In_ size_t nDestLen,
427 _In_reads_opt_(nChars) const XCHAR* pchSrc,
428 _In_ int nChars) throw()
429 {
430 memcpy(pchDest, pchSrc, nChars * sizeof(XCHAR));
431 }
432
433 static void __cdecl CopyCharsOverlapped(
434 _Out_writes_to_(nDestLen, nDestLen) XCHAR* pchDest,
435 _In_ size_t nDestLen,
436 _In_reads_(nChars) const XCHAR* pchSrc,
437 _In_ int nChars) throw()
438 {
439 memmove(pchDest, pchSrc, nChars * sizeof(XCHAR));
440 }
441
442 static int __cdecl StringLength(_In_opt_z_ const char* psz) throw()
443 {
444 if (psz == NULL) return 0;
445 return (int)strlen(psz);
446 }
447
448 static int __cdecl StringLength(_In_opt_z_ const wchar_t* psz) throw()
449 {
450 if (psz == NULL) return 0;
451 return (int)wcslen(psz);
452 }
453
454 #if 0 // For whatever reason we do not link with strnlen / wcsnlen. Please investigate!
455 // strnlen / wcsnlen are available in MSVCRT starting Vista+.
456 static int __cdecl StringLengthN(
457 _In_opt_z_count_(sizeInXChar) const char* psz,
458 _In_ size_t sizeInXChar) throw()
459 {
460 if (psz == NULL) return 0;
461 return (int)strnlen(psz, sizeInXChar);
462 }
463
464 static int __cdecl StringLengthN(
465 _In_opt_z_count_(sizeInXChar) const wchar_t* psz,
466 _In_ size_t sizeInXChar) throw()
467 {
468 if (psz == NULL) return 0;
469 return (int)wcsnlen(psz, sizeInXChar);
470 }
471 #endif
472
473 protected:
474 static void __cdecl Concatenate(
475 _Inout_ CSimpleStringT& strResult,
476 _In_count_(nLength1) PCXSTR psz1,
477 _In_ int nLength1,
478 _In_count_(nLength2) PCXSTR psz2,
479 _In_ int nLength2)
480 {
481 int nNewLength = nLength1 + nLength2;
482 PXSTR pszBuffer = strResult.GetBuffer(nNewLength);
483 CopyChars(pszBuffer, nLength1, psz1, nLength1);
484 CopyChars(pszBuffer + nLength1, nLength2, psz2, nLength2);
485 strResult.ReleaseBufferSetLength(nNewLength);
486 }
487
488 private:
489 void Attach(_Inout_ CStringData* pData) throw()
490 {
491 m_pszData = static_cast<PXSTR>(pData->data());
492 }
493
494 __declspec(noinline) void Fork(_In_ int nLength)
495 {
496 CStringData* pOldData = GetData();
497 int nOldLength = pOldData->nDataLength;
498 CStringData* pNewData = pOldData->pStringMgr->Clone()->Allocate(nLength, sizeof(XCHAR));
499 if (pNewData == NULL)
500 {
501 ThrowMemoryException();
502 }
503 int nCharsToCopy = ((nOldLength < nLength) ? nOldLength : nLength) + 1;
504 CopyChars(PXSTR(pNewData->data()), nCharsToCopy,
505 PCXSTR(pOldData->data()), nCharsToCopy);
506 pNewData->nDataLength = nOldLength;
507 pOldData->Release();
508 Attach(pNewData);
509 }
510
511 PXSTR PrepareWrite(_In_ int nLength)
512 {
513 CStringData* pOldData = GetData();
514 int nShared = 1 - pOldData->nRefs;
515 int nTooShort = pOldData->nAllocLength - nLength;
516 if ((nShared | nTooShort) < 0)
517 {
518 PrepareWrite2(nLength);
519 }
520
521 return m_pszData;
522 }
523 void PrepareWrite2(_In_ int nLength)
524 {
525 CStringData* pOldData = GetData();
526 if (pOldData->nDataLength > nLength)
527 {
528 nLength = pOldData->nDataLength;
529 }
530 if (pOldData->IsShared())
531 {
532 Fork(nLength);
533 //ATLASSERT(FALSE);
534 }
535 else if (pOldData->nAllocLength < nLength)
536 {
537 int nNewLength = pOldData->nAllocLength;
538 if (nNewLength > 1024 * 1024 * 1024)
539 {
540 nNewLength += 1024 * 1024;
541 }
542 else
543 {
544 nNewLength = nNewLength + nNewLength / 2;
545 }
546 if (nNewLength < nLength)
547 {
548 nNewLength = nLength;
549 }
550 Reallocate(nNewLength);
551 }
552 }
553
554 void Reallocate(_In_ int nLength)
555 {
556 CStringData* pOldData = GetData();
557 ATLASSERT(pOldData->nAllocLength < nLength);
558 IAtlStringMgr* pStringMgr = pOldData->pStringMgr;
559 if (pOldData->nAllocLength >= nLength || nLength <= 0)
560 {
561 return;
562 }
563 CStringData* pNewData = pStringMgr->Reallocate(pOldData, nLength, sizeof(XCHAR));
564 if (pNewData == NULL)
565 {
566 ThrowMemoryException();
567 }
568
569 Attach(pNewData);
570 }
571
572 void SetLength(_In_ int nLength)
573 {
574 ATLASSERT(nLength >= 0);
575 ATLASSERT(nLength <= GetData()->nAllocLength);
576
577 if (nLength < 0 || nLength > GetData()->nAllocLength)
578 {
579 AtlThrow(E_INVALIDARG);
580 }
581
582 GetData()->nDataLength = nLength;
583 m_pszData[nLength] = 0;
584 }
585
586 static CStringData* __cdecl CloneData(_Inout_ CStringData* pData)
587 {
588 CStringData* pNewData = NULL;
589
590 IAtlStringMgr* pNewStringMgr = pData->pStringMgr->Clone();
591 if (!pData->IsLocked() && (pNewStringMgr == pData->pStringMgr))
592 {
593 pNewData = pData;
594 pNewData->AddRef();
595 }
596 else
597 {
598 pNewData = pNewStringMgr->Allocate(pData->nDataLength, sizeof(XCHAR));
599 if (pNewData == NULL)
600 {
601 ThrowMemoryException();
602 }
603
604 pNewData->nDataLength = pData->nDataLength;
605 CopyChars(PXSTR(pNewData->data()), pData->nDataLength + 1,
606 PCXSTR(pData->data()), pData->nDataLength + 1);
607 }
608
609 return pNewData;
610 }
611
612
613 static void ThrowMemoryException()
614 {
615 AtlThrow(E_OUTOFMEMORY);
616 }
617
618 };
619
620 #ifdef UNICODE
621 typedef CSimpleStringT<WCHAR> CSimpleString;
622 #else
623 typedef CSimpleStringT<CHAR> CSimpleString;
624 #endif
625 }
626
627 #endif