source: trunk/libdjvu/GString.cpp @ 280

Last change on this file since 280 was 280, checked in by rbri, 11 years ago

DJVU plugin: djvulibre updated to version 3.5.22

File size: 58.4 KB
Line 
1//C-  -*- C++ -*-
2//C- -------------------------------------------------------------------
3//C- DjVuLibre-3.5
4//C- Copyright (c) 2002  Leon Bottou and Yann Le Cun.
5//C- Copyright (c) 2001  AT&T
6//C-
7//C- This software is subject to, and may be distributed under, the
8//C- GNU General Public License, either Version 2 of the license,
9//C- or (at your option) any later version. The license should have
10//C- accompanied the software or you may obtain a copy of the license
11//C- from the Free Software Foundation at http://www.fsf.org .
12//C-
13//C- This program is distributed in the hope that it will be useful,
14//C- but WITHOUT ANY WARRANTY; without even the implied warranty of
15//C- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16//C- GNU General Public License for more details.
17//C-
18//C- DjVuLibre-3.5 is derived from the DjVu(r) Reference Library from
19//C- Lizardtech Software.  Lizardtech Software has authorized us to
20//C- replace the original DjVu(r) Reference Library notice by the following
21//C- text (see doc/lizard2002.djvu and doc/lizardtech2007.djvu):
22//C-
23//C-  ------------------------------------------------------------------
24//C- | DjVu (r) Reference Library (v. 3.5)
25//C- | Copyright (c) 1999-2001 LizardTech, Inc. All Rights Reserved.
26//C- | The DjVu Reference Library is protected by U.S. Pat. No.
27//C- | 6,058,214 and patents pending.
28//C- |
29//C- | This software is subject to, and may be distributed under, the
30//C- | GNU General Public License, either Version 2 of the license,
31//C- | or (at your option) any later version. The license should have
32//C- | accompanied the software or you may obtain a copy of the license
33//C- | from the Free Software Foundation at http://www.fsf.org .
34//C- |
35//C- | The computer code originally released by LizardTech under this
36//C- | license and unmodified by other parties is deemed "the LIZARDTECH
37//C- | ORIGINAL CODE."  Subject to any third party intellectual property
38//C- | claims, LizardTech grants recipient a worldwide, royalty-free,
39//C- | non-exclusive license to make, use, sell, or otherwise dispose of
40//C- | the LIZARDTECH ORIGINAL CODE or of programs derived from the
41//C- | LIZARDTECH ORIGINAL CODE in compliance with the terms of the GNU
42//C- | General Public License.   This grant only confers the right to
43//C- | infringe patent claims underlying the LIZARDTECH ORIGINAL CODE to
44//C- | the extent such infringement is reasonably necessary to enable
45//C- | recipient to make, have made, practice, sell, or otherwise dispose
46//C- | of the LIZARDTECH ORIGINAL CODE (or portions thereof) and not to
47//C- | any greater extent that may be necessary to utilize further
48//C- | modifications or combinations.
49//C- |
50//C- | The LIZARDTECH ORIGINAL CODE is provided "AS IS" WITHOUT WARRANTY
51//C- | OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
52//C- | TO ANY WARRANTY OF NON-INFRINGEMENT, OR ANY IMPLIED WARRANTY OF
53//C- | MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
54//C- +------------------------------------------------------------------
55//
56// $Id: GString.cpp,v 1.27 2009/05/17 23:57:42 leonb Exp $
57// $Name: release_3_5_22 $
58
59// From: Leon Bottou, 1/31/2002
60// This file has very little to do with my initial implementation.
61// It has been practically rewritten by Lizardtech for i18n changes.
62// My original implementation was very small in comparison
63// <http://prdownloads.sourceforge.net/djvu/DjVu2_2b-src.tgz>.
64// In my opinion, the duplication of the string classes is a failed
65// attempt to use the type system to enforce coding policies.
66// This could be fixed.  But there are better things to do in djvulibre.
67
68#ifdef HAVE_CONFIG_H
69# include "config.h"
70#endif
71#if NEED_GNUG_PRAGMAS
72# pragma implementation
73#endif
74
75#include "GString.h"
76#include "GThreads.h"
77#include "debug.h"
78
79#include <stdlib.h>
80#include <stdio.h>
81#include <string.h>
82#if HAS_WCHAR
83# include <locale.h>
84# if !defined(AUTOCONF) || HAVE_WCHAR_H
85#  include <wchar.h>
86# endif
87# if HAS_WCTYPE
88#  include <wctype.h>
89# endif
90#endif
91#include <ctype.h>
92
93#ifndef DO_CHANGELOCALE
94#define DO_CHANGELOCALE 1
95#ifdef UNIX
96#if THREADMODEL != COTHREADS
97#if THREADMODEL != NOTHREADS
98#undef DO_CHANGELOCALE
99#define DO_CHANGELOCALE 0
100#endif
101#endif
102#endif
103#endif
104
105
106#ifdef HAVE_NAMESPACES
107namespace DJVU {
108# ifdef NOT_DEFINED // Just to fool emacs c++ mode
109}
110#endif
111#endif
112
113
114GBaseString::~GBaseString() {}
115GNativeString::~GNativeString() {}
116GUTF8String::~GUTF8String() {}
117
118#if !HAS_MBSTATE && HAS_WCHAR
119// Under some systems, wctomb() and mbtowc() are not thread
120// safe.  In those cases, wcrtomb and mbrtowc are preferred.
121// For Solaris, wctomb() and mbtowc() are thread safe, and
122// wcrtomb() and mbrtowc() don't exist.
123
124#define wcrtomb MYwcrtomb
125#define mbrtowc MYmbrtowc
126#define mbrlen  MYmbrlen
127
128static inline int
129wcrtomb(char *bytes,wchar_t w,mbstate_t *)
130{
131  return wctomb(bytes,w);
132}
133
134static inline int
135mbrtowc(wchar_t *w,const char *source, size_t n, mbstate_t *)
136{
137  return mbtowc(w,source,n);
138}
139
140static inline size_t
141mbrlen(const char *s, size_t n, mbstate_t *)
142{
143  return mblen(s,n);
144}
145#endif // !HAS_MBSTATE || HAS_WCHAR
146
147
148GP<GStringRep>
149GStringRep::upcase(void) const
150{ return tocase(giswupper,gtowupper); }
151
152GP<GStringRep>
153GStringRep::downcase(void) const
154{ return tocase(giswlower,gtowlower); }
155
156GP<GStringRep>
157GStringRep::UTF8::create(const unsigned int sz)
158{
159  return GStringRep::create(sz,(GStringRep::UTF8 *)0);
160}
161
162GP<GStringRep>
163GStringRep::UTF8::create(const char *s)
164{
165  GStringRep::UTF8 dummy;
166  return dummy.strdup(s);
167}
168
169GP<GStringRep> 
170GStringRep::UTF8::create(const GP<GStringRep> &s1,const GP<GStringRep> &s2)
171{
172  GStringRep::UTF8 dummy;
173  return dummy.concat(s1,s2);
174}
175
176GP<GStringRep> 
177GStringRep::UTF8::create( const GP<GStringRep> &s1,const char *s2)
178{
179  GStringRep::UTF8 dummy;
180  return dummy.concat(s1,s2);
181}
182
183GP<GStringRep> 
184GStringRep::UTF8::create( const char *s1, const GP<GStringRep> &s2)
185{
186  GStringRep::UTF8 dummy;
187  return dummy.concat(s1,s2);
188}
189
190GP<GStringRep> 
191GStringRep::UTF8::create( const char *s1,const char *s2)
192{ 
193  GStringRep::UTF8 dummy;
194  return dummy.concat(s1,s2);
195}
196
197GP<GStringRep> 
198GStringRep::UTF8::create(const char *s,const int start,const int length)
199{
200  GStringRep::UTF8 dummy;
201  return dummy.substr(s,start,length);
202}
203
204GP<GStringRep> 
205GStringRep::UTF8::create(
206  const uint16_t *s,const int start,const int length)
207{
208  GStringRep::UTF8 dummy;
209  return dummy.substr(s,start,length);
210}
211
212GP<GStringRep>
213GStringRep::UTF8::create(
214  const uint32_t *s,const int start,const int length)
215{
216  GStringRep::UTF8 dummy;
217  return dummy.substr(s,start,length);
218}
219
220GP<GStringRep> 
221GStringRep::UTF8::blank(const unsigned int sz) const
222{
223   return GStringRep::create(sz,(GStringRep::UTF8 *)0);
224}
225
226bool
227GStringRep::UTF8::isUTF8(void) const
228{
229  return true;
230}
231
232GP<GStringRep> 
233GStringRep::UTF8::toThis(
234    const GP<GStringRep> &rep,const GP<GStringRep> &) const
235{
236  return rep?(rep->toUTF8(true)):rep;
237}
238
239GP<GStringRep> 
240GStringRep::UTF8::create(const char fmt[],va_list& args)
241{ 
242  const GP<GStringRep> s(create(fmt));
243  return (s?(s->vformat(args)):s);
244}
245
246#if !HAS_WCHAR
247
248#define NATIVE_CREATE(x) UTF8::create( x );
249
250#ifdef LC_ALL
251#undef LC_ALL
252#endif
253#define LC_ALL 0
254
255class GStringRep::ChangeLocale
256{
257public:
258  ChangeLocale(const int,const char *) {}
259  ~ChangeLocale() {};
260};
261
262GP<GStringRep>
263GStringRep::NativeToUTF8( const char *s )
264{
265  return GStringRep::UTF8::create(s);
266}
267
268#else
269
270#define NATIVE_CREATE(x) Native::create( x );
271
272// The declaration and implementation of GStringRep::ChangeLocale
273// Not used in WinCE
274
275class GStringRep::ChangeLocale
276{
277public:
278  ChangeLocale(const int category,const char locale[]);
279  ~ChangeLocale();
280private:
281  GUTF8String locale;
282  int category;
283};
284
285class GStringRep::Native : public GStringRep
286{
287public:
288  // default constructor
289  Native(void);
290  // virtual destructor
291  virtual ~Native();
292
293    // Other virtual methods.
294      // Create an empty string.
295  virtual GP<GStringRep> blank(const unsigned int sz = 0) const;
296      // Append a string.
297  virtual GP<GStringRep> append(const GP<GStringRep> &s2) const;
298      // Test if Native.
299  virtual bool isNative(void) const;
300      // Convert to Native.
301  virtual GP<GStringRep> toNative(
302    const EscapeMode escape=UNKNOWN_ESCAPED) const;
303      // Convert to UTF8.
304  virtual GP<GStringRep> toUTF8(const bool nothrow=false) const;
305      // Convert to UTF8.
306  virtual GP<GStringRep> toThis(
307     const GP<GStringRep> &rep,const GP<GStringRep> &) const;
308      // Compare with #s2#.
309  virtual int cmp(const GP<GStringRep> &s2, const int len=(-1)) const;
310
311  // Convert strings to numbers.
312  virtual int toInt(void) const;
313  virtual long toLong(
314    const int pos, int &endpos, const int base=10) const;
315  virtual unsigned long toULong(
316    const int pos, int &endpos, const int base=10) const;
317  virtual double toDouble(
318    const int pos, int &endpos) const;
319
320    // Create an empty string
321  static GP<GStringRep> create(const unsigned int sz = 0);
322
323    // Create a strdup string.
324  static GP<GStringRep> create(const char *s);
325
326  // Creates by appending to the current string
327
328   // Creates with a concat operation.
329  static GP<GStringRep> create(
330    const GP<GStringRep> &s1,const GP<GStringRep> &s2);
331  static GP<GStringRep> create( const GP<GStringRep> &s1,const char *s2);
332  static GP<GStringRep> create( const char *s1, const GP<GStringRep> &s2);
333  static GP<GStringRep> create(const char *s1,const char *s2);
334
335    // Create with a strdup and substr operation.
336  static GP<GStringRep> create(
337    const char *s,const int start,const int length=(-1));
338  static GP<GStringRep> create(
339    const uint16_t *s,const int start,const int length=(-1));
340  static GP<GStringRep> create(
341    const uint32_t *s,const int start,const int length=(-1));
342
343    // Create with an sprintf()
344  static GP<GStringRep> create_format(const char fmt[],...);
345  static GP<GStringRep> create(const char fmt[],va_list &args);
346
347  virtual unsigned char *UCS4toString(
348    const uint32_t w,unsigned char *ptr, mbstate_t *ps=0) const;
349
350  // Tests if a string is legally encoded in the current character set.
351  virtual bool is_valid(void) const;
352
353  virtual int ncopy(wchar_t * const buf, const int buflen) const;
354
355  friend class GBaseString;
356protected:
357  // Return the next character and increment the source pointer.
358  virtual uint32_t getValidUCS4(const char *&source) const;
359};
360
361GP<GStringRep>
362GStringRep::Native::create(const unsigned int sz)
363{
364  return GStringRep::create(sz,(GStringRep::Native *)0);
365}
366
367    // Create a strdup string.
368GP<GStringRep>
369GStringRep::Native::create(const char *s)
370{
371  GStringRep::Native dummy;
372  return dummy.strdup(s);
373}
374
375GP<GStringRep>
376GStringRep::Native::create(const GP<GStringRep> &s1,const GP<GStringRep> &s2)
377{
378  GStringRep::Native dummy;
379  return dummy.concat(s1,s2);
380}
381
382GP<GStringRep> 
383GStringRep::Native::create( const GP<GStringRep> &s1,const char *s2)
384{
385  GStringRep::Native dummy;
386  return dummy.concat(s1,s2);
387}
388
389GP<GStringRep>
390GStringRep::Native::create( const char *s1, const GP<GStringRep> &s2)
391{
392  GStringRep::Native dummy;
393  return dummy.concat(s1,s2);
394}
395
396GP<GStringRep>
397GStringRep::Native::create(const char *s1,const char *s2)
398{
399  GStringRep::Native dummy;
400  return dummy.concat(s1,s2);
401}
402
403GP<GStringRep>
404GStringRep::Native::create(
405  const char *s,const int start,const int length)
406{
407  GStringRep::Native dummy;
408  return dummy.substr(s,start,length);
409}
410
411GP<GStringRep>
412GStringRep::Native::create(
413    const uint16_t *s,const int start,const int length)
414{
415  GStringRep::Native dummy;
416  return dummy.substr(s,start,length);
417}
418
419GP<GStringRep>
420GStringRep::Native::create(
421  const uint32_t *s,const int start,const int length)
422{
423  GStringRep::Native dummy;
424  return dummy.substr(s,start,length);
425}
426
427GP<GStringRep> 
428GStringRep::Native::blank(const unsigned int sz) const
429{
430  return GStringRep::create(sz,(GStringRep::Native *)0);
431}
432
433bool
434GStringRep::Native::isNative(void) const
435{
436  return true;
437}
438
439GP<GStringRep>
440GStringRep::Native::toThis(
441     const GP<GStringRep> &rep,const GP<GStringRep> &) const
442{
443  return rep?(rep->toNative(NOT_ESCAPED)):rep;
444}
445
446GP<GStringRep> 
447GStringRep::Native::create(const char fmt[],va_list &args)
448{ 
449  const GP<GStringRep> s(create(fmt));
450  return (s?(s->vformat(args)):s);
451}
452
453int
454GStringRep::Native::ncopy(
455  wchar_t * const buf, const int buflen ) const
456{
457  return toUTF8()->ncopy(buf,buflen);
458}
459
460GStringRep::ChangeLocale::ChangeLocale(const int xcategory, const char xlocale[] )
461  : category(xcategory)
462{
463#if DO_CHANGELOCALE
464  // This is disabled under UNIX because
465  // it does not play nice with MT.
466  if(xlocale)
467    {
468      locale=setlocale(xcategory,0);
469      if(locale.length() &&(locale!=xlocale))
470        {
471          if(locale == setlocale(category,xlocale))
472            {
473              locale.empty();
474            }
475        }
476      else
477        {
478          locale.empty();
479        }
480    }
481#endif
482}
483
484GStringRep::ChangeLocale::~ChangeLocale()
485{
486#if DO_CHANGELOCALE
487  if(locale.length())
488    {
489      setlocale(category,(const char *)locale);
490    }
491#endif
492}
493
494GNativeString &
495GNativeString::format(const char fmt[], ... )
496{
497  va_list args;
498  va_start(args, fmt);
499  return init(GStringRep::Native::create(fmt,args));
500}
501
502// Gather the native implementations here. Not used in WinCE.
503
504GStringRep::Native::Native(void) {}
505GStringRep::Native::~Native() {}
506
507GP<GStringRep>
508GStringRep::Native::append(const GP<GStringRep> &s2) const
509{
510  GP<GStringRep> retval;
511  if(s2)
512  {
513    if(s2->isUTF8())
514    {
515      G_THROW( ERR_MSG("GStringRep.appendUTF8toNative") );
516    }
517    retval=concat(data,s2->data);
518  }else
519  {
520    retval=const_cast<GStringRep::Native *>(this); 
521  }
522  return retval;
523}
524
525GP<GStringRep>
526GStringRep::Native::create_format(const char fmt[],...)
527{
528  va_list args;
529  va_start(args, fmt);
530  return create(fmt,args);
531}
532
533unsigned char *
534GStringRep::Native::UCS4toString(
535  const uint32_t w0,unsigned char *ptr, mbstate_t *ps) const
536{
537  return UCS4toNative(w0,ptr,ps);
538}
539
540// Convert a UCS4 to a multibyte string in the value bytes. 
541// The data pointed to by ptr should be long enough to contain
542// the results with a nill termination.  (Normally 7 characters
543// is enough.)
544unsigned char *
545GStringRep::UCS4toNative(
546  const uint32_t w0,unsigned char *ptr, mbstate_t *ps)
547{
548  uint16_t w1;
549  uint16_t w2=1;
550  for(int count=(sizeof(wchar_t)==sizeof(w1)) ? UCS4toUTF16(w0,w1,w2) : 1;
551      count;
552      --count,w1=w2)
553  {
554    // wchar_t can be either UCS4 or UCS2
555    const wchar_t w=(sizeof(wchar_t) == sizeof(w1))?(wchar_t)w1:(wchar_t)w0;
556    int i=wcrtomb((char *)ptr,w,ps);
557    if(i<0)
558    {
559      break;
560    }
561    ptr[i]=0;
562    ptr += i;
563  }
564  ptr[0]=0;
565  return ptr;
566}
567
568GP<GStringRep>
569GStringRep::Native::toNative(const EscapeMode escape) const
570{
571  if(escape == UNKNOWN_ESCAPED)
572    G_THROW( ERR_MSG("GStringRep.NativeToNative") );
573  return const_cast<GStringRep::Native *>(this);
574}
575
576GP<GStringRep>
577GStringRep::Native::toUTF8(const bool) const
578{
579  unsigned char *buf;
580  GPBuffer<unsigned char> gbuf(buf,size*6+1);
581  buf[0]=0;
582  if(data && size)
583  {
584    size_t n=size;
585    const char *source=data;
586    mbstate_t ps;
587    unsigned char *ptr=buf;
588    //(void)mbrlen(source, n, &ps);
589    memset(&ps,0,sizeof(mbstate_t));
590    int i=0;
591    if(sizeof(wchar_t) == sizeof(uint32_t))
592      {
593        wchar_t w = 0;
594        for(;(n>0)&&((i=mbrtowc(&w,source,n,&ps))>=0); n-=i,source+=i)
595          {
596            ptr=UCS4toUTF8((uint32_t)w,ptr);
597          }
598      }
599    else
600      { 
601        wchar_t w = 0;
602        for(;(n>0)&&((i=mbrtowc(&w,source,n,&ps))>=0);n-=i,source+=i)
603          {
604            uint16_t s[2];
605            s[0]=w;
606            uint32_t w0;
607            if(UTF16toUCS4(w0,s,s+1)<=0)
608              {
609                source+=i;
610                n-=i;
611                if((n>0)&&((i=mbrtowc(&w,source,n,&ps))>=0))
612                  {
613                    s[1]=w;
614                    if(UTF16toUCS4(w0,s,s+2)<=0)
615                      {
616                        i=(-1);
617                        break;
618                      }
619                  }
620                else
621                  {
622                    i=(-1);
623                    break;
624                  }
625              }
626            ptr=UCS4toUTF8(w0,ptr);
627          }
628      }
629    if(i<0)
630      {
631        gbuf.resize(0);
632      }
633    else
634      {
635        ptr[0]=0;
636      }
637  }
638  return GStringRep::UTF8::create((const char *)buf);
639}
640
641GNativeString
642GBaseString::UTF8ToNative(
643  const bool currentlocale,const EscapeMode escape) const
644{
645  const char *source=(*this);
646  GP<GStringRep> retval;
647  if(source && source[0]) 
648  {
649#if DO_CHANGELOCALE
650    GUTF8String lc_ctype(setlocale(LC_CTYPE,0));
651#endif
652    bool repeat;
653    for(repeat=!currentlocale;;repeat=false)
654    {
655      retval=(*this)->toNative((GStringRep::EscapeMode)escape);
656#if DO_CHANGELOCALE
657      if (!repeat || retval || (lc_ctype == setlocale(LC_CTYPE,"")))
658#endif
659        break;
660    }
661#if DO_CHANGELOCALE
662    if(!repeat)
663      {
664        setlocale(LC_CTYPE,(const char *)lc_ctype);
665      }
666#endif
667  }
668  return GNativeString(retval);
669}
670
671/*MBCS*/
672GNativeString
673GBaseString::getUTF82Native( EscapeMode escape ) const
674{ //MBCS cvt
675  GNativeString retval;
676
677  // We don't want to convert this if it
678  // already is known to be native...
679//  if (isNative()) return *this;
680
681  const size_t slen=length()+1;
682  if(slen>1)
683  {
684/* Lucide */
685#ifndef OS2
686    retval=UTF8ToNative(false,escape) ;
687#endif
688    if(!retval.length())
689    {
690      retval=(const char*)*this;
691    }
692  }
693  return retval;
694}
695
696GUTF8String
697GBaseString::NativeToUTF8(void) const
698{
699  GP<GStringRep> retval;
700  if(length())
701  {
702    const char *source=(*this);
703#if DO_CHANGELOCALE
704    GUTF8String lc_ctype=setlocale(LC_CTYPE,0);
705#endif
706    bool repeat;
707    for(repeat=true;;repeat=false)
708    {
709      if( (retval=GStringRep::NativeToUTF8(source)) )
710      {
711        if(GStringRep::cmp(retval->toNative(),source))
712        {
713          retval=GStringRep::UTF8::create((unsigned int)0);
714        }
715      }
716#if DO_CHANGELOCALE
717      if(!repeat || retval || (lc_ctype == setlocale(LC_CTYPE,"")))
718#endif
719        break;
720    }
721#if DO_CHANGELOCALE
722    if(!repeat)
723    {
724      setlocale(LC_CTYPE,(const char *)lc_ctype);
725    }
726#endif
727  }
728  return GUTF8String(retval);
729}
730
731GUTF8String
732GBaseString::getNative2UTF8(void) const
733{ //MBCS cvt
734
735   // We don't want to do a transform this
736   // if we already are in the given type.
737//   if (isUTF8()) return *this;
738   
739  const size_t slen=length()+1;
740  GUTF8String retval;
741  if(slen > 1)
742  {
743    retval=NativeToUTF8();
744    if(!retval.length())
745    {
746      retval=(const char *)(*this);
747    }
748  }
749  return retval;
750} /*MBCS*/
751
752int
753GStringRep::Native::cmp(const GP<GStringRep> &s2,const int len) const
754{
755  int retval;
756  if(s2)
757  {
758    if(s2->isUTF8())
759    {
760      const GP<GStringRep> r(toUTF8(true));
761      if(r)
762      {
763        retval=GStringRep::cmp(r->data,s2->data,len);
764      }else
765      {
766        retval=cmp(s2->toNative(NOT_ESCAPED),len);
767      }
768    }else
769    {
770      retval=GStringRep::cmp(data,s2->data,len);
771    }
772  }else
773  {
774    retval=GStringRep::cmp(data,0,len);
775  }
776  return retval;
777}
778
779int
780GStringRep::Native::toInt() const
781{
782  return atoi(data);
783}
784
785long
786GStringRep::Native::toLong(
787  const int pos, int &endpos, const int base) const
788{
789   char *edata=0;
790   const long retval=strtol(data+pos, &edata, base);
791   if(edata)
792   {
793     endpos=(int)((size_t)edata-(size_t)data);
794   }else
795   {
796     endpos=(-1);
797   }
798   return retval;
799}
800
801unsigned long
802GStringRep::Native::toULong(
803  const int pos, int &endpos, const int base) const
804{
805   char *edata=0;
806   const unsigned long retval=strtoul(data+pos, &edata, base);
807   if(edata)
808   {
809     endpos=(int)((size_t)edata-(size_t)data);
810   }else
811   {
812     endpos=(-1);
813   }
814   return retval;
815}
816
817double
818GStringRep::Native::toDouble(
819  const int pos, int &endpos) const
820{
821   char *edata=0;
822   const double retval=strtod(data+pos, &edata);
823   if(edata)
824   {
825     endpos=(int)((size_t)edata-(size_t)data);
826   }else
827   {
828     endpos=(-1);
829   }
830   return retval;
831}
832
833uint32_t
834GStringRep::Native::getValidUCS4(const char *&source) const
835{
836  uint32_t retval=0;
837  int n=(int)((size_t)size+(size_t)data-(size_t)source);
838  if(source && (n > 0))
839  {
840    mbstate_t ps;
841    //(void)mbrlen(source, n, &ps);
842    memset(&ps,0,sizeof(mbstate_t));
843    wchar_t wt;
844    const int len=mbrtowc(&wt,source,n,&ps); 
845    if(len>=0)
846    {
847      if(sizeof(wchar_t) == sizeof(uint16_t))
848      {
849        source+=len;
850        uint16_t s[2];
851        s[0]=(uint16_t)wt;
852        if(UTF16toUCS4(retval,s,s+1)<=0)
853        {
854          if((n-=len)>0)
855          {
856            const int len=mbrtowc(&wt,source,n,&ps);
857            if(len>=0)
858            {
859              s[1]=(uint16_t)wt;
860              uint32_t w;
861              if(UTF16toUCS4(w,s,s+2)>0)
862              {
863                source+=len;
864                retval=w;
865              }
866            }
867          }
868        }
869      }else
870      {
871        retval=(uint32_t)wt;
872        source++;
873      } 
874    }else
875    {
876      source++;
877    }
878  }
879  return retval;
880}
881
882// Tests if a string is legally encoded in the current character set.
883bool 
884GStringRep::Native::is_valid(void) const
885{
886  bool retval=true;
887  if(data && size)
888  {
889    size_t n=size;
890    const char *s=data;
891    mbstate_t ps;
892    //(void)mbrlen(s, n, &ps);
893    memset(&ps,0,sizeof(mbstate_t));
894    do
895    {
896      size_t m=mbrlen(s,n,&ps);
897      if(m > n)
898      {
899        retval=false;
900        break;
901      }else if(m)
902      {
903        s+=m;
904        n-=m;
905      }else
906      {
907        break;
908      }
909    } while(n);
910  }
911  return retval;
912}
913
914// These are dummy functions.
915void 
916GStringRep::set_remainder(void const * const, const unsigned int,
917  const EncodeType) {}
918void 
919GStringRep::set_remainder(void const * const, const unsigned int,
920  const GP<GStringRep> &encoding) {}
921void
922GStringRep::set_remainder( const GP<GStringRep::Unicode> &) {}
923
924GP<GStringRep::Unicode>
925GStringRep::get_remainder( void ) const
926{
927  return 0;
928}
929
930GNativeString::GNativeString(const char dat)
931{
932  init(GStringRep::Native::create(&dat,0,1));
933}
934
935GNativeString::GNativeString(const char *str)
936{
937  init(GStringRep::Native::create(str));
938}
939
940GNativeString::GNativeString(const unsigned char *str)
941{
942  init(GStringRep::Native::create((const char *)str));
943}
944
945GNativeString::GNativeString(const uint16_t *str)
946{
947  init(GStringRep::Native::create(str,0,-1));
948}
949
950GNativeString::GNativeString(const uint32_t *str)
951{
952  init(GStringRep::Native::create(str,0,-1));
953}
954
955GNativeString::GNativeString(const char *dat, unsigned int len)
956{
957  init(
958    GStringRep::Native::create(dat,0,((int)len<0)?(-1):(int)len));
959}
960
961GNativeString::GNativeString(const uint16_t *dat, unsigned int len)
962{
963  init(
964    GStringRep::Native::create(dat,0,((int)len<0)?(-1):(int)len));
965}
966
967GNativeString::GNativeString(const uint32_t *dat, unsigned int len)
968{
969  init(
970    GStringRep::Native::create(dat,0,((int)len<0)?(-1):(int)len));
971}
972
973GNativeString::GNativeString(const GNativeString &str)
974{
975  init(str);
976}
977
978GNativeString::GNativeString(const GBaseString &gs, int from, int len)
979{
980  init(
981    GStringRep::Native::create(gs,from,((int)len<0)?(-1):(int)len));
982}
983
984GNativeString::GNativeString(const int number)
985{
986  init(GStringRep::Native::create_format("%d",number));
987}
988
989GNativeString::GNativeString(const double number)
990{
991  init(GStringRep::Native::create_format("%f",number));
992}
993
994GNativeString&
995GNativeString::operator= (const char str)
996{ return init(GStringRep::Native::create(&str,0,1)); }
997
998GNativeString&
999GNativeString::operator= (const char *str)
1000{ return init(GStringRep::Native::create(str)); }
1001
1002GNativeString
1003GBaseString::operator+(const GNativeString &s2) const
1004{
1005  return GStringRep::Native::create(*this,s2);
1006}
1007
1008GP<GStringRep>
1009GStringRep::NativeToUTF8( const char *s )
1010{
1011  return GStringRep::Native::create(s)->toUTF8();
1012}
1013
1014#endif // HAS_WCHAR
1015
1016template <class TYPE>
1017GP<GStringRep>
1018GStringRep::create(const unsigned int sz, TYPE *)
1019{
1020  GP<GStringRep> gaddr;
1021  if (sz > 0)
1022  {
1023    GStringRep *addr;
1024    gaddr=(addr=new TYPE);
1025    addr->data=(char *)(::operator new(sz+1));
1026    addr->size = sz;
1027    addr->data[sz] = 0;
1028  }
1029  return gaddr;
1030}
1031
1032GP<GStringRep>
1033GStringRep::strdup(const char *s) const
1034{
1035  GP<GStringRep> retval;
1036  const int length=s?strlen(s):0;
1037  if(length>0)
1038  {
1039    retval=blank(length);
1040    char const * const end=s+length;
1041    char *ptr=retval->data;
1042    for(;*s&&(s!=end);ptr++)
1043    {
1044      ptr[0]=s++[0];
1045    }
1046    ptr[0]=0;
1047  }
1048  return retval;
1049}
1050
1051GP<GStringRep>
1052GStringRep::substr(const char *s,const int start,const int len) const
1053{
1054  GP<GStringRep> retval;
1055  if(s && s[0])
1056  {
1057    const unsigned int length=(start<0 || len<0)?(unsigned int)strlen(s):(unsigned int)(-1);
1058    const char *startptr, *endptr;
1059    if(start<0)
1060    {
1061      startptr=s+length+start;
1062      if(startptr<s)
1063        startptr=s;
1064    }else
1065    { 
1066      startptr=s;
1067      for(const char * const ptr=s+start;(startptr<ptr)&&*startptr;++startptr)
1068        EMPTY_LOOP;
1069    }
1070    if(len<0)
1071    {
1072      if(s+length+1 < startptr+len)
1073      {
1074        endptr=startptr;
1075      }else
1076      {
1077        endptr=s+length+1+len;
1078      } 
1079    }else
1080    {
1081      endptr=startptr;
1082      for(const char * const ptr=startptr+len;(endptr<ptr)&&*endptr;++endptr)
1083        EMPTY_LOOP;
1084    }
1085    if(endptr>startptr)
1086    {
1087      retval=blank((size_t)(endptr-startptr));
1088      char *data=retval->data;
1089      for(; (startptr<endptr) && *startptr; ++startptr,++data)
1090      {
1091        data[0]=startptr[0];
1092      }
1093      data[0]=0;
1094    }
1095  }
1096  return retval;
1097}
1098
1099GP<GStringRep>
1100GStringRep::substr(const uint16_t *s,const int start,const int len) const
1101{
1102  GP<GStringRep> retval;
1103  if(s && s[0])
1104  {
1105    uint16_t const *eptr;
1106    if(len<0)
1107    {
1108      for(eptr=s;eptr[0];++eptr)
1109        EMPTY_LOOP;
1110    }else
1111    {
1112      eptr=&(s[len]);
1113    }
1114    s=&s[start];
1115    if((size_t)s<(size_t)eptr)
1116    {
1117      mbstate_t ps;
1118      memset(&ps,0,sizeof(mbstate_t));
1119      unsigned char *buf,*ptr;
1120      GPBuffer<unsigned char> gbuf(buf,(((size_t)eptr-(size_t)s)/2)*3+7);
1121      for(ptr=buf;s[0];)
1122      {
1123        uint32_t w;
1124        int i=UTF16toUCS4(w,s,eptr);
1125        if(i<=0)
1126          break;
1127        s+=i;
1128        ptr=UCS4toString(w,ptr,&ps);
1129      }
1130      ptr[0]=0;
1131      retval = strdup( (const char *)buf );
1132    }
1133  }
1134  return retval;
1135}
1136
1137GP<GStringRep>
1138GStringRep::substr(const uint32_t *s,const int start,const int len) const
1139{
1140  GP<GStringRep> retval;
1141  if(s && s[0])
1142  {
1143    uint32_t const *eptr;
1144    if(len<0)
1145    {
1146      for(eptr=s;eptr[0];++eptr)
1147        EMPTY_LOOP;
1148    }else
1149    {
1150      eptr=&(s[len]);
1151    }
1152    s=&s[start];
1153    if((size_t)s<(size_t)eptr)
1154    {
1155      mbstate_t ps;
1156      memset(&ps,0,sizeof(mbstate_t));
1157      unsigned char *buf,*ptr;
1158      GPBuffer<unsigned char> gbuf(buf,((((size_t)eptr-(size_t)s))/4)*6+7);
1159      for(ptr=buf;s[0];++s)
1160      {
1161        ptr=UCS4toString(s[0],ptr,&ps);
1162      }
1163      ptr[0]=0;
1164      retval = strdup( (const char *)buf );
1165    }
1166  }
1167  return retval;
1168}
1169
1170GP<GStringRep>
1171GStringRep::append(const char *s2) const
1172{
1173  GP<GStringRep> retval;
1174  if(s2)
1175  {
1176    retval=concat(data,s2);
1177  }else
1178  {
1179    retval=const_cast<GStringRep *>(this);
1180  }
1181  return retval;
1182}
1183
1184GP<GStringRep>
1185GStringRep::UTF8::append(const GP<GStringRep> &s2) const
1186{
1187  GP<GStringRep> retval;
1188  if(s2)
1189  {
1190    if(s2->isNative())
1191    {
1192      G_THROW( ERR_MSG("GStringRep.appendNativeToUTF8") );
1193    }
1194    retval=concat(data,s2->data);
1195  }else
1196  {
1197    retval=const_cast<GStringRep::UTF8 *>(this); 
1198  }
1199  return retval;
1200}
1201
1202GP<GStringRep>
1203GStringRep::concat(const char *s1,const char *s2) const
1204{
1205  const int length1=(s1?strlen(s1):0);
1206  const int length2=(s2?strlen(s2):0);
1207  const int length=length1+length2;
1208  GP<GStringRep> retval;
1209  if(length>0)
1210  {
1211    retval=blank(length);
1212    GStringRep &r=*retval;
1213    if(length1)
1214    {
1215      strcpy(r.data,s1);
1216      if(length2)
1217        strcat(r.data,s2);
1218    }else
1219    {
1220      strcpy(r.data,s2);
1221    }
1222  }
1223  return retval;
1224}
1225
1226const char *GBaseString::nullstr = "";
1227
1228void
1229GBaseString::empty( void )
1230{
1231  init(0);
1232}
1233
1234GP<GStringRep>
1235GStringRep::getbuf(int n) const
1236{
1237  GP<GStringRep> retval;
1238  if(n< 0)
1239    n=strlen(data);
1240  if(n>0)
1241  {
1242    retval=blank(n);
1243    char *ndata=retval->data;
1244    strncpy(ndata,data,n);
1245    ndata[n]=0;
1246  }
1247  return retval;
1248}
1249
1250const char *
1251GStringRep::isCharType(
1252  bool (*xiswtest)(const unsigned long wc), const char *ptr, const bool reverse) const
1253{
1254  char const * xptr=ptr;
1255  const unsigned long w=getValidUCS4(xptr);
1256  if((ptr != xptr)
1257    &&(((sizeof(wchar_t) == 2)&&(w&~0xffff))
1258      ||(reverse?(!xiswtest(w)):xiswtest(w))))
1259  {
1260    ptr=xptr;
1261  }
1262  return ptr;
1263}
1264
1265int
1266GStringRep::nextCharType(
1267  bool (*xiswtest)(const unsigned long wc), const int from, const int len,
1268  const bool reverse) const
1269{
1270  // We want to return the position of the next
1271  // non white space starting from the #from#
1272  // location.  isspace should work in any locale
1273  // so we should only need to do this for the non-
1274  // native locales (UTF8)
1275  int retval;
1276  if(from<size)
1277  {
1278    retval=from;
1279    const char * ptr = data+from;
1280    for( const char * const eptr=ptr+((len<0)?(size-from):len);
1281      (ptr<eptr) && *ptr;)
1282    {
1283       // Skip characters that fail the isCharType test
1284      char const * const xptr=isCharType(xiswtest,ptr,!reverse);
1285      if(xptr == ptr)
1286        break;
1287      ptr=xptr;
1288    }
1289    retval=(int)((size_t)ptr-(size_t)data);
1290  }else
1291  {
1292    retval=size;
1293  }
1294  return retval;
1295}
1296
1297bool
1298GStringRep::giswspace(const unsigned long w)
1299{
1300#if HAS_WCTYPE
1301  return iswspace((wchar_t)w);
1302#else
1303  if (w & ~0xff) || isspace((int)(w & 0xff));
1304#endif
1305}
1306
1307bool
1308GStringRep::giswupper(const unsigned long w)
1309{
1310#if HAS_WCTYPE
1311  return iswupper((wchar_t)w);
1312#else
1313  return (w & ~0xff) || isupper((int)(w & 0xff));
1314#endif
1315}
1316
1317bool
1318GStringRep::giswlower(const unsigned long w)
1319{
1320#if HAS_WCTYPE
1321  return iswlower((wchar_t)w);
1322#else
1323  return (w & ~0xff) || islower((int)(w & 0xff));
1324#endif
1325}
1326
1327unsigned long
1328GStringRep::gtowupper(const unsigned long w)
1329{
1330#if HAS_WCTYPE
1331  return (unsigned long)towupper((wchar_t)w);
1332#else
1333  return (w&~0xff) ? w : (unsigned long)toupper(w & 0xff);
1334#endif
1335}
1336
1337unsigned long
1338GStringRep::gtowlower(const unsigned long w)
1339{
1340#if HAS_WCTYPE
1341  return (unsigned long)towlower((wchar_t)w);
1342#else
1343  return (w&~0xff) ? w : (unsigned long)tolower(w & 0xff);
1344#endif
1345}
1346
1347GP<GStringRep>
1348GStringRep::tocase(
1349  bool (*xiswcase)(const unsigned long wc),
1350  unsigned long (*xtowcase)(const unsigned long wc)) const
1351{
1352  GP<GStringRep> retval;
1353  char const * const eptr=data+size;
1354  char const *ptr=data;
1355  while(ptr<eptr)
1356  {
1357    char const * const xptr=isCharType(xiswcase,ptr,false);
1358    if(ptr == xptr)
1359      break;
1360    ptr=xptr;
1361  }
1362  if(ptr<eptr)
1363  {
1364    const int n=(int)((size_t)ptr-(size_t)data);
1365    unsigned char *buf;
1366    GPBuffer<unsigned char> gbuf(buf,n+(1+size-n)*6);
1367    if(n>0)
1368    {
1369      strncpy((char *)buf,data,n);
1370    }
1371    unsigned char *buf_ptr=buf+n;
1372    for(char const *ptr=data+n;ptr<eptr;)
1373    {
1374      char const * const xptr=ptr;
1375      const unsigned long w=getValidUCS4(ptr);
1376      if(ptr == xptr)
1377        break;
1378      if(xiswcase(w))
1379      {
1380        const int len=(int)((size_t)ptr-(size_t)xptr);
1381        strncpy((char *)buf_ptr,xptr,len);
1382        buf_ptr+=len;
1383      }else
1384      {
1385        mbstate_t ps;
1386        memset(&ps,0,sizeof(mbstate_t));
1387        buf_ptr=UCS4toString(xtowcase(w),buf_ptr,&ps);
1388      }
1389    }
1390    buf_ptr[0]=0;
1391    retval=substr((const char *)buf,0,(int)((size_t)buf_ptr-(size_t)buf));
1392  }else
1393  {
1394    retval=const_cast<GStringRep *>(this);
1395  }
1396  return retval;
1397}
1398
1399// Returns a copy of this string with characters used in XML escaped as follows:
1400//      '<'  -->  "&lt;"
1401//      '>'  -->  "&gt;"
1402//      '&'  -->  "&amp;"
1403//      '\'' -->  "&apos;"
1404//      '\"' -->  "&quot;"
1405//  Also escapes characters 0x00 through 0x1f and 0x7e through 0x7f.
1406GP<GStringRep>
1407GStringRep::toEscaped( const bool tosevenbit ) const
1408{
1409  bool modified=false;
1410  char *ret;
1411  GPBuffer<char> gret(ret,size*7);
1412  ret[0]=0;
1413  char *retptr=ret;
1414  char const *start=data;
1415  char const *s=start;
1416  char const *last=s;
1417  GP<GStringRep> special;
1418  for(unsigned long w;(w=getValidUCS4(s));last=s)
1419  {
1420    char const *ss=0;
1421    switch(w)
1422    {
1423    case '<':
1424      ss="&lt;";
1425      break;
1426    case '>':
1427      ss="&gt;";
1428      break;
1429    case '&':
1430      ss="&amp;";
1431      break;
1432    case '\47':
1433      ss="&apos;";
1434      break;
1435    case '\42':
1436      ss="&quot;";
1437      break;
1438    default:
1439      if((w<' ')||(w>=0x7e && (tosevenbit || (w < 0x80))))
1440      {
1441        special=toThis(UTF8::create_format("&#%lu;",w));
1442        ss=special->data;
1443      }
1444      break;
1445    }
1446    if(ss)
1447    {
1448      modified=true;
1449      if(s!=start)
1450      {
1451        size_t len=(size_t)last-(size_t)start;
1452        strncpy(retptr,start,len);
1453        retptr+=len;
1454        start=s;
1455      }
1456      if(ss[0])
1457      {
1458        size_t len=strlen(ss);
1459        strcpy(retptr,ss);
1460        retptr+=len;
1461      }
1462    }
1463  }
1464  GP<GStringRep> retval;
1465  if(modified)
1466  {
1467    strcpy(retptr,start);
1468    retval=strdup( ret );
1469  }else
1470  {
1471    retval=const_cast<GStringRep *>(this);
1472  }
1473//  DEBUG_MSG( "Escaped string is '" << ret << "'\n" );
1474  return retval;
1475}
1476
1477
1478static const GMap<GUTF8String,GUTF8String> &
1479BasicMap( void )
1480{
1481  static GMap<GUTF8String,GUTF8String> Basic;
1482  if (! Basic.size())
1483    {
1484      Basic["lt"]   = GUTF8String('<');
1485      Basic["gt"]   = GUTF8String('>');
1486      Basic["amp"]  = GUTF8String('&');
1487      Basic["apos"] = GUTF8String('\47');
1488      Basic["quot"] = GUTF8String('\42');
1489    }
1490  return Basic;
1491}
1492
1493GUTF8String
1494GUTF8String::fromEscaped( const GMap<GUTF8String,GUTF8String> ConvMap ) const
1495{
1496  GUTF8String ret;                  // Build output string here
1497  int start_locn = 0;           // Beginning of substring to skip
1498  int amp_locn;                 // Location of a found ampersand
1499
1500  while( (amp_locn = search( '&', start_locn )) > -1 )
1501  {
1502      // Found the next apostrophe
1503      // Locate the closing semicolon
1504    const int semi_locn = search( ';', amp_locn );
1505      // No closing semicolon, exit and copy
1506      //  the rest of the string.
1507    if( semi_locn < 0 )
1508      break;
1509    ret += substr( start_locn, amp_locn - start_locn );
1510    int const len = semi_locn - amp_locn - 1;
1511    if(len)
1512    {
1513      GUTF8String key = substr( amp_locn+1, len);
1514      //DEBUG_MSG( "key = '" << key << "'\n" );
1515      char const * s=key;
1516      if( s[0] == '#')
1517      {
1518        unsigned long value;
1519        char *ptr=0;
1520        if(s[1] == 'x' || s[1] == 'X')
1521        {
1522          value=strtoul((char const *)(s+2),&ptr,16);
1523        }else
1524        {
1525          value=strtoul((char const *)(s+1),&ptr,10);
1526        }
1527        if(ptr)
1528        {
1529          unsigned char utf8char[7];
1530          unsigned char const * const end=GStringRep::UCS4toUTF8(value,utf8char);
1531          ret+=GUTF8String((char const *)utf8char,(size_t)end-(size_t)utf8char);
1532        }else
1533        {
1534          ret += substr( amp_locn, semi_locn - amp_locn + 1 );
1535        }
1536      }else
1537      { 
1538        GPosition map_entry = ConvMap.contains( key );
1539        if( map_entry )
1540        {                           // Found in the conversion map, substitute
1541          ret += ConvMap[map_entry];
1542        } else
1543        {
1544          static const GMap<GUTF8String,GUTF8String> &Basic = BasicMap();
1545          GPosition map_entry = Basic.contains( key );
1546          if ( map_entry )
1547          {
1548            ret += Basic[map_entry];
1549          }else
1550          {
1551            ret += substr( amp_locn, len+2 );
1552          }
1553        }
1554      }
1555    }else
1556    {
1557      ret += substr( amp_locn, len+2 );
1558    }
1559    start_locn = semi_locn + 1;
1560//    DEBUG_MSG( "ret = '" << ret << "'\n" );
1561  }
1562
1563                                // Copy the end of the string to the output
1564  ret += substr( start_locn, length()-start_locn );
1565
1566//  DEBUG_MSG( "Unescaped string is '" << ret << "'\n" );
1567  return (ret == *this)?(*this):ret;
1568}
1569
1570GUTF8String
1571GUTF8String::fromEscaped(void) const
1572{
1573  const GMap<GUTF8String,GUTF8String> nill;
1574  return fromEscaped(nill);
1575}
1576
1577GP<GStringRep>
1578GStringRep::setat(int n, char ch) const
1579{
1580  GP<GStringRep> retval;
1581  if(n<0)
1582    n+=size;
1583  if (n < 0 || n>size) 
1584    GBaseString::throw_illegal_subscript();
1585  if(ch == data[n])
1586  {
1587    retval=const_cast<GStringRep *>(this);
1588  }else if(!ch)
1589  {
1590    retval=getbuf(n);
1591  }else
1592  {
1593    retval=getbuf((n<size)?size:n);
1594    retval->data[n]=ch;
1595    if(n == size)
1596      retval->data[n+1]=0;
1597  }
1598  return retval;
1599}
1600
1601#if defined(AUTOCONF) && defined(HAVE_VSNPRINTF)
1602# define USE_VSNPRINTF vsnprintf
1603#elif defined(WIN32) && !defined(__CYGWIN32__)
1604# define USE_VSNPRINTF _vsnprintf
1605#elif defined(linux)
1606# define USE_VSNPRINTF vsnprintf
1607#endif
1608 
1609GUTF8String &
1610GUTF8String::format(const char fmt[], ... )
1611{
1612  va_list args;
1613  va_start(args, fmt);
1614  return init(GStringRep::UTF8::create(fmt,args));
1615}
1616
1617GP<GStringRep>
1618GStringRep::UTF8::create_format(const char fmt[],...)
1619{
1620  va_list args;
1621  va_start(args, fmt);
1622  return create(fmt,args);
1623}
1624
1625GP<GStringRep>
1626GStringRep::vformat(va_list args) const
1627{
1628  GP<GStringRep> retval;
1629  if(size)
1630  {
1631    char const * const fmt=data;
1632    int buflen=32768;
1633    char *buffer;
1634    GPBuffer<char> gbuffer(buffer,buflen);
1635    ChangeLocale locale(LC_NUMERIC,(isNative()?0:"C"));
1636    // Format string
1637#ifdef USE_VSNPRINTF
1638    while(USE_VSNPRINTF(buffer, buflen, fmt, args)<0)
1639      {
1640        gbuffer.resize(0);
1641        gbuffer.resize(buflen+32768);
1642      }
1643    va_end(args);
1644#else
1645    buffer[buflen-1] = 0;
1646    vsprintf(buffer, fmt, args);
1647    va_end(args);
1648    if (buffer[buflen-1])
1649      {
1650        // This isn't as fatal since it is on the stack, but we
1651        // definitely should stop the current operation.
1652        G_THROW( ERR_MSG("GString.overwrite") );
1653      }
1654#endif
1655    retval=strdup((const char *)buffer);
1656  }
1657  // Go altering the string
1658  return retval;
1659}
1660
1661int 
1662GStringRep::search(char c, int from) const
1663{
1664  if (from<0)
1665    from += size;
1666  int retval=(-1);
1667  if (from>=0 && from<size)
1668  {
1669    char const *const s = strchr(data+from,c);
1670    if(s)
1671      retval=(int)((size_t)s-(size_t)data);
1672  }
1673  return retval;
1674}
1675
1676int 
1677GStringRep::search(char const *ptr, int from) const
1678{
1679  if(from<0)
1680  {
1681    from+=size;
1682    if(from<0)
1683      G_THROW( ERR_MSG("GString.bad_subscript") );
1684  }
1685  int retval=(-1);
1686  if (from>=0 && from<size)
1687  {
1688    char const *const s = strstr(data+from,ptr);
1689    if(s)
1690      retval=(int)((size_t)s-(size_t)data);
1691  }
1692  return retval;
1693}
1694
1695int 
1696GStringRep::rsearch(char c, int from) const
1697{
1698  if(from<0)
1699  {
1700    from+=size;
1701    if(from<0)
1702      G_THROW( ERR_MSG("GString.bad_subscript") );
1703  }
1704  int retval=(-1);
1705  if ((from>=0) && (from<size))
1706  {
1707    char const *const s = strrchr(data+from,c);
1708    if(s)
1709      retval=(int)((size_t)s-(size_t)data);
1710  }
1711  return retval;
1712}
1713
1714int 
1715GStringRep::rsearch(char const *ptr, int from) const
1716{
1717  if(from<0)
1718  {
1719    from+=size;
1720    if(from<0)
1721      G_THROW( ERR_MSG("GString.bad_subscript") );
1722  }
1723  int retval=(-1);
1724  for(int loc=from;(loc=search(ptr,loc)) >= 0;++loc)
1725    retval=loc;
1726  return retval;
1727}
1728
1729int
1730GStringRep::contains(const char accept[],int from) const
1731{
1732  if(from<0)
1733  {
1734    from+=size;
1735    if(from<0)
1736      G_THROW( ERR_MSG("GString.bad_subscript") );
1737  }
1738  int retval=(-1);
1739  if (accept && accept[0] && from>=0 && from<size)
1740  {
1741    char const * const src = data+from;
1742    char const *ptr=strpbrk(src,accept);
1743    if(ptr)
1744    {
1745      retval=(int)(ptr-src)+from;
1746    }
1747  }
1748  return retval;
1749}
1750
1751int
1752GStringRep::rcontains(const char accept[],int from) const
1753{
1754  int retval=(-1);
1755  while((from=contains(accept,from)) >= 0)
1756  {
1757    retval=from++;
1758  }
1759  return retval;
1760}
1761
1762bool
1763GBaseString::is_int(void) const
1764{
1765  bool isLong=!!ptr;
1766  if(isLong)
1767  {
1768    int endpos;
1769    (*this)->toLong(0,endpos);
1770    if(endpos>=0)
1771    {
1772      isLong=((*this)->nextNonSpace(endpos) == (int)length());
1773    }
1774  }
1775  return isLong;
1776}
1777
1778bool
1779GBaseString::is_float(void) const
1780{
1781  bool isDouble=!!ptr;
1782  if(isDouble)
1783  {
1784    int endpos;
1785    (*this)->toDouble(0,endpos);
1786    if(endpos>=0)
1787    {
1788      isDouble=((*this)->nextNonSpace(endpos) == (int)length());
1789    }
1790  }
1791  return isDouble;
1792}
1793
1794unsigned int 
1795hash(const GBaseString &str)
1796{
1797  unsigned int x = 0;
1798  const char *s = (const char*)str;
1799  while (*s) 
1800    x = x ^ (x<<6) ^ (unsigned char)(*s++);
1801  return x;
1802}
1803
1804void 
1805GBaseString::throw_illegal_subscript()
1806{
1807  G_THROW( ERR_MSG("GString.bad_subscript") );
1808}
1809
1810unsigned char *
1811GStringRep::UTF8::UCS4toString(
1812  const uint32_t w0,unsigned char *ptr, mbstate_t *) const
1813{
1814  return UCS4toUTF8(w0,ptr);
1815}
1816
1817int
1818GStringRep::UTF8::ncopy(
1819  wchar_t * const buf, const int buflen ) const
1820{
1821  int retval=(-1);
1822  if(buf && buflen)
1823  {
1824        buf[0]=0;
1825    if(data[0])
1826        {
1827      const size_t length=strlen(data);
1828      const unsigned char * const eptr=(const unsigned char *)(data+length);
1829          wchar_t *r=buf;
1830          wchar_t const * const rend=buf+buflen;
1831      for(const unsigned char *s=(const unsigned char *)data;(r<rend)&&(s<eptr)&&*s;)
1832          {
1833        const uint32_t w0=UTF8toUCS4(s,eptr);
1834        uint16_t w1;
1835        uint16_t w2=1;
1836        for(int count=(sizeof(wchar_t) == sizeof(w1))?UCS4toUTF16(w0,w1,w2):1;
1837            count&&(r<rend);
1838            --count,w1=w2,++r)
1839                {
1840                  r[0]=(sizeof(wchar_t) == sizeof(w1))?(wchar_t)w1:(wchar_t)w0;
1841                }
1842          }
1843          if(r<rend)
1844          {
1845            r[0]=0;
1846                retval=((size_t)r-(size_t)buf)/sizeof(wchar_t);
1847          }
1848        }else
1849        {
1850          retval=0;
1851        }
1852  }
1853  return retval;
1854}
1855
1856GP<GStringRep> 
1857GStringRep::UTF8::toNative(const EscapeMode escape) const
1858{
1859  GP<GStringRep> retval;
1860  if(data[0])
1861  {
1862    const size_t length=strlen(data);
1863    const unsigned char * const eptr=(const unsigned char *)(data+length);
1864    unsigned char *buf;
1865    GPBuffer<unsigned char> gbuf(buf,12*length+12); 
1866    unsigned char *r=buf;
1867    mbstate_t ps;
1868    memset(&ps,0,sizeof(mbstate_t));
1869    for(const unsigned char *s=(const unsigned char *)data;(s<eptr)&& *s;)
1870    {
1871      const uint32_t w0=UTF8toUCS4(s,eptr);
1872      const unsigned char * const r0=r;
1873      r=UCS4toNative(w0,r,&ps);
1874      if(r == r0)
1875      {
1876        if(escape == IS_ESCAPED)
1877        {
1878          sprintf((char *)r,"&#%lu;",(unsigned long)w0);
1879          r+=strlen((char *)r);
1880        }else
1881        {
1882          r=buf;
1883          break;
1884        }
1885      }
1886    }
1887    r[0]=0;
1888    retval = NATIVE_CREATE( (const char *)buf );
1889  } else
1890  {
1891    retval = NATIVE_CREATE( (unsigned int)0 );
1892  }
1893  return retval;
1894}
1895
1896GP<GStringRep>
1897GStringRep::UTF8::toUTF8(const bool nothrow) const
1898{
1899  if(!nothrow)
1900    G_THROW( ERR_MSG("GStringRep.UTF8ToUTF8") );
1901  return const_cast<GStringRep::UTF8 *>(this);
1902}
1903
1904// Tests if a string is legally encoded in the current character set.
1905bool 
1906GStringRep::UTF8::is_valid(void) const
1907{
1908  bool retval=true;
1909  if(data && size)
1910  {
1911    const unsigned char * const eptr=(const unsigned char *)(data+size);
1912    for(const unsigned char *s=(const unsigned char *)data;(s<eptr)&& *s;)
1913    {
1914      const unsigned char * const r=s;
1915      (void)UTF8toUCS4(s,eptr);
1916      if(r == s)
1917      {
1918        retval=false;
1919        break;
1920      }
1921    }
1922  }
1923  return retval;
1924}
1925
1926static inline uint32_t
1927add_char(uint32_t const U, unsigned char const * const r)
1928{
1929  uint32_t const C=r[0];
1930  return ((C|0x3f) == 0xbf)?((U<<6)|(C&0x3f)):0;
1931}
1932
1933uint32_t
1934GStringRep::UTF8toUCS4(
1935  unsigned char const *&s,void const * const eptr)
1936{
1937  uint32_t U=0;
1938  unsigned char const *r=s;
1939  if(r < eptr)
1940  {
1941    uint32_t const C1=r++[0];
1942    if(C1&0x80)
1943    {
1944      if(r < eptr)
1945      {
1946        U=C1;
1947        if((U=((C1&0x40)?add_char(U,r++):0)))
1948        {
1949          if(C1&0x20)
1950          {
1951            if(r < eptr)
1952            {
1953              if((U=add_char(U,r++)))
1954              {
1955                if(C1&0x10)
1956                {
1957                  if(r < eptr)
1958                  {
1959                    if((U=add_char(U,r++)))
1960                    {
1961                      if(C1&0x8)
1962                      {
1963                        if(r < eptr)
1964                        {
1965                          if((U=add_char(U,r++)))
1966                          {
1967                            if(C1&0x4)
1968                            {
1969                              if(r < eptr)
1970                              {
1971                                if((U=((!(C1&0x2))?(add_char(U,r++)&0x7fffffff):0)))
1972                                {
1973                                  s=r;
1974                                }else
1975                                {
1976                                  U=(unsigned int)(-1)-s++[0];
1977                                }
1978                              }else
1979                              {
1980                                U=0;
1981                              }
1982                            }else if((U=((U&0x4000000)?0:(U&0x3ffffff))))
1983                            {
1984                              s=r;
1985                            }
1986                          }else
1987                          {
1988                            U=(unsigned int)(-1)-s++[0];
1989                          }
1990                        }else
1991                        {
1992                          U=0;
1993                        }
1994                      }else if((U=((U&0x200000)?0:(U&0x1fffff))))
1995                      {
1996                        s=r;
1997                      }
1998                    }else
1999                    {
2000                      U=(unsigned int)(-1)-s++[0];
2001                    }
2002                  }else
2003                  {
2004                    U=0;
2005                  }
2006                }else if((U=((U&0x10000)?0:(U&0xffff))))
2007                {
2008                  s=r;
2009                }
2010              }else
2011              {
2012                U=(unsigned int)(-1)-s++[0];
2013              }
2014            }else
2015            {
2016              U=0;
2017            }
2018          }else if((U=((U&0x800)?0:(U&0x7ff))))
2019          {
2020            s=r;
2021          }
2022        }else
2023        {
2024          U=(unsigned int)(-1)-s++[0];
2025        }
2026      }else
2027      {
2028        U=0;
2029      }
2030    }else if((U=C1))
2031    {
2032      s=r;
2033    }
2034  }
2035  return U;
2036}
2037
2038unsigned char *
2039GStringRep::UCS4toUTF8(const uint32_t w,unsigned char *ptr)
2040{
2041  if(w <= 0x7f)
2042  {
2043    *ptr++ = (unsigned char)w;
2044  }
2045  else if(w <= 0x7ff)
2046  {
2047    *ptr++ = (unsigned char)((w>>6)|0xC0);
2048    *ptr++ = (unsigned char)((w|0x80)&0xBF);
2049  }
2050  else if(w <= 0xFFFF)
2051  {
2052    *ptr++ = (unsigned char)((w>>12)|0xE0);
2053    *ptr++ = (unsigned char)(((w>>6)|0x80)&0xBF);
2054    *ptr++ = (unsigned char)((w|0x80)&0xBF);
2055  }
2056  else if(w <= 0x1FFFFF)
2057  {
2058    *ptr++ = (unsigned char)((w>>18)|0xF0);
2059    *ptr++ = (unsigned char)(((w>>12)|0x80)&0xBF);
2060    *ptr++ = (unsigned char)(((w>>6)|0x80)&0xBF);
2061    *ptr++ = (unsigned char)((w|0x80)&0xBF);
2062  }
2063  else if(w <= 0x3FFFFFF)
2064  {
2065    *ptr++ = (unsigned char)((w>>24)|0xF8);
2066    *ptr++ = (unsigned char)(((w>>18)|0x80)&0xBF);
2067    *ptr++ = (unsigned char)(((w>>12)|0x80)&0xBF);
2068    *ptr++ = (unsigned char)(((w>>6)|0x80)&0xBF);
2069    *ptr++ = (unsigned char)((w|0x80)&0xBF);
2070  }
2071  else if(w <= 0x7FFFFFFF)
2072  {
2073    *ptr++ = (unsigned char)((w>>30)|0xFC);
2074    *ptr++ = (unsigned char)(((w>>24)|0x80)&0xBF);
2075    *ptr++ = (unsigned char)(((w>>18)|0x80)&0xBF);
2076    *ptr++ = (unsigned char)(((w>>12)|0x80)&0xBF);
2077    *ptr++ = (unsigned char)(((w>>6)|0x80)&0xBF);
2078    *ptr++ = (unsigned char)((w|0x80)&0xBF);
2079  }
2080  else
2081  { 
2082    *ptr++ = '?';
2083  }
2084  return ptr;
2085}
2086
2087   // Creates with a concat operation.
2088GP<GStringRep> 
2089GStringRep::concat( const char *s1, const GP<GStringRep> &s2) const
2090{
2091  GP<GStringRep> retval;
2092  if(s2)
2093  {
2094    retval=toThis(s2);
2095    if(s1 && s1[0])
2096    {
2097      if(retval)
2098      {
2099        retval=concat(s1,retval->data);
2100      }else
2101      {
2102        retval=strdup(s1);
2103      }
2104    }
2105  }else if(s1 && s1[0])
2106  {
2107    retval=strdup(s1);
2108  }
2109  return retval;
2110}
2111
2112   // Creates with a concat operation.
2113
2114GP<GStringRep> 
2115GStringRep::concat( const GP<GStringRep> &s1,const char *s2) const
2116{
2117  GP<GStringRep> retval;
2118  if(s1)
2119  {
2120    retval=toThis(s1);
2121    if(s2 && s2[0])
2122    {
2123      if(retval)
2124      {
2125        retval=retval->append(s2);
2126      }else
2127      {
2128        retval=strdup(s2);
2129      }
2130    }
2131  }else if(s2 && s2[0])
2132  {
2133    retval=strdup(s2);
2134  }
2135  return retval;
2136}
2137
2138GP<GStringRep> 
2139GStringRep::concat(const GP<GStringRep> &s1,const GP<GStringRep> &s2) const
2140{ 
2141  GP<GStringRep> retval; 
2142  if(s1)
2143  {
2144    retval=toThis(s1,s2);
2145    if(retval && s2)
2146    {
2147      retval=retval->append(toThis(s2));
2148    }
2149  }else if(s2)
2150  {
2151    retval=toThis(s2);
2152  }
2153  return retval;
2154}
2155
2156#ifdef WIN32
2157static const char *setlocale_win32(void)
2158{
2159  static const char *locale=setlocale(LC_ALL,0);
2160  if(! locale || (locale[0] == 'C' && !locale[1]))
2161  {
2162    locale=setlocale(LC_ALL,"");
2163  }
2164  return locale;
2165}
2166const char *setlocale_win32_var = setlocale_win32();
2167#endif
2168
2169GStringRep::GStringRep(void)
2170{
2171  size=0;
2172  data=0;
2173}
2174
2175GStringRep::~GStringRep()
2176{
2177  if(data)
2178  {
2179    data[0]=0;
2180    ::operator delete(data);
2181  }
2182  data=0;
2183}
2184
2185GStringRep::UTF8::UTF8(void) {}
2186
2187GStringRep::UTF8::~UTF8() {}
2188
2189int
2190GStringRep::cmp(const char *s1,const int len) const
2191{
2192  return cmp(data,s1,len);
2193}
2194
2195int
2196GStringRep::cmp(const char *s1, const char *s2,const int len)
2197{
2198  return (len
2199   ?((s1&&s1[0])
2200      ?((s2&&s2[0])
2201        ?((len>0)
2202          ?strncmp(s1,s2,len)
2203          :strcmp(s1,s2))
2204        :1)
2205      :((s2&&s2[0])?(-1):0))
2206   :0);
2207}
2208
2209int 
2210GStringRep::cmp(const GP<GStringRep> &s1, const GP<GStringRep> &s2,
2211  const int len )
2212{
2213  return (s1?(s1->cmp(s2,len)):cmp(0,(s2?(s2->data):0),len));
2214}
2215
2216int 
2217GStringRep::cmp(const GP<GStringRep> &s1, const char *s2, 
2218  const int len )
2219{
2220  return cmp((s1?s1->data:0),s2,len);
2221}
2222
2223int 
2224GStringRep::cmp(const char *s1, const GP<GStringRep> &s2,
2225  const int len )
2226{
2227  return cmp(s1,(s2?(s2->data):0),len);
2228}
2229
2230int
2231GStringRep::UTF8::cmp(const GP<GStringRep> &s2,const int len) const
2232{
2233  int retval;
2234  if(s2)
2235  {
2236    if(s2->isNative())
2237    {
2238      GP<GStringRep> r(s2->toUTF8(true));
2239      if(r)
2240      {
2241        retval=GStringRep::cmp(data,r->data,len);
2242      }else
2243      {
2244        retval=-(s2->cmp(toNative(NOT_ESCAPED),len));
2245      }
2246    }else
2247    {
2248      retval=GStringRep::cmp(data,s2->data,len);
2249    }
2250  }else
2251  { 
2252    retval=GStringRep::cmp(data,0,len);
2253  }
2254  return retval;
2255} 
2256
2257int
2258GStringRep::UTF8::toInt() const
2259{
2260  int endpos;
2261  return (int)toLong(0,endpos);
2262}
2263
2264static inline long
2265Cstrtol(char *data,char **edata, const int base)
2266{
2267  GStringRep::ChangeLocale locale(LC_NUMERIC,"C");
2268  while (data && *data==' ') data++;
2269  return strtol(data,edata,base);
2270}
2271
2272long 
2273GStringRep::UTF8::toLong(
2274  const int pos, int &endpos, const int base) const
2275{
2276  char *edata=0;
2277  long retval=Cstrtol(data+pos,&edata, base);
2278  if(edata)
2279  {
2280    endpos=edata-data;
2281  }else
2282  {
2283    endpos=(-1);
2284    GP<GStringRep> ptr=ptr->strdup(data+pos);
2285    if(ptr)
2286      ptr=ptr->toNative(NOT_ESCAPED);
2287    if(ptr)
2288    {
2289      int xendpos;
2290      retval=ptr->toLong(0,xendpos,base);
2291      if(xendpos> 0)
2292      {
2293        endpos=(int)size;
2294        ptr=ptr->strdup(data+xendpos);
2295        if(ptr)
2296        {
2297          ptr=ptr->toUTF8(true);
2298          if(ptr)
2299          {
2300            endpos-=(int)(ptr->size);
2301          }
2302        }
2303      }
2304    }
2305  }
2306  return retval;
2307}
2308
2309static inline unsigned long
2310Cstrtoul(char *data,char **edata, const int base)
2311{
2312  GStringRep::ChangeLocale locale(LC_NUMERIC,"C");
2313  while (data && *data==' ') data++;
2314  return strtoul(data,edata,base);
2315}
2316
2317unsigned long 
2318GStringRep::UTF8::toULong(
2319  const int pos, int &endpos, const int base) const
2320{
2321  char *edata=0;
2322  unsigned long retval=Cstrtoul(data+pos,&edata, base);
2323  if(edata)
2324  {
2325    endpos=edata-data;
2326  }else
2327  {
2328    endpos=(-1);
2329    GP<GStringRep> ptr=ptr->strdup(data+pos);
2330    if(ptr)
2331      ptr=ptr->toNative(NOT_ESCAPED);
2332    if(ptr)
2333    {
2334      int xendpos;
2335      retval=ptr->toULong(0,xendpos,base);
2336      if(xendpos> 0)
2337      {
2338        endpos=(int)size;
2339        ptr=ptr->strdup(data+xendpos);
2340        if(ptr)
2341        {
2342          ptr=ptr->toUTF8(true);
2343          if(ptr)
2344          {
2345            endpos-=(int)(ptr->size);
2346          }
2347        }
2348      }
2349    }
2350  }
2351  return retval;
2352}
2353
2354static inline double
2355Cstrtod(char *data,char **edata)
2356{
2357  GStringRep::ChangeLocale locale(LC_NUMERIC,"C");
2358  while (data && *data==' ') data++;
2359  return strtod(data,edata);
2360}
2361
2362double
2363GStringRep::UTF8::toDouble(const int pos, int &endpos) const
2364{
2365  char *edata=0;
2366  double retval=Cstrtod(data+pos,&edata);
2367  if(edata)
2368  {
2369    endpos=edata-data;
2370  }else
2371  {
2372    endpos=(-1);
2373    GP<GStringRep> ptr=ptr->strdup(data+pos);
2374    if(ptr)
2375      ptr=ptr->toNative(NOT_ESCAPED);
2376    if(ptr)
2377    {
2378      int xendpos;
2379      retval=ptr->toDouble(0,xendpos);
2380      if(xendpos >= 0)
2381      {
2382        endpos=(int)size;
2383        ptr=ptr->strdup(data+xendpos);
2384        if(ptr)
2385        {
2386          ptr=ptr->toUTF8(true);
2387          if(ptr)
2388          {
2389            endpos-=(int)(ptr->size);
2390          }
2391        }
2392      }
2393    }
2394  }
2395  return retval;
2396}
2397
2398int 
2399GStringRep::getUCS4(uint32_t &w, const int from) const
2400{
2401  int retval;
2402  if(from>=size)
2403  {
2404    w=0;
2405    retval=size;
2406  }else if(from<0)
2407  {
2408    w=(unsigned int)(-1);
2409    retval=(-1);
2410  }else
2411  {
2412    const char *source=data+from;
2413    w=getValidUCS4(source);
2414    retval=(int)((size_t)source-(size_t)data);
2415  } 
2416  return retval;
2417}
2418
2419
2420uint32_t
2421GStringRep::UTF8::getValidUCS4(const char *&source) const
2422{
2423  return GStringRep::UTF8toUCS4((const unsigned char *&)source,data+size);
2424}
2425
2426int
2427GStringRep::nextNonSpace(const int from,const int len) const
2428{
2429  return nextCharType(giswspace,from,len,true);
2430}
2431
2432int
2433GStringRep::nextSpace(const int from,const int len) const
2434{
2435  return nextCharType(giswspace,from,len,false);
2436}
2437
2438int
2439GStringRep::nextChar(const int from) const
2440{
2441  char const * xptr=data+from;
2442  (void)getValidUCS4(xptr);
2443  return (int)((size_t)xptr-(size_t)data);
2444}
2445
2446int 
2447GStringRep::firstEndSpace(int from,const int len) const
2448{
2449  const int xsize=(len<0)?size:(from+len);
2450  const int ysize=(size<xsize)?size:xsize;
2451  int retval=ysize;
2452  while(from<ysize)
2453  {
2454    from=nextNonSpace(from,ysize-from);
2455    if(from < size)
2456    {
2457      const int r=nextSpace(from,ysize-from);
2458      // If a character isn't legal, then it will return
2459      // tru for both nextSpace and nextNonSpace.
2460      if(r == from)
2461      {
2462        from++;
2463      }else
2464      {
2465        from=retval=r;
2466      }
2467    }
2468  }
2469  return retval;
2470}
2471
2472int
2473GStringRep::UCS4toUTF16(
2474  const uint32_t w,uint16_t &w1, uint16_t &w2)
2475{
2476  int retval;
2477  if(w<0x10000)
2478  {
2479    w1=(uint16_t)w;
2480    w2=0;
2481    retval=1;
2482  }else
2483  {
2484    w1=(uint16_t)((((w-0x10000)>>10)&0x3ff)+0xD800);
2485    w2=(uint16_t)((w&0x3ff)+0xDC00);
2486    retval=2;
2487  }
2488  return retval;
2489}
2490
2491int
2492GStringRep::UTF16toUCS4(
2493  uint32_t &U,uint16_t const * const s,void const * const eptr)
2494{
2495  int retval=0;
2496  U=0;
2497  uint16_t const * const r=s+1;
2498  if(r <= eptr)
2499  {
2500    uint32_t const W1=s[0];
2501    if((W1<0xD800)||(W1>0xDFFF))
2502    {
2503      if((U=W1))
2504      {
2505        retval=1;
2506      }
2507    }else if(W1<=0xDBFF)
2508    {
2509      uint16_t const * const rr=r+1;
2510      if(rr <= eptr)
2511      {
2512        uint32_t const W2=s[1];
2513        if(((W2>=0xDC00)||(W2<=0xDFFF))&&((U=(0x10000+((W1&0x3ff)<<10))|(W2&0x3ff))))
2514        {
2515          retval=2;
2516        }else
2517        {
2518          retval=(-1);
2519        }
2520      }
2521    }
2522  }
2523  return retval;
2524}
2525
2526
2527//bcr
2528
2529GUTF8String&
2530GUTF8String::operator+= (char ch)
2531{
2532  return init(
2533    GStringRep::UTF8::create((const char*)*this,
2534    GStringRep::UTF8::create(&ch,0,1)));
2535}
2536
2537GUTF8String&
2538GUTF8String::operator+= (const char *str)
2539{
2540  return init(GStringRep::UTF8::create(*this,str));
2541}
2542
2543GUTF8String&
2544GUTF8String::operator+= (const GBaseString &str)
2545{
2546  return init(GStringRep::UTF8::create(*this,str));
2547}
2548
2549GUTF8String
2550GUTF8String::substr(int from, int len) const
2551{ return GUTF8String(*this, from, len); }
2552
2553GUTF8String
2554GUTF8String::operator+(const GBaseString &s2) const
2555{ return GStringRep::UTF8::create(*this,s2); }
2556
2557GUTF8String
2558GUTF8String::operator+(const GUTF8String &s2) const
2559{ return GStringRep::UTF8::create(*this,s2); }
2560
2561GUTF8String
2562GUTF8String::operator+(const char    *s2) const
2563{ return GStringRep::UTF8::create(*this,s2); }
2564
2565char *
2566GUTF8String::getbuf(int n)
2567{
2568  if(ptr)
2569    init((*this)->getbuf(n));
2570  else if(n>0)
2571    init(GStringRep::UTF8::create(n));
2572  else
2573    init(0);
2574  return ptr?((*this)->data):0;
2575}
2576
2577void 
2578GUTF8String::setat(const int n, const char ch)
2579{
2580  if((!n)&&(!ptr))
2581  {
2582    init(GStringRep::UTF8::create(&ch,0,1));
2583  }else
2584  {
2585    init((*this)->setat(CheckSubscript(n),ch));
2586  }
2587}
2588
2589GP<GStringRep>
2590GStringRep::UTF8ToNative( const char *s, const EscapeMode escape )
2591{
2592  return GStringRep::UTF8::create(s)->toNative(escape);
2593}
2594
2595GUTF8String::GUTF8String(const char dat)
2596{ init(GStringRep::UTF8::create(&dat,0,1)); }
2597
2598GUTF8String::GUTF8String(const GUTF8String &fmt, va_list &args)
2599{ 
2600  if (fmt.ptr)
2601    init(fmt->vformat(args));
2602  else 
2603    init(fmt); 
2604}
2605
2606GUTF8String::GUTF8String(const char *str)
2607{ init(GStringRep::UTF8::create(str)); }
2608
2609GUTF8String::GUTF8String(const unsigned char *str)
2610{ init(GStringRep::UTF8::create((const char *)str)); }
2611
2612GUTF8String::GUTF8String(const uint16_t *str)
2613{ init(GStringRep::UTF8::create(str,0,-1)); }
2614
2615GUTF8String::GUTF8String(const uint32_t *str)
2616{ init(GStringRep::UTF8::create(str,0,-1)); }
2617
2618GUTF8String::GUTF8String(const char *dat, unsigned int len)
2619{ init(GStringRep::UTF8::create(dat,0,((int)len<0)?(-1):(int)len)); }
2620
2621GUTF8String::GUTF8String(const uint16_t *dat, unsigned int len)
2622{ init(GStringRep::UTF8::create(dat,0,((int)len<0)?(-1):(int)len)); }
2623
2624GUTF8String::GUTF8String(const uint32_t *dat, unsigned int len)
2625{ init(GStringRep::UTF8::create(dat,0,((int)len<0)?(-1):(int)len)); }
2626
2627GUTF8String::GUTF8String(const GBaseString &gs, int from, int len)
2628{ init(GStringRep::UTF8::create(gs,from,((int)len<0)?(-1):(int)len)); }
2629
2630GUTF8String::GUTF8String(const int number)
2631{ init(GStringRep::UTF8::create_format("%d",number)); }
2632
2633GUTF8String::GUTF8String(const double number)
2634{ init(GStringRep::UTF8::create_format("%f",number)); }
2635
2636GUTF8String& GUTF8String::operator= (const char str)
2637{ return init(GStringRep::UTF8::create(&str,0,1)); }
2638
2639GUTF8String& GUTF8String::operator= (const char *str)
2640{ return init(GStringRep::UTF8::create(str)); }
2641
2642GUTF8String GBaseString::operator+(const GUTF8String &s2) const
2643{ return GStringRep::UTF8::create(*this,s2); }
2644
2645#if HAS_WCHAR
2646GUTF8String
2647GNativeString::operator+(const GUTF8String &s2) const
2648{
2649  if (ptr)
2650    return GStringRep::UTF8::create((*this)->toUTF8(true),s2);
2651  else
2652    return GStringRep::UTF8::create((*this),s2);
2653}
2654#endif
2655
2656GUTF8String
2657GUTF8String::operator+(const GNativeString &s2) const
2658{
2659  GP<GStringRep> g = s2;
2660  if (s2.ptr)
2661    g = s2->toUTF8(true);
2662  return GStringRep::UTF8::create(*this,g);
2663}
2664
2665GUTF8String
2666operator+(const char    *s1, const GUTF8String &s2)
2667{ return GStringRep::UTF8::create(s1,s2); }
2668
2669#if HAS_WCHAR
2670GNativeString
2671operator+(const char    *s1, const GNativeString &s2)
2672{ return GStringRep::Native::create(s1,s2); }
2673
2674GNativeString&
2675GNativeString::operator+= (char ch)
2676{
2677  char s[2]; s[0]=ch; s[1]=0;
2678  return init(GStringRep::Native::create((const char*)*this, s));
2679}
2680
2681GNativeString&
2682GNativeString::operator+= (const char *str)
2683{
2684  return init(GStringRep::Native::create(*this,str));
2685}
2686
2687GNativeString&
2688GNativeString::operator+= (const GBaseString &str)
2689{
2690  return init(GStringRep::Native::create(*this,str));
2691}
2692
2693GNativeString
2694GNativeString::operator+(const GBaseString &s2) const
2695{ return GStringRep::Native::create(*this,s2); }
2696
2697GNativeString
2698GNativeString::operator+(const GNativeString &s2) const
2699{ return GStringRep::Native::create(*this,s2); }
2700
2701GNativeString
2702GNativeString::operator+(const char    *s2) const
2703{ return GStringRep::Native::create(*this,s2); }
2704
2705char *
2706GNativeString::getbuf(int n)
2707{
2708  if(ptr)
2709    init((*this)->getbuf(n));
2710  else if(n>0)
2711    init(GStringRep::Native::create(n));
2712  else
2713    init(0);
2714  return ptr?((*this)->data):0;
2715}
2716
2717void
2718GNativeString::setat(const int n, const char ch)
2719{
2720  if((!n)&&(!ptr))
2721  {
2722    init(GStringRep::Native::create(&ch,0,1));
2723  }else
2724  {
2725    init((*this)->setat(CheckSubscript(n),ch));
2726  }
2727}
2728
2729#endif
2730
2731
2732#ifdef HAVE_NAMESPACES
2733}
2734# ifndef NOT_USING_DJVU_NAMESPACE
2735using namespace DJVU;
2736# endif
2737#endif
Note: See TracBrowser for help on using the repository browser.