首页 > 代码库 > 跨平台的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
跨平台的CStdString类,实现了CString的接口
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。