/[rdesktop]/sourceforge.net/trunk/seamlessrdp/ClientDLL/stdstring.h
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Annotation of /sourceforge.net/trunk/seamlessrdp/ClientDLL/stdstring.h

Parent Directory Parent Directory | Revision Log Revision Log


Revision 921 - (hide annotations)
Thu Jun 30 09:06:43 2005 UTC (19 years ago) by astrand
File MIME type: text/plain
File size: 88302 byte(s)
Renamed solution to seamlessrdp.sln. Converted filenames to lowercase.

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

  ViewVC Help
Powered by ViewVC 1.1.26