source: trunk/libdjvu/GString.cpp @ 17

Last change on this file since 17 was 17, checked in by Eugene Romanenko, 15 years ago

update makefiles, remove absolute paths, update djvulibre to version 3.5.17

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