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