ea4434c9db27777339142c761a2af6bf966e8bf4
[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
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 operator PCXSTR() const throw()
238 {
239 return m_pszData;
240 }
241
242 void Empty() throw()
243 {
244 CStringData* pOldData = GetData();
245 IAtlStringMgr* pStringMgr = pOldData->pStringMgr;
246 if (pOldData->nDataLength == 0) return;
247
248 if (pOldData->IsLocked())
249 {
250 SetLength(0);
251 }
252 else
253 {
254 pOldData->Release();
255 CStringData* pNewData = pStringMgr->GetNilString();
256 Attach(pNewData);
257 }
258 }
259
260 void Append(
261 _In_count_(nLength) PCXSTR pszSrc,
262 _In_ int nLength)
263 {
264 UINT_PTR nOffset = pszSrc - GetString();
265
266 int nOldLength = GetLength();
267 if (nOldLength < 0)
268 nOldLength = 0;
269
270 ATLASSERT(nLength >= 0);
271
272 #if 0 // FIXME: See comment for StringLengthN below.
273 nLength = StringLengthN(pszSrc, nLength);
274 if (!(INT_MAX - nLength >= nOldLength))
275 throw;
276 #endif
277
278 int nNewLength = nOldLength + nLength;
279 PXSTR pszBuffer = GetBuffer(nNewLength);
280 if (nOffset <= (UINT_PTR)nOldLength)
281 {
282 pszSrc = pszBuffer + nOffset;
283 }
284 CopyChars(pszBuffer + nOldLength, nLength, pszSrc, nLength);
285 ReleaseBufferSetLength(nNewLength);
286 }
287
288 void Append(_In_z_ PCXSTR pszSrc)
289 {
290 Append(pszSrc, StringLength(pszSrc));
291 }
292
293 void Append(_In_ const CSimpleStringT& strSrc)
294 {
295 Append(strSrc.GetString(), strSrc.GetLength());
296 }
297
298 void SetString(_In_opt_z_ PCXSTR pszSrc)
299 {
300 SetString(pszSrc, StringLength(pszSrc));
301 }
302
303 void SetString(_In_reads_opt_(nLength) PCXSTR pszSrc,
304 _In_ int nLength)
305 {
306 if (nLength == 0)
307 {
308 Empty();
309 }
310 else
311 {
312 UINT nOldLength = GetLength();
313 UINT_PTR nOffset = pszSrc - GetString();
314
315 PXSTR pszBuffer = GetBuffer(nLength);
316 if (nOffset <= nOldLength)
317 {
318 CopyCharsOverlapped(pszBuffer, GetAllocLength(),
319 pszBuffer + nOffset, nLength);
320 }
321 else
322 {
323 CopyChars(pszBuffer, GetAllocLength(), pszSrc, nLength);
324 }
325 ReleaseBufferSetLength(nLength);
326 }
327 }
328
329 PXSTR GetBuffer()
330 {
331 CStringData* pData = GetData();
332 if (pData->IsShared())
333 {
334 // We should fork here
335 Fork(pData->nDataLength);
336 }
337
338 return m_pszData;
339 }
340
341 _Ret_notnull_ _Post_writable_size_(nMinBufferLength + 1) PXSTR GetBuffer(_In_ int nMinBufferLength)
342 {
343 return PrepareWrite(nMinBufferLength);
344 }
345
346 int GetAllocLength() const throw()
347 {
348 return GetData()->nAllocLength;
349 }
350
351 int GetLength() const throw()
352 {
353 return GetData()->nDataLength;
354 }
355
356 PCXSTR GetString() const throw()
357 {
358 return m_pszData;
359 }
360
361 void ReleaseBufferSetLength(_In_ int nNewLength)
362 {
363 ATLASSERT(nNewLength >= 0);
364 SetLength(nNewLength);
365 }
366
367 bool IsEmpty() const throw()
368 {
369 return (GetLength() == 0);
370 }
371
372 CStringData* GetData() const throw()
373 {
374 return (reinterpret_cast<CStringData*>(m_pszData) - 1);
375 }
376
377 IAtlStringMgr* GetManager() const throw()
378 {
379 IAtlStringMgr* pStringMgr = GetData()->pStringMgr;
380 return (pStringMgr ? pStringMgr->Clone() : NULL);
381 }
382
383 public:
384 friend CSimpleStringT operator+(
385 _In_ const CSimpleStringT& str1,
386 _In_ const CSimpleStringT& str2)
387 {
388 CSimpleStringT s(str1.GetManager());
389 Concatenate(s, str1, str1.GetLength(), str2, str2.GetLength());
390 return s;
391 }
392
393 friend CSimpleStringT operator+(
394 _In_ const CSimpleStringT& str1,
395 _In_z_ PCXSTR psz2)
396 {
397 CSimpleStringT s(str1.GetManager());
398 Concatenate(s, str1, str1.GetLength(), psz2, StringLength(psz2));
399 return s;
400 }
401
402 friend CSimpleStringT operator+(
403 _In_z_ PCXSTR psz1,
404 _In_ const CSimpleStringT& str2)
405 {
406 CSimpleStringT s(str2.GetManager());
407 Concatenate(s, psz1, StringLength(psz1), str2, str2.GetLength());
408 return s;
409 }
410
411 static void __cdecl CopyChars(
412 _Out_writes_to_(nDestLen, nChars) XCHAR* pchDest,
413 _In_ size_t nDestLen,
414 _In_reads_opt_(nChars) const XCHAR* pchSrc,
415 _In_ int nChars) throw()
416 {
417 memcpy(pchDest, pchSrc, nChars * sizeof(XCHAR));
418 }
419
420 static void __cdecl CopyCharsOverlapped(
421 _Out_writes_to_(nDestLen, nDestLen) XCHAR* pchDest,
422 _In_ size_t nDestLen,
423 _In_reads_(nChars) const XCHAR* pchSrc,
424 _In_ int nChars) throw()
425 {
426 memmove(pchDest, pchSrc, nChars * sizeof(XCHAR));
427 }
428
429 static int __cdecl StringLength(_In_opt_z_ const char* psz) throw()
430 {
431 if (psz == NULL) return 0;
432 return (int)strlen(psz);
433 }
434
435 static int __cdecl StringLength(_In_opt_z_ const wchar_t* psz) throw()
436 {
437 if (psz == NULL) return 0;
438 return (int)wcslen(psz);
439 }
440
441 #if 0 // For whatever reason we do not link with strnlen / wcsnlen. Please investigate!
442 // strnlen / wcsnlen are available in MSVCRT starting Vista+.
443 static int __cdecl StringLengthN(
444 _In_opt_z_count_(sizeInXChar) const char* psz,
445 _In_ size_t sizeInXChar) throw()
446 {
447 if (psz == NULL) return 0;
448 return (int)strnlen(psz, sizeInXChar);
449 }
450
451 static int __cdecl StringLengthN(
452 _In_opt_z_count_(sizeInXChar) const wchar_t* psz,
453 _In_ size_t sizeInXChar) throw()
454 {
455 if (psz == NULL) return 0;
456 return (int)wcsnlen(psz, sizeInXChar);
457 }
458 #endif
459
460 protected:
461 static void __cdecl Concatenate(
462 _Inout_ CSimpleStringT& strResult,
463 _In_count_(nLength1) PCXSTR psz1,
464 _In_ int nLength1,
465 _In_count_(nLength2) PCXSTR psz2,
466 _In_ int nLength2)
467 {
468 int nNewLength = nLength1 + nLength2;
469 PXSTR pszBuffer = strResult.GetBuffer(nNewLength);
470 CopyChars(pszBuffer, nLength1, psz1, nLength1);
471 CopyChars(pszBuffer + nLength1, nLength2, psz2, nLength2);
472 strResult.ReleaseBufferSetLength(nNewLength);
473 }
474
475 private:
476 void Attach(_Inout_ CStringData* pData) throw()
477 {
478 m_pszData = static_cast<PXSTR>(pData->data());
479 }
480
481 __declspec(noinline) void Fork(_In_ int nLength)
482 {
483 CStringData* pOldData = GetData();
484 int nOldLength = pOldData->nDataLength;
485 CStringData* pNewData = pOldData->pStringMgr->Clone()->Allocate(nLength, sizeof(XCHAR));
486 if (pNewData == NULL)
487 {
488 throw; // ThrowMemoryException();
489 }
490 int nCharsToCopy = ((nOldLength < nLength) ? nOldLength : nLength) + 1;
491 CopyChars(PXSTR(pNewData->data()), nCharsToCopy,
492 PCXSTR(pOldData->data()), nCharsToCopy);
493 pNewData->nDataLength = nOldLength;
494 pOldData->Release();
495 Attach(pNewData);
496 }
497
498 PXSTR PrepareWrite(_In_ int nLength)
499 {
500 CStringData* pOldData = GetData();
501 int nShared = 1 - pOldData->nRefs;
502 int nTooShort = pOldData->nAllocLength - nLength;
503 if ((nShared | nTooShort) < 0)
504 {
505 PrepareWrite2(nLength);
506 }
507
508 return m_pszData;
509 }
510 void PrepareWrite2(_In_ int nLength)
511 {
512 CStringData* pOldData = GetData();
513 if (pOldData->nDataLength > nLength)
514 {
515 nLength = pOldData->nDataLength;
516 }
517 if (pOldData->IsShared())
518 {
519 Fork(nLength);
520 //ATLASSERT(FALSE);
521 }
522 else if (pOldData->nAllocLength < nLength)
523 {
524 int nNewLength = pOldData->nAllocLength;
525 if (nNewLength > 1024 * 1024 * 1024)
526 {
527 nNewLength += 1024 * 1024;
528 }
529 else
530 {
531 nNewLength = nNewLength + nNewLength / 2;
532 }
533 if (nNewLength < nLength)
534 {
535 nNewLength = nLength;
536 }
537 Reallocate(nNewLength);
538 }
539 }
540
541 void Reallocate(_In_ int nLength)
542 {
543 CStringData* pOldData = GetData();
544 ATLASSERT(pOldData->nAllocLength < nLength);
545 IAtlStringMgr* pStringMgr = pOldData->pStringMgr;
546 if (pOldData->nAllocLength >= nLength || nLength <= 0)
547 {
548 return;
549 }
550 CStringData* pNewData = pStringMgr->Reallocate(pOldData, nLength, sizeof(XCHAR));
551 if (pNewData == NULL)
552 {
553 throw; // ThrowMemoryException();
554 }
555
556 Attach(pNewData);
557 }
558
559 void SetLength(_In_ int nLength)
560 {
561 ATLASSERT(nLength >= 0);
562 ATLASSERT(nLength <= GetData()->nAllocLength);
563
564 if (nLength < 0 || nLength > GetData()->nAllocLength)
565 throw;
566
567 GetData()->nDataLength = nLength;
568 m_pszData[nLength] = 0;
569 }
570
571 static CStringData* __cdecl CloneData(_Inout_ CStringData* pData)
572 {
573 CStringData* pNewData = NULL;
574
575 IAtlStringMgr* pNewStringMgr = pData->pStringMgr->Clone();
576 if (!pData->IsLocked() && (pNewStringMgr == pData->pStringMgr))
577 {
578 pNewData = pData;
579 pNewData->AddRef();
580 }
581 else
582 {
583 pNewData = pNewStringMgr->Allocate(pData->nDataLength, sizeof(XCHAR));
584 if (pNewData == NULL)
585 {
586 throw; // ThrowMemoryException();
587 }
588
589 pNewData->nDataLength = pData->nDataLength;
590 CopyChars(PXSTR(pNewData->data()), pData->nDataLength + 1,
591 PCXSTR(pData->data()), pData->nDataLength + 1);
592 }
593
594 return pNewData;
595 }
596
597 };
598 }
599
600 #endif