首页 > 代码库 > 跨平台的CStdString类,实现了CString的接口

跨平台的CStdString类,实现了CString的接口

在实际工作中,std的string功能相对于MFC的CString来说,实在是相形见绌。

CStdString类实现了CString的功能,支持跨平台。

   1 // =============================================================================   2 //  FILE:  StdString.h   3 //  AUTHOR:    Joe O‘Leary (with outside help noted in comments)   4     //   5 //        If you find any bugs in this code, please let me know:   6 //   7 //                jmoleary@earthlink.net   8 //                http://www.joeo.net/stdstring.htm (a bit outdated)   9 //  10 //      The latest version of this code should always be available at the  11 //      following link:  12 //  13 //              http://www.joeo.net/code/StdString.zip (Dec 6, 2003)  14 //  15 //  16 //  REMARKS:  17 //        This header file declares the CStdStr template.  This template derives  18 //        the Standard C++ Library basic_string<> template and add to it the  19 //        the following conveniences:  20 //            - The full MFC CString set of functions (including implicit cast)  21 //            - writing to/reading from COM IStream interfaces  22 //            - Functional objects for use in STL algorithms  23 //  24 //        From this template, we intstantiate two classes:  CStdStringA and  25 //        CStdStringW.  The name "CStdString" is just a #define of one of these,  26 //        based upone the UNICODE macro setting  27 //  28 //        This header also declares our own version of the MFC/ATL UNICODE-MBCS  29 //        conversion macros.  Our version looks exactly like the Microsoft‘s to  30 //        facilitate portability.  31 //  32 //    NOTE:  33 //        If you you use this in an MFC or ATL build, you should include either  34 //        afx.h or atlbase.h first, as appropriate.  35 //  36 //    PEOPLE WHO HAVE CONTRIBUTED TO THIS CLASS:  37 //  38 //        Several people have helped me iron out problems and othewise improve  39 //        this class.  OK, this is a long list but in my own defense, this code  40 //        has undergone two major rewrites.  Many of the improvements became  41 //        necessary after I rewrote the code as a template.  Others helped me  42 //        improve the CString facade.  43 //  44 //        Anyway, these people are (in chronological order):  45 //  46 //            - Pete the Plumber (???)  47 //            - Julian Selman  48 //            - Chris (of Melbsys)  49 //            - Dave Plummer  50 //            - John C Sipos  51 //            - Chris Sells  52 //            - Nigel Nunn  53 //            - Fan Xia  54 //            - Matthew Williams  55 //            - Carl Engman  56 //            - Mark Zeren  57 //            - Craig Watson  58 //            - Rich Zuris  59 //            - Karim Ratib  60 //            - Chris Conti  61 //            - Baptiste Lepilleur  62 //            - Greg Pickles  63 //            - Jim Cline  64 //            - Jeff Kohn  65 //            - Todd Heckel  66 //            - Ullrich Poll鋒ne  67 //            - Joe Vitaterna  68 //            - Joe Woodbury  69 //            - Aaron (no last name)  70 //            - Joldakowski (???)  71 //            - Scott Hathaway  72 //            - Eric Nitzche  73 //            - Pablo Presedo  74 //            - Farrokh Nejadlotfi  75 //            - Jason Mills  76 //            - Igor Kholodov  77 //            - Mike Crusader  78 //            - John James  79 //            - Wang Haifeng  80 //            - Tim Dowty  81 //          - Arnt Witteveen  82 //          - Glen Maynard  83 //          - Paul DeMarco  84 //          - Bagira (full name?)  85 //          - Ronny Schulz  86 //          - Jakko Van Hunen  87 //            - Charles Godwin  88 //            - Henk Demper  89 //            - Greg Marr  90 //            - Bill Carducci  91 //            - Brian Groose  92 //            - MKingman  93 //            - Don Beusee  94 //  95 //    REVISION HISTORY  96 //  97 //      2005-JAN-10 - Thanks to Don Beusee for pointing out the danger in mapping  98 //                    length-checked formatting functions to non-length-checked  99 //                    CRT equivalents.  Also thanks to him for motivating me to 100 //                    optimize my implementation of Replace() 101 // 102 //      2004-APR-22 - A big, big thank you to "MKingman" (whoever you are) for 103 //                    finally spotting a silly little error in StdCodeCvt that 104 //                    has been causing me (and users of CStdString) problems for 105 //                    years in some relatively rare conversions.  I had reversed 106 //                    two length arguments.  107 // 108 //    2003-NOV-24 - Thanks to a bunch of people for helping me clean up many 109 //                    compiler warnings (and yes, even a couple of actual compiler 110 //                    errors).  These include Henk Demper for figuring out how 111 //                    to make the Intellisense work on with CStdString on VC6, 112 //                    something I was never able to do.  Greg Marr pointed out 113 //                    a compiler warning about an unreferenced symbol and a 114 //                    problem with my version of Load in MFC builds.  Bill 115 //                    Carducci took a lot of time with me to help me figure out 116 //                    why some implementations of the Standard C++ Library were 117 //                    returning error codes for apparently successful conversions 118 //                    between ASCII and UNICODE.  Finally thanks to Brian Groose 119 //                    for helping me fix compiler signed unsigned warnings in 120 //                    several functions. 121 // 122 //    2003-JUL-10 - Thanks to Charles Godwin for making me realize my ‘FmtArg‘ 123 //                    fixes had inadvertently broken the DLL-export code (which is 124 //                  normally commented out.  I had to move it up higher.  Also 125 //                    this helped me catch a bug in ssicoll that would prevent 126 //                  compilation, otherwise. 127 // 128 //    2003-MAR-14 - Thanks to Jakko Van Hunen for pointing out a copy-and-paste 129 //                  bug in one of the overloads of FmtArg. 130 // 131 //    2003-MAR-10 - Thanks to Ronny Schulz for (twice!) sending me some changes 132 //                  to help CStdString build on SGI and for pointing out an 133 //                  error in placement of my preprocessor macros for ssfmtmsg. 134 // 135 //    2002-NOV-26 - Thanks to Bagira for pointing out that my implementation of 136 //                  SpanExcluding was not properly handling the case in which 137 //                  the string did NOT contain any of the given characters 138 // 139 //    2002-OCT-21 - Many thanks to Paul DeMarco who was invaluable in helping me 140 //                  get this code working with Borland‘s free compiler as well 141 //                  as the Dev-C++ compiler (available free at SourceForge). 142 // 143 //    2002-SEP-13 - Thanks to Glen Maynard who helped me get rid of some loud 144 //                  but harmless warnings that were showing up on g++.  Glen 145 //                  also pointed out that some pre-declarations of FmtArg<> 146 //                  specializations were unnecessary (and no good on G++) 147 // 148 //    2002-JUN-26 - Thanks to Arnt Witteveen for pointing out that I was using 149 //                  static_cast<> in a place in which I should have been using 150 //                  reinterpret_cast<> (the ctor for unsigned char strings). 151 //                  That‘s what happens when I don‘t unit-test properly! 152 //                  Arnt also noticed that CString was silently correcting the 153 //                  ‘nCount‘ argument to Left() and Right() where CStdString was 154 //                  not (and crashing if it was bad).  That is also now fixed! 155 // 156 //      2002-FEB-25 - Thanks to Tim Dowty for pointing out (and giving me the fix 157 //                    for) a conversion problem with non-ASCII MBCS characters. 158 //                    CStdString is now used in my favorite commercial MP3 player! 159 // 160 //      2001-DEC-06 - Thanks to Wang Haifeng for spotting a problem in one of the 161 //                    assignment operators (for _bstr_t) that would cause compiler 162 //                    errors when refcounting protection was turned off. 163 // 164 //      2001-NOV-27 - Remove calls to operator!= which involve reverse_iterators 165 //                    due to a conflict with the rel_ops operator!=.  Thanks to 166 //                    John James for pointing this out. 167 // 168 //    2001-OCT-29 - Added a minor range checking fix for the Mid function to 169 //                    make it as forgiving as CString‘s version is.  Thanks to 170 //                    Igor Kholodov for noticing this.   171 //                  - Added a specialization of std::swap for CStdString.  Thanks 172 //                    to Mike Crusader for suggesting this!  It‘s commented out 173 //                    because you‘re not supposed to inject your own code into the 174 //                    ‘std‘ namespace.  But if you don‘t care about that, it‘s 175 //                    there if you want it 176 //                  - Thanks to Jason Mills for catching a case where CString was 177 //                    more forgiving in the Delete() function than I was. 178 // 179 //      2001-JUN-06 - I was violating the Standard name lookup rules stated 180 //                    in [14.6.2(3)].  None of the compilers I‘ve tried so 181 //                    far apparently caught this but HP-UX aCC 3.30 did.  The 182 //                    fix was to add ‘this->‘ prefixes in many places. 183 //                    Thanks to Farrokh Nejadlotfi for this! 184 // 185 //      2001-APR-27 - StreamLoad was calculating the number of BYTES in one 186 //                    case, not characters.  Thanks to Pablo Presedo for this. 187 // 188 //    2001-FEB-23 - Replace() had a bug which caused infinite loops if the 189 //                    source string was empty.  Fixed thanks to Eric Nitzsche. 190 // 191 //    2001-FEB-23 - Scott Hathaway was a huge help in providing me with the 192 //                    ability to build CStdString on Sun Unix systems.  He 193 //                    sent me detailed build reports about what works and what 194 //                    does not.  If CStdString compiles on your Unix box, you 195 //                    can thank Scott for it. 196 // 197 //      2000-DEC-29 - Joldakowski noticed one overload of Insert failed to do a 198 //                    range check as CString‘s does.  Now fixed -- thanks! 199 // 200 //      2000-NOV-07 - Aaron pointed out that I was calling static member 201 //                    functions of char_traits via a temporary.  This was not 202 //                    technically wrong, but it was unnecessary and caused 203 //                    problems for poor old buggy VC5.  Thanks Aaron! 204 // 205 //      2000-JUL-11 - Joe Woodbury noted that the CString::Find docs don‘t match 206 //                    what the CString::Find code really ends up doing.   I was 207 //                    trying to match the docs.  Now I match the CString code 208 //                  - Joe also caught me truncating strings for GetBuffer() calls 209 //                    when the supplied length was less than the current length. 210 // 211 //      2000-MAY-25 - Better support for STLPORT‘s Standard library distribution 212 //                  - Got rid of the NSP macro - it interfered with Koenig lookup 213 //                  - Thanks to Joe Woodbury for catching a TrimLeft() bug that 214 //                    I introduced in January.  Empty strings were not getting 215 //                    trimmed 216 // 217 //      2000-APR-17 - Thanks to Joe Vitaterna for pointing out that ReverseFind 218 //                    is supposed to be a const function. 219 // 220 //      2000-MAR-07 - Thanks to Ullrich Poll鋒ne for catching a range bug in one 221 //                    of the overloads of assign. 222 // 223 //    2000-FEB-01 - You can now use CStdString on the Mac with CodeWarrior! 224 //                    Thanks to Todd Heckel for helping out with this. 225 // 226 //      2000-JAN-23 - Thanks to Jim Cline for pointing out how I could make the 227 //                    Trim() function more efficient. 228 //                  - Thanks to Jeff Kohn for prompting me to find and fix a typo 229 //                    in one of the addition operators that takes _bstr_t. 230 //                  - Got rid of the .CPP file -  you only need StdString.h now! 231 // 232 //      1999-DEC-22 - Thanks to Greg Pickles for helping me identify a problem 233 //                    with my implementation of CStdString::FormatV in which 234 //                    resulting string might not be properly NULL terminated. 235 // 236 //      1999-DEC-06 - Chris Conti pointed yet another basic_string<> assignment 237 //                    bug that MS has not fixed.  CStdString did nothing to fix 238 //                    it either but it does now!  The bug was: create a string 239 //                    longer than 31 characters, get a pointer to it (via c_str()) 240 //                    and then assign that pointer to the original string object. 241 //                    The resulting string would be empty.  Not with CStdString! 242 // 243 //      1999-OCT-06 - BufferSet was erasing the string even when it was merely 244 //                    supposed to shrink it.  Fixed.  Thanks to Chris Conti. 245 //                  - Some of the Q172398 fixes were not checking for assignment- 246 //                    to-self.  Fixed.  Thanks to Baptiste Lepilleur. 247 // 248 //      1999-AUG-20 - Improved Load() function to be more efficient by using  249 //                    SizeOfResource().  Thanks to Rich Zuris for this. 250 //                  - Corrected resource ID constructor, again thanks to Rich. 251 //                  - Fixed a bug that occurred with UNICODE characters above 252 //                    the first 255 ANSI ones.  Thanks to Craig Watson.  253 //                  - Added missing overloads of TrimLeft() and TrimRight(). 254 //                    Thanks to Karim Ratib for pointing them out 255 // 256 //      1999-JUL-21 - Made all calls to GetBuf() with no args check length first. 257 // 258 //      1999-JUL-10 - Improved MFC/ATL independence of conversion macros 259 //                  - Added SS_NO_REFCOUNT macro to allow you to disable any 260 //                    reference-counting your basic_string<> impl. may do. 261 //                  - Improved ReleaseBuffer() to be as forgiving as CString. 262 //                    Thanks for Fan Xia for helping me find this and to 263 //                    Matthew Williams for pointing it out directly. 264 // 265 //      1999-JUL-06 - Thanks to Nigel Nunn for catching a very sneaky bug in 266 //                    ToLower/ToUpper.  They should call GetBuf() instead of 267 //                    data() in order to ensure the changed string buffer is not 268 //                    reference-counted (in those implementations that refcount). 269 // 270 //      1999-JUL-01 - Added a true CString facade.  Now you can use CStdString as 271 //                    a drop-in replacement for CString.  If you find this useful, 272 //                    you can thank Chris Sells for finally convincing me to give 273 //                    in and implement it. 274 //                  - Changed operators << and >> (for MFC CArchive) to serialize 275 //                    EXACTLY as CString‘s do.  So now you can send a CString out 276 //                    to a CArchive and later read it in as a CStdString.   I have 277 //                    no idea why you would want to do this but you can.  278 // 279 //      1999-JUN-21 - Changed the CStdString class into the CStdStr template. 280 //                  - Fixed FormatV() to correctly decrement the loop counter. 281 //                    This was harmless bug but a bug nevertheless.  Thanks to 282 //                    Chris (of Melbsys) for pointing it out 283 //                  - Changed Format() to try a normal stack-based array before 284 //                    using to _alloca(). 285 //                  - Updated the text conversion macros to properly use code 286 //                    pages and to fit in better in MFC/ATL builds.  In other 287 //                    words, I copied Microsoft‘s conversion stuff again.  288 //                  - Added equivalents of CString::GetBuffer, GetBufferSetLength 289 //                  - new sscpy() replacement of CStdString::CopyString() 290 //                  - a Trim() function that combines TrimRight() and TrimLeft(). 291 // 292 //      1999-MAR-13 - Corrected the "NotSpace" functional object to use _istpace() 293 //                    instead of _isspace()   Thanks to Dave Plummer for this. 294 // 295 //      1999-FEB-26 - Removed errant line (left over from testing) that #defined 296 //                    _MFC_VER.  Thanks to John C Sipos for noticing this. 297 // 298 //      1999-FEB-03 - Fixed a bug in a rarely-used overload of operator+() that 299 //                    caused infinite recursion and stack overflow 300 //                  - Added member functions to simplify the process of 301 //                    persisting CStdStrings to/from DCOM IStream interfaces  302 //                  - Added functional objects (e.g. StdStringLessNoCase) that 303 //                    allow CStdStrings to be used as keys STL map objects with 304 //                    case-insensitive comparison  305 //                  - Added array indexing operators (i.e. operator[]).  I 306 //                    originally assumed that these were unnecessary and would be 307 //                    inherited from basic_string.  However, without them, Visual 308 //                    C++ complains about ambiguous overloads when you try to use 309 //                    them.  Thanks to Julian Selman to pointing this out.  310 // 311 //      1998-FEB-?? - Added overloads of assign() function to completely account 312 //                    for Q172398 bug.  Thanks to "Pete the Plumber" for this 313 // 314 //      1998-FEB-?? - Initial submission 315 // 316 // COPYRIGHT: 317 //        2002 Joseph M. O‘Leary.  This code is 100% free.  Use it anywhere you 318 //      want.  Rewrite it, restructure it, whatever.  If you can write software 319 //      that makes money off of it, good for you.  I kinda like capitalism.  320 //      Please don‘t blame me if it causes your $30 billion dollar satellite 321 //      explode in orbit.  If you redistribute it in any form, I‘d appreciate it 322 //      if you would leave this notice here. 323 // ============================================================================= 324  325 // Avoid multiple inclusion 326  327 #ifndef STDSTRING_H 328 #define STDSTRING_H 329  330 // When using VC, turn off browser references 331 // Turn off unavoidable compiler warnings 332  333 #if defined(_MSC_VER) && (_MSC_VER > 1100) 334     #pragma component(browser, off, references, "CStdString") 335     #pragma warning (disable : 4290) // C++ Exception Specification ignored 336     #pragma warning (disable : 4127) // Conditional expression is constant 337     #pragma warning (disable : 4097) // typedef name used as synonym for class name 338 #endif 339  340 #ifndef _UNICODE 341     #define SS_ANSI 342 #endif 343  344 // Borland warnings to turn off 345  346 #ifdef __BORLANDC__ 347     #pragma option push -w-inl 348 //    #pragma warn -inl   // Turn off inline function warnings 349 #endif 350  351 // SS_IS_INTRESOURCE 352 // ----------------- 353 //        A copy of IS_INTRESOURCE from VC7.  Because old VC6 version of winuser.h 354 //        doesn‘t have this. 355  356 #define SS_IS_INTRESOURCE(_r) (false) 357  358 #if !defined (SS_ANSI) && defined(_MSC_VER) 359     #undef SS_IS_INTRESOURCE 360     #if defined(_WIN64) 361         #define SS_IS_INTRESOURCE(_r) (((unsigned __int64)(_r) >> 16) == 0) 362     #else 363         #define SS_IS_INTRESOURCE(_r) (((unsigned long)(_r) >> 16) == 0) 364     #endif 365 #endif 366  367  368 // MACRO: SS_UNSIGNED 369 // ------------------ 370 //      This macro causes the addition of a constructor and assignment operator 371 //      which take unsigned characters.  CString has such functions and in order 372 //      to provide maximum CString-compatability, this code needs them as well. 373 //      In practice you will likely never need these functions... 374  375 //#define SS_UNSIGNED 376  377 #ifdef SS_ALLOW_UNSIGNED_CHARS 378     #define SS_UNSIGNED 379 #endif 380  381 // MACRO: SS_SAFE_FORMAT 382 // --------------------- 383 //      This macro provides limited compatability with a questionable CString 384 //      "feature".  You can define it in order to avoid a common problem that 385 //      people encounter when switching from CString to CStdString. 386 // 387 //      To illustrate the problem -- With CString, you can do this: 388 // 389 //          CString sName("Joe"); 390 //          CString sTmp; 391 //          sTmp.Format("My name is %s", sName);                    // WORKS! 392 // 393 //      However if you were to try this with CStdString, your program would 394 //      crash. 395 // 396 //          CStdString sName("Joe"); 397 //          CStdString sTmp; 398 //          sTmp.Format("My name is %s", sName);                    // CRASHES! 399 // 400 //      You must explicitly call c_str() or cast the object to the proper type 401 // 402 //          sTmp.Format("My name is %s", sName.c_str());            // WORKS! 403 //          sTmp.Format("My name is %s", static_cast<PCSTR>(sName));// WORKS! 404 //          sTmp.Format("My name is %s", (PCSTR)sName);                // WORKS! 405 // 406 //      This is because it is illegal to pass anything but a POD type as a 407 //      variadic argument to a variadic function (i.e. as one of the "..." 408 //      arguments).  The type const char* is a POD type.  The type CStdString 409 //      is not.  Of course, neither is the type CString, but CString lets you do 410 //      it anyway due to the way they laid out the class in binary.  I have no 411 //      control over this in CStdString since I derive from whatever 412 //      implementation of basic_string is available. 413 // 414 //      However if you have legacy code (which does this) that you want to take 415 //      out of the MFC world and you don‘t want to rewrite all your calls to 416 //      Format(), then you can define this flag and it will no longer crash. 417 // 418 //      Note however that this ONLY works for Format(), not sprintf, fprintf,  419 //      etc.  If you pass a CStdString object to one of those functions, your 420 //      program will crash.  Not much I can do to get around this, short of 421 //      writing substitutes for those functions as well. 422  423 #define SS_SAFE_FORMAT  // use new template style Format() function 424  425  426 // MACRO: SS_NO_IMPLICIT_CAST 427 // -------------------------- 428 //      Some people don‘t like the implicit cast to const char* (or rather to 429 //      const CT*) that CStdString (and MFC‘s CString) provide.  That was the 430 //      whole reason I created this class in the first place, but hey, whatever 431 //      bakes your cake.  Just #define this macro to get rid of the the implicit 432 //      cast. 433  434 //#define SS_NO_IMPLICIT_CAST // gets rid of operator const CT*() 435  436  437 // MACRO: SS_NO_REFCOUNT 438 // --------------------- 439 //        turns off reference counting at the assignment level.  Only needed 440 //        for the version of basic_string<> that comes with Visual C++ versions 441 //        6.0 or earlier, and only then in some heavily multithreaded scenarios. 442 //        Uncomment it if you feel you need it. 443  444 //#define SS_NO_REFCOUNT 445  446 // MACRO: SS_WIN32 447 // --------------- 448 //      When this flag is set, we are building code for the Win32 platform and 449 //      may use Win32 specific functions (such as LoadString).  This gives us 450 //      a couple of nice extras for the code. 451 // 452 //      Obviously, Microsoft‘s is not the only compiler available for Win32 out 453 //      there.  So I can‘t just check to see if _MSC_VER is defined to detect 454 //      if I‘m building on Win32.  So for now, if you use MS Visual C++ or 455 //      Borland‘s compiler, I turn this on.  Otherwise you may turn it on 456 //      yourself, if you prefer 457  458 #if defined(_MSC_VER) || defined(__BORLANDC__) || defined(_WIN32) 459     #define SS_WIN32 460 #endif 461  462 // MACRO: SS_ANSI 463 // -------------- 464 //      When this macro is defined, the code attempts only to use ANSI/ISO 465 //      standard library functions to do it‘s work.  It will NOT attempt to use 466 //      any Win32 of Visual C++ specific functions -- even if they are 467 //      available.  You may define this flag yourself to prevent any Win32 468 //      of VC++ specific functions from being called.  469  470 // If we‘re not on Win32, we MUST use an ANSI build 471  472 #ifndef SS_WIN32 473     #if !defined(SS_NO_ANSI) 474         #define SS_ANSI 475     #endif 476 #endif 477  478 // MACRO: SS_ALLOCA 479 // ---------------- 480 //      Some implementations of the Standard C Library have a non-standard 481 //      function known as alloca().  This functions allows one to allocate a 482 //      variable amount of memory on the stack.  It is needed to implement 483 //      the ASCII/MBCS conversion macros. 484 // 485 //      I wanted to find some way to determine automatically if alloca() is 486 //        available on this platform via compiler flags but that is asking for 487 //        trouble.  The crude test presented here will likely need fixing on 488 //        other platforms.  Therefore I‘ll leave it up to you to fiddle with 489 //        this test to determine if it exists.  Just make sure SS_ALLOCA is or 490 //        is not defined as appropriate and you control this feature. 491  492 #if defined(_MSC_VER) && !defined(SS_ANSI) 493     #define SS_ALLOCA 494 #endif 495  496  497 // MACRO: SS_MBCS 498 // -------------- 499 //        Setting this macro means you are using MBCS characters.  In MSVC builds, 500 //        this macro gets set automatically by detection of the preprocessor flag 501 //        _MBCS.  For other platforms you may set it manually if you wish.  The 502 //        only effect it currently has is to cause the allocation of more space 503 //        for wchar_t --> char conversions. 504 //        Note that MBCS does not mean UNICODE. 505 // 506 //    #define SS_MBCS 507 // 508  509 #ifdef _MBCS 510     #define SS_MBCS 511 #endif 512  513  514 // MACRO SS_NO_LOCALE 515 // ------------------ 516 // If your implementation of the Standard C++ Library lacks the <locale> header, 517 // you can #define this macro to make your code build properly.  Note that this 518 // is some of my newest code and frankly I‘m not very sure of it, though it does 519 // pass my unit tests. 520  521 // #define SS_NO_LOCALE 522  523  524 // Compiler Error regarding _UNICODE and UNICODE 525 // ----------------------------------------------- 526 // Microsoft header files are screwy.  Sometimes they depend on a preprocessor  527 // flag named "_UNICODE".  Other times they check "UNICODE" (note the lack of 528 // leading underscore in the second version".  In several places, they silently 529 // "synchronize" these two flags this by defining one of the other was defined.  530 // In older version of this header, I used to try to do the same thing.  531 // 532 // However experience has taught me that this is a bad idea.  You get weird 533 // compiler errors that seem to indicate things like LPWSTR and LPTSTR not being 534 // equivalent in UNICODE builds, stuff like that (when they MUST be in a proper 535 // UNICODE  build).  You end up scratching your head and saying, "But that HAS 536 // to compile!". 537 // 538 // So what should you do if you get this error? 539 // 540 // Make sure that both macros (_UNICODE and UNICODE) are defined before this 541 // file is included.  You can do that by either 542 // 543 //        a) defining both yourself before any files get included 544 //        b) including the proper MS headers in the proper order 545 //        c) including this file before any other file, uncommenting 546 //           the #defines below, and commenting out the #errors 547 // 548 //    Personally I recommend solution a) but it‘s your call. 549  550 #ifdef _MSC_VER 551     #if defined (_UNICODE) && !defined (UNICODE) 552         #error UNICODE defined  but not UNICODE 553     //    #define UNICODE  // no longer silently fix this 554     #endif 555     #if defined (UNICODE) && !defined (_UNICODE) 556         #error Warning, UNICODE defined  but not _UNICODE 557     //    #define _UNICODE  // no longer silently fix this 558     #endif 559 #endif 560  561  562 // ----------------------------------------------------------------------------- 563 // MIN and MAX.  The Standard C++ template versions go by so many names (at 564 // at least in the MS implementation) that you never know what‘s available  565 // ----------------------------------------------------------------------------- 566 template<class Type> 567 inline const Type& SSMIN(const Type& arg1, const Type& arg2) 568 { 569     return arg2 < arg1 ? arg2 : arg1; 570 } 571 template<class Type> 572 inline const Type& SSMAX(const Type& arg1, const Type& arg2) 573 { 574     return arg2 > arg1 ? arg2 : arg1; 575 } 576  577 // If they have not #included W32Base.h (part of my W32 utility library) then 578 // we need to define some stuff.  Otherwise, this is all defined there. 579  580 #if !defined(W32BASE_H) 581  582     // If they want us to use only standard C++ stuff (no Win32 stuff) 583  584     #ifdef SS_ANSI 585  586         // On Win32 we have TCHAR.H so just include it.  This is NOT violating 587         // the spirit of SS_ANSI as we are not calling any Win32 functions here. 588          589         #ifdef SS_WIN32 590  591             #include <TCHAR.H> 592             #include <WTYPES.H> 593             #ifndef STRICT 594                 #define STRICT 595             #endif 596  597         // ... but on non-Win32 platforms, we must #define the types we need. 598  599         #else 600  601             typedef const char*        PCSTR; 602             typedef char*            PSTR; 603             typedef const wchar_t*    PCWSTR; 604             typedef wchar_t*        PWSTR; 605             #ifdef UNICODE 606                 typedef wchar_t        TCHAR; 607             #else 608                 typedef char        TCHAR; 609             #endif 610             typedef wchar_t            OLECHAR; 611  612         #endif    // #ifndef _WIN32 613  614  615         // Make sure ASSERT and verify are defined using only ANSI stuff 616  617         #ifndef ASSERT 618             #include <assert.h> 619             #define ASSERT(f) assert((f)) 620         #endif 621         #ifndef VERIFY 622             #ifdef _DEBUG 623                 #define VERIFY(x) ASSERT((x)) 624             #else 625                 #define VERIFY(x) x 626             #endif 627         #endif 628  629     #else // ...else SS_ANSI is NOT defined 630  631         #include <TCHAR.H> 632         #include <WTYPES.H> 633         #ifndef STRICT 634             #define STRICT 635         #endif 636  637         // Make sure ASSERT and verify are defined 638  639         #ifndef ASSERT 640             #include <crtdbg.h> 641             #define ASSERT(f) _ASSERTE((f)) 642         #endif 643         #ifndef VERIFY 644             #ifdef _DEBUG 645                 #define VERIFY(x) ASSERT((x)) 646             #else 647                 #define VERIFY(x) x 648             #endif 649         #endif 650  651     #endif // #ifdef SS_ANSI 652  653     #ifndef UNUSED 654         #define UNUSED(x) x 655     #endif 656  657 #endif // #ifndef W32BASE_H 658  659 // Standard headers needed 660  661 #include <string>            // basic_string 662 #include <algorithm>        // for_each, etc. 663 #include <functional>        // for StdStringLessNoCase, et al 664 #ifndef SS_NO_LOCALE 665     #include <locale>            // for various facets 666 #endif 667  668 // If this is a recent enough version of VC include comdef.h, so we can write 669 // member functions to deal with COM types & compiler support classes e.g. 670 // _bstr_t 671  672 #if defined (_MSC_VER) && (_MSC_VER >= 1100) 673     #include <comdef.h> 674     #define SS_INC_COMDEF        // signal that we #included MS comdef.h file 675     #define STDSTRING_INC_COMDEF 676     #define SS_NOTHROW __declspec(nothrow) 677 #else 678     #define SS_NOTHROW 679 #endif 680  681 #ifndef TRACE 682     #define TRACE_DEFINED_HERE 683     #define TRACE 684 #endif 685  686 // Microsoft defines PCSTR, PCWSTR, etc, but no PCTSTR.  I hate to use the 687 // versions with the "L" in front of them because that‘s a leftover from Win 16 688 // days, even though it evaluates to the same thing.  Therefore, Define a PCSTR 689 // as an LPCTSTR. 690  691 #if !defined(PCTSTR) && !defined(PCTSTR_DEFINED) 692     typedef const TCHAR*            PCTSTR; 693     #define PCTSTR_DEFINED 694 #endif 695  696 #if !defined(PCOLESTR) && !defined(PCOLESTR_DEFINED) 697     typedef const OLECHAR*            PCOLESTR; 698     #define PCOLESTR_DEFINED 699 #endif 700  701 #if !defined(POLESTR) && !defined(POLESTR_DEFINED) 702     typedef OLECHAR*                POLESTR; 703     #define POLESTR_DEFINED 704 #endif 705  706 #if !defined(PCUSTR) && !defined(PCUSTR_DEFINED) 707     typedef const unsigned char*    PCUSTR; 708     typedef unsigned char*            PUSTR; 709     #define PCUSTR_DEFINED 710 #endif 711  712  713 // SGI compiler 7.3 doesnt know these  types - oh and btw, remember to use 714 // -LANG:std in the CXX Flags 715 #if defined(__sgi) 716     typedef unsigned long           DWORD; 717     typedef void *                  LPCVOID; 718 #endif 719  720  721 // SS_USE_FACET macro and why we need it: 722 // 723 // Since I‘m a good little Standard C++ programmer, I use locales.  Thus, I 724 // need to make use of the use_facet<> template function here.   Unfortunately, 725 // this need is complicated by the fact the MS‘ implementation of the Standard 726 // C++ Library has a non-standard version of use_facet that takes more 727 // arguments than the standard dictates.  Since I‘m trying to write CStdString 728 // to work with any version of the Standard library, this presents a problem. 729 // 730 // The upshot of this is that I can‘t do ‘use_facet‘ directly.  The MS‘ docs 731 // tell me that I have to use a macro, _USE() instead.  Since _USE obviously 732 // won‘t be available in other implementations, this means that I have to write 733 // my OWN macro -- SS_USE_FACET -- that evaluates either to _USE or to the 734 // standard, use_facet. 735 // 736 // If you are having trouble with the SS_USE_FACET macro, in your implementation 737 // of the Standard C++ Library, you can define your own version of SS_USE_FACET. 738  739 #ifndef schMSG 740     #define schSTR(x)       #x 741     #define schSTR2(x)    schSTR(x) 742     #define schMSG(desc) message(__FILE__ "(" schSTR2(__LINE__) "):" #desc) 743 #endif 744  745 #ifndef SS_USE_FACET 746  747     // STLPort #defines a macro (__STL_NO_EXPLICIT_FUNCTION_TMPL_ARGS) for 748     // all MSVC builds, erroneously in my opinion.  It causes problems for 749     // my SS_ANSI builds.  In my code, I always comment out that line.  You‘ll 750     // find it in   \stlport\config\stl_msvc.h 751  752     #if defined(__SGI_STL_PORT) && (__SGI_STL_PORT >= 0x400 ) 753  754         #if defined(__STL_NO_EXPLICIT_FUNCTION_TMPL_ARGS) && defined(_MSC_VER) 755             #ifdef SS_ANSI 756                 #pragma schMSG(__STL_NO_EXPLICIT_FUNCTION_TMPL_ARGS defined!!) 757             #endif 758         #endif 759         #define SS_USE_FACET(loc, fac) std::use_facet<fac >(loc) 760  761     #elif defined(_MSC_VER ) 762  763         #define SS_USE_FACET(loc, fac) std::_USE(loc, fac) 764  765     // ...and 766     #elif defined(_RWSTD_NO_TEMPLATE_ON_RETURN_TYPE) 767  768         #define SS_USE_FACET(loc, fac) std::use_facet(loc, (fac*)0) 769  770     #else 771  772         #define SS_USE_FACET(loc, fac) std::use_facet<fac >(loc) 773  774     #endif 775  776 #endif 777  778 // ============================================================================= 779 // UNICODE/MBCS conversion macros.  Made to work just like the MFC/ATL ones. 780 // ============================================================================= 781  782 #include <wchar.h>      // Added to Std Library with Amendment #1. 783  784 // First define the conversion helper functions.  We define these regardless of 785 // any preprocessor macro settings since their names won‘t collide.  786  787 // Not sure if we need all these headers.   I believe ANSI says we do. 788  789 #include <stdio.h> 790 #include <stdarg.h> 791 #include <wctype.h> 792 #include <ctype.h> 793 #include <stdlib.h> 794 #ifndef va_start 795     #include <varargs.h> 796 #endif 797  798  799 #ifdef SS_NO_LOCALE 800  801     #if defined(_WIN32) || defined (_WIN32_WCE) 802  803         inline PWSTR StdCodeCvt(PWSTR pDstW, int nDst, PCSTR pSrcA, int nSrc,  804             UINT acp=CP_ACP) 805         { 806             ASSERT(0 != pSrcA); 807             ASSERT(0 != pDstW); 808             pDstW[0] = \0; 809             MultiByteToWideChar(acp, 0, pSrcA, nSrc, pDstW, nDst); 810             return pDstW; 811         } 812         inline PWSTR StdCodeCvt(PWSTR pDstW, int nDst, PCUSTR pSrcA, int nSrc,  813             UINT acp=CP_ACP) 814         { 815             return StdCodeCvt(pDstW, nDst, (PCSTR)pSrcA, nSrc, acp); 816         } 817  818         inline PSTR StdCodeCvt(PSTR pDstA, int nDst, PCWSTR pSrcW, int nSrc,  819             UINT acp=CP_ACP) 820         { 821             ASSERT(0 != pDstA); 822             ASSERT(0 != pSrcW); 823             pDstA[0] = \0; 824             WideCharToMultiByte(acp, 0, pSrcW, nSrc, pDstA, nDst, 0, 0); 825             return pDstA; 826         } 827         inline PUSTR StdCodeCvt(PUSTR pDstA, int nDst, PCWSTR pSrcW, int nSrc,  828             UINT acp=CP_ACP) 829         { 830             return (PUSTR)StdCodeCvt((PSTR)pDstA, nDst, pSrcW, nSrc, acp); 831         } 832     #else 833     #endif 834  835 #else 836  837     // StdCodeCvt - made to look like Win32 functions WideCharToMultiByte 838     //                and MultiByteToWideChar but uses locales in SS_ANSI 839     //                builds.  There are a number of overloads. 840     //              First argument is the destination buffer. 841     //              Second argument is the source buffer 842     //#if defined (SS_ANSI) || !defined (SS_WIN32) 843  844     // ‘SSCodeCvt‘ - shorthand name for the codecvt facet we use 845  846     typedef std::codecvt<wchar_t, char, mbstate_t> SSCodeCvt; 847  848     inline PWSTR StdCodeCvt(PWSTR pDstW, int nDst, PCSTR pSrcA, int nSrc, 849         const std::locale& loc=std::locale()) 850     { 851         ASSERT(0 != pSrcA); 852         ASSERT(0 != pDstW); 853  854         pDstW[0]                    = \0;     855  856         if ( nSrc > 0 ) 857         { 858             PCSTR pNextSrcA            = pSrcA; 859             PWSTR pNextDstW            = pDstW; 860             SSCodeCvt::result res    = SSCodeCvt::ok; 861             const SSCodeCvt& conv    = SS_USE_FACET(loc, SSCodeCvt); 862             SSCodeCvt::state_type st= { 0 }; 863             res                        = conv.in(st, 864                                         pSrcA, pSrcA + nSrc, pNextSrcA, 865                                         pDstW, pDstW + nDst, pNextDstW); 866  867             ASSERT(SSCodeCvt::ok == res); 868             ASSERT(SSCodeCvt::error != res); 869             ASSERT(pNextDstW >= pDstW); 870             ASSERT(pNextSrcA >= pSrcA); 871  872             // Null terminate the converted string 873  874             if ( pNextDstW - pDstW > nDst ) 875                 *(pDstW + nDst) = \0; 876             else 877                 *pNextDstW = \0; 878         } 879         return pDstW; 880     } 881     inline PWSTR StdCodeCvt(PWSTR pDstW, int nDst, PCUSTR pSrcA, int nSrc, 882         const std::locale& loc=std::locale()) 883     { 884         return StdCodeCvt(pDstW, nDst, (PCSTR)pSrcA, nSrc, loc); 885     } 886  887     inline PSTR StdCodeCvt(PSTR pDstA, int nDst, PCWSTR pSrcW, int nSrc, 888         const std::locale& loc=std::locale()) 889     { 890         ASSERT(0 != pDstA); 891         ASSERT(0 != pSrcW); 892  893         pDstA[0]                    = \0;     894  895         if ( nSrc > 0 ) 896         { 897             PSTR pNextDstA            = pDstA; 898             PCWSTR pNextSrcW        = pSrcW; 899             SSCodeCvt::result res    = SSCodeCvt::ok; 900             const SSCodeCvt& conv    = SS_USE_FACET(loc, SSCodeCvt); 901             SSCodeCvt::state_type st= { 0 }; 902             res                        = conv.out(st, 903                                         pSrcW, pSrcW + nSrc, pNextSrcW, 904                                         pDstA, pDstA + nDst, pNextDstA); 905  906             ASSERT(SSCodeCvt::error != res); 907             ASSERT(SSCodeCvt::ok == res);    // strict, comment out for sanity 908             ASSERT(pNextDstA >= pDstA); 909             ASSERT(pNextSrcW >= pSrcW); 910  911             // Null terminate the converted string 912  913             if ( pNextDstA - pDstA > nDst ) 914                 *(pDstA + nDst) = \0; 915             else 916                 *pNextDstA = \0; 917         } 918         return pDstA; 919     } 920  921     inline PUSTR StdCodeCvt(PUSTR pDstA, int nDst, PCWSTR pSrcW, int nSrc, 922         const std::locale& loc=std::locale()) 923     { 924         return (PUSTR)StdCodeCvt((PSTR)pDstA, nDst, pSrcW, nSrc, loc); 925     } 926  927 #endif 928  929  930  931 // Unicode/MBCS conversion macros are only available on implementations of 932 // the "C" library that have the non-standard _alloca function.  As far as I 933 // know that‘s only Microsoft‘s though I‘ve heard that the function exists 934 // elsewhere.   935      936 #if defined(SS_ALLOCA) && !defined SS_NO_CONVERSION 937  938     #include <malloc.h>    // needed for _alloca 939  940     // Define our conversion macros to look exactly like Microsoft‘s to 941     // facilitate using this stuff both with and without MFC/ATL 942  943     #ifdef _CONVERSION_USES_THREAD_LOCALE 944  945         #ifndef _DEBUG 946             #define SSCVT int _cvt; _cvt; UINT _acp=GetACP();  947                 _acp; PCWSTR _pw; _pw; PCSTR _pa; _pa 948         #else 949             #define SSCVT int _cvt = 0; _cvt; UINT _acp=GetACP(); 950                  _acp; PCWSTR _pw=0; _pw; PCSTR _pa=0; _pa 951         #endif 952         #define SSA2W(pa) ( 953             ((_pa = pa) == 0) ? 0 : ( 954                 _cvt = (sslen(_pa)), 955                 StdCodeCvt((PWSTR) _alloca((_cvt+1)*2), (_cvt+1)*2,  956                             _pa, _cvt, _acp))) 957         #define SSW2A(pw) ( 958             ((_pw = pw) == 0) ? 0 : ( 959                 _cvt = sslen(_pw),  960                 StdCodeCvt((LPSTR) _alloca((_cvt+1)*2), (_cvt+1)*2,  961                     _pw, _cvt, _acp))) 962     #else 963  964         #ifndef _DEBUG 965             #define SSCVT int _cvt; _cvt; UINT _acp=CP_ACP; _acp; 966                  PCWSTR _pw; _pw; PCSTR _pa; _pa 967         #else 968             #define SSCVT int _cvt = 0; _cvt; UINT _acp=CP_ACP;  969                 _acp; PCWSTR _pw=0; _pw; PCSTR _pa=0; _pa 970         #endif 971         #define SSA2W(pa) ( 972             ((_pa = pa) == 0) ? 0 : ( 973                 _cvt = (sslen(_pa)), 974                 StdCodeCvt((PWSTR) _alloca((_cvt+1)*2), (_cvt+1)*2,  975                     _pa, _cvt))) 976         #define SSW2A(pw) ( 977             ((_pw = pw) == 0) ? 0 : ( 978                 _cvt = (sslen(_pw)), 979                 StdCodeCvt((LPSTR) _alloca((_cvt+1)*2), (_cvt+1)*2,  980                     _pw, _cvt))) 981     #endif 982  983     #define SSA2CW(pa) ((PCWSTR)SSA2W((pa))) 984     #define SSW2CA(pw) ((PCSTR)SSW2A((pw))) 985  986     #ifdef UNICODE 987         #define SST2A    SSW2A 988         #define SSA2T    SSA2W 989         #define SST2CA    SSW2CA 990         #define SSA2CT    SSA2CW 991         // (Did you get a compiler error here about not being able to convert 992         // PTSTR into PWSTR?  Then your _UNICODE and UNICODE flags are messed  993         // up.  Best bet: #define BOTH macros before including any MS headers.) 994         inline PWSTR    SST2W(PTSTR p)            { return p; } 995         inline PTSTR    SSW2T(PWSTR p)            { return p; } 996         inline PCWSTR    SST2CW(PCTSTR p)        { return p; } 997         inline PCTSTR    SSW2CT(PCWSTR p)        { return p; } 998     #else 999         #define SST2W    SSA2W1000         #define SSW2T    SSW2A1001         #define SST2CW    SSA2CW1002         #define SSW2CT    SSW2CA1003         inline PSTR        SST2A(PTSTR p)            { return p; }1004         inline PTSTR    SSA2T(PSTR p)            { return p; }1005         inline PCSTR    SST2CA(PCTSTR p)        { return p; }1006         inline PCTSTR    SSA2CT(PCSTR p)            { return p; }1007     #endif // #ifdef UNICODE1008 1009     #if defined(UNICODE)1010     // in these cases the default (TCHAR) is the same as OLECHAR1011         inline PCOLESTR    SST2COLE(PCTSTR p)        { return p; }1012         inline PCTSTR    SSOLE2CT(PCOLESTR p)    { return p; }1013         inline POLESTR    SST2OLE(PTSTR p)        { return p; }1014         inline PTSTR    SSOLE2T(POLESTR p)        { return p; }1015     #elif defined(OLE2ANSI)1016     // in these cases the default (TCHAR) is the same as OLECHAR1017         inline PCOLESTR    SST2COLE(PCTSTR p)        { return p; }1018         inline PCTSTR    SSOLE2CT(PCOLESTR p)    { return p; }1019         inline POLESTR    SST2OLE(PTSTR p)        { return p; }1020         inline PTSTR    SSOLE2T(POLESTR p)        { return p; }1021     #else1022         //CharNextW doesn‘t work on Win95 so we use this1023         #define SST2COLE(pa)    SSA2CW((pa))1024         #define SST2OLE(pa)        SSA2W((pa))1025         #define SSOLE2CT(po)    SSW2CA((po))1026         #define SSOLE2T(po)        SSW2A((po))1027     #endif1028 1029     #ifdef OLE2ANSI1030         #define SSW2OLE        SSW2A1031         #define SSOLE2W        SSA2W1032         #define SSW2COLE    SSW2CA1033         #define SSOLE2CW    SSA2CW1034         inline POLESTR        SSA2OLE(PSTR p)        { return p; }1035         inline PSTR            SSOLE2A(POLESTR p)    { return p; }1036         inline PCOLESTR        SSA2COLE(PCSTR p)    { return p; }1037         inline PCSTR        SSOLE2CA(PCOLESTR p){ return p; }1038     #else1039         #define SSA2OLE        SSA2W1040         #define SSOLE2A        SSW2A1041         #define SSA2COLE    SSA2CW1042         #define SSOLE2CA    SSW2CA1043         inline POLESTR        SSW2OLE(PWSTR p)    { return p; }1044         inline PWSTR        SSOLE2W(POLESTR p)    { return p; }1045         inline PCOLESTR        SSW2COLE(PCWSTR p)    { return p; }1046         inline PCWSTR        SSOLE2CW(PCOLESTR p){ return p; }1047     #endif1048 1049     // Above we‘ve defined macros that look like MS‘ but all have1050     // an ‘SS‘ prefix.  Now we need the real macros.  We‘ll either1051     // get them from the macros above or from MFC/ATL. 1052 1053     #if defined (USES_CONVERSION)1054 1055         #define _NO_STDCONVERSION    // just to be consistent1056 1057     #else1058 1059         #ifdef _MFC_VER1060 1061             #include <afxconv.h>1062             #define _NO_STDCONVERSION // just to be consistent1063 1064         #else1065 1066             #define USES_CONVERSION SSCVT1067             #define A2CW            SSA2CW1068             #define W2CA            SSW2CA1069             #define T2A                SST2A1070             #define A2T                SSA2T1071             #define T2W                SST2W1072             #define W2T                SSW2T1073             #define T2CA            SST2CA1074             #define A2CT            SSA2CT1075             #define T2CW            SST2CW1076             #define W2CT            SSW2CT1077             #define ocslen            sslen1078             #define ocscpy            sscpy1079             #define T2COLE            SST2COLE1080             #define OLE2CT            SSOLE2CT1081             #define T2OLE            SST2COLE1082             #define OLE2T            SSOLE2CT1083             #define A2OLE            SSA2OLE1084             #define OLE2A            SSOLE2A1085             #define W2OLE            SSW2OLE1086             #define OLE2W            SSOLE2W1087             #define A2COLE            SSA2COLE1088             #define OLE2CA            SSOLE2CA1089             #define W2COLE            SSW2COLE1090             #define OLE2CW            SSOLE2CW1091     1092         #endif // #ifdef _MFC_VER1093     #endif // #ifndef USES_CONVERSION1094 #endif // #ifndef SS_NO_CONVERSION1095 1096 // Define ostring - generic name for std::basic_string<OLECHAR>1097 1098 #if !defined(ostring) && !defined(OSTRING_DEFINED)1099     typedef std::basic_string<OLECHAR> ostring;1100     #define OSTRING_DEFINED1101 #endif1102 1103 // StdCodeCvt when there‘s no conversion to be done1104 inline PSTR StdCodeCvt(PSTR pDst, int nDst, PCSTR pSrc, int nSrc)1105 {1106     int nChars = SSMIN(nSrc, nDst);1107 1108     if ( nChars > 0 )1109     {1110         pDst[0]                = \0;1111         std::basic_string<char>::traits_type::copy(pDst, pSrc, nChars);1112 //        std::char_traits<char>::copy(pDst, pSrc, nChars);1113         pDst[nChars]    = \0;1114     }1115 1116     return pDst;1117 }1118 inline PSTR StdCodeCvt(PSTR pDst, int nDst, PCUSTR pSrc, int nSrc)1119 {1120     return StdCodeCvt(pDst, nDst, (PCSTR)pSrc, nSrc);1121 }1122 inline PUSTR StdCodeCvt(PUSTR pDst, int nDst, PCSTR pSrc, int nSrc)1123 {1124     return (PUSTR)StdCodeCvt((PSTR)pDst, nDst, pSrc, nSrc);1125 }1126 1127 inline PWSTR StdCodeCvt(PWSTR pDst, int nDst, PCWSTR pSrc, int nSrc)1128 {1129     int nChars = SSMIN(nSrc, nDst);1130 1131     if ( nChars > 0 )1132     {1133         pDst[0]                = \0;1134         std::basic_string<wchar_t>::traits_type::copy(pDst, pSrc, nChars);1135 //        std::char_traits<wchar_t>::copy(pDst, pSrc, nChars);1136         pDst[nChars]    = \0;1137     }1138 1139     return pDst;1140 }1141 1142 1143 // Define tstring -- generic name for std::basic_string<TCHAR>1144 1145 #if !defined(tstring) && !defined(TSTRING_DEFINED)1146     typedef std::basic_string<TCHAR> tstring;1147     #define TSTRING_DEFINED1148 #endif1149 1150 // a very shorthand way of applying the fix for KB problem Q1723981151 // (basic_string assignment bug)1152 1153 #if defined ( _MSC_VER ) && ( _MSC_VER < 1200 )1154     #define Q172398(x) (x).erase()1155 #else1156     #define Q172398(x)1157 #endif1158 1159 // =============================================================================1160 // INLINE FUNCTIONS ON WHICH CSTDSTRING RELIES1161 //1162 // Usually for generic text mapping, we rely on preprocessor macro definitions1163 // to map to string functions.  However the CStdStr<> template cannot use1164 // macro-based generic text mappings because its character types do not get1165 // resolved until template processing which comes AFTER macro processing.  In1166 // other words, the preprocessor macro UNICODE is of little help to us in the1167 // CStdStr template1168 //1169 // Therefore, to keep the CStdStr declaration simple, we have these inline1170 // functions.  The template calls them often.  Since they are inline (and NOT1171 // exported when this is built as a DLL), they will probably be resolved away1172 // to nothing. 1173 //1174 // Without these functions, the CStdStr<> template would probably have to broken1175 // out into two, almost identical classes.  Either that or it would be a huge,1176 // convoluted mess, with tons of "if" statements all over the place checking the1177 // size of template parameter CT.1178 // =============================================================================1179 1180 #ifdef SS_NO_LOCALE1181 1182     // --------------------------------------------------------------------------1183     // Win32 GetStringTypeEx wrappers1184     // --------------------------------------------------------------------------1185     inline bool wsGetStringType(LCID lc, DWORD dwT, PCSTR pS, int nSize, 1186         WORD* pWd)1187     {1188         return FALSE != GetStringTypeExA(lc, dwT, pS, nSize, pWd);1189     }1190     inline bool wsGetStringType(LCID lc, DWORD dwT, PCWSTR pS, int nSize, 1191         WORD* pWd)1192     {1193         return FALSE != GetStringTypeExW(lc, dwT, pS, nSize, pWd);1194     }1195 1196 1197     template<typename CT>1198         inline bool ssisspace (CT t)1199     { 1200         WORD toYourMother;1201         return    wsGetStringType(GetThreadLocale(), CT_CTYPE1, &t, 1, &toYourMother)1202             && 0 != (C1_BLANK & toYourMother);1203     }1204 1205 #endif1206 1207 // If they defined SS_NO_REFCOUNT, then we must convert all assignments1208 1209 #if defined (_MSC_VER) && (_MSC_VER < 1300)1210     #ifdef SS_NO_REFCOUNT1211         #define SSREF(x) (x).c_str()1212     #else1213         #define SSREF(x) (x)1214     #endif1215 #else1216     #define SSREF(x) (x)1217 #endif1218 1219 // -----------------------------------------------------------------------------1220 // sslen: strlen/wcslen wrappers1221 // -----------------------------------------------------------------------------1222 template<typename CT> inline int sslen(const CT* pT)1223 {1224     return 0 == pT ? 0 : (int)std::basic_string<CT>::traits_type::length(pT);1225 //    return 0 == pT ? 0 : std::char_traits<CT>::length(pT);1226 }1227 inline SS_NOTHROW int sslen(const std::string& s)1228 {1229     return static_cast<int>(s.length());1230 }1231 inline SS_NOTHROW int sslen(const std::wstring& s)1232 {1233     return static_cast<int>(s.length());1234 }1235 1236 // -----------------------------------------------------------------------------1237 // sstolower/sstoupper -- convert characters to upper/lower case1238 // -----------------------------------------------------------------------------1239 1240 #ifdef SS_NO_LOCALE1241     inline char sstoupper(char ch)        { return (char)::toupper(ch); }1242     inline wchar_t sstoupper(wchar_t ch){ return (wchar_t)::towupper(ch); }1243     inline char sstolower(char ch)        { return (char)::tolower(ch); }1244     inline wchar_t sstolower(wchar_t ch){ return (wchar_t)::tolower(ch); }1245 #else1246     template<typename CT>1247     inline CT sstolower(const CT& t, const std::locale& loc = std::locale())1248     {1249         return std::tolower<CT>(t, loc);1250     }1251     template<typename CT>1252     inline CT sstoupper(const CT& t, const std::locale& loc = std::locale())1253     {1254         return std::toupper<CT>(t, loc);1255     }1256 #endif1257 1258 // -----------------------------------------------------------------------------1259 // ssasn: assignment functions -- assign "sSrc" to "sDst"1260 // -----------------------------------------------------------------------------1261 typedef std::string::size_type        SS_SIZETYPE; // just for shorthand, really1262 typedef std::string::pointer        SS_PTRTYPE;  1263 typedef std::wstring::size_type        SW_SIZETYPE;1264 typedef std::wstring::pointer        SW_PTRTYPE;  1265 1266 inline void    ssasn(std::string& sDst, const std::string& sSrc)1267 {1268     if ( sDst.c_str() != sSrc.c_str() )1269     {1270         sDst.erase();1271         sDst.assign(SSREF(sSrc));1272     }1273 }1274 inline void    ssasn(std::string& sDst, PCSTR pA)1275 {1276     // Watch out for NULLs, as always.1277 1278     if ( 0 == pA )1279     {1280         sDst.erase();1281     }1282 1283     // If pA actually points to part of sDst, we must NOT erase(), but1284     // rather take a substring1285 1286     else if ( pA >= sDst.c_str() && pA <= sDst.c_str() + sDst.size() )1287     {1288         sDst =sDst.substr(static_cast<SS_SIZETYPE>(pA-sDst.c_str()));1289     }1290 1291     // Otherwise (most cases) apply the assignment bug fix, if applicable1292     // and do the assignment1293 1294     else1295     {1296         Q172398(sDst);1297         sDst.assign(pA);1298     }1299 }1300 inline void    ssasn(std::string& sDst, const std::wstring& sSrc)1301 {1302     if ( sSrc.empty() )1303     {1304         sDst.erase();1305     }1306     else1307     {1308         int nDst    = static_cast<int>(sSrc.size());1309 1310         // In MBCS builds, pad the buffer to account for the possibility of1311         // some 3 byte characters.  Not perfect but should get most cases.1312 1313 #ifdef SS_MBCS1314         nDst    = static_cast<int>(static_cast<double>(nDst) * 1.3);1315 #endif1316 1317         sDst.resize(nDst+1);1318         PCSTR szCvt = StdCodeCvt(const_cast<SS_PTRTYPE>(sDst.data()), nDst,1319             sSrc.c_str(), static_cast<int>(sSrc.size()));1320 1321         // In MBCS builds, we don‘t know how long the destination string will be.1322 1323 #ifdef SS_MBCS1324         sDst.resize(sslen(szCvt));1325 #else1326         szCvt;1327         sDst.resize(sSrc.size());1328 #endif1329     }1330 }1331 inline void    ssasn(std::string& sDst, PCWSTR pW)1332 {1333     int nSrc    =http://www.mamicode.com/ sslen(pW);1334     if ( nSrc > 0 )1335     {1336         int nSrc    =http://www.mamicode.com/ sslen(pW);1337         int nDst    = nSrc;1338 1339         // In MBCS builds, pad the buffer to account for the possibility of1340         // some 3 byte characters.  Not perfect but should get most cases.1341 1342 #ifdef SS_MBCS1343         nDst    = static_cast<int>(static_cast<double>(nDst) * 1.3);1344 #endif1345 1346         sDst.resize(nDst + 1);1347         PCSTR szCvt = StdCodeCvt(const_cast<SS_PTRTYPE>(sDst.data()), nDst,1348             pW, nSrc);1349 1350         // In MBCS builds, we don‘t know how long the destination string will be.1351 1352 #ifdef SS_MBCS1353         sDst.resize(sslen(szCvt));1354 #else1355         sDst.resize(nDst);1356         szCvt;1357 #endif1358     }1359     else1360     {1361         sDst.erase();1362     }1363 }1364 inline void ssasn(std::string& sDst, const int nNull)1365 {1366     UNUSED(nNull);1367     ASSERT(nNull==0);1368     sDst.assign("");1369 }    1370 inline void    ssasn(std::wstring& sDst, const std::wstring& sSrc)1371 {1372     if ( sDst.c_str() != sSrc.c_str() )1373     {1374         sDst.erase();1375         sDst.assign(SSREF(sSrc));1376     }1377 }1378 inline void    ssasn(std::wstring& sDst, PCWSTR pW)1379 {1380     // Watch out for NULLs, as always.1381 1382     if ( 0 == pW )1383     {1384         sDst.erase();1385     }1386 1387     // If pW actually points to part of sDst, we must NOT erase(), but1388     // rather take a substring1389 1390     else if ( pW >= sDst.c_str() && pW <= sDst.c_str() + sDst.size() )1391     {1392         sDst = sDst.substr(static_cast<SW_SIZETYPE>(pW-sDst.c_str()));1393     }1394 1395     // Otherwise (most cases) apply the assignment bug fix, if applicable1396     // and do the assignment1397 1398     else1399     {1400         Q172398(sDst);1401         sDst.assign(pW);1402     }1403 }1404 #undef StrSizeType1405 inline void    ssasn(std::wstring& sDst, const std::string& sSrc)1406 {1407     if ( sSrc.empty() )1408     {1409         sDst.erase();1410     }1411     else1412     {1413         int nSrc    = http://www.mamicode.com/static_cast<int>(sSrc.size());1414         int nDst    = nSrc;1415 1416         sDst.resize(nSrc+1);1417         PCWSTR szCvt = StdCodeCvt(const_cast<SW_PTRTYPE>(sDst.data()), nDst,1418             sSrc.c_str(), nSrc);1419 1420         sDst.resize(sslen(szCvt));1421     }1422 }1423 inline void    ssasn(std::wstring& sDst, PCSTR pA)1424 {1425     int nSrc    =http://www.mamicode.com/ sslen(pA);1426 1427     if ( 0 == nSrc )1428     {1429         sDst.erase();1430     }1431     else1432     {1433         int nDst    = nSrc;1434         sDst.resize(nDst+1);1435         PCWSTR szCvt = StdCodeCvt(const_cast<SW_PTRTYPE>(sDst.data()), nDst, pA,1436             nSrc);1437 1438         sDst.resize(sslen(szCvt));1439     }1440 }1441 inline void ssasn(std::wstring& sDst, const int nNull)1442 {1443     UNUSED(nNull);1444     ASSERT(nNull==0);1445     sDst.assign(L"");1446 }1447 1448 1449 // -----------------------------------------------------------------------------1450 // ssadd: string object concatenation -- add second argument to first1451 // -----------------------------------------------------------------------------1452 inline void    ssadd(std::string& sDst, const std::wstring& sSrc)1453 {1454     int nSrc    = http://www.mamicode.com/static_cast<int>(sSrc.size());1455 1456     if ( nSrc > 0 )1457     {1458         int nDst    = static_cast<int>(sDst.size());1459         int nAdd    = nSrc;1460 1461         // In MBCS builds, pad the buffer to account for the possibility of1462         // some 3 byte characters.  Not perfect but should get most cases.1463 1464 #ifdef SS_MBCS1465         nAdd        = static_cast<int>(static_cast<double>(nAdd) * 1.3);1466 #endif1467 1468         sDst.resize(nDst+nAdd+1);1469         PCSTR szCvt = StdCodeCvt(const_cast<SS_PTRTYPE>(sDst.data()+nDst),1470             nAdd, sSrc.c_str(), nSrc);1471 1472 #ifdef SS_MBCS1473         sDst.resize(nDst + sslen(szCvt));1474 #else1475         sDst.resize(nDst + nAdd);1476         szCvt;1477 #endif1478     }1479 }1480 inline void    ssadd(std::string& sDst, const std::string& sSrc)1481 {1482     sDst += sSrc;1483 }1484 inline void    ssadd(std::string& sDst, PCWSTR pW)1485 {1486     int nSrc        =http://www.mamicode.com/ sslen(pW);1487     if ( nSrc > 0 )1488     {1489         int nDst    = static_cast<int>(sDst.size());1490         int nAdd    = nSrc;1491 1492 #ifdef SS_MBCS1493         nAdd    = static_cast<int>(static_cast<double>(nAdd) * 1.3);1494 #endif1495 1496         sDst.resize(nDst + nAdd + 1);1497         PCSTR szCvt = StdCodeCvt(const_cast<SS_PTRTYPE>(sDst.data()+nDst),1498             nAdd, pW, nSrc);1499 1500 #ifdef SS_MBCS1501         sDst.resize(nDst + sslen(szCvt));1502 #else1503         sDst.resize(nDst + nSrc);1504         szCvt;1505 #endif1506     }1507 }1508 inline void    ssadd(std::string& sDst, PCSTR pA)1509 {1510     if ( pA )1511     {1512         // If the string being added is our internal string or a part of our1513         // internal string, then we must NOT do any reallocation without1514         // first copying that string to another object (since we‘re using a1515         // direct pointer)1516 1517         if ( pA >= sDst.c_str() && pA <= sDst.c_str()+sDst.length())1518         {1519             if ( sDst.capacity() <= sDst.size()+sslen(pA) )1520                 sDst.append(std::string(pA));1521             else1522                 sDst.append(pA);1523         }1524         else1525         {1526             sDst.append(pA); 1527         }1528     }1529 }1530 inline void    ssadd(std::wstring& sDst, const std::wstring& sSrc)1531 {1532     sDst += sSrc;1533 }1534 inline void    ssadd(std::wstring& sDst, const std::string& sSrc)1535 {1536     if ( !sSrc.empty() )1537     {1538         int nSrc    = http://www.mamicode.com/static_cast<int>(sSrc.size());1539         int nDst    = static_cast<int>(sDst.size());1540 1541         sDst.resize(nDst + nSrc + 1);1542         PCWSTR szCvt = StdCodeCvt(const_cast<SW_PTRTYPE>(sDst.data()+nDst), 1543             nSrc, sSrc.c_str(), nSrc+1);1544 1545 #ifdef SS_MBCS1546         sDst.resize(nDst + sslen(szCvt));1547 #else1548         sDst.resize(nDst + nSrc);1549         szCvt;1550 #endif1551     }1552 }1553 inline void    ssadd(std::wstring& sDst, PCSTR pA)1554 {1555     int nSrc        =http://www.mamicode.com/ sslen(pA);1556 1557     if ( nSrc > 0 )1558     {1559         int nDst    = static_cast<int>(sDst.size());1560 1561         sDst.resize(nDst + nSrc + 1);1562         PCWSTR szCvt = StdCodeCvt(const_cast<SW_PTRTYPE>(sDst.data()+nDst),1563             nSrc, pA, nSrc+1);1564 1565 #ifdef SS_MBCS1566         sDst.resize(nDst + sslen(szCvt));1567 #else1568         sDst.resize(nDst + nSrc);1569         szCvt;1570 #endif1571     }1572 }1573 inline void    ssadd(std::wstring& sDst, PCWSTR pW)1574 {1575     if ( pW )1576     {1577         // If the string being added is our internal string or a part of our1578         // internal string, then we must NOT do any reallocation without1579         // first copying that string to another object (since we‘re using a1580         // direct pointer)1581 1582         if ( pW >= sDst.c_str() && pW <= sDst.c_str()+sDst.length())1583         {1584             if ( sDst.capacity() <= sDst.size()+sslen(pW) )1585                 sDst.append(std::wstring(pW));1586             else1587                 sDst.append(pW);1588         }1589         else1590         {1591             sDst.append(pW);1592         }1593     }1594 }1595 1596 1597 // -----------------------------------------------------------------------------1598 // sscmp: comparison (case sensitive, not affected by locale)1599 // -----------------------------------------------------------------------------1600 template<typename CT>1601 inline int sscmp(const CT* pA1, const CT* pA2)1602 {1603     CT f;1604     CT l;1605 1606     do 1607     {1608         f = *(pA1++);1609         l = *(pA2++);1610     } while ( (f) && (f == l) );1611 1612     return (int)(f - l);1613 }1614 1615 // -----------------------------------------------------------------------------1616 // ssicmp: comparison (case INsensitive, not affected by locale)1617 // -----------------------------------------------------------------------------1618 template<typename CT>1619 inline int ssicmp(const CT* pA1, const CT* pA2)1620 {1621     // Using the "C" locale = "not affected by locale"1622 1623     std::locale loc = std::locale::classic();1624     const std::ctype<CT>& ct = SS_USE_FACET(loc, std::ctype<CT>);1625     CT f;1626     CT l;1627 1628     do 1629     {1630         f = ct.tolower(*(pA1++));1631         l = ct.tolower(*(pA2++));1632     } while ( (f) && (f == l) );1633 1634     return (int)(f - l);1635 }1636 1637 // -----------------------------------------------------------------------------1638 // ssupr/sslwr: Uppercase/Lowercase conversion functions1639 // -----------------------------------------------------------------------------1640 1641 template<typename CT>1642 inline void sslwr(CT* pT, size_t nLen, const std::locale& loc=std::locale())1643 {1644     SS_USE_FACET(loc, std::ctype<CT>).tolower(pT, pT+nLen);1645 }1646 template<typename CT>1647 inline void ssupr(CT* pT, size_t nLen, const std::locale& loc=std::locale())1648 {1649     SS_USE_FACET(loc, std::ctype<CT>).toupper(pT, pT+nLen);1650 }1651 1652 // -----------------------------------------------------------------------------1653 // vsprintf/vswprintf or _vsnprintf/_vsnwprintf equivalents.  In standard1654 // builds we can‘t use _vsnprintf/_vsnwsprintf because they‘re MS extensions.1655 //1656 // -----------------------------------------------------------------------------1657 // Borland‘s headers put some ANSI "C" functions in the ‘std‘ namespace. 1658 // Promote them to the global namespace so we can use them here.1659 1660 #if defined(__BORLANDC__)1661     using std::vsprintf;1662     using std::vswprintf;1663 #endif1664 1665     // GNU is supposed to have vsnprintf and vsnwprintf.  But only the newer1666     // distributions do.1667 1668 #if defined(__GNUC__)1669 1670     inline int ssvsprintf(PSTR pA, size_t nCount, PCSTR pFmtA, va_list vl)1671     { 1672         return vsnprintf(pA, nCount, pFmtA, vl);1673     }1674     inline int ssvsprintf(PWSTR pW, size_t nCount, PCWSTR pFmtW, va_list vl)1675     {1676         return vswprintf(pW, nCount, pFmtW, vl);1677     }1678 1679     // Else if this is VC++ in a regular (non-ANSI) build1680 #elif defined(_MSC_VER) && !defined(SS_ANSI)1681 1682     inline int    ssvsprintf(PSTR pA, size_t nCount, PCSTR pFmtA, va_list vl)1683     { 1684         return _vsnprintf(pA, nCount, pFmtA, vl);1685     }1686     inline int    ssvsprintf(PWSTR pW, size_t nCount, PCWSTR pFmtW, va_list vl)1687     {1688         return _vsnwprintf(pW, nCount, pFmtW, vl);1689     }1690 1691     // Else (an ANSI build) if they want to allow "dangerous" (i.e. non-length-1692     // checked) formatting1693 #elif defined (SS_DANGEROUS_FORMAT)  // ignore buffer size parameter if needed?1694 1695     inline int ssvsprintf(PSTR pA, size_t /*nCount*/, PCSTR pFmtA, va_list vl)1696     {1697         return vsprintf(pA, pFmtA, vl);1698     }1699 1700     inline int ssvsprintf(PWSTR pW, size_t nCount, PCWSTR pFmtW, va_list vl)1701     {1702         // JMO: Some distributions of the "C" have a version of vswprintf that1703         // takes 3 arguments (e.g. Microsoft, Borland, GNU).  Others have a 1704         // version which takes 4 arguments (an extra "count" argument in the1705         // second position.  The best stab I can take at this so far is that if1706         // you are NOT running with MS, Borland, or GNU, then I‘ll assume you1707         // have the version that takes 4 arguments.1708         //1709         // I‘m sure that these checks don‘t catch every platform correctly so if1710         // you get compiler errors on one of the lines immediately below, it‘s1711         // probably because your implemntation takes a different number of1712         // arguments.  You can comment out the offending line (and use the1713         // alternate version) or you can figure out what compiler flag to check1714         // and add that preprocessor check in.  Regardless, if you get an error1715         // on these lines, I‘d sure like to hear from you about it.1716         //1717         // Thanks to Ronny Schulz for the SGI-specific checks here.1718 1719 //    #if !defined(__MWERKS__) && !defined(__SUNPRO_CC_COMPAT) && !defined(__SUNPRO_CC)1720     #if    !defined(_MSC_VER) 1721         && !defined (__BORLANDC__) 1722         && !defined(__GNUC__) 1723         && !defined(__sgi)1724 1725         return vswprintf(pW, nCount, pFmtW, vl);1726 1727     // suddenly with the current SGI 7.3 compiler there is no such function as1728     // vswprintf and the substitute needs explicit casts to compile1729 1730     #elif defined(__sgi)1731 1732         nCount;1733         return vsprintf( (char *)pW, (char *)pFmtW, vl);1734 1735     #else1736 1737         nCount;1738         return vswprintf(pW, pFmtW, vl);1739 1740     #endif1741 1742     }1743 1744     // OK, it‘s some kind of ANSI build but no "dangerous" formatting allowed1745 #else 1746 1747     // GOT COMPILER PROBLEMS HERE?1748     // ---------------------------1749     // Does your compiler choke on one or more of the following 2 functions?  It1750     // probably means that you don‘t have have either vsnprintf or vsnwprintf in1751     // your version of the CRT.  This is understandable since neither is an ANSI1752     // "C" function.  However it still leaves you in a dilemma.  In order to make1753     // this code build, you‘re going to have to to use some non-length-checked1754     // formatting functions that every CRT has:  vsprintf and vswprintf.  1755     //1756     // This is very dangerous.  With the proper erroneous (or malicious) code, it1757     // can lead to buffer overlows and crashing your PC.  Use at your own risk1758     // In order to use them, just #define SS_DANGEROUS_FORMAT at the top of1759     // this file.1760     //1761     // Even THEN you might not be all the way home due to some non-conforming1762     // distributions.  More on this in the comments below.1763 1764     inline int    ssvsprintf(PSTR pA, size_t nCount, PCSTR pFmtA, va_list vl)1765     {1766     #ifdef _MSC_VER1767             return _vsnprintf(pA, nCount, pFmtA, vl);1768     #else1769             return vsnprintf(pA, nCount, pFmtA, vl);1770     #endif1771     }1772     inline int    ssvsprintf(PWSTR pW, size_t nCount, PCWSTR pFmtW, va_list vl)1773     {1774     #ifdef _MSC_VER1775             return _vsnwprintf(pW, nCount, pFmtW, vl);1776     #else1777             return vsnwprintf(pW, nCount, pFmtW, vl);1778     #endif1779     }1780 1781 #endif1782 1783 1784 1785 1786 // -----------------------------------------------------------------------------1787 // ssload: Type safe, overloaded ::LoadString wrappers1788 // There is no equivalent of these in non-Win32-specific builds.  However, I‘m1789 // thinking that with the message facet, there might eventually be one1790 // -----------------------------------------------------------------------------1791 #if defined (SS_WIN32) && !defined(SS_ANSI)1792     inline int ssload(HMODULE hInst, UINT uId, PSTR pBuf, int nMax)1793     {1794         return ::LoadStringA(hInst, uId, pBuf, nMax);1795     }1796     inline int ssload(HMODULE hInst, UINT uId, PWSTR pBuf, int nMax)1797     {1798         return ::LoadStringW(hInst, uId, pBuf, nMax);1799     }1800 #endif1801 1802 1803 // -----------------------------------------------------------------------------1804 // sscoll/ssicoll: Collation wrappers1805 //        Note -- with MSVC I have reversed the arguments order here because the1806 //        functions appear to return the opposite of what they should1807 // -----------------------------------------------------------------------------1808 #ifndef SS_NO_LOCALE1809 template <typename CT>1810 inline int sscoll(const CT* sz1, int nLen1, const CT* sz2, int nLen2)1811 {1812     const std::collate<CT>& coll =1813         SS_USE_FACET(std::locale(), std::collate<CT>);1814 1815     return coll.compare(sz2, sz2+nLen2, sz1, sz1+nLen1);1816 }1817 template <typename CT>1818 inline int ssicoll(const CT* sz1, int nLen1, const CT* sz2, int nLen2)1819 {1820     const std::locale loc;1821     const std::collate<CT>& coll = SS_USE_FACET(loc, std::collate<CT>);1822 1823     // Some implementations seem to have trouble using the collate<>1824     // facet typedefs so we‘ll just default to basic_string and hope1825     // that‘s what the collate facet uses (which it generally should)1826 1827 //    std::collate<CT>::string_type s1(sz1);1828 //    std::collate<CT>::string_type s2(sz2);1829     const std::basic_string<CT> sEmpty;1830     std::basic_string<CT> s1(sz1 ? sz1 : sEmpty.c_str());1831     std::basic_string<CT> s2(sz2 ? sz2 : sEmpty.c_str());1832 1833     sslwr(const_cast<CT*>(s1.c_str()), nLen1, loc);1834     sslwr(const_cast<CT*>(s2.c_str()), nLen2, loc);1835     return coll.compare(s2.c_str(), s2.c_str()+nLen2,1836                         s1.c_str(), s1.c_str()+nLen1);1837 }1838 #endif1839 1840 1841 // -----------------------------------------------------------------------------1842 // ssfmtmsg: FormatMessage equivalents.  Needed because I added a CString facade1843 // Again -- no equivalent of these on non-Win32 builds but their might one day1844 // be one if the message facet gets implemented1845 // -----------------------------------------------------------------------------1846 #if defined (SS_WIN32) && !defined(SS_ANSI)1847     inline DWORD ssfmtmsg(DWORD dwFlags, LPCVOID pSrc, DWORD dwMsgId,1848                           DWORD dwLangId, PSTR pBuf, DWORD nSize,1849                           va_list* vlArgs)1850     { 1851         return FormatMessageA(dwFlags, pSrc, dwMsgId, dwLangId,1852                               pBuf, nSize,vlArgs);1853     }1854     inline DWORD ssfmtmsg(DWORD dwFlags, LPCVOID pSrc, DWORD dwMsgId,1855                           DWORD dwLangId, PWSTR pBuf, DWORD nSize,1856                           va_list* vlArgs)1857     {1858         return FormatMessageW(dwFlags, pSrc, dwMsgId, dwLangId,1859                               pBuf, nSize,vlArgs);1860     }1861 #else1862 #endif1863  1864 1865 1866 // FUNCTION: sscpy.  Copies up to ‘nMax‘ characters from pSrc to pDst.1867 // -----------------------------------------------------------------------------1868 // FUNCTION:  sscpy1869 //        inline int sscpy(PSTR pDst, PCSTR pSrc, int nMax=-1);1870 //        inline int sscpy(PUSTR pDst,  PCSTR pSrc, int nMax=-1)1871 //        inline int sscpy(PSTR pDst, PCWSTR pSrc, int nMax=-1);1872 //        inline int sscpy(PWSTR pDst, PCWSTR pSrc, int nMax=-1);1873 //        inline int sscpy(PWSTR pDst, PCSTR pSrc, int nMax=-1);1874 //1875 // DESCRIPTION:1876 //        This function is very much (but not exactly) like strcpy.  These1877 //        overloads simplify copying one C-style string into another by allowing1878 //        the caller to specify two different types of strings if necessary.1879 //1880 //        The strings must NOT overlap1881 //1882 //        "Character" is expressed in terms of the destination string, not1883 //        the source.  If no ‘nMax‘ argument is supplied, then the number of1884 //        characters copied will be sslen(pSrc).  A NULL terminator will1885 //        also be added so pDst must actually be big enough to hold nMax+11886 //        characters.  The return value is the number of characters copied,1887 //        not including the NULL terminator.1888 //1889 // PARAMETERS: 1890 //        pSrc - the string to be copied FROM.  May be a char based string, an1891 //               MBCS string (in Win32 builds) or a wide string (wchar_t).1892 //        pSrc - the string to be copied TO.  Also may be either MBCS or wide1893 //        nMax - the maximum number of characters to be copied into szDest.  Note1894 //               that this is expressed in whatever a "character" means to pDst.1895 //               If pDst is a wchar_t type string than this will be the maximum1896 //               number of wchar_ts that my be copied.  The pDst string must be1897 //               large enough to hold least nMaxChars+1 characters.1898 //               If the caller supplies no argument for nMax this is a signal to1899 //               the routine to copy all the characters in pSrc, regardless of1900 //               how long it is.1901 //1902 // RETURN VALUE: none1903 // -----------------------------------------------------------------------------1904 template<typename CT1, typename CT2>1905 inline int sscpycvt(CT1* pDst, const CT2* pSrc, int nMax)1906 {1907     // Note -- we assume pDst is big enough to hold pSrc.  If not, we‘re in1908     // big trouble.  No bounds checking.  Caveat emptor.1909     1910     int nSrc =http://www.mamicode.com/ sslen(pSrc);1911 1912     const CT1* szCvt = StdCodeCvt(pDst, nMax, pSrc, nSrc);1913 1914     // If we‘re copying the same size characters, then all the "code convert"1915     // just did was basically memcpy so the #of characters copied is the same1916     // as the number requested.  I should probably specialize this function1917     // template to achieve this purpose as it is silly to do a runtime check1918     // of a fact known at compile time.  I‘ll get around to it.1919 1920     return sslen(szCvt);1921 }1922 1923 inline int sscpycvt(PSTR pDst, PCSTR pSrc, int nMax)1924 {1925     int nCount = nMax;1926     for (; nCount > 0 && *pSrc; ++pSrc, ++pDst, --nCount)1927         std::basic_string<char>::traits_type::assign(*pDst, *pSrc);1928 1929     *pDst =  \0;1930     return nMax - nCount;1931 }1932 inline int sscpycvt(PWSTR pDst, PCWSTR pSrc, int nMax)1933 {1934     int nCount = nMax;1935     for (; nCount > 0 && *pSrc; ++pSrc, ++pDst, --nCount)1936         std::basic_string<wchar_t>::traits_type::assign(*pDst, *pSrc);1937 1938     *pDst = L\0;1939     return nMax - nCount;1940 }1941 inline int sscpycvt(PWSTR pDst, PCSTR pSrc, int nMax)1942 {1943     // Note -- we assume pDst is big enough to hold pSrc.  If not, we‘re in1944     // big trouble.  No bounds checking.  Caveat emptor.1945 1946     const PWSTR szCvt = StdCodeCvt(pDst, nMax, pSrc, nMax);1947     return sslen(szCvt);1948 }1949 1950 template<typename CT1, typename CT2>1951 inline int sscpy(CT1* pDst, const CT2* pSrc, int nMax, int nLen)1952 {1953     return sscpycvt(pDst, pSrc, SSMIN(nMax, nLen));1954 }1955 template<typename CT1, typename CT2>1956 inline int sscpy(CT1* pDst, const CT2* pSrc, int nMax)1957 {1958     return sscpycvt(pDst, pSrc, SSMIN(nMax, sslen(pSrc)));1959 }1960 template<typename CT1, typename CT2>1961 inline int sscpy(CT1* pDst, const CT2* pSrc)1962 {1963     return sscpycvt(pDst, pSrc, sslen(pSrc));1964 }1965 template<typename CT1, typename CT2>1966 inline int sscpy(CT1* pDst, const std::basic_string<CT2>& sSrc, int nMax)1967 {1968     return sscpycvt(pDst, sSrc.c_str(), SSMIN(nMax, (int)sSrc.length()));1969 }1970 template<typename CT1, typename CT2>1971 inline int sscpy(CT1* pDst, const std::basic_string<CT2>& sSrc)1972 {1973     return sscpycvt(pDst, sSrc.c_str(), (int)sSrc.length());1974 }1975 1976 #ifdef SS_INC_COMDEF1977     template<typename CT1>1978     inline int sscpy(CT1* pDst, const _bstr_t& bs, int nMax)1979     {1980         return sscpycvt(pDst, static_cast<PCOLESTR>(bs),1981             SSMIN(nMax, static_cast<int>(bs.length())));1982     }1983     template<typename CT1>1984     inline int sscpy(CT1* pDst, const _bstr_t& bs)1985     {1986         return sscpy(pDst, bs, static_cast<int>(bs.length()));1987     }1988 #endif1989 1990 1991 // -----------------------------------------------------------------------------1992 // Functional objects for changing case.  They also let you pass locales1993 // -----------------------------------------------------------------------------1994 1995 #ifdef SS_NO_LOCALE1996     template<typename CT>1997     struct SSToUpper : public std::unary_function<CT, CT>1998     {1999         inline CT operator()(const CT& t) const2000         {2001             return sstoupper(t);2002         }2003     };2004     template<typename CT>2005     struct SSToLower : public std::unary_function<CT, CT>2006     {2007         inline CT operator()(const CT& t) const2008         {2009             return sstolower(t);2010         }2011     };2012 #else2013     template<typename CT>2014     struct SSToUpper : public std::binary_function<CT, std::locale, CT>2015     {2016         inline CT operator()(const CT& t, const std::locale& loc) const2017         {2018             return sstoupper<CT>(t, loc);2019         }2020     };2021     template<typename CT>2022     struct SSToLower : public std::binary_function<CT, std::locale, CT>2023     {2024         inline CT operator()(const CT& t, const std::locale& loc) const2025         {2026             return sstolower<CT>(t, loc);2027         }2028     };2029 #endif2030 2031 // This struct is used for TrimRight() and TrimLeft() function implementations.2032 //template<typename CT>2033 //struct NotSpace : public std::unary_function<CT, bool>2034 //{2035 //    const std::locale& loc;2036 //    inline NotSpace(const std::locale& locArg) : loc(locArg) {}2037 //    inline bool operator() (CT t) { return !std::isspace(t, loc); }2038 //};2039 template<typename CT>2040 struct NotSpace : public std::unary_function<CT, bool>2041 {2042     // DINKUMWARE BUG:2043     // Note -- using std::isspace in a COM DLL gives us access violations2044     // because it causes the dynamic addition of a function to be called2045     // when the library shuts down.  Unfortunately the list is maintained2046     // in DLL memory but the function is in static memory.  So the COM DLL2047     // goes away along with the function that was supposed to be called,2048     // and then later when the DLL CRT shuts down it unloads the list and2049     // tries to call the long-gone function.2050     // This is DinkumWare‘s implementation problem.  If you encounter this2051     // problem, you may replace the calls here with good old isspace() and2052     // iswspace() from the CRT unless they specify SS_ANSI2053     2054 #ifdef SS_NO_LOCALE2055     2056     bool operator() (CT t) const { return !ssisspace(t); }2057 2058 #else2059     const std::locale loc;2060     NotSpace(const std::locale& locArg=std::locale()) : loc(locArg) {}2061     bool operator() (CT t) const { return !std::isspace(t, loc); }2062 #endif2063 };2064 2065 2066 2067 2068 //            Now we can define the template (finally!)2069 // =============================================================================2070 // TEMPLATE: CStdStr2071 //        template<typename CT> class CStdStr : public std::basic_string<CT>2072 //2073 // REMARKS:2074 //        This template derives from basic_string<CT> and adds some MFC CString-2075 //        like functionality2076 //2077 //        Basically, this is my attempt to make Standard C++ library strings as2078 //        easy to use as the MFC CString class.2079 //2080 //        Note that although this is a template, it makes the assumption that the2081 //        template argument (CT, the character type) is either char or wchar_t.  2082 // =============================================================================2083 2084 //#define CStdStr _SS    // avoid compiler warning 47862085 2086 //    template<typename ARG> ARG& FmtArg(ARG& arg)  { return arg; }2087 //    PCSTR  FmtArg(const std::string& arg)  { return arg.c_str(); }2088 //    PCWSTR FmtArg(const std::wstring& arg) { return arg.c_str(); }2089 2090 template<typename ARG>2091 struct FmtArg2092 {2093     explicit FmtArg(const ARG& arg) : a_(arg) {}2094     const ARG& operator()() const { return a_; }2095     const ARG& a_;2096 private:2097     FmtArg& operator=(const FmtArg&) { return *this; }2098 };2099 2100 template<typename CT>2101 class CStdStr : public std::basic_string<CT>2102 {2103     // Typedefs for shorter names.  Using these names also appears to help2104     // us avoid some ambiguities that otherwise arise on some platforms2105 2106     #define MYBASE std::basic_string<CT>                 // my base class2107     //typedef typename std::basic_string<CT>        MYBASE;     // my base class2108     typedef CStdStr<CT>                            MYTYPE;     // myself2109     typedef typename MYBASE::const_pointer        PCMYSTR; // PCSTR or PCWSTR 2110     typedef typename MYBASE::pointer            PMYSTR;     // PSTR or PWSTR2111     typedef typename MYBASE::iterator            MYITER;  // my iterator type2112     typedef typename MYBASE::const_iterator        MYCITER; // you get the idea...2113     typedef typename MYBASE::reverse_iterator    MYRITER;2114     typedef typename MYBASE::size_type            MYSIZE;   2115     typedef typename MYBASE::value_type            MYVAL; 2116     typedef typename MYBASE::allocator_type        MYALLOC;2117     2118 public:2119     // shorthand conversion from PCTSTR to string resource ID2120     #define SSRES(pctstr)  LOWORD(reinterpret_cast<unsigned long>(pctstr))    2121 2122     bool TryLoad(const void* pT)2123     {2124         bool bLoaded = false;2125 2126 #if defined(SS_WIN32) && !defined(SS_ANSI)2127         if ( ( pT != NULL ) && SS_IS_INTRESOURCE(pT) )2128         {2129             UINT nId = LOWORD(reinterpret_cast<unsigned long>(pT));2130             if ( !LoadString(nId) )2131             {2132                 TRACE(_T("Can‘t load string %u\n"), SSRES(pT));2133             }2134             bLoaded = true;2135         }2136 #endif2137 2138         return bLoaded;2139     }2140 2141 2142     // CStdStr inline constructors2143     CStdStr()2144     {2145     }2146 2147     CStdStr(const MYTYPE& str) : MYBASE(SSREF(str))2148     {2149     }2150 2151     CStdStr(const std::string& str)2152     {2153         ssasn(*this, SSREF(str));2154     }2155 2156     CStdStr(const std::wstring& str)2157     {2158         ssasn(*this, SSREF(str));2159     }2160 2161     CStdStr(PCMYSTR pT, MYSIZE n) : MYBASE(NULL == pT ? MYTYPE().c_str() : pT, n)2162     {2163     }2164 2165 #ifdef SS_UNSIGNED2166     CStdStr(PCUSTR pU)2167     {2168         *this = reinterpret_cast<PCSTR>(pU);2169     }2170 #endif2171 2172     CStdStr(PCSTR pA)2173     {2174     #ifdef SS_ANSI2175         *this = pA;2176     #else2177         if ( !TryLoad(pA) )2178             *this = pA;2179     #endif2180     }2181 2182     CStdStr(PCWSTR pW)2183     {2184     #ifdef SS_ANSI2185         *this = pW;2186     #else2187         if ( !TryLoad(pW) )2188             *this = pW;2189     #endif2190     }2191 2192     CStdStr(MYCITER first, MYCITER last)2193         : MYBASE(first, last)2194     {2195     }2196 2197     CStdStr(MYSIZE nSize, MYVAL ch, const MYALLOC& al=MYALLOC())2198         : MYBASE(nSize, ch, al)2199     {2200     }2201 2202     #ifdef SS_INC_COMDEF2203         CStdStr(const _bstr_t& bstr)2204         {2205             if ( bstr.length() > 0 )2206                 this->append(static_cast<PCMYSTR>(bstr), bstr.length());2207         }2208     #endif2209 2210     // CStdStr inline assignment operators -- the ssasn function now takes care2211     // of fixing  the MSVC assignment bug (see knowledge base article Q172398).2212     MYTYPE& operator=(const MYTYPE& str)2213     { 2214         ssasn(*this, str); 2215         return *this;2216     }2217 2218     MYTYPE& operator=(const std::string& str)2219     {2220         ssasn(*this, str);2221         return *this;2222     }2223 2224     MYTYPE& operator=(const std::wstring& str)2225     {2226         ssasn(*this, str);2227         return *this;2228     }2229 2230     MYTYPE& operator=(PCSTR pA)2231     {2232         ssasn(*this, pA);2233         return *this;2234     }2235 2236     MYTYPE& operator=(PCWSTR pW)2237     {2238         ssasn(*this, pW);2239         return *this;2240     }2241 2242 #ifdef SS_UNSIGNED2243     MYTYPE& operator=(PCUSTR pU)2244     {2245         ssasn(*this, reinterpret_cast<PCSTR>(pU));2246         return *this;2247     }2248 #endif2249 2250     MYTYPE& operator=(CT t)2251     {2252         Q172398(*this);2253         this->assign(1, t);2254         return *this;2255     }2256 2257     #ifdef SS_INC_COMDEF2258         MYTYPE& operator=(const _bstr_t& bstr)2259         {2260             if ( bstr.length() > 0 )2261             {2262                 this->assign(static_cast<PCMYSTR>(bstr), bstr.length());2263                 return *this;2264             }2265             else2266             {2267                 this->erase();2268                 return *this;2269             }2270         }2271     #endif2272 2273 2274     // Overloads  also needed to fix the MSVC assignment bug (KB: Q172398)2275     //  *** Thanks to Pete The Plumber for catching this one ***2276     // They also are compiled if you have explicitly turned off refcounting2277     #if ( defined(_MSC_VER) && ( _MSC_VER < 1200 ) ) || defined(SS_NO_REFCOUNT) 2278 2279         MYTYPE& assign(const MYTYPE& str)2280         {2281             Q172398(*this);2282             sscpy(GetBuffer(str.size()+1), SSREF(str));2283             this->ReleaseBuffer(str.size());2284             return *this;2285         }2286 2287         MYTYPE& assign(const MYTYPE& str, MYSIZE nStart, MYSIZE nChars)2288         {2289             // This overload of basic_string::assign is supposed to assign up to2290             // <nChars> or the NULL terminator, whichever comes first.  Since we2291             // are about to call a less forgiving overload (in which <nChars>2292             // must be a valid length), we must adjust the length here to a safe2293             // value.  Thanks to Ullrich Poll鋒ne for catching this bug2294 2295             nChars        = SSMIN(nChars, str.length() - nStart);2296             MYTYPE strTemp(str.c_str()+nStart, nChars);2297             Q172398(*this);2298             this->assign(strTemp);2299             return *this;2300         }2301 2302         MYTYPE& assign(const MYBASE& str)2303         {2304             ssasn(*this, str);2305             return *this;2306         }2307 2308         MYTYPE& assign(const MYBASE& str, MYSIZE nStart, MYSIZE nChars)2309         {2310             // This overload of basic_string::assign is supposed to assign up to2311             // <nChars> or the NULL terminator, whichever comes first.  Since we2312             // are about to call a less forgiving overload (in which <nChars>2313             // must be a valid length), we must adjust the length here to a safe2314             // value. Thanks to Ullrich Poll鋒ne for catching this bug2315 2316             nChars        = SSMIN(nChars, str.length() - nStart);2317 2318             // Watch out for assignment to self2319 2320             if ( this == &str )2321             {2322                 MYTYPE strTemp(str.c_str() + nStart, nChars);2323                 static_cast<MYBASE*>(this)->assign(strTemp);2324             }2325             else2326             {2327                 Q172398(*this);2328                 static_cast<MYBASE*>(this)->assign(str.c_str()+nStart, nChars);2329             }2330             return *this;2331         }2332 2333         MYTYPE& assign(const CT* pC, MYSIZE nChars)2334         {2335             // Q172398 only fix -- erase before assigning, but not if we‘re2336             // assigning from our own buffer2337 2338     #if defined ( _MSC_VER ) && ( _MSC_VER < 1200 )2339             if ( !this->empty() &&2340                 ( pC < this->data() || pC > this->data() + this->capacity() ) )2341             {2342                 this->erase();2343             }2344     #endif2345             Q172398(*this);2346             static_cast<MYBASE*>(this)->assign(pC, nChars);2347             return *this;2348         }2349 2350         MYTYPE& assign(MYSIZE nChars, MYVAL val)2351         {2352             Q172398(*this);2353             static_cast<MYBASE*>(this)->assign(nChars, val);2354             return *this;2355         }2356 2357         MYTYPE& assign(const CT* pT)2358         {2359             return this->assign(pT, MYBASE::traits_type::length(pT));2360         }2361 2362         MYTYPE& assign(MYCITER iterFirst, MYCITER iterLast)2363         {2364     #if defined ( _MSC_VER ) && ( _MSC_VER < 1200 ) 2365             // Q172398 fix.  don‘t call erase() if we‘re assigning from ourself2366             if ( iterFirst < this->begin() ||2367                  iterFirst > this->begin() + this->size() )2368             {2369                 this->erase()2370             }2371     #endif2372             this->replace(this->begin(), this->end(), iterFirst, iterLast);2373             return *this;2374         }2375     #endif2376 2377 2378     // -------------------------------------------------------------------------2379     // CStdStr inline concatenation.2380     // -------------------------------------------------------------------------2381     MYTYPE& operator+=(const MYTYPE& str)2382     {2383         ssadd(*this, str);2384         return *this;2385     }2386 2387     MYTYPE& operator+=(const std::string& str)2388     {2389         ssadd(*this, str);2390         return *this; 2391     }2392 2393     MYTYPE& operator+=(const std::wstring& str)2394     {2395         ssadd(*this, str);2396         return *this;2397     }2398 2399     MYTYPE& operator+=(PCSTR pA)2400     {2401         ssadd(*this, pA);2402         return *this;2403     }2404 2405     MYTYPE& operator+=(PCWSTR pW)2406     {2407         ssadd(*this, pW);2408         return *this;2409     }2410 2411     MYTYPE& operator+=(CT t)2412     {2413         this->append(1, t);2414         return *this;2415     }2416     #ifdef SS_INC_COMDEF    // if we have _bstr_t, define a += for it too.2417         MYTYPE& operator+=(const _bstr_t& bstr)2418         {2419             return this->operator+=(static_cast<PCMYSTR>(bstr));2420         }2421     #endif2422 2423 2424     // -------------------------------------------------------------------------2425     // Case changing functions2426     // -------------------------------------------------------------------------2427 2428     MYTYPE& ToUpper(const std::locale& loc=std::locale())2429     {2430         // Note -- if there are any MBCS character sets in which the lowercase2431         // form a character takes up a different number of bytes than the2432         // uppercase form, this would probably not work...2433 2434         std::transform(this->begin(),2435                        this->end(),2436                        this->begin(),2437 #ifdef SS_NO_LOCALE2438                        SSToUpper<CT>());2439 #else2440                        std::bind2nd(SSToUpper<CT>(), loc));2441 #endif2442 2443         // ...but if it were, this would probably work better.  Also, this way2444         // seems to be a bit faster when anything other then the "C" locale is2445         // used...2446 2447 //        if ( !empty() )2448 //        {2449 //            ssupr(this->GetBuf(), this->size(), loc);2450 //            this->RelBuf();2451 //        }2452 2453         return *this;2454     }2455 2456     MYTYPE& ToLower(const std::locale& loc=std::locale())2457     {2458         // Note -- if there are any MBCS character sets in which the lowercase2459         // form a character takes up a different number of bytes than the2460         // uppercase form, this would probably not work...2461 2462         std::transform(this->begin(),2463                        this->end(),2464                        this->begin(),2465 #ifdef SS_NO_LOCALE2466                        SSToLower<CT>());2467 #else2468                        std::bind2nd(SSToLower<CT>(), loc));2469 #endif2470 2471         // ...but if it were, this would probably work better.  Also, this way2472         // seems to be a bit faster when anything other then the "C" locale is2473         // used...2474 2475 //        if ( !empty() )2476 //        {2477 //            sslwr(this->GetBuf(), this->size(), loc);2478 //            this->RelBuf();2479 //        }2480         return *this;2481     }2482 2483 2484     MYTYPE& Normalize()2485     {2486         return Trim().ToLower();2487     }2488 2489 2490     // -------------------------------------------------------------------------2491     // CStdStr -- Direct access to character buffer.  In the MS‘ implementation,2492     // the at() function that we use here also calls _Freeze() providing us some2493     // protection from multithreading problems associated with ref-counting.2494     // In VC 7 and later, of course, the ref-counting stuff is gone.2495     // -------------------------------------------------------------------------2496 2497     CT* GetBuf(int nMinLen=-1)2498     {2499         if ( static_cast<int>(this->size()) < nMinLen )2500             this->resize(static_cast<MYSIZE>(nMinLen));2501 2502         return this->empty() ? const_cast<CT*>(this->data()) : &(this->at(0));2503     }2504 2505     CT* SetBuf(int nLen)2506     {2507         nLen = ( nLen > 0 ? nLen : 0 );2508         if ( this->capacity() < 1 && nLen == 0 )2509             this->resize(1);2510 2511         this->resize(static_cast<MYSIZE>(nLen));2512         return const_cast<CT*>(this->data());2513     }2514     void RelBuf(int nNewLen=-1)2515     {2516         this->resize(static_cast<MYSIZE>(nNewLen > -1 ? nNewLen :2517                                                         sslen(this->c_str())));2518     }2519 2520     void BufferRel()         { RelBuf(); }            // backwards compatability2521     CT*  Buffer()             { return GetBuf(); }    // backwards compatability2522     CT*  BufferSet(int nLen) { return SetBuf(nLen);}// backwards compatability2523 2524     bool Equals(const CT* pT, bool bUseCase=false) const2525     {2526         return  0 == (bUseCase ? this->compare(pT) : ssicmp(this->c_str(), pT));2527     } 2528 2529     // -------------------------------------------------------------------------2530     // FUNCTION:  CStdStr::Load2531     // REMARKS:2532     //        Loads string from resource specified by nID2533     //2534     // PARAMETERS:2535     //        nID - resource Identifier.  Purely a Win32 thing in this case2536     //2537     // RETURN VALUE:2538     //        true if successful, false otherwise2539     // -------------------------------------------------------------------------2540 2541 #ifndef SS_ANSI2542 2543     bool Load(UINT nId, HMODULE hModule=NULL)2544     {2545         bool bLoaded        = false;    // set to true of we succeed.2546 2547     #ifdef _MFC_VER        // When in Rome (or MFC land)...2548 2549         // If they gave a resource handle, use it.  Note - this is archaic2550         // and not really what I would recommend.  But then again, in MFC2551         // land, you ought to be using CString for resources anyway since2552         // it walks the resource chain for you.2553 2554         HMODULE hModuleOld = NULL;2555 2556         if ( NULL != hModule )2557         {2558             hModuleOld = AfxGetResourceHandle();2559             AfxSetResourceHandle(hModule);2560         }2561 2562         // ...load the string2563 2564         CString strRes;2565         bLoaded                = FALSE != strRes.LoadString(nId);2566 2567         // ...and if we set the resource handle, restore it.2568 2569         if ( NULL != hModuleOld )2570             AfxSetResourceHandle(hModule);2571 2572         if ( bLoaded )2573             *this            = strRes;2574 2575     #else // otherwise make our own hackneyed version of CString‘s Load2576         2577         // Get the resource name and module handle2578 2579         if ( NULL == hModule )2580             hModule            = GetResourceHandle();2581 2582         PCTSTR szName        = MAKEINTRESOURCE((nId>>4)+1); // lifted 2583         DWORD dwSize        = 0;2584 2585         // No sense continuing if we can‘t find the resource2586 2587         HRSRC hrsrc            =http://www.mamicode.com/ ::FindResource(hModule, szName, RT_STRING);2588 2589         if ( NULL == hrsrc )2590         {2591             TRACE(_T("Cannot find resource %d: 0x%X"), nId, ::GetLastError());2592         }2593         else if ( 0 == (dwSize = ::SizeofResource(hModule, hrsrc) / sizeof(CT)))2594         {2595             TRACE(_T("Cant get size of resource %d 0x%X\n"),nId,GetLastError());2596         }2597         else2598         {2599             bLoaded            = 0 != ssload(hModule, nId, GetBuf(dwSize), dwSize);2600             ReleaseBuffer();2601         }2602 2603     #endif  // #ifdef _MFC_VER2604 2605         if ( !bLoaded )2606             TRACE(_T("String not loaded 0x%X\n"), ::GetLastError());2607 2608         return bLoaded;2609     }2610 2611 #endif  // #ifdef SS_ANSI2612     2613     // -------------------------------------------------------------------------2614     // FUNCTION:  CStdStr::Format2615     //        void _cdecl Formst(CStdStringA& PCSTR szFormat, ...)2616     //        void _cdecl Format(PCSTR szFormat);2617     //           2618     // DESCRIPTION:2619     //        This function does sprintf/wsprintf style formatting on CStdStringA2620     //        objects.  It looks a lot like MFC‘s CString::Format.  Some people2621     //        might even call this identical.  Fortunately, these people are now2622     //        dead... heh heh.2623     //2624     // PARAMETERS: 2625     //        nId - ID of string resource holding the format string2626     //        szFormat - a PCSTR holding the format specifiers2627     //        argList - a va_list holding the arguments for the format specifiers.2628     //2629     // RETURN VALUE:  None.2630     // -------------------------------------------------------------------------2631     // formatting (using wsprintf style formatting)2632 2633     // If they want a Format() function that safely handles string objects2634     // without casting2635  2636 #ifdef SS_SAFE_FORMAT       2637     2638     // Question:  Joe, you wacky coder you, why do you have so many overloads2639     //      of the Format() function2640     // Answer:  One reason only - CString compatability.  In short, by making2641     //      the Format() function a template this way, I can do strong typing2642     //      and allow people to pass CStdString arguments as fillers for2643     //      "%s" format specifiers without crashing their program!  The downside2644     //      is that I need to overload on the number of arguments.   If you are2645     //      passing more arguments than I have listed below in any of my2646     //      overloads, just add another one.2647     //2648     //      Yes, yes, this is really ugly.  In essence what I am doing here is2649     //      protecting people from a bad (and incorrect) programming practice2650     //      that they should not be doing anyway.  I am protecting them from2651     //      themselves.  Why am I doing this?  Well, if you had any idea the2652     //      number of times I‘ve been emailed by people about this2653     //      "incompatability" in my code, you wouldn‘t ask.2654 2655     void Fmt(const CT* szFmt, ...)2656     {2657         va_list argList;2658         va_start(argList, szFmt);2659         FormatV(szFmt, argList);2660         va_end(argList);2661     }2662 2663 #ifndef SS_ANSI2664 2665     void Format(UINT nId)2666     {2667         MYTYPE strFmt;2668         if ( strFmt.Load(nId) ) 2669             this->swap(strFmt);2670     }2671     template<class A1>2672     void Format(UINT nId, const A1& v)2673     {2674         MYTYPE strFmt;2675         if ( strFmt.Load(nId) )2676             Fmt(strFmt, FmtArg<A1>(v)());2677     }2678     template<class A1, class A2>2679     void Format(UINT nId, const A1& v1, const A2& v2)2680     {2681         MYTYPE strFmt;2682         if ( strFmt.Load(nId) )2683            Fmt(strFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)());2684     }2685     template<class A1, class A2, class A3>2686     void Format(UINT nId, const A1& v1, const A2& v2, const A3& v3)2687     {2688         MYTYPE strFmt;2689         if ( strFmt.Load(nId) )2690         {2691             Fmt(strFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)(),2692             FmtArg<A3>(v3)());2693         }2694     }2695     template<class A1, class A2, class A3, class A4>2696     void Format(UINT nId, const A1& v1, const A2& v2, const A3& v3,2697                 const A4& v4)2698     {2699         MYTYPE strFmt;2700         if ( strFmt.Load(nId) )2701         {2702             Fmt(strFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)(),2703                 FmtArg<A3>(v3)(), FmtArg<A4>(v4)());2704         }2705     }2706     template<class A1, class A2, class A3, class A4, class A5>2707     void Format(UINT nId, const A1& v1, const A2& v2, const A3& v3,2708                 const A4& v4, const A5& v5)2709     {2710         MYTYPE strFmt;2711         if ( strFmt.Load(nId) )2712         {2713             Fmt(strFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)(),2714                 FmtArg<A3>(v3)(), FmtArg<A4>(v4)(), FmtArg<A5>(v5)());2715         }2716     }2717     template<class A1, class A2, class A3, class A4, class A5, class A6>2718     void Format(UINT nId, const A1& v1, const A2& v2, const A3& v3,2719                 const A4& v4, const A5& v5, const A6& v6)2720     {2721         MYTYPE strFmt;2722         if ( strFmt.Load(nId) )2723         {2724             Fmt(strFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)(),2725                 FmtArg<A3>(v3)(), FmtArg<A4>(v4)(),FmtArg<A5>(v5)(),2726                 FmtArg<A6>(v6)());2727         }2728     }2729     template<class A1, class A2, class A3, class A4, class A5, class A6,2730         class A7>2731     void Format(UINT nId, const A1& v1, const A2& v2, const A3& v3,2732                 const A4& v4, const A5& v5, const A6& v6, const A7& v7)2733     {2734         MYTYPE strFmt;2735         if ( strFmt.Load(nId) )2736         {2737             Fmt(strFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)(),2738                 FmtArg<A3>(v3)(), FmtArg<A4>(v4)(),FmtArg<A5>(v5)(),2739                 FmtArg<A6>(v6)(), FmtArg<A7>(v7)());2740         }2741     }2742     template<class A1, class A2, class A3, class A4, class A5, class A6,2743         class A7, class A8>2744     void Format(UINT nId, const A1& v1, const A2& v2, const A3& v3,2745                 const A4& v4, const A5& v5, const A6& v6, const A7& v7,2746                 const A8& v8)2747     {2748         MYTYPE strFmt;2749         if ( strFmt.Load(nId) )2750         {2751            Fmt(strFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)(),2752                 FmtArg<A3>(v3)(), FmtArg<A4>(v4)(), FmtArg<A5>(v5)(),2753                 FmtArg<A6>(v6)(), FmtArg<A7>(v7)(), FmtArg<A8>(v8)());2754         }2755     }2756     template<class A1, class A2, class A3, class A4, class A5, class A6,2757         class A7, class A8, class A9>2758     void Format(UINT nId, const A1& v1, const A2& v2, const A3& v3,2759                 const A4& v4, const A5& v5, const A6& v6, const A7& v7,2760                 const A8& v8, const A9& v9)2761     {2762         MYTYPE strFmt;2763         if ( strFmt.Load(nId) )2764         {2765             Fmt(strFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)(),2766                 FmtArg<A3>(v3)(), FmtArg<A4>(v4)(), FmtArg<A5>(v5)(),2767                 FmtArg<A6>(v6)(), FmtArg<A7>(v7)(), FmtArg<A8>(v8)(),2768                 FmtArg<A9>(v9)());2769         }2770     }2771     template<class A1, class A2, class A3, class A4, class A5, class A6,2772         class A7, class A8, class A9, class A10>2773     void Format(UINT nId, const A1& v1, const A2& v2, const A3& v3,2774                 const A4& v4, const A5& v5, const A6& v6, const A7& v7,2775                 const A8& v8, const A9& v9, const A10& v10)2776     {2777         MYTYPE strFmt;2778         if ( strFmt.Load(nId) )2779         {2780             Fmt(strFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)(),2781                 FmtArg<A3>(v3)(), FmtArg<A4>(v4)(), FmtArg<A5>(v5)(),2782                 FmtArg<A6>(v6)(), FmtArg<A7>(v7)(), FmtArg<A8>(v8)(),2783                 FmtArg<A9>(v9)(), FmtArg<A10>(v10)());2784         }2785     }2786     template<class A1, class A2, class A3, class A4, class A5, class A6,2787         class A7, class A8, class A9, class A10, class A11>2788     void Format(UINT nId, const A1& v1, const A2& v2, const A3& v3,2789                 const A4& v4, const A5& v5, const A6& v6, const A7& v7,2790                 const A8& v8, const A9& v9, const A10& v10, const A11& v11)2791     {2792         MYTYPE strFmt;2793         if ( strFmt.Load(nId) )2794         {2795             Fmt(strFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)(),2796                 FmtArg<A3>(v3)(), FmtArg<A4>(v4)(), FmtArg<A5>(v5)(),2797                 FmtArg<A6>(v6)(), FmtArg<A7>(v7)(), FmtArg<A8>(v8)(),2798                 FmtArg<A9>(v9)(),FmtArg<A10>(v10)(),FmtArg<A11>(v11)());2799         }2800     }2801     template<class A1, class A2, class A3, class A4, class A5, class A6,2802         class A7, class A8, class A9, class A10, class A11, class A12>2803     void Format(UINT nId, const A1& v1, const A2& v2, const A3& v3,2804                 const A4& v4, const A5& v5, const A6& v6, const A7& v7,2805                 const A8& v8, const A9& v9, const A10& v10, const A11& v11,2806                 const A12& v12)2807     {2808         MYTYPE strFmt;2809         if ( strFmt.Load(nId) )2810         {2811             Fmt(strFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)(),2812                 FmtArg<A3>(v3)(), FmtArg<A4>(v4)(), FmtArg<A5>(v5)(),2813                 FmtArg<A6>(v6)(), FmtArg<A7>(v7)(), FmtArg<A8>(v8)(),2814                 FmtArg<A9>(v9)(), FmtArg<A10>(v10)(),FmtArg<A11>(v11)(),2815                 FmtArg<A12>(v12)());2816         }2817     }2818     template<class A1, class A2, class A3, class A4, class A5, class A6,2819         class A7, class A8, class A9, class A10, class A11, class A12,2820         class A13>2821     void Format(UINT nId, const A1& v1, const A2& v2, const A3& v3,2822                 const A4& v4, const A5& v5, const A6& v6, const A7& v7,2823                 const A8& v8, const A9& v9, const A10& v10, const A11& v11,2824                 const A12& v12, const A13& v13)2825     {2826         MYTYPE strFmt;2827         if ( strFmt.Load(nId) )2828         {2829             Fmt(strFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)(),2830                 FmtArg<A3>(v3)(), FmtArg<A4>(v4)(), FmtArg<A5>(v5)(),2831                 FmtArg<A6>(v6)(), FmtArg<A7>(v7)(), FmtArg<A8>(v8)(),2832                 FmtArg<A9>(v9)(), FmtArg<A10>(v10)(),FmtArg<A11>(v11)(),2833                 FmtArg<A12>(v12)(), FmtArg<A13>(v13)());2834         }2835     }2836     template<class A1, class A2, class A3, class A4, class A5, class A6,2837         class A7, class A8, class A9, class A10, class A11, class A12,2838         class A13, class A14>2839     void Format(UINT nId, const A1& v1, const A2& v2, const A3& v3,2840                 const A4& v4, const A5& v5, const A6& v6, const A7& v7,2841                 const A8& v8, const A9& v9, const A10& v10, const A11& v11,2842                 const A12& v12, const A13& v13, const A14& v14)2843     {2844         MYTYPE strFmt;2845         if ( strFmt.Load(nId) )2846         {2847             Fmt(strFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)(),2848                 FmtArg<A3>(v3)(), FmtArg<A4>(v4)(), FmtArg<A5>(v5)(),2849                 FmtArg<A6>(v6)(), FmtArg<A7>(v7)(), FmtArg<A8>(v8)(),2850                 FmtArg<A9>(v9)(), FmtArg<A10>(v10)(),FmtArg<A11>(v11)(),2851                 FmtArg<A12>(v12)(), FmtArg<A13>(v13)(),FmtArg<A14>(v14)());2852         }2853     }2854     template<class A1, class A2, class A3, class A4, class A5, class A6,2855         class A7, class A8, class A9, class A10, class A11, class A12,2856         class A13, class A14, class A15>2857     void Format(UINT nId, const A1& v1, const A2& v2, const A3& v3,2858                 const A4& v4, const A5& v5, const A6& v6, const A7& v7,2859                 const A8& v8, const A9& v9, const A10& v10, const A11& v11,2860                 const A12& v12, const A13& v13, const A14& v14, const A15& v15)2861     {2862         MYTYPE strFmt;2863         if ( strFmt.Load(nId) )2864         {2865             Fmt(strFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)(),2866                 FmtArg<A3>(v3)(), FmtArg<A4>(v4)(), FmtArg<A5>(v5)(),2867                 FmtArg<A6>(v6)(), FmtArg<A7>(v7)(), FmtArg<A8>(v8)(),2868                 FmtArg<A9>(v9)(), FmtArg<A10>(v10)(),FmtArg<A11>(v11)(),2869                 FmtArg<A12>(v12)(),FmtArg<A13>(v13)(),FmtArg<A14>(v14)(),2870                 FmtArg<A15>(v15)());2871         }2872     }2873     template<class A1, class A2, class A3, class A4, class A5, class A6,2874         class A7, class A8, class A9, class A10, class A11, class A12,2875         class A13, class A14, class A15, class A16>2876     void Format(UINT nId, const A1& v1, const A2& v2, const A3& v3,2877                 const A4& v4, const A5& v5, const A6& v6, const A7& v7,2878                 const A8& v8, const A9& v9, const A10& v10, const A11& v11,2879                 const A12& v12, const A13& v13, const A14& v14, const A15& v15,2880                 const A16& v16)2881     {2882         MYTYPE strFmt;2883         if ( strFmt.Load(nId) )2884         {2885             Fmt(strFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)(),2886                 FmtArg<A3>(v3)(), FmtArg<A4>(v4)(), FmtArg<A5>(v5)(),2887                 FmtArg<A6>(v6)(), FmtArg<A7>(v7)(), FmtArg<A8>(v8)(),2888                 FmtArg<A9>(v9)(), FmtArg<A10>(v10)(),FmtArg<A11>(v11)(),2889                 FmtArg<A12>(v12)(),FmtArg<A13>(v13)(),FmtArg<A14>(v14)(),2890                 FmtArg<A15>(v15)(), FmtArg<A16>(v16)());2891         }2892     }2893     template<class A1, class A2, class A3, class A4, class A5, class A6,2894         class A7, class A8, class A9, class A10, class A11, class A12,2895         class A13, class A14, class A15, class A16, class A17>2896     void Format(UINT nId, const A1& v1, const A2& v2, const A3& v3,2897                 const A4& v4, const A5& v5, const A6& v6, const A7& v7,2898                 const A8& v8, const A9& v9, const A10& v10, const A11& v11,2899                 const A12& v12, const A13& v13, const A14& v14, const A15& v15,2900                 const A16& v16, const A17& v17)2901     {2902         MYTYPE strFmt;2903         if ( strFmt.Load(nId) )2904         {2905             Fmt(strFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)(),2906                 FmtArg<A3>(v3)(), FmtArg<A4>(v4)(), FmtArg<A5>(v5)(),2907                 FmtArg<A6>(v6)(), FmtArg<A7>(v7)(), FmtArg<A8>(v8)(),2908                 FmtArg<A9>(v9)(), FmtArg<A10>(v10)(),FmtArg<A11>(v11)(),2909                 FmtArg<A12>(v12)(),FmtArg<A13>(v13)(),FmtArg<A14>(v14)(),2910                 FmtArg<A15>(v15)(),FmtArg<A16>(v16)(),FmtArg<A17>(v17)());2911         }2912     }2913     2914 #endif // #ifndef SS_ANSI2915 2916     // ...now the other overload of Format: the one that takes a string literal2917 2918     void Format(const CT* szFmt)2919     {2920         *this = szFmt;2921     }2922     template<class A1>2923     void Format(const CT* szFmt, const A1& v)2924     {2925         Fmt(szFmt, FmtArg<A1>(v)());2926     }2927     template<class A1, class A2>2928     void Format(const CT* szFmt, const A1& v1, const A2& v2)2929     {2930         Fmt(szFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)());2931     }2932     template<class A1, class A2, class A3>2933     void Format(const CT* szFmt, const A1& v1, const A2& v2, const A3& v3)2934     {2935         Fmt(szFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)(),2936             FmtArg<A3>(v3)());2937     }2938     template<class A1, class A2, class A3, class A4>2939     void Format(const CT* szFmt, const A1& v1, const A2& v2, const A3& v3,2940                 const A4& v4)2941     {2942         Fmt(szFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)(),2943             FmtArg<A3>(v3)(), FmtArg<A4>(v4)());2944     }2945     template<class A1, class A2, class A3, class A4, class A5>2946     void Format(const CT* szFmt, const A1& v1, const A2& v2, const A3& v3,2947                 const A4& v4, const A5& v5)2948     {2949         Fmt(szFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)(),2950             FmtArg<A3>(v3)(), FmtArg<A4>(v4)(), FmtArg<A5>(v5)());2951     }2952     template<class A1, class A2, class A3, class A4, class A5, class A6>2953     void Format(const CT* szFmt, const A1& v1, const A2& v2, const A3& v3,2954                 const A4& v4, const A5& v5, const A6& v6)2955     {2956         Fmt(szFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)(),2957             FmtArg<A3>(v3)(), FmtArg<A4>(v4)(), FmtArg<A5>(v5)(),2958             FmtArg<A6>(v6)());2959     }2960     template<class A1, class A2, class A3, class A4, class A5, class A6,2961         class A7>2962     void Format(const CT* szFmt, const A1& v1, const A2& v2, const A3& v3,2963                 const A4& v4, const A5& v5, const A6& v6, const A7& v7)2964     {2965         Fmt(szFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)(),2966             FmtArg<A3>(v3)(), FmtArg<A4>(v4)(), FmtArg<A5>(v5)(),2967             FmtArg<A6>(v6)(), FmtArg<A7>(v7)());2968     }2969     template<class A1, class A2, class A3, class A4, class A5, class A6,2970         class A7, class A8>2971     void Format(const CT* szFmt, const A1& v1, const A2& v2, const A3& v3,2972                 const A4& v4, const A5& v5, const A6& v6, const A7& v7,2973                 const A8& v8)2974     {2975         Fmt(szFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)(),2976             FmtArg<A3>(v3)(), FmtArg<A4>(v4)(), FmtArg<A5>(v5)(),2977             FmtArg<A6>(v6)(), FmtArg<A7>(v7)(), FmtArg<A8>(v8)());2978     }2979     template<class A1, class A2, class A3, class A4, class A5, class A6,2980         class A7, class A8, class A9>2981     void Format(const CT* szFmt, const A1& v1, const A2& v2, const A3& v3,2982                 const A4& v4, const A5& v5, const A6& v6, const A7& v7,2983                 const A8& v8, const A9& v9)2984     {2985         Fmt(szFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)(),2986             FmtArg<A3>(v3)(), FmtArg<A4>(v4)(), FmtArg<A5>(v5)(),2987             FmtArg<A6>(v6)(), FmtArg<A7>(v7)(), FmtArg<A8>(v8)(),2988             FmtArg<A9>(v9)());2989     }2990     template<class A1, class A2, class A3, class A4, class A5, class A6,2991         class A7, class A8, class A9, class A10>2992     void Format(const CT* szFmt, const A1& v1, const A2& v2, const A3& v3,2993                 const A4& v4, const A5& v5, const A6& v6, const A7& v7,2994                 const A8& v8, const A9& v9, const A10& v10)2995     {2996         Fmt(szFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)(),2997             FmtArg<A3>(v3)(), FmtArg<A4>(v4)(), FmtArg<A5>(v5)(),2998             FmtArg<A6>(v6)(), FmtArg<A7>(v7)(), FmtArg<A8>(v8)(),2999             FmtArg<A9>(v9)(), FmtArg<A10>(v10)());3000     }3001     template<class A1, class A2, class A3, class A4, class A5, class A6,3002         class A7, class A8, class A9, class A10, class A11>3003     void Format(const CT* szFmt, const A1& v1, const A2& v2, const A3& v3,3004                 const A4& v4, const A5& v5, const A6& v6, const A7& v7,3005                 const A8& v8, const A9& v9, const A10& v10, const A11& v11)3006     {3007         Fmt(szFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)(),3008             FmtArg<A3>(v3)(), FmtArg<A4>(v4)(), FmtArg<A5>(v5)(),3009             FmtArg<A6>(v6)(), FmtArg<A7>(v7)(), FmtArg<A8>(v8)(),3010             FmtArg<A9>(v9)(),FmtArg<A10>(v10)(),FmtArg<A11>(v11)());3011     }3012     template<class A1, class A2, class A3, class A4, class A5, class A6,3013         class A7, class A8, class A9, class A10, class A11, class A12>3014     void Format(const CT* szFmt, const A1& v1, const A2& v2, const A3& v3,3015                 const A4& v4, const A5& v5, const A6& v6, const A7& v7,3016                 const A8& v8, const A9& v9, const A10& v10, const A11& v11,3017                 const A12& v12)3018     {3019         Fmt(szFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)(),3020             FmtArg<A3>(v3)(), FmtArg<A4>(v4)(), FmtArg<A5>(v5)(),3021             FmtArg<A6>(v6)(), FmtArg<A7>(v7)(), FmtArg<A8>(v8)(),3022             FmtArg<A9>(v9)(), FmtArg<A10>(v10)(),FmtArg<A11>(v11)(),3023             FmtArg<A12>(v12)());3024     }3025     template<class A1, class A2, class A3, class A4, class A5, class A6,3026         class A7, class A8, class A9, class A10, class A11, class A12,3027         class A13>3028     void Format(const CT* szFmt, const A1& v1, const A2& v2, const A3& v3,3029                 const A4& v4, const A5& v5, const A6& v6, const A7& v7,3030                 const A8& v8, const A9& v9, const A10& v10, const A11& v11,3031                 const A12& v12, const A13& v13)3032     {3033         Fmt(szFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)(),3034             FmtArg<A3>(v3)(), FmtArg<A4>(v4)(), FmtArg<A5>(v5)(),3035             FmtArg<A6>(v6)(), FmtArg<A7>(v7)(), FmtArg<A8>(v8)(),3036             FmtArg<A9>(v9)(), FmtArg<A10>(v10)(),FmtArg<A11>(v11)(),3037             FmtArg<A12>(v12)(), FmtArg<A13>(v13)());3038     }3039     template<class A1, class A2, class A3, class A4, class A5, class A6,3040         class A7, class A8, class A9, class A10, class A11, class A12,3041         class A13, class A14>3042     void Format(const CT* szFmt, const A1& v1, const A2& v2, const A3& v3,3043                 const A4& v4, const A5& v5, const A6& v6, const A7& v7,3044                 const A8& v8, const A9& v9, const A10& v10, const A11& v11,3045                 const A12& v12, const A13& v13, const A14& v14)3046     {3047         Fmt(szFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)(),3048             FmtArg<A3>(v3)(), FmtArg<A4>(v4)(), FmtArg<A5>(v5)(),3049             FmtArg<A6>(v6)(), FmtArg<A7>(v7)(), FmtArg<A8>(v8)(),3050             FmtArg<A9>(v9)(), FmtArg<A10>(v10)(),FmtArg<A11>(v11)(),3051             FmtArg<A12>(v12)(), FmtArg<A13>(v13)(),FmtArg<A14>(v14)());3052     }3053     template<class A1, class A2, class A3, class A4, class A5, class A6,3054         class A7, class A8, class A9, class A10, class A11, class A12,3055         class A13, class A14, class A15>3056     void Format(const CT* szFmt, const A1& v1, const A2& v2, const A3& v3,3057                 const A4& v4, const A5& v5, const A6& v6, const A7& v7,3058                 const A8& v8, const A9& v9, const A10& v10, const A11& v11,3059                 const A12& v12, const A13& v13, const A14& v14, const A15& v15)3060     {3061         Fmt(szFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)(),3062             FmtArg<A3>(v3)(), FmtArg<A4>(v4)(), FmtArg<A5>(v5)(),3063             FmtArg<A6>(v6)(), FmtArg<A7>(v7)(), FmtArg<A8>(v8)(),3064             FmtArg<A9>(v9)(), FmtArg<A10>(v10)(),FmtArg<A11>(v11)(),3065             FmtArg<A12>(v12)(),FmtArg<A13>(v13)(),FmtArg<A14>(v14)(),3066             FmtArg<A15>(v15)());3067     }3068     template<class A1, class A2, class A3, class A4, class A5, class A6,3069         class A7, class A8, class A9, class A10, class A11, class A12,3070         class A13, class A14, class A15, class A16>3071     void Format(const CT* szFmt, const A1& v1, const A2& v2, const A3& v3,3072                 const A4& v4, const A5& v5, const A6& v6, const A7& v7,3073                 const A8& v8, const A9& v9, const A10& v10, const A11& v11,3074                 const A12& v12, const A13& v13, const A14& v14, const A15& v15,3075                 const A16& v16)3076     {3077         Fmt(szFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)(),3078             FmtArg<A3>(v3)(), FmtArg<A4>(v4)(), FmtArg<A5>(v5)(),3079             FmtArg<A6>(v6)(), FmtArg<A7>(v7)(), FmtArg<A8>(v8)(),3080             FmtArg<A9>(v9)(), FmtArg<A10>(v10)(),FmtArg<A11>(v11)(),3081             FmtArg<A12>(v12)(),FmtArg<A13>(v13)(),FmtArg<A14>(v14)(),3082             FmtArg<A15>(v15)(), FmtArg<A16>(v16)());3083     }3084     template<class A1, class A2, class A3, class A4, class A5, class A6,3085         class A7, class A8, class A9, class A10, class A11, class A12,3086         class A13, class A14, class A15, class A16, class A17>3087     void Format(const CT* szFmt, const A1& v1, const A2& v2, const A3& v3,3088                 const A4& v4, const A5& v5, const A6& v6, const A7& v7,3089                 const A8& v8, const A9& v9, const A10& v10, const A11& v11,3090                 const A12& v12, const A13& v13, const A14& v14, const A15& v15,3091                 const A16& v16, const A17& v17)3092     {3093         Fmt(szFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)(),3094             FmtArg<A3>(v3)(), FmtArg<A4>(v4)(), FmtArg<A5>(v5)(),3095             FmtArg<A6>(v6)(), FmtArg<A7>(v7)(), FmtArg<A8>(v8)(),3096             FmtArg<A9>(v9)(), FmtArg<A10>(v10)(),FmtArg<A11>(v11)(),3097             FmtArg<A12>(v12)(),FmtArg<A13>(v13)(),FmtArg<A14>(v14)(),3098             FmtArg<A15>(v15)(),FmtArg<A16>(v16)(),FmtArg<A17>(v17)());3099     }3100 3101 #else  // #ifdef SS_SAFE_FORMAT3102 3103 3104 #ifndef SS_ANSI3105 3106     void Format(UINT nId, ...)3107     {3108         va_list argList;3109         va_start(argList, nId);3110 3111         MYTYPE strFmt;3112         if ( strFmt.Load(nId) )3113             FormatV(strFmt, argList);3114 3115         va_end(argList);3116     }3117     3118 #endif  // #ifdef SS_ANSI3119 3120     void Format(const CT* szFmt, ...)3121     {3122         va_list argList;3123         va_start(argList, szFmt);3124         FormatV(szFmt, argList);3125         va_end(argList);3126     }3127 3128 #endif // #ifdef SS_SAFE_FORMAT3129 3130     void AppendFormat(const CT* szFmt, ...)3131     {3132         va_list argList;3133         va_start(argList, szFmt);3134         AppendFormatV(szFmt, argList);3135         va_end(argList);3136     }3137 3138     #define MAX_FMT_TRIES        5     // #of times we try 3139     #define FMT_BLOCK_SIZE        2048 // # of bytes to increment per try3140     #define BUFSIZE_1ST    2563141     #define BUFSIZE_2ND 5123142     #define STD_BUF_SIZE        10243143 3144     // an efficient way to add formatted characters to the string.  You may only3145     // add up to STD_BUF_SIZE characters at a time, though3146     void AppendFormatV(const CT* szFmt, va_list argList)3147     {3148         CT szBuf[STD_BUF_SIZE];3149         int nLen = ssvsprintf(szBuf, STD_BUF_SIZE-1, szFmt, argList);3150 3151         if ( 0 < nLen )3152             this->append(szBuf, nLen);3153     }3154 3155     // -------------------------------------------------------------------------3156     // FUNCTION:  FormatV3157     //        void FormatV(PCSTR szFormat, va_list, argList);3158     //           3159     // DESCRIPTION:3160     //        This function formats the string with sprintf style format-specs. 3161     //        It makes a general guess at required buffer size and then tries3162     //        successively larger buffers until it finds one big enough or a3163     //        threshold (MAX_FMT_TRIES) is exceeded.3164     //3165     // PARAMETERS: 3166     //        szFormat - a PCSTR holding the format of the output3167     //        argList - a Microsoft specific va_list for variable argument lists3168     //3169     // RETURN VALUE: 3170     // -------------------------------------------------------------------------3171 3172     void FormatV(const CT* szFormat, va_list argList)3173     {3174     #ifdef SS_ANSI3175         MYTYPE str;3176 3177         int n;3178         int nLen = GetLength();3179         if(nLen <= 0)3180             nLen = 100;        /* Guess we need no more than 100 bytes. */3181 3182         while(1) {3183             n = ssvsprintf(str.GetBuffer(nLen), nLen - 1, szFormat, argList);3184 3185             /* If that worked, return the string. */3186             if(n > -1 && n < nLen)3187             {3188                 str.ReleaseBuffer();3189                 break;3190             }3191 3192             /* Else try again with more space. */3193             if (n > -1)    /* glibc 2.1 */3194                 nLen = n+1; /* precisely what is needed */3195             else           /* glibc 2.0 */3196                 nLen *= 2;  /* twice the old size */3197         }3198         *this = str;3199 3200     #else3201 3202         CT* pBuf            = NULL;3203         int nChars            = 1;3204         int nUsed            = 0;3205         size_type nActual    = 0;3206         int nTry            = 0;3207 3208         do    3209         {3210             // Grow more than linearly (e.g. 512, 1536, 3072, etc)3211 3212             nChars            += ((nTry+1) * FMT_BLOCK_SIZE);3213             pBuf            = reinterpret_cast<CT*>(_alloca(sizeof(CT)*nChars));3214             nUsed            = ssvsprintf(pBuf, nChars-1, szFormat, argList);3215 3216             // Ensure proper NULL termination.3217 3218             nActual            = nUsed == -1 ? nChars-1 : SSMIN(nUsed, nChars-1);3219             pBuf[nActual]= \0;3220 3221 3222         } while ( nUsed < 0 && nTry++ < MAX_FMT_TRIES );3223 3224         // assign whatever we managed to format3225 3226         this->assign(pBuf, nActual);3227 3228     #endif3229     }3230 3231     // -------------------------------------------------------------------------3232     // CString Facade Functions:3233     //3234     // The following methods are intended to allow you to use this class as a3235     // near drop-in replacement for CString.3236     // -------------------------------------------------------------------------3237     #ifdef SS_WIN323238         BSTR AllocSysString() const3239         {3240             ostring os;3241             ssasn(os, *this);3242             return ::SysAllocString(os.c_str());3243         }3244     #endif3245 3246 #ifndef SS_NO_LOCALE3247     int Collate(PCMYSTR szThat) const3248     {3249         return sscoll(this->c_str(), this->length(), szThat, sslen(szThat));3250     }3251 3252     int CollateNoCase(PCMYSTR szThat) const3253     {3254         return ssicoll(this->c_str(), this->length(), szThat, sslen(szThat));3255     }3256 #endif3257     int Compare(PCMYSTR szThat) const3258     {3259         return this->compare(szThat);    3260     }3261 3262     int CompareNoCase(PCMYSTR szThat)    const3263     {3264         return ssicmp(this->c_str(), szThat);3265     }3266 3267     int Delete(int nIdx, int nCount=1)3268     {3269         if ( nIdx < 0 )3270             nIdx = 0;3271 3272         if ( nIdx < this->GetLength() )3273             this->erase(static_cast<MYSIZE>(nIdx), static_cast<MYSIZE>(nCount));3274 3275         return GetLength();3276     }3277 3278     void Empty()3279     {3280         this->erase();3281     }3282 3283     int Find(CT ch) const3284     {3285         MYSIZE nIdx    = this->find_first_of(ch);3286         return static_cast<int>(MYBASE::npos == nIdx  ? -1 : nIdx);3287     }3288 3289     int Find(PCMYSTR szSub) const3290     {3291         MYSIZE nIdx    = this->find(szSub);3292         return static_cast<int>(MYBASE::npos == nIdx ? -1 : nIdx);3293     }3294 3295     int Find(CT ch, int nStart) const3296     {3297         // CString::Find docs say add 1 to nStart when it‘s not zero3298         // CString::Find code doesn‘t do that however.  We‘ll stick3299         // with what the code does3300 3301         MYSIZE nIdx    = this->find_first_of(ch, static_cast<MYSIZE>(nStart));3302         return static_cast<int>(MYBASE::npos == nIdx ? -1 : nIdx);3303     }3304 3305     int Find(PCMYSTR szSub, int nStart) const3306     {3307         // CString::Find docs say add 1 to nStart when it‘s not zero3308         // CString::Find code doesn‘t do that however.  We‘ll stick3309         // with what the code does3310 3311         MYSIZE nIdx    = this->find(szSub, static_cast<MYSIZE>(nStart));3312         return static_cast<int>(MYBASE::npos == nIdx ? -1 : nIdx);3313     }3314 3315     int FindOneOf(PCMYSTR szCharSet) const3316     {3317         MYSIZE nIdx = this->find_first_of(szCharSet);3318         return static_cast<int>(MYBASE::npos == nIdx ? -1 : nIdx);3319     }3320 3321 #ifndef SS_ANSI3322     void FormatMessage(PCMYSTR szFormat, ...) throw(std::exception)3323     {3324         va_list argList;3325         va_start(argList, szFormat);3326         PMYSTR szTemp;3327         if ( ssfmtmsg(FORMAT_MESSAGE_FROM_STRING|FORMAT_MESSAGE_ALLOCATE_BUFFER,3328                        szFormat, 0, 0,3329                        reinterpret_cast<PMYSTR>(&szTemp), 0, &argList) == 0 ||3330              szTemp == 0 )3331         {3332             throw std::runtime_error("out of memory");3333         }3334         *this = szTemp;3335         LocalFree(szTemp);3336         va_end(argList);3337     }3338 3339     void FormatMessage(UINT nFormatId, ...) throw(std::exception)3340     {3341         MYTYPE sFormat;3342         VERIFY(sFormat.LoadString(nFormatId));3343         va_list argList;3344         va_start(argList, nFormatId);3345         PMYSTR szTemp;3346         if ( ssfmtmsg(FORMAT_MESSAGE_FROM_STRING|FORMAT_MESSAGE_ALLOCATE_BUFFER,3347                        sFormat, 0, 0,3348                        reinterpret_cast<PMYSTR>(&szTemp), 0, &argList) == 0 ||3349             szTemp == 0)3350         {3351             throw std::runtime_error("out of memory");3352         }3353         *this = szTemp;3354         LocalFree(szTemp);3355         va_end(argList);3356     }3357 #endif3358 3359     // GetAllocLength -- an MSVC7 function but it costs us nothing to add it.3360 3361     int GetAllocLength()3362     {3363         return static_cast<int>(this->capacity());3364     }3365 3366     // -------------------------------------------------------------------------3367     // GetXXXX -- Direct access to character buffer3368     // -------------------------------------------------------------------------3369     CT GetAt(int nIdx) const3370     {3371         return this->at(static_cast<MYSIZE>(nIdx));3372     }3373 3374     CT* GetBuffer(int nMinLen=-1)3375     {3376         return GetBuf(nMinLen);3377     }3378 3379     CT* GetBufferSetLength(int nLen)3380     {3381         return BufferSet(nLen);3382     }3383 3384     // GetLength() -- MFC docs say this is the # of BYTES but3385     // in truth it is the number of CHARACTERs (chars or wchar_ts)3386 3387     int GetLength() const3388     {3389         return static_cast<int>(this->length());3390     }3391     3392     // GetString function added in Visual Studio 2008, if I recall correctly.3393 3394     PCMYSTR GetString() const3395     {3396         return this->c_str();3397     }3398 3399     int Insert(int nIdx, CT ch)3400     {3401         if ( static_cast<MYSIZE>(nIdx) > this->size()-1 )3402             this->append(1, ch);3403         else3404             this->insert(static_cast<MYSIZE>(nIdx), 1, ch);3405 3406         return GetLength();3407     }3408     int Insert(int nIdx, PCMYSTR sz)3409     {3410         if ( static_cast<MYSIZE>(nIdx) >= this->size() )3411             this->append(sz, static_cast<MYSIZE>(sslen(sz)));3412         else3413             this->insert(static_cast<MYSIZE>(nIdx), sz);3414 3415         return GetLength();3416     }3417 3418     bool IsEmpty() const3419     {3420         return this->empty();3421     }3422 3423     MYTYPE Left(int nCount) const3424     {3425         // Range check the count.3426 3427         nCount = SSMAX(0, SSMIN(nCount, static_cast<int>(this->size())));3428         return this->substr(0, static_cast<MYSIZE>(nCount)); 3429     }3430 3431 #ifndef SS_ANSI3432     bool LoadString(UINT nId)3433     {3434         return this->Load(nId);3435     }3436 #endif3437 3438     void MakeLower()3439     {3440         ToLower();3441     }3442 3443     void MakeReverse()3444     {3445         std::reverse(this->begin(), this->end());3446     }3447 3448     void MakeUpper()3449     { 3450         ToUpper();3451     }3452 3453     MYTYPE Mid(int nFirst) const3454     {3455         return Mid(nFirst, this->GetLength()-nFirst);3456     }3457 3458     MYTYPE Mid(int nFirst, int nCount) const3459     {3460         // CString does range checking here.  Since we‘re trying to emulate it,3461         // we must check too.3462 3463         if ( nFirst < 0 )3464             nFirst = 0;3465         if ( nCount < 0 )3466             nCount = 0;3467 3468         int nSize = static_cast<int>(this->size());3469 3470         if ( nFirst + nCount > nSize )3471             nCount = nSize - nFirst;3472 3473         if ( nFirst > nSize )3474             return MYTYPE();3475 3476         ASSERT(nFirst >= 0);3477         ASSERT(nFirst + nCount <= nSize);3478 3479         return this->substr(static_cast<MYSIZE>(nFirst),3480                             static_cast<MYSIZE>(nCount));3481     }3482 3483     void ReleaseBuffer(int nNewLen=-1)3484     {3485         RelBuf(nNewLen);3486     }3487 3488     int Remove(CT ch)3489     {3490         MYSIZE nIdx        = 0;3491         int nRemoved    = 0;3492         while ( (nIdx=this->find_first_of(ch)) != MYBASE::npos )3493         {3494             this->erase(nIdx, 1);3495             nRemoved++;3496         }3497         return nRemoved;3498     }3499 3500     int Replace(CT chOld, CT chNew)3501     {3502         int nReplaced    = 0;3503 3504         for ( MYITER iter=this->begin(); iter != this->end(); iter++ )3505         {3506             if ( *iter == chOld )3507             {3508                 *iter = chNew;3509                 nReplaced++;3510             }3511         }3512 3513         return nReplaced;3514     }3515 3516     int Replace(PCMYSTR szOld, PCMYSTR szNew)3517     {3518         int nReplaced        = 0;3519         MYSIZE nIdx            = 0;3520         MYSIZE nOldLen        = sslen(szOld);3521 3522         if ( 0 != nOldLen )3523         {3524             // If the replacement string is longer than the one it replaces, this3525             // string is going to have to grow in size,  Figure out how much3526             // and grow it all the way now, rather than incrementally3527 3528             MYSIZE nNewLen        = sslen(szNew);3529             if ( nNewLen > nOldLen )3530             {3531                 int nFound            = 0;3532                 while ( nIdx < this->length() &&3533                     (nIdx=this->find(szOld, nIdx)) != MYBASE::npos )3534                 {3535                     nFound++;3536                     nIdx += nOldLen;3537                 }3538                 this->reserve(this->size() + nFound * (nNewLen - nOldLen));3539             }3540 3541 3542             static const CT ch    = CT(0);3543             PCMYSTR szRealNew    = szNew == 0 ? &ch : szNew;3544             nIdx                = 0;3545 3546             while ( nIdx < this->length() && 3547                 (nIdx=this->find(szOld, nIdx)) != MYBASE::npos )3548             {3549                 this->replace(this->begin()+nIdx, this->begin()+nIdx+nOldLen,3550                     szRealNew);3551 3552                 nReplaced++;3553                 nIdx += nNewLen;3554             }3555         }3556 3557         return nReplaced;3558     }3559 3560     int ReverseFind(CT ch) const3561     {3562         MYSIZE nIdx    = this->find_last_of(ch);3563         return static_cast<int>(MYBASE::npos == nIdx ? -1 : nIdx);3564     }3565 3566     // ReverseFind overload that‘s not in CString but might be useful3567     int ReverseFind(PCMYSTR szFind, MYSIZE pos=MYBASE::npos) const3568     {3569         MYSIZE nIdx    = this->rfind(0 == szFind ? MYTYPE() : szFind, pos);3570         return static_cast<int>(MYBASE::npos == nIdx ? -1 : nIdx);3571     }3572 3573     MYTYPE Right(int nCount) const3574     {3575         // Range check the count.3576 3577         nCount = SSMAX(0, SSMIN(nCount, static_cast<int>(this->size())));3578         return this->substr(this->size()-static_cast<MYSIZE>(nCount));3579     }3580 3581     void SetAt(int nIndex, CT ch)3582     {3583         ASSERT(this->size() > static_cast<MYSIZE>(nIndex));3584         this->at(static_cast<MYSIZE>(nIndex))        = ch;3585     }3586 3587 #ifndef SS_ANSI3588     BSTR SetSysString(BSTR* pbstr) const3589     {3590         ostring os;3591         ssasn(os, *this);3592         if ( !::SysReAllocStringLen(pbstr, os.c_str(), os.length()) )3593             throw std::runtime_error("out of memory");3594 3595         ASSERT(*pbstr != 0);3596         return *pbstr;3597     }3598 #endif3599 3600     MYTYPE SpanExcluding(PCMYSTR szCharSet) const3601     {3602         MYSIZE pos = this->find_first_of(szCharSet);3603         return pos == MYBASE::npos ? *this : Left(pos);3604     }3605 3606     MYTYPE SpanIncluding(PCMYSTR szCharSet) const3607     {3608         MYSIZE pos = this->find_first_not_of(szCharSet);3609         return pos == MYBASE::npos ? *this : Left(pos);3610     }3611 3612 #if defined SS_WIN32 && !defined(UNICODE) && !defined(SS_ANSI)3613 3614     // CString‘s OemToAnsi and AnsiToOem functions are available only in3615     // Unicode builds.  However since we‘re a template we also need a3616     // runtime check of CT and a reinterpret_cast to account for the fact3617     // that CStdStringW gets instantiated even in non-Unicode builds.3618 3619     void AnsiToOem()3620     {3621         if ( sizeof(CT) == sizeof(char) && !empty() )3622         {3623             ::CharToOem(reinterpret_cast<PCSTR>(this->c_str()),3624                         reinterpret_cast<PSTR>(GetBuf()));3625         }3626         else3627         {3628             ASSERT(false);3629         }3630     }3631 3632     void OemToAnsi()3633     {3634         if ( sizeof(CT) == sizeof(char) && !empty() )3635         {3636             ::OemToChar(reinterpret_cast<PCSTR>(this->c_str()),3637                         reinterpret_cast<PSTR>(GetBuf()));3638         }3639         else3640         {3641             ASSERT(false);3642         }3643     }3644 3645 #endif3646     3647 3648     // -------------------------------------------------------------------------3649     // Trim and its variants3650     // -------------------------------------------------------------------------3651     MYTYPE& Trim()3652     {3653         return TrimLeft().TrimRight();3654     }3655 3656     MYTYPE& TrimLeft()3657     {3658         this->erase(this->begin(),3659             std::find_if(this->begin(), this->end(), NotSpace<CT>()));3660 3661         return *this;3662     }3663 3664     MYTYPE&  TrimLeft(CT tTrim)3665     {3666         this->erase(0, this->find_first_not_of(tTrim));3667         return *this;3668     }3669 3670     MYTYPE&  TrimLeft(PCMYSTR szTrimChars)3671     {3672         this->erase(0, this->find_first_not_of(szTrimChars));3673         return *this;3674     }3675 3676     MYTYPE& TrimRight()3677     {3678         // NOTE:  When comparing reverse_iterators here (MYRITER), I avoid using3679         // operator!=.  This is because namespace rel_ops also has a template3680         // operator!= which conflicts with the global operator!= already defined3681         // for reverse_iterator in the header <utility>.3682         // Thanks to John James for alerting me to this.3683 3684         MYRITER it = std::find_if(this->rbegin(), this->rend(), NotSpace<CT>());3685         if ( !(this->rend() == it) )3686             this->erase(this->rend() - it);3687 3688         this->erase(!(it == this->rend()) ? this->find_last_of(*it) + 1 : 0);3689         return *this;3690     }3691 3692     MYTYPE&  TrimRight(CT tTrim)3693     {3694         MYSIZE nIdx    = this->find_last_not_of(tTrim);3695         this->erase(MYBASE::npos == nIdx ? 0 : ++nIdx);3696         return *this;3697     }3698 3699     MYTYPE&  TrimRight(PCMYSTR szTrimChars)3700     {3701         MYSIZE nIdx    = this->find_last_not_of(szTrimChars);3702         this->erase(MYBASE::npos == nIdx ? 0 : ++nIdx);3703         return *this;3704     }3705 3706     void            FreeExtra()3707     {3708         MYTYPE mt;3709         this->swap(mt);3710         if ( !mt.empty() )3711             this->assign(mt.c_str(), mt.size());3712     }3713 3714     // I have intentionally not implemented the following CString3715     // functions.   You cannot make them work without taking advantage3716     // of implementation specific behavior.  However if you absolutely3717     // MUST have them, uncomment out these lines for "sort-of-like"3718     // their behavior.  You‘re on your own.3719 3720 //    CT*                LockBuffer()    { return GetBuf(); }// won‘t really lock3721 //    void            UnlockBuffer(); { }    // why have UnlockBuffer w/o LockBuffer?3722 3723     // Array-indexing operators.  Required because we defined an implicit cast3724     // to operator const CT* (Thanks to Julian Selman for pointing this out)3725 3726     CT& operator[](int nIdx)3727     {3728         return static_cast<MYBASE*>(this)->operator[](static_cast<MYSIZE>(nIdx));3729     }3730 3731     const CT& operator[](int nIdx) const3732     {3733         return static_cast<const MYBASE*>(this)->operator[](static_cast<MYSIZE>(nIdx));3734     }3735 3736     CT& operator[](unsigned int nIdx)3737     {3738         return static_cast<MYBASE*>(this)->operator[](static_cast<MYSIZE>(nIdx));3739     }3740 3741     const CT& operator[](unsigned int nIdx) const3742     {3743         return static_cast<const MYBASE*>(this)->operator[](static_cast<MYSIZE>(nIdx));3744     }3745 3746 #ifndef SS_NO_IMPLICIT_CAST3747     operator const CT*() const3748     {3749         return this->c_str();3750     }3751 #endif3752 3753     // IStream related functions.  Useful in IPersistStream implementations3754 3755 #ifdef SS_INC_COMDEF3756 3757     // struct SSSHDR - useful for non Std C++ persistence schemes.3758     typedef struct SSSHDR3759     {3760         BYTE    byCtrl;3761         ULONG    nChars;3762     } SSSHDR;    // as in "Standard String Stream Header"3763 3764     #define SSSO_UNICODE    0x01    // the string is a wide string3765     #define SSSO_COMPRESS    0x02    // the string is compressed3766 3767     // -------------------------------------------------------------------------3768     // FUNCTION: StreamSize3769     // REMARKS:3770     //        Returns how many bytes it will take to StreamSave() this CStdString3771     //        object to an IStream.3772     // -------------------------------------------------------------------------3773     ULONG StreamSize() const3774     {3775         // Control header plus string3776         ASSERT(this->size()*sizeof(CT) < 0xffffffffUL - sizeof(SSSHDR));3777         return (this->size() * sizeof(CT)) + sizeof(SSSHDR);3778     }3779 3780     // -------------------------------------------------------------------------3781     // FUNCTION: StreamSave3782     // REMARKS:3783     //        Saves this CStdString object to a COM IStream.3784     // -------------------------------------------------------------------------3785     HRESULT StreamSave(IStream* pStream) const3786     {3787         ASSERT(this->size()*sizeof(CT) < 0xffffffffUL - sizeof(SSSHDR));3788         HRESULT hr        = E_FAIL;3789         ASSERT(pStream != 0);3790         SSSHDR hdr;3791         hdr.byCtrl        = sizeof(CT) == 2 ? SSSO_UNICODE : 0;3792         hdr.nChars        = this->size();3793 3794 3795         if ( FAILED(hr=pStream->Write(&hdr, sizeof(SSSHDR), 0)) )3796         {3797             TRACE(_T("StreamSave: Cannot write control header, ERR=0x%X\n"),hr);3798         }3799         else if ( empty() )3800         {3801             ;        // nothing to write3802         }3803         else if ( FAILED(hr=pStream->Write(this->c_str(),3804             this->size()*sizeof(CT), 0)) )3805         {3806             TRACE(_T("StreamSave: Cannot write string to stream 0x%X\n"), hr);3807         }3808 3809         return hr;3810     }3811 3812 3813     // -------------------------------------------------------------------------3814     // FUNCTION: StreamLoad3815     // REMARKS:3816     //        This method loads the object from an IStream.3817     // -------------------------------------------------------------------------3818     HRESULT StreamLoad(IStream* pStream)3819     {3820         ASSERT(pStream != 0);3821         SSSHDR hdr;3822         HRESULT hr            = E_FAIL;3823 3824         if ( FAILED(hr=pStream->Read(&hdr, sizeof(SSSHDR), 0)) )3825         {3826             TRACE(_T("StreamLoad: Cant read control header, ERR=0x%X\n"), hr);3827         }3828         else if ( hdr.nChars > 0 )3829         {3830             ULONG nRead        = 0;3831             PMYSTR pMyBuf    = BufferSet(hdr.nChars);3832 3833             // If our character size matches the character size of the string3834             // we‘re trying to read, then we can read it directly into our3835             // buffer. Otherwise, we have to read into an intermediate buffer3836             // and convert.3837             3838             if ( (hdr.byCtrl & SSSO_UNICODE) != 0 )3839             {3840                 ULONG nBytes    = hdr.nChars * sizeof(wchar_t);3841                 if ( sizeof(CT) == sizeof(wchar_t) )3842                 {3843                     if ( FAILED(hr=pStream->Read(pMyBuf, nBytes, &nRead)) )3844                         TRACE(_T("StreamLoad: Cannot read string: 0x%X\n"), hr);3845                 }3846                 else3847                 {    3848                     PWSTR pBufW = reinterpret_cast<PWSTR>(_alloca((nBytes)+1));3849                     if ( FAILED(hr=pStream->Read(pBufW, nBytes, &nRead)) )3850                         TRACE(_T("StreamLoad: Cannot read string: 0x%X\n"), hr);3851                     else3852                         sscpy(pMyBuf, pBufW, hdr.nChars);3853                 }3854             }3855             else3856             {3857                 ULONG nBytes    = hdr.nChars * sizeof(char);3858                 if ( sizeof(CT) == sizeof(char) )3859                 {3860                     if ( FAILED(hr=pStream->Read(pMyBuf, nBytes, &nRead)) )3861                         TRACE(_T("StreamLoad: Cannot read string: 0x%X\n"), hr);3862                 }3863                 else3864                 {3865                     PSTR pBufA = reinterpret_cast<PSTR>(_alloca(nBytes));3866                     if ( FAILED(hr=pStream->Read(pBufA, hdr.nChars, &nRead)) )3867                         TRACE(_T("StreamLoad: Cannot read string: 0x%X\n"), hr);3868                     else3869                         sscpy(pMyBuf, pBufA, hdr.nChars);3870                 }3871             }3872         }3873         else3874         {3875             this->erase();3876         }3877         return hr;3878     }3879 #endif // #ifdef SS_INC_COMDEF3880 3881 #ifndef SS_ANSI3882 3883     // SetResourceHandle/GetResourceHandle.  In MFC builds, these map directly3884     // to AfxSetResourceHandle and AfxGetResourceHandle.  In non-MFC builds they3885     // point to a single static HINST so that those who call the member3886     // functions that take resource IDs can provide an alternate HINST of a DLL3887     // to search.  This is not exactly the list of HMODULES that MFC provides3888     // but it‘s better than nothing.3889 3890     #ifdef _MFC_VER3891         static void SetResourceHandle(HMODULE hNew)3892         {3893             AfxSetResourceHandle(hNew);3894         }3895         static HMODULE GetResourceHandle()3896         {3897             return AfxGetResourceHandle();3898         }3899     #else3900         static void SetResourceHandle(HMODULE hNew)3901         {3902             SSResourceHandle() = hNew;3903         }3904         static HMODULE GetResourceHandle()3905         {3906             return SSResourceHandle();3907         }3908     #endif3909 3910 #endif3911 };3912 3913 // -----------------------------------------------------------------------------3914 // MSVC USERS: HOW TO EXPORT CSTDSTRING FROM A DLL3915 //3916 // If you are using MS Visual C++ and you want to export CStdStringA and3917 // CStdStringW from a DLL, then all you need to3918 //3919 //        1.    make sure that all components link to the same DLL version3920 //            of the CRT (not the static one).3921 //        2.    Uncomment the 3 lines of code below3922 //        3.    #define 2 macros per the instructions in MS KnowledgeBase3923 //            article Q168958.  The macros are:3924 //3925 //        MACRO        DEFINTION WHEN EXPORTING        DEFINITION WHEN IMPORTING3926 //        -----        ------------------------        -------------------------3927 //        SSDLLEXP    (nothing, just #define it)        extern3928 //        SSDLLSPEC    __declspec(dllexport)            __declspec(dllimport)3929 //3930 //        Note that these macros must be available to ALL clients who want to 3931 //        link to the DLL and use the class.  If they 3932 //3933 // A word of advice: Don‘t bother.3934 //3935 // Really, it is not necessary to export CStdString functions from a DLL.  I3936 // never do.  In my projects, I do generally link to the DLL version of the3937 // Standard C++ Library, but I do NOT attempt to export CStdString functions.3938 // I simply include the header where it is needed and allow for the code3939 // redundancy.3940 //3941 // That redundancy is a lot less than you think.  This class does most of its3942 // work via the Standard C++ Library, particularly the base_class basic_string<>3943 // member functions.  Most of the functions here are small enough to be inlined3944 // anyway.  Besides, you‘ll find that in actual practice you use less than 1/23945 // of the code here, even in big projects and different modules will use as3946 // little as 10% of it.  That means a lot less functions actually get linked3947 // your binaries.  If you export this code from a DLL, it ALL gets linked in.3948 //3949 // I‘ve compared the size of the binaries from exporting vs NOT exporting.  Take3950 // my word for it -- exporting this code is not worth the hassle.3951 //3952 // -----------------------------------------------------------------------------3953 //#pragma warning(disable:4231) // non-standard extension ("extern template")3954 //    SSDLLEXP template class SSDLLSPEC CStdStr<char>;3955 //    SSDLLEXP template class SSDLLSPEC CStdStr<wchar_t>;3956 3957 3958 // =============================================================================3959 //                        END OF CStdStr INLINE FUNCTION DEFINITIONS3960 // =============================================================================3961 3962 //    Now typedef our class names based upon this humongous template3963 3964 typedef CStdStr<char>        CStdStringA;    // a better std::string3965 typedef CStdStr<wchar_t>    CStdStringW;    // a better std::wstring3966 typedef CStdStr<OLECHAR>    CStdStringO;    // almost always CStdStringW3967 3968 // -----------------------------------------------------------------------------3969 // CStdStr addition functions defined as inline3970 // -----------------------------------------------------------------------------3971 3972 3973 inline CStdStringA operator+(const CStdStringA& s1, const CStdStringA& s2)3974 {3975     CStdStringA sRet(SSREF(s1));3976     sRet.append(s2);3977     return sRet;3978 }3979 inline CStdStringA operator+(const CStdStringA& s1, CStdStringA::value_type t)3980 {3981     CStdStringA sRet(SSREF(s1));3982     sRet.append(1, t);3983     return sRet;3984 }3985 inline CStdStringA operator+(const CStdStringA& s1, PCSTR pA)3986 {3987     CStdStringA sRet(SSREF(s1));3988     sRet.append(pA);3989     return sRet;3990 }3991 inline CStdStringA operator+(PCSTR pA, const CStdStringA& sA)3992 {3993     CStdStringA sRet;3994     CStdStringA::size_type nObjSize = sA.size();3995     CStdStringA::size_type nLitSize = 3996         static_cast<CStdStringA::size_type>(sslen(pA));3997 3998     sRet.reserve(nLitSize + nObjSize);3999     sRet.assign(pA);4000     sRet.append(sA);4001     return sRet;4002 }4003 4004 4005 inline CStdStringA operator+(const CStdStringA& s1, const CStdStringW& s2)4006 {4007     return s1 + CStdStringA(s2);4008 }4009 inline CStdStringW operator+(const CStdStringW& s1, const CStdStringW& s2)4010 {4011     CStdStringW sRet(SSREF(s1));4012     sRet.append(s2);4013     return sRet;4014 }4015 inline CStdStringA operator+(const CStdStringA& s1, PCWSTR pW)4016 {4017     return s1 + CStdStringA(pW);4018 }4019 4020 #ifdef UNICODE4021     inline CStdStringW operator+(PCWSTR pW, const CStdStringA& sA)4022     {4023         return CStdStringW(pW) + CStdStringW(SSREF(sA));4024     }4025     inline CStdStringW operator+(PCSTR pA, const CStdStringW& sW)4026     {4027         return CStdStringW(pA) + sW;4028     }4029 #else4030     inline CStdStringA operator+(PCWSTR pW, const CStdStringA& sA)4031     {4032         return CStdStringA(pW) + sA;4033     }4034     inline CStdStringA operator+(PCSTR pA, const CStdStringW& sW)4035     {4036         return pA + CStdStringA(sW);4037     }4038 #endif4039 4040 // ...Now the wide string versions.4041 inline CStdStringW operator+(const CStdStringW& s1, CStdStringW::value_type t)4042 {4043     CStdStringW sRet(SSREF(s1));4044     sRet.append(1, t);4045     return sRet;4046 }4047 inline CStdStringW operator+(const CStdStringW& s1, PCWSTR pW)4048 {4049     CStdStringW sRet(SSREF(s1));4050     sRet.append(pW);4051     return sRet;4052 }4053 inline CStdStringW operator+(PCWSTR pW, const CStdStringW& sW)4054 {4055     CStdStringW sRet;4056     CStdStringW::size_type nObjSize = sW.size();4057     CStdStringA::size_type nLitSize = 4058         static_cast<CStdStringW::size_type>(sslen(pW));4059 4060     sRet.reserve(nLitSize + nObjSize);4061     sRet.assign(pW);4062     sRet.append(sW);4063     return sRet;4064 }4065 4066 inline CStdStringW operator+(const CStdStringW& s1, const CStdStringA& s2)4067 {4068     return s1 + CStdStringW(s2);4069 }4070 inline CStdStringW operator+(const CStdStringW& s1, PCSTR pA)4071 {4072     return s1 + CStdStringW(pA);4073 }4074 4075 4076 // New-style format function is a template4077 4078 #ifdef SS_SAFE_FORMAT4079 4080 template<>4081 struct FmtArg<CStdStringA>4082 {4083     explicit FmtArg(const CStdStringA& arg) : a_(arg) {}4084     PCSTR operator()() const { return a_.c_str(); }4085     const CStdStringA& a_;4086 private:4087     FmtArg<CStdStringA>& operator=(const FmtArg<CStdStringA>&) { return *this; }4088 };4089 template<>4090 struct FmtArg<CStdStringW>4091 {4092     explicit FmtArg(const CStdStringW& arg) : a_(arg) {}4093     PCWSTR operator()() const { return a_.c_str(); }4094     const CStdStringW& a_;4095 private:4096     FmtArg<CStdStringW>& operator=(const FmtArg<CStdStringW>&) { return *this; }4097 };4098 4099 template<>4100 struct FmtArg<std::string>4101 {4102     explicit FmtArg(const std::string& arg) : a_(arg) {}4103     PCSTR operator()() const { return a_.c_str(); }4104     const std::string& a_;4105 private:4106     FmtArg<std::string>& operator=(const FmtArg<std::string>&) { return *this; }4107 };4108 template<>4109 struct FmtArg<std::wstring>4110 {4111     explicit FmtArg(const std::wstring& arg) : a_(arg) {}4112     PCWSTR operator()() const { return a_.c_str(); }4113     const std::wstring& a_;4114 private:4115     FmtArg<std::wstring>& operator=(const FmtArg<std::wstring>&) {return *this;}4116 };4117 #endif // #ifdef SS_SAFEFORMAT4118 4119 #ifndef SS_ANSI4120     // SSResourceHandle: our MFC-like resource handle4121     inline HMODULE& SSResourceHandle()4122     {4123         static HMODULE hModuleSS    = GetModuleHandle(0);4124         return hModuleSS;4125     }4126 #endif4127 4128 4129 // In MFC builds, define some global serialization operators4130 // Special operators that allow us to serialize CStdStrings to CArchives.4131 // Note that we use an intermediate CString object in order to ensure that4132 // we use the exact same format.4133 4134 #ifdef _MFC_VER4135     inline CArchive& AFXAPI operator<<(CArchive& ar, const CStdStringA& strA)4136     {4137         CString strTemp(strA);4138         return ar << strTemp;4139     }4140     inline CArchive& AFXAPI operator<<(CArchive& ar, const CStdStringW& strW)4141     {4142         CString strTemp(strW);4143         return ar << strTemp;4144     }4145 4146     inline CArchive& AFXAPI operator>>(CArchive& ar, CStdStringA& strA)4147     {4148         CString strTemp;4149         ar >> strTemp;4150         strA = strTemp;4151         return ar;4152     }4153     inline CArchive& AFXAPI operator>>(CArchive& ar, CStdStringW& strW)4154     {4155         CString strTemp;4156         ar >> strTemp;4157         strW = strTemp;4158         return ar;4159     }4160 #endif    // #ifdef _MFC_VER -- (i.e. is this MFC?)4161 4162 4163 4164 // -----------------------------------------------------------------------------4165 // GLOBAL FUNCTION:  WUFormat4166 //        CStdStringA WUFormat(UINT nId, ...);4167 //        CStdStringA WUFormat(PCSTR szFormat, ...);4168 //4169 // REMARKS:4170 //        This function allows the caller for format and return a CStdStringA4171 //        object with a single line of code.4172 // -----------------------------------------------------------------------------4173 4174 inline CStdStringA WUFormatA(PCSTR szFormat, ...)4175 {4176     va_list argList;4177     va_start(argList, szFormat);4178     CStdStringA strOut;4179     strOut.FormatV(szFormat, argList);4180     va_end(argList);4181     return strOut;4182 }4183 inline CStdStringW WUFormatW(PCWSTR szwFormat, ...)4184 {4185     va_list argList;4186     va_start(argList, szwFormat);4187     CStdStringW strOut;4188     strOut.FormatV(szwFormat, argList);4189     va_end(argList);4190     return strOut;4191 }4192 #ifdef SS_ANSI4193 #else4194     inline CStdStringA WUFormatA(UINT nId, ...)4195     {4196         va_list argList;4197         va_start(argList, nId);4198 4199         CStdStringA strFmt;4200         CStdStringA strOut;4201         if ( strFmt.Load(nId) )4202             strOut.FormatV(strFmt, argList);4203 4204         va_end(argList);4205         return strOut;4206     }4207 4208     inline CStdStringW WUFormatW(UINT nId, ...)4209     {4210         va_list argList;4211         va_start(argList, nId);4212 4213         CStdStringW strFmt;4214         CStdStringW strOut;4215         if ( strFmt.Load(nId) )4216             strOut.FormatV(strFmt, argList);4217 4218         va_end(argList);4219         return strOut;4220     }4221 #endif // #ifdef SS_ANSI4222 4223 4224 4225 #if defined(SS_WIN32) && !defined (SS_ANSI)4226     // -------------------------------------------------------------------------4227     // FUNCTION: WUSysMessage4228     //     CStdStringA WUSysMessageA(DWORD dwError, DWORD dwLangId=SS_DEFLANGID);4229     //     CStdStringW WUSysMessageW(DWORD dwError, DWORD dwLangId=SS_DEFLANGID);4230     //           4231     // DESCRIPTION:4232     //     This function simplifies the process of obtaining a string equivalent4233     //     of a system error code returned from GetLastError().  You simply4234     //     supply the value returned by GetLastError() to this function and the4235     //     corresponding system string is returned in the form of a CStdStringA.4236     //4237     // PARAMETERS: 4238     //     dwError - a DWORD value representing the error code to be translated4239     //     dwLangId - the language id to use.  defaults to english.4240     //4241     // RETURN VALUE: 4242     //     a CStdStringA equivalent of the error code.  Currently, this function4243     //     only returns either English of the system default language strings.  4244     // -------------------------------------------------------------------------4245     #define SS_DEFLANGID MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT)4246     inline CStdStringA WUSysMessageA(DWORD dwError, DWORD dwLangId=SS_DEFLANGID)4247     {4248         CHAR szBuf[512];4249 4250         if ( 0 != ::FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, NULL, dwError,4251                                    dwLangId, szBuf, 511, NULL) )4252             return WUFormatA("%s (0x%X)", szBuf, dwError);4253         else4254              return WUFormatA("Unknown error (0x%X)", dwError);4255     }4256     inline CStdStringW WUSysMessageW(DWORD dwError, DWORD dwLangId=SS_DEFLANGID)4257     {4258         WCHAR szBuf[512];4259 4260         if ( 0 != ::FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM, NULL, dwError,4261                                    dwLangId, szBuf, 511, NULL) )4262             return WUFormatW(L"%s (0x%X)", szBuf, dwError);4263         else4264              return WUFormatW(L"Unknown error (0x%X)", dwError);4265     }4266 #endif4267 4268 // Define TCHAR based friendly names for some of these functions4269 4270 #ifdef UNICODE4271     //#define CStdString                CStdStringW4272     typedef CStdStringW                CStdString;4273     #define WUSysMessage            WUSysMessageW4274     #define WUFormat                WUFormatW4275 #else4276     //#define CStdString                CStdStringA4277     typedef CStdStringA                CStdString;4278     #define WUSysMessage            WUSysMessageA4279     #define WUFormat                WUFormatA4280 #endif4281 4282 // ...and some shorter names for the space-efficient4283 4284 #define WUSysMsg                    WUSysMessage4285 #define WUSysMsgA                    WUSysMessageA4286 #define WUSysMsgW                    WUSysMessageW4287 #define WUFmtA                        WUFormatA4288 #define    WUFmtW                        WUFormatW4289 #define WUFmt                        WUFormat4290 #define WULastErrMsg()                WUSysMessage(::GetLastError())4291 #define WULastErrMsgA()                WUSysMessageA(::GetLastError())4292 #define WULastErrMsgW()                WUSysMessageW(::GetLastError())4293 4294 4295 // -----------------------------------------------------------------------------4296 // FUNCTIONAL COMPARATORS:4297 // REMARKS:4298 //        These structs are derived from the std::binary_function template.  They4299 //        give us functional classes (which may be used in Standard C++ Library4300 //        collections and algorithms) that perform case-insensitive comparisons of4301 //        CStdString objects.  This is useful for maps in which the key may be the4302 //         proper string but in the wrong case.4303 // -----------------------------------------------------------------------------4304 #define StdStringLessNoCaseW        SSLNCW    // avoid VC compiler warning 47864305 #define StdStringEqualsNoCaseW        SSENCW        4306 #define StdStringLessNoCaseA        SSLNCA        4307 #define StdStringEqualsNoCaseA        SSENCA        4308 4309 #ifdef UNICODE4310     #define StdStringLessNoCase        SSLNCW        4311     #define StdStringEqualsNoCase    SSENCW        4312 #else4313     #define StdStringLessNoCase        SSLNCA        4314     #define StdStringEqualsNoCase    SSENCA        4315 #endif4316 4317 struct StdStringLessNoCaseW4318     : std::binary_function<CStdStringW, CStdStringW, bool>4319 {4320     inline4321     bool operator()(const CStdStringW& sLeft, const CStdStringW& sRight) const4322     { return ssicmp(sLeft.c_str(), sRight.c_str()) < 0; }4323 };4324 struct StdStringEqualsNoCaseW4325     : std::binary_function<CStdStringW, CStdStringW, bool>4326 {4327     inline4328     bool operator()(const CStdStringW& sLeft, const CStdStringW& sRight) const4329     { return ssicmp(sLeft.c_str(), sRight.c_str()) == 0; }4330 };4331 struct StdStringLessNoCaseA4332     : std::binary_function<CStdStringA, CStdStringA, bool>4333 {4334     inline4335     bool operator()(const CStdStringA& sLeft, const CStdStringA& sRight) const4336     { return ssicmp(sLeft.c_str(), sRight.c_str()) < 0; }4337 };4338 struct StdStringEqualsNoCaseA4339     : std::binary_function<CStdStringA, CStdStringA, bool>4340 {4341     inline4342     bool operator()(const CStdStringA& sLeft, const CStdStringA& sRight) const4343     { return ssicmp(sLeft.c_str(), sRight.c_str()) == 0; }4344 };4345 4346 // If we had to define our own version of TRACE above, get rid of it now4347 4348 #ifdef TRACE_DEFINED_HERE4349     #undef TRACE4350     #undef TRACE_DEFINED_HERE4351 #endif4352 4353 4354 // These std::swap specializations come courtesy of Mike Crusader. 4355 4356 //namespace std4357 //{4358 //    inline void swap(CStdStringA& s1, CStdStringA& s2) throw()4359 //    {4360 //        s1.swap(s2);4361 //    }4362 //    template<>4363 //    inline void swap(CStdStringW& s1, CStdStringW& s2) throw()4364 //    {4365 //        s1.swap(s2);4366 //    }4367 //}4368 4369 // Turn back on any Borland warnings we turned off.4370 4371 #ifdef __BORLANDC__4372     #pragma option pop  // Turn back on inline function warnings4373 //    #pragma warn +inl   // Turn back on inline function warnings4374 #endif4375 4376 #endif    // #ifndef STDSTRING_H
stdstring.h

 

跨平台的CStdString类,实现了CString的接口