Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1883 lines
51 KiB

  1. // This is a part of the Active Template Library.
  2. // Copyright (C) 1996-1998 Microsoft Corporation
  3. // All rights reserved.
  4. //
  5. // This source code is only intended as a supplement to the
  6. // Active Template Library Reference and related
  7. // electronic documentation provided with the library.
  8. // See these sources for detailed information regarding the
  9. // Active Template Library product.
  10. // atltmp.h - temporary location for these classes
  11. #ifndef __ATLTMP_H__
  12. #define __ATLTMP_H__
  13. #ifndef __cplusplus
  14. #error ATL requires C++ compilation (use a .cpp suffix)
  15. #endif
  16. #ifndef __ATLBASE_H__
  17. #error atltmp.h requires atlbase.h to be included first
  18. #endif
  19. #pragma once
  20. #ifndef _ATL_TMP_NO_CSTRING
  21. #include <limits.h>
  22. #include <stdio.h>
  23. #endif //!_ATL_TMP_NO_CSTRING
  24. namespace ATL
  25. {
  26. /////////////////////////////////////////////////////////////////////////////
  27. // Forward declarations
  28. class CSize;
  29. class CPoint;
  30. class CRect;
  31. #ifndef _ATL_TMP_NO_CSTRING
  32. class CString;
  33. #endif //!_ATL_TMP_NO_CSTRING
  34. /////////////////////////////////////////////////////////////////////////////
  35. // CSize - An extent, similar to Windows SIZE structure.
  36. class CSize : public tagSIZE
  37. {
  38. public:
  39. // Constructors
  40. CSize();
  41. CSize(int initCX, int initCY);
  42. CSize(SIZE initSize);
  43. CSize(POINT initPt);
  44. CSize(DWORD dwSize);
  45. // Operations
  46. BOOL operator==(SIZE size) const;
  47. BOOL operator!=(SIZE size) const;
  48. void operator+=(SIZE size);
  49. void operator-=(SIZE size);
  50. // Operators returning CSize values
  51. CSize operator+(SIZE size) const;
  52. CSize operator-(SIZE size) const;
  53. CSize operator-() const;
  54. // Operators returning CPoint values
  55. CPoint operator+(POINT point) const;
  56. CPoint operator-(POINT point) const;
  57. // Operators returning CRect values
  58. CRect operator+(const RECT* lpRect) const;
  59. CRect operator-(const RECT* lpRect) const;
  60. };
  61. /////////////////////////////////////////////////////////////////////////////
  62. // CPoint - A 2-D point, similar to Windows POINT structure.
  63. class CPoint : public tagPOINT
  64. {
  65. public:
  66. // Constructors
  67. CPoint();
  68. CPoint(int initX, int initY);
  69. CPoint(POINT initPt);
  70. CPoint(SIZE initSize);
  71. CPoint(DWORD dwPoint);
  72. // Operations
  73. void Offset(int xOffset, int yOffset);
  74. void Offset(POINT point);
  75. void Offset(SIZE size);
  76. BOOL operator==(POINT point) const;
  77. BOOL operator!=(POINT point) const;
  78. void operator+=(SIZE size);
  79. void operator-=(SIZE size);
  80. void operator+=(POINT point);
  81. void operator-=(POINT point);
  82. // Operators returning CPoint values
  83. CPoint operator+(SIZE size) const;
  84. CPoint operator-(SIZE size) const;
  85. CPoint operator-() const;
  86. CPoint operator+(POINT point) const;
  87. // Operators returning CSize values
  88. CSize operator-(POINT point) const;
  89. // Operators returning CRect values
  90. CRect operator+(const RECT* lpRect) const;
  91. CRect operator-(const RECT* lpRect) const;
  92. };
  93. /////////////////////////////////////////////////////////////////////////////
  94. // CRect - A 2-D rectangle, similar to Windows RECT structure.
  95. //typedef const RECT* LPCRECT; // pointer to read/only RECT
  96. class CRect : public tagRECT
  97. {
  98. public:
  99. // Constructors
  100. CRect();
  101. CRect(int l, int t, int r, int b);
  102. CRect(const RECT& srcRect);
  103. CRect(LPCRECT lpSrcRect);
  104. CRect(POINT point, SIZE size);
  105. CRect(POINT topLeft, POINT bottomRight);
  106. // Attributes (in addition to RECT members)
  107. int Width() const;
  108. int Height() const;
  109. CSize Size() const;
  110. CPoint& TopLeft();
  111. CPoint& BottomRight();
  112. const CPoint& TopLeft() const;
  113. const CPoint& BottomRight() const;
  114. CPoint CenterPoint() const;
  115. // convert between CRect and LPRECT/LPCRECT (no need for &)
  116. operator LPRECT();
  117. operator LPCRECT() const;
  118. BOOL IsRectEmpty() const;
  119. BOOL IsRectNull() const;
  120. BOOL PtInRect(POINT point) const;
  121. // Operations
  122. void SetRect(int x1, int y1, int x2, int y2);
  123. void SetRect(POINT topLeft, POINT bottomRight);
  124. void SetRectEmpty();
  125. void CopyRect(LPCRECT lpSrcRect);
  126. BOOL EqualRect(LPCRECT lpRect) const;
  127. void InflateRect(int x, int y);
  128. void InflateRect(SIZE size);
  129. void InflateRect(LPCRECT lpRect);
  130. void InflateRect(int l, int t, int r, int b);
  131. void DeflateRect(int x, int y);
  132. void DeflateRect(SIZE size);
  133. void DeflateRect(LPCRECT lpRect);
  134. void DeflateRect(int l, int t, int r, int b);
  135. void OffsetRect(int x, int y);
  136. void OffsetRect(SIZE size);
  137. void OffsetRect(POINT point);
  138. void NormalizeRect();
  139. // operations that fill '*this' with result
  140. BOOL IntersectRect(LPCRECT lpRect1, LPCRECT lpRect2);
  141. BOOL UnionRect(LPCRECT lpRect1, LPCRECT lpRect2);
  142. BOOL SubtractRect(LPCRECT lpRectSrc1, LPCRECT lpRectSrc2);
  143. // Additional Operations
  144. void operator=(const RECT& srcRect);
  145. BOOL operator==(const RECT& rect) const;
  146. BOOL operator!=(const RECT& rect) const;
  147. void operator+=(POINT point);
  148. void operator+=(SIZE size);
  149. void operator+=(LPCRECT lpRect);
  150. void operator-=(POINT point);
  151. void operator-=(SIZE size);
  152. void operator-=(LPCRECT lpRect);
  153. void operator&=(const RECT& rect);
  154. void operator|=(const RECT& rect);
  155. // Operators returning CRect values
  156. CRect operator+(POINT point) const;
  157. CRect operator-(POINT point) const;
  158. CRect operator+(LPCRECT lpRect) const;
  159. CRect operator+(SIZE size) const;
  160. CRect operator-(SIZE size) const;
  161. CRect operator-(LPCRECT lpRect) const;
  162. CRect operator&(const RECT& rect2) const;
  163. CRect operator|(const RECT& rect2) const;
  164. CRect MulDiv(int nMultiplier, int nDivisor) const;
  165. };
  166. /////////////////////////////////////////////////////////////////////////////
  167. // Strings
  168. #ifndef _ATL_TMP_NO_CSTRING
  169. #ifndef _OLEAUTO_H_
  170. #ifdef OLE2ANSI
  171. typedef LPSTR BSTR;
  172. #else
  173. typedef LPWSTR BSTR; // must (semantically) match typedef in oleauto.h
  174. #endif
  175. #endif
  176. int __stdcall AfxLoadString(UINT nID, LPTSTR lpszBuf, UINT nMaxBuf);
  177. struct CStringData
  178. {
  179. long nRefs; // reference count
  180. int nDataLength;
  181. int nAllocLength;
  182. // TCHAR data[nAllocLength]
  183. TCHAR* data()
  184. { return (TCHAR*)(this+1); }
  185. };
  186. class CString
  187. {
  188. public:
  189. // Constructors
  190. CString();
  191. CString(const CString& stringSrc);
  192. CString(TCHAR ch, int nRepeat = 1);
  193. CString(LPCSTR lpsz);
  194. CString(LPCWSTR lpsz);
  195. CString(LPCTSTR lpch, int nLength);
  196. CString(const unsigned char* psz);
  197. // Attributes & Operations
  198. // as an array of characters
  199. int GetLength() const;
  200. BOOL IsEmpty() const;
  201. void Empty(); // free up the data
  202. TCHAR GetAt(int nIndex) const; // 0 based
  203. TCHAR operator[](int nIndex) const; // same as GetAt
  204. void SetAt(int nIndex, TCHAR ch);
  205. operator LPCTSTR() const; // as a C string
  206. // overloaded assignment
  207. const CString& operator=(const CString& stringSrc);
  208. const CString& operator=(TCHAR ch);
  209. #ifdef _UNICODE
  210. const CString& operator=(char ch);
  211. #endif
  212. const CString& operator=(LPCSTR lpsz);
  213. const CString& operator=(LPCWSTR lpsz);
  214. const CString& operator=(const unsigned char* psz);
  215. // string concatenation
  216. const CString& operator+=(const CString& string);
  217. const CString& operator+=(TCHAR ch);
  218. #ifdef _UNICODE
  219. const CString& operator+=(char ch);
  220. #endif
  221. const CString& operator+=(LPCTSTR lpsz);
  222. friend CString __stdcall operator+(const CString& string1, const CString& string2);
  223. friend CString __stdcall operator+(const CString& string, TCHAR ch);
  224. friend CString __stdcall operator+(TCHAR ch, const CString& string);
  225. #ifdef _UNICODE
  226. friend CString __stdcall operator+(const CString& string, char ch);
  227. friend CString __stdcall operator+(char ch, const CString& string);
  228. #endif
  229. friend CString __stdcall operator+(const CString& string, LPCTSTR lpsz);
  230. friend CString __stdcall operator+(LPCTSTR lpsz, const CString& string);
  231. // string comparison
  232. int Compare(LPCTSTR lpsz) const; // straight character
  233. int CompareNoCase(LPCTSTR lpsz) const; // ignore case
  234. int Collate(LPCTSTR lpsz) const; // NLS aware
  235. // simple sub-string extraction
  236. CString Mid(int nFirst, int nCount) const;
  237. CString Mid(int nFirst) const;
  238. CString Left(int nCount) const;
  239. CString Right(int nCount) const;
  240. CString SpanIncluding(LPCTSTR lpszCharSet) const;
  241. CString SpanExcluding(LPCTSTR lpszCharSet) const;
  242. // upper/lower/reverse conversion
  243. void MakeUpper();
  244. void MakeLower();
  245. void MakeReverse();
  246. // trimming whitespace (either side)
  247. void TrimRight();
  248. void TrimLeft();
  249. // searching (return starting index, or -1 if not found)
  250. // look for a single character match
  251. int Find(TCHAR ch) const; // like "C" strchr
  252. int ReverseFind(TCHAR ch) const;
  253. int FindOneOf(LPCTSTR lpszCharSet) const;
  254. // look for a specific sub-string
  255. int Find(LPCTSTR lpszSub) const; // like "C" strstr
  256. // simple formatting
  257. void __cdecl Format(LPCTSTR lpszFormat, ...);
  258. void __cdecl Format(UINT nFormatID, ...);
  259. // formatting for localization (uses FormatMessage API)
  260. BOOL __cdecl FormatMessage(LPCTSTR lpszFormat, ...);
  261. BOOL __cdecl FormatMessage(UINT nFormatID, ...);
  262. // Windows support
  263. BOOL LoadString(UINT nID); // load from string resource
  264. // 255 chars max
  265. #ifndef _UNICODE
  266. // ANSI <-> OEM support (convert string in place)
  267. void AnsiToOem();
  268. void OemToAnsi();
  269. #endif
  270. #ifndef _ATL_NO_COM
  271. // OLE BSTR support (use for OLE automation)
  272. BSTR AllocSysString() const;
  273. BSTR SetSysString(BSTR* pbstr) const;
  274. #endif //!_ATL_NO_COM
  275. // Access to string implementation buffer as "C" character array
  276. LPTSTR GetBuffer(int nMinBufLength);
  277. void ReleaseBuffer(int nNewLength = -1);
  278. LPTSTR GetBufferSetLength(int nNewLength);
  279. void FreeExtra();
  280. // Use LockBuffer/UnlockBuffer to turn refcounting off
  281. LPTSTR LockBuffer();
  282. void UnlockBuffer();
  283. // Implementation
  284. public:
  285. ~CString();
  286. int GetAllocLength() const;
  287. protected:
  288. LPTSTR m_pchData; // pointer to ref counted string data
  289. // implementation helpers
  290. CStringData* GetData() const;
  291. void Init();
  292. void AllocCopy(CString& dest, int nCopyLen, int nCopyIndex, int nExtraLen) const;
  293. BOOL AllocBuffer(int nLen);
  294. void AssignCopy(int nSrcLen, LPCTSTR lpszSrcData);
  295. void ConcatCopy(int nSrc1Len, LPCTSTR lpszSrc1Data, int nSrc2Len, LPCTSTR lpszSrc2Data);
  296. void ConcatInPlace(int nSrcLen, LPCTSTR lpszSrcData);
  297. void FormatV(LPCTSTR lpszFormat, va_list argList);
  298. void CopyBeforeWrite();
  299. BOOL AllocBeforeWrite(int nLen);
  300. void Release();
  301. static void PASCAL Release(CStringData* pData);
  302. static int PASCAL SafeStrlen(LPCTSTR lpsz);
  303. };
  304. // Compare helpers
  305. bool __stdcall operator==(const CString& s1, const CString& s2);
  306. bool __stdcall operator==(const CString& s1, LPCTSTR s2);
  307. bool __stdcall operator==(LPCTSTR s1, const CString& s2);
  308. bool __stdcall operator!=(const CString& s1, const CString& s2);
  309. bool __stdcall operator!=(const CString& s1, LPCTSTR s2);
  310. bool __stdcall operator!=(LPCTSTR s1, const CString& s2);
  311. bool __stdcall operator<(const CString& s1, const CString& s2);
  312. bool __stdcall operator<(const CString& s1, LPCTSTR s2);
  313. bool __stdcall operator<(LPCTSTR s1, const CString& s2);
  314. bool __stdcall operator>(const CString& s1, const CString& s2);
  315. bool __stdcall operator>(const CString& s1, LPCTSTR s2);
  316. bool __stdcall operator>(LPCTSTR s1, const CString& s2);
  317. bool __stdcall operator<=(const CString& s1, const CString& s2);
  318. bool __stdcall operator<=(const CString& s1, LPCTSTR s2);
  319. bool __stdcall operator<=(LPCTSTR s1, const CString& s2);
  320. bool __stdcall operator>=(const CString& s1, const CString& s2);
  321. bool __stdcall operator>=(const CString& s1, LPCTSTR s2);
  322. bool __stdcall operator>=(LPCTSTR s1, const CString& s2);
  323. // conversion helpers
  324. int __cdecl _wcstombsz(char* mbstr, const wchar_t* wcstr, size_t count);
  325. int __cdecl _mbstowcsz(wchar_t* wcstr, const char* mbstr, size_t count);
  326. // Globals
  327. // afxChNil is left for backward compatibility
  328. _declspec(selectany) TCHAR afxChNil = '\0';
  329. // For an empty string, m_pchData will point here
  330. // (note: avoids special case of checking for NULL m_pchData)
  331. // empty string data (and locked)
  332. _declspec(selectany) int rgInitData[] = { -1, 0, 0, 0 };
  333. _declspec(selectany) CStringData* afxDataNil = (CStringData*)&rgInitData;
  334. _declspec(selectany) LPCTSTR afxPchNil = (LPCTSTR)(((BYTE*)&rgInitData)+sizeof(CStringData));
  335. inline const CString& __stdcall AfxGetEmptyString()
  336. { return *(CString*)&afxPchNil; }
  337. #define afxEmptyString AfxGetEmptyString()
  338. #endif //!_ATL_TMP_NO_CSTRING
  339. /////////////////////////////////////////////////////////////////////////////
  340. // Implementation
  341. // CSize
  342. inline CSize::CSize()
  343. { /* random filled */ }
  344. inline CSize::CSize(int initCX, int initCY)
  345. { cx = initCX; cy = initCY; }
  346. inline CSize::CSize(SIZE initSize)
  347. { *(SIZE*)this = initSize; }
  348. inline CSize::CSize(POINT initPt)
  349. { *(POINT*)this = initPt; }
  350. inline CSize::CSize(DWORD dwSize)
  351. {
  352. cx = (short)LOWORD(dwSize);
  353. cy = (short)HIWORD(dwSize);
  354. }
  355. inline BOOL CSize::operator==(SIZE size) const
  356. { return (cx == size.cx && cy == size.cy); }
  357. inline BOOL CSize::operator!=(SIZE size) const
  358. { return (cx != size.cx || cy != size.cy); }
  359. inline void CSize::operator+=(SIZE size)
  360. { cx += size.cx; cy += size.cy; }
  361. inline void CSize::operator-=(SIZE size)
  362. { cx -= size.cx; cy -= size.cy; }
  363. inline CSize CSize::operator+(SIZE size) const
  364. { return CSize(cx + size.cx, cy + size.cy); }
  365. inline CSize CSize::operator-(SIZE size) const
  366. { return CSize(cx - size.cx, cy - size.cy); }
  367. inline CSize CSize::operator-() const
  368. { return CSize(-cx, -cy); }
  369. inline CPoint CSize::operator+(POINT point) const
  370. { return CPoint(cx + point.x, cy + point.y); }
  371. inline CPoint CSize::operator-(POINT point) const
  372. { return CPoint(cx - point.x, cy - point.y); }
  373. inline CRect CSize::operator+(const RECT* lpRect) const
  374. { return CRect(lpRect) + *this; }
  375. inline CRect CSize::operator-(const RECT* lpRect) const
  376. { return CRect(lpRect) - *this; }
  377. // CPoint
  378. inline CPoint::CPoint()
  379. { /* random filled */ }
  380. inline CPoint::CPoint(int initX, int initY)
  381. { x = initX; y = initY; }
  382. inline CPoint::CPoint(POINT initPt)
  383. { *(POINT*)this = initPt; }
  384. inline CPoint::CPoint(SIZE initSize)
  385. { *(SIZE*)this = initSize; }
  386. inline CPoint::CPoint(DWORD dwPoint)
  387. {
  388. x = (short)LOWORD(dwPoint);
  389. y = (short)HIWORD(dwPoint);
  390. }
  391. inline void CPoint::Offset(int xOffset, int yOffset)
  392. { x += xOffset; y += yOffset; }
  393. inline void CPoint::Offset(POINT point)
  394. { x += point.x; y += point.y; }
  395. inline void CPoint::Offset(SIZE size)
  396. { x += size.cx; y += size.cy; }
  397. inline BOOL CPoint::operator==(POINT point) const
  398. { return (x == point.x && y == point.y); }
  399. inline BOOL CPoint::operator!=(POINT point) const
  400. { return (x != point.x || y != point.y); }
  401. inline void CPoint::operator+=(SIZE size)
  402. { x += size.cx; y += size.cy; }
  403. inline void CPoint::operator-=(SIZE size)
  404. { x -= size.cx; y -= size.cy; }
  405. inline void CPoint::operator+=(POINT point)
  406. { x += point.x; y += point.y; }
  407. inline void CPoint::operator-=(POINT point)
  408. { x -= point.x; y -= point.y; }
  409. inline CPoint CPoint::operator+(SIZE size) const
  410. { return CPoint(x + size.cx, y + size.cy); }
  411. inline CPoint CPoint::operator-(SIZE size) const
  412. { return CPoint(x - size.cx, y - size.cy); }
  413. inline CPoint CPoint::operator-() const
  414. { return CPoint(-x, -y); }
  415. inline CPoint CPoint::operator+(POINT point) const
  416. { return CPoint(x + point.x, y + point.y); }
  417. inline CSize CPoint::operator-(POINT point) const
  418. { return CSize(x - point.x, y - point.y); }
  419. inline CRect CPoint::operator+(const RECT* lpRect) const
  420. { return CRect(lpRect) + *this; }
  421. inline CRect CPoint::operator-(const RECT* lpRect) const
  422. { return CRect(lpRect) - *this; }
  423. // CRect
  424. inline CRect::CRect()
  425. { /* random filled */ }
  426. inline CRect::CRect(int l, int t, int r, int b)
  427. { left = l; top = t; right = r; bottom = b; }
  428. inline CRect::CRect(const RECT& srcRect)
  429. { ::CopyRect(this, &srcRect); }
  430. inline CRect::CRect(LPCRECT lpSrcRect)
  431. { ::CopyRect(this, lpSrcRect); }
  432. inline CRect::CRect(POINT point, SIZE size)
  433. { right = (left = point.x) + size.cx; bottom = (top = point.y) + size.cy; }
  434. inline CRect::CRect(POINT topLeft, POINT bottomRight)
  435. { left = topLeft.x; top = topLeft.y;
  436. right = bottomRight.x; bottom = bottomRight.y; }
  437. inline int CRect::Width() const
  438. { return right - left; }
  439. inline int CRect::Height() const
  440. { return bottom - top; }
  441. inline CSize CRect::Size() const
  442. { return CSize(right - left, bottom - top); }
  443. inline CPoint& CRect::TopLeft()
  444. { return *((CPoint*)this); }
  445. inline CPoint& CRect::BottomRight()
  446. { return *((CPoint*)this+1); }
  447. inline const CPoint& CRect::TopLeft() const
  448. { return *((CPoint*)this); }
  449. inline const CPoint& CRect::BottomRight() const
  450. { return *((CPoint*)this+1); }
  451. inline CPoint CRect::CenterPoint() const
  452. { return CPoint((left+right)/2, (top+bottom)/2); }
  453. inline CRect::operator LPRECT()
  454. { return this; }
  455. inline CRect::operator LPCRECT() const
  456. { return this; }
  457. inline BOOL CRect::IsRectEmpty() const
  458. { return ::IsRectEmpty(this); }
  459. inline BOOL CRect::IsRectNull() const
  460. { return (left == 0 && right == 0 && top == 0 && bottom == 0); }
  461. inline BOOL CRect::PtInRect(POINT point) const
  462. { return ::PtInRect(this, point); }
  463. inline void CRect::SetRect(int x1, int y1, int x2, int y2)
  464. { ::SetRect(this, x1, y1, x2, y2); }
  465. inline void CRect::SetRect(POINT topLeft, POINT bottomRight)
  466. { ::SetRect(this, topLeft.x, topLeft.y, bottomRight.x, bottomRight.y); }
  467. inline void CRect::SetRectEmpty()
  468. { ::SetRectEmpty(this); }
  469. inline void CRect::CopyRect(LPCRECT lpSrcRect)
  470. { ::CopyRect(this, lpSrcRect); }
  471. inline BOOL CRect::EqualRect(LPCRECT lpRect) const
  472. { return ::EqualRect(this, lpRect); }
  473. inline void CRect::InflateRect(int x, int y)
  474. { ::InflateRect(this, x, y); }
  475. inline void CRect::InflateRect(SIZE size)
  476. { ::InflateRect(this, size.cx, size.cy); }
  477. inline void CRect::DeflateRect(int x, int y)
  478. { ::InflateRect(this, -x, -y); }
  479. inline void CRect::DeflateRect(SIZE size)
  480. { ::InflateRect(this, -size.cx, -size.cy); }
  481. inline void CRect::OffsetRect(int x, int y)
  482. { ::OffsetRect(this, x, y); }
  483. inline void CRect::OffsetRect(POINT point)
  484. { ::OffsetRect(this, point.x, point.y); }
  485. inline void CRect::OffsetRect(SIZE size)
  486. { ::OffsetRect(this, size.cx, size.cy); }
  487. inline BOOL CRect::IntersectRect(LPCRECT lpRect1, LPCRECT lpRect2)
  488. { return ::IntersectRect(this, lpRect1, lpRect2);}
  489. inline BOOL CRect::UnionRect(LPCRECT lpRect1, LPCRECT lpRect2)
  490. { return ::UnionRect(this, lpRect1, lpRect2); }
  491. inline void CRect::operator=(const RECT& srcRect)
  492. { ::CopyRect(this, &srcRect); }
  493. inline BOOL CRect::operator==(const RECT& rect) const
  494. { return ::EqualRect(this, &rect); }
  495. inline BOOL CRect::operator!=(const RECT& rect) const
  496. { return !::EqualRect(this, &rect); }
  497. inline void CRect::operator+=(POINT point)
  498. { ::OffsetRect(this, point.x, point.y); }
  499. inline void CRect::operator+=(SIZE size)
  500. { ::OffsetRect(this, size.cx, size.cy); }
  501. inline void CRect::operator+=(LPCRECT lpRect)
  502. { InflateRect(lpRect); }
  503. inline void CRect::operator-=(POINT point)
  504. { ::OffsetRect(this, -point.x, -point.y); }
  505. inline void CRect::operator-=(SIZE size)
  506. { ::OffsetRect(this, -size.cx, -size.cy); }
  507. inline void CRect::operator-=(LPCRECT lpRect)
  508. { DeflateRect(lpRect); }
  509. inline void CRect::operator&=(const RECT& rect)
  510. { ::IntersectRect(this, this, &rect); }
  511. inline void CRect::operator|=(const RECT& rect)
  512. { ::UnionRect(this, this, &rect); }
  513. inline CRect CRect::operator+(POINT pt) const
  514. { CRect rect(*this); ::OffsetRect(&rect, pt.x, pt.y); return rect; }
  515. inline CRect CRect::operator-(POINT pt) const
  516. { CRect rect(*this); ::OffsetRect(&rect, -pt.x, -pt.y); return rect; }
  517. inline CRect CRect::operator+(SIZE size) const
  518. { CRect rect(*this); ::OffsetRect(&rect, size.cx, size.cy); return rect; }
  519. inline CRect CRect::operator-(SIZE size) const
  520. { CRect rect(*this); ::OffsetRect(&rect, -size.cx, -size.cy); return rect; }
  521. inline CRect CRect::operator+(LPCRECT lpRect) const
  522. { CRect rect(this); rect.InflateRect(lpRect); return rect; }
  523. inline CRect CRect::operator-(LPCRECT lpRect) const
  524. { CRect rect(this); rect.DeflateRect(lpRect); return rect; }
  525. inline CRect CRect::operator&(const RECT& rect2) const
  526. { CRect rect; ::IntersectRect(&rect, this, &rect2);
  527. return rect; }
  528. inline CRect CRect::operator|(const RECT& rect2) const
  529. { CRect rect; ::UnionRect(&rect, this, &rect2);
  530. return rect; }
  531. inline BOOL CRect::SubtractRect(LPCRECT lpRectSrc1, LPCRECT lpRectSrc2)
  532. { return ::SubtractRect(this, lpRectSrc1, lpRectSrc2); }
  533. inline void CRect::NormalizeRect()
  534. {
  535. int nTemp;
  536. if (left > right)
  537. {
  538. nTemp = left;
  539. left = right;
  540. right = nTemp;
  541. }
  542. if (top > bottom)
  543. {
  544. nTemp = top;
  545. top = bottom;
  546. bottom = nTemp;
  547. }
  548. }
  549. inline void CRect::InflateRect(LPCRECT lpRect)
  550. {
  551. left -= lpRect->left;
  552. top -= lpRect->top;
  553. right += lpRect->right;
  554. bottom += lpRect->bottom;
  555. }
  556. inline void CRect::InflateRect(int l, int t, int r, int b)
  557. {
  558. left -= l;
  559. top -= t;
  560. right += r;
  561. bottom += b;
  562. }
  563. inline void CRect::DeflateRect(LPCRECT lpRect)
  564. {
  565. left += lpRect->left;
  566. top += lpRect->top;
  567. right -= lpRect->right;
  568. bottom -= lpRect->bottom;
  569. }
  570. inline void CRect::DeflateRect(int l, int t, int r, int b)
  571. {
  572. left += l;
  573. top += t;
  574. right -= r;
  575. bottom -= b;
  576. }
  577. inline CRect CRect::MulDiv(int nMultiplier, int nDivisor) const
  578. {
  579. return CRect(
  580. ::MulDiv(left, nMultiplier, nDivisor),
  581. ::MulDiv(top, nMultiplier, nDivisor),
  582. ::MulDiv(right, nMultiplier, nDivisor),
  583. ::MulDiv(bottom, nMultiplier, nDivisor));
  584. }
  585. #ifndef _ATL_TMP_NO_CSTRING
  586. // CString
  587. inline CStringData* CString::GetData() const
  588. { ATLASSERT(m_pchData != NULL); return ((CStringData*)m_pchData)-1; }
  589. inline void CString::Init()
  590. { m_pchData = afxEmptyString.m_pchData; }
  591. inline CString::CString(const unsigned char* lpsz)
  592. { Init(); *this = (LPCSTR)lpsz; }
  593. inline const CString& CString::operator=(const unsigned char* lpsz)
  594. { *this = (LPCSTR)lpsz; return *this; }
  595. #ifdef _UNICODE
  596. inline const CString& CString::operator+=(char ch)
  597. { *this += (TCHAR)ch; return *this; }
  598. inline const CString& CString::operator=(char ch)
  599. { *this = (TCHAR)ch; return *this; }
  600. inline CString __stdcall operator+(const CString& string, char ch)
  601. { return string + (TCHAR)ch; }
  602. inline CString __stdcall operator+(char ch, const CString& string)
  603. { return (TCHAR)ch + string; }
  604. #endif
  605. inline int CString::GetLength() const
  606. { return GetData()->nDataLength; }
  607. inline int CString::GetAllocLength() const
  608. { return GetData()->nAllocLength; }
  609. inline BOOL CString::IsEmpty() const
  610. { return GetData()->nDataLength == 0; }
  611. inline CString::operator LPCTSTR() const
  612. { return m_pchData; }
  613. inline int PASCAL CString::SafeStrlen(LPCTSTR lpsz)
  614. { return (lpsz == NULL) ? 0 : lstrlen(lpsz); }
  615. // CString support (windows specific)
  616. inline int CString::Compare(LPCTSTR lpsz) const
  617. { return _tcscmp(m_pchData, lpsz); } // MBCS/Unicode aware
  618. inline int CString::CompareNoCase(LPCTSTR lpsz) const
  619. { return _tcsicmp(m_pchData, lpsz); } // MBCS/Unicode aware
  620. // CString::Collate is often slower than Compare but is MBSC/Unicode
  621. // aware as well as locale-sensitive with respect to sort order.
  622. inline int CString::Collate(LPCTSTR lpsz) const
  623. { return _tcscoll(m_pchData, lpsz); } // locale sensitive
  624. inline TCHAR CString::GetAt(int nIndex) const
  625. {
  626. ATLASSERT(nIndex >= 0);
  627. ATLASSERT(nIndex < GetData()->nDataLength);
  628. return m_pchData[nIndex];
  629. }
  630. inline TCHAR CString::operator[](int nIndex) const
  631. {
  632. // same as GetAt
  633. ATLASSERT(nIndex >= 0);
  634. ATLASSERT(nIndex < GetData()->nDataLength);
  635. return m_pchData[nIndex];
  636. }
  637. inline bool __stdcall operator==(const CString& s1, const CString& s2)
  638. { return s1.Compare(s2) == 0; }
  639. inline bool __stdcall operator==(const CString& s1, LPCTSTR s2)
  640. { return s1.Compare(s2) == 0; }
  641. inline bool __stdcall operator==(LPCTSTR s1, const CString& s2)
  642. { return s2.Compare(s1) == 0; }
  643. inline bool __stdcall operator!=(const CString& s1, const CString& s2)
  644. { return s1.Compare(s2) != 0; }
  645. inline bool __stdcall operator!=(const CString& s1, LPCTSTR s2)
  646. { return s1.Compare(s2) != 0; }
  647. inline bool __stdcall operator!=(LPCTSTR s1, const CString& s2)
  648. { return s2.Compare(s1) != 0; }
  649. inline bool __stdcall operator<(const CString& s1, const CString& s2)
  650. { return s1.Compare(s2) < 0; }
  651. inline bool __stdcall operator<(const CString& s1, LPCTSTR s2)
  652. { return s1.Compare(s2) < 0; }
  653. inline bool __stdcall operator<(LPCTSTR s1, const CString& s2)
  654. { return s2.Compare(s1) > 0; }
  655. inline bool __stdcall operator>(const CString& s1, const CString& s2)
  656. { return s1.Compare(s2) > 0; }
  657. inline bool __stdcall operator>(const CString& s1, LPCTSTR s2)
  658. { return s1.Compare(s2) > 0; }
  659. inline bool __stdcall operator>(LPCTSTR s1, const CString& s2)
  660. { return s2.Compare(s1) < 0; }
  661. inline bool __stdcall operator<=(const CString& s1, const CString& s2)
  662. { return s1.Compare(s2) <= 0; }
  663. inline bool __stdcall operator<=(const CString& s1, LPCTSTR s2)
  664. { return s1.Compare(s2) <= 0; }
  665. inline bool __stdcall operator<=(LPCTSTR s1, const CString& s2)
  666. { return s2.Compare(s1) >= 0; }
  667. inline bool __stdcall operator>=(const CString& s1, const CString& s2)
  668. { return s1.Compare(s2) >= 0; }
  669. inline bool __stdcall operator>=(const CString& s1, LPCTSTR s2)
  670. { return s1.Compare(s2) >= 0; }
  671. inline bool __stdcall operator>=(LPCTSTR s1, const CString& s2)
  672. { return s2.Compare(s1) <= 0; }
  673. inline BOOL __stdcall AfxIsValidString(LPCWSTR lpsz, int nLength)
  674. {
  675. if(lpsz == NULL)
  676. return FALSE;
  677. return !::IsBadStringPtrW(lpsz, nLength);
  678. }
  679. inline BOOL __stdcall AfxIsValidString(LPCSTR lpsz, int nLength)
  680. {
  681. if(lpsz == NULL)
  682. return FALSE;
  683. return !::IsBadStringPtrA(lpsz, nLength);
  684. }
  685. inline BOOL __stdcall AfxIsValidAddress(const void* lp, UINT nBytes, BOOL bReadWrite = TRUE)
  686. {
  687. // simple version using Win-32 APIs for pointer validation.
  688. return (lp != NULL && !IsBadReadPtr(lp, nBytes) &&
  689. (!bReadWrite || !IsBadWritePtr((LPVOID)lp, nBytes)));
  690. }
  691. inline CString::CString()
  692. {
  693. Init();
  694. }
  695. inline CString::CString(const CString& stringSrc)
  696. {
  697. ATLASSERT(stringSrc.GetData()->nRefs != 0);
  698. if (stringSrc.GetData()->nRefs >= 0)
  699. {
  700. ATLASSERT(stringSrc.GetData() != afxDataNil);
  701. m_pchData = stringSrc.m_pchData;
  702. InterlockedIncrement(&GetData()->nRefs);
  703. }
  704. else
  705. {
  706. Init();
  707. *this = stringSrc.m_pchData;
  708. }
  709. }
  710. inline BOOL CString::AllocBuffer(int nLen)
  711. // always allocate one extra character for '\0' termination
  712. // assumes [optimistically] that data length will equal allocation length
  713. {
  714. ATLASSERT(nLen >= 0);
  715. ATLASSERT(nLen <= INT_MAX-1); // max size (enough room for 1 extra)
  716. if (nLen == 0)
  717. Init();
  718. else
  719. {
  720. CStringData* pData = NULL;
  721. ATLTRY(pData = (CStringData*)new BYTE[sizeof(CStringData) + (nLen+1)*sizeof(TCHAR)]);
  722. if(pData == NULL)
  723. return FALSE;
  724. pData->nRefs = 1;
  725. pData->data()[nLen] = '\0';
  726. pData->nDataLength = nLen;
  727. pData->nAllocLength = nLen;
  728. m_pchData = pData->data();
  729. }
  730. return TRUE;
  731. }
  732. inline void CString::Release()
  733. {
  734. if (GetData() != afxDataNil)
  735. {
  736. ATLASSERT(GetData()->nRefs != 0);
  737. if (InterlockedDecrement(&GetData()->nRefs) <= 0)
  738. delete[] (BYTE*)GetData();
  739. Init();
  740. }
  741. }
  742. inline void PASCAL CString::Release(CStringData* pData)
  743. {
  744. if (pData != afxDataNil)
  745. {
  746. ATLASSERT(pData->nRefs != 0);
  747. if (InterlockedDecrement(&pData->nRefs) <= 0)
  748. delete[] (BYTE*)pData;
  749. }
  750. }
  751. inline void CString::Empty()
  752. {
  753. if (GetData()->nDataLength == 0)
  754. return;
  755. if (GetData()->nRefs >= 0)
  756. Release();
  757. else
  758. *this = &afxChNil;
  759. ATLASSERT(GetData()->nDataLength == 0);
  760. ATLASSERT(GetData()->nRefs < 0 || GetData()->nAllocLength == 0);
  761. }
  762. inline void CString::CopyBeforeWrite()
  763. {
  764. if (GetData()->nRefs > 1)
  765. {
  766. CStringData* pData = GetData();
  767. Release();
  768. if(AllocBuffer(pData->nDataLength))
  769. memcpy(m_pchData, pData->data(), (pData->nDataLength+1)*sizeof(TCHAR));
  770. }
  771. ATLASSERT(GetData()->nRefs <= 1);
  772. }
  773. inline BOOL CString::AllocBeforeWrite(int nLen)
  774. {
  775. BOOL bRet = TRUE;
  776. if (GetData()->nRefs > 1 || nLen > GetData()->nAllocLength)
  777. {
  778. Release();
  779. bRet = AllocBuffer(nLen);
  780. }
  781. ATLASSERT(GetData()->nRefs <= 1);
  782. return bRet;
  783. }
  784. inline CString::~CString()
  785. // free any attached data
  786. {
  787. if (GetData() != afxDataNil)
  788. {
  789. if (InterlockedDecrement(&GetData()->nRefs) <= 0)
  790. delete[] (BYTE*)GetData();
  791. }
  792. }
  793. inline void CString::AllocCopy(CString& dest, int nCopyLen, int nCopyIndex,
  794. int nExtraLen) const
  795. {
  796. // will clone the data attached to this string
  797. // allocating 'nExtraLen' characters
  798. // Places results in uninitialized string 'dest'
  799. // Will copy the part or all of original data to start of new string
  800. int nNewLen = nCopyLen + nExtraLen;
  801. if (nNewLen == 0)
  802. {
  803. dest.Init();
  804. }
  805. else
  806. {
  807. if(dest.AllocBuffer(nNewLen))
  808. memcpy(dest.m_pchData, m_pchData+nCopyIndex, nCopyLen*sizeof(TCHAR));
  809. }
  810. }
  811. inline CString::CString(LPCTSTR lpsz)
  812. {
  813. Init();
  814. if (lpsz != NULL && HIWORD(lpsz) == NULL)
  815. {
  816. UINT nID = LOWORD((DWORD_PTR)lpsz);
  817. if (!LoadString(nID))
  818. #if (_ATL_VER >= 0x0300)
  819. ATLTRACE2(atlTraceGeneral, 0, _T("Warning: implicit LoadString(%u) in CString failed\n"), nID);
  820. #else
  821. ATLTRACE2(atlTraceGeneral, 0, _T("Warning: implicit LoadString in CString failed\n"));
  822. #endif //(_ATL_VER >= 0x0300)
  823. }
  824. else
  825. {
  826. int nLen = SafeStrlen(lpsz);
  827. if (nLen != 0)
  828. {
  829. if(AllocBuffer(nLen))
  830. memcpy(m_pchData, lpsz, nLen*sizeof(TCHAR));
  831. }
  832. }
  833. }
  834. #ifdef _UNICODE
  835. inline CString::CString(LPCSTR lpsz)
  836. {
  837. Init();
  838. int nSrcLen = lpsz != NULL ? lstrlenA(lpsz) : 0;
  839. if (nSrcLen != 0)
  840. {
  841. if(AllocBuffer(nSrcLen))
  842. {
  843. _mbstowcsz(m_pchData, lpsz, nSrcLen+1);
  844. ReleaseBuffer();
  845. }
  846. }
  847. }
  848. #else //_UNICODE
  849. inline CString::CString(LPCWSTR lpsz)
  850. {
  851. Init();
  852. int nSrcLen = lpsz != NULL ? wcslen(lpsz) : 0;
  853. if (nSrcLen != 0)
  854. {
  855. if(AllocBuffer(nSrcLen*2))
  856. {
  857. _wcstombsz(m_pchData, lpsz, (nSrcLen*2)+1);
  858. ReleaseBuffer();
  859. }
  860. }
  861. }
  862. #endif //!_UNICODE
  863. // Assignment operators
  864. // All assign a new value to the string
  865. // (a) first see if the buffer is big enough
  866. // (b) if enough room, copy on top of old buffer, set size and type
  867. // (c) otherwise free old string data, and create a new one
  868. //
  869. // All routines return the new string (but as a 'const CString&' so that
  870. // assigning it again will cause a copy, eg: s1 = s2 = "hi there".
  871. //
  872. inline void CString::AssignCopy(int nSrcLen, LPCTSTR lpszSrcData)
  873. {
  874. if(AllocBeforeWrite(nSrcLen))
  875. {
  876. memcpy(m_pchData, lpszSrcData, nSrcLen*sizeof(TCHAR));
  877. GetData()->nDataLength = nSrcLen;
  878. m_pchData[nSrcLen] = '\0';
  879. }
  880. }
  881. inline const CString& CString::operator=(const CString& stringSrc)
  882. {
  883. if (m_pchData != stringSrc.m_pchData)
  884. {
  885. if ((GetData()->nRefs < 0 && GetData() != afxDataNil) ||
  886. stringSrc.GetData()->nRefs < 0)
  887. {
  888. // actual copy necessary since one of the strings is locked
  889. AssignCopy(stringSrc.GetData()->nDataLength, stringSrc.m_pchData);
  890. }
  891. else
  892. {
  893. // can just copy references around
  894. Release();
  895. ATLASSERT(stringSrc.GetData() != afxDataNil);
  896. m_pchData = stringSrc.m_pchData;
  897. InterlockedIncrement(&GetData()->nRefs);
  898. }
  899. }
  900. return *this;
  901. }
  902. inline const CString& CString::operator=(LPCTSTR lpsz)
  903. {
  904. ATLASSERT(lpsz == NULL || AfxIsValidString(lpsz, FALSE));
  905. AssignCopy(SafeStrlen(lpsz), lpsz);
  906. return *this;
  907. }
  908. #ifdef _UNICODE
  909. inline const CString& CString::operator=(LPCSTR lpsz)
  910. {
  911. int nSrcLen = lpsz != NULL ? lstrlenA(lpsz) : 0;
  912. if(AllocBeforeWrite(nSrcLen))
  913. {
  914. _mbstowcsz(m_pchData, lpsz, nSrcLen+1);
  915. ReleaseBuffer();
  916. }
  917. return *this;
  918. }
  919. #else //!_UNICODE
  920. inline const CString& CString::operator=(LPCWSTR lpsz)
  921. {
  922. int nSrcLen = lpsz != NULL ? wcslen(lpsz) : 0;
  923. if(AllocBeforeWrite(nSrcLen*2))
  924. {
  925. _wcstombsz(m_pchData, lpsz, (nSrcLen*2)+1);
  926. ReleaseBuffer();
  927. }
  928. return *this;
  929. }
  930. #endif //!_UNICODE
  931. // Concatenation
  932. // NOTE: "operator+" is done as friend functions for simplicity
  933. // There are three variants:
  934. // CString + CString
  935. // and for ? = TCHAR, LPCTSTR
  936. // CString + ?
  937. // ? + CString
  938. inline void CString::ConcatCopy(int nSrc1Len, LPCTSTR lpszSrc1Data,
  939. int nSrc2Len, LPCTSTR lpszSrc2Data)
  940. {
  941. // -- master concatenation routine
  942. // Concatenate two sources
  943. // -- assume that 'this' is a new CString object
  944. int nNewLen = nSrc1Len + nSrc2Len;
  945. if (nNewLen != 0)
  946. {
  947. if(AllocBuffer(nNewLen))
  948. {
  949. memcpy(m_pchData, lpszSrc1Data, nSrc1Len*sizeof(TCHAR));
  950. memcpy(m_pchData+nSrc1Len, lpszSrc2Data, nSrc2Len*sizeof(TCHAR));
  951. }
  952. }
  953. }
  954. inline CString __stdcall operator+(const CString& string1, const CString& string2)
  955. {
  956. CString s;
  957. s.ConcatCopy(string1.GetData()->nDataLength, string1.m_pchData,
  958. string2.GetData()->nDataLength, string2.m_pchData);
  959. return s;
  960. }
  961. inline CString __stdcall operator+(const CString& string, LPCTSTR lpsz)
  962. {
  963. ATLASSERT(lpsz == NULL || AfxIsValidString(lpsz, FALSE));
  964. CString s;
  965. s.ConcatCopy(string.GetData()->nDataLength, string.m_pchData,
  966. CString::SafeStrlen(lpsz), lpsz);
  967. return s;
  968. }
  969. inline CString __stdcall operator+(LPCTSTR lpsz, const CString& string)
  970. {
  971. ATLASSERT(lpsz == NULL || AfxIsValidString(lpsz, FALSE));
  972. CString s;
  973. s.ConcatCopy(CString::SafeStrlen(lpsz), lpsz, string.GetData()->nDataLength,
  974. string.m_pchData);
  975. return s;
  976. }
  977. inline void CString::ConcatInPlace(int nSrcLen, LPCTSTR lpszSrcData)
  978. {
  979. // -- the main routine for += operators
  980. // concatenating an empty string is a no-op!
  981. if (nSrcLen == 0)
  982. return;
  983. // if the buffer is too small, or we have a width mis-match, just
  984. // allocate a new buffer (slow but sure)
  985. if (GetData()->nRefs > 1 || GetData()->nDataLength + nSrcLen > GetData()->nAllocLength)
  986. {
  987. // we have to grow the buffer, use the ConcatCopy routine
  988. CStringData* pOldData = GetData();
  989. ConcatCopy(GetData()->nDataLength, m_pchData, nSrcLen, lpszSrcData);
  990. ATLASSERT(pOldData != NULL);
  991. CString::Release(pOldData);
  992. }
  993. else
  994. {
  995. // fast concatenation when buffer big enough
  996. memcpy(m_pchData+GetData()->nDataLength, lpszSrcData, nSrcLen*sizeof(TCHAR));
  997. GetData()->nDataLength += nSrcLen;
  998. ATLASSERT(GetData()->nDataLength <= GetData()->nAllocLength);
  999. m_pchData[GetData()->nDataLength] = '\0';
  1000. }
  1001. }
  1002. inline const CString& CString::operator+=(LPCTSTR lpsz)
  1003. {
  1004. ATLASSERT(lpsz == NULL || AfxIsValidString(lpsz, FALSE));
  1005. ConcatInPlace(SafeStrlen(lpsz), lpsz);
  1006. return *this;
  1007. }
  1008. inline const CString& CString::operator+=(TCHAR ch)
  1009. {
  1010. ConcatInPlace(1, &ch);
  1011. return *this;
  1012. }
  1013. inline const CString& CString::operator+=(const CString& string)
  1014. {
  1015. ConcatInPlace(string.GetData()->nDataLength, string.m_pchData);
  1016. return *this;
  1017. }
  1018. inline LPTSTR CString::GetBuffer(int nMinBufLength)
  1019. {
  1020. ATLASSERT(nMinBufLength >= 0);
  1021. if (GetData()->nRefs > 1 || nMinBufLength > GetData()->nAllocLength)
  1022. {
  1023. // we have to grow the buffer
  1024. CStringData* pOldData = GetData();
  1025. int nOldLen = GetData()->nDataLength; // AllocBuffer will tromp it
  1026. if (nMinBufLength < nOldLen)
  1027. nMinBufLength = nOldLen;
  1028. if(AllocBuffer(nMinBufLength))
  1029. {
  1030. memcpy(m_pchData, pOldData->data(), (nOldLen+1)*sizeof(TCHAR));
  1031. GetData()->nDataLength = nOldLen;
  1032. CString::Release(pOldData);
  1033. }
  1034. }
  1035. ATLASSERT(GetData()->nRefs <= 1);
  1036. // return a pointer to the character storage for this string
  1037. ATLASSERT(m_pchData != NULL);
  1038. return m_pchData;
  1039. }
  1040. inline void CString::ReleaseBuffer(int nNewLength)
  1041. {
  1042. CopyBeforeWrite(); // just in case GetBuffer was not called
  1043. if (nNewLength == -1)
  1044. nNewLength = lstrlen(m_pchData); // zero terminated
  1045. ATLASSERT(nNewLength <= GetData()->nAllocLength);
  1046. GetData()->nDataLength = nNewLength;
  1047. m_pchData[nNewLength] = '\0';
  1048. }
  1049. inline LPTSTR CString::GetBufferSetLength(int nNewLength)
  1050. {
  1051. ATLASSERT(nNewLength >= 0);
  1052. GetBuffer(nNewLength);
  1053. GetData()->nDataLength = nNewLength;
  1054. m_pchData[nNewLength] = '\0';
  1055. return m_pchData;
  1056. }
  1057. inline void CString::FreeExtra()
  1058. {
  1059. ATLASSERT(GetData()->nDataLength <= GetData()->nAllocLength);
  1060. if (GetData()->nDataLength != GetData()->nAllocLength)
  1061. {
  1062. CStringData* pOldData = GetData();
  1063. if(AllocBuffer(GetData()->nDataLength))
  1064. {
  1065. memcpy(m_pchData, pOldData->data(), pOldData->nDataLength*sizeof(TCHAR));
  1066. ATLASSERT(m_pchData[GetData()->nDataLength] == '\0');
  1067. CString::Release(pOldData);
  1068. }
  1069. }
  1070. ATLASSERT(GetData() != NULL);
  1071. }
  1072. inline LPTSTR CString::LockBuffer()
  1073. {
  1074. LPTSTR lpsz = GetBuffer(0);
  1075. GetData()->nRefs = -1;
  1076. return lpsz;
  1077. }
  1078. inline void CString::UnlockBuffer()
  1079. {
  1080. ATLASSERT(GetData()->nRefs == -1);
  1081. if (GetData() != afxDataNil)
  1082. GetData()->nRefs = 1;
  1083. }
  1084. inline int CString::Find(TCHAR ch) const
  1085. {
  1086. // find first single character
  1087. LPTSTR lpsz = _tcschr(m_pchData, (_TUCHAR)ch);
  1088. // return -1 if not found and index otherwise
  1089. return (lpsz == NULL) ? -1 : (int)(lpsz - m_pchData);
  1090. }
  1091. inline int CString::FindOneOf(LPCTSTR lpszCharSet) const
  1092. {
  1093. ATLASSERT(AfxIsValidString(lpszCharSet, FALSE));
  1094. LPTSTR lpsz = _tcspbrk(m_pchData, lpszCharSet);
  1095. return (lpsz == NULL) ? -1 : (int)(lpsz - m_pchData);
  1096. }
  1097. inline void CString::MakeUpper()
  1098. {
  1099. CopyBeforeWrite();
  1100. _tcsupr(m_pchData);
  1101. }
  1102. inline void CString::MakeLower()
  1103. {
  1104. CopyBeforeWrite();
  1105. _tcslwr(m_pchData);
  1106. }
  1107. inline void CString::MakeReverse()
  1108. {
  1109. CopyBeforeWrite();
  1110. _tcsrev(m_pchData);
  1111. }
  1112. inline void CString::SetAt(int nIndex, TCHAR ch)
  1113. {
  1114. ATLASSERT(nIndex >= 0);
  1115. ATLASSERT(nIndex < GetData()->nDataLength);
  1116. CopyBeforeWrite();
  1117. m_pchData[nIndex] = ch;
  1118. }
  1119. #ifndef _UNICODE
  1120. inline void CString::AnsiToOem()
  1121. {
  1122. CopyBeforeWrite();
  1123. ::AnsiToOem(m_pchData, m_pchData);
  1124. }
  1125. inline void CString::OemToAnsi()
  1126. {
  1127. CopyBeforeWrite();
  1128. ::OemToAnsi(m_pchData, m_pchData);
  1129. }
  1130. #endif
  1131. // CString conversion helpers (these use the current system locale)
  1132. inline int __cdecl _wcstombsz(char* mbstr, const wchar_t* wcstr, size_t count)
  1133. {
  1134. if (count == 0 && mbstr != NULL)
  1135. return 0;
  1136. int result = ::WideCharToMultiByte(CP_ACP, 0, wcstr, -1,
  1137. mbstr, count, NULL, NULL);
  1138. ATLASSERT(mbstr == NULL || result <= (int)count);
  1139. if (result > 0)
  1140. mbstr[result-1] = 0;
  1141. return result;
  1142. }
  1143. inline int __cdecl _mbstowcsz(wchar_t* wcstr, const char* mbstr, size_t count)
  1144. {
  1145. if (count == 0 && wcstr != NULL)
  1146. return 0;
  1147. int result = ::MultiByteToWideChar(CP_ACP, 0, mbstr, -1,
  1148. wcstr, count);
  1149. ATLASSERT(wcstr == NULL || result <= (int)count);
  1150. if (result > 0)
  1151. wcstr[result-1] = 0;
  1152. return result;
  1153. }
  1154. inline CString::CString(TCHAR ch, int nLength)
  1155. {
  1156. ATLASSERT(!_istlead(ch)); // can't create a lead byte string
  1157. Init();
  1158. if (nLength >= 1)
  1159. {
  1160. if(AllocBuffer(nLength))
  1161. {
  1162. #ifdef _UNICODE
  1163. for (int i = 0; i < nLength; i++)
  1164. m_pchData[i] = ch;
  1165. #else
  1166. memset(m_pchData, ch, nLength);
  1167. #endif
  1168. }
  1169. }
  1170. }
  1171. inline CString::CString(LPCTSTR lpch, int nLength)
  1172. {
  1173. Init();
  1174. if (nLength != 0)
  1175. {
  1176. ATLASSERT(AfxIsValidAddress(lpch, nLength, FALSE));
  1177. if(AllocBuffer(nLength))
  1178. memcpy(m_pchData, lpch, nLength*sizeof(TCHAR));
  1179. }
  1180. }
  1181. inline const CString& CString::operator=(TCHAR ch)
  1182. {
  1183. ATLASSERT(!_istlead(ch)); // can't set single lead byte
  1184. AssignCopy(1, &ch);
  1185. return *this;
  1186. }
  1187. inline CString __stdcall operator+(const CString& string1, TCHAR ch)
  1188. {
  1189. CString s;
  1190. s.ConcatCopy(string1.GetData()->nDataLength, string1.m_pchData, 1, &ch);
  1191. return s;
  1192. }
  1193. inline CString __stdcall operator+(TCHAR ch, const CString& string)
  1194. {
  1195. CString s;
  1196. s.ConcatCopy(1, &ch, string.GetData()->nDataLength, string.m_pchData);
  1197. return s;
  1198. }
  1199. inline CString CString::Mid(int nFirst) const
  1200. {
  1201. return Mid(nFirst, GetData()->nDataLength - nFirst);
  1202. }
  1203. inline CString CString::Mid(int nFirst, int nCount) const
  1204. {
  1205. // out-of-bounds requests return sensible things
  1206. if (nFirst < 0)
  1207. nFirst = 0;
  1208. if (nCount < 0)
  1209. nCount = 0;
  1210. if (nFirst + nCount > GetData()->nDataLength)
  1211. nCount = GetData()->nDataLength - nFirst;
  1212. if (nFirst > GetData()->nDataLength)
  1213. nCount = 0;
  1214. CString dest;
  1215. AllocCopy(dest, nCount, nFirst, 0);
  1216. return dest;
  1217. }
  1218. inline CString CString::Right(int nCount) const
  1219. {
  1220. if (nCount < 0)
  1221. nCount = 0;
  1222. else if (nCount > GetData()->nDataLength)
  1223. nCount = GetData()->nDataLength;
  1224. CString dest;
  1225. AllocCopy(dest, nCount, GetData()->nDataLength-nCount, 0);
  1226. return dest;
  1227. }
  1228. inline CString CString::Left(int nCount) const
  1229. {
  1230. if (nCount < 0)
  1231. nCount = 0;
  1232. else if (nCount > GetData()->nDataLength)
  1233. nCount = GetData()->nDataLength;
  1234. CString dest;
  1235. AllocCopy(dest, nCount, 0, 0);
  1236. return dest;
  1237. }
  1238. // strspn equivalent
  1239. inline CString CString::SpanIncluding(LPCTSTR lpszCharSet) const
  1240. {
  1241. ATLASSERT(AfxIsValidString(lpszCharSet, FALSE));
  1242. return Left(_tcsspn(m_pchData, lpszCharSet));
  1243. }
  1244. // strcspn equivalent
  1245. inline CString CString::SpanExcluding(LPCTSTR lpszCharSet) const
  1246. {
  1247. ATLASSERT(AfxIsValidString(lpszCharSet, FALSE));
  1248. return Left(_tcscspn(m_pchData, lpszCharSet));
  1249. }
  1250. inline int CString::ReverseFind(TCHAR ch) const
  1251. {
  1252. // find last single character
  1253. LPTSTR lpsz = _tcsrchr(m_pchData, (_TUCHAR)ch);
  1254. // return -1 if not found, distance from beginning otherwise
  1255. return (lpsz == NULL) ? -1 : (int)(lpsz - m_pchData);
  1256. }
  1257. // find a sub-string (like strstr)
  1258. inline int CString::Find(LPCTSTR lpszSub) const
  1259. {
  1260. ATLASSERT(AfxIsValidString(lpszSub, FALSE));
  1261. // find first matching substring
  1262. LPTSTR lpsz = _tcsstr(m_pchData, lpszSub);
  1263. // return -1 for not found, distance from beginning otherwise
  1264. return (lpsz == NULL) ? -1 : (int)(lpsz - m_pchData);
  1265. }
  1266. #define TCHAR_ARG TCHAR
  1267. #define WCHAR_ARG WCHAR
  1268. #define CHAR_ARG char
  1269. struct _AFX_DOUBLE { BYTE doubleBits[sizeof(double)]; };
  1270. #if defined(_X86_)
  1271. #define DOUBLE_ARG _AFX_DOUBLE
  1272. #else
  1273. #define DOUBLE_ARG double
  1274. #endif
  1275. #define FORCE_ANSI 0x10000
  1276. #define FORCE_UNICODE 0x20000
  1277. inline void CString::FormatV(LPCTSTR lpszFormat, va_list argList)
  1278. {
  1279. ATLASSERT(AfxIsValidString(lpszFormat, FALSE));
  1280. va_list argListSave = argList;
  1281. // make a guess at the maximum length of the resulting string
  1282. int nMaxLen = 0;
  1283. for (LPCTSTR lpsz = lpszFormat; *lpsz != '\0'; lpsz = _tcsinc(lpsz))
  1284. {
  1285. // handle '%' character, but watch out for '%%'
  1286. if (*lpsz != '%' || *(lpsz = _tcsinc(lpsz)) == '%')
  1287. {
  1288. nMaxLen += _tclen(lpsz);
  1289. continue;
  1290. }
  1291. int nItemLen = 0;
  1292. // handle '%' character with format
  1293. int nWidth = 0;
  1294. for (; *lpsz != '\0'; lpsz = _tcsinc(lpsz))
  1295. {
  1296. // check for valid flags
  1297. if (*lpsz == '#')
  1298. nMaxLen += 2; // for '0x'
  1299. else if (*lpsz == '*')
  1300. nWidth = va_arg(argList, int);
  1301. else if (*lpsz == '-' || *lpsz == '+' || *lpsz == '0' ||
  1302. *lpsz == ' ')
  1303. ;
  1304. else // hit non-flag character
  1305. break;
  1306. }
  1307. // get width and skip it
  1308. if (nWidth == 0)
  1309. {
  1310. // width indicated by
  1311. nWidth = _ttoi(lpsz);
  1312. for (; *lpsz != '\0' && _istdigit(*lpsz); lpsz = _tcsinc(lpsz))
  1313. ;
  1314. }
  1315. ATLASSERT(nWidth >= 0);
  1316. int nPrecision = 0;
  1317. if (*lpsz == '.')
  1318. {
  1319. // skip past '.' separator (width.precision)
  1320. lpsz = _tcsinc(lpsz);
  1321. // get precision and skip it
  1322. if (*lpsz == '*')
  1323. {
  1324. nPrecision = va_arg(argList, int);
  1325. lpsz = _tcsinc(lpsz);
  1326. }
  1327. else
  1328. {
  1329. nPrecision = _ttoi(lpsz);
  1330. for (; *lpsz != '\0' && _istdigit(*lpsz); lpsz = _tcsinc(lpsz))
  1331. ;
  1332. }
  1333. ATLASSERT(nPrecision >= 0);
  1334. }
  1335. // should be on type modifier or specifier
  1336. int nModifier = 0;
  1337. switch (*lpsz)
  1338. {
  1339. // modifiers that affect size
  1340. case 'h':
  1341. nModifier = FORCE_ANSI;
  1342. lpsz = _tcsinc(lpsz);
  1343. break;
  1344. case 'l':
  1345. nModifier = FORCE_UNICODE;
  1346. lpsz = _tcsinc(lpsz);
  1347. break;
  1348. // modifiers that do not affect size
  1349. case 'F':
  1350. case 'N':
  1351. case 'L':
  1352. lpsz = _tcsinc(lpsz);
  1353. break;
  1354. }
  1355. // now should be on specifier
  1356. switch (*lpsz | nModifier)
  1357. {
  1358. // single characters
  1359. case 'c':
  1360. case 'C':
  1361. nItemLen = 2;
  1362. va_arg(argList, TCHAR_ARG);
  1363. break;
  1364. case 'c'|FORCE_ANSI:
  1365. case 'C'|FORCE_ANSI:
  1366. nItemLen = 2;
  1367. va_arg(argList, CHAR_ARG);
  1368. break;
  1369. case 'c'|FORCE_UNICODE:
  1370. case 'C'|FORCE_UNICODE:
  1371. nItemLen = 2;
  1372. va_arg(argList, WCHAR_ARG);
  1373. break;
  1374. // strings
  1375. case 's':
  1376. {
  1377. LPCTSTR pstrNextArg = va_arg(argList, LPCTSTR);
  1378. if (pstrNextArg == NULL)
  1379. nItemLen = 6; // "(null)"
  1380. else
  1381. {
  1382. nItemLen = lstrlen(pstrNextArg);
  1383. nItemLen = max(1, nItemLen);
  1384. }
  1385. break;
  1386. }
  1387. case 'S':
  1388. {
  1389. #ifndef _UNICODE
  1390. LPWSTR pstrNextArg = va_arg(argList, LPWSTR);
  1391. if (pstrNextArg == NULL)
  1392. nItemLen = 6; // "(null)"
  1393. else
  1394. {
  1395. nItemLen = wcslen(pstrNextArg);
  1396. nItemLen = max(1, nItemLen);
  1397. }
  1398. #else
  1399. LPCSTR pstrNextArg = va_arg(argList, LPCSTR);
  1400. if (pstrNextArg == NULL)
  1401. nItemLen = 6; // "(null)"
  1402. else
  1403. {
  1404. nItemLen = lstrlenA(pstrNextArg);
  1405. nItemLen = max(1, nItemLen);
  1406. }
  1407. #endif
  1408. break;
  1409. }
  1410. case 's'|FORCE_ANSI:
  1411. case 'S'|FORCE_ANSI:
  1412. {
  1413. LPCSTR pstrNextArg = va_arg(argList, LPCSTR);
  1414. if (pstrNextArg == NULL)
  1415. nItemLen = 6; // "(null)"
  1416. else
  1417. {
  1418. nItemLen = lstrlenA(pstrNextArg);
  1419. nItemLen = max(1, nItemLen);
  1420. }
  1421. break;
  1422. }
  1423. case 's'|FORCE_UNICODE:
  1424. case 'S'|FORCE_UNICODE:
  1425. {
  1426. LPWSTR pstrNextArg = va_arg(argList, LPWSTR);
  1427. if (pstrNextArg == NULL)
  1428. nItemLen = 6; // "(null)"
  1429. else
  1430. {
  1431. nItemLen = wcslen(pstrNextArg);
  1432. nItemLen = max(1, nItemLen);
  1433. }
  1434. break;
  1435. }
  1436. }
  1437. // adjust nItemLen for strings
  1438. if (nItemLen != 0)
  1439. {
  1440. nItemLen = max(nItemLen, nWidth);
  1441. if (nPrecision != 0)
  1442. nItemLen = min(nItemLen, nPrecision);
  1443. }
  1444. else
  1445. {
  1446. switch (*lpsz)
  1447. {
  1448. // integers
  1449. case 'd':
  1450. case 'i':
  1451. case 'u':
  1452. case 'x':
  1453. case 'X':
  1454. case 'o':
  1455. va_arg(argList, int);
  1456. nItemLen = 32;
  1457. nItemLen = max(nItemLen, nWidth+nPrecision);
  1458. break;
  1459. case 'e':
  1460. case 'f':
  1461. case 'g':
  1462. case 'G':
  1463. va_arg(argList, DOUBLE_ARG);
  1464. nItemLen = 128;
  1465. nItemLen = max(nItemLen, nWidth+nPrecision);
  1466. break;
  1467. case 'p':
  1468. va_arg(argList, void*);
  1469. nItemLen = 32;
  1470. nItemLen = max(nItemLen, nWidth+nPrecision);
  1471. break;
  1472. // no output
  1473. case 'n':
  1474. va_arg(argList, int*);
  1475. break;
  1476. default:
  1477. ATLASSERT(FALSE); // unknown formatting option
  1478. }
  1479. }
  1480. // adjust nMaxLen for output nItemLen
  1481. nMaxLen += nItemLen;
  1482. }
  1483. GetBuffer(nMaxLen);
  1484. int nRet = _vstprintf(m_pchData, lpszFormat, argListSave);
  1485. nRet; // ref
  1486. ATLASSERT(nRet <= GetAllocLength());
  1487. ReleaseBuffer();
  1488. va_end(argListSave);
  1489. }
  1490. // formatting (using wsprintf style formatting)
  1491. inline void __cdecl CString::Format(LPCTSTR lpszFormat, ...)
  1492. {
  1493. ATLASSERT(AfxIsValidString(lpszFormat, FALSE));
  1494. va_list argList;
  1495. va_start(argList, lpszFormat);
  1496. FormatV(lpszFormat, argList);
  1497. va_end(argList);
  1498. }
  1499. inline void __cdecl CString::Format(UINT nFormatID, ...)
  1500. {
  1501. CString strFormat;
  1502. BOOL bRet = strFormat.LoadString(nFormatID);
  1503. bRet; // ref
  1504. ATLASSERT(bRet != 0);
  1505. va_list argList;
  1506. va_start(argList, nFormatID);
  1507. FormatV(strFormat, argList);
  1508. va_end(argList);
  1509. }
  1510. // formatting (using FormatMessage style formatting)
  1511. inline BOOL __cdecl CString::FormatMessage(LPCTSTR lpszFormat, ...)
  1512. {
  1513. // format message into temporary buffer lpszTemp
  1514. va_list argList;
  1515. va_start(argList, lpszFormat);
  1516. LPTSTR lpszTemp;
  1517. BOOL bRet = TRUE;
  1518. if (::FormatMessage(FORMAT_MESSAGE_FROM_STRING|FORMAT_MESSAGE_ALLOCATE_BUFFER,
  1519. lpszFormat, 0, 0, (LPTSTR)&lpszTemp, 0, &argList) == 0 ||
  1520. lpszTemp == NULL)
  1521. bRet = FALSE;
  1522. // assign lpszTemp into the resulting string and free the temporary
  1523. *this = lpszTemp;
  1524. LocalFree(lpszTemp);
  1525. va_end(argList);
  1526. return bRet;
  1527. }
  1528. inline BOOL __cdecl CString::FormatMessage(UINT nFormatID, ...)
  1529. {
  1530. // get format string from string table
  1531. CString strFormat;
  1532. BOOL bRetTmp = strFormat.LoadString(nFormatID);
  1533. bRetTmp; // ref
  1534. ATLASSERT(bRetTmp != 0);
  1535. // format message into temporary buffer lpszTemp
  1536. va_list argList;
  1537. va_start(argList, nFormatID);
  1538. LPTSTR lpszTemp;
  1539. BOOL bRet = TRUE;
  1540. if (::FormatMessage(FORMAT_MESSAGE_FROM_STRING|FORMAT_MESSAGE_ALLOCATE_BUFFER,
  1541. strFormat, 0, 0, (LPTSTR)&lpszTemp, 0, &argList) == 0 ||
  1542. lpszTemp == NULL)
  1543. bRet = FALSE;
  1544. // assign lpszTemp into the resulting string and free lpszTemp
  1545. *this = lpszTemp;
  1546. LocalFree(lpszTemp);
  1547. va_end(argList);
  1548. return bRet;
  1549. }
  1550. inline void CString::TrimRight()
  1551. {
  1552. CopyBeforeWrite();
  1553. // find beginning of trailing spaces by starting at beginning (DBCS aware)
  1554. LPTSTR lpsz = m_pchData;
  1555. LPTSTR lpszLast = NULL;
  1556. while (*lpsz != '\0')
  1557. {
  1558. if (_istspace(*lpsz))
  1559. {
  1560. if (lpszLast == NULL)
  1561. lpszLast = lpsz;
  1562. }
  1563. else
  1564. lpszLast = NULL;
  1565. lpsz = _tcsinc(lpsz);
  1566. }
  1567. if (lpszLast != NULL)
  1568. {
  1569. // truncate at trailing space start
  1570. *lpszLast = '\0';
  1571. GetData()->nDataLength = (int)(lpszLast - m_pchData);
  1572. }
  1573. }
  1574. inline void CString::TrimLeft()
  1575. {
  1576. CopyBeforeWrite();
  1577. // find first non-space character
  1578. LPCTSTR lpsz = m_pchData;
  1579. while (_istspace(*lpsz))
  1580. lpsz = _tcsinc(lpsz);
  1581. // fix up data and length
  1582. int nDataLength = GetData()->nDataLength - (int)(lpsz - m_pchData);
  1583. memmove(m_pchData, lpsz, (nDataLength+1)*sizeof(TCHAR));
  1584. GetData()->nDataLength = nDataLength;
  1585. }
  1586. #ifdef _UNICODE
  1587. #define CHAR_FUDGE 1 // one TCHAR unused is good enough
  1588. #else
  1589. #define CHAR_FUDGE 2 // two BYTES unused for case of DBC last char
  1590. #endif
  1591. inline BOOL CString::LoadString(UINT nID)
  1592. {
  1593. // try fixed buffer first (to avoid wasting space in the heap)
  1594. TCHAR szTemp[256];
  1595. int nCount = sizeof(szTemp) / sizeof(szTemp[0]);
  1596. int nLen = AfxLoadString(nID, szTemp, nCount);
  1597. if (nCount - nLen > CHAR_FUDGE)
  1598. {
  1599. *this = szTemp;
  1600. return nLen > 0;
  1601. }
  1602. // try buffer size of 512, then larger size until entire string is retrieved
  1603. int nSize = 256;
  1604. do
  1605. {
  1606. nSize += 256;
  1607. nLen = AfxLoadString(nID, GetBuffer(nSize-1), nSize);
  1608. } while (nSize - nLen <= CHAR_FUDGE);
  1609. ReleaseBuffer();
  1610. return nLen > 0;
  1611. }
  1612. inline int __stdcall AfxLoadString(UINT nID, LPTSTR lpszBuf, UINT nMaxBuf)
  1613. {
  1614. ATLASSERT(AfxIsValidAddress(lpszBuf, nMaxBuf*sizeof(TCHAR)));
  1615. #ifdef _DEBUG
  1616. // LoadString without annoying warning from the Debug kernel if the
  1617. // segment containing the string is not present
  1618. if (::FindResource(_Module.GetResourceInstance(),
  1619. MAKEINTRESOURCE((nID>>4)+1), RT_STRING) == NULL)
  1620. {
  1621. lpszBuf[0] = '\0';
  1622. return 0; // not found
  1623. }
  1624. #endif //_DEBUG
  1625. int nLen = ::LoadString(_Module.GetResourceInstance(), nID, lpszBuf, nMaxBuf);
  1626. if (nLen == 0)
  1627. lpszBuf[0] = '\0';
  1628. return nLen;
  1629. }
  1630. #ifndef _ATL_NO_COM
  1631. inline BSTR CString::AllocSysString() const
  1632. {
  1633. #if defined(_UNICODE) || defined(OLE2ANSI)
  1634. BSTR bstr = ::SysAllocStringLen(m_pchData, GetData()->nDataLength);
  1635. #else
  1636. int nLen = MultiByteToWideChar(CP_ACP, 0, m_pchData,
  1637. GetData()->nDataLength, NULL, NULL);
  1638. BSTR bstr = ::SysAllocStringLen(NULL, nLen);
  1639. if(bstr != NULL)
  1640. MultiByteToWideChar(CP_ACP, 0, m_pchData, GetData()->nDataLength, bstr, nLen);
  1641. #endif
  1642. return bstr;
  1643. }
  1644. inline BSTR CString::SetSysString(BSTR* pbstr) const
  1645. {
  1646. ATLASSERT(AfxIsValidAddress(pbstr, sizeof(BSTR)));
  1647. #if defined(_UNICODE) || defined(OLE2ANSI)
  1648. ::SysReAllocStringLen(pbstr, m_pchData, GetData()->nDataLength);
  1649. #else
  1650. int nLen = MultiByteToWideChar(CP_ACP, 0, m_pchData,
  1651. GetData()->nDataLength, NULL, NULL);
  1652. if(::SysReAllocStringLen(pbstr, NULL, nLen))
  1653. MultiByteToWideChar(CP_ACP, 0, m_pchData, GetData()->nDataLength, *pbstr, nLen);
  1654. #endif
  1655. ATLASSERT(*pbstr != NULL);
  1656. return *pbstr;
  1657. }
  1658. #endif //!_ATL_NO_COM
  1659. #endif //!_ATL_TMP_NO_CSTRING
  1660. }; //namespace ATL
  1661. #endif // __ATLTMP_H__
  1662. /////////////////////////////////////////////////////////////////////////////