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