6 #if defined(TARGET_WINDOWS) && !defined(va_copy)
7 #define va_copy(dst, src) ((dst) = (src))
10 // =============================================================================
12 // AUTHOR: Joe O'Leary (with outside help noted in comments)
14 // If you find any bugs in this code, please let me know:
16 // jmoleary@earthlink.net
17 // http://www.joeo.net/stdstring.htm (a bit outdated)
19 // The latest version of this code should always be available at the
22 // http://www.joeo.net/code/StdString.zip (Dec 6, 2003)
26 // This header file declares the CStdStr template. This template derives
27 // the Standard C++ Library basic_string<> template and add to it the
28 // the following conveniences:
29 // - The full MFC CString set of functions (including implicit cast)
30 // - writing to/reading from COM IStream interfaces
31 // - Functional objects for use in STL algorithms
33 // From this template, we intstantiate two classes: CStdStringA and
34 // CStdStringW. The name "CStdString" is just a #define of one of these,
35 // based upone the UNICODE macro setting
37 // This header also declares our own version of the MFC/ATL UNICODE-MBCS
38 // conversion macros. Our version looks exactly like the Microsoft's to
39 // facilitate portability.
42 // If you you use this in an MFC or ATL build, you should include either
43 // afx.h or atlbase.h first, as appropriate.
45 // PEOPLE WHO HAVE CONTRIBUTED TO THIS CLASS:
47 // Several people have helped me iron out problems and othewise improve
48 // this class. OK, this is a long list but in my own defense, this code
49 // has undergone two major rewrites. Many of the improvements became
50 // necessary after I rewrote the code as a template. Others helped me
51 // improve the CString facade.
53 // Anyway, these people are (in chronological order):
55 // - Pete the Plumber (???)
57 // - Chris (of Melbsys)
70 // - Baptiste Lepilleur
78 // - Aaron (no last name)
79 // - Joldakowski (???)
83 // - Farrokh Nejadlotfi
93 // - Bagira (full name?)
106 // 2005-JAN-10 - Thanks to Don Beusee for pointing out the danger in mapping
107 // length-checked formatting functions to non-length-checked
108 // CRT equivalents. Also thanks to him for motivating me to
109 // optimize my implementation of Replace()
111 // 2004-APR-22 - A big, big thank you to "MKingman" (whoever you are) for
112 // finally spotting a silly little error in StdCodeCvt that
113 // has been causing me (and users of CStdString) problems for
114 // years in some relatively rare conversions. I had reversed
115 // two length arguments.
117 // 2003-NOV-24 - Thanks to a bunch of people for helping me clean up many
118 // compiler warnings (and yes, even a couple of actual compiler
119 // errors). These include Henk Demper for figuring out how
120 // to make the Intellisense work on with CStdString on VC6,
121 // something I was never able to do. Greg Marr pointed out
122 // a compiler warning about an unreferenced symbol and a
123 // problem with my version of Load in MFC builds. Bill
124 // Carducci took a lot of time with me to help me figure out
125 // why some implementations of the Standard C++ Library were
126 // returning error codes for apparently successful conversions
127 // between ASCII and UNICODE. Finally thanks to Brian Groose
128 // for helping me fix compiler signed unsigned warnings in
129 // several functions.
131 // 2003-JUL-10 - Thanks to Charles Godwin for making me realize my 'FmtArg'
132 // fixes had inadvertently broken the DLL-export code (which is
133 // normally commented out. I had to move it up higher. Also
134 // this helped me catch a bug in ssicoll that would prevent
135 // compilation, otherwise.
137 // 2003-MAR-14 - Thanks to Jakko Van Hunen for pointing out a copy-and-paste
138 // bug in one of the overloads of FmtArg.
140 // 2003-MAR-10 - Thanks to Ronny Schulz for (twice!) sending me some changes
141 // to help CStdString build on SGI and for pointing out an
142 // error in placement of my preprocessor macros for ssfmtmsg.
144 // 2002-NOV-26 - Thanks to Bagira for pointing out that my implementation of
145 // SpanExcluding was not properly handling the case in which
146 // the string did NOT contain any of the given characters
148 // 2002-OCT-21 - Many thanks to Paul DeMarco who was invaluable in helping me
149 // get this code working with Borland's free compiler as well
150 // as the Dev-C++ compiler (available free at SourceForge).
152 // 2002-SEP-13 - Thanks to Glen Maynard who helped me get rid of some loud
153 // but harmless warnings that were showing up on g++. Glen
154 // also pointed out that some pre-declarations of FmtArg<>
155 // specializations were unnecessary (and no good on G++)
157 // 2002-JUN-26 - Thanks to Arnt Witteveen for pointing out that I was using
158 // static_cast<> in a place in which I should have been using
159 // reinterpret_cast<> (the ctor for unsigned char strings).
160 // That's what happens when I don't unit-test properly!
161 // Arnt also noticed that CString was silently correcting the
162 // 'nCount' argument to Left() and Right() where CStdString was
163 // not (and crashing if it was bad). That is also now fixed!
165 // 2002-FEB-25 - Thanks to Tim Dowty for pointing out (and giving me the fix
166 // for) a conversion problem with non-ASCII MBCS characters.
167 // CStdString is now used in my favorite commercial MP3 player!
169 // 2001-DEC-06 - Thanks to Wang Haifeng for spotting a problem in one of the
170 // assignment operators (for _bstr_t) that would cause compiler
171 // errors when refcounting protection was turned off.
173 // 2001-NOV-27 - Remove calls to operator!= which involve reverse_iterators
174 // due to a conflict with the rel_ops operator!=. Thanks to
175 // John James for pointing this out.
177 // 2001-OCT-29 - Added a minor range checking fix for the Mid function to
178 // make it as forgiving as CString's version is. Thanks to
179 // Igor Kholodov for noticing this.
180 // - Added a specialization of std::swap for CStdString. Thanks
181 // to Mike Crusader for suggesting this! It's commented out
182 // because you're not supposed to inject your own code into the
183 // 'std' namespace. But if you don't care about that, it's
184 // there if you want it
185 // - Thanks to Jason Mills for catching a case where CString was
186 // more forgiving in the Delete() function than I was.
188 // 2001-JUN-06 - I was violating the Standard name lookup rules stated
189 // in [14.6.2(3)]. None of the compilers I've tried so
190 // far apparently caught this but HP-UX aCC 3.30 did. The
191 // fix was to add 'this->' prefixes in many places.
192 // Thanks to Farrokh Nejadlotfi for this!
194 // 2001-APR-27 - StreamLoad was calculating the number of BYTES in one
195 // case, not characters. Thanks to Pablo Presedo for this.
197 // 2001-FEB-23 - Replace() had a bug which caused infinite loops if the
198 // source string was empty. Fixed thanks to Eric Nitzsche.
200 // 2001-FEB-23 - Scott Hathaway was a huge help in providing me with the
201 // ability to build CStdString on Sun Unix systems. He
202 // sent me detailed build reports about what works and what
203 // does not. If CStdString compiles on your Unix box, you
204 // can thank Scott for it.
206 // 2000-DEC-29 - Joldakowski noticed one overload of Insert failed to do a
207 // range check as CString's does. Now fixed -- thanks!
209 // 2000-NOV-07 - Aaron pointed out that I was calling static member
210 // functions of char_traits via a temporary. This was not
211 // technically wrong, but it was unnecessary and caused
212 // problems for poor old buggy VC5. Thanks Aaron!
214 // 2000-JUL-11 - Joe Woodbury noted that the CString::Find docs don't match
215 // what the CString::Find code really ends up doing. I was
216 // trying to match the docs. Now I match the CString code
217 // - Joe also caught me truncating strings for GetBuffer() calls
218 // when the supplied length was less than the current length.
220 // 2000-MAY-25 - Better support for STLPORT's Standard library distribution
221 // - Got rid of the NSP macro - it interfered with Koenig lookup
222 // - Thanks to Joe Woodbury for catching a TrimLeft() bug that
223 // I introduced in January. Empty strings were not getting
226 // 2000-APR-17 - Thanks to Joe Vitaterna for pointing out that ReverseFind
227 // is supposed to be a const function.
229 // 2000-MAR-07 - Thanks to Ullrich Poll�hne for catching a range bug in one
230 // of the overloads of assign.
232 // 2000-FEB-01 - You can now use CStdString on the Mac with CodeWarrior!
233 // Thanks to Todd Heckel for helping out with this.
235 // 2000-JAN-23 - Thanks to Jim Cline for pointing out how I could make the
236 // Trim() function more efficient.
237 // - Thanks to Jeff Kohn for prompting me to find and fix a typo
238 // in one of the addition operators that takes _bstr_t.
239 // - Got rid of the .CPP file - you only need StdString.h now!
241 // 1999-DEC-22 - Thanks to Greg Pickles for helping me identify a problem
242 // with my implementation of CStdString::FormatV in which
243 // resulting string might not be properly NULL terminated.
245 // 1999-DEC-06 - Chris Conti pointed yet another basic_string<> assignment
246 // bug that MS has not fixed. CStdString did nothing to fix
247 // it either but it does now! The bug was: create a string
248 // longer than 31 characters, get a pointer to it (via c_str())
249 // and then assign that pointer to the original string object.
250 // The resulting string would be empty. Not with CStdString!
252 // 1999-OCT-06 - BufferSet was erasing the string even when it was merely
253 // supposed to shrink it. Fixed. Thanks to Chris Conti.
254 // - Some of the Q172398 fixes were not checking for assignment-
255 // to-self. Fixed. Thanks to Baptiste Lepilleur.
257 // 1999-AUG-20 - Improved Load() function to be more efficient by using
258 // SizeOfResource(). Thanks to Rich Zuris for this.
259 // - Corrected resource ID constructor, again thanks to Rich.
260 // - Fixed a bug that occurred with UNICODE characters above
261 // the first 255 ANSI ones. Thanks to Craig Watson.
262 // - Added missing overloads of TrimLeft() and TrimRight().
263 // Thanks to Karim Ratib for pointing them out
265 // 1999-JUL-21 - Made all calls to GetBuf() with no args check length first.
267 // 1999-JUL-10 - Improved MFC/ATL independence of conversion macros
268 // - Added SS_NO_REFCOUNT macro to allow you to disable any
269 // reference-counting your basic_string<> impl. may do.
270 // - Improved ReleaseBuffer() to be as forgiving as CString.
271 // Thanks for Fan Xia for helping me find this and to
272 // Matthew Williams for pointing it out directly.
274 // 1999-JUL-06 - Thanks to Nigel Nunn for catching a very sneaky bug in
275 // ToLower/ToUpper. They should call GetBuf() instead of
276 // data() in order to ensure the changed string buffer is not
277 // reference-counted (in those implementations that refcount).
279 // 1999-JUL-01 - Added a true CString facade. Now you can use CStdString as
280 // a drop-in replacement for CString. If you find this useful,
281 // you can thank Chris Sells for finally convincing me to give
282 // in and implement it.
283 // - Changed operators << and >> (for MFC CArchive) to serialize
284 // EXACTLY as CString's do. So now you can send a CString out
285 // to a CArchive and later read it in as a CStdString. I have
286 // no idea why you would want to do this but you can.
288 // 1999-JUN-21 - Changed the CStdString class into the CStdStr template.
289 // - Fixed FormatV() to correctly decrement the loop counter.
290 // This was harmless bug but a bug nevertheless. Thanks to
291 // Chris (of Melbsys) for pointing it out
292 // - Changed Format() to try a normal stack-based array before
293 // using to _alloca().
294 // - Updated the text conversion macros to properly use code
295 // pages and to fit in better in MFC/ATL builds. In other
296 // words, I copied Microsoft's conversion stuff again.
297 // - Added equivalents of CString::GetBuffer, GetBufferSetLength
298 // - new sscpy() replacement of CStdString::CopyString()
299 // - a Trim() function that combines TrimRight() and TrimLeft().
301 // 1999-MAR-13 - Corrected the "NotSpace" functional object to use _istpace()
302 // instead of _isspace() Thanks to Dave Plummer for this.
304 // 1999-FEB-26 - Removed errant line (left over from testing) that #defined
305 // _MFC_VER. Thanks to John C Sipos for noticing this.
307 // 1999-FEB-03 - Fixed a bug in a rarely-used overload of operator+() that
308 // caused infinite recursion and stack overflow
309 // - Added member functions to simplify the process of
310 // persisting CStdStrings to/from DCOM IStream interfaces
311 // - Added functional objects (e.g. StdStringLessNoCase) that
312 // allow CStdStrings to be used as keys STL map objects with
313 // case-insensitive comparison
314 // - Added array indexing operators (i.e. operator[]). I
315 // originally assumed that these were unnecessary and would be
316 // inherited from basic_string. However, without them, Visual
317 // C++ complains about ambiguous overloads when you try to use
318 // them. Thanks to Julian Selman to pointing this out.
320 // 1998-FEB-?? - Added overloads of assign() function to completely account
321 // for Q172398 bug. Thanks to "Pete the Plumber" for this
323 // 1998-FEB-?? - Initial submission
326 // 2002 Joseph M. O'Leary. This code is 100% free. Use it anywhere you
327 // want. Rewrite it, restructure it, whatever. If you can write software
328 // that makes money off of it, good for you. I kinda like capitalism.
329 // Please don't blame me if it causes your $30 billion dollar satellite
330 // explode in orbit. If you redistribute it in any form, I'd appreciate it
331 // if you would leave this notice here.
332 // =============================================================================
334 // Avoid multiple inclusion
339 // When using VC, turn off browser references
340 // Turn off unavoidable compiler warnings
342 #if defined(_MSC_VER) && (_MSC_VER > 1100)
343 #pragma component(browser, off, references, "CStdString")
344 #pragma warning (disable : 4290) // C++ Exception Specification ignored
345 #pragma warning (disable : 4127) // Conditional expression is constant
346 #pragma warning (disable : 4097) // typedef name used as synonym for class name
349 // Borland warnings to turn off
352 #pragma option push -w-inl
353 // #pragma warn -inl // Turn off inline function warnings
358 // A copy of IS_INTRESOURCE from VC7. Because old VC6 version of winuser.h
359 // doesn't have this.
361 #define SS_IS_INTRESOURCE(_r) (false)
363 #if !defined (SS_ANSI) && defined(_MSC_VER)
364 #undef SS_IS_INTRESOURCE
366 #define SS_IS_INTRESOURCE(_r) (((uint64_t)(_r) >> 16) == 0)
368 #define SS_IS_INTRESOURCE(_r) (((unsigned long)(_r) >> 16) == 0)
373 // MACRO: SS_UNSIGNED
374 // ------------------
375 // This macro causes the addition of a constructor and assignment operator
376 // which take unsigned characters. CString has such functions and in order
377 // to provide maximum CString-compatability, this code needs them as well.
378 // In practice you will likely never need these functions...
380 //#define SS_UNSIGNED
382 #ifdef SS_ALLOW_UNSIGNED_CHARS
386 // MACRO: SS_SAFE_FORMAT
387 // ---------------------
388 // This macro provides limited compatability with a questionable CString
389 // "feature". You can define it in order to avoid a common problem that
390 // people encounter when switching from CString to CStdString.
392 // To illustrate the problem -- With CString, you can do this:
394 // CString sName("Joe");
396 // sTmp.Format("My name is %s", sName); // WORKS!
398 // However if you were to try this with CStdString, your program would
401 // CStdString sName("Joe");
403 // sTmp.Format("My name is %s", sName); // CRASHES!
405 // You must explicitly call c_str() or cast the object to the proper type
407 // sTmp.Format("My name is %s", sName.c_str()); // WORKS!
408 // sTmp.Format("My name is %s", static_cast<PCSTR>(sName));// WORKS!
409 // sTmp.Format("My name is %s", (PCSTR)sName); // WORKS!
411 // This is because it is illegal to pass anything but a POD type as a
412 // variadic argument to a variadic function (i.e. as one of the "..."
413 // arguments). The type const char* is a POD type. The type CStdString
414 // is not. Of course, neither is the type CString, but CString lets you do
415 // it anyway due to the way they laid out the class in binary. I have no
416 // control over this in CStdString since I derive from whatever
417 // implementation of basic_string is available.
419 // However if you have legacy code (which does this) that you want to take
420 // out of the MFC world and you don't want to rewrite all your calls to
421 // Format(), then you can define this flag and it will no longer crash.
423 // Note however that this ONLY works for Format(), not sprintf, fprintf,
424 // etc. If you pass a CStdString object to one of those functions, your
425 // program will crash. Not much I can do to get around this, short of
426 // writing substitutes for those functions as well.
428 #define SS_SAFE_FORMAT // use new template style Format() function
431 // MACRO: SS_NO_IMPLICIT_CAST
432 // --------------------------
433 // Some people don't like the implicit cast to const char* (or rather to
434 // const CT*) that CStdString (and MFC's CString) provide. That was the
435 // whole reason I created this class in the first place, but hey, whatever
436 // bakes your cake. Just #define this macro to get rid of the the implicit
439 //#define SS_NO_IMPLICIT_CAST // gets rid of operator const CT*()
442 // MACRO: SS_NO_REFCOUNT
443 // ---------------------
444 // turns off reference counting at the assignment level. Only needed
445 // for the version of basic_string<> that comes with Visual C++ versions
446 // 6.0 or earlier, and only then in some heavily multithreaded scenarios.
447 // Uncomment it if you feel you need it.
449 //#define SS_NO_REFCOUNT
453 // When this flag is set, we are building code for the Win32 platform and
454 // may use Win32 specific functions (such as LoadString). This gives us
455 // a couple of nice extras for the code.
457 // Obviously, Microsoft's is not the only compiler available for Win32 out
458 // there. So I can't just check to see if _MSC_VER is defined to detect
459 // if I'm building on Win32. So for now, if you use MS Visual C++ or
460 // Borland's compiler, I turn this on. Otherwise you may turn it on
461 // yourself, if you prefer
463 #if defined(_MSC_VER) || defined(__BORLANDC__) || defined(_WIN32)
469 // When this macro is defined, the code attempts only to use ANSI/ISO
470 // standard library functions to do it's work. It will NOT attempt to use
471 // any Win32 of Visual C++ specific functions -- even if they are
472 // available. You may define this flag yourself to prevent any Win32
473 // of VC++ specific functions from being called.
475 // If we're not on Win32, we MUST use an ANSI build
478 #if !defined(SS_NO_ANSI)
485 // Some implementations of the Standard C Library have a non-standard
486 // function known as alloca(). This functions allows one to allocate a
487 // variable amount of memory on the stack. It is needed to implement
488 // the ASCII/MBCS conversion macros.
490 // I wanted to find some way to determine automatically if alloca() is
491 // available on this platform via compiler flags but that is asking for
492 // trouble. The crude test presented here will likely need fixing on
493 // other platforms. Therefore I'll leave it up to you to fiddle with
494 // this test to determine if it exists. Just make sure SS_ALLOCA is or
495 // is not defined as appropriate and you control this feature.
497 #if defined(_MSC_VER) && !defined(SS_ANSI)
504 // Setting this macro means you are using MBCS characters. In MSVC builds,
505 // this macro gets set automatically by detection of the preprocessor flag
506 // _MBCS. For other platforms you may set it manually if you wish. The
507 // only effect it currently has is to cause the allocation of more space
508 // for wchar_t --> char conversions.
509 // Note that MBCS does not mean UNICODE.
519 // MACRO SS_NO_LOCALE
520 // ------------------
521 // If your implementation of the Standard C++ Library lacks the <locale> header,
522 // you can #define this macro to make your code build properly. Note that this
523 // is some of my newest code and frankly I'm not very sure of it, though it does
524 // pass my unit tests.
526 // #define SS_NO_LOCALE
529 // Compiler Error regarding _UNICODE and UNICODE
530 // -----------------------------------------------
531 // Microsoft header files are screwy. Sometimes they depend on a preprocessor
532 // flag named "_UNICODE". Other times they check "UNICODE" (note the lack of
533 // leading underscore in the second version". In several places, they silently
534 // "synchronize" these two flags this by defining one of the other was defined.
535 // In older version of this header, I used to try to do the same thing.
537 // However experience has taught me that this is a bad idea. You get weird
538 // compiler errors that seem to indicate things like LPWSTR and LPTSTR not being
539 // equivalent in UNICODE builds, stuff like that (when they MUST be in a proper
540 // UNICODE build). You end up scratching your head and saying, "But that HAS
543 // So what should you do if you get this error?
545 // Make sure that both macros (_UNICODE and UNICODE) are defined before this
546 // file is included. You can do that by either
548 // a) defining both yourself before any files get included
549 // b) including the proper MS headers in the proper order
550 // c) including this file before any other file, uncommenting
551 // the #defines below, and commenting out the #errors
553 // Personally I recommend solution a) but it's your call.
556 #if defined (_UNICODE) && !defined (UNICODE)
557 #error UNICODE defined but not UNICODE
558 // #define UNICODE // no longer silently fix this
560 #if defined (UNICODE) && !defined (_UNICODE)
561 #error Warning, UNICODE defined but not _UNICODE
562 // #define _UNICODE // no longer silently fix this
567 // -----------------------------------------------------------------------------
568 // MIN and MAX. The Standard C++ template versions go by so many names (at
569 // at least in the MS implementation) that you never know what's available
570 // -----------------------------------------------------------------------------
572 inline const Type& SSMIN(const Type& arg1, const Type& arg2)
574 return arg2 < arg1 ? arg2 : arg1;
577 inline const Type& SSMAX(const Type& arg1, const Type& arg2)
579 return arg2 > arg1 ? arg2 : arg1;
582 // If they have not #included W32Base.h (part of my W32 utility library) then
583 // we need to define some stuff. Otherwise, this is all defined there.
585 #if !defined(W32BASE_H)
587 // If they want us to use only standard C++ stuff (no Win32 stuff)
591 // On Win32 we have TCHAR.H so just include it. This is NOT violating
592 // the spirit of SS_ANSI as we are not calling any Win32 functions here.
602 // ... but on non-Win32 platforms, we must #define the types we need.
606 typedef const char* PCSTR;
608 typedef const wchar_t* PCWSTR;
609 typedef wchar_t* PWSTR;
611 typedef wchar_t TCHAR;
615 typedef wchar_t OLECHAR;
617 #endif // #ifndef _WIN32
620 // Make sure ASSERT and verify are defined using only ANSI stuff
624 #define ASSERT(f) assert((f))
628 #define VERIFY(x) ASSERT((x))
634 #else // ...else SS_ANSI is NOT defined
642 // Make sure ASSERT and verify are defined
646 #define ASSERT(f) _ASSERTE((f))
650 #define VERIFY(x) ASSERT((x))
656 #endif // #ifdef SS_ANSI
662 #endif // #ifndef W32BASE_H
664 // Standard headers needed
666 #include <string> // basic_string
667 #include <algorithm> // for_each, etc.
668 #include <functional> // for StdStringLessNoCase, et al
670 #include <locale> // for various facets
673 // If this is a recent enough version of VC include comdef.h, so we can write
674 // member functions to deal with COM types & compiler support classes e.g.
677 #if defined (_MSC_VER) && (_MSC_VER >= 1100)
679 #define SS_INC_COMDEF // signal that we #included MS comdef.h file
680 #define STDSTRING_INC_COMDEF
681 #define SS_NOTHROW __declspec(nothrow)
687 #define TRACE_DEFINED_HERE
691 // Microsoft defines PCSTR, PCWSTR, etc, but no PCTSTR. I hate to use the
692 // versions with the "L" in front of them because that's a leftover from Win 16
693 // days, even though it evaluates to the same thing. Therefore, Define a PCSTR
696 #if !defined(PCTSTR) && !defined(PCTSTR_DEFINED)
697 typedef const TCHAR* PCTSTR;
698 #define PCTSTR_DEFINED
701 #if !defined(PCOLESTR) && !defined(PCOLESTR_DEFINED)
702 typedef const OLECHAR* PCOLESTR;
703 #define PCOLESTR_DEFINED
706 #if !defined(POLESTR) && !defined(POLESTR_DEFINED)
707 typedef OLECHAR* POLESTR;
708 #define POLESTR_DEFINED
711 #if !defined(PCUSTR) && !defined(PCUSTR_DEFINED)
712 typedef const unsigned char* PCUSTR;
713 typedef unsigned char* PUSTR;
714 #define PCUSTR_DEFINED
718 // SGI compiler 7.3 doesnt know these types - oh and btw, remember to use
719 // -LANG:std in the CXX Flags
721 typedef unsigned long DWORD;
722 typedef void * LPCVOID;
726 // SS_USE_FACET macro and why we need it:
728 // Since I'm a good little Standard C++ programmer, I use locales. Thus, I
729 // need to make use of the use_facet<> template function here. Unfortunately,
730 // this need is complicated by the fact the MS' implementation of the Standard
731 // C++ Library has a non-standard version of use_facet that takes more
732 // arguments than the standard dictates. Since I'm trying to write CStdString
733 // to work with any version of the Standard library, this presents a problem.
735 // The upshot of this is that I can't do 'use_facet' directly. The MS' docs
736 // tell me that I have to use a macro, _USE() instead. Since _USE obviously
737 // won't be available in other implementations, this means that I have to write
738 // my OWN macro -- SS_USE_FACET -- that evaluates either to _USE or to the
739 // standard, use_facet.
741 // If you are having trouble with the SS_USE_FACET macro, in your implementation
742 // of the Standard C++ Library, you can define your own version of SS_USE_FACET.
746 #define schSTR2(x) schSTR(x)
747 #define schMSG(desc) message(__FILE__ "(" schSTR2(__LINE__) "):" #desc)
752 // STLPort #defines a macro (__STL_NO_EXPLICIT_FUNCTION_TMPL_ARGS) for
753 // all MSVC builds, erroneously in my opinion. It causes problems for
754 // my SS_ANSI builds. In my code, I always comment out that line. You'll
755 // find it in \stlport\config\stl_msvc.h
757 #if defined(__SGI_STL_PORT) && (__SGI_STL_PORT >= 0x400 )
759 #if defined(__STL_NO_EXPLICIT_FUNCTION_TMPL_ARGS) && defined(_MSC_VER)
761 #pragma schMSG(__STL_NO_EXPLICIT_FUNCTION_TMPL_ARGS defined!!)
764 #define SS_USE_FACET(loc, fac) std::use_facet<fac >(loc)
766 #elif defined(_MSC_VER )
768 #define SS_USE_FACET(loc, fac) std::_USE(loc, fac)
771 #elif defined(_RWSTD_NO_TEMPLATE_ON_RETURN_TYPE)
773 #define SS_USE_FACET(loc, fac) std::use_facet(loc, (fac*)0)
777 #define SS_USE_FACET(loc, fac) std::use_facet<fac >(loc)
783 // =============================================================================
784 // UNICODE/MBCS conversion macros. Made to work just like the MFC/ATL ones.
785 // =============================================================================
787 #include <wchar.h> // Added to Std Library with Amendment #1.
789 // First define the conversion helper functions. We define these regardless of
790 // any preprocessor macro settings since their names won't collide.
792 // Not sure if we need all these headers. I believe ANSI says we do.
806 #if defined(_WIN32) || defined (_WIN32_WCE)
808 inline PWSTR StdCodeCvt(PWSTR pDstW, int nDst, PCSTR pSrcA, int nSrc,
814 MultiByteToWideChar(acp, 0, pSrcA, nSrc, pDstW, nDst);
817 inline PWSTR StdCodeCvt(PWSTR pDstW, int nDst, PCUSTR pSrcA, int nSrc,
820 return StdCodeCvt(pDstW, nDst, (PCSTR)pSrcA, nSrc, acp);
823 inline PSTR StdCodeCvt(PSTR pDstA, int nDst, PCWSTR pSrcW, int nSrc,
829 WideCharToMultiByte(acp, 0, pSrcW, nSrc, pDstA, nDst, 0, 0);
832 inline PUSTR StdCodeCvt(PUSTR pDstA, int nDst, PCWSTR pSrcW, int nSrc,
835 return (PUSTR)StdCodeCvt((PSTR)pDstA, nDst, pSrcW, nSrc, acp);
842 // StdCodeCvt - made to look like Win32 functions WideCharToMultiByte
843 // and MultiByteToWideChar but uses locales in SS_ANSI
844 // builds. There are a number of overloads.
845 // First argument is the destination buffer.
846 // Second argument is the source buffer
847 //#if defined (SS_ANSI) || !defined (SS_WIN32)
849 // 'SSCodeCvt' - shorthand name for the codecvt facet we use
851 typedef std::codecvt<wchar_t, char, mbstate_t> SSCodeCvt;
853 inline PWSTR StdCodeCvt(PWSTR pDstW, int nDst, PCSTR pSrcA, int nSrc,
854 const std::locale& loc=std::locale())
863 PCSTR pNextSrcA = pSrcA;
864 PWSTR pNextDstW = pDstW;
865 SSCodeCvt::result res = SSCodeCvt::ok;
866 const SSCodeCvt& conv = SS_USE_FACET(loc, SSCodeCvt);
867 #if defined(TARGET_DARWIN) || defined(TARGET_FREEBSD)
868 SSCodeCvt::state_type st= { { 0 } };
870 SSCodeCvt::state_type st= { 0 };
873 pSrcA, pSrcA + nSrc, pNextSrcA,
874 pDstW, pDstW + nDst, pNextDstW);
876 #define ASSERT2(a) if (!(a)) {fprintf(stderr, "StdString: Assertion Failed on line %d\n", __LINE__);}
878 #define ASSERT2 ASSERT
880 ASSERT2(SSCodeCvt::ok == res);
881 ASSERT2(SSCodeCvt::error != res);
882 ASSERT2(pNextDstW >= pDstW);
883 ASSERT2(pNextSrcA >= pSrcA);
885 // Null terminate the converted string
887 if ( pNextDstW - pDstW > nDst )
888 *(pDstW + nDst) = '\0';
894 inline PWSTR StdCodeCvt(PWSTR pDstW, int nDst, PCUSTR pSrcA, int nSrc,
895 const std::locale& loc=std::locale())
897 return StdCodeCvt(pDstW, nDst, (PCSTR)pSrcA, nSrc, loc);
900 inline PSTR StdCodeCvt(PSTR pDstA, int nDst, PCWSTR pSrcW, int nSrc,
901 const std::locale& loc=std::locale())
910 PSTR pNextDstA = pDstA;
911 PCWSTR pNextSrcW = pSrcW;
912 SSCodeCvt::result res = SSCodeCvt::ok;
913 const SSCodeCvt& conv = SS_USE_FACET(loc, SSCodeCvt);
914 #if defined(TARGET_DARWIN) || defined(TARGET_FREEBSD)
915 SSCodeCvt::state_type st= { { 0 } };
917 SSCodeCvt::state_type st= { 0 };
920 pSrcW, pSrcW + nSrc, pNextSrcW,
921 pDstA, pDstA + nDst, pNextDstA);
923 #define ASSERT2(a) if (!(a)) {fprintf(stderr, "StdString: Assertion Failed on line %d\n", __LINE__);}
925 #define ASSERT2 ASSERT
927 ASSERT2(SSCodeCvt::error != res);
928 ASSERT2(SSCodeCvt::ok == res); // strict, comment out for sanity
929 ASSERT2(pNextDstA >= pDstA);
930 ASSERT2(pNextSrcW >= pSrcW);
933 // Null terminate the converted string
935 if ( pNextDstA - pDstA > nDst )
936 *(pDstA + nDst) = '\0';
943 inline PUSTR StdCodeCvt(PUSTR pDstA, int nDst, PCWSTR pSrcW, int nSrc,
944 const std::locale& loc=std::locale())
946 return (PUSTR)StdCodeCvt((PSTR)pDstA, nDst, pSrcW, nSrc, loc);
953 // Unicode/MBCS conversion macros are only available on implementations of
954 // the "C" library that have the non-standard _alloca function. As far as I
955 // know that's only Microsoft's though I've heard that the function exists
958 #if defined(SS_ALLOCA) && !defined SS_NO_CONVERSION
960 #include <malloc.h> // needed for _alloca
962 // Define our conversion macros to look exactly like Microsoft's to
963 // facilitate using this stuff both with and without MFC/ATL
965 #ifdef _CONVERSION_USES_THREAD_LOCALE
968 #define SSCVT int _cvt; _cvt; UINT _acp=GetACP(); \
969 _acp; PCWSTR _pw; _pw; PCSTR _pa; _pa
971 #define SSCVT int _cvt = 0; _cvt; UINT _acp=GetACP();\
972 _acp; PCWSTR _pw=0; _pw; PCSTR _pa=0; _pa
975 ((_pa = pa) == 0) ? 0 : (\
976 _cvt = (sslen(_pa)),\
977 StdCodeCvt((PWSTR) _alloca((_cvt+1)*2), (_cvt+1)*2, \
980 ((_pw = pw) == 0) ? 0 : (\
982 StdCodeCvt((LPSTR) _alloca((_cvt+1)*2), (_cvt+1)*2, \
987 #define SSCVT int _cvt; _cvt; UINT _acp=CP_ACP; _acp;\
988 PCWSTR _pw; _pw; PCSTR _pa; _pa
990 #define SSCVT int _cvt = 0; _cvt; UINT _acp=CP_ACP; \
991 _acp; PCWSTR _pw=0; _pw; PCSTR _pa=0; _pa
994 ((_pa = pa) == 0) ? 0 : (\
995 _cvt = (sslen(_pa)),\
996 StdCodeCvt((PWSTR) _alloca((_cvt+1)*2), (_cvt+1)*2, \
999 ((_pw = pw) == 0) ? 0 : (\
1000 _cvt = (sslen(_pw)),\
1001 StdCodeCvt((LPSTR) _alloca((_cvt+1)*2), (_cvt+1)*2, \
1005 #define SSA2CW(pa) ((PCWSTR)SSA2W((pa)))
1006 #define SSW2CA(pw) ((PCSTR)SSW2A((pw)))
1011 #define SST2CA SSW2CA
1012 #define SSA2CT SSA2CW
1013 // (Did you get a compiler error here about not being able to convert
1014 // PTSTR into PWSTR? Then your _UNICODE and UNICODE flags are messed
1015 // up. Best bet: #define BOTH macros before including any MS headers.)
1016 inline PWSTR SST2W(PTSTR p) { return p; }
1017 inline PTSTR SSW2T(PWSTR p) { return p; }
1018 inline PCWSTR SST2CW(PCTSTR p) { return p; }
1019 inline PCTSTR SSW2CT(PCWSTR p) { return p; }
1023 #define SST2CW SSA2CW
1024 #define SSW2CT SSW2CA
1025 inline PSTR SST2A(PTSTR p) { return p; }
1026 inline PTSTR SSA2T(PSTR p) { return p; }
1027 inline PCSTR SST2CA(PCTSTR p) { return p; }
1028 inline PCTSTR SSA2CT(PCSTR p) { return p; }
1029 #endif // #ifdef UNICODE
1031 #if defined(UNICODE)
1032 // in these cases the default (TCHAR) is the same as OLECHAR
1033 inline PCOLESTR SST2COLE(PCTSTR p) { return p; }
1034 inline PCTSTR SSOLE2CT(PCOLESTR p) { return p; }
1035 inline POLESTR SST2OLE(PTSTR p) { return p; }
1036 inline PTSTR SSOLE2T(POLESTR p) { return p; }
1037 #elif defined(OLE2ANSI)
1038 // in these cases the default (TCHAR) is the same as OLECHAR
1039 inline PCOLESTR SST2COLE(PCTSTR p) { return p; }
1040 inline PCTSTR SSOLE2CT(PCOLESTR p) { return p; }
1041 inline POLESTR SST2OLE(PTSTR p) { return p; }
1042 inline PTSTR SSOLE2T(POLESTR p) { return p; }
1044 //CharNextW doesn't work on Win95 so we use this
1045 #define SST2COLE(pa) SSA2CW((pa))
1046 #define SST2OLE(pa) SSA2W((pa))
1047 #define SSOLE2CT(po) SSW2CA((po))
1048 #define SSOLE2T(po) SSW2A((po))
1052 #define SSW2OLE SSW2A
1053 #define SSOLE2W SSA2W
1054 #define SSW2COLE SSW2CA
1055 #define SSOLE2CW SSA2CW
1056 inline POLESTR SSA2OLE(PSTR p) { return p; }
1057 inline PSTR SSOLE2A(POLESTR p) { return p; }
1058 inline PCOLESTR SSA2COLE(PCSTR p) { return p; }
1059 inline PCSTR SSOLE2CA(PCOLESTR p){ return p; }
1061 #define SSA2OLE SSA2W
1062 #define SSOLE2A SSW2A
1063 #define SSA2COLE SSA2CW
1064 #define SSOLE2CA SSW2CA
1065 inline POLESTR SSW2OLE(PWSTR p) { return p; }
1066 inline PWSTR SSOLE2W(POLESTR p) { return p; }
1067 inline PCOLESTR SSW2COLE(PCWSTR p) { return p; }
1068 inline PCWSTR SSOLE2CW(PCOLESTR p){ return p; }
1071 // Above we've defined macros that look like MS' but all have
1072 // an 'SS' prefix. Now we need the real macros. We'll either
1073 // get them from the macros above or from MFC/ATL.
1075 #if defined (USES_CONVERSION)
1077 #define _NO_STDCONVERSION // just to be consistent
1083 #include <afxconv.h>
1084 #define _NO_STDCONVERSION // just to be consistent
1088 #define USES_CONVERSION SSCVT
1099 #define ocslen sslen
1100 #define ocscpy sscpy
1101 #define T2COLE SST2COLE
1102 #define OLE2CT SSOLE2CT
1103 #define T2OLE SST2COLE
1104 #define OLE2T SSOLE2CT
1105 #define A2OLE SSA2OLE
1106 #define OLE2A SSOLE2A
1107 #define W2OLE SSW2OLE
1108 #define OLE2W SSOLE2W
1109 #define A2COLE SSA2COLE
1110 #define OLE2CA SSOLE2CA
1111 #define W2COLE SSW2COLE
1112 #define OLE2CW SSOLE2CW
1114 #endif // #ifdef _MFC_VER
1115 #endif // #ifndef USES_CONVERSION
1116 #endif // #ifndef SS_NO_CONVERSION
1118 // Define ostring - generic name for std::basic_string<OLECHAR>
1120 #if !defined(ostring) && !defined(OSTRING_DEFINED)
1121 typedef std::basic_string<OLECHAR> ostring;
1122 #define OSTRING_DEFINED
1125 // StdCodeCvt when there's no conversion to be done
1126 template <typename T>
1127 inline T* StdCodeCvt(T* pDst, int nDst, const T* pSrc, int nSrc)
1129 int nChars = SSMIN(nSrc, nDst);
1134 std::basic_string<T>::traits_type::copy(pDst, pSrc, nChars);
1135 // std::char_traits<T>::copy(pDst, pSrc, nChars);
1136 pDst[nChars] = '\0';
1141 inline PSTR StdCodeCvt(PSTR pDst, int nDst, PCUSTR pSrc, int nSrc)
1143 return StdCodeCvt(pDst, nDst, (PCSTR)pSrc, nSrc);
1145 inline PUSTR StdCodeCvt(PUSTR pDst, int nDst, PCSTR pSrc, int nSrc)
1147 return (PUSTR)StdCodeCvt((PSTR)pDst, nDst, pSrc, nSrc);
1150 // Define tstring -- generic name for std::basic_string<TCHAR>
1152 #if !defined(tstring) && !defined(TSTRING_DEFINED)
1153 typedef std::basic_string<TCHAR> tstring;
1154 #define TSTRING_DEFINED
1157 // a very shorthand way of applying the fix for KB problem Q172398
1158 // (basic_string assignment bug)
1160 #if defined ( _MSC_VER ) && ( _MSC_VER < 1200 )
1161 #define Q172398(x) (x).erase()
1166 // =============================================================================
1167 // INLINE FUNCTIONS ON WHICH CSTDSTRING RELIES
1169 // Usually for generic text mapping, we rely on preprocessor macro definitions
1170 // to map to string functions. However the CStdStr<> template cannot use
1171 // macro-based generic text mappings because its character types do not get
1172 // resolved until template processing which comes AFTER macro processing. In
1173 // other words, the preprocessor macro UNICODE is of little help to us in the
1176 // Therefore, to keep the CStdStr declaration simple, we have these inline
1177 // functions. The template calls them often. Since they are inline (and NOT
1178 // exported when this is built as a DLL), they will probably be resolved away
1181 // Without these functions, the CStdStr<> template would probably have to broken
1182 // out into two, almost identical classes. Either that or it would be a huge,
1183 // convoluted mess, with tons of "if" statements all over the place checking the
1184 // size of template parameter CT.
1185 // =============================================================================
1189 // --------------------------------------------------------------------------
1190 // Win32 GetStringTypeEx wrappers
1191 // --------------------------------------------------------------------------
1192 inline bool wsGetStringType(LCID lc, DWORD dwT, PCSTR pS, int nSize,
1195 return FALSE != GetStringTypeExA(lc, dwT, pS, nSize, pWd);
1197 inline bool wsGetStringType(LCID lc, DWORD dwT, PCWSTR pS, int nSize,
1200 return FALSE != GetStringTypeExW(lc, dwT, pS, nSize, pWd);
1204 template<typename CT>
1205 inline bool ssisspace (CT t)
1208 return wsGetStringType(GetThreadLocale(), CT_CTYPE1, &t, 1, &toYourMother)
1209 && 0 != (C1_BLANK & toYourMother);
1214 // If they defined SS_NO_REFCOUNT, then we must convert all assignments
1216 #if defined (_MSC_VER) && (_MSC_VER < 1300)
1217 #ifdef SS_NO_REFCOUNT
1218 #define SSREF(x) (x).c_str()
1220 #define SSREF(x) (x)
1223 #define SSREF(x) (x)
1226 // -----------------------------------------------------------------------------
1227 // sslen: strlen/wcslen wrappers
1228 // -----------------------------------------------------------------------------
1229 template<typename CT> inline int sslen(const CT* pT)
1231 return 0 == pT ? 0 : (int)std::basic_string<CT>::traits_type::length(pT);
1232 // return 0 == pT ? 0 : std::char_traits<CT>::length(pT);
1234 inline SS_NOTHROW int sslen(const std::string& s)
1236 return static_cast<int>(s.length());
1238 inline SS_NOTHROW int sslen(const std::wstring& s)
1240 return static_cast<int>(s.length());
1243 // -----------------------------------------------------------------------------
1244 // sstolower/sstoupper -- convert characters to upper/lower case
1245 // -----------------------------------------------------------------------------
1248 inline char sstoupper(char ch) { return (char)::toupper(ch); }
1249 inline wchar_t sstoupper(wchar_t ch){ return (wchar_t)::towupper(ch); }
1250 inline char sstolower(char ch) { return (char)::tolower(ch); }
1251 inline wchar_t sstolower(wchar_t ch){ return (wchar_t)::tolower(ch); }
1253 template<typename CT>
1254 inline CT sstolower(const CT& t, const std::locale& loc = std::locale())
1256 return std::tolower<CT>(t, loc);
1258 template<typename CT>
1259 inline CT sstoupper(const CT& t, const std::locale& loc = std::locale())
1261 return std::toupper<CT>(t, loc);
1265 // -----------------------------------------------------------------------------
1266 // ssasn: assignment functions -- assign "sSrc" to "sDst"
1267 // -----------------------------------------------------------------------------
1268 typedef std::string::size_type SS_SIZETYPE; // just for shorthand, really
1269 typedef std::string::pointer SS_PTRTYPE;
1270 typedef std::wstring::size_type SW_SIZETYPE;
1271 typedef std::wstring::pointer SW_PTRTYPE;
1274 template <typename T>
1275 inline void ssasn(std::basic_string<T>& sDst, const std::basic_string<T>& sSrc)
1277 if ( sDst.c_str() != sSrc.c_str() )
1280 sDst.assign(SSREF(sSrc));
1283 template <typename T>
1284 inline void ssasn(std::basic_string<T>& sDst, const T *pA)
1286 // Watch out for NULLs, as always.
1293 // If pA actually points to part of sDst, we must NOT erase(), but
1294 // rather take a substring
1296 else if ( pA >= sDst.c_str() && pA <= sDst.c_str() + sDst.size() )
1298 sDst =sDst.substr(static_cast<typename std::basic_string<T>::size_type>(pA-sDst.c_str()));
1301 // Otherwise (most cases) apply the assignment bug fix, if applicable
1302 // and do the assignment
1310 inline void ssasn(std::string& sDst, const std::wstring& sSrc)
1318 int nDst = static_cast<int>(sSrc.size());
1320 // In MBCS builds, pad the buffer to account for the possibility of
1321 // some 3 byte characters. Not perfect but should get most cases.
1324 // In MBCS builds, we don't know how long the destination string will be.
1325 nDst = static_cast<int>(static_cast<double>(nDst) * 1.3);
1326 sDst.resize(nDst+1);
1327 PCSTR szCvt = StdCodeCvt(const_cast<SS_PTRTYPE>(sDst.data()), nDst,
1328 sSrc.c_str(), static_cast<int>(sSrc.size()));
1329 sDst.resize(sslen(szCvt));
1331 sDst.resize(nDst+1);
1332 StdCodeCvt(const_cast<SS_PTRTYPE>(sDst.data()), nDst,
1333 sSrc.c_str(), static_cast<int>(sSrc.size()));
1334 sDst.resize(sSrc.size());
1338 inline void ssasn(std::string& sDst, PCWSTR pW)
1340 int nSrc = sslen(pW);
1343 int nSrc = sslen(pW);
1346 // In MBCS builds, pad the buffer to account for the possibility of
1347 // some 3 byte characters. Not perfect but should get most cases.
1350 nDst = static_cast<int>(static_cast<double>(nDst) * 1.3);
1351 // In MBCS builds, we don't know how long the destination string will be.
1352 sDst.resize(nDst + 1);
1353 PCSTR szCvt = StdCodeCvt(const_cast<SS_PTRTYPE>(sDst.data()), nDst,
1355 sDst.resize(sslen(szCvt));
1357 sDst.resize(nDst + 1);
1358 StdCodeCvt(const_cast<SS_PTRTYPE>(sDst.data()), nDst, pW, nSrc);
1367 inline void ssasn(std::string& sDst, const int nNull)
1374 inline void ssasn(std::wstring& sDst, const std::string& sSrc)
1382 int nSrc = static_cast<int>(sSrc.size());
1385 sDst.resize(nSrc+1);
1386 PCWSTR szCvt = StdCodeCvt(const_cast<SW_PTRTYPE>(sDst.data()), nDst,
1387 sSrc.c_str(), nSrc);
1389 sDst.resize(sslen(szCvt));
1392 inline void ssasn(std::wstring& sDst, PCSTR pA)
1394 int nSrc = sslen(pA);
1403 sDst.resize(nDst+1);
1404 PCWSTR szCvt = StdCodeCvt(const_cast<SW_PTRTYPE>(sDst.data()), nDst, pA,
1407 sDst.resize(sslen(szCvt));
1410 inline void ssasn(std::wstring& sDst, const int nNull)
1417 // -----------------------------------------------------------------------------
1418 // ssadd: string object concatenation -- add second argument to first
1419 // -----------------------------------------------------------------------------
1420 inline void ssadd(std::string& sDst, const std::wstring& sSrc)
1422 int nSrc = static_cast<int>(sSrc.size());
1426 int nDst = static_cast<int>(sDst.size());
1429 // In MBCS builds, pad the buffer to account for the possibility of
1430 // some 3 byte characters. Not perfect but should get most cases.
1433 nAdd = static_cast<int>(static_cast<double>(nAdd) * 1.3);
1434 sDst.resize(nDst+nAdd+1);
1435 PCSTR szCvt = StdCodeCvt(const_cast<SS_PTRTYPE>(sDst.data()+nDst),
1436 nAdd, sSrc.c_str(), nSrc);
1437 sDst.resize(nDst + sslen(szCvt));
1439 sDst.resize(nDst+nAdd+1);
1440 StdCodeCvt(const_cast<SS_PTRTYPE>(sDst.data()+nDst), nAdd, sSrc.c_str(), nSrc);
1441 sDst.resize(nDst + nAdd);
1445 template <typename T>
1446 inline void ssadd(typename std::basic_string<T>& sDst, const typename std::basic_string<T>& sSrc)
1450 inline void ssadd(std::string& sDst, PCWSTR pW)
1452 int nSrc = sslen(pW);
1455 int nDst = static_cast<int>(sDst.size());
1459 nAdd = static_cast<int>(static_cast<double>(nAdd) * 1.3);
1460 sDst.resize(nDst + nAdd + 1);
1461 PCSTR szCvt = StdCodeCvt(const_cast<SS_PTRTYPE>(sDst.data()+nDst),
1463 sDst.resize(nDst + sslen(szCvt));
1465 sDst.resize(nDst + nAdd + 1);
1466 StdCodeCvt(const_cast<SS_PTRTYPE>(sDst.data()+nDst), nAdd, pW, nSrc);
1467 sDst.resize(nDst + nSrc);
1471 template <typename T>
1472 inline void ssadd(typename std::basic_string<T>& sDst, const T *pA)
1476 // If the string being added is our internal string or a part of our
1477 // internal string, then we must NOT do any reallocation without
1478 // first copying that string to another object (since we're using a
1481 if ( pA >= sDst.c_str() && pA <= sDst.c_str()+sDst.length())
1483 if ( sDst.capacity() <= sDst.size()+sslen(pA) )
1484 sDst.append(std::basic_string<T>(pA));
1494 inline void ssadd(std::wstring& sDst, const std::string& sSrc)
1496 if ( !sSrc.empty() )
1498 int nSrc = static_cast<int>(sSrc.size());
1499 int nDst = static_cast<int>(sDst.size());
1501 sDst.resize(nDst + nSrc + 1);
1503 PCWSTR szCvt = StdCodeCvt(const_cast<SW_PTRTYPE>(sDst.data()+nDst),
1504 nSrc, sSrc.c_str(), nSrc+1);
1505 sDst.resize(nDst + sslen(szCvt));
1507 StdCodeCvt(const_cast<SW_PTRTYPE>(sDst.data()+nDst), nSrc, sSrc.c_str(), nSrc+1);
1508 sDst.resize(nDst + nSrc);
1512 inline void ssadd(std::wstring& sDst, PCSTR pA)
1514 int nSrc = sslen(pA);
1518 int nDst = static_cast<int>(sDst.size());
1520 sDst.resize(nDst + nSrc + 1);
1522 PCWSTR szCvt = StdCodeCvt(const_cast<SW_PTRTYPE>(sDst.data()+nDst),
1524 sDst.resize(nDst + sslen(szCvt));
1526 StdCodeCvt(const_cast<SW_PTRTYPE>(sDst.data()+nDst), nSrc, pA, nSrc+1);
1527 sDst.resize(nDst + nSrc);
1532 // -----------------------------------------------------------------------------
1533 // sscmp: comparison (case sensitive, not affected by locale)
1534 // -----------------------------------------------------------------------------
1535 template<typename CT>
1536 inline int sscmp(const CT* pA1, const CT* pA2)
1545 } while ( (f) && (f == l) );
1547 return (int)(f - l);
1550 // -----------------------------------------------------------------------------
1551 // ssicmp: comparison (case INsensitive, not affected by locale)
1552 // -----------------------------------------------------------------------------
1553 template<typename CT>
1554 inline int ssicmp(const CT* pA1, const CT* pA2)
1556 // Using the "C" locale = "not affected by locale"
1558 std::locale loc = std::locale::classic();
1559 const std::ctype<CT>& ct = SS_USE_FACET(loc, std::ctype<CT>);
1565 f = ct.tolower(*(pA1++));
1566 l = ct.tolower(*(pA2++));
1567 } while ( (f) && (f == l) );
1569 return (int)(f - l);
1572 // -----------------------------------------------------------------------------
1573 // ssupr/sslwr: Uppercase/Lowercase conversion functions
1574 // -----------------------------------------------------------------------------
1576 template<typename CT>
1577 inline void sslwr(CT* pT, size_t nLen, const std::locale& loc=std::locale())
1579 SS_USE_FACET(loc, std::ctype<CT>).tolower(pT, pT+nLen);
1581 template<typename CT>
1582 inline void ssupr(CT* pT, size_t nLen, const std::locale& loc=std::locale())
1584 SS_USE_FACET(loc, std::ctype<CT>).toupper(pT, pT+nLen);
1587 // -----------------------------------------------------------------------------
1588 // vsprintf/vswprintf or _vsnprintf/_vsnwprintf equivalents. In standard
1589 // builds we can't use _vsnprintf/_vsnwsprintf because they're MS extensions.
1591 // -----------------------------------------------------------------------------
1592 // Borland's headers put some ANSI "C" functions in the 'std' namespace.
1593 // Promote them to the global namespace so we can use them here.
1595 #if defined(__BORLANDC__)
1596 using std::vsprintf;
1597 using std::vswprintf;
1600 // GNU is supposed to have vsnprintf and vsnwprintf. But only the newer
1601 // distributions do.
1603 #if defined(__GNUC__)
1605 inline int ssvsprintf(PSTR pA, size_t nCount, PCSTR pFmtA, va_list vl)
1607 return vsnprintf(pA, nCount, pFmtA, vl);
1609 inline int ssvsprintf(PWSTR pW, size_t nCount, PCWSTR pFmtW, va_list vl)
1611 return vswprintf(pW, nCount, pFmtW, vl);
1614 // Microsofties can use
1615 #elif defined(_MSC_VER) && !defined(SS_ANSI)
1617 inline int ssvsprintf(PSTR pA, size_t nCount, PCSTR pFmtA, va_list vl)
1619 return _vsnprintf(pA, nCount, pFmtA, vl);
1621 inline int ssvsprintf(PWSTR pW, size_t nCount, PCWSTR pFmtW, va_list vl)
1623 return _vsnwprintf(pW, nCount, pFmtW, vl);
1626 #elif defined (SS_DANGEROUS_FORMAT) // ignore buffer size parameter if needed?
1628 inline int ssvsprintf(PSTR pA, size_t /*nCount*/, PCSTR pFmtA, va_list vl)
1630 return vsprintf(pA, pFmtA, vl);
1633 inline int ssvsprintf(PWSTR pW, size_t nCount, PCWSTR pFmtW, va_list vl)
1635 // JMO: Some distributions of the "C" have a version of vswprintf that
1636 // takes 3 arguments (e.g. Microsoft, Borland, GNU). Others have a
1637 // version which takes 4 arguments (an extra "count" argument in the
1638 // second position. The best stab I can take at this so far is that if
1639 // you are NOT running with MS, Borland, or GNU, then I'll assume you
1640 // have the version that takes 4 arguments.
1642 // I'm sure that these checks don't catch every platform correctly so if
1643 // you get compiler errors on one of the lines immediately below, it's
1644 // probably because your implemntation takes a different number of
1645 // arguments. You can comment out the offending line (and use the
1646 // alternate version) or you can figure out what compiler flag to check
1647 // and add that preprocessor check in. Regardless, if you get an error
1648 // on these lines, I'd sure like to hear from you about it.
1650 // Thanks to Ronny Schulz for the SGI-specific checks here.
1652 // #if !defined(__MWERKS__) && !defined(__SUNPRO_CC_COMPAT) && !defined(__SUNPRO_CC)
1653 #if !defined(_MSC_VER) \
1654 && !defined (__BORLANDC__) \
1655 && !defined(__GNUC__) \
1658 return vswprintf(pW, nCount, pFmtW, vl);
1660 // suddenly with the current SGI 7.3 compiler there is no such function as
1661 // vswprintf and the substitute needs explicit casts to compile
1663 #elif defined(__sgi)
1666 return vsprintf( (char *)pW, (char *)pFmtW, vl);
1671 return vswprintf(pW, pFmtW, vl);
1679 // GOT COMPILER PROBLEMS HERE?
1680 // ---------------------------
1681 // Does your compiler choke on one or more of the following 2 functions? It
1682 // probably means that you don't have have either vsnprintf or vsnwprintf in
1683 // your version of the CRT. This is understandable since neither is an ANSI
1684 // "C" function. However it still leaves you in a dilemma. In order to make
1685 // this code build, you're going to have to to use some non-length-checked
1686 // formatting functions that every CRT has: vsprintf and vswprintf.
1688 // This is very dangerous. With the proper erroneous (or malicious) code, it
1689 // can lead to buffer overlows and crashing your PC. Use at your own risk
1690 // In order to use them, just #define SS_DANGEROUS_FORMAT at the top of
1693 // Even THEN you might not be all the way home due to some non-conforming
1694 // distributions. More on this in the comments below.
1696 inline int ssnprintf(PSTR pA, size_t nCount, PCSTR pFmtA, va_list vl)
1699 return _vsnprintf(pA, nCount, pFmtA, vl);
1701 return vsnprintf(pA, nCount, pFmtA, vl);
1704 inline int ssnprintf(PWSTR pW, size_t nCount, PCWSTR pFmtW, va_list vl)
1707 return _vsnwprintf(pW, nCount, pFmtW, vl);
1709 return vswprintf(pW, nCount, pFmtW, vl);
1716 // -----------------------------------------------------------------------------
1717 // ssload: Type safe, overloaded ::LoadString wrappers
1718 // There is no equivalent of these in non-Win32-specific builds. However, I'm
1719 // thinking that with the message facet, there might eventually be one
1720 // -----------------------------------------------------------------------------
1721 #if defined (SS_WIN32) && !defined(SS_ANSI)
1722 inline int ssload(HMODULE hInst, UINT uId, PSTR pBuf, int nMax)
1724 return ::LoadStringA(hInst, uId, pBuf, nMax);
1726 inline int ssload(HMODULE hInst, UINT uId, PWSTR pBuf, int nMax)
1728 return ::LoadStringW(hInst, uId, pBuf, nMax);
1730 #if defined ( _MSC_VER ) && ( _MSC_VER >= 1500 )
1731 inline int ssload(HMODULE hInst, UINT uId, uint16_t *pBuf, int nMax)
1735 inline int ssload(HMODULE hInst, UINT uId, uint32_t *pBuf, int nMax)
1743 // -----------------------------------------------------------------------------
1744 // sscoll/ssicoll: Collation wrappers
1745 // Note -- with MSVC I have reversed the arguments order here because the
1746 // functions appear to return the opposite of what they should
1747 // -----------------------------------------------------------------------------
1748 #ifndef SS_NO_LOCALE
1749 template <typename CT>
1750 inline int sscoll(const CT* sz1, int nLen1, const CT* sz2, int nLen2)
1752 const std::collate<CT>& coll =
1753 SS_USE_FACET(std::locale(), std::collate<CT>);
1755 return coll.compare(sz2, sz2+nLen2, sz1, sz1+nLen1);
1757 template <typename CT>
1758 inline int ssicoll(const CT* sz1, int nLen1, const CT* sz2, int nLen2)
1760 const std::locale loc;
1761 const std::collate<CT>& coll = SS_USE_FACET(loc, std::collate<CT>);
1763 // Some implementations seem to have trouble using the collate<>
1764 // facet typedefs so we'll just default to basic_string and hope
1765 // that's what the collate facet uses (which it generally should)
1767 // std::collate<CT>::string_type s1(sz1);
1768 // std::collate<CT>::string_type s2(sz2);
1769 const std::basic_string<CT> sEmpty;
1770 std::basic_string<CT> s1(sz1 ? sz1 : sEmpty.c_str());
1771 std::basic_string<CT> s2(sz2 ? sz2 : sEmpty.c_str());
1773 sslwr(const_cast<CT*>(s1.c_str()), nLen1, loc);
1774 sslwr(const_cast<CT*>(s2.c_str()), nLen2, loc);
1775 return coll.compare(s2.c_str(), s2.c_str()+nLen2,
1776 s1.c_str(), s1.c_str()+nLen1);
1781 // -----------------------------------------------------------------------------
1782 // ssfmtmsg: FormatMessage equivalents. Needed because I added a CString facade
1783 // Again -- no equivalent of these on non-Win32 builds but their might one day
1784 // be one if the message facet gets implemented
1785 // -----------------------------------------------------------------------------
1786 #if defined (SS_WIN32) && !defined(SS_ANSI)
1787 inline DWORD ssfmtmsg(DWORD dwFlags, LPCVOID pSrc, DWORD dwMsgId,
1788 DWORD dwLangId, PSTR pBuf, DWORD nSize,
1791 return FormatMessageA(dwFlags, pSrc, dwMsgId, dwLangId,
1792 pBuf, nSize,vlArgs);
1794 inline DWORD ssfmtmsg(DWORD dwFlags, LPCVOID pSrc, DWORD dwMsgId,
1795 DWORD dwLangId, PWSTR pBuf, DWORD nSize,
1798 return FormatMessageW(dwFlags, pSrc, dwMsgId, dwLangId,
1799 pBuf, nSize,vlArgs);
1806 // FUNCTION: sscpy. Copies up to 'nMax' characters from pSrc to pDst.
1807 // -----------------------------------------------------------------------------
1809 // inline int sscpy(PSTR pDst, PCSTR pSrc, int nMax=-1);
1810 // inline int sscpy(PUSTR pDst, PCSTR pSrc, int nMax=-1)
1811 // inline int sscpy(PSTR pDst, PCWSTR pSrc, int nMax=-1);
1812 // inline int sscpy(PWSTR pDst, PCWSTR pSrc, int nMax=-1);
1813 // inline int sscpy(PWSTR pDst, PCSTR pSrc, int nMax=-1);
1816 // This function is very much (but not exactly) like strcpy. These
1817 // overloads simplify copying one C-style string into another by allowing
1818 // the caller to specify two different types of strings if necessary.
1820 // The strings must NOT overlap
1822 // "Character" is expressed in terms of the destination string, not
1823 // the source. If no 'nMax' argument is supplied, then the number of
1824 // characters copied will be sslen(pSrc). A NULL terminator will
1825 // also be added so pDst must actually be big enough to hold nMax+1
1826 // characters. The return value is the number of characters copied,
1827 // not including the NULL terminator.
1830 // pSrc - the string to be copied FROM. May be a char based string, an
1831 // MBCS string (in Win32 builds) or a wide string (wchar_t).
1832 // pSrc - the string to be copied TO. Also may be either MBCS or wide
1833 // nMax - the maximum number of characters to be copied into szDest. Note
1834 // that this is expressed in whatever a "character" means to pDst.
1835 // If pDst is a wchar_t type string than this will be the maximum
1836 // number of wchar_ts that my be copied. The pDst string must be
1837 // large enough to hold least nMaxChars+1 characters.
1838 // If the caller supplies no argument for nMax this is a signal to
1839 // the routine to copy all the characters in pSrc, regardless of
1842 // RETURN VALUE: none
1843 // -----------------------------------------------------------------------------
1845 template<typename CT1, typename CT2>
1846 inline int sscpycvt(CT1* pDst, const CT2* pSrc, int nMax)
1848 // Note -- we assume pDst is big enough to hold pSrc. If not, we're in
1849 // big trouble. No bounds checking. Caveat emptor.
1851 int nSrc = sslen(pSrc);
1853 const CT1* szCvt = StdCodeCvt(pDst, nMax, pSrc, nSrc);
1855 // If we're copying the same size characters, then all the "code convert"
1856 // just did was basically memcpy so the #of characters copied is the same
1857 // as the number requested. I should probably specialize this function
1858 // template to achieve this purpose as it is silly to do a runtime check
1859 // of a fact known at compile time. I'll get around to it.
1861 return sslen(szCvt);
1864 template<typename T>
1865 inline int sscpycvt(T* pDst, const T* pSrc, int nMax)
1868 for (; nCount > 0 && *pSrc; ++pSrc, ++pDst, --nCount)
1869 std::basic_string<T>::traits_type::assign(*pDst, *pSrc);
1872 return nMax - nCount;
1875 inline int sscpycvt(PWSTR pDst, PCSTR pSrc, int nMax)
1877 // Note -- we assume pDst is big enough to hold pSrc. If not, we're in
1878 // big trouble. No bounds checking. Caveat emptor.
1880 const PWSTR szCvt = StdCodeCvt(pDst, nMax, pSrc, nMax);
1881 return sslen(szCvt);
1884 template<typename CT1, typename CT2>
1885 inline int sscpy(CT1* pDst, const CT2* pSrc, int nMax, int nLen)
1887 return sscpycvt(pDst, pSrc, SSMIN(nMax, nLen));
1889 template<typename CT1, typename CT2>
1890 inline int sscpy(CT1* pDst, const CT2* pSrc, int nMax)
1892 return sscpycvt(pDst, pSrc, SSMIN(nMax, sslen(pSrc)));
1894 template<typename CT1, typename CT2>
1895 inline int sscpy(CT1* pDst, const CT2* pSrc)
1897 return sscpycvt(pDst, pSrc, sslen(pSrc));
1899 template<typename CT1, typename CT2>
1900 inline int sscpy(CT1* pDst, const std::basic_string<CT2>& sSrc, int nMax)
1902 return sscpycvt(pDst, sSrc.c_str(), SSMIN(nMax, (int)sSrc.length()));
1904 template<typename CT1, typename CT2>
1905 inline int sscpy(CT1* pDst, const std::basic_string<CT2>& sSrc)
1907 return sscpycvt(pDst, sSrc.c_str(), (int)sSrc.length());
1910 #ifdef SS_INC_COMDEF
1911 template<typename CT1>
1912 inline int sscpy(CT1* pDst, const _bstr_t& bs, int nMax)
1914 return sscpycvt(pDst, static_cast<PCOLESTR>(bs),
1915 SSMIN(nMax, static_cast<int>(bs.length())));
1917 template<typename CT1>
1918 inline int sscpy(CT1* pDst, const _bstr_t& bs)
1920 return sscpy(pDst, bs, static_cast<int>(bs.length()));
1925 // -----------------------------------------------------------------------------
1926 // Functional objects for changing case. They also let you pass locales
1927 // -----------------------------------------------------------------------------
1930 template<typename CT>
1931 struct SSToUpper : public std::unary_function<CT, CT>
1933 inline CT operator()(const CT& t) const
1935 return sstoupper(t);
1938 template<typename CT>
1939 struct SSToLower : public std::unary_function<CT, CT>
1941 inline CT operator()(const CT& t) const
1943 return sstolower(t);
1947 template<typename CT>
1948 struct SSToUpper : public std::binary_function<CT, std::locale, CT>
1950 inline CT operator()(const CT& t, const std::locale& loc) const
1952 return sstoupper<CT>(t, loc);
1955 template<typename CT>
1956 struct SSToLower : public std::binary_function<CT, std::locale, CT>
1958 inline CT operator()(const CT& t, const std::locale& loc) const
1960 return sstolower<CT>(t, loc);
1965 // This struct is used for TrimRight() and TrimLeft() function implementations.
1966 //template<typename CT>
1967 //struct NotSpace : public std::unary_function<CT, bool>
1969 // const std::locale& loc;
1970 // inline NotSpace(const std::locale& locArg) : loc(locArg) {}
1971 // inline bool operator() (CT t) { return !std::isspace(t, loc); }
1973 template<typename CT>
1974 struct NotSpace : public std::unary_function<CT, bool>
1977 // Note -- using std::isspace in a COM DLL gives us access violations
1978 // because it causes the dynamic addition of a function to be called
1979 // when the library shuts down. Unfortunately the list is maintained
1980 // in DLL memory but the function is in static memory. So the COM DLL
1981 // goes away along with the function that was supposed to be called,
1982 // and then later when the DLL CRT shuts down it unloads the list and
1983 // tries to call the long-gone function.
1984 // This is DinkumWare's implementation problem. If you encounter this
1985 // problem, you may replace the calls here with good old isspace() and
1986 // iswspace() from the CRT unless they specify SS_ANSI
1990 bool operator() (CT t) const { return !ssisspace(t); }
1993 const std::locale loc;
1994 NotSpace(const std::locale& locArg=std::locale()) : loc(locArg) {}
1995 bool operator() (CT t) const { return !std::isspace(t, loc); }
2002 // Now we can define the template (finally!)
2003 // =============================================================================
2004 // TEMPLATE: CStdStr
2005 // template<typename CT> class CStdStr : public std::basic_string<CT>
2008 // This template derives from basic_string<CT> and adds some MFC CString-
2009 // like functionality
2011 // Basically, this is my attempt to make Standard C++ library strings as
2012 // easy to use as the MFC CString class.
2014 // Note that although this is a template, it makes the assumption that the
2015 // template argument (CT, the character type) is either char or wchar_t.
2016 // =============================================================================
2018 //#define CStdStr _SS // avoid compiler warning 4786
2020 // template<typename ARG> ARG& FmtArg(ARG& arg) { return arg; }
2021 // PCSTR FmtArg(const std::string& arg) { return arg.c_str(); }
2022 // PCWSTR FmtArg(const std::wstring& arg) { return arg.c_str(); }
2024 template<typename ARG>
2027 explicit FmtArg(const ARG& arg) : a_(arg) {}
2028 const ARG& operator()() const { return a_; }
2031 FmtArg& operator=(const FmtArg&) { return *this; }
2034 template<typename CT>
2035 class CStdStr : public std::basic_string<CT>
2037 // Typedefs for shorter names. Using these names also appears to help
2038 // us avoid some ambiguities that otherwise arise on some platforms
2040 #define MYBASE std::basic_string<CT> // my base class
2041 //typedef typename std::basic_string<CT> MYBASE; // my base class
2042 typedef CStdStr<CT> MYTYPE; // myself
2043 typedef typename MYBASE::const_pointer PCMYSTR; // PCSTR or PCWSTR
2044 typedef typename MYBASE::pointer PMYSTR; // PSTR or PWSTR
2045 typedef typename MYBASE::iterator MYITER; // my iterator type
2046 typedef typename MYBASE::const_iterator MYCITER; // you get the idea...
2047 typedef typename MYBASE::reverse_iterator MYRITER;
2048 typedef typename MYBASE::size_type MYSIZE;
2049 typedef typename MYBASE::value_type MYVAL;
2050 typedef typename MYBASE::allocator_type MYALLOC;
2053 // shorthand conversion from PCTSTR to string resource ID
2054 #define SSRES(pctstr) LOWORD(reinterpret_cast<unsigned long>(pctstr))
2056 bool TryLoad(const void* pT)
2058 bool bLoaded = false;
2060 #if defined(SS_WIN32) && !defined(SS_ANSI)
2061 if ( ( pT != NULL ) && SS_IS_INTRESOURCE(pT) )
2063 UINT nId = LOWORD(reinterpret_cast<unsigned long>(pT));
2064 if ( !LoadString(nId) )
2066 TRACE(_T("Can't load string %u\n"), SSRES(pT));
2076 // CStdStr inline constructors
2081 CStdStr(const MYTYPE& str) : MYBASE(SSREF(str))
2085 CStdStr(const std::string& str)
2087 ssasn(*this, SSREF(str));
2090 CStdStr(const std::wstring& str)
2092 ssasn(*this, SSREF(str));
2095 CStdStr(PCMYSTR pT, MYSIZE n) : MYBASE(pT, n)
2102 *this = reinterpret_cast<PCSTR>(pU);
2126 CStdStr(uint16_t* pW)
2136 CStdStr(uint32_t* pW)
2146 CStdStr(MYCITER first, MYCITER last)
2147 : MYBASE(first, last)
2151 CStdStr(MYSIZE nSize, MYVAL ch, const MYALLOC& al=MYALLOC())
2152 : MYBASE(nSize, ch, al)
2156 #ifdef SS_INC_COMDEF
2157 CStdStr(const _bstr_t& bstr)
2159 if ( bstr.length() > 0 )
2160 this->append(static_cast<PCMYSTR>(bstr), bstr.length());
2164 // CStdStr inline assignment operators -- the ssasn function now takes care
2165 // of fixing the MSVC assignment bug (see knowledge base article Q172398).
2166 MYTYPE& operator=(const MYTYPE& str)
2172 MYTYPE& operator=(const std::string& str)
2178 MYTYPE& operator=(const std::wstring& str)
2184 MYTYPE& operator=(PCSTR pA)
2190 MYTYPE& operator=(PCWSTR pW)
2197 MYTYPE& operator=(PCUSTR pU)
2199 ssasn(*this, reinterpret_cast<PCSTR>(pU));
2204 MYTYPE& operator=(uint16_t* pA)
2210 MYTYPE& operator=(uint32_t* pA)
2216 MYTYPE& operator=(CT t)
2223 #ifdef SS_INC_COMDEF
2224 MYTYPE& operator=(const _bstr_t& bstr)
2226 if ( bstr.length() > 0 )
2228 this->assign(static_cast<PCMYSTR>(bstr), bstr.length());
2240 // Overloads also needed to fix the MSVC assignment bug (KB: Q172398)
2241 // *** Thanks to Pete The Plumber for catching this one ***
2242 // They also are compiled if you have explicitly turned off refcounting
2243 #if ( defined(_MSC_VER) && ( _MSC_VER < 1200 ) ) || defined(SS_NO_REFCOUNT)
2245 MYTYPE& assign(const MYTYPE& str)
2248 sscpy(GetBuffer(str.size()+1), SSREF(str));
2249 this->ReleaseBuffer(str.size());
2253 MYTYPE& assign(const MYTYPE& str, MYSIZE nStart, MYSIZE nChars)
2255 // This overload of basic_string::assign is supposed to assign up to
2256 // <nChars> or the NULL terminator, whichever comes first. Since we
2257 // are about to call a less forgiving overload (in which <nChars>
2258 // must be a valid length), we must adjust the length here to a safe
2259 // value. Thanks to Ullrich Poll�hne for catching this bug
2261 nChars = SSMIN(nChars, str.length() - nStart);
2262 MYTYPE strTemp(str.c_str()+nStart, nChars);
2264 this->assign(strTemp);
2268 MYTYPE& assign(const MYBASE& str)
2274 MYTYPE& assign(const MYBASE& str, MYSIZE nStart, MYSIZE nChars)
2276 // This overload of basic_string::assign is supposed to assign up to
2277 // <nChars> or the NULL terminator, whichever comes first. Since we
2278 // are about to call a less forgiving overload (in which <nChars>
2279 // must be a valid length), we must adjust the length here to a safe
2280 // value. Thanks to Ullrich Poll�hne for catching this bug
2282 nChars = SSMIN(nChars, str.length() - nStart);
2284 // Watch out for assignment to self
2288 MYTYPE strTemp(str.c_str() + nStart, nChars);
2289 static_cast<MYBASE*>(this)->assign(strTemp);
2294 static_cast<MYBASE*>(this)->assign(str.c_str()+nStart, nChars);
2299 MYTYPE& assign(const CT* pC, MYSIZE nChars)
2301 // Q172398 only fix -- erase before assigning, but not if we're
2302 // assigning from our own buffer
2304 #if defined ( _MSC_VER ) && ( _MSC_VER < 1200 )
2305 if ( !this->empty() &&
2306 ( pC < this->data() || pC > this->data() + this->capacity() ) )
2312 static_cast<MYBASE*>(this)->assign(pC, nChars);
2316 MYTYPE& assign(MYSIZE nChars, MYVAL val)
2319 static_cast<MYBASE*>(this)->assign(nChars, val);
2323 MYTYPE& assign(const CT* pT)
2325 return this->assign(pT, MYBASE::traits_type::length(pT));
2328 MYTYPE& assign(MYCITER iterFirst, MYCITER iterLast)
2330 #if defined ( _MSC_VER ) && ( _MSC_VER < 1200 )
2331 // Q172398 fix. don't call erase() if we're assigning from ourself
2332 if ( iterFirst < this->begin() ||
2333 iterFirst > this->begin() + this->size() )
2338 this->replace(this->begin(), this->end(), iterFirst, iterLast);
2344 // -------------------------------------------------------------------------
2345 // CStdStr inline concatenation.
2346 // -------------------------------------------------------------------------
2347 MYTYPE& operator+=(const MYTYPE& str)
2353 MYTYPE& operator+=(const std::string& str)
2359 MYTYPE& operator+=(const std::wstring& str)
2365 MYTYPE& operator+=(PCSTR pA)
2371 MYTYPE& operator+=(PCWSTR pW)
2377 MYTYPE& operator+=(uint16_t* pW)
2383 MYTYPE& operator+=(uint32_t* pW)
2389 MYTYPE& operator+=(CT t)
2394 #ifdef SS_INC_COMDEF // if we have _bstr_t, define a += for it too.
2395 MYTYPE& operator+=(const _bstr_t& bstr)
2397 return this->operator+=(static_cast<PCMYSTR>(bstr));
2402 // -------------------------------------------------------------------------
2403 // Case changing functions
2404 // -------------------------------------------------------------------------
2406 MYTYPE& ToUpper(const std::locale& loc=std::locale())
2408 // Note -- if there are any MBCS character sets in which the lowercase
2409 // form a character takes up a different number of bytes than the
2410 // uppercase form, this would probably not work...
2412 std::transform(this->begin(),
2418 std::bind2nd(SSToUpper<CT>(), loc));
2421 // ...but if it were, this would probably work better. Also, this way
2422 // seems to be a bit faster when anything other then the "C" locale is
2427 // ssupr(this->GetBuf(), this->size(), loc);
2434 MYTYPE& ToLower(const std::locale& loc=std::locale())
2436 // Note -- if there are any MBCS character sets in which the lowercase
2437 // form a character takes up a different number of bytes than the
2438 // uppercase form, this would probably not work...
2440 std::transform(this->begin(),
2446 std::bind2nd(SSToLower<CT>(), loc));
2449 // ...but if it were, this would probably work better. Also, this way
2450 // seems to be a bit faster when anything other then the "C" locale is
2455 // sslwr(this->GetBuf(), this->size(), loc);
2464 return Trim().ToLower();
2468 // -------------------------------------------------------------------------
2469 // CStdStr -- Direct access to character buffer. In the MS' implementation,
2470 // the at() function that we use here also calls _Freeze() providing us some
2471 // protection from multithreading problems associated with ref-counting.
2472 // In VC 7 and later, of course, the ref-counting stuff is gone.
2473 // -------------------------------------------------------------------------
2475 CT* GetBuf(int nMinLen=-1)
2477 if ( static_cast<int>(this->size()) < nMinLen )
2478 this->resize(static_cast<MYSIZE>(nMinLen));
2480 return this->empty() ? const_cast<CT*>(this->data()) : &(this->at(0));
2483 CT* SetBuf(int nLen)
2485 nLen = ( nLen > 0 ? nLen : 0 );
2486 if ( this->capacity() < 1 && nLen == 0 )
2489 this->resize(static_cast<MYSIZE>(nLen));
2490 return const_cast<CT*>(this->data());
2492 void RelBuf(int nNewLen=-1)
2494 this->resize(static_cast<MYSIZE>(nNewLen > -1 ? nNewLen :
2495 sslen(this->c_str())));
2498 void BufferRel() { RelBuf(); } // backwards compatability
2499 CT* Buffer() { return GetBuf(); } // backwards compatability
2500 CT* BufferSet(int nLen) { return SetBuf(nLen);}// backwards compatability
2502 bool Equals(const CT* pT, bool bUseCase=false) const
2504 return 0 == (bUseCase ? this->compare(pT) : ssicmp(this->c_str(), pT));
2507 // -------------------------------------------------------------------------
2508 // FUNCTION: CStdStr::Load
2510 // Loads string from resource specified by nID
2513 // nID - resource Identifier. Purely a Win32 thing in this case
2516 // true if successful, false otherwise
2517 // -------------------------------------------------------------------------
2521 bool Load(UINT nId, HMODULE hModule=NULL)
2523 bool bLoaded = false; // set to true of we succeed.
2525 #ifdef _MFC_VER // When in Rome (or MFC land)...
2527 // If they gave a resource handle, use it. Note - this is archaic
2528 // and not really what I would recommend. But then again, in MFC
2529 // land, you ought to be using CString for resources anyway since
2530 // it walks the resource chain for you.
2532 HMODULE hModuleOld = NULL;
2534 if ( NULL != hModule )
2536 hModuleOld = AfxGetResourceHandle();
2537 AfxSetResourceHandle(hModule);
2540 // ...load the string
2543 bLoaded = FALSE != strRes.LoadString(nId);
2545 // ...and if we set the resource handle, restore it.
2547 if ( NULL != hModuleOld )
2548 AfxSetResourceHandle(hModule);
2553 #else // otherwise make our own hackneyed version of CString's Load
2555 // Get the resource name and module handle
2557 if ( NULL == hModule )
2558 hModule = GetResourceHandle();
2560 PCTSTR szName = MAKEINTRESOURCE((nId>>4)+1); // lifted
2563 // No sense continuing if we can't find the resource
2565 HRSRC hrsrc = ::FindResource(hModule, szName, RT_STRING);
2567 if ( NULL == hrsrc )
2569 TRACE(_T("Cannot find resource %d: 0x%X"), nId, ::GetLastError());
2571 else if ( 0 == (dwSize = ::SizeofResource(hModule, hrsrc) / sizeof(CT)))
2573 TRACE(_T("Cant get size of resource %d 0x%X\n"),nId,GetLastError());
2577 bLoaded = 0 != ssload(hModule, nId, GetBuf(dwSize), dwSize);
2581 #endif // #ifdef _MFC_VER
2584 TRACE(_T("String not loaded 0x%X\n"), ::GetLastError());
2589 #endif // #ifdef SS_ANSI
2591 void AppendFormat(const CT* szFmt, ...)
2594 va_start(argList, szFmt);
2595 AppendFormatV(szFmt, argList);
2599 #define MAX_FMT_TRIES 5 // #of times we try
2600 #define FMT_BLOCK_SIZE 2048 // # of bytes to increment per try
2601 #define BUFSIZE_1ST 256
2602 #define BUFSIZE_2ND 512
2603 #define STD_BUF_SIZE 1024
2605 // an efficient way to add formatted characters to the string. You may only
2606 // add up to STD_BUF_SIZE characters at a time, though
2607 void AppendFormatV(const CT* szFmt, va_list argList)
2609 CT szBuf[STD_BUF_SIZE];
2610 int nLen = ssnprintf(szBuf, STD_BUF_SIZE-1, szFmt, argList);
2613 this->append(szBuf, nLen);
2616 // -------------------------------------------------------------------------
2617 // FUNCTION: FormatV
2618 // void FormatV(PCSTR szFormat, va_list, argList);
2621 // This function formats the string with sprintf style format-specs.
2622 // It makes a general guess at required buffer size and then tries
2623 // successively larger buffers until it finds one big enough or a
2624 // threshold (MAX_FMT_TRIES) is exceeded.
2627 // szFormat - a PCSTR holding the format of the output
2628 // argList - a Microsoft specific va_list for variable argument lists
2631 // -------------------------------------------------------------------------
2633 // NOTE: Changed by JM to actually function under non-win32,
2634 // and to remove the upper limit on size.
2635 void FormatV(const CT* szFormat, va_list argList)
2637 // try and grab a sufficient buffersize
2638 int nChars = FMT_BLOCK_SIZE;
2641 CT *p = reinterpret_cast<CT*>(malloc(sizeof(CT)*nChars));
2646 va_copy(argCopy, argList);
2648 int nActual = ssvsprintf(p, nChars, szFormat, argCopy);
2649 /* If that worked, return the string. */
2650 if (nActual > -1 && nActual < nChars)
2651 { /* make sure it's NULL terminated */
2653 this->assign(p, nActual);
2658 /* Else try again with more space. */
2659 if (nActual > -1) /* glibc 2.1 */
2660 nChars = nActual + 1; /* precisely what is needed */
2661 else /* glibc 2.0 */
2662 nChars *= 2; /* twice the old size */
2664 CT *np = reinterpret_cast<CT*>(realloc(p, sizeof(CT)*nChars));
2669 return; // failed :(
2676 // -------------------------------------------------------------------------
2677 // CString Facade Functions:
2679 // The following methods are intended to allow you to use this class as a
2680 // near drop-in replacement for CString.
2681 // -------------------------------------------------------------------------
2683 BSTR AllocSysString() const
2687 return ::SysAllocString(os.c_str());
2691 #ifndef SS_NO_LOCALE
2692 int Collate(PCMYSTR szThat) const
2694 return sscoll(this->c_str(), this->length(), szThat, sslen(szThat));
2697 int CollateNoCase(PCMYSTR szThat) const
2699 return ssicoll(this->c_str(), this->length(), szThat, sslen(szThat));
2702 int Compare(PCMYSTR szThat) const
2704 return this->compare(szThat);
2707 int CompareNoCase(PCMYSTR szThat) const
2709 return ssicmp(this->c_str(), szThat);
2712 int Delete(int nIdx, int nCount=1)
2717 if ( nIdx < this->GetLength() )
2718 this->erase(static_cast<MYSIZE>(nIdx), static_cast<MYSIZE>(nCount));
2728 int Find(CT ch) const
2730 MYSIZE nIdx = this->find_first_of(ch);
2731 return static_cast<int>(MYBASE::npos == nIdx ? -1 : nIdx);
2734 int Find(PCMYSTR szSub) const
2736 MYSIZE nIdx = this->find(szSub);
2737 return static_cast<int>(MYBASE::npos == nIdx ? -1 : nIdx);
2740 int Find(CT ch, int nStart) const
2742 // CString::Find docs say add 1 to nStart when it's not zero
2743 // CString::Find code doesn't do that however. We'll stick
2744 // with what the code does
2746 MYSIZE nIdx = this->find_first_of(ch, static_cast<MYSIZE>(nStart));
2747 return static_cast<int>(MYBASE::npos == nIdx ? -1 : nIdx);
2750 int Find(PCMYSTR szSub, int nStart) const
2752 // CString::Find docs say add 1 to nStart when it's not zero
2753 // CString::Find code doesn't do that however. We'll stick
2754 // with what the code does
2756 MYSIZE nIdx = this->find(szSub, static_cast<MYSIZE>(nStart));
2757 return static_cast<int>(MYBASE::npos == nIdx ? -1 : nIdx);
2760 int FindOneOf(PCMYSTR szCharSet) const
2762 MYSIZE nIdx = this->find_first_of(szCharSet);
2763 return static_cast<int>(MYBASE::npos == nIdx ? -1 : nIdx);
2767 void FormatMessage(PCMYSTR szFormat, ...) throw(std::exception)
2770 va_start(argList, szFormat);
2772 if ( ssfmtmsg(FORMAT_MESSAGE_FROM_STRING|FORMAT_MESSAGE_ALLOCATE_BUFFER,
2774 reinterpret_cast<PMYSTR>(&szTemp), 0, &argList) == 0 ||
2777 throw std::runtime_error("out of memory");
2784 void FormatMessage(UINT nFormatId, ...) throw(std::exception)
2787 VERIFY(sFormat.LoadString(nFormatId));
2789 va_start(argList, nFormatId);
2791 if ( ssfmtmsg(FORMAT_MESSAGE_FROM_STRING|FORMAT_MESSAGE_ALLOCATE_BUFFER,
2793 reinterpret_cast<PMYSTR>(&szTemp), 0, &argList) == 0 ||
2796 throw std::runtime_error("out of memory");
2804 // GetAllocLength -- an MSVC7 function but it costs us nothing to add it.
2806 int GetAllocLength()
2808 return static_cast<int>(this->capacity());
2811 // -------------------------------------------------------------------------
2812 // GetXXXX -- Direct access to character buffer
2813 // -------------------------------------------------------------------------
2814 CT GetAt(int nIdx) const
2816 return this->at(static_cast<MYSIZE>(nIdx));
2819 CT* GetBuffer(int nMinLen=-1)
2821 return GetBuf(nMinLen);
2824 CT* GetBufferSetLength(int nLen)
2826 return BufferSet(nLen);
2829 // GetLength() -- MFC docs say this is the # of BYTES but
2830 // in truth it is the number of CHARACTERs (chars or wchar_ts)
2831 int GetLength() const
2833 return static_cast<int>(this->length());
2836 int Insert(int nIdx, CT ch)
2838 if ( static_cast<MYSIZE>(nIdx) > this->size()-1 )
2839 this->append(1, ch);
2841 this->insert(static_cast<MYSIZE>(nIdx), 1, ch);
2845 int Insert(int nIdx, PCMYSTR sz)
2847 if ( static_cast<MYSIZE>(nIdx) >= this->size() )
2848 this->append(sz, static_cast<MYSIZE>(sslen(sz)));
2850 this->insert(static_cast<MYSIZE>(nIdx), sz);
2855 bool IsEmpty() const
2857 return this->empty();
2860 MYTYPE Left(int nCount) const
2862 // Range check the count.
2864 nCount = SSMIN(SSMAX(0, nCount), static_cast<int>(this->size()));
2865 return this->substr(0, static_cast<MYSIZE>(nCount));
2869 bool LoadString(UINT nId)
2871 return this->Load(nId);
2882 std::reverse(this->begin(), this->end());
2890 MYTYPE Mid(int nFirst) const
2892 return Mid(nFirst, this->GetLength()-nFirst);
2895 MYTYPE Mid(int nFirst, int nCount) const
2897 // CString does range checking here. Since we're trying to emulate it,
2898 // we must check too.
2905 int nSize = static_cast<int>(this->size());
2907 if ( nFirst + nCount > nSize )
2908 nCount = nSize - nFirst;
2910 if ( nFirst > nSize )
2913 ASSERT(nFirst >= 0);
2914 ASSERT(nFirst + nCount <= nSize);
2916 return this->substr(static_cast<MYSIZE>(nFirst),
2917 static_cast<MYSIZE>(nCount));
2920 void ReleaseBuffer(int nNewLen=-1)
2929 while ( (nIdx=this->find_first_of(ch)) != MYBASE::npos )
2931 this->erase(nIdx, 1);
2937 int Replace(CT chOld, CT chNew)
2941 for ( MYITER iter=this->begin(); iter != this->end(); iter++ )
2943 if ( *iter == chOld )
2953 int Replace(PCMYSTR szOld, PCMYSTR szNew)
2957 MYSIZE nOldLen = sslen(szOld);
2961 // If the replacement string is longer than the one it replaces, this
2962 // string is going to have to grow in size, Figure out how much
2963 // and grow it all the way now, rather than incrementally
2965 MYSIZE nNewLen = sslen(szNew);
2966 if ( nNewLen > nOldLen )
2969 while ( nIdx < this->length() &&
2970 (nIdx=this->find(szOld, nIdx)) != MYBASE::npos )
2975 this->reserve(this->size() + nFound * (nNewLen - nOldLen));
2979 static const CT ch = CT(0);
2980 PCMYSTR szRealNew = szNew == 0 ? &ch : szNew;
2983 while ( nIdx < this->length() &&
2984 (nIdx=this->find(szOld, nIdx)) != MYBASE::npos )
2986 this->replace(this->begin()+nIdx, this->begin()+nIdx+nOldLen,
2997 int ReverseFind(CT ch) const
2999 MYSIZE nIdx = this->find_last_of(ch);
3000 return static_cast<int>(MYBASE::npos == nIdx ? -1 : nIdx);
3003 // ReverseFind overload that's not in CString but might be useful
3004 int ReverseFind(PCMYSTR szFind, MYSIZE pos=MYBASE::npos) const
3006 //yuvalt - this does not compile with g++ since MYTTYPE() is different type
3007 //MYSIZE nIdx = this->rfind(0 == szFind ? MYTYPE() : szFind, pos);
3008 MYSIZE nIdx = this->rfind(0 == szFind ? "" : szFind, pos);
3009 return static_cast<int>(MYBASE::npos == nIdx ? -1 : nIdx);
3012 MYTYPE Right(int nCount) const
3014 // Range check the count.
3016 nCount = SSMAX(0, SSMIN(nCount, static_cast<int>(this->size())));
3017 return this->substr(this->size()-static_cast<MYSIZE>(nCount));
3020 void SetAt(int nIndex, CT ch)
3022 ASSERT(this->size() > static_cast<MYSIZE>(nIndex));
3023 this->at(static_cast<MYSIZE>(nIndex)) = ch;
3027 BSTR SetSysString(BSTR* pbstr) const
3031 if ( !::SysReAllocStringLen(pbstr, os.c_str(), os.length()) )
3032 throw std::runtime_error("out of memory");
3034 ASSERT(*pbstr != 0);
3039 MYTYPE SpanExcluding(PCMYSTR szCharSet) const
3041 MYSIZE pos = this->find_first_of(szCharSet);
3042 return pos == MYBASE::npos ? *this : Left(pos);
3045 MYTYPE SpanIncluding(PCMYSTR szCharSet) const
3047 MYSIZE pos = this->find_first_not_of(szCharSet);
3048 return pos == MYBASE::npos ? *this : Left(pos);
3051 #if defined SS_WIN32 && !defined(UNICODE) && !defined(SS_ANSI)
3053 // CString's OemToAnsi and AnsiToOem functions are available only in
3054 // Unicode builds. However since we're a template we also need a
3055 // runtime check of CT and a reinterpret_cast to account for the fact
3056 // that CStdStringW gets instantiated even in non-Unicode builds.
3060 if ( sizeof(CT) == sizeof(char) && !empty() )
3062 ::CharToOem(reinterpret_cast<PCSTR>(this->c_str()),
3063 reinterpret_cast<PSTR>(GetBuf()));
3073 if ( sizeof(CT) == sizeof(char) && !empty() )
3075 ::OemToChar(reinterpret_cast<PCSTR>(this->c_str()),
3076 reinterpret_cast<PSTR>(GetBuf()));
3087 // -------------------------------------------------------------------------
3088 // Trim and its variants
3089 // -------------------------------------------------------------------------
3092 return TrimLeft().TrimRight();
3097 this->erase(this->begin(),
3098 std::find_if(this->begin(), this->end(), NotSpace<CT>()));
3103 MYTYPE& TrimLeft(CT tTrim)
3105 this->erase(0, this->find_first_not_of(tTrim));
3109 MYTYPE& TrimLeft(PCMYSTR szTrimChars)
3111 this->erase(0, this->find_first_not_of(szTrimChars));
3117 // NOTE: When comparing reverse_iterators here (MYRITER), I avoid using
3118 // operator!=. This is because namespace rel_ops also has a template
3119 // operator!= which conflicts with the global operator!= already defined
3120 // for reverse_iterator in the header <utility>.
3121 // Thanks to John James for alerting me to this.
3123 MYRITER it = std::find_if(this->rbegin(), this->rend(), NotSpace<CT>());
3124 if ( !(this->rend() == it) )
3125 this->erase(this->rend() - it);
3127 this->erase(!(it == this->rend()) ? this->find_last_of(*it) + 1 : 0);
3131 MYTYPE& TrimRight(CT tTrim)
3133 MYSIZE nIdx = this->find_last_not_of(tTrim);
3134 this->erase(MYBASE::npos == nIdx ? 0 : ++nIdx);
3138 MYTYPE& TrimRight(PCMYSTR szTrimChars)
3140 MYSIZE nIdx = this->find_last_not_of(szTrimChars);
3141 this->erase(MYBASE::npos == nIdx ? 0 : ++nIdx);
3150 this->assign(mt.c_str(), mt.size());
3153 // I have intentionally not implemented the following CString
3154 // functions. You cannot make them work without taking advantage
3155 // of implementation specific behavior. However if you absolutely
3156 // MUST have them, uncomment out these lines for "sort-of-like"
3157 // their behavior. You're on your own.
3159 // CT* LockBuffer() { return GetBuf(); }// won't really lock
3160 // void UnlockBuffer(); { } // why have UnlockBuffer w/o LockBuffer?
3162 // Array-indexing operators. Required because we defined an implicit cast
3163 // to operator const CT* (Thanks to Julian Selman for pointing this out)
3165 CT& operator[](int nIdx)
3167 return static_cast<MYBASE*>(this)->operator[](static_cast<MYSIZE>(nIdx));
3170 const CT& operator[](int nIdx) const
3172 return static_cast<const MYBASE*>(this)->operator[](static_cast<MYSIZE>(nIdx));
3175 CT& operator[](unsigned int nIdx)
3177 return static_cast<MYBASE*>(this)->operator[](static_cast<MYSIZE>(nIdx));
3180 const CT& operator[](unsigned int nIdx) const
3182 return static_cast<const MYBASE*>(this)->operator[](static_cast<MYSIZE>(nIdx));
3185 CT& operator[](unsigned long nIdx)
3187 return static_cast<MYBASE*>(this)->operator[](static_cast<MYSIZE>(nIdx));
3190 const CT& operator[](unsigned long nIdx) const
3192 return static_cast<const MYBASE*>(this)->operator[](static_cast<MYSIZE>(nIdx));
3195 #ifndef SS_NO_IMPLICIT_CAST
3196 operator const CT*() const
3198 return this->c_str();
3202 // IStream related functions. Useful in IPersistStream implementations
3204 #ifdef SS_INC_COMDEF
3206 // struct SSSHDR - useful for non Std C++ persistence schemes.
3207 typedef struct SSSHDR
3211 } SSSHDR; // as in "Standard String Stream Header"
3213 #define SSSO_UNICODE 0x01 // the string is a wide string
3214 #define SSSO_COMPRESS 0x02 // the string is compressed
3216 // -------------------------------------------------------------------------
3217 // FUNCTION: StreamSize
3219 // Returns how many bytes it will take to StreamSave() this CStdString
3220 // object to an IStream.
3221 // -------------------------------------------------------------------------
3222 ULONG StreamSize() const
3224 // Control header plus string
3225 ASSERT(this->size()*sizeof(CT) < 0xffffffffUL - sizeof(SSSHDR));
3226 return (this->size() * sizeof(CT)) + sizeof(SSSHDR);
3229 // -------------------------------------------------------------------------
3230 // FUNCTION: StreamSave
3232 // Saves this CStdString object to a COM IStream.
3233 // -------------------------------------------------------------------------
3234 HRESULT StreamSave(IStream* pStream) const
3236 ASSERT(this->size()*sizeof(CT) < 0xffffffffUL - sizeof(SSSHDR));
3237 HRESULT hr = E_FAIL;
3238 ASSERT(pStream != 0);
3240 hdr.byCtrl = sizeof(CT) == 2 ? SSSO_UNICODE : 0;
3241 hdr.nChars = this->size();
3244 if ( FAILED(hr=pStream->Write(&hdr, sizeof(SSSHDR), 0)) )
3246 TRACE(_T("StreamSave: Cannot write control header, ERR=0x%X\n"),hr);
3250 ; // nothing to write
3252 else if ( FAILED(hr=pStream->Write(this->c_str(),
3253 this->size()*sizeof(CT), 0)) )
3255 TRACE(_T("StreamSave: Cannot write string to stream 0x%X\n"), hr);
3262 // -------------------------------------------------------------------------
3263 // FUNCTION: StreamLoad
3265 // This method loads the object from an IStream.
3266 // -------------------------------------------------------------------------
3267 HRESULT StreamLoad(IStream* pStream)
3269 ASSERT(pStream != 0);
3271 HRESULT hr = E_FAIL;
3273 if ( FAILED(hr=pStream->Read(&hdr, sizeof(SSSHDR), 0)) )
3275 TRACE(_T("StreamLoad: Cant read control header, ERR=0x%X\n"), hr);
3277 else if ( hdr.nChars > 0 )
3280 PMYSTR pMyBuf = BufferSet(hdr.nChars);
3282 // If our character size matches the character size of the string
3283 // we're trying to read, then we can read it directly into our
3284 // buffer. Otherwise, we have to read into an intermediate buffer
3287 if ( (hdr.byCtrl & SSSO_UNICODE) != 0 )
3289 ULONG nBytes = hdr.nChars * sizeof(wchar_t);
3290 if ( sizeof(CT) == sizeof(wchar_t) )
3292 if ( FAILED(hr=pStream->Read(pMyBuf, nBytes, &nRead)) )
3293 TRACE(_T("StreamLoad: Cannot read string: 0x%X\n"), hr);
3297 PWSTR pBufW = reinterpret_cast<PWSTR>(_alloca((nBytes)+1));
3298 if ( FAILED(hr=pStream->Read(pBufW, nBytes, &nRead)) )
3299 TRACE(_T("StreamLoad: Cannot read string: 0x%X\n"), hr);
3301 sscpy(pMyBuf, pBufW, hdr.nChars);
3306 ULONG nBytes = hdr.nChars * sizeof(char);
3307 if ( sizeof(CT) == sizeof(char) )
3309 if ( FAILED(hr=pStream->Read(pMyBuf, nBytes, &nRead)) )
3310 TRACE(_T("StreamLoad: Cannot read string: 0x%X\n"), hr);
3314 PSTR pBufA = reinterpret_cast<PSTR>(_alloca(nBytes));
3315 if ( FAILED(hr=pStream->Read(pBufA, hdr.nChars, &nRead)) )
3316 TRACE(_T("StreamLoad: Cannot read string: 0x%X\n"), hr);
3318 sscpy(pMyBuf, pBufA, hdr.nChars);
3328 #endif // #ifdef SS_INC_COMDEF
3332 // SetResourceHandle/GetResourceHandle. In MFC builds, these map directly
3333 // to AfxSetResourceHandle and AfxGetResourceHandle. In non-MFC builds they
3334 // point to a single static HINST so that those who call the member
3335 // functions that take resource IDs can provide an alternate HINST of a DLL
3336 // to search. This is not exactly the list of HMODULES that MFC provides
3337 // but it's better than nothing.
3340 static void SetResourceHandle(HMODULE hNew)
3342 AfxSetResourceHandle(hNew);
3344 static HMODULE GetResourceHandle()
3346 return AfxGetResourceHandle();
3349 static void SetResourceHandle(HMODULE hNew)
3351 SSResourceHandle() = hNew;
3353 static HMODULE GetResourceHandle()
3355 return SSResourceHandle();
3362 // -----------------------------------------------------------------------------
3363 // MSVC USERS: HOW TO EXPORT CSTDSTRING FROM A DLL
3365 // If you are using MS Visual C++ and you want to export CStdStringA and
3366 // CStdStringW from a DLL, then all you need to
3368 // 1. make sure that all components link to the same DLL version
3369 // of the CRT (not the static one).
3370 // 2. Uncomment the 3 lines of code below
3371 // 3. #define 2 macros per the instructions in MS KnowledgeBase
3372 // article Q168958. The macros are:
3374 // MACRO DEFINTION WHEN EXPORTING DEFINITION WHEN IMPORTING
3375 // ----- ------------------------ -------------------------
3376 // SSDLLEXP (nothing, just #define it) extern
3377 // SSDLLSPEC __declspec(dllexport) __declspec(dllimport)
3379 // Note that these macros must be available to ALL clients who want to
3380 // link to the DLL and use the class. If they
3382 // A word of advice: Don't bother.
3384 // Really, it is not necessary to export CStdString functions from a DLL. I
3385 // never do. In my projects, I do generally link to the DLL version of the
3386 // Standard C++ Library, but I do NOT attempt to export CStdString functions.
3387 // I simply include the header where it is needed and allow for the code
3390 // That redundancy is a lot less than you think. This class does most of its
3391 // work via the Standard C++ Library, particularly the base_class basic_string<>
3392 // member functions. Most of the functions here are small enough to be inlined
3393 // anyway. Besides, you'll find that in actual practice you use less than 1/2
3394 // of the code here, even in big projects and different modules will use as
3395 // little as 10% of it. That means a lot less functions actually get linked
3396 // your binaries. If you export this code from a DLL, it ALL gets linked in.
3398 // I've compared the size of the binaries from exporting vs NOT exporting. Take
3399 // my word for it -- exporting this code is not worth the hassle.
3401 // -----------------------------------------------------------------------------
3402 //#pragma warning(disable:4231) // non-standard extension ("extern template")
3403 // SSDLLEXP template class SSDLLSPEC CStdStr<char>;
3404 // SSDLLEXP template class SSDLLSPEC CStdStr<wchar_t>;
3407 // =============================================================================
3408 // END OF CStdStr INLINE FUNCTION DEFINITIONS
3409 // =============================================================================
3411 // Now typedef our class names based upon this humongous template
3413 typedef CStdStr<char> CStdStringA; // a better std::string
3414 typedef CStdStr<wchar_t> CStdStringW; // a better std::wstring
3415 typedef CStdStr<uint16_t> CStdString16; // a 16bit char string
3416 typedef CStdStr<uint32_t> CStdString32; // a 32bit char string
3417 typedef CStdStr<OLECHAR> CStdStringO; // almost always CStdStringW
3419 // -----------------------------------------------------------------------------
3420 // CStdStr addition functions defined as inline
3421 // -----------------------------------------------------------------------------
3424 inline CStdStringA operator+(const CStdStringA& s1, const CStdStringA& s2)
3426 CStdStringA sRet(SSREF(s1));
3430 inline CStdStringA operator+(const CStdStringA& s1, CStdStringA::value_type t)
3432 CStdStringA sRet(SSREF(s1));
3436 inline CStdStringA operator+(const CStdStringA& s1, PCSTR pA)
3438 CStdStringA sRet(SSREF(s1));
3442 inline CStdStringA operator+(PCSTR pA, const CStdStringA& sA)
3445 CStdStringA::size_type nObjSize = sA.size();
3446 CStdStringA::size_type nLitSize =
3447 static_cast<CStdStringA::size_type>(sslen(pA));
3449 sRet.reserve(nLitSize + nObjSize);
3456 inline CStdStringA operator+(const CStdStringA& s1, const CStdStringW& s2)
3458 return s1 + CStdStringA(s2);
3460 inline CStdStringW operator+(const CStdStringW& s1, const CStdStringW& s2)
3462 CStdStringW sRet(SSREF(s1));
3466 inline CStdStringA operator+(const CStdStringA& s1, PCWSTR pW)
3468 return s1 + CStdStringA(pW);
3472 inline CStdStringW operator+(PCWSTR pW, const CStdStringA& sA)
3474 return CStdStringW(pW) + CStdStringW(SSREF(sA));
3476 inline CStdStringW operator+(PCSTR pA, const CStdStringW& sW)
3478 return CStdStringW(pA) + sW;
3481 inline CStdStringA operator+(PCWSTR pW, const CStdStringA& sA)
3483 return CStdStringA(pW) + sA;
3485 inline CStdStringA operator+(PCSTR pA, const CStdStringW& sW)
3487 return pA + CStdStringA(sW);
3491 // ...Now the wide string versions.
3492 inline CStdStringW operator+(const CStdStringW& s1, CStdStringW::value_type t)
3494 CStdStringW sRet(SSREF(s1));
3498 inline CStdStringW operator+(const CStdStringW& s1, PCWSTR pW)
3500 CStdStringW sRet(SSREF(s1));
3504 inline CStdStringW operator+(PCWSTR pW, const CStdStringW& sW)
3507 CStdStringW::size_type nObjSize = sW.size();
3508 CStdStringA::size_type nLitSize =
3509 static_cast<CStdStringW::size_type>(sslen(pW));
3511 sRet.reserve(nLitSize + nObjSize);
3517 inline CStdStringW operator+(const CStdStringW& s1, const CStdStringA& s2)
3519 return s1 + CStdStringW(s2);
3521 inline CStdStringW operator+(const CStdStringW& s1, PCSTR pA)
3523 return s1 + CStdStringW(pA);
3527 // New-style format function is a template
3529 #ifdef SS_SAFE_FORMAT
3532 struct FmtArg<CStdStringA>
3534 explicit FmtArg(const CStdStringA& arg) : a_(arg) {}
3535 PCSTR operator()() const { return a_.c_str(); }
3536 const CStdStringA& a_;
3538 FmtArg<CStdStringA>& operator=(const FmtArg<CStdStringA>&) { return *this; }
3541 struct FmtArg<CStdStringW>
3543 explicit FmtArg(const CStdStringW& arg) : a_(arg) {}
3544 PCWSTR operator()() const { return a_.c_str(); }
3545 const CStdStringW& a_;
3547 FmtArg<CStdStringW>& operator=(const FmtArg<CStdStringW>&) { return *this; }
3551 struct FmtArg<std::string>
3553 explicit FmtArg(const std::string& arg) : a_(arg) {}
3554 PCSTR operator()() const { return a_.c_str(); }
3555 const std::string& a_;
3557 FmtArg<std::string>& operator=(const FmtArg<std::string>&) { return *this; }
3560 struct FmtArg<std::wstring>
3562 explicit FmtArg(const std::wstring& arg) : a_(arg) {}
3563 PCWSTR operator()() const { return a_.c_str(); }
3564 const std::wstring& a_;
3566 FmtArg<std::wstring>& operator=(const FmtArg<std::wstring>&) {return *this;}
3568 #endif // #ifdef SS_SAFEFORMAT
3571 // SSResourceHandle: our MFC-like resource handle
3572 inline HMODULE& SSResourceHandle()
3574 static HMODULE hModuleSS = GetModuleHandle(0);
3580 // In MFC builds, define some global serialization operators
3581 // Special operators that allow us to serialize CStdStrings to CArchives.
3582 // Note that we use an intermediate CString object in order to ensure that
3583 // we use the exact same format.
3586 inline CArchive& AFXAPI operator<<(CArchive& ar, const CStdStringA& strA)
3588 CString strTemp = strA;
3589 return ar << strTemp;
3591 inline CArchive& AFXAPI operator<<(CArchive& ar, const CStdStringW& strW)
3593 CString strTemp = strW;
3594 return ar << strTemp;
3597 inline CArchive& AFXAPI operator>>(CArchive& ar, CStdStringA& strA)
3604 inline CArchive& AFXAPI operator>>(CArchive& ar, CStdStringW& strW)
3611 #endif // #ifdef _MFC_VER -- (i.e. is this MFC?)
3615 // -----------------------------------------------------------------------------
3616 // GLOBAL FUNCTION: WUFormat
3617 // CStdStringA WUFormat(UINT nId, ...);
3618 // CStdStringA WUFormat(PCSTR szFormat, ...);
3621 // This function allows the caller for format and return a CStdStringA
3622 // object with a single line of code.
3623 // -----------------------------------------------------------------------------
3626 inline CStdStringA WUFormatA(UINT nId, ...)
3629 va_start(argList, nId);
3633 if ( strFmt.Load(nId) )
3634 strOut.FormatV(strFmt, argList);
3639 inline CStdStringA WUFormatA(PCSTR szFormat, ...)
3642 va_start(argList, szFormat);
3644 strOut.FormatV(szFormat, argList);
3648 inline CStdStringW WUFormatW(UINT nId, ...)
3651 va_start(argList, nId);
3655 if ( strFmt.Load(nId) )
3656 strOut.FormatV(strFmt, argList);
3661 inline CStdStringW WUFormatW(PCWSTR szwFormat, ...)
3664 va_start(argList, szwFormat);
3666 strOut.FormatV(szwFormat, argList);
3670 #endif // #ifdef SS_ANSI
3674 #if defined(SS_WIN32) && !defined (SS_ANSI)
3675 // -------------------------------------------------------------------------
3676 // FUNCTION: WUSysMessage
3677 // CStdStringA WUSysMessageA(DWORD dwError, DWORD dwLangId=SS_DEFLANGID);
3678 // CStdStringW WUSysMessageW(DWORD dwError, DWORD dwLangId=SS_DEFLANGID);
3681 // This function simplifies the process of obtaining a string equivalent
3682 // of a system error code returned from GetLastError(). You simply
3683 // supply the value returned by GetLastError() to this function and the
3684 // corresponding system string is returned in the form of a CStdStringA.
3687 // dwError - a DWORD value representing the error code to be translated
3688 // dwLangId - the language id to use. defaults to english.
3691 // a CStdStringA equivalent of the error code. Currently, this function
3692 // only returns either English of the system default language strings.
3693 // -------------------------------------------------------------------------
3694 #define SS_DEFLANGID MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT)
3695 inline CStdStringA WUSysMessageA(DWORD dwError, DWORD dwLangId=SS_DEFLANGID)
3699 if ( 0 != ::FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, NULL, dwError,
3700 dwLangId, szBuf, 511, NULL) )
3701 return WUFormatA("%s (0x%X)", szBuf, dwError);
3703 return WUFormatA("Unknown error (0x%X)", dwError);
3705 inline CStdStringW WUSysMessageW(DWORD dwError, DWORD dwLangId=SS_DEFLANGID)
3709 if ( 0 != ::FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM, NULL, dwError,
3710 dwLangId, szBuf, 511, NULL) )
3711 return WUFormatW(L"%s (0x%X)", szBuf, dwError);
3713 return WUFormatW(L"Unknown error (0x%X)", dwError);
3717 // Define TCHAR based friendly names for some of these functions
3720 //#define CStdString CStdStringW
3721 typedef CStdStringW CStdString;
3722 #define WUSysMessage WUSysMessageW
3723 #define WUFormat WUFormatW
3725 //#define CStdString CStdStringA
3726 typedef CStdStringA CStdString;
3727 #define WUSysMessage WUSysMessageA
3728 #define WUFormat WUFormatA
3731 // ...and some shorter names for the space-efficient
3733 #define WUSysMsg WUSysMessage
3734 #define WUSysMsgA WUSysMessageA
3735 #define WUSysMsgW WUSysMessageW
3736 #define WUFmtA WUFormatA
3737 #define WUFmtW WUFormatW
3738 #define WUFmt WUFormat
3739 #define WULastErrMsg() WUSysMessage(::GetLastError())
3740 #define WULastErrMsgA() WUSysMessageA(::GetLastError())
3741 #define WULastErrMsgW() WUSysMessageW(::GetLastError())
3744 // -----------------------------------------------------------------------------
3745 // FUNCTIONAL COMPARATORS:
3747 // These structs are derived from the std::binary_function template. They
3748 // give us functional classes (which may be used in Standard C++ Library
3749 // collections and algorithms) that perform case-insensitive comparisons of
3750 // CStdString objects. This is useful for maps in which the key may be the
3751 // proper string but in the wrong case.
3752 // -----------------------------------------------------------------------------
3753 #define StdStringLessNoCaseW SSLNCW // avoid VC compiler warning 4786
3754 #define StdStringEqualsNoCaseW SSENCW
3755 #define StdStringLessNoCaseA SSLNCA
3756 #define StdStringEqualsNoCaseA SSENCA
3759 #define StdStringLessNoCase SSLNCW
3760 #define StdStringEqualsNoCase SSENCW
3762 #define StdStringLessNoCase SSLNCA
3763 #define StdStringEqualsNoCase SSENCA
3766 struct StdStringLessNoCaseW
3767 : std::binary_function<CStdStringW, CStdStringW, bool>
3770 bool operator()(const CStdStringW& sLeft, const CStdStringW& sRight) const
3771 { return ssicmp(sLeft.c_str(), sRight.c_str()) < 0; }
3773 struct StdStringEqualsNoCaseW
3774 : std::binary_function<CStdStringW, CStdStringW, bool>
3777 bool operator()(const CStdStringW& sLeft, const CStdStringW& sRight) const
3778 { return ssicmp(sLeft.c_str(), sRight.c_str()) == 0; }
3780 struct StdStringLessNoCaseA
3781 : std::binary_function<CStdStringA, CStdStringA, bool>
3784 bool operator()(const CStdStringA& sLeft, const CStdStringA& sRight) const
3785 { return ssicmp(sLeft.c_str(), sRight.c_str()) < 0; }
3787 struct StdStringEqualsNoCaseA
3788 : std::binary_function<CStdStringA, CStdStringA, bool>
3791 bool operator()(const CStdStringA& sLeft, const CStdStringA& sRight) const
3792 { return ssicmp(sLeft.c_str(), sRight.c_str()) == 0; }
3795 // If we had to define our own version of TRACE above, get rid of it now
3797 #ifdef TRACE_DEFINED_HERE
3799 #undef TRACE_DEFINED_HERE
3803 // These std::swap specializations come courtesy of Mike Crusader.
3807 // inline void swap(CStdStringA& s1, CStdStringA& s2) throw()
3812 // inline void swap(CStdStringW& s1, CStdStringW& s2) throw()
3818 // Turn back on any Borland warnings we turned off.
3821 #pragma option pop // Turn back on inline function warnings
3822 // #pragma warn +inl // Turn back on inline function warnings
3825 typedef std::vector<CStdString> CStdStringArray;
3827 #endif // #ifndef STDSTRING_H