2nd attempt at updated Waves audio backend, with added -fms-extensions as previously...
[ardour.git] / libs / backends / wavesaudio / wavesapi / miscutils / WCFixedString.h
1 #ifndef __WCFixedString_h__
2         #define __WCFixedString_h__
3
4 /* Copy to include.
5 #include "WCFixedString.h"
6 */
7 // do not #include anything else here but standard C++ library files, this file should be free from any and all depandencies
8 // do not put any DEBUG_s or TRACE_s in this file, since it is used in BgkConsole functions
9
10 #include <algorithm>
11 #include <cctype>
12 #include <cstring>
13 #include <cstdio>
14
15 #ifdef __MACOS__
16 #include <strings.h>
17 #endif
18
19 #include "BasicTypes/WUDefines.h"
20 #include "BasicTypes/WTByteOrder.h"
21 #include "WavesPublicAPI/wstdint.h"
22 #include "MiscUtils/MinMaxUtilities.h"
23
24 // use this macro instead of std :: string to mark the that use of std :: string could not be replaced
25 // by WFixedString.
26 #define std_string_approved std::string
27
28 #ifdef __POSIX__
29 const char* const kStrNewLine = "\n";
30 #endif
31 #ifdef _WINDOWS
32 const char* const kStrNewLine = "\r\n";
33 #endif
34
35 class DllExport WCFixedStringBase
36 {
37 public:
38     typedef size_t pos_t;
39     typedef intptr_t spos_t; // signed position, defined to intptr_t because Windows does not have ssize_t
40         static const pos_t npos = UINTPTR_MAX; // Same as size_max
41
42         WCFixedStringBase(char* const in_begin, const size_t in_MaxFixedStringLength) : 
43                 m_begin(in_begin),
44                 m_MaxFixedStringLength(in_MaxFixedStringLength),
45                 m_end(in_begin)
46         {
47                 *m_end = '\0';
48         }
49
50         inline WCFixedStringBase& operator=(const WCFixedStringBase& in_fixedStrToAssign)
51         {
52                 if (this != &in_fixedStrToAssign)
53                 {
54                         clear();
55                         operator<<(in_fixedStrToAssign);
56                 }
57
58                 return *this;
59         }
60
61         inline WCFixedStringBase& operator=(const char* in_CStrToAssign)
62         {
63                 clear();
64                 operator<<(in_CStrToAssign);
65
66                 return *this;
67         }
68
69         inline WCFixedStringBase& operator=(const char in_charToAssign)
70         {
71                 clear();
72                 operator<<(in_charToAssign);
73
74                 return *this;
75         }
76
77         char operator[](const pos_t in_index) const
78         {
79                 if (in_index < m_MaxFixedStringLength)
80                         return m_begin[in_index];
81                 else
82                         return m_begin[m_MaxFixedStringLength]; // in_index was too big 
83         }
84
85         char& operator[](const pos_t in_index)
86         {
87                 if (in_index < m_MaxFixedStringLength)
88                         return m_begin[in_index];
89                 else
90                         return m_begin[m_MaxFixedStringLength]; // in_index was too big 
91         }
92
93         inline size_t resize(const size_t in_newSize)
94         {
95                 m_end = m_begin + WUMin<size_t>(in_newSize, m_MaxFixedStringLength);
96                 *m_end = '\0';
97                 return size();
98         }
99
100         size_t max_size()
101         {
102                 return m_MaxFixedStringLength;
103         }
104
105         size_t capacity()
106         {
107                 return m_MaxFixedStringLength;
108         }
109
110
111         inline char * peek()
112         {
113                 return m_begin;
114         }
115
116         inline const char * c_str() const
117         {
118                 *m_end = '\0';
119                 return m_begin;
120         }
121
122         inline void clear()
123         {
124                 m_end = m_begin;
125                 *m_end = '\0';
126         }
127
128         inline size_t size() const
129         {
130                 return m_end - m_begin;
131         }
132
133     inline char* begin() const
134     {
135         return m_begin;
136     }
137
138     inline char* end() const
139     {
140         return m_end;
141     }
142
143         inline size_t length() const
144         {
145                 return size();
146         }
147
148         inline bool empty() const
149         {
150                 return m_begin == m_end;
151         }
152
153         inline void reverse(char* in_left, char* in_right)
154         {
155                 char* left = in_left;
156                 char* right = in_right;
157                 while (left < right)
158                 {
159                         char temp = *--right;
160                         *right = *left;
161                         *left++ = temp;
162                 }
163         }
164
165         inline void reverse()
166         {
167                 reverse(m_begin, m_end);
168         }
169
170         inline void to_lower()
171         {
172                 char* pToDo = m_begin;
173
174                 while (pToDo < m_end)
175                 {
176                         *pToDo = static_cast<char>(std::tolower(*pToDo));
177                         ++pToDo;
178                 }
179         }
180
181         inline void to_upper()
182         {
183                 char* pToDo = m_begin;
184
185                 while (pToDo < m_end)
186                 {
187                         *pToDo = static_cast<char>(std::toupper(*pToDo));
188                         ++pToDo;
189                 }
190         }
191
192         // append a single char in_count times
193         inline void append(const char in_charToAppend, const size_t in_count)
194         {
195                 size_t counter = 0;
196                 while ((m_end < m_begin+m_MaxFixedStringLength) && counter++ < in_count)
197                         *m_end++ = in_charToAppend;
198 #if kEnableDebug == 1
199                 if (counter < in_count)    // if there wasn't enough room for some appended chars
200                 {
201                         m_begin[0] = '@';       // mark the string as overflowed
202                 }
203 #endif
204                 *m_end = '\0';
205         }
206
207         inline void append(const char* in_chars)
208         {
209                 operator<<(in_chars);
210         }
211
212         // append "iterator style"
213         inline void append(const char* in_chars_begin, const char* in_chars_end)
214         {
215                 const char* curr_char = in_chars_begin;
216                 while ((m_end < m_begin+m_MaxFixedStringLength) && curr_char < in_chars_end && *curr_char != '\0')
217                         *m_end++ = *curr_char++;
218
219 #if kEnableDebug == 1
220                 if (curr_char < in_chars_end)   // if there wasn't enough room for some appended chars  
221                 {
222                         m_begin[0] = '@';           // mark the string as overflowed
223                 }
224 #endif
225                 *m_end = '\0';
226         }
227
228         // append from a char* in_count chars, (no \0 is required to terminate the input string) 
229         inline void append(const char* in_chars_begin, const size_t in_count)
230         {
231                 append(in_chars_begin, in_chars_begin + in_count);
232         }
233
234         // assign from a char* in_count chars, (no \0 is required to terminate the input string) 
235         inline void assign(const char* in_chars_begin, const size_t in_count)
236         {
237                 clear();
238                 append(in_chars_begin, in_chars_begin + in_count);
239         }
240
241         // assign from a char* , (a \0 is required to terminate the input string) 
242         inline void assign(const char* in_chars_ptr)
243         {
244                 clear();
245                 operator<<(in_chars_ptr);
246         }
247
248     // assign from a char* to a char*
249     inline void assign(const char* in_begin, const char* in_end)
250     {
251         assign(in_begin, size_t(in_end - in_begin));
252     }
253
254         inline void append_double_with_precision(const double in_double, const int in_precision)
255         {
256                 const unsigned int tempBufSize = 32;
257                 char buf[tempBufSize];
258
259         #ifdef _WINDOWS
260                 _snprintf_s(buf, tempBufSize, tempBufSize - 1, "%.*f", in_precision, in_double);
261         #endif
262         #ifdef __MACOS__
263                 std::snprintf(buf, tempBufSize, "%.*f", in_precision, in_double);
264         #endif          
265         #ifdef __linux__        
266                 snprintf(buf, tempBufSize, "%.*f", in_precision, in_double);
267         #endif          
268
269                 operator<<(buf);
270         }
271
272         inline void append_uint(const uint64_t in_uint, const int_fast16_t in_base = 10)
273         {
274                 uint_fast64_t num = in_uint;
275
276                 char* lasr_char_before = m_end;
277
278                 do {
279                         char  remainder(static_cast<char>(num % in_base));
280
281                         if ( remainder < 10 )
282                                 operator<<(char(remainder + '0'));
283                         else
284                                 operator<<(char(remainder - 10 + 'A'));
285
286                         num /= in_base;
287                 } while (num != 0);
288
289                 reverse(lasr_char_before, m_end);
290         }
291
292         inline void append_hex_binary(const uint8_t* in_binary, const size_t in_size)
293         {
294                 static const char hexdigits[] = "0123456789ABCDEF";
295
296 #if _BYTEORDER_BIG_ENDIAN==1
297                 for (size_t ibyte = 0; ibyte < in_size; ++ibyte)
298 #elif _BYTEORDER_BIG_ENDIAN==0
299                         for (size_t ibyte = in_size; ibyte > 0; --ibyte)
300 #endif
301                         {
302                                 operator<<(hexdigits[in_binary[ibyte - 1] >> 4]);
303                                 operator<<(hexdigits[in_binary[ibyte - 1] & 0x0F]);
304                         }
305         }
306
307         inline WCFixedStringBase& operator<<(const char in_charToAppend)
308         {
309                 if (m_end < m_begin+m_MaxFixedStringLength)
310                         *m_end++ = in_charToAppend;
311 #if kEnableDebug == 1
312                 else                    // if there wasn't enough room for the appended char
313                 {
314                         m_begin[0] = '@'; // mark the string as overflowed
315                 }
316 #endif
317
318                 *m_end = '\0';
319
320                 return *this;
321         }
322
323         inline WCFixedStringBase& operator<<(const char* const in_strToAppend)
324         {
325                 if (0 != in_strToAppend)
326                 {
327                         const char* pSource = in_strToAppend;
328
329                         while (*pSource != '\0' && m_end < m_begin+m_MaxFixedStringLength)
330                                 *m_end++ = *pSource++;
331
332 #if kEnableDebug == 1
333                         if (*pSource != '\0')   // if there wasn't enough room for some appended chars  
334                         {
335                                 m_begin[0] = '@';  // mark the string as overflowed
336                         }
337 #endif
338                         *m_end = '\0';
339                 }
340
341                 return *this;
342         }
343
344         WCFixedStringBase& operator<<(const uint64_t in_uint)
345         {
346                 append_uint(in_uint, 10);
347
348                 return *this;
349         }
350
351
352         // Warning prevention: the operator<< function overload for unsigneds used to create lots
353     // of warnings once size_t usage was becoming widespread. So for each OS we define only
354     // those overloads that are actually needed. On Windows 32 bit we still get
355         // 'warning C4267: 'argument' : conversion from 'size_t' to 'const unsigned int', possible loss of data'
356         // warning which we do not know how to solve yet. The function DummyFunctionsForWarningTest
357     // in file WCFixedStringStream.cpp calls all combinations of operator<<(unsigned something)
358     // And should produce no warnings - (except the C4267 on windows).
359 #if defined(__MACOS__) // both 32 & 64 bit
360         WCFixedStringBase& operator<<(const size_t in_uint) {
361                 return operator<<(static_cast<unsigned long long>(in_uint));
362         }
363 #endif   
364 //      WCFixedStringBase& operator<<(const unsigned char in_uint) {
365 //              return operator<<(static_cast<const unsigned long long>(in_uint));
366 //              }
367 //              
368 //      WCFixedStringBase& operator<<(const size_t in_uint) {
369 //              return operator<<(static_cast<const uint64_t>(in_uint));
370 //              }
371 //              
372 #if defined(__MACOS__) || defined(_WINDOWS) || defined(__linux__) // both 32 & 64 bit
373         WCFixedStringBase& operator<<(const unsigned int in_uint) {
374                 return operator<<(static_cast<uint64_t>(in_uint));
375         }
376 #endif   
377 //              
378 #if defined(_WINDOWS) || defined(__linux__) // both 32 & 64 bit
379         WCFixedStringBase& operator<<(const unsigned long in_uint) {
380                 return operator<<(static_cast<uint64_t>(in_uint));
381         }
382 #endif   
383
384         WCFixedStringBase& operator<<(const long long in_int)
385         {
386                 if (in_int < 0)
387                         operator<<('-');
388 #ifdef _WINDOWS
389 //        uintmax_t unsigned_in_num = _abs64(in_int);
390                 uintmax_t unsigned_in_num = in_int < 0 ? static_cast<uintmax_t>(-in_int) : static_cast<uintmax_t>(in_int);
391 #else
392                 uintmax_t unsigned_in_num = std::abs(in_int);
393 #endif
394                 append_uint(unsigned_in_num, 10);
395
396                 return *this;
397         }
398
399         WCFixedStringBase& operator<<(const short in_int) {
400                 return operator<<(static_cast<int64_t>(in_int));
401         }
402
403         WCFixedStringBase& operator<<(const int in_int) {
404                 return operator<<(static_cast<int64_t>(in_int));
405         }
406
407         WCFixedStringBase& operator<<(const long in_int) {
408                 return operator<<(static_cast<int64_t>(in_int));
409         }
410
411         WCFixedStringBase& operator<<(const double in_doubleToWrite)
412         {
413                 append_double_with_precision(in_doubleToWrite, 10);
414
415                 return *this;
416         }
417
418         WCFixedStringBase& operator<<(const float in_floatToWrite)
419         {
420                 append_double_with_precision(double(in_floatToWrite), 5);
421
422                 return *this;
423         }
424
425         inline WCFixedStringBase& operator<<(const WCFixedStringBase& in_fixedStrToAppend)
426         {
427                 operator<<(in_fixedStrToAppend.c_str());
428
429                 return *this;
430         }
431
432         WCFixedStringBase& operator<< (bool abool)
433         {
434                 return abool ? operator<<("true") : operator<<("false");
435         }
436
437         template<typename T> WCFixedStringBase& operator+=(T in_type)
438         {
439                 return operator<<(in_type);
440         }
441
442         ptrdiff_t compare(const char* in_to_compare) const
443         {
444                 ptrdiff_t retVal = 1;
445
446                 if (0 != in_to_compare)
447                 {
448                         retVal =  strcmp(c_str(), in_to_compare);
449                 }
450
451                 return retVal;
452         }
453
454
455         ptrdiff_t compare(const WCFixedStringBase& in_to_compare) const
456         {
457                 ptrdiff_t retVal = compare(in_to_compare.c_str());              
458                 return retVal;
459         }
460
461         ptrdiff_t case_insensitive_compare(const char* in_to_compare) const
462         {
463                 ptrdiff_t retVal = 1;
464
465                 if (0 != in_to_compare)
466                 {
467 #ifdef _WINDOWS
468                         retVal = _stricmp(c_str(), in_to_compare);
469 #endif
470 #if defined(__linux__) || defined(__MACOS__)
471                         retVal =  strcasecmp(c_str(), in_to_compare);
472 #endif
473                 }
474
475                 return retVal;
476         }
477
478         ptrdiff_t case_insensitive_compare(const WCFixedStringBase& in_to_compare) const
479         {
480                 ptrdiff_t retVal = case_insensitive_compare(in_to_compare.c_str());             
481                 return retVal;
482         }
483
484         pos_t find(const char in_char_to_find) const
485         {
486                 const char* pCurrChar = m_begin;
487                 while (pCurrChar < m_end && *pCurrChar != in_char_to_find)
488                         ++pCurrChar;
489
490                 return (pCurrChar < m_end) ? (pCurrChar - m_begin) : npos;
491         }
492
493     pos_t rfind(const char in_char_to_find) const
494     {
495         pos_t retVal = npos;
496         const char* pCurrChar = m_end;
497
498         while (pCurrChar != m_begin) 
499         {
500             --pCurrChar;
501             if (*pCurrChar == in_char_to_find)
502             {
503                 retVal = pCurrChar - m_begin;
504                 break;
505             }
506         }
507         
508         return retVal;
509     }
510     
511         pos_t find(const char* in_chars_to_find, const pos_t in_start_from = 0) const
512         {
513                 pos_t retVal = npos;
514                 size_t to_find_size = ::strlen(in_chars_to_find);
515         
516                 if (to_find_size > 0 && to_find_size <= size() && in_start_from < size())
517                 {
518                         const char* pCurrChar = m_begin + in_start_from;
519                         while ((m_end - pCurrChar) >= (ptrdiff_t)to_find_size)
520                         {
521                                 int found = ::memcmp(pCurrChar, in_chars_to_find, to_find_size);
522                                 if (0 == found)
523                                 {
524                                         retVal = (pCurrChar - m_begin);
525                                         break;
526                                 }
527                 
528                                 ++pCurrChar;
529                         }
530                 }
531         
532                 return retVal;
533         }
534     
535         pos_t rfind(const char* in_chars_to_find) const
536         {
537                 pos_t retVal = npos;
538                 size_t to_find_size = ::strlen(in_chars_to_find);
539         
540                 if (to_find_size > 0 && to_find_size <= size())
541                 {
542                         const char* pCurrChar = m_end - to_find_size;
543                         while (m_begin <= pCurrChar)
544                         {
545                                 int found = ::memcmp(pCurrChar, in_chars_to_find, to_find_size);
546                                 if (0 == found)
547                                 {
548                                         retVal = (pCurrChar - m_begin);
549                                         break;
550                                 }
551                 
552                                 --pCurrChar;
553                         }
554                 }
555         
556                 return retVal;
557         }
558     
559         pos_t find_case_insensitive(const char* in_chars_to_find, const pos_t in_start_from = 0) const
560         {
561                 pos_t retVal = npos;
562                 size_t to_find_size = ::strlen(in_chars_to_find);
563         
564                 if (to_find_size > 0 && to_find_size <= size() && in_start_from < size())
565                 {
566                         const char* pCurrChar = m_begin + in_start_from;
567                         while ((m_end - pCurrChar) >= (ptrdiff_t)to_find_size)
568                         {
569                 size_t i;
570                 for (i = 0; i < to_find_size; ++i)
571                 {
572                         if (tolower(*(pCurrChar+i)) != tolower(in_chars_to_find[i]))
573                         break;
574                 }
575                 
576                                 if (i == to_find_size)
577                                 {
578                                         retVal = (pCurrChar - m_begin);
579                                         break;
580                                 }
581                 
582                                 ++pCurrChar;
583                         }
584                 }
585         
586                 return retVal;
587         }
588     
589         pos_t find_first_of(const char* in_possibe_chars_to_find, const pos_t in_start_from = 0) const
590         {
591                 pos_t retVal = npos;
592
593                 if (in_start_from < size())
594                 {
595                         const char* pFoundChar = strpbrk(m_begin + in_start_from, in_possibe_chars_to_find);
596                         if (0 != pFoundChar)
597                         {
598                                 retVal = (pFoundChar - m_begin);
599                         }
600                 }
601
602                 return retVal;
603         }
604
605         pos_t find_last_of(const char* in_possibe_chars_to_find, const pos_t in_start_from = 0) const
606         {
607                 pos_t retVal = npos;
608
609                 pos_t curr_location = in_start_from;
610
611                 while (size() > curr_location)
612                 {
613                         pos_t found = find_first_of(in_possibe_chars_to_find, curr_location);
614                         if (npos != found)
615                         {
616                                 retVal = found;
617                                 curr_location = found + 1;
618                         }
619                         else
620                                 break;
621                 }
622
623                 return retVal;
624         }
625
626         pos_t find_first_not_of(const char* in_acceptable_chars, const pos_t in_start_from = 0) const
627         {
628                 pos_t retVal = npos;
629
630                 if (in_start_from < size())
631                 {
632                         retVal = (strspn(m_begin + in_start_from, in_acceptable_chars));
633                         if (size() <= retVal + in_start_from)
634                         {
635                                 retVal = npos;
636                         }
637                         else
638                         {
639                                 retVal += in_start_from;
640                         }
641                 }
642
643                 return retVal;
644         }
645
646         pos_t find_last_not_of(const char* in_acceptable_chars, const pos_t in_start_from = 0) const
647         {
648                 pos_t retVal = npos;
649
650                 pos_t curr_location = in_start_from;
651
652                 while (size() > curr_location)
653                 {
654                         pos_t found = find_first_not_of(in_acceptable_chars, curr_location);
655                         if (npos != found)
656                         {
657                                 retVal = found;
658                                 curr_location = found + 1;
659                         }
660                         else
661                                 break;
662                 }
663
664                 return retVal;
665         }
666
667         // return true if in_begin_text is found at position 0 OR if in_begin_text is empty
668         bool begins_with(const char* in_begin_text) const
669     {
670         pos_t where = find(in_begin_text, 0);
671         bool retVal = (0 == where) || (0 == ::strlen(in_begin_text));
672         return retVal;
673     }
674         
675     // return true if in_end_text is found at th end OR if in_end_text is empty
676         bool ends_with(const char* in_end_text) const
677     {
678         pos_t where = rfind(in_end_text);
679         bool retVal = ((size() - strlen(in_end_text)) == where) || (0 == ::strlen(in_end_text));
680         return retVal;
681     }
682     
683         size_t replace(const char in_look_for, const char in_replace_with)
684         {
685                 size_t retVal = 0;
686
687                 char* pCurrChar = m_begin;
688                 while (pCurrChar < m_end)
689                 {
690                         if (*pCurrChar == in_look_for)
691                         {
692                                 *pCurrChar = in_replace_with;
693                                 ++retVal;
694                         }
695             ++pCurrChar;
696                 }
697
698                 return retVal;
699         }
700
701     // erase in_size chars starting from in_location
702         void erase(const pos_t in_location, const size_t in_num_chars = 1)
703         {
704                 if (size() > in_location && in_num_chars > 0)
705                 {
706                         size_t actual_num_chars = WUMin(in_num_chars, size_t(size() - in_location));
707                         char* pTo = m_begin + in_location;
708                         char* pFrom = pTo + actual_num_chars;
709
710                         while (pFrom < m_end)
711                                 *pTo++ = *pFrom++;
712
713                         resize(size() - actual_num_chars);
714                 }
715         }
716
717     // erase any char that appear in in_forbidden_chars
718         void erase_all_of(const char* in_forbidden_chars)
719         {
720                 pos_t curr_location = 0;
721
722                 while (npos != curr_location)
723                 {
724                         curr_location = find_first_of(in_forbidden_chars, curr_location);
725                         if (npos != curr_location)
726                                 erase(curr_location);
727                 }
728         }
729
730     // erase any char that do not appear in in_allowed_chars
731         void erase_all_not_of(const char* in_allowed_chars)
732         {
733                 pos_t curr_location = 0;
734
735                 while (npos != curr_location)
736                 {
737                         curr_location = find_first_not_of(in_allowed_chars, curr_location);
738                         if (npos != curr_location)
739                                 erase(curr_location);
740                 }
741         }
742
743         //! Copy the content of fixed string to a buffer appending a '\0' at the end.
744     //! If in_buffer_size is more than the allocated buffer size memory over write will happen!
745         void copy_to_buffer(const size_t in_buffer_size, char* out_buffer)
746     {
747         if (in_buffer_size > 0 && 0 != out_buffer)
748         {
749             char* cur_buffer = out_buffer;
750             const char* cur_fixed = m_begin;
751             const char* end_buffer = out_buffer + (WUMin<size_t>(in_buffer_size - 1, m_end - m_begin));
752             while (cur_buffer < end_buffer)
753                 *cur_buffer++ = *cur_fixed++;
754             
755             *cur_buffer = '\0';
756         }
757     }
758     
759 protected:      
760         ~WCFixedStringBase() {}
761
762         char* const m_begin;
763         const size_t m_MaxFixedStringLength;
764         char* m_end;
765
766 private:
767         WCFixedStringBase();
768         WCFixedStringBase(const WCFixedStringBase& in_fixedStrToCopy);
769 #if 0
770         :
771         m_begin(in_fixedStrToCopy.m_begin),
772         m_MaxFixedStringLength(in_fixedStrToCopy.m_MaxFixedStringLength),
773         m_end(in_fixedStrToCopy.m_end)
774         {
775         }
776 #endif
777 };
778
779 template<size_t kMaxFixedStringLength> class DllExport WCFixedString : public WCFixedStringBase
780 {
781 public:
782
783         inline WCFixedString() : 
784                 WCFixedStringBase(m_fixedString, kMaxFixedStringLength)
785         {
786         }
787
788         inline  WCFixedString(const char* const in_strToAssign) :
789                 WCFixedStringBase(m_fixedString, kMaxFixedStringLength)
790         {
791                 operator<<(in_strToAssign);
792         }
793
794         inline  WCFixedString(const WCFixedStringBase& in_fixedStrToAssign) :
795                 WCFixedStringBase(m_fixedString, kMaxFixedStringLength)
796         {
797                 operator<<(in_fixedStrToAssign);
798         }
799
800         inline  WCFixedString(const WCFixedString& in_fixedStrToAssign) :
801                 WCFixedStringBase(m_fixedString, kMaxFixedStringLength)
802         {
803                 operator<<(in_fixedStrToAssign);
804         }
805
806         inline  WCFixedString(const char in_char, const size_t in_count = 1) :
807                 WCFixedStringBase(m_fixedString, kMaxFixedStringLength)
808         {
809                 append(in_char, in_count);
810         }
811
812         inline  WCFixedString(const char* in_chars, const size_t in_count) :
813                 WCFixedStringBase(m_fixedString, kMaxFixedStringLength)
814         {
815                 append(in_chars, in_count);
816         }
817
818     // substr now supports negative in_length, which means "from the end" so
819     // "abcdefg".substr(1, -1) == "bcdef"
820         inline const WCFixedString substr(const pos_t in_pos = 0, const spos_t in_length = kMaxFixedStringLength) const
821         {
822                 pos_t adjusted_pos = WUMin<size_t>(in_pos, size());
823         size_t adjusted_length = 0;
824         if (in_length < 0)
825         {
826                 adjusted_length = size_t(WUMax<spos_t>(0, spos_t(size() - adjusted_pos) + in_length));
827         }
828         else
829                 adjusted_length = WUMin<size_t>(in_length, size() - adjusted_pos);
830
831                 WCFixedString retVal;
832                 retVal.append(m_begin + adjusted_pos, adjusted_length);
833
834                 return retVal;
835         }
836
837 protected:      
838
839         char m_fixedString[kMaxFixedStringLength + 1]; // the "+ 1" is so that *m_end is always valid, and we can put the '\0' there};
840 };
841
842 inline bool operator==(const WCFixedStringBase& in_left, const WCFixedStringBase& in_right)     
843 {
844         return 0 == in_left.compare(in_right.c_str());
845 }
846
847 inline bool operator==(const WCFixedStringBase& in_left, const char* const in_right)
848 {
849         return 0 == in_left.compare(in_right);
850 }
851
852 inline bool operator!=(const WCFixedStringBase& in_left, const WCFixedStringBase& in_right)     
853 {
854         return 0 != in_left.compare(in_right.c_str());
855 }
856
857 inline bool operator!=(const WCFixedStringBase& in_left, const char* const in_right)
858 {
859         return 0 != in_left.compare(in_right);
860 }
861
862 // class WCFixedStringBase
863 typedef WCFixedString<4>        WCFixedString4;
864 typedef WCFixedString<15>       WCFixedString15;
865 typedef WCFixedString<31>       WCFixedString31;
866 typedef WCFixedString<63>       WCFixedString63;
867 typedef WCFixedString<127>      WCFixedString127;
868 typedef WCFixedString<255>      WCFixedString255;
869 typedef WCFixedString<511>      WCFixedString511;
870 typedef WCFixedString<1023>     WCFixedString1023;
871 typedef WCFixedString<2047>     WCFixedString2047;
872
873 template<size_t kSizeOfFirst, size_t kSizeOfSecond> 
874         class WCFixedStringPair : public std::pair< WCFixedString<kSizeOfFirst>, WCFixedString<kSizeOfSecond> >
875 {
876 public:
877         WCFixedStringPair(const char* const in_firstStr = 0, const char* const in_secondStr = 0) :      
878         std::pair< WCFixedString<kSizeOfFirst>, WCFixedString<kSizeOfSecond> >(in_firstStr, in_secondStr) {}
879         WCFixedStringPair(const WCFixedStringBase& in_firstStr, const char* const in_secondStr = 0) :   
880         std::pair< WCFixedString<kSizeOfFirst>, WCFixedString<kSizeOfSecond> >(in_firstStr, in_secondStr) {}
881         WCFixedStringPair(const WCFixedStringBase& in_firstStr, const WCFixedStringBase& in_secondStr) :        
882         std::pair< WCFixedString<kSizeOfFirst>, WCFixedString<kSizeOfSecond> >(in_firstStr, in_secondStr) {}
883 };
884
885 #endif  //  #ifndef __WCFixedString_h__