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() throw() 56 { 57 return (this + 1); 58 } 59 60 void AddRef() throw() 61 { 62 ATLASSERT(nRefs > 0); 63 _InterlockedIncrement(&nRefs); 64 } 65 66 void Release() throw() 67 { 68 ATLASSERT(nRefs != 0); 69 70 if (_InterlockedDecrement(&nRefs) <= 0) 71 { 72 pStringMgr->Free(this); 73 } 74 } 75 76 bool IsLocked() const throw() 77 { 78 return (nRefs < 0); 79 } 80 81 bool IsShared() const throw() 82 { 83 return (nRefs > 1); 84 } 85 }; 86 87 class CNilStringData : 88 public CStringData 89 { 90 public: 91 CNilStringData() throw() 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) throw() 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() throw() 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 throw() 249 { 250 return m_pszData; 251 } 252 253 void Empty() throw() 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 throw() 358 { 359 return GetData()->nAllocLength; 360 } 361 362 int GetLength() const throw() 363 { 364 return GetData()->nDataLength; 365 } 366 367 PXSTR GetString() throw() 368 { 369 return m_pszData; 370 } 371 PCXSTR GetString() const throw() 372 { 373 return m_pszData; 374 } 375 376 void ReleaseBufferSetLength(_In_ int nNewLength) 377 { 378 ATLASSERT(nNewLength >= 0); 379 SetLength(nNewLength); 380 } 381 382 void ReleaseBuffer(_In_ int nNewLength = -1) 383 { 384 if (nNewLength < 0) 385 nNewLength = StringLength(m_pszData); 386 ReleaseBufferSetLength(nNewLength); 387 } 388 389 bool IsEmpty() const throw() 390 { 391 return (GetLength() == 0); 392 } 393 394 CStringData* GetData() const throw() 395 { 396 return (reinterpret_cast<CStringData*>(m_pszData) - 1); 397 } 398 399 IAtlStringMgr* GetManager() const throw() 400 { 401 IAtlStringMgr* pStringMgr = GetData()->pStringMgr; 402 return (pStringMgr ? pStringMgr->Clone() : NULL); 403 } 404 405 public: 406 friend CSimpleStringT operator+( 407 _In_ const CSimpleStringT& str1, 408 _In_ const CSimpleStringT& str2) 409 { 410 CSimpleStringT s(str1.GetManager()); 411 Concatenate(s, str1, str1.GetLength(), str2, str2.GetLength()); 412 return s; 413 } 414 415 friend CSimpleStringT operator+( 416 _In_ const CSimpleStringT& str1, 417 _In_z_ PCXSTR psz2) 418 { 419 CSimpleStringT s(str1.GetManager()); 420 Concatenate(s, str1, str1.GetLength(), psz2, StringLength(psz2)); 421 return s; 422 } 423 424 friend CSimpleStringT operator+( 425 _In_z_ PCXSTR psz1, 426 _In_ const CSimpleStringT& str2) 427 { 428 CSimpleStringT s(str2.GetManager()); 429 Concatenate(s, psz1, StringLength(psz1), str2, str2.GetLength()); 430 return s; 431 } 432 433 static void __cdecl CopyChars( 434 _Out_writes_to_(nDestLen, nChars) XCHAR* pchDest, 435 _In_ size_t nDestLen, 436 _In_reads_opt_(nChars) const XCHAR* pchSrc, 437 _In_ int nChars) throw() 438 { 439 memcpy(pchDest, pchSrc, nChars * sizeof(XCHAR)); 440 } 441 442 static void __cdecl CopyCharsOverlapped( 443 _Out_writes_to_(nDestLen, nDestLen) XCHAR* pchDest, 444 _In_ size_t nDestLen, 445 _In_reads_(nChars) const XCHAR* pchSrc, 446 _In_ int nChars) throw() 447 { 448 memmove(pchDest, pchSrc, nChars * sizeof(XCHAR)); 449 } 450 451 static int __cdecl StringLength(_In_opt_z_ const char* psz) throw() 452 { 453 if (psz == NULL) return 0; 454 return (int)strlen(psz); 455 } 456 457 static int __cdecl StringLength(_In_opt_z_ const wchar_t* psz) throw() 458 { 459 if (psz == NULL) return 0; 460 return (int)wcslen(psz); 461 } 462 463 #if 0 // For whatever reason we do not link with strnlen / wcsnlen. Please investigate! 464 // strnlen / wcsnlen are available in MSVCRT starting Vista+. 465 static int __cdecl StringLengthN( 466 _In_opt_z_count_(sizeInXChar) const char* psz, 467 _In_ size_t sizeInXChar) throw() 468 { 469 if (psz == NULL) return 0; 470 return (int)strnlen(psz, sizeInXChar); 471 } 472 473 static int __cdecl StringLengthN( 474 _In_opt_z_count_(sizeInXChar) const wchar_t* psz, 475 _In_ size_t sizeInXChar) throw() 476 { 477 if (psz == NULL) return 0; 478 return (int)wcsnlen(psz, sizeInXChar); 479 } 480 #endif 481 482 protected: 483 static void __cdecl Concatenate( 484 _Inout_ CSimpleStringT& strResult, 485 _In_count_(nLength1) PCXSTR psz1, 486 _In_ int nLength1, 487 _In_count_(nLength2) PCXSTR psz2, 488 _In_ int nLength2) 489 { 490 int nNewLength = nLength1 + nLength2; 491 PXSTR pszBuffer = strResult.GetBuffer(nNewLength); 492 CopyChars(pszBuffer, nLength1, psz1, nLength1); 493 CopyChars(pszBuffer + nLength1, nLength2, psz2, nLength2); 494 strResult.ReleaseBufferSetLength(nNewLength); 495 } 496 497 private: 498 void Attach(_Inout_ CStringData* pData) throw() 499 { 500 m_pszData = static_cast<PXSTR>(pData->data()); 501 } 502 503 __declspec(noinline) void Fork(_In_ int nLength) 504 { 505 CStringData* pOldData = GetData(); 506 int nOldLength = pOldData->nDataLength; 507 CStringData* pNewData = pOldData->pStringMgr->Clone()->Allocate(nLength, sizeof(XCHAR)); 508 if (pNewData == NULL) 509 { 510 ThrowMemoryException(); 511 } 512 int nCharsToCopy = ((nOldLength < nLength) ? nOldLength : nLength) + 1; 513 CopyChars(PXSTR(pNewData->data()), nCharsToCopy, 514 PCXSTR(pOldData->data()), nCharsToCopy); 515 pNewData->nDataLength = nOldLength; 516 pOldData->Release(); 517 Attach(pNewData); 518 } 519 520 PXSTR PrepareWrite(_In_ int nLength) 521 { 522 CStringData* pOldData = GetData(); 523 int nShared = 1 - pOldData->nRefs; 524 int nTooShort = pOldData->nAllocLength - nLength; 525 if ((nShared | nTooShort) < 0) 526 { 527 PrepareWrite2(nLength); 528 } 529 530 return m_pszData; 531 } 532 void PrepareWrite2(_In_ int nLength) 533 { 534 CStringData* pOldData = GetData(); 535 if (pOldData->nDataLength > nLength) 536 { 537 nLength = pOldData->nDataLength; 538 } 539 if (pOldData->IsShared()) 540 { 541 Fork(nLength); 542 //ATLASSERT(FALSE); 543 } 544 else if (pOldData->nAllocLength < nLength) 545 { 546 int nNewLength = pOldData->nAllocLength; 547 if (nNewLength > 1024 * 1024 * 1024) 548 { 549 nNewLength += 1024 * 1024; 550 } 551 else 552 { 553 nNewLength = nNewLength + nNewLength / 2; 554 } 555 if (nNewLength < nLength) 556 { 557 nNewLength = nLength; 558 } 559 Reallocate(nNewLength); 560 } 561 } 562 563 void Reallocate(_In_ int nLength) 564 { 565 CStringData* pOldData = GetData(); 566 ATLASSERT(pOldData->nAllocLength < nLength); 567 IAtlStringMgr* pStringMgr = pOldData->pStringMgr; 568 if (pOldData->nAllocLength >= nLength || nLength <= 0) 569 { 570 return; 571 } 572 CStringData* pNewData = pStringMgr->Reallocate(pOldData, nLength, sizeof(XCHAR)); 573 if (pNewData == NULL) 574 { 575 ThrowMemoryException(); 576 } 577 578 Attach(pNewData); 579 } 580 581 void SetLength(_In_ int nLength) 582 { 583 ATLASSERT(nLength >= 0); 584 ATLASSERT(nLength <= GetData()->nAllocLength); 585 586 if (nLength < 0 || nLength > GetData()->nAllocLength) 587 { 588 AtlThrow(E_INVALIDARG); 589 } 590 591 GetData()->nDataLength = nLength; 592 m_pszData[nLength] = 0; 593 } 594 595 static CStringData* __cdecl CloneData(_Inout_ CStringData* pData) 596 { 597 CStringData* pNewData = NULL; 598 599 IAtlStringMgr* pNewStringMgr = pData->pStringMgr->Clone(); 600 if (!pData->IsLocked() && (pNewStringMgr == pData->pStringMgr)) 601 { 602 pNewData = pData; 603 pNewData->AddRef(); 604 } 605 else 606 { 607 pNewData = pNewStringMgr->Allocate(pData->nDataLength, sizeof(XCHAR)); 608 if (pNewData == NULL) 609 { 610 ThrowMemoryException(); 611 } 612 613 pNewData->nDataLength = pData->nDataLength; 614 CopyChars(PXSTR(pNewData->data()), pData->nDataLength + 1, 615 PCXSTR(pData->data()), pData->nDataLength + 1); 616 } 617 618 return pNewData; 619 } 620 621 protected: 622 static void ThrowMemoryException() 623 { 624 AtlThrow(E_OUTOFMEMORY); 625 } 626 627 static void ThrowInvalidArgException() 628 { 629 AtlThrow(E_INVALIDARG); 630 } 631 }; 632 633 #ifdef UNICODE 634 typedef CSimpleStringT<WCHAR> CSimpleString; 635 #else 636 typedef CSimpleStringT<CHAR> CSimpleString; 637 #endif 638 } 639 640 #endif 641