StdString.h
上传用户:lswyart
上传日期:2008-06-12
资源大小:3441k
文件大小:87k
源码类别:

杀毒

开发平台:

Visual C++

  1. /*-----------------------------------------------------------------------------
  2. # Name:        StdString.h
  3. # Product:     ClamWin Antivirus
  4. # Licence:     
  5. #   This program is free software; you can redistribute it and/or modify
  6. #   it under the terms of the GNU General Public License as published by
  7. #   the Free Software Foundation; either version 2 of the License, or
  8. #   (at your option) any later version.
  9. #   This program is distributed in the hope that it will be useful,
  10. #   but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. #   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12. #   GNU General Public License for more details.
  13. #   You should have received a copy of the GNU General Public License
  14. #   along with this program; if not, write to the Free Software
  15. #   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  16. #-----------------------------------------------------------------------------
  17. */
  18. // =============================================================================
  19. //  FILE:  StdString.h
  20. //  AUTHOR: Joe O'Leary (with outside help noted in comments)
  21. //  REMARKS:
  22. // This header file declares the CStdStr template.  This template derives
  23. // the Standard C++ Library basic_string<> template and add to it the
  24. // the following conveniences:
  25. // - The full MFC CString set of functions (including implicit cast)
  26. // - writing to/reading from COM IStream interfaces
  27. // - Functional objects for use in STL algorithms
  28. //
  29. // From this template, we intstantiate two classes:  CStdStringA and
  30. // CStdStringW.  The name "CStdString" is just a #define of one of these,
  31. // based upone the _UNICODE macro setting
  32. //
  33. // This header also declares our own version of the MFC/ATL UNICODE-MBCS
  34. // conversion macros.  Our version looks exactly like the Microsoft's to
  35. // facilitate portability.
  36. //
  37. // NOTE:
  38. // If you you use this in an MFC or ATL build, you should include either
  39. // afx.h or atlbase.h first, as appropriate.
  40. //
  41. // PEOPLE WHO HAVE CONTRIBUTED TO THIS CLASS:
  42. //
  43. // Several people have helped me iron out problems and othewise improve
  44. // this class.  OK, this is a long list but in my own defense, this code
  45. // has undergone two major rewrites.  Many of the improvements became
  46. // necessary after I rewrote the code as a template.  Others helped me
  47. // improve the CString facade.
  48. //
  49. // Anyway, these people are (in chronological order):
  50. //
  51. // - Pete the Plumber (???)
  52. // - Julian Selman
  53. // - Chris (of Melbsys)
  54. // - Dave Plummer
  55. // - John C Sipos
  56. // - Chris Sells
  57. // - Nigel Nunn
  58. // - Fan Xia
  59. // - Matthew Williams
  60. // - Carl Engman
  61. // - Mark Zeren
  62. // - Craig Watson
  63. // - Rich Zuris
  64. // - Karim Ratib
  65. // - Chris Conti
  66. // - Baptiste Lepilleur
  67. // - Greg Pickles
  68. // - Jim Cline
  69. // - Jeff Kohn
  70. // - Todd Heckel
  71. // - Ullrich Poll鋒ne
  72. // - Joe Vitaterna
  73. // - Joe Woodbury
  74. // - Aaron (no last name)
  75. // - Joldakowski (???)
  76. // - Scott Hathaway
  77. // - Eric Nitzche
  78. // - Pablo Presedo
  79. //
  80. // REVISION HISTORY
  81. //   2001-APR-27 - StreamLoad was calculating the number of BYTES in one
  82. // case, not characters.  Thanks to Pablo Presedo for this.
  83. //
  84. //    2001-FEB-23 - Replace() had a bug which caused infinite loops if the
  85. // source string was empty.  Fixed thanks to Eric Nitzsche.
  86. //
  87. //    2001-FEB-23 - Scott Hathaway was a huge help in providing me with the
  88. // ability to build CStdString on Sun Unix systems.  He
  89. // sent me detailed build reports about what works and what
  90. // does not.  If CStdString compiles on your Unix box, you
  91. // can thank Scott for it.
  92. //
  93. //   2000-DEC-29 - Joldakowski noticed one overload of Insert failed to do
  94. // range check as CString's does.  Now fixed -- thanks!
  95. //
  96. //   2000-NOV-07 - Aaron pointed out that I was calling static member
  97. // functions of char_traits via a temporary.  This was not
  98. // technically wrong, but it was unnecessary and caused
  99. // problems for poor old buggy VC5.  Thanks Aaron!
  100. //
  101. //   2000-JUL-11 - Joe Woodbury noted that the CString::Find docs don't match
  102. // what the CString::Find code really ends up doing.   I was
  103. // trying to match the docs.  Now I match the CString code
  104. //   - Joe also caught me truncating strings for GetBuffer() calls
  105. // when the supplied length was less than the current length.
  106. //
  107. //   2000-MAY-25 - Better support for STLPORT's Standard library distribution
  108. //   - Got rid of the NSP macro - it interfered with Koenig lookup
  109. //   - Thanks to Joe Woodbury for catching a TrimLeft() bug that
  110. // I introduced in January.  Empty strings were not getting
  111. // trimmed
  112. //
  113. //   2000-APR-17 - Thanks to Joe Vitaterna for pointing out that ReverseFind
  114. // is supposed to be a const function.
  115. //
  116. //   2000-MAR-07 - Thanks to Ullrich Poll鋒ne for catching a range bug in one
  117. // of the overloads of assign.
  118. //
  119. //    2000-FEB-01 - You can now use CStdString on the Mac with CodeWarrior!
  120. // Thanks to Todd Heckel for helping out with this.
  121. //
  122. //   2000-JAN-23 - Thanks to Jim Cline for pointing out how I could make the
  123. // Trim() function more efficient.
  124. //   - Thanks to Jeff Kohn for prompting me to find and fix a typo
  125. // in one of the addition operators that takes _bstr_t.
  126. //   - Got rid of the .CPP file -  you only need StdString.h now!
  127. //
  128. //   1999-DEC-22 - Thanks to Greg Pickles for helping me identify a problem
  129. // with my implementation of CStdString::FormatV in which
  130. // resulting string might not be properly NULL terminated.
  131. //
  132. //   1999-DEC-06 - Chris Conti pointed yet another basic_string<> assignment
  133. // bug that MS has not fixed.  CStdString did nothing to fix
  134. // it either but it does now!  The bug was: create a string
  135. // longer than 31 characters, get a pointer to it (via c_str())
  136. // and then assign that pointer to the original string object.
  137. // The resulting string would be empty.  Not with CStdString!
  138. //
  139. //   1999-OCT-06 - BufferSet was erasing the string even when it was merely
  140. // supposed to shrink it.  Fixed.  Thanks to Chris Conti.
  141. //   - Some of the Q172398 fixes were not checking for assignment-
  142. // to-self.  Fixed.  Thanks to Baptiste Lepilleur.
  143. //
  144. //   1999-AUG-20 - Improved Load() function to be more efficient by using 
  145. // SizeOfResource().  Thanks to Rich Zuris for this.
  146. //   - Corrected resource ID constructor, again thanks to Rich.
  147. //   - Fixed a bug that occurred with UNICODE characters above
  148. // the first 255 ANSI ones.  Thanks to Craig Watson. 
  149. //   - Added missing overloads of TrimLeft() and TrimRight().
  150. // Thanks to Karim Ratib for pointing them out
  151. //
  152. //   1999-JUL-21 - Made all calls to GetBuf() with no args check length first.
  153. //
  154. //   1999-JUL-10 - Improved MFC/ATL independence of conversion macros
  155. //   - Added SS_NO_REFCOUNT macro to allow you to disable any
  156. // reference-counting your basic_string<> impl. may do.
  157. //   - Improved ReleaseBuffer() to be as forgiving as CString.
  158. // Thanks for Fan Xia for helping me find this and to
  159. // Matthew Williams for pointing it out directly.
  160. //
  161. //   1999-JUL-06 - Thanks to Nigel Nunn for catching a very sneaky bug in
  162. // ToLower/ToUpper.  They should call GetBuf() instead of
  163. // data() in order to ensure the changed string buffer is not
  164. // reference-counted (in those implementations that refcount).
  165. //
  166. //   1999-JUL-01 - Added a true CString facade.  Now you can use CStdString as
  167. // a drop-in replacement for CString.  If you find this useful,
  168. // you can thank Chris Sells for finally convincing me to give
  169. // in and implement it.
  170. //   - Changed operators << and >> (for MFC CArchive) to serialize
  171. // EXACTLY as CString's do.  So now you can send a CString out
  172. // to a CArchive and later read it in as a CStdString.   I have
  173. // no idea why you would want to do this but you can. 
  174. //
  175. //   1999-JUN-21 - Changed the CStdString class into the CStdStr template.
  176. //   - Fixed FormatV() to correctly decrement the loop counter.
  177. // This was harmless bug but a bug nevertheless.  Thanks to
  178. // Chris (of Melbsys) for pointing it out
  179. //   - Changed Format() to try a normal stack-based array before
  180. // using to _alloca().
  181. //   - Updated the text conversion macros to properly use code
  182. // pages and to fit in better in MFC/ATL builds.  In other
  183. // words, I copied Microsoft's conversion stuff again. 
  184. //   - Added equivalents of CString::GetBuffer, GetBufferSetLength
  185. //   - new sscpy() replacement of CStdString::CopyString()
  186. //   - a Trim() function that combines TrimRight() and TrimLeft().
  187. //
  188. //   1999-MAR-13 - Corrected the "NotSpace" functional object to use _istpace()
  189. // instead of _isspace()   Thanks to Dave Plummer for this.
  190. //
  191. //   1999-FEB-26 - Removed errant line (left over from testing) that #defined
  192. // _MFC_VER.  Thanks to John C Sipos for noticing this.
  193. //
  194. //   1999-FEB-03 - Fixed a bug in a rarely-used overload of operator+() that
  195. // caused infinite recursion and stack overflow
  196. //   - Added member functions to simplify the process of
  197. // persisting CStdStrings to/from DCOM IStream interfaces 
  198. //   - Added functional objects (e.g. StdStringLessNoCase) that
  199. // allow CStdStrings to be used as keys STL map objects with
  200. // case-insensitive comparison 
  201. //   - Added array indexing operators (i.e. operator[]).  I
  202. // originally assumed that these were unnecessary and would be
  203. // inherited from basic_string.  However, without them, Visual
  204. // C++ complains about ambiguous overloads when you try to use
  205. // them.  Thanks to Julian Selman to pointing this out. 
  206. //
  207. //   1998-FEB-?? - Added overloads of assign() function to completely account
  208. // for Q172398 bug.  Thanks to "Pete the Plumber" for this
  209. //
  210. //   1998-FEB-?? - Initial submission
  211. //
  212. // COPYRIGHT:
  213. // 1999 Joseph M. O'Leary.  This code is free.  Use it anywhere you want.
  214. // Rewrite it, restructure it, whatever.  Please don't blame me if it makes
  215. // your $30 billion dollar satellite explode in orbit.  If you redistribute
  216. // it in any form, I'd appreciate it if you would leave this notice here.
  217. //
  218. // If you find any bugs, please let me know:
  219. //
  220. // jmoleary@earthlink.net
  221. // http://home.earthlink.net/~jmoleary
  222. // =============================================================================
  223. // Avoid multiple inclusion the VC++ way,
  224. // Turn off browser references
  225. // Turn off unavoidable compiler warnings
  226. #if defined(_MSC_VER) && (_MSC_VER > 1100)
  227. #pragma once
  228. #pragma component(browser, off, references, "CStdString")
  229. #pragma warning (disable : 4290) // C++ Exception Specification ignored
  230. #pragma warning (disable : 4127) // Conditional expression is constant
  231. #pragma warning (disable : 4097) // typedef name used as synonym for class name
  232. #endif
  233. #ifndef STDSTRING_H
  234. #define STDSTRING_H
  235. // MACRO: SS_NO_REFCOUNT:
  236. // turns off reference counting at the assignment level
  237. // I define this by default.  comment it out if you don't want it.
  238. #define SS_NO_REFCOUNT
  239. // In non-Visual C++ and/or non-Win32 builds, we can't use some cool stuff.
  240. #if !defined(_MSC_VER) || !defined(_WIN32)
  241. #define SS_ANSI
  242. #endif
  243. // Avoid legacy code screw up: if _UNICODE is defined, UNICODE must be as well
  244. #if defined (_UNICODE) && !defined (UNICODE)
  245. #define UNICODE
  246. #endif
  247. #if defined (UNICODE) && !defined (_UNICODE)
  248. #define _UNICODE
  249. #endif
  250. // -----------------------------------------------------------------------------
  251. // MIN and MAX.  The Standard C++ template versions go by so many names (at
  252. // at least in the MS implementation) that you never know what's available 
  253. // -----------------------------------------------------------------------------
  254. template<class Type>
  255. inline const Type& SSMIN(const Type& arg1, const Type& arg2)
  256. {
  257. return arg2 < arg1 ? arg2 : arg1;
  258. }
  259. template<class Type>
  260. inline const Type& SSMAX(const Type& arg1, const Type& arg2)
  261. {
  262. return arg2 > arg1 ? arg2 : arg1;
  263. }
  264. // If they have not #included W32Base.h (part of my W32 utility library) then
  265. // we need to define some stuff.  Otherwise, this is all defined there.
  266. #if !defined(W32BASE_H)
  267. // If they want us to use only standard C++ stuff (no Win32 stuff)
  268. #ifdef SS_ANSI
  269. // On non-Win32 platforms, there is no TCHAR.H so define what we need
  270. #ifndef _WIN32
  271. typedef const char* PCSTR;
  272. typedef char* PSTR;
  273. typedef const wchar_t* PCWSTR;
  274. typedef wchar_t* PWSTR;
  275. #ifdef UNICODE
  276. typedef wchar_t TCHAR;
  277. #else
  278. typedef char TCHAR;
  279. #endif
  280. typedef wchar_t OLECHAR;
  281. #else
  282. #include <TCHAR.H>
  283. #include <WTYPES.H>
  284. #ifndef STRICT
  285. #define STRICT
  286. #endif
  287. #endif // #ifndef _WIN32
  288. // Make sure ASSERT and verify are defined in an ANSI fashion
  289. #ifndef ASSERT
  290. #include <assert.h>
  291. #define ASSERT(f) assert((f))
  292. #endif
  293. #ifndef VERIFY
  294. #ifdef _DEBUG
  295. #define VERIFY(x) ASSERT((x))
  296. #else
  297. #define VERIFY(x) x
  298. #endif
  299. #endif
  300. #else // #ifdef SS_ANSI
  301. #include <TCHAR.H>
  302. #include <WTYPES.H>
  303. #ifndef STRICT
  304. #define STRICT
  305. #endif
  306. // Make sure ASSERT and verify are defined
  307. #ifndef ASSERT
  308. #include <crtdbg.h>
  309. #define ASSERT(f) _ASSERTE((f))
  310. #endif
  311. #ifndef VERIFY
  312. #ifdef _DEBUG
  313. #define VERIFY(x) ASSERT((x))
  314. #else
  315. #define VERIFY(x) x
  316. #endif
  317. #endif
  318. #endif // #ifdef SS_ANSI
  319. #ifndef UNUSED
  320. #define UNUSED(x) x
  321. #endif
  322. #endif // #ifndef W32BASE_H
  323. // Standard headers needed
  324. #include <string> // basic_string
  325. #include <algorithm> // for_each, etc.
  326. #include <functional> // for StdStringLessNoCase, et al
  327. #include <locale> // for various facets
  328. // If this is a recent enough version of VC include comdef.h, so we can write
  329. // member functions to deal with COM types & compiler support classes e.g. _bstr_t
  330. #if defined (_INCLUDE_COMDEF) && (_MSC_VER) && (_MSC_VER >= 1100)
  331. #include <comdef.h>
  332. #define SS_INC_COMDEF // signal that we #included MS comdef.h file
  333. #define STDSTRING_INC_COMDEF
  334. #define SS_NOTHROW __declspec(nothrow)
  335. #else
  336. #define SS_NOTHROW
  337. #endif
  338. #ifndef TRACE
  339. #define TRACE_DEFINED_HERE
  340. #define TRACE
  341. #endif
  342. // Microsoft defines PCSTR, PCWSTR, etc, but no PCTSTR.  I hate to use the
  343. // versions with the "L" in front of them because that's a leftover from Win 16
  344. // days, even though it evaluates to the same thing.  Therefore, Define a PCSTR
  345. // as an LPCTSTR.
  346. #if !defined(PCTSTR) && !defined(PCTSTR_DEFINED)
  347. typedef const TCHAR* PCTSTR;
  348. #define PCTSTR_DEFINED
  349. #endif
  350. #if !defined(PCOLESTR) && !defined(PCOLESTR_DEFINED)
  351. typedef const OLECHAR* PCOLESTR;
  352. #define PCOLESTR_DEFINED
  353. #endif
  354. #if !defined(POLESTR) && !defined(POLESTR_DEFINED)
  355. typedef OLECHAR* POLESTR;
  356. #define POLESTR_DEFINED
  357. #endif
  358. #if !defined(PCUSTR) && !defined(PCUSTR_DEFINED)
  359. typedef const unsigned char* PCUSTR;
  360. typedef unsigned char* PUSTR;
  361. #define PCUSTR_DEFINED
  362. #endif
  363. // SS_USE_FACET macro and why we need it:
  364. //
  365. // Since I'm a good little Standard C++ programmer, I use locales.  Thus, I
  366. // need to make use of the use_facet<> template function here.   Unfortunately,
  367. // this need is complicated by the fact the MS' implementation of the Standard
  368. // C++ Library has a non-standard version of use_facet that takes more
  369. // arguments than the standard dictates.  Since I'm trying to write CStdString
  370. // to work with any version of the Standard library, this presents a problem.
  371. //
  372. // The upshot of this is that I can't do 'use_facet' directly.  The MS' docs
  373. // tell me that I have to use a macro, _USE() instead.  Since _USE obviously
  374. // won't be available in other implementations, this means that I have to write
  375. // my OWN macro -- SS_USE_FACET -- that evaluates either to _USE or to the
  376. // standard, use_facet.
  377. //
  378. // If you are having trouble with the SS_USE_FACET macro, in your implementation
  379. // of the Standard C++ Library, you can define your own version of SS_USE_FACET.
  380. #ifndef schMSG
  381. #define schSTR(x)    #x
  382. #define schSTR2(x) schSTR(x)
  383. #define schMSG(desc) message(__FILE__ "(" schSTR2(__LINE__) "):" #desc)
  384. #endif
  385. #ifndef SS_USE_FACET
  386. // STLPort #defines a macro (__STL_NO_EXPLICIT_FUNCTION_TMPL_ARGS) for
  387. // all MSVC builds, erroneously in my opinion.  It causes problems for
  388. // my SS_ANSI builds.  In my code, I always comment out that line.  You'll
  389. // find it in   stlportconfigstl_msvc.h
  390. #if defined(__SGI_STL_PORT) && (__SGI_STL_PORT >= 0x400 )
  391. #if defined(__STL_NO_EXPLICIT_FUNCTION_TMPL_ARGS) && defined(_MSC_VER)
  392. #ifdef SS_ANSI
  393. #pragma schMSG(__STL_NO_EXPLICIT_FUNCTION_TMPL_ARGS defined!!)
  394. #endif
  395. #endif
  396. #define SS_USE_FACET(loc, fac) std::use_facet<fac >(loc)
  397. #elif defined(_MSC_VER )
  398. #define SS_USE_FACET(loc, fac) _USE(loc, fac)
  399. // ...and
  400. #elif defined(_RWSTD_NO_TEMPLATE_ON_RETURN_TYPE)
  401.         #define SS_USE_FACET(loc, fac) std::use_facet(loc, (fac*)0)
  402. #else
  403. #define SS_USE_FACET(loc, fac) std::use_facet<fac >(loc)
  404. #endif
  405. #endif
  406. // =============================================================================
  407. // UNICODE/MBCS conversion macros.  Made to work just like the MFC/ATL ones.
  408. // =============================================================================
  409. // First define the conversion helper functions.  We define these regardless of
  410. // any preprocessor macro settings since their names won't collide. 
  411. #ifdef SS_ANSI // Are we doing things the standard, non-Win32 way?...
  412. typedef std::codecvt<wchar_t, char, mbstate_t> SSCodeCvt;
  413. // Not sure if we need all these headers.   I believe ANSI says we do.
  414. #include <stdio.h>
  415. #include <stdarg.h>
  416. #include <wchar.h>
  417. #ifndef va_start
  418. #include <varargs.h>
  419. #endif
  420. // StdCodeCvt - made to look like Win32 functions WideCharToMultiByte annd
  421. //              MultiByteToWideChar but uses locales in SS_ANSI builds
  422. inline PWSTR StdCodeCvt(PWSTR pW, PCSTR pA, int nChars,
  423. const std::locale& loc=std::locale())
  424. {
  425. ASSERT(0 != pA);
  426. ASSERT(0 != pW);
  427. pW[0] = '';
  428. PCSTR pBadA = 0;
  429. PWSTR pBadW = 0;
  430. SSCodeCvt::result res = SSCodeCvt::ok;
  431. const SSCodeCvt& conv = SS_USE_FACET(loc, SSCodeCvt);
  432.         SSCodeCvt::state_type st= { 0 };
  433. res = conv.in(st,
  434.   pA, pA + nChars, pBadA,
  435.   pW, pW + nChars, pBadW);
  436. ASSERT(SSCodeCvt::ok == res);
  437. return pW;
  438. }
  439. inline PWSTR StdCodeCvt(PWSTR pW, PCUSTR pA, int nChars,
  440. const std::locale& loc=std::locale())
  441. {
  442. return StdCodeCvt(pW, (PCSTR)pA, nChars, loc);
  443. }
  444. inline PSTR StdCodeCvt(PSTR pA, PCWSTR pW, int nChars,
  445. const std::locale& loc=std::locale())
  446. {
  447. ASSERT(0 != pA);
  448. ASSERT(0 != pW);
  449. pA[0] = '';
  450. PSTR pBadA = 0;
  451. PCWSTR pBadW = 0;
  452. SSCodeCvt::result res = SSCodeCvt::ok;
  453. const SSCodeCvt& conv = SS_USE_FACET(loc, SSCodeCvt);
  454.         SSCodeCvt::state_type st= { 0 };
  455. res = conv.out(st,
  456.    pW, pW + nChars, pBadW,
  457.    pA, pA + nChars, pBadA);
  458. ASSERT(SSCodeCvt::ok == res);
  459. return pA;
  460. }
  461. inline PUSTR StdCodeCvt(PUSTR pA, PCWSTR pW, int nChars,
  462. const std::locale& loc=std::locale())
  463. {
  464. return (PUSTR)StdCodeCvt((PSTR)pA, pW, nChars, loc);
  465. }
  466. #else   // ...or are we doing things assuming win32 and Visual C++?
  467. #include <malloc.h> // needed for _alloca
  468. inline PWSTR StdCodeCvt(PWSTR pW, PCSTR pA, int nChars, UINT acp=CP_ACP)
  469. {
  470. ASSERT(0 != pA);
  471. ASSERT(0 != pW);
  472. pW[0] = '';
  473. MultiByteToWideChar(acp, 0, pA, -1, pW, nChars);
  474. return pW;
  475. }
  476. inline PWSTR StdCodeCvt(PWSTR pW, PCUSTR pA, int nChars, UINT acp=CP_ACP)
  477. {
  478. return StdCodeCvt(pW, (PCSTR)pA, nChars, acp);
  479. }
  480. inline PSTR StdCodeCvt(PSTR pA, PCWSTR pW, int nChars, UINT acp=CP_ACP)
  481. {
  482. ASSERT(0 != pA);
  483. ASSERT(0 != pW);
  484. pA[0] = '';
  485. WideCharToMultiByte(acp, 0, pW, -1, pA, nChars, 0, 0);
  486. return pA;
  487. }
  488. inline PUSTR StdCodeCvt(PUSTR pA, PCWSTR pW, int nChars, UINT acp=CP_ACP)
  489. {
  490. return (PUSTR)StdCodeCvt((PSTR)pA, pW, nChars, acp);
  491. }
  492. // Define our conversion macros to look exactly like Microsoft's to
  493. // facilitate using this stuff both with and without MFC/ATL
  494. #ifdef _CONVERSION_USES_THREAD_LOCALE
  495. #ifndef _DEBUG
  496. #define SSCVT int _cvt; _cvt; UINT _acp=GetACP(); 
  497. _acp; PCWSTR _pw; _pw; PCSTR _pa; _pa
  498. #else
  499. #define SSCVT int _cvt = 0; _cvt; UINT _acp=GetACP();
  500.  _acp; PCWSTR _pw=0; _pw; PCSTR _pa=0; _pa
  501. #endif
  502. #else
  503. #ifndef _DEBUG
  504. #define SSCVT int _cvt; _cvt; UINT _acp=CP_ACP; _acp;
  505.  PCWSTR _pw; _pw; PCSTR _pa; _pa
  506. #else
  507. #define SSCVT int _cvt = 0; _cvt; UINT _acp=CP_ACP; 
  508. _acp; PCWSTR _pw=0; _pw; PCSTR _pa=0; _pa
  509. #endif
  510. #endif
  511. #ifdef _CONVERSION_USES_THREAD_LOCALE
  512. #define SSA2W(pa) (
  513. ((_pa = pa) == 0) ? 0 : (
  514. _cvt = (strlen(_pa)+1),
  515. StdCodeCvt((PWSTR) _alloca(_cvt*2), _pa, _cvt, _acp)))
  516. #define SSW2A(pw) (
  517. ((_pw = pw) == 0) ? 0 : (
  518. _cvt = (wcslen(_pw)+1)*2,
  519. StdW2AHelper((LPSTR) _alloca(_cvt), _pw, _cvt, _acp)))
  520. #else
  521. #define SSA2W(pa) (
  522. ((_pa = pa) == 0) ? 0 : (
  523. _cvt = (strlen(_pa)+1),
  524. StdCodeCvt((PWSTR) _alloca(_cvt*2), _pa, _cvt)))
  525. #define SSW2A(pw) (
  526. ((_pw = pw) == 0) ? 0 : (
  527. _cvt = (wcslen(_pw)+1)*2,
  528. StdCodeCvt((LPSTR) _alloca(_cvt), _pw, _cvt)))
  529. #endif
  530. #define SSA2CW(pa) ((PCWSTR)SSA2W((pa)))
  531. #define SSW2CA(pw) ((PCSTR)SSW2A((pw)))
  532. #ifdef UNICODE
  533. #define SST2A SSW2A
  534. #define SSA2T SSA2W
  535. #define SST2CA SSW2CA
  536. #define SSA2CT SSA2CW
  537. inline PWSTR SST2W(PTSTR p) { return p; }
  538. inline PTSTR SSW2T(PWSTR p) { return p; }
  539. inline PCWSTR SST2CW(PCTSTR p) { return p; }
  540. inline PCTSTR SSW2CT(PCWSTR p) { return p; }
  541. #else
  542. #define SST2W SSA2W
  543. #define SSW2T SSW2A
  544. #define SST2CW SSA2CW
  545. #define SSW2CT SSW2CA
  546. inline PSTR SST2A(PTSTR p) { return p; }
  547. inline PTSTR SSA2T(PSTR p) { return p; }
  548. inline PCSTR SST2CA(PCTSTR p) { return p; }
  549. inline PCTSTR SSA2CT(PCSTR p) { return p; }
  550. #endif // #ifdef UNICODE
  551. #if defined(UNICODE)
  552. // in these cases the default (TCHAR) is the same as OLECHAR
  553. inline PCOLESTR SST2COLE(PCTSTR p) { return p; }
  554. inline PCTSTR SSOLE2CT(PCOLESTR p) { return p; }
  555. inline POLESTR SST2OLE(PTSTR p) { return p; }
  556. inline PTSTR SSOLE2T(POLESTR p) { return p; }
  557. #elif defined(OLE2ANSI)
  558. // in these cases the default (TCHAR) is the same as OLECHAR
  559. inline PCOLESTR SST2COLE(PCTSTR p) { return p; }
  560. inline PCTSTR SSOLE2CT(PCOLESTR p) { return p; }
  561. inline POLESTR SST2OLE(PTSTR p) { return p; }
  562. inline PTSTR SSOLE2T(POLESTR p) { return p; }
  563. #else
  564. //CharNextW doesn't work on Win95 so we use this
  565. #define SST2COLE(pa) SSA2CW((pa))
  566. #define SST2OLE(pa) SSA2W((pa))
  567. #define SSOLE2CT(po) SSW2CA((po))
  568. #define SSOLE2T(po) SSW2A((po))
  569. #endif
  570. #ifdef OLE2ANSI
  571. #define SSW2OLE SSW2A
  572. #define SSOLE2W SSA2W
  573. #define SSW2COLE SSW2CA
  574. #define SSOLE2CW SSA2CW
  575. inline POLESTR SSA2OLE(PSTR p) { return p; }
  576. inline PSTR SSOLE2A(POLESTR p) { return p; }
  577. inline PCOLESTR SSA2COLE(PCSTR p) { return p; }
  578. inline PCSTR SSOLE2CA(PCOLESTR p){ return p; }
  579. #else
  580. #define SSA2OLE SSA2W
  581. #define SSOLE2A SSW2A
  582. #define SSA2COLE SSA2CW
  583. #define SSOLE2CA SSW2CA
  584. inline POLESTR SSW2OLE(PWSTR p) { return p; }
  585. inline PWSTR SSOLE2W(POLESTR p) { return p; }
  586. inline PCOLESTR SSW2COLE(PCWSTR p) { return p; }
  587. inline PCWSTR SSOLE2CW(PCOLESTR p){ return p; }
  588. #endif
  589. // Above we've defined macros that look like MS' but all have
  590. // an 'SS' prefix.  Now we need the real macros.  We'll either
  591. // get them from the macros above or from MFC/ATL.  If
  592. // SS_NO_CONVERSION is #defined, we'll forgo them
  593. #ifndef SS_NO_CONVERSION
  594. #if defined (USES_CONVERSION)
  595. #define _NO_STDCONVERSION // just to be consistent
  596. #else
  597. #ifdef _MFC_VER
  598. #include <afxconv.h>
  599. #define _NO_STDCONVERSION // just to be consistent
  600. #else
  601. #define USES_CONVERSION SSCVT
  602. #define A2CW SSA2CW
  603. #define W2CA SSW2CA
  604. #define T2A SST2A
  605. #define A2T SSA2T
  606. #define T2W SST2W
  607. #define W2T SSW2T
  608. #define T2CA SST2CA
  609. #define A2CT SSA2CT
  610. #define T2CW SST2CW
  611. #define W2CT SSW2CT
  612. #define ocslen sslen
  613. #define ocscpy sscpy
  614. #define T2COLE SST2COLE
  615. #define OLE2CT SSOLE2CT
  616. #define T2OLE SST2COLE
  617. #define OLE2T SSOLE2CT
  618. #define A2OLE SSA2OLE
  619. #define OLE2A SSOLE2A
  620. #define W2OLE SSW2OLE
  621. #define OLE2W SSOLE2W
  622. #define A2COLE SSA2COLE
  623. #define OLE2CA SSOLE2CA
  624. #define W2COLE SSW2COLE
  625. #define OLE2CW SSOLE2CW
  626. #endif // #ifdef _MFC_VER
  627. #endif // #ifndef USES_CONVERSION
  628. #endif // #ifndef SS_NO_CONVERSION
  629. // Define ostring - generic name for std::basic_string<OLECHAR>
  630. #if !defined(ostring) && !defined(OSTRING_DEFINED)
  631. typedef std::basic_string<OLECHAR> ostring;
  632. #define OSTRING_DEFINED
  633. #endif
  634. #endif // #ifndef SS_ANSI
  635. // StdCodeCvt when there's no conversion to be done
  636. inline PSTR StdCodeCvt(PSTR pDst, PCSTR pSrc, int nChars)
  637. {
  638. pDst[0] = '';
  639. std::char_traits<char>::copy(pDst, pSrc, nChars);
  640. if ( nChars > 0 )
  641. pDst[nChars] = '';
  642. return pDst;
  643. }
  644. inline PSTR StdCodeCvt(PSTR pDst, PCUSTR pSrc, int nChars)
  645. {
  646. return StdCodeCvt(pDst, (PCSTR)pSrc, nChars);
  647. }
  648. inline PUSTR StdCodeCvt(PUSTR pDst, PCSTR pSrc, int nChars)
  649. {
  650. return (PUSTR)StdCodeCvt((PSTR)pDst, pSrc, nChars);
  651. }
  652. inline PWSTR StdCodeCvt(PWSTR pDst, PCWSTR pSrc, int nChars)
  653. {
  654. pDst[0] = '';
  655. std::char_traits<wchar_t>::copy(pDst, pSrc, nChars);
  656. if ( nChars > 0 )
  657. pDst[nChars] = '';
  658. return pDst;
  659. }
  660. // Define tstring -- generic name for std::basic_string<TCHAR>
  661. #if !defined(tstring) && !defined(TSTRING_DEFINED)
  662. typedef std::basic_string<TCHAR> tstring;
  663. #define TSTRING_DEFINED
  664. #endif
  665. // a very shorthand way of applying the fix for KB problem Q172398
  666. // (basic_string assignment bug)
  667. #if defined ( _MSC_VER ) && ( _MSC_VER < 1200 )
  668. #define Q172398(x) (x).erase()
  669. #else
  670. #define Q172398(x)
  671. #endif
  672. // =============================================================================
  673. // INLINE FUNCTIONS ON WHICH CSTDSTRING RELIES
  674. //
  675. // Usually for generic text mapping, we rely on preprocessor macro definitions
  676. // to map to string functions.  However the CStdStr<> template cannot use
  677. // macro-based generic text mappings because its character types do not get
  678. // resolved until template processing which comes AFTER macro processing.  In
  679. // other words, UNICODE is of little help to us in the CStdStr template
  680. //
  681. // Therefore, to keep the CStdStr declaration simple, we have these inline
  682. // functions.  The template calls them often.  Since they are inline (and NOT
  683. // exported when this is built as a DLL), they will probably be resolved away
  684. // to nothing. 
  685. //
  686. // Without these functions, the CStdStr<> template would probably have to broken
  687. // out into two, almost identical classes.  Either that or it would be a huge,
  688. // convoluted mess, with tons of "if" statements all over the place checking the
  689. // size of template parameter CT.
  690. // 
  691. // In several cases, you will see two versions of each function.  One version is
  692. // the more portable, standard way of doing things, while the other is the
  693. // non-standard, but often significantly faster Visual C++ way.
  694. // =============================================================================
  695. // If they defined SS_NO_REFCOUNT, then we must convert all assignments
  696. #ifdef SS_NO_REFCOUNT
  697. #define SSREF(x) (x).c_str()
  698. #else
  699. #define SSREF(x) (x)
  700. #endif
  701. // -----------------------------------------------------------------------------
  702. // sslen: strlen/wcslen wrappers
  703. // -----------------------------------------------------------------------------
  704. template<typename CT> inline int sslen(const CT* pT)
  705. {
  706. return 0 == pT ? 0 : std::char_traits<CT>::length(pT);
  707. }
  708. inline SS_NOTHROW int sslen(const std::string& s)
  709. {
  710. return s.length();
  711. }
  712. inline SS_NOTHROW int sslen(const std::wstring& s)
  713. {
  714. return s.length();
  715. }
  716. // -----------------------------------------------------------------------------
  717. // ssasn: assignment functions -- assign "sSrc" to "sDst"
  718. // -----------------------------------------------------------------------------
  719. typedef std::string::size_type SS_SIZETYPE; // just for shorthand, really
  720. typedef std::string::pointer SS_PTRTYPE;  
  721. typedef std::wstring::size_type SW_SIZETYPE;
  722. typedef std::wstring::pointer SW_PTRTYPE;  
  723. inline void ssasn(std::string& sDst, const std::string& sSrc)
  724. {
  725. if ( sDst.c_str() != sSrc.c_str() )
  726. {
  727. sDst.erase();
  728. sDst.assign(SSREF(sSrc));
  729. }
  730. }
  731. inline void ssasn(std::string& sDst, PCSTR pA)
  732. {
  733. // Watch out for NULLs, as always.
  734. if ( 0 == pA )
  735. {
  736. sDst.erase();
  737. }
  738. // If pA actually points to part of sDst, we must NOT erase(), but
  739. // rather take a substring
  740. else if ( pA >= sDst.c_str() && pA <= sDst.c_str() + sDst.size() )
  741. {
  742. sDst =sDst.substr(static_cast<SS_SIZETYPE>(pA-sDst.c_str()));
  743. }
  744. // Otherwise (most cases) apply the assignment bug fix, if applicable
  745. // and do the assignment
  746. else
  747. {
  748. Q172398(sDst);
  749. sDst.assign(pA);
  750. }
  751. }
  752. inline void ssasn(std::string& sDst, const std::wstring& sSrc)
  753. {
  754. #ifdef SS_ANSI
  755. int nLen = sSrc.size();
  756. sDst.resize(0);
  757. sDst.resize(nLen);
  758. StdCodeCvt(const_cast<SS_PTRTYPE>(sDst.data()), sSrc.c_str(), nLen);
  759. #else
  760. SSCVT;
  761. sDst.assign(SSW2CA(sSrc.c_str()));
  762. #endif
  763. }
  764. inline void ssasn(std::string& sDst, PCWSTR pW)
  765. {
  766. #ifdef SS_ANSI
  767. int nLen = sslen(pW);
  768. sDst.resize(0);
  769. sDst.resize(nLen);
  770. StdCodeCvt(const_cast<SS_PTRTYPE>(sDst.data()), pW, nLen);
  771. #else
  772. SSCVT;
  773. sDst.assign(pW ? SSW2CA(pW) : "");
  774. #endif
  775. }
  776. inline void ssasn(std::string& sDst, const int nNull)
  777. {
  778. UNUSED(nNull);
  779. ASSERT(nNull==0);
  780. sDst.assign("");
  781. }
  782. inline void ssasn(std::wstring& sDst, const std::wstring& sSrc)
  783. {
  784. if ( sDst.c_str() != sSrc.c_str() )
  785. {
  786. sDst.erase();
  787. sDst.assign(SSREF(sSrc));
  788. }
  789. }
  790. inline void ssasn(std::wstring& sDst, PCWSTR pW)
  791. {
  792. // Watch out for NULLs, as always.
  793. if ( 0 == pW )
  794. {
  795. sDst.erase();
  796. }
  797. // If pW actually points to part of sDst, we must NOT erase(), but
  798. // rather take a substring
  799. else if ( pW >= sDst.c_str() && pW <= sDst.c_str() + sDst.size() )
  800. {
  801. sDst = sDst.substr(static_cast<SW_SIZETYPE>(pW-sDst.c_str()));
  802. }
  803. // Otherwise (most cases) apply the assignment bug fix, if applicable
  804. // and do the assignment
  805. else
  806. {
  807. Q172398(sDst);
  808. sDst.assign(pW);
  809. }
  810. }
  811. #undef StrSizeType
  812. inline void ssasn(std::wstring& sDst, const std::string& sSrc)
  813. {
  814. #ifdef SS_ANSI
  815. int nLen = sSrc.size();
  816. sDst.resize(0);
  817. sDst.resize(nLen);
  818. StdCodeCvt(const_cast<SW_PTRTYPE>(sDst.data()), sSrc.c_str(), nLen);
  819. #else
  820. SSCVT;
  821. sDst.assign(SSA2CW(sSrc.c_str()));
  822. #endif
  823. }
  824. inline void ssasn(std::wstring& sDst, PCSTR pA)
  825. {
  826. #ifdef SS_ANSI
  827. int nLen = sslen(pA);
  828. sDst.resize(0);
  829. sDst.resize(nLen);
  830. StdCodeCvt(const_cast<SW_PTRTYPE>(sDst.data()), pA, nLen);
  831. #else
  832. SSCVT;
  833. sDst.assign(pA ? SSA2CW(pA) : L"");
  834. #endif
  835. }
  836. inline void ssasn(std::wstring& sDst, const int nNull)
  837. {
  838. UNUSED(nNull);
  839. ASSERT(nNull==0);
  840. sDst.assign(L"");
  841. }
  842. // -----------------------------------------------------------------------------
  843. // ssadd: string object concatenation -- add second argument to first
  844. // -----------------------------------------------------------------------------
  845. inline void ssadd(std::string& sDst, const std::wstring& sSrc)
  846. {
  847. #ifdef SS_ANSI
  848. int nLen = sSrc.size();
  849. sDst.resize(sDst.size() + nLen);
  850. StdCodeCvt(const_cast<SS_PTRTYPE>(sDst.data()+nLen), sSrc.c_str(), nLen);
  851. #else
  852. SSCVT; 
  853. sDst.append(SSW2CA(sSrc.c_str())); 
  854. #endif
  855. }
  856. inline void ssadd(std::string& sDst, const std::string& sSrc)
  857. sDst.append(sSrc.c_str());
  858. }
  859. inline void ssadd(std::string& sDst, PCWSTR pW)
  860. {
  861. #ifdef SS_ANSI
  862. int nLen = sslen(pW);
  863. sDst.resize(sDst.size() + nLen);
  864. StdCodeCvt(const_cast<SS_PTRTYPE>(sDst.data()+nLen), pW, nLen);
  865. #else
  866. SSCVT;
  867. if ( 0 != pW )
  868. sDst.append(SSW2CA(pW)); 
  869. #endif
  870. }
  871. inline void ssadd(std::string& sDst, PCSTR pA)
  872. {
  873. if ( pA )
  874. sDst.append(pA); 
  875. }
  876. inline void ssadd(std::wstring& sDst, const std::wstring& sSrc)
  877. {
  878. sDst.append(sSrc.c_str());
  879. }
  880. inline void ssadd(std::wstring& sDst, const std::string& sSrc)
  881. {
  882. #ifdef SS_ANSI
  883. int nLen = sSrc.size();
  884. sDst.resize(sDst.size() + nLen);
  885. StdCodeCvt(const_cast<SW_PTRTYPE>(sDst.data()+nLen), sSrc.c_str(), nLen);
  886. #else
  887. SSCVT;
  888. sDst.append(SSA2CW(sSrc.c_str()));
  889. #endif
  890. }
  891. inline void ssadd(std::wstring& sDst, PCSTR pA)
  892. {
  893. #ifdef SS_ANSI
  894. int nLen = sslen(pA);
  895. sDst.resize(sDst.size() + nLen);
  896. StdCodeCvt(const_cast<SW_PTRTYPE>(sDst.data()+nLen), pA, nLen);
  897. #else
  898. SSCVT;
  899. if ( 0 != pA )
  900. sDst.append(SSA2CW(pA));
  901. #endif
  902. }
  903. inline void ssadd(std::wstring& sDst, PCWSTR pW)
  904. {
  905. if ( pW )
  906. sDst.append(pW);
  907. }
  908. // -----------------------------------------------------------------------------
  909. // ssicmp: comparison (case insensitive )
  910. // -----------------------------------------------------------------------------
  911. #ifdef SS_ANSI
  912. template<typename CT>
  913. inline int ssicmp(const CT* pA1, const CT* pA2)
  914. {
  915. std::locale loc;
  916. const std::ctype<CT>& ct = SS_USE_FACET(loc, std::ctype<CT>);
  917. CT f;
  918. CT l;
  919.             do 
  920. {
  921. f = ct.tolower(*(pA1++));
  922. l = ct.tolower(*(pA2++));
  923.             } while ( (f) && (f == l) );
  924.         return (int)(f - l);
  925. }
  926. #else
  927. #ifdef _MBCS
  928. inline long sscmp(PCSTR pA1, PCSTR pA2)
  929. {
  930. return _mbscmp((PCUSTR)pA1, (PCUSTR)pA2);
  931. }
  932. inline long ssicmp(PCSTR pA1, PCSTR pA2)
  933. {
  934. return _mbsicmp((PCUSTR)pA1, (PCUSTR)pA2);
  935. }
  936. #else
  937. inline long sscmp(PCSTR pA1, PCSTR pA2)
  938. {
  939. return strcmp(pA1, pA2);
  940. }
  941. inline long ssicmp(PCSTR pA1, PCSTR pA2)
  942. {
  943. return _stricmp(pA1, pA2);
  944. }
  945. #endif
  946. inline long sscmp(PCWSTR pW1, PCWSTR pW2)
  947. {
  948. return wcscmp(pW1, pW2);
  949. }
  950. inline long ssicmp(PCWSTR pW1, PCWSTR pW2)
  951. {
  952. return _wcsicmp(pW1, pW2);
  953. }
  954. #endif
  955. // -----------------------------------------------------------------------------
  956. // ssupr/sslwr: Uppercase/Lowercase conversion functions
  957. // -----------------------------------------------------------------------------
  958. #ifdef SS_ANSI
  959. template<typename CT>
  960. inline void sslwr(CT* pT, size_t nLen)
  961. {
  962. SS_USE_FACET(std::locale(), std::ctype<CT>).tolower(pT, pT+nLen);
  963. }
  964. template<typename CT>
  965. inline void ssupr(CT* pT, size_t nLen)
  966. {
  967. SS_USE_FACET(std::locale(), std::ctype<CT>).toupper(pT, pT+nLen);
  968. }
  969. #else  // #else we must be on Win32
  970. #ifdef _MBCS
  971. inline void ssupr(PSTR pA, size_t /*nLen*/)
  972. {
  973. _mbsupr((PUSTR)pA);
  974. }
  975. inline void sslwr(PSTR pA, size_t /*nLen*/)
  976. {
  977. _mbslwr((PUSTR)pA);
  978. }
  979. #else
  980. inline void ssupr(PSTR pA, size_t /*nLen*/)
  981. {
  982. _strupr(pA); 
  983. }
  984. inline void sslwr(PSTR pA, size_t /*nLen*/)
  985. {
  986. _strlwr(pA);
  987. }
  988. #endif
  989. inline void ssupr(PWSTR pW, size_t /*nLen*/)
  990. {
  991. _wcsupr(pW);
  992. }
  993. inline void sslwr(PWSTR pW, size_t /*nLen*/)
  994. {
  995. _wcslwr(pW);
  996. }
  997. #endif // #ifdef SS_ANSI
  998. // -----------------------------------------------------------------------------
  999. //  vsprintf/vswprintf or _vsnprintf/_vsnwprintf equivalents.  In standard
  1000. //  builds we can't use _vsnprintf/_vsnwsprintf because they're MS extensions.
  1001. // -----------------------------------------------------------------------------
  1002. #ifdef SS_ANSI
  1003. inline int ssvsprintf(PSTR pA, size_t /*nCount*/, PCSTR pFmtA, va_list vl)
  1004. {
  1005. return vsprintf(pA, pFmtA, vl);
  1006. }
  1007. inline int ssvsprintf(PWSTR pW, size_t nCount, PCWSTR pFmtW, va_list vl)
  1008. {
  1009. // JMO: It is beginning to seem like Microsoft Visual C++ is the only
  1010. // CRT distribution whose version of vswprintf takes THREE arguments.
  1011. // All others seem to take FOUR arguments.  Therefore instead of 
  1012. // checking for every possible distro here, I'll assume that unless
  1013. // I am running with Microsoft's CRT, then vswprintf takes four
  1014. // arguments.  If you get a compilation error here, then you can just
  1015. // change this code to call the three-argument version.
  1016. // #if !defined(__MWERKS__) && !defined(__SUNPRO_CC_COMPAT) && !defined(__SUNPRO_CC)
  1017. //#ifndef _MSC_VER
  1018. // return vswprintf(pW, nCount, pFmtW, vl);
  1019. // #else
  1020. nCount;
  1021. return vswprintf(pW, pFmtW, vl);
  1022. // #endif
  1023. }
  1024. #else
  1025. inline int ssnprintf(PSTR pA, size_t nCount, PCSTR pFmtA, va_list vl)
  1026. return _vsnprintf(pA, nCount, pFmtA, vl);
  1027. }
  1028. inline int ssnprintf(PWSTR pW, size_t nCount, PCWSTR pFmtW, va_list vl)
  1029. {
  1030. return _vsnwprintf(pW, nCount, pFmtW, vl);
  1031. }
  1032. #endif
  1033. // -----------------------------------------------------------------------------
  1034. // ssload: Type safe, overloaded ::LoadString wrappers
  1035. // There is no equivalent of these in non-Win32-specific builds.  However, I'm
  1036. // thinking that with the message facet, there might eventually be one
  1037. // -----------------------------------------------------------------------------
  1038. #ifdef SS_ANSI
  1039. #else
  1040. inline int ssload(HMODULE hInst, UINT uId, PSTR pBuf, int nMax)
  1041. {
  1042. return ::LoadStringA(hInst, uId, pBuf, nMax);
  1043. }
  1044. inline int ssload(HMODULE hInst, UINT uId, PWSTR pBuf, int nMax)
  1045. {
  1046. return ::LoadStringW(hInst, uId, pBuf, nMax);
  1047. }
  1048. #endif
  1049. // -----------------------------------------------------------------------------
  1050. // sscoll/ssicoll: Collation wrappers
  1051. // -----------------------------------------------------------------------------
  1052. #ifdef SS_ANSI
  1053. template <typename CT>
  1054. inline int sscoll(const CT* sz1, int nLen1, const CT* sz2, int nLen2)
  1055. {
  1056. const std::collate<CT>& coll =
  1057. SS_USE_FACET(std::locale(), std::collate<CT>);
  1058. return coll.compare(sz1, sz1+nLen1, sz2, sz2+nLen2);
  1059. }
  1060. template <typename CT>
  1061. inline int ssicoll(const CT* sz1, int nLen1, const CT* sz2, int nLen2)
  1062. {
  1063. const std::locale loc;
  1064. const std::collate<CT>& coll = SS_USE_FACET(loc, std::collate<CT>);
  1065. // Some implementations seem to have trouble using the collate<>
  1066. // facet typedefs so we'll just default to basic_string and hope
  1067. // that's what the collate facet uses (which it generally should)
  1068. // std::collate<CT>::string_type s1(sz1);
  1069. // std::collate<CT>::string_type s2(sz2);
  1070. std::basic_string<CT> s1(sz1);
  1071. std::basic_string<CT> s2(sz2);
  1072. sslwr(const_cast<CT*>(s1.c_str()), nLen1);
  1073. sslwr(const_cast<CT*>(s2.c_str()), nLen2);
  1074. return coll.compare(s1.c_str(), s1.c_str()+nLen1,
  1075. s2.c_str(), s2.c_str()+nLen2);
  1076. }
  1077. #else
  1078. #ifdef _MBCS
  1079. inline int sscoll(PCSTR sz1, int /*nLen1*/, PCSTR sz2, int /*nLen2*/)
  1080. {
  1081. return _mbscoll((PCUSTR)sz1, (PCUSTR)sz2);
  1082. }
  1083. inline int ssicoll(PCSTR sz1, int /*nLen1*/, PCSTR sz2, int /*nLen2*/)
  1084. {
  1085. return _mbsicoll((PCUSTR)sz1, (PCUSTR)sz2);
  1086. }
  1087. #else
  1088. inline int sscoll(PCSTR sz1, int /*nLen1*/, PCSTR sz2, int /*nLen2*/)
  1089. {
  1090. return strcoll(sz1, sz2);
  1091. }
  1092. inline int ssicoll(PCSTR sz1, int /*nLen1*/, PCSTR sz2, int /*nLen2*/)
  1093. {
  1094. return _stricoll(sz1, sz2);
  1095. }
  1096. #endif
  1097. inline int sscoll(PCWSTR sz1, int /*nLen1*/, PCWSTR sz2, int /*nLen2*/)
  1098. {
  1099. return wcscoll(sz1, sz2);
  1100. }
  1101. inline int ssicoll(PCWSTR sz1, int /*nLen1*/, PCWSTR sz2, int /*nLen2*/)
  1102. {
  1103. return _wcsicoll(sz1, sz2);
  1104. }
  1105. #endif
  1106. // -----------------------------------------------------------------------------
  1107. // ssfmtmsg: FormatMessage equivalents.  Needed because I added a CString facade
  1108. // Again -- no equivalent of these on non-Win32 builds but their might one day
  1109. // be one if the message facet gets implemented
  1110. // -----------------------------------------------------------------------------
  1111. #ifdef SS_ANSI
  1112. #else
  1113. inline DWORD ssfmtmsg(DWORD dwFlags, LPCVOID pSrc, DWORD dwMsgId,
  1114.   DWORD dwLangId, PSTR pBuf, DWORD nSize,
  1115.   va_list* vlArgs)
  1116. return FormatMessageA(dwFlags, pSrc, dwMsgId, dwLangId,
  1117.   pBuf, nSize,vlArgs);
  1118. }
  1119. inline DWORD ssfmtmsg(DWORD dwFlags, LPCVOID pSrc, DWORD dwMsgId,
  1120.   DWORD dwLangId, PWSTR pBuf, DWORD nSize,
  1121.   va_list* vlArgs)
  1122. {
  1123. return FormatMessageW(dwFlags, pSrc, dwMsgId, dwLangId,
  1124.   pBuf, nSize,vlArgs);
  1125. }
  1126. #endif
  1127.  
  1128. // FUNCTION: sscpy.  Copies up to 'nMax' characters from pSrc to pDst.
  1129. // -----------------------------------------------------------------------------
  1130. // FUNCTION:  sscpy
  1131. // inline int sscpy(PSTR pDst, PCSTR pSrc, int nMax=-1);
  1132. // inline int sscpy(PUSTR pDst,  PCSTR pSrc, int nMax=-1)
  1133. // inline int sscpy(PSTR pDst, PCWSTR pSrc, int nMax=-1);
  1134. // inline int sscpy(PWSTR pDst, PCWSTR pSrc, int nMax=-1);
  1135. // inline int sscpy(PWSTR pDst, PCSTR pSrc, int nMax=-1);
  1136. //
  1137. // DESCRIPTION:
  1138. // This function is very much (but not exactly) like strcpy.  These
  1139. // overloads simplify copying one C-style string into another by allowing
  1140. // the caller to specify two different types of strings if necessary.
  1141. //
  1142. // The strings must NOT overlap
  1143. //
  1144. // "Character" is expressed in terms of the destination string, not
  1145. // the source.  If no 'nMax' argument is supplied, then the number of
  1146. // characters copied will be sslen(pSrc).  A NULL terminator will
  1147. // also be added so pDst must actually be big enough to hold nMax+1
  1148. // characters.  The return value is the number of characters copied,
  1149. // not including the NULL terminator.
  1150. //
  1151. // PARAMETERS: 
  1152. // pSrc - the string to be copied FROM.  May be a char based string, an
  1153. //    MBCS string (in Win32 builds) or a wide string (wchar_t).
  1154. // pSrc - the string to be copied TO.  Also may be either MBCS or wide
  1155. // nMax - the maximum number of characters to be copied into szDest.  Note
  1156. //    that this is expressed in whatever a "character" means to pDst.
  1157. //    If pDst is a wchar_t type string than this will be the maximum
  1158. //    number of wchar_ts that my be copied.  The pDst string must be
  1159. //    large enough to hold least nMaxChars+1 characters.
  1160. //    If the caller supplies no argument for nMax this is a signal to
  1161. //    the routine to copy all the characters in pSrc, regardless of
  1162. //    how long it is.
  1163. //
  1164. // RETURN VALUE: none
  1165. // -----------------------------------------------------------------------------
  1166. template<typename CT1, typename CT2>
  1167. inline int sscpycvt(CT1* pDst, const CT2* pSrc, int nChars)
  1168. {
  1169. StdCodeCvt(pDst, pSrc, nChars);
  1170. pDst[SSMAX(nChars, 0)] = '';
  1171. return nChars;
  1172. }
  1173. template<typename CT1, typename CT2>
  1174. inline int sscpy(CT1* pDst, const CT2* pSrc, int nMax, int nLen)
  1175. {
  1176. return sscpycvt(pDst, pSrc, SSMIN(nMax, nLen));
  1177. }
  1178. template<typename CT1, typename CT2>
  1179. inline int sscpy(CT1* pDst, const CT2* pSrc, int nMax)
  1180. {
  1181. return sscpycvt(pDst, pSrc, SSMIN(nMax, sslen(pSrc)));
  1182. }
  1183. template<typename CT1, typename CT2>
  1184. inline int sscpy(CT1* pDst, const CT2* pSrc)
  1185. {
  1186. return sscpycvt(pDst, pSrc, sslen(pSrc));
  1187. }
  1188. template<typename CT1, typename CT2>
  1189. inline int sscpy(CT1* pDst, const std::basic_string<CT2>& sSrc, int nMax)
  1190. {
  1191. return sscpycvt(pDst, sSrc.c_str(), SSMIN(nMax, (int)sSrc.length()));
  1192. }
  1193. template<typename CT1, typename CT2>
  1194. inline int sscpy(CT1* pDst, const std::basic_string<CT2>& sSrc)
  1195. {
  1196. return sscpycvt(pDst, sSrc.c_str(), (int)sSrc.length());
  1197. }
  1198. #ifdef SS_INC_COMDEF
  1199. template<typename CT1>
  1200. inline int sscpy(CT1* pDst, const _bstr_t& bs, int nMax)
  1201. {
  1202. return sscpycvt(pDst, static_cast<PCOLESTR>(bs), SSMIN(nMax, (int)bs.length()));
  1203. }
  1204. template<typename CT1>
  1205. inline int sscpy(CT1* pDst, const _bstr_t& bs)
  1206. {
  1207. return sscpy(pDst, bs, bs.length());
  1208. }
  1209. #endif
  1210. // -----------------------------------------------------------------------------
  1211. // Functional objects for changing case.  They also let you pass locales
  1212. // -----------------------------------------------------------------------------
  1213. #ifdef SS_ANSI
  1214. template<typename CT>
  1215. struct SSToUpper : public std::binary_function<CT, std::locale, CT>
  1216. {
  1217. inline CT operator()(const CT& t, const std::locale& loc) const
  1218. {
  1219. return std::toupper<CT>(t, loc);
  1220. }
  1221. };
  1222. template<typename CT>
  1223. struct SSToLower : public std::binary_function<CT, std::locale, CT>
  1224. {
  1225. inline CT operator()(const CT& t, const std::locale& loc) const
  1226. {
  1227. return std::tolower<CT>(t, loc);
  1228. }
  1229. };
  1230. #endif
  1231. // This struct is used for TrimRight() and TrimLeft() function implementations.
  1232. //template<typename CT>
  1233. //struct NotSpace : public std::unary_function<CT, bool>
  1234. //{
  1235. // const std::locale& loc;
  1236. // inline NotSpace(const std::locale& locArg) : loc(locArg) {}
  1237. // inline bool operator() (CT t) { return !std::isspace(t, loc); }
  1238. //};
  1239. template<typename CT>
  1240. struct NotSpace : public std::unary_function<CT, bool>
  1241. {
  1242. const std::locale& loc;
  1243. NotSpace(const std::locale& locArg) : loc(locArg) {}
  1244. // DINKUMWARE BUG:
  1245. // Note -- using std::isspace in a COM DLL gives us access violations
  1246. // because it causes the dynamic addition of a function to be called
  1247. // when the library shuts down.  Unfortunately the list is maintained
  1248. // in DLL memory but the function is in static memory.  So the COM DLL
  1249. // goes away along with the function that was supposed to be called,
  1250. // and then later when the DLL CRT shuts down it unloads the list and
  1251. // tries to call the long-gone function.
  1252. // This is DinkumWare's implementation problem.  Until then, we will
  1253. // use good old isspace and iswspace from the CRT unless they
  1254. // specify SS_ANSI
  1255. #ifdef SS_ANSI
  1256. bool operator() (CT t) const { return !std::isspace(t, loc); }
  1257. #else
  1258. bool ssisp(char c) const { return FALSE != ::isspace((int) c); }
  1259. bool ssisp(wchar_t c) const { return FALSE != ::iswspace((wint_t) c); }
  1260. bool operator()(CT t) const  { return !ssisp(t); }
  1261. #endif
  1262. };
  1263. // Now we can define the template (finally!)
  1264. // =============================================================================
  1265. // TEMPLATE: CStdStr
  1266. // template<typename CT> class CStdStr : public std::basic_string<CT>
  1267. //
  1268. // REMARKS:
  1269. // This template derives from basic_string<CT> and adds some MFC CString-
  1270. // like functionality
  1271. //
  1272. // Basically, this is my attempt to make Standard C++ library strings as
  1273. // easy to use as the MFC CString class.
  1274. //
  1275. // Note that although this is a template, it makes the assumption that the
  1276. // template argument (CT, the character type) is either char or wchar_t.  
  1277. // =============================================================================
  1278. //#define CStdStr _SS // avoid compiler warning 4786
  1279. template<typename CT>
  1280. class CStdStr : public std::basic_string<CT>
  1281. {
  1282. // Typedefs for shorter names.  Using these names also appears to help
  1283. // us avoid some ambiguities that otherwise arise on some platforms
  1284. typedef typename std::basic_string<CT> MYBASE;  // my base class
  1285. typedef CStdStr<CT> MYTYPE;  // myself
  1286. typedef typename MYBASE::const_pointer PCMYSTR; // PCSTR or PCWSTR 
  1287. typedef typename MYBASE::pointer PMYSTR;  // PSTR or PWSTR
  1288. typedef typename MYBASE::iterator MYITER;  // my iterator type
  1289. typedef typename MYBASE::const_iterator MYCITER; // you get the idea...
  1290. typedef typename MYBASE::reverse_iterator MYRITER;
  1291. typedef typename MYBASE::size_type MYSIZE;   
  1292. typedef typename MYBASE::value_type MYVAL; 
  1293. typedef typename MYBASE::allocator_type MYALLOC;
  1294. public:
  1295. // shorthand conversion from PCTSTR to string resource ID
  1296. #define _TRES(pctstr) (LOWORD((DWORD)(pctstr)))
  1297. // CStdStr inline constructors
  1298. CStdStr()
  1299. {
  1300. }
  1301. CStdStr(const MYTYPE& str) : MYBASE(SSREF(str))
  1302. {
  1303. }
  1304. CStdStr(const std::string& str)
  1305. {
  1306. ssasn(*this, SSREF(str));
  1307. }
  1308. CStdStr(const std::wstring& str)
  1309. {
  1310. ssasn(*this, SSREF(str));
  1311. }
  1312. CStdStr(PCMYSTR pT, MYSIZE n) : MYBASE(pT, n)
  1313. {
  1314. }
  1315. CStdStr(PCSTR pA)
  1316. {
  1317. #ifdef SS_ANSI
  1318. *this = pA;
  1319. #else
  1320. if ( 0 != HIWORD(pA) )
  1321. *this = pA;
  1322. else if ( 0 != pA && !Load(_TRES(pA)) )
  1323. TRACE(_T("Can't load string %un"), _TRES(pA));
  1324. #endif
  1325. }
  1326. CStdStr(PCWSTR pW)
  1327. {
  1328. #ifdef SS_ANSI
  1329. *this = pW;
  1330. #else
  1331. if ( 0 != HIWORD(pW) )
  1332. *this = pW;
  1333. else if ( 0 != pW && !Load(_TRES(pW)) )
  1334. TRACE(_T("Can't load string %un"), _TRES(pW));
  1335. #endif
  1336. }
  1337. CStdStr(MYCITER first, MYCITER last)
  1338. : MYBASE(first, last)
  1339. {
  1340. }
  1341. CStdStr(MYSIZE nSize, MYVAL ch, const MYALLOC& al=MYALLOC())
  1342. : MYBASE(nSize, ch, al)
  1343. {
  1344. }
  1345. #ifdef SS_INC_COMDEF
  1346. CStdStr(const _bstr_t& bstr)
  1347. {
  1348. if ( bstr.length() > 0 )
  1349. append(static_cast<PCMYSTR>(bstr), bstr.length());
  1350. }
  1351. #endif
  1352. // CStdStr inline assignment operators -- the ssasn function now takes care
  1353. // of fixing  the MSVC assignment bug (see knowledge base article Q172398).
  1354. MYTYPE& operator=(const MYTYPE& str)
  1355. ssasn(*this, str); 
  1356. return *this;
  1357. }
  1358. MYTYPE& operator=(const std::string& str)
  1359. {
  1360. ssasn(*this, str);
  1361. return *this;
  1362. }
  1363. MYTYPE& operator=(const std::wstring& str)
  1364. {
  1365. ssasn(*this, str);
  1366. return *this;
  1367. }
  1368. MYTYPE& operator=(PCSTR pA)
  1369. {
  1370. ssasn(*this, pA);
  1371. return *this;
  1372. }
  1373. MYTYPE& operator=(PCWSTR pW)
  1374. {
  1375. ssasn(*this, pW);
  1376. return *this;
  1377. }
  1378. MYTYPE& operator=(CT t)
  1379. {
  1380. Q172398(*this);
  1381. MYBASE::assign(1, t);
  1382. return *this;
  1383. }
  1384. #ifdef SS_INC_COMDEF
  1385. MYTYPE& operator=(const _bstr_t& bstr)
  1386. {
  1387. if ( bstr.length() > 0 )
  1388. return assign(static_cast<PCMYSTR>(bstr), bstr.length());
  1389. else
  1390. {
  1391. erase();
  1392. return *this;
  1393. }
  1394. }
  1395. #endif
  1396. // Overloads  also needed to fix the MSVC assignment bug (KB: Q172398)
  1397. //  *** Thanks to Pete The Plumber for catching this one ***
  1398. // They also are compiled if you have explicitly turned off refcounting
  1399. #if ( defined(_MSC_VER) && ( _MSC_VER < 1200 ) ) || defined(SS_NO_REFCOUNT) 
  1400. MYTYPE& assign(const MYTYPE& str)
  1401. {
  1402. ssasn(*this, str);
  1403. return *this;
  1404. }
  1405. MYTYPE& assign(const MYTYPE& str, MYSIZE nStart, MYSIZE nChars)
  1406. {
  1407. // This overload of basic_string::assign is supposed to assign up to
  1408. // <nChars> or the NULL terminator, whichever comes first.  Since we
  1409. // are about to call a less forgiving overload (in which <nChars>
  1410. // must be a valid length), we must adjust the length here to a safe
  1411. // value.  Thanks to Ullrich Poll鋒ne for catching this bug
  1412. nChars = SSMIN(nChars, str.length() - nStart);
  1413. // Watch out for assignment to self
  1414. if ( this == &str )
  1415. {
  1416. MYTYPE strTemp(str.c_str()+nStart, nChars);
  1417. assign(strTemp);
  1418. }
  1419. else
  1420. {
  1421. Q172398(*this);
  1422. MYBASE::assign(str.c_str()+nStart, nChars);
  1423. }
  1424. return *this;
  1425. }
  1426. MYTYPE& assign(const MYBASE& str)
  1427. {
  1428. ssasn(*this, str);
  1429. return *this;
  1430. }
  1431. MYTYPE& assign(const MYBASE& str, MYSIZE nStart, MYSIZE nChars)
  1432. {
  1433. // This overload of basic_string::assign is supposed to assign up to
  1434. // <nChars> or the NULL terminator, whichever comes first.  Since we
  1435. // are about to call a less forgiving overload (in which <nChars>
  1436. // must be a valid length), we must adjust the length here to a safe
  1437. // value. Thanks to Ullrich Poll鋒ne for catching this bug
  1438. nChars = SSMIN(nChars, str.length() - nStart);
  1439. // Watch out for assignment to self
  1440. if ( this == &str ) // watch out for assignment to self
  1441. {
  1442. MYTYPE strTemp(str.c_str() + nStart, nChars);
  1443. assign(strTemp);
  1444. }
  1445. else
  1446. {
  1447. Q172398(*this);
  1448. MYBASE::assign(str.c_str()+nStart, nChars);
  1449. }
  1450. return *this;
  1451. }
  1452. MYTYPE& assign(const CT* pC, MYSIZE nChars)
  1453. {
  1454. // Q172398 only fix -- erase before assigning, but not if we're
  1455. // assigning from our own buffer
  1456. #if defined ( _MSC_VER ) && ( _MSC_VER < 1200 )
  1457. if ( !empty() && ( pC < data() || pC > data() + capacity() ) )
  1458. erase();
  1459. #endif
  1460. Q172398(*this);
  1461. MYBASE::assign(pC, nChars);
  1462. return *this;
  1463. }
  1464. MYTYPE& assign(MYSIZE nChars, MYVAL val)
  1465. {
  1466. Q172398(*this);
  1467. MYBASE::assign(nChars, val);
  1468. return *this;
  1469. }
  1470. MYTYPE& assign(const CT* pT)
  1471. {
  1472. return assign(pT, CStdStr::traits_type::length(pT));
  1473. }
  1474. MYTYPE& assign(MYCITER iterFirst, MYCITER iterLast)
  1475. {
  1476. #if defined ( _MSC_VER ) && ( _MSC_VER < 1200 ) 
  1477. // Q172398 fix.  don't call erase() if we're assigning from ourself
  1478. if ( iterFirst < begin() || iterFirst > begin() + size() )
  1479. erase()
  1480. #endif
  1481. replace(begin(), end(), iterFirst, iterLast);
  1482. return *this;
  1483. }
  1484. #endif
  1485. // -------------------------------------------------------------------------
  1486. // CStdStr inline concatenation.
  1487. // -------------------------------------------------------------------------
  1488. MYTYPE& operator+=(const MYTYPE& str)
  1489. {
  1490. ssadd(*this, str);
  1491. return *this;
  1492. }
  1493. MYTYPE& operator+=(const std::string& str)
  1494. {
  1495. ssadd(*this, str);
  1496. return *this; 
  1497. }
  1498. MYTYPE& operator+=(const std::wstring& str)
  1499. {
  1500. ssadd(*this, str);
  1501. return *this;
  1502. }
  1503. MYTYPE& operator+=(PCSTR pA)
  1504. {
  1505. ssadd(*this, pA);
  1506. return *this;
  1507. }
  1508. MYTYPE& operator+=(PCWSTR pW)
  1509. {
  1510. ssadd(*this, pW);
  1511. return *this;
  1512. }
  1513. MYTYPE& operator+=(CT t)
  1514. {
  1515. append(1, t);
  1516. return *this;
  1517. }
  1518. #ifdef SS_INC_COMDEF // if we have _bstr_t, define a += for it too.
  1519. MYTYPE& operator+=(const _bstr_t& bstr)
  1520. {
  1521. return operator+=(static_cast<PCMYSTR>(bstr));
  1522. }
  1523. #endif
  1524. // addition operators -- global friend functions.
  1525. friend MYTYPE operator+(const MYTYPE& str1, const MYTYPE& str2);
  1526. friend MYTYPE operator+(const MYTYPE& str, CT t);
  1527. friend MYTYPE operator+(const MYTYPE& str, PCSTR sz);
  1528. friend MYTYPE operator+(const MYTYPE& str, PCWSTR sz);
  1529. friend MYTYPE operator+(PCSTR pA, const MYTYPE& str);
  1530. friend MYTYPE operator+(PCWSTR pW, const MYTYPE& str);
  1531. #ifdef SS_INC_COMDEF
  1532. friend MYTYPE operator+(const _bstr_t& bstr, const MYTYPE& str);
  1533. friend MYTYPE operator+(const MYTYPE& str, const _bstr_t& bstr);
  1534. #endif
  1535. // -------------------------------------------------------------------------
  1536. // Case changing functions
  1537. // -------------------------------------------------------------------------
  1538. // -------------------------------------------------------------------------
  1539. MYTYPE& ToUpper()
  1540. {
  1541. //  Strictly speaking, this would be about the most portable way
  1542. // std::transform(begin(),
  1543. //    end(),
  1544. //    begin(),
  1545. //    std::bind2nd(SSToUpper<CT>(), std::locale()));
  1546. // But practically speaking, this works faster
  1547. if ( !empty() )
  1548. ssupr(GetBuf(), size());
  1549. return *this;
  1550. }
  1551. MYTYPE& ToLower()
  1552. {
  1553. //  Strictly speaking, this would be about the most portable way
  1554. // std::transform(begin(),
  1555. //    end(),
  1556. //    begin(),
  1557. //    std::bind2nd(SSToLower<CT>(), std::locale()));
  1558. // But practically speaking, this works faster
  1559. if ( !empty() )
  1560. sslwr(GetBuf(), size());
  1561. return *this;
  1562. }
  1563. MYTYPE& Normalize()
  1564. {
  1565. return Trim().ToLower();
  1566. }
  1567. // -------------------------------------------------------------------------
  1568. // CStdStr -- Direct access to character buffer.  In the MS' implementation,
  1569. // the at() function that we use here also calls _Freeze() providing us some
  1570. // protection from multithreading problems associated with ref-counting.
  1571. // -------------------------------------------------------------------------
  1572. CT* GetBuf(int nMinLen=-1)
  1573. {
  1574. if ( static_cast<int>(size()) < nMinLen )
  1575. resize(static_cast<MYSIZE>(nMinLen));
  1576. return empty() ? const_cast<CT*>(data()) : &(at(0));
  1577. }
  1578. CT* SetBuf(int nLen)
  1579. {
  1580. nLen = ( nLen > 0 ? nLen : 0 );
  1581. if ( capacity() < 1 && nLen == 0 )
  1582. resize(1);
  1583. resize(static_cast<MYSIZE>(nLen));
  1584. return const_cast<CT*>(data());
  1585. }
  1586. void RelBuf(int nNewLen=-1)
  1587. {
  1588. resize(static_cast<MYSIZE>(nNewLen > -1 ? nNewLen : sslen(c_str())));
  1589. }
  1590. void BufferRel()  { RelBuf(); } // backwards compatability
  1591. CT*  Buffer()  { return GetBuf(); } // backwards compatability
  1592. CT*  BufferSet(int nLen) { return SetBuf(nLen);}// backwards compatability
  1593. bool Equals(const CT* pT, bool bUseCase=false) const
  1594. { // get copy, THEN compare (thread safe)
  1595. return  bUseCase ? compare(pT) == 0 : ssicmp(MYTYPE(*this), pT) == 0;
  1596. // -------------------------------------------------------------------------
  1597. // FUNCTION:  CStdStr::Load
  1598. // REMARKS:
  1599. // Loads string from resource specified by nID
  1600. //
  1601. // PARAMETERS:
  1602. // nID - resource Identifier.  Purely a Win32 thing in this case
  1603. //
  1604. // RETURN VALUE:
  1605. // true if successful, false otherwise
  1606. // -------------------------------------------------------------------------
  1607. #ifndef SS_ANSI
  1608. bool Load(UINT nId, HMODULE hModule=NULL)
  1609. {
  1610. bool bLoaded = false; // set to true of we succeed.
  1611. #ifdef _MFC_VER // When in Rome...
  1612. CString strRes;
  1613. bLoaded = FALSE != strRes.LoadString(nId);
  1614. if ( bLoaded )
  1615. *this = strRes;
  1616. #else
  1617. // Get the resource name and module handle
  1618. if ( NULL == hModule )
  1619. hModule = GetResourceHandle();
  1620. PCTSTR szName = MAKEINTRESOURCE((nId>>4)+1); // lifted 
  1621. DWORD dwSize = 0;
  1622. // No sense continuing if we can't find the resource
  1623. HRSRC hrsrc = ::FindResource(hModule, szName, RT_STRING);
  1624. if ( NULL == hrsrc )
  1625. TRACE(_T("Cannot find resource %d: 0x%X"), nId, ::GetLastError());
  1626. else if ( 0 == (dwSize = ::SizeofResource(hModule, hrsrc) / sizeof(CT)))
  1627. TRACE(_T("Cant get size of resource %d 0x%Xn"),nId,GetLastError());
  1628. else
  1629. {
  1630. bLoaded = 0 != ssload(hModule, nId, GetBuf(dwSize), dwSize);
  1631. ReleaseBuffer();
  1632. }
  1633. #endif
  1634. if ( !bLoaded )
  1635. TRACE(_T("String not loaded 0x%Xn"), ::GetLastError());
  1636. return bLoaded;
  1637. }
  1638. #endif
  1639. // -------------------------------------------------------------------------
  1640. // FUNCTION:  CStdStr::Format
  1641. // void _cdecl Formst(CStdStringA& PCSTR szFormat, ...)
  1642. // void _cdecl Format(PCSTR szFormat);
  1643. //           
  1644. // DESCRIPTION:
  1645. // This function does sprintf/wsprintf style formatting on CStdStringA
  1646. // objects.  It looks a lot like MFC's CString::Format.  Some people
  1647. // might even call this identical.  Fortunately, these people are now
  1648. // dead.
  1649. //
  1650. // PARAMETERS: 
  1651. // nId - ID of string resource holding the format string
  1652. // szFormat - a PCSTR holding the format specifiers
  1653. // argList - a va_list holding the arguments for the format specifiers.
  1654. //
  1655. // RETURN VALUE:  None.
  1656. // -------------------------------------------------------------------------
  1657. // formatting (using wsprintf style formatting)
  1658. #ifndef SS_ANSI
  1659. void Format(UINT nId, ...)
  1660. {
  1661. va_list argList;
  1662. va_start(argList, nId);
  1663. va_start(argList, nId);
  1664. MYTYPE strFmt;
  1665. if ( strFmt.Load(nId) )
  1666. FormatV(strFmt, argList);
  1667. va_end(argList);
  1668. }
  1669. #endif
  1670. void Format(const CT* szFmt, ...)
  1671. {
  1672. va_list argList;
  1673. va_start(argList, szFmt);
  1674. FormatV(szFmt, argList);
  1675. va_end(argList);
  1676. }
  1677. void AppendFormat(const CT* szFmt, ...)
  1678. {
  1679. va_list argList;
  1680. va_start(argList, szFmt);
  1681. AppendFormatV(szFmt, argList);
  1682. va_end(argList);
  1683. }
  1684. #define MAX_FMT_TRIES 5  // #of times we try 
  1685. #define FMT_BLOCK_SIZE 2048 // # of bytes to increment per try
  1686. #define BUFSIZE_1ST 256
  1687. #define BUFSIZE_2ND 512
  1688. #define STD_BUF_SIZE 1024
  1689. // an efficient way to add formatted characters to the string.  You may only
  1690. // add up to STD_BUF_SIZE characters at a time, though
  1691. void AppendFormatV(const CT* szFmt, va_list argList)
  1692. {
  1693. CT szBuf[STD_BUF_SIZE];
  1694. #ifdef SS_ANSI
  1695. int nLen = ssvsprintf(szBuf, STD_BUF_SIZE-1, szFmt, argList);
  1696. #else
  1697. int nLen = ssnprintf(szBuf, STD_BUF_SIZE-1, szFmt, argList);
  1698. #endif
  1699. if ( 0 < nLen )
  1700. append(szBuf, nLen);
  1701. }
  1702. // -------------------------------------------------------------------------
  1703. // FUNCTION:  FormatV
  1704. // void FormatV(PCSTR szFormat, va_list, argList);
  1705. //           
  1706. // DESCRIPTION:
  1707. // This function formats the string with sprintf style format-specs. 
  1708. // It makes a general guess at required buffer size and then tries
  1709. // successively larger buffers until it finds one big enough or a
  1710. // threshold (MAX_FMT_TRIES) is exceeded.
  1711. //
  1712. // PARAMETERS: 
  1713. // szFormat - a PCSTR holding the format of the output
  1714. // argList - a Microsoft specific va_list for variable argument lists
  1715. //
  1716. // RETURN VALUE: 
  1717. // -------------------------------------------------------------------------
  1718. void FormatV(const CT* szFormat, va_list argList)
  1719. {
  1720. #ifdef SS_ANSI
  1721. int nLen = sslen(szFormat) + STD_BUF_SIZE;
  1722. ssvsprintf(GetBuffer(nLen), nLen-1, szFormat, argList);
  1723. ReleaseBuffer();
  1724. #else
  1725. CT* pBuf = NULL;
  1726. int nChars = 1;
  1727. int nUsed = 0;
  1728. size_type nActual = 0;
  1729. int nTry = 0;
  1730. do
  1731. {
  1732. // Grow more than linearly (e.g. 512, 1536, 3072, etc)
  1733. nChars += ((nTry+1) * FMT_BLOCK_SIZE);
  1734. pBuf = reinterpret_cast<CT*>(_alloca(sizeof(CT)*nChars));
  1735. nUsed = ssnprintf(pBuf, nChars-1, szFormat, argList);
  1736. // Ensure proper NULL termination.
  1737. nActual = nUsed == -1 ? nChars-1 : SSMIN(nUsed, nChars-1);
  1738. pBuf[nActual+1]= '';
  1739. } while ( nUsed < 0 && nTry++ < MAX_FMT_TRIES );
  1740. // assign whatever we managed to format
  1741. assign(pBuf, nActual);
  1742. #endif
  1743. }
  1744. // -------------------------------------------------------------------------
  1745. // CString Facade Functions:
  1746. //
  1747. // The following methods are intended to allow you to use this class as a
  1748. // drop-in replacement for CString.
  1749. // -------------------------------------------------------------------------
  1750. #ifndef SS_ANSI
  1751. BSTR AllocSysString() const
  1752. {
  1753. ostring os;
  1754. ssasn(os, *this);
  1755. return ::SysAllocString(os.c_str());
  1756. }
  1757. #endif
  1758. int Collate(PCMYSTR szThat) const
  1759. {
  1760. return sscoll(c_str(), length(), szThat, sslen(szThat));
  1761. }
  1762. int CollateNoCase(PCMYSTR szThat) const
  1763. {
  1764. return ssicoll(c_str(), length(), szThat, sslen(szThat));
  1765. }
  1766. int Compare(PCMYSTR szThat) const
  1767. {
  1768. return MYBASE::compare(szThat);
  1769. }
  1770. int CompareNoCase(PCMYSTR szThat) const
  1771. {
  1772. return ssicmp(c_str(), szThat);
  1773. }
  1774. int Delete(int nIdx, int nCount=1)
  1775. {
  1776. if ( nIdx < GetLength() )
  1777. erase(static_cast<MYSIZE>(nIdx), static_cast<MYSIZE>(nCount));
  1778. return GetLength();
  1779. }
  1780. void Empty()
  1781. {
  1782. erase();
  1783. }
  1784. int Find(CT ch) const
  1785. {
  1786. MYSIZE nIdx = find_first_of(ch);
  1787. return static_cast<int>(MYBASE::npos == nIdx  ? -1 : nIdx);
  1788. }
  1789. int Find(PCMYSTR szSub) const
  1790. {
  1791. MYSIZE nIdx = find(szSub);
  1792. return static_cast<int>(MYBASE::npos == nIdx ? -1 : nIdx);
  1793. }
  1794. int Find(CT ch, int nStart) const
  1795. {
  1796. // CString::Find docs say add 1 to nStart when it's not zero
  1797. // CString::Find code doesn't do that however.  We'll stick
  1798. // with what the code does
  1799. MYSIZE nIdx = find_first_of(ch, static_cast<MYSIZE>(nStart));
  1800. return static_cast<int>(MYBASE::npos == nIdx ? -1 : nIdx);
  1801. }
  1802. int Find(PCMYSTR szSub, int nStart) const
  1803. {
  1804. // CString::Find docs say add 1 to nStart when it's not zero
  1805. // CString::Find code doesn't do that however.  We'll stick
  1806. // with what the code does
  1807. MYSIZE nIdx = find(szSub, static_cast<MYSIZE>(nStart));
  1808. return static_cast<int>(MYBASE::npos == nIdx ? -1 : nIdx);
  1809. }
  1810. int FindOneOf(PCMYSTR szCharSet) const
  1811. {
  1812. MYSIZE nIdx = find_first_of(szCharSet);
  1813. return static_cast<int>(MYBASE::npos == nIdx ? -1 : nIdx);
  1814. }
  1815. #ifndef SS_ANSI
  1816. void FormatMessage(PCMYSTR szFormat, ...) throw(std::exception)
  1817. {
  1818. va_list argList;
  1819. va_start(argList, szFormat);
  1820. PMYSTR szTemp;
  1821. if ( ssfmtmsg(FORMAT_MESSAGE_FROM_STRING|FORMAT_MESSAGE_ALLOCATE_BUFFER,
  1822.    szFormat, 0, 0,
  1823.    reinterpret_cast<PMYSTR>(&szTemp), 0, &argList) == 0 ||
  1824.  szTemp == 0 )
  1825. {
  1826. throw std::runtime_error("out of memory");
  1827. }
  1828. *this = szTemp;
  1829. LocalFree(szTemp);
  1830. va_end(argList);
  1831. }
  1832. void FormatMessage(UINT nFormatId, ...) throw(std::exception)
  1833. {
  1834. MYTYPE sFormat;
  1835. VERIFY(sFormat.LoadString(nFormatId) != 0);
  1836. va_list argList;
  1837. va_start(argList, nFormatId);
  1838. PMYSTR szTemp;
  1839. if ( ssfmtmsg(FORMAT_MESSAGE_FROM_STRING|FORMAT_MESSAGE_ALLOCATE_BUFFER,
  1840.    sFormat, 0, 0,
  1841.    reinterpret_cast<PMYSTR>(&szTemp), 0, &argList) == 0 ||
  1842. szTemp == 0)
  1843. {
  1844. throw std::runtime_error("out of memory");
  1845. }
  1846. *this = szTemp;
  1847. LocalFree(szTemp);
  1848. va_end(argList);
  1849. }
  1850. #endif
  1851. // -------------------------------------------------------------------------
  1852. // GetXXXX -- Direct access to character buffer
  1853. // -------------------------------------------------------------------------
  1854. CT GetAt(int nIdx) const
  1855. {
  1856. return at(static_cast<MYSIZE>(nIdx));
  1857. }
  1858. CT* GetBuffer(int nMinLen=-1)
  1859. {
  1860. return GetBuf(nMinLen);
  1861. }
  1862. CT* GetBufferSetLength(int nLen)
  1863. {
  1864. return BufferSet(nLen);
  1865. }
  1866. // GetLength() -- MFC docs say this is the # of BYTES but
  1867. // in truth it is the number of CHARACTERs (chars or wchar_ts)
  1868. int GetLength() const
  1869. {
  1870. return static_cast<int>(length());
  1871. }
  1872. int Insert(int nIdx, CT ch)
  1873. {
  1874. if ( static_cast<MYSIZE>(nIdx) > size() -1 )
  1875. append(1, ch);
  1876. else
  1877. insert(static_cast<MYSIZE>(nIdx), 1, ch);
  1878. return GetLength();
  1879. }
  1880. int Insert(int nIdx, PCMYSTR sz)
  1881. {
  1882. if ( nIdx >= size() )
  1883. append(sz, sslen(sz));
  1884. else
  1885. insert(static_cast<MYSIZE>(nIdx), sz);
  1886. return GetLength();
  1887. }
  1888. bool IsEmpty() const
  1889. {
  1890. return empty();
  1891. }
  1892. MYTYPE Left(int nCount) const
  1893. {
  1894. return substr(0, static_cast<MYSIZE>(nCount)); 
  1895. }
  1896. #ifndef SS_ANSI
  1897. bool LoadString(UINT nId)
  1898. {
  1899. return this->Load(nId);
  1900. }
  1901. #endif
  1902. void MakeLower()
  1903. {
  1904. ToLower();
  1905. }
  1906. void MakeReverse()
  1907. {
  1908. std::reverse(begin(), end());
  1909. }
  1910. void MakeUpper()
  1911. ToUpper();
  1912. }
  1913. MYTYPE Mid(int nFirst ) const
  1914. {
  1915. return substr(static_cast<MYSIZE>(nFirst));
  1916. }
  1917. MYTYPE Mid(int nFirst, int nCount) const
  1918. {
  1919. return substr(static_cast<MYSIZE>(nFirst), static_cast<MYSIZE>(nCount));
  1920. }
  1921. void ReleaseBuffer(int nNewLen=-1)
  1922. {
  1923. RelBuf(nNewLen);
  1924. }
  1925. int Remove(CT ch)
  1926. {
  1927. MYSIZE nIdx = 0;
  1928. int nRemoved = 0;
  1929. while ( (nIdx=find_first_of(ch)) != MYBASE::npos )
  1930. {
  1931. erase(nIdx, 1);
  1932. nRemoved++;
  1933. }
  1934. return nRemoved;
  1935. }
  1936. int Replace(CT chOld, CT chNew)
  1937. {
  1938. int nReplaced = 0;
  1939. for ( MYITER iter=begin(); iter != end(); iter++ )
  1940. {
  1941. if ( *iter == chOld )
  1942. {
  1943. *iter = chNew;
  1944. nReplaced++;
  1945. }
  1946. }
  1947. return nReplaced;
  1948. }
  1949. int Replace(PCMYSTR szOld, PCMYSTR szNew)
  1950. {
  1951. int nReplaced = 0;
  1952. MYSIZE nIdx = 0;
  1953. MYSIZE nOldLen = sslen(szOld);
  1954. if ( 0 == nOldLen )
  1955. return 0;
  1956. static const CT ch = CT(0);
  1957. MYSIZE nNewLen = sslen(szNew);
  1958. PCMYSTR szRealNew = szNew == 0 ? &ch : szNew;
  1959. while ( (nIdx=find(szOld, nIdx)) != MYBASE::npos )
  1960. {
  1961. replace(begin()+nIdx, begin()+nIdx+nOldLen, szRealNew);
  1962. nReplaced++;
  1963. nIdx += nNewLen;
  1964. }
  1965. return nReplaced;
  1966. }
  1967. int ReverseFind(CT ch) const
  1968. {
  1969. MYSIZE nIdx = find_last_of(ch);
  1970. return static_cast<int>(MYBASE::npos == nIdx ? -1 : nIdx);
  1971. }
  1972. // ReverseFind overload that's not in CString but might be useful
  1973. int ReverseFind(PCMYSTR szFind, MYSIZE pos=MYBASE::npos) const
  1974. {
  1975. MYSIZE nIdx = rfind(0 == szFind ? MYTYPE() : szFind, pos);
  1976. return static_cast<int>(MYBASE::npos == nIdx ? -1 : nIdx);
  1977. }
  1978. MYTYPE Right(int nCount) const
  1979. {
  1980. nCount = SSMIN(nCount, static_cast<int>(size()));
  1981. return substr(size()-static_cast<MYSIZE>(nCount));
  1982. }
  1983. void SetAt(int nIndex, CT ch)
  1984. {
  1985. ASSERT(size() > static_cast<MYSIZE>(nIndex));
  1986. at(static_cast<MYSIZE>(nIndex)) = ch;
  1987. }
  1988. #ifndef SS_ANSI
  1989. BSTR SetSysString(BSTR* pbstr) const
  1990. {
  1991. ostring os;
  1992. ssasn(os, *this);
  1993. if ( !::SysReAllocStringLen(pbstr, os.c_str(), os.length()) )
  1994. throw std::runtime_error("out of memory");
  1995. ASSERT(*pbstr != 0);
  1996. return *pbstr;
  1997. }
  1998. #endif
  1999. MYTYPE SpanExcluding(PCMYSTR szCharSet) const
  2000. {
  2001. return Left(find_first_of(szCharSet));
  2002. }
  2003. MYTYPE SpanIncluding(PCMYSTR szCharSet) const
  2004. {
  2005. return Left(find_first_not_of(szCharSet));
  2006. }
  2007. #if !defined(UNICODE) && !defined(SS_ANSI)
  2008. // CString's OemToAnsi and AnsiToOem functions are available only in
  2009. // Unicode builds.  However since we're a template we also need a
  2010. // runtime check of CT and a reinterpret_cast to account for the fact
  2011. // that CStdStringW gets instantiated even in non-Unicode builds.
  2012. void AnsiToOem()
  2013. {
  2014. if ( sizeof(CT) == sizeof(char) && !empty() )
  2015. {
  2016. ::CharToOem(reinterpret_cast<PCSTR>(c_str()),
  2017. reinterpret_cast<PSTR>(GetBuf()));
  2018. }
  2019. else
  2020. {
  2021. ASSERT(false);
  2022. }
  2023. }
  2024. void OemToAnsi()
  2025. {
  2026. if ( sizeof(CT) == sizeof(char) && !empty() )
  2027. {
  2028. ::OemToChar(reinterpret_cast<PCSTR>(c_str()),
  2029. reinterpret_cast<PSTR>(GetBuf()));
  2030. }
  2031. else
  2032. {
  2033. ASSERT(false);
  2034. }
  2035. }
  2036. #endif
  2037. // -------------------------------------------------------------------------
  2038. // Trim and its variants
  2039. // -------------------------------------------------------------------------
  2040. MYTYPE& Trim()
  2041. {
  2042. return TrimLeft().TrimRight();
  2043. }
  2044. MYTYPE& TrimLeft()
  2045. {
  2046. erase(begin(), std::find_if(begin(),end(),NotSpace<CT>(std::locale())));
  2047. return *this;
  2048. }
  2049. MYTYPE&  TrimLeft(CT tTrim)
  2050. {
  2051. erase(0, find_first_not_of(tTrim));
  2052. return *this;
  2053. }
  2054. MYTYPE&  TrimLeft(PCMYSTR szTrimChars)
  2055. {
  2056. erase(0, find_first_not_of(szTrimChars));
  2057. return *this;
  2058. }
  2059. MYTYPE& TrimRight()
  2060. {
  2061. std::locale loc;
  2062. MYRITER it = std::find_if(rbegin(), rend(), NotSpace<CT>(loc));
  2063. if ( rend() != it )
  2064. erase(rend() - it);
  2065. erase(it != rend() ? find_last_of(*it) + 1 : 0);
  2066. return *this;
  2067. }
  2068. MYTYPE&  TrimRight(CT tTrim)
  2069. {
  2070. MYSIZE nIdx = find_last_not_of(tTrim);
  2071. erase(MYBASE::npos == nIdx ? 0 : ++nIdx);
  2072. return *this;
  2073. }
  2074. MYTYPE&  TrimRight(PCMYSTR szTrimChars)
  2075. {
  2076. MYSIZE nIdx = find_last_not_of(szTrimChars);
  2077. erase(MYBASE::npos == nIdx ? 0 : ++nIdx);
  2078. return *this;
  2079. }
  2080. void FreeExtra()
  2081. {
  2082. MYTYPE mt;
  2083. swap(mt);
  2084. if ( !mt.empty() )
  2085. assign(mt.c_str(), mt.size());
  2086. }
  2087. // I have intentionally not implemented the following CString
  2088. // functions.   You cannot make them work without taking advantage
  2089. // of implementation specific behavior.  However if you absolutely
  2090. // MUST have them, uncomment out these lines for "sort-of-like"
  2091. // their behavior.  You're on your own.
  2092. // CT* LockBuffer() { return GetBuf(); }// won't really lock
  2093. // void UnlockBuffer(); { } // why have UnlockBuffer w/o LockBuffer?
  2094. // Array-indexing operators.  Required because we defined an implicit cast
  2095. // to operator const CT* (Thanks to Julian Selman for pointing this out)
  2096. CT& operator[](int nIdx)
  2097. {
  2098. return MYBASE::operator[](static_cast<MYSIZE>(nIdx));
  2099. }
  2100. const CT& operator[](int nIdx) const
  2101. {
  2102. return MYBASE::operator[](static_cast<MYSIZE>(nIdx));
  2103. }
  2104. CT& operator[](unsigned int nIdx)
  2105. {
  2106. return MYBASE::operator[](static_cast<MYSIZE>(nIdx));
  2107. }
  2108. const CT& operator[](unsigned int nIdx) const
  2109. {
  2110. return MYBASE::operator[](static_cast<MYSIZE>(nIdx));
  2111. }
  2112. operator const CT*() const
  2113. {
  2114. return c_str();
  2115. }
  2116. // IStream related functions.  Useful in IPersistStream implementations
  2117. #ifdef SS_INC_COMDEF
  2118. // struct SSSHDR - useful for non Std C++ persistence schemes.
  2119. typedef struct SSSHDR
  2120. {
  2121. BYTE byCtrl;
  2122. ULONG nChars;
  2123. } SSSHDR; // as in "Standard String Stream Header"
  2124. #define SSSO_UNICODE 0x01 // the string is a wide string
  2125. #define SSSO_COMPRESS 0x02 // the string is compressed
  2126. // -------------------------------------------------------------------------
  2127. // FUNCTION: StreamSize
  2128. // REMARKS:
  2129. // Returns how many bytes it will take to StreamSave() this CStdString
  2130. // object to an IStream.
  2131. // -------------------------------------------------------------------------
  2132. ULONG StreamSize() const
  2133. {
  2134. // Control header plus string
  2135. ASSERT(size()*sizeof(CT) < 0xffffffffUL - sizeof(SSSHDR));
  2136. return (size() * sizeof(CT)) + sizeof(SSSHDR);
  2137. }
  2138. // -------------------------------------------------------------------------
  2139. // FUNCTION: StreamSave
  2140. // REMARKS:
  2141. // Saves this CStdString object to a COM IStream.
  2142. // -------------------------------------------------------------------------
  2143. HRESULT StreamSave(IStream* pStream) const
  2144. {
  2145. ASSERT(size()*sizeof(CT) < 0xffffffffUL - sizeof(SSSHDR));
  2146. HRESULT hr = E_FAIL;
  2147. ASSERT(pStream != 0);
  2148. SSSHDR hdr;
  2149. hdr.byCtrl = sizeof(CT) == 2 ? SSSO_UNICODE : 0;
  2150. hdr.nChars = size();
  2151. if ( FAILED(hr=pStream->Write(&hdr, sizeof(SSSHDR), 0)) )
  2152. TRACE(_T("StreamSave: Cannot write control header, ERR=0x%Xn"),hr);
  2153. else if ( empty() )
  2154. ; // nothing to write
  2155. else if ( FAILED(hr=pStream->Write(c_str(), size()*sizeof(CT), 0)) )
  2156. TRACE(_T("StreamSave: Cannot write string to stream 0x%Xn"), hr);
  2157. return hr;
  2158. }
  2159. // -------------------------------------------------------------------------
  2160. // FUNCTION: StreamLoad
  2161. // REMARKS:
  2162. // This method loads the object from an IStream.
  2163. // -------------------------------------------------------------------------
  2164. HRESULT StreamLoad(IStream* pStream)
  2165. {
  2166. ASSERT(pStream != 0);
  2167. SSSHDR hdr;
  2168. HRESULT hr = E_FAIL;
  2169. if ( FAILED(hr=pStream->Read(&hdr, sizeof(SSSHDR), 0)) )
  2170. {
  2171. TRACE(_T("StreamLoad: Cant read control header, ERR=0x%Xn"), hr);
  2172. }
  2173. else if ( hdr.nChars > 0 )
  2174. {
  2175. ULONG nRead = 0;
  2176. PMYSTR pMyBuf = BufferSet(hdr.nChars);
  2177. // If our character size matches the character size of the string
  2178. // we're trying to read, then we can read it directly into our
  2179. // buffer. Otherwise, we have to read into an intermediate buffer
  2180. // and convert.
  2181. if ( (hdr.byCtrl & SSSO_UNICODE) != 0 )
  2182. {
  2183. ULONG nBytes = hdr.nChars * sizeof(wchar_t);
  2184. if ( sizeof(CT) == sizeof(wchar_t) )
  2185. {
  2186. if ( FAILED(hr=pStream->Read(pMyBuf, nBytes, &nRead)) )
  2187. TRACE(_T("StreamLoad: Cannot read string: 0x%Xn"), hr);
  2188. }
  2189. else
  2190. {
  2191. PWSTR pBufW = reinterpret_cast<PWSTR>(_alloca((nBytes)+1));
  2192. if ( FAILED(hr=pStream->Read(pBufW, nBytes, &nRead)) )
  2193. TRACE(_T("StreamLoad: Cannot read string: 0x%Xn"), hr);
  2194. else
  2195. sscpy(pMyBuf, pBufW, hdr.nChars);
  2196. }
  2197. }
  2198. else
  2199. {
  2200. ULONG nBytes = hdr.nChars * sizeof(char);
  2201. if ( sizeof(CT) == sizeof(char) )
  2202. {
  2203. if ( FAILED(hr=pStream->Read(pMyBuf, nBytes, &nRead)) )
  2204. TRACE(_T("StreamLoad: Cannot read string: 0x%Xn"), hr);
  2205. }
  2206. else
  2207. {
  2208. PSTR pBufA = reinterpret_cast<PSTR>(_alloca(nBytes));
  2209. if ( FAILED(hr=pStream->Read(pBufA, hdr.nChars, &nRead)) )
  2210. TRACE(_T("StreamLoad: Cannot read string: 0x%Xn"), hr);
  2211. else
  2212. sscpy(pMyBuf, pBufA, hdr.nChars);
  2213. }
  2214. }
  2215. }
  2216. else
  2217. {
  2218. this->erase();
  2219. }
  2220. return hr;
  2221. }
  2222. #endif // #ifdef SS_INC_COMDEF
  2223. #ifndef SS_ANSI
  2224. // SetResourceHandle/GetResourceHandle.  In MFC builds, these map directly
  2225. // to AfxSetResourceHandle and AfxGetResourceHandle.  In non-MFC builds they
  2226. // point to a single static HINST so that those who call the member
  2227. // functions that take resource IDs can provide an alternate HINST of a DLL
  2228. // to search.  This is not exactly the list of HMODULES that MFC provides
  2229. // but it's better than nothing.
  2230. #ifdef _MFC_VER
  2231. static void SetResourceHandle(HMODULE hNew)
  2232. {
  2233. AfxSetResourceHandle(hNew);
  2234. }
  2235. static HMODULE GetResourceHandle()
  2236. {
  2237. return AfxGetResourceHandle();
  2238. }
  2239. #else
  2240. static void SetResourceHandle(HMODULE hNew)
  2241. {
  2242. SSResourceHandle() = hNew;
  2243. }
  2244. static HMODULE GetResourceHandle()
  2245. {
  2246. return SSResourceHandle();
  2247. }
  2248. #endif
  2249. #endif
  2250. };
  2251. // -----------------------------------------------------------------------------
  2252. // CStdStr friend addition functions defined as inline
  2253. // -----------------------------------------------------------------------------
  2254. template<typename CT>
  2255. inline
  2256. CStdStr<CT> operator+(const  CStdStr<CT>& str1, const  CStdStr<CT>& str2)
  2257. {
  2258. CStdStr<CT> strRet(SSREF(str1));
  2259. strRet.append(str2);
  2260. return strRet;
  2261. }
  2262. template<typename CT>
  2263. inline
  2264. CStdStr<CT> operator+(const  CStdStr<CT>& str, CT t)
  2265. {
  2266. // this particular overload is needed for disabling reference counting
  2267. // though it's only an issue from line 1 to line 2
  2268. CStdStr<CT> strRet(SSREF(str)); // 1
  2269. strRet.append(1, t); // 2
  2270. return strRet;
  2271. }
  2272. template<typename CT>
  2273. inline
  2274. CStdStr<CT> operator+(const  CStdStr<CT>& str, PCSTR pA)
  2275. {
  2276. return CStdStr<CT>(str) + CStdStr<CT>(pA);
  2277. }
  2278. template<typename CT>
  2279. inline
  2280. CStdStr<CT> operator+(PCSTR pA, const  CStdStr<CT>& str)
  2281. {
  2282. CStdStr<CT> strRet(pA);
  2283. strRet.append(str);
  2284. return strRet;
  2285. }
  2286. template<typename CT>
  2287. inline
  2288. CStdStr<CT> operator+(const CStdStr<CT>& str, PCWSTR pW)
  2289. return CStdStr<CT>(SSREF(str)) + CStdStr<CT>(pW);
  2290. }
  2291. template<typename CT>
  2292. inline
  2293. CStdStr<CT> operator+(PCWSTR pW, const CStdStr<CT>& str)
  2294. {
  2295. CStdStr<CT> strRet(pW);
  2296. strRet.append(str);
  2297. return strRet;
  2298. }
  2299. #ifdef SS_INC_COMDEF
  2300. template<typename CT>
  2301. inline
  2302. CStdStr<CT> operator+(const _bstr_t& bstr, const CStdStr<CT>& str)
  2303. {
  2304. return static_cast<const CT*>(bstr) + str;
  2305. }
  2306. template<typename CT>
  2307. inline
  2308. CStdStr<CT> operator+(const CStdStr<CT>& str, const _bstr_t& bstr)
  2309. {
  2310. return str + static_cast<const CT*>(bstr);
  2311. }
  2312. #endif
  2313. // -----------------------------------------------------------------------------
  2314. // These versions of operator+ provided by Scott Hathaway in order to allow
  2315. // CStdString to build on Sun Unix systems.
  2316. // -----------------------------------------------------------------------------
  2317. #if defined(__SUNPRO_CC_COMPAT) || defined(__SUNPRO_CC)
  2318. // Made non-template versions due to "undefined" errors on Sun Forte compiler
  2319. // when linking with friend template functions
  2320. inline
  2321. CStdStr<wchar_t> operator+(const CStdStr<wchar_t>& str1,
  2322.    const CStdStr<wchar_t>& str2)
  2323. {
  2324. CStdStr<wchar_t> strRet(SSREF(str1));
  2325. strRet.append(str2);
  2326. return strRet;
  2327. }
  2328. inline
  2329. CStdStr<wchar_t> operator+(const CStdStr<wchar_t>& str, wchar_t t)
  2330. {
  2331. // this particular overload is needed for disabling reference counting
  2332. // though it's only an issue from line 1 to line 2
  2333. CStdStr<wchar_t> strRet(SSREF(str)); // 1
  2334. strRet.append(1, t); // 2
  2335. return strRet;
  2336. }
  2337. inline
  2338. CStdStr<wchar_t> operator+(const CStdStr<wchar_t>& str, PCWSTR pW)
  2339. {
  2340. return CStdStr<wchar_t>(str) + CStdStr<wchar_t>(pW);
  2341. }
  2342. inline
  2343. CStdStr<wchar_t> operator+(PCWSTR pA, const  CStdStr<wchar_t>& str)
  2344. {
  2345. CStdStr<wchar_t> strRet(pA);
  2346. strRet.append(str);
  2347. return strRet;
  2348. }
  2349. inline
  2350. CStdStr<wchar_t> operator+(const CStdStr<wchar_t>& str, PCSTR pW)
  2351. return CStdStr<wchar_t>(SSREF(str)) + CStdStr<wchar_t>(pW);
  2352. }
  2353. inline
  2354. CStdStr<wchar_t> operator+(PCSTR pW, const CStdStr<wchar_t>& str)
  2355. {
  2356. CStdStr<wchar_t> strRet(pW);
  2357. strRet.append(str);
  2358. return strRet;
  2359. }
  2360. inline
  2361. CStdStr<char> operator+(const  CStdStr<char>& str1, const  CStdStr<char>& str2)
  2362. {
  2363. CStdStr<char> strRet(SSREF(str1));
  2364. strRet.append(str2);
  2365. return strRet;
  2366. }
  2367. inline
  2368. CStdStr<char> operator+(const  CStdStr<char>& str, char t)
  2369. {
  2370. // this particular overload is needed for disabling reference counting
  2371. // though it's only an issue from line 1 to line 2
  2372. CStdStr<char> strRet(SSREF(str)); // 1
  2373. strRet.append(1, t); // 2
  2374. return strRet;
  2375. }
  2376. inline
  2377. CStdStr<char> operator+(const  CStdStr<char>& str, PCSTR pA)
  2378. {
  2379. return CStdStr<char>(str) + CStdStr<char>(pA);
  2380. }
  2381. inline
  2382. CStdStr<char> operator+(PCSTR pA, const  CStdStr<char>& str)
  2383. {
  2384. CStdStr<char> strRet(pA);
  2385. strRet.append(str);
  2386. return strRet;
  2387. }
  2388. inline
  2389. CStdStr<char> operator+(const CStdStr<char>& str, PCWSTR pW)
  2390. return CStdStr<char>(SSREF(str)) + CStdStr<char>(pW);
  2391. }
  2392. inline
  2393. CStdStr<char> operator+(PCWSTR pW, const CStdStr<char>& str)
  2394. {
  2395. CStdStr<char> strRet(pW);
  2396. strRet.append(str);
  2397. return strRet;
  2398. }
  2399. #endif // defined(__SUNPRO_CC_COMPAT) || defined(__SUNPRO_CC)
  2400. // =============================================================================
  2401. // END OF CStdStr INLINE FUNCTION DEFINITIONS
  2402. // =============================================================================
  2403. // Now typedef our class names based upon this humongous template
  2404. typedef CStdStr<char> CStdStringA; // a better std::string
  2405. typedef CStdStr<wchar_t> CStdStringW; // a better std::wstring
  2406. typedef CStdStr<OLECHAR> CStdStringO; // almost always CStdStringW
  2407. #ifndef SS_ANSI
  2408. // SSResourceHandle: our MFC-like resource handle
  2409. inline HMODULE& SSResourceHandle()
  2410. {
  2411. static HMODULE hModuleSS = GetModuleHandle(0);
  2412. return hModuleSS;
  2413. }
  2414. #endif
  2415. // In MFC builds, define some global serialization operators
  2416. // Special operators that allow us to serialize CStdStrings to CArchives.
  2417. // Note that we use an intermediate CString object in order to ensure that
  2418. // we use the exact same format.
  2419. #ifdef _MFC_VER
  2420. inline CArchive& AFXAPI operator<<(CArchive& ar, const CStdStringA& strA)
  2421. {
  2422. CString strTemp = strA;
  2423. return ar << strTemp;
  2424. }
  2425. inline CArchive& AFXAPI operator<<(CArchive& ar, const CStdStringW& strW)
  2426. {
  2427. CString strTemp = strW;
  2428. return ar << strTemp;
  2429. }
  2430. inline CArchive& AFXAPI operator>>(CArchive& ar, CStdStringA& strA)
  2431. {
  2432. CString strTemp;
  2433. ar >> strTemp;
  2434. strA = strTemp;
  2435. return ar;
  2436. }
  2437. inline CArchive& AFXAPI operator>>(CArchive& ar, CStdStringW& strW)
  2438. {
  2439. CString strTemp;
  2440. ar >> strTemp;
  2441. strW = strTemp;
  2442. return ar;
  2443. }
  2444. #endif // #ifdef _MFC_VER -- (i.e. is this MFC?)
  2445. // -----------------------------------------------------------------------------
  2446. // HOW TO EXPORT CSTDSTRING FROM A DLL
  2447. //
  2448. // If you want to export CStdStringA and CStdStringW from a DLL, then all you
  2449. // need to
  2450. // 1. make sure that all components link to the same DLL version
  2451. // of the CRT (not the static one).
  2452. // 2. Uncomment the 3 lines of code below
  2453. // 3. #define 2 macros per the instructions in MS KnowledgeBase
  2454. // article Q168958.  The macros are:
  2455. //
  2456. // MACRO DEFINTION WHEN EXPORTING DEFINITION WHEN IMPORTING
  2457. // ----- ------------------------ -------------------------
  2458. // SSDLLEXP (nothing, just #define it) extern
  2459. // SSDLLSPEC __declspec(dllexport) __declspec(dllimport)
  2460. //
  2461. // Note that these macros must be available to ALL clients who want to 
  2462. // link to the DLL and use the class.  If they 
  2463. // -----------------------------------------------------------------------------
  2464. //#pragma warning(disable:4231) // non-standard extension ("extern template")
  2465. // SSDLLEXP template class SSDLLSPEC CStdStr<char>;
  2466. // SSDLLEXP template class SSDLLSPEC CStdStr<wchar_t>;
  2467. // -----------------------------------------------------------------------------
  2468. // GLOBAL FUNCTION:  WUFormat
  2469. // CStdStringA WUFormat(UINT nId, ...);
  2470. // CStdStringA WUFormat(PCSTR szFormat, ...);
  2471. //
  2472. // REMARKS:
  2473. // This function allows the caller for format and return a CStdStringA
  2474. // object with a single line of code.
  2475. // -----------------------------------------------------------------------------
  2476. #ifdef SS_ANSI
  2477. #else
  2478. inline CStdStringA WUFormatA(UINT nId, ...)
  2479. {
  2480. va_list argList;
  2481. va_start(argList, nId);
  2482. CStdStringA strFmt;
  2483. CStdStringA strOut;
  2484. if ( strFmt.Load(nId) )
  2485. strOut.FormatV(strFmt, argList);
  2486. va_end(argList);
  2487. return strOut;
  2488. }
  2489. inline CStdStringA WUFormatA(PCSTR szFormat, ...)
  2490. {
  2491. va_list argList;
  2492. va_start(argList, szFormat);
  2493. CStdStringA strOut;
  2494. strOut.FormatV(szFormat, argList);
  2495. va_end(argList);
  2496. return strOut;
  2497. }
  2498. inline CStdStringW WUFormatW(UINT nId, ...)
  2499. {
  2500. va_list argList;
  2501. va_start(argList, nId);
  2502. CStdStringW strFmt;
  2503. CStdStringW strOut;
  2504. if ( strFmt.Load(nId) )
  2505. strOut.FormatV(strFmt, argList);
  2506. va_end(argList);
  2507. return strOut;
  2508. }
  2509. inline CStdStringW WUFormatW(PCWSTR szwFormat, ...)
  2510. {
  2511. va_list argList;
  2512. va_start(argList, szwFormat);
  2513. CStdStringW strOut;
  2514. strOut.FormatV(szwFormat, argList);
  2515. va_end(argList);
  2516. return strOut;
  2517. }
  2518. #endif // #ifdef SS_ANSI
  2519. #ifdef SS_ANSI
  2520. #else
  2521. // -------------------------------------------------------------------------
  2522. // FUNCTION: WUSysMessage
  2523. //  CStdStringA WUSysMessageA(DWORD dwError, DWORD dwLangId=SS_DEFLANGID);
  2524. //  CStdStringW WUSysMessageW(DWORD dwError, DWORD dwLangId=SS_DEFLANGID);
  2525. //           
  2526. // DESCRIPTION:
  2527. //  This function simplifies the process of obtaining a string equivalent
  2528. //  of a system error code returned from GetLastError().  You simply
  2529. //  supply the value returned by GetLastError() to this function and the
  2530. //  corresponding system string is returned in the form of a CStdStringA.
  2531. //
  2532. // PARAMETERS: 
  2533. //  dwError - a DWORD value representing the error code to be translated
  2534. //  dwLangId - the language id to use.  defaults to english.
  2535. //
  2536. // RETURN VALUE: 
  2537. //  a CStdStringA equivalent of the error code.  Currently, this function
  2538. //  only returns either English of the system default language strings.  
  2539. // -------------------------------------------------------------------------
  2540. #define SS_DEFLANGID MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT)
  2541. inline CStdStringA WUSysMessageA(DWORD dwError, DWORD dwLangId=SS_DEFLANGID)
  2542. {
  2543. CHAR szBuf[512];
  2544. if ( 0 != ::FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, NULL, dwError,
  2545.    dwLangId, szBuf, 511, NULL) )
  2546. return WUFormatA("%s (0x%X)", szBuf, dwError);
  2547. else
  2548.   return WUFormatA("Unknown error (0x%X)", dwError);
  2549. }
  2550. inline CStdStringW WUSysMessageW(DWORD dwError, DWORD dwLangId=SS_DEFLANGID)
  2551. {
  2552. WCHAR szBuf[512];
  2553. if ( 0 != ::FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM, NULL, dwError,
  2554.    dwLangId, szBuf, 511, NULL) )
  2555. return WUFormatW(L"%s (0x%X)", szBuf, dwError);
  2556. else
  2557.   return WUFormatW(L"Unknown error (0x%X)", dwError);
  2558. }
  2559. #endif
  2560. // Define TCHAR based friendly names for some of these functions
  2561. #ifdef UNICODE
  2562. #define CStdString CStdStringW
  2563. #define WUSysMessage WUSysMessageW
  2564. #define WUFormat WUFormatW
  2565. #else
  2566. #define CStdString CStdStringA
  2567. #define WUSysMessage WUSysMessageA
  2568. #define WUFormat WUFormatA
  2569. #endif
  2570. // ...and some shorter names for the space-efficient
  2571. #define WUSysMsg WUSysMessage
  2572. #define WUSysMsgA WUSysMessageA
  2573. #define WUSysMsgW WUSysMessageW
  2574. #define WUFmtA WUFormatA
  2575. #define WUFmtW WUFormatW
  2576. #define WUFmt WUFormat
  2577. #define WULastErrMsg() WUSysMessage(::GetLastError())
  2578. #define WULastErrMsgA() WUSysMessageA(::GetLastError())
  2579. #define WULastErrMsgW() WUSysMessageW(::GetLastError())
  2580. // -----------------------------------------------------------------------------
  2581. // FUNCTIONAL COMPARATORS:
  2582. // REMARKS:
  2583. // These structs are derived from the std::binary_function template.  They
  2584. // give us functional classes (which may be used in Standard C++ Library
  2585. // collections and algorithms) that perform case-insensitive comparisons of
  2586. // CStdString objects.  This is useful for maps in which the key may be the
  2587. //  proper string but in the wrong case.
  2588. // -----------------------------------------------------------------------------
  2589. #define StdStringLessNoCaseW SSLNCW // avoid VC compiler warning 4786
  2590. #define StdStringEqualsNoCaseW SSENCW
  2591. #define StdStringLessNoCaseA SSLNCA
  2592. #define StdStringEqualsNoCaseA SSENCA
  2593. #ifdef UNICODE
  2594. #define StdStringLessNoCase SSLNCW
  2595. #define StdStringEqualsNoCase SSENCW
  2596. #else
  2597. #define StdStringLessNoCase SSLNCA
  2598. #define StdStringEqualsNoCase SSENCA
  2599. #endif
  2600. struct StdStringLessNoCaseW
  2601. : std::binary_function<CStdStringW, CStdStringW, bool>
  2602. {
  2603. inline
  2604. bool operator()(const CStdStringW& sLeft, const CStdStringW& sRight) const
  2605. { return ssicmp(sLeft.c_str(), sRight.c_str()) < 0; }
  2606. };
  2607. struct StdStringEqualsNoCaseW
  2608. : std::binary_function<CStdStringW, CStdStringW, bool>
  2609. {
  2610. inline
  2611. bool operator()(const CStdStringW& sLeft, const CStdStringW& sRight) const
  2612. { return ssicmp(sLeft.c_str(), sRight.c_str()) == 0; }
  2613. };
  2614. struct StdStringLessNoCaseA
  2615. : std::binary_function<CStdStringA, CStdStringA, bool>
  2616. {
  2617. inline
  2618. bool operator()(const CStdStringA& sLeft, const CStdStringA& sRight) const
  2619. { return ssicmp(sLeft.c_str(), sRight.c_str()) < 0; }
  2620. };
  2621. struct StdStringEqualsNoCaseA
  2622. : std::binary_function<CStdStringA, CStdStringA, bool>
  2623. {
  2624. inline
  2625. bool operator()(const CStdStringA& sLeft, const CStdStringA& sRight) const
  2626. { return ssicmp(sLeft.c_str(), sRight.c_str()) == 0; }
  2627. };
  2628. // If we had to define our own version of TRACE above, get rid of it now
  2629. #ifdef TRACE_DEFINED_HERE
  2630. #undef TRACE
  2631. #undef TRACE_DEFINED_HERE
  2632. #endif
  2633. #endif // #ifndef STDSTRING_H