source: trunk/libdjvu/GString.cpp @ 206

Last change on this file since 206 was 206, checked in by Eugene Romanenko, 14 years ago

DJVU plugin: djvulibre updated to version 3.5.19

File size: 60.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.24 2007/03/25 20:48:32 leonb Exp $
57// $Name: release_3_5_19 $
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 unsigned short *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 unsigned long *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 unsigned short *s,const int start,const int length=(-1));
340  static GP<GStringRep> create(
341    const unsigned long *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 unsigned long 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 unsigned long 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 unsigned short *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 unsigned long *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 unsigned long 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 unsigned long w0,unsigned char *ptr, mbstate_t *ps)
547{
548  unsigned short w1;
549  unsigned short 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(unsigned long))
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(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            unsigned short s[2];
605            s[0]=w;
606            unsigned long 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    retval=UTF8ToNative(false,escape) ;
685    if(!retval.length())
686    {
687      retval=(const char*)*this;
688    }
689  }
690  return retval;
691}
692
693GUTF8String
694GBaseString::NativeToUTF8(void) const
695{
696  GP<GStringRep> retval;
697  if(length())
698  {
699    const char *source=(*this);
700#if DO_CHANGELOCALE
701    GUTF8String lc_ctype=setlocale(LC_CTYPE,0);
702#endif
703    bool repeat;
704    for(repeat=true;;repeat=false)
705    {
706      if( (retval=GStringRep::NativeToUTF8(source)) )
707      {
708        if(GStringRep::cmp(retval->toNative(),source))
709        {
710          retval=GStringRep::UTF8::create((unsigned int)0);
711        }
712      }
713#if DO_CHANGELOCALE
714      if(!repeat || retval || (lc_ctype == setlocale(LC_CTYPE,"")))
715#endif
716        break;
717    }
718#if DO_CHANGELOCALE
719    if(!repeat)
720    {
721      setlocale(LC_CTYPE,(const char *)lc_ctype);
722    }
723#endif
724  }
725  return GUTF8String(retval);
726}
727
728GUTF8String
729GBaseString::getNative2UTF8(void) const
730{ //MBCS cvt
731
732   // We don't want to do a transform this
733   // if we already are in the given type.
734//   if (isUTF8()) return *this;
735   
736  const size_t slen=length()+1;
737  GUTF8String retval;
738  if(slen > 1)
739  {
740    retval=NativeToUTF8();
741    if(!retval.length())
742    {
743      retval=(const char *)(*this);
744    }
745  }
746  return retval;
747} /*MBCS*/
748
749int
750GStringRep::Native::cmp(const GP<GStringRep> &s2,const int len) const
751{
752  int retval;
753  if(s2)
754  {
755    if(s2->isUTF8())
756    {
757      const GP<GStringRep> r(toUTF8(true));
758      if(r)
759      {
760        retval=GStringRep::cmp(r->data,s2->data,len);
761      }else
762      {
763        retval=cmp(s2->toNative(NOT_ESCAPED),len);
764      }
765    }else
766    {
767      retval=GStringRep::cmp(data,s2->data,len);
768    }
769  }else
770  {
771    retval=GStringRep::cmp(data,0,len);
772  }
773  return retval;
774}
775
776int
777GStringRep::Native::toInt() const
778{
779  return atoi(data);
780}
781
782long
783GStringRep::Native::toLong(
784  const int pos, int &endpos, const int base) const
785{
786   char *edata=0;
787   const long retval=strtol(data+pos, &edata, base);
788   if(edata)
789   {
790     endpos=(int)((size_t)edata-(size_t)data);
791   }else
792   {
793     endpos=(-1);
794   }
795   return retval;
796}
797
798unsigned long
799GStringRep::Native::toULong(
800  const int pos, int &endpos, const int base) const
801{
802   char *edata=0;
803   const unsigned long retval=strtoul(data+pos, &edata, base);
804   if(edata)
805   {
806     endpos=(int)((size_t)edata-(size_t)data);
807   }else
808   {
809     endpos=(-1);
810   }
811   return retval;
812}
813
814double
815GStringRep::Native::toDouble(
816  const int pos, int &endpos) const
817{
818   char *edata=0;
819   const double retval=strtod(data+pos, &edata);
820   if(edata)
821   {
822     endpos=(int)((size_t)edata-(size_t)data);
823   }else
824   {
825     endpos=(-1);
826   }
827   return retval;
828}
829
830unsigned long
831GStringRep::Native::getValidUCS4(const char *&source) const
832{
833  unsigned long retval=0;
834  int n=(int)((size_t)size+(size_t)data-(size_t)source);
835  if(source && (n > 0))
836  {
837    mbstate_t ps;
838    //(void)mbrlen(source, n, &ps);
839    memset(&ps,0,sizeof(mbstate_t));
840    wchar_t wt;
841    const int len=mbrtowc(&wt,source,n,&ps); 
842    if(len>=0)
843    {
844      if(sizeof(wchar_t) == sizeof(unsigned short))
845      {
846        source+=len;
847        unsigned short s[2];
848        s[0]=(unsigned short)wt;
849        if(UTF16toUCS4(retval,s,s+1)<=0)
850        {
851          if((n-=len)>0)
852          {
853            const int len=mbrtowc(&wt,source,n,&ps);
854            if(len>=0)
855            {
856              s[1]=(unsigned short)wt;
857              unsigned long w;
858              if(UTF16toUCS4(w,s,s+2)>0)
859              {
860                source+=len;
861                retval=w;
862              }
863            }
864          }
865        }
866      }else
867      {
868        retval=(unsigned long)wt;
869        source++;
870      } 
871    }else
872    {
873      source++;
874    }
875  }
876  return retval;
877}
878
879// Tests if a string is legally encoded in the current character set.
880bool 
881GStringRep::Native::is_valid(void) const
882{
883  bool retval=true;
884  if(data && size)
885  {
886    size_t n=size;
887    const char *s=data;
888    mbstate_t ps;
889    //(void)mbrlen(s, n, &ps);
890    memset(&ps,0,sizeof(mbstate_t));
891    do
892    {
893      size_t m=mbrlen(s,n,&ps);
894      if(m > n)
895      {
896        retval=false;
897        break;
898      }else if(m)
899      {
900        s+=m;
901        n-=m;
902      }else
903      {
904        break;
905      }
906    } while(n);
907  }
908  return retval;
909}
910
911// These are dummy functions.
912void 
913GStringRep::set_remainder(void const * const, const unsigned int,
914  const EncodeType) {}
915void 
916GStringRep::set_remainder(void const * const, const unsigned int,
917  const GP<GStringRep> &encoding) {}
918void
919GStringRep::set_remainder( const GP<GStringRep::Unicode> &) {}
920
921GP<GStringRep::Unicode>
922GStringRep::get_remainder( void ) const
923{
924  return 0;
925}
926
927GNativeString::GNativeString(const char dat)
928{
929  init(GStringRep::Native::create(&dat,0,1));
930}
931
932GNativeString::GNativeString(const char *str)
933{
934  init(GStringRep::Native::create(str));
935}
936
937GNativeString::GNativeString(const unsigned char *str)
938{
939  init(GStringRep::Native::create((const char *)str));
940}
941
942GNativeString::GNativeString(const unsigned short *str)
943{
944  init(GStringRep::Native::create(str,0,-1));
945}
946
947GNativeString::GNativeString(const unsigned long *str)
948{
949  init(GStringRep::Native::create(str,0,-1));
950}
951
952GNativeString::GNativeString(const char *dat, unsigned int len)
953{
954  init(
955    GStringRep::Native::create(dat,0,((int)len<0)?(-1):(int)len));
956}
957
958GNativeString::GNativeString(const unsigned short *dat, unsigned int len)
959{
960  init(
961    GStringRep::Native::create(dat,0,((int)len<0)?(-1):(int)len));
962}
963
964GNativeString::GNativeString(const unsigned long *dat, unsigned int len)
965{
966  init(
967    GStringRep::Native::create(dat,0,((int)len<0)?(-1):(int)len));
968}
969
970GNativeString::GNativeString(const GNativeString &str)
971{
972  init(str);
973}
974
975GNativeString::GNativeString(const GBaseString &gs, int from, int len)
976{
977  init(
978    GStringRep::Native::create(gs,from,((int)len<0)?(-1):(int)len));
979}
980
981GNativeString::GNativeString(const int number)
982{
983  init(GStringRep::Native::create_format("%d",number));
984}
985
986GNativeString::GNativeString(const double number)
987{
988  init(GStringRep::Native::create_format("%f",number));
989}
990
991GNativeString&
992GNativeString::operator= (const char str)
993{ return init(GStringRep::Native::create(&str,0,1)); }
994
995GNativeString&
996GNativeString::operator= (const char *str)
997{ return init(GStringRep::Native::create(str)); }
998
999GNativeString
1000GBaseString::operator+(const GNativeString &s2) const
1001{
1002  return GStringRep::Native::create(*this,s2);
1003}
1004
1005GP<GStringRep>
1006GStringRep::NativeToUTF8( const char *s )
1007{
1008  return GStringRep::Native::create(s)->toUTF8();
1009}
1010
1011#endif // HAS_WCHAR
1012
1013template <class TYPE>
1014GP<GStringRep>
1015GStringRep::create(const unsigned int sz, TYPE *)
1016{
1017  GP<GStringRep> gaddr;
1018  if (sz > 0)
1019  {
1020    GStringRep *addr;
1021    gaddr=(addr=new TYPE);
1022    addr->data=(char *)(::operator new(sz+1));
1023    addr->size = sz;
1024    addr->data[sz] = 0;
1025  }
1026  return gaddr;
1027}
1028
1029GP<GStringRep>
1030GStringRep::strdup(const char *s) const
1031{
1032  GP<GStringRep> retval;
1033  const int length=s?strlen(s):0;
1034  if(length>0)
1035  {
1036    retval=blank(length);
1037    char const * const end=s+length;
1038    char *ptr=retval->data;
1039    for(;*s&&(s!=end);ptr++)
1040    {
1041      ptr[0]=s++[0];
1042    }
1043    ptr[0]=0;
1044  }
1045  return retval;
1046}
1047
1048GP<GStringRep>
1049GStringRep::substr(const char *s,const int start,const int len) const
1050{
1051  GP<GStringRep> retval;
1052  if(s && s[0])
1053  {
1054    const unsigned int length=(start<0 || len<0)?(unsigned int)strlen(s):(unsigned int)(-1);
1055    const char *startptr, *endptr;
1056    if(start<0)
1057    {
1058      startptr=s+length+start;
1059      if(startptr<s)
1060        startptr=s;
1061    }else
1062    { 
1063      startptr=s;
1064      for(const char * const ptr=s+start;(startptr<ptr)&&*startptr;++startptr)
1065        EMPTY_LOOP;
1066    }
1067    if(len<0)
1068    {
1069      if(s+length+1 < startptr+len)
1070      {
1071        endptr=startptr;
1072      }else
1073      {
1074        endptr=s+length+1+len;
1075      } 
1076    }else
1077    {
1078      endptr=startptr;
1079      for(const char * const ptr=startptr+len;(endptr<ptr)&&*endptr;++endptr)
1080        EMPTY_LOOP;
1081    }
1082    if(endptr>startptr)
1083    {
1084      retval=blank((size_t)(endptr-startptr));
1085      char *data=retval->data;
1086      for(; (startptr<endptr) && *startptr; ++startptr,++data)
1087      {
1088        data[0]=startptr[0];
1089      }
1090      data[0]=0;
1091    }
1092  }
1093  return retval;
1094}
1095
1096GP<GStringRep>
1097GStringRep::substr(const unsigned short *s,const int start,const int len) const
1098{
1099  GP<GStringRep> retval;
1100  if(s && s[0])
1101  {
1102    unsigned short const *eptr;
1103    if(len<0)
1104    {
1105      for(eptr=s;eptr[0];++eptr)
1106        EMPTY_LOOP;
1107    }else
1108    {
1109      eptr=&(s[len]);
1110    }
1111    s=&s[start];
1112    if((size_t)s<(size_t)eptr)
1113    {
1114      mbstate_t ps;
1115      memset(&ps,0,sizeof(mbstate_t));
1116      unsigned char *buf,*ptr;
1117      GPBuffer<unsigned char> gbuf(buf,(((size_t)eptr-(size_t)s)/2)*3+7);
1118      for(ptr=buf;s[0];)
1119      {
1120        unsigned long w;
1121        int i=UTF16toUCS4(w,s,eptr);
1122        if(i<=0)
1123          break;
1124        s+=i;
1125        ptr=UCS4toString(w,ptr,&ps);
1126      }
1127      ptr[0]=0;
1128      retval = strdup( (const char *)buf );
1129    }
1130  }
1131  return retval;
1132}
1133
1134GP<GStringRep>
1135GStringRep::substr(const unsigned long *s,const int start,const int len) const
1136{
1137  GP<GStringRep> retval;
1138  if(s && s[0])
1139  {
1140    unsigned long const *eptr;
1141    if(len<0)
1142    {
1143      for(eptr=s;eptr[0];++eptr)
1144        EMPTY_LOOP;
1145    }else
1146    {
1147      eptr=&(s[len]);
1148    }
1149    s=&s[start];
1150    if((size_t)s<(size_t)eptr)
1151    {
1152      mbstate_t ps;
1153      memset(&ps,0,sizeof(mbstate_t));
1154      unsigned char *buf,*ptr;
1155      GPBuffer<unsigned char> gbuf(buf,((((size_t)eptr-(size_t)s))/4)*6+7);
1156      for(ptr=buf;s[0];++s)
1157      {
1158        ptr=UCS4toString(s[0],ptr,&ps);
1159      }
1160      ptr[0]=0;
1161      retval = strdup( (const char *)buf );
1162    }
1163  }
1164  return retval;
1165}
1166
1167GP<GStringRep>
1168GStringRep::append(const char *s2) const
1169{
1170  GP<GStringRep> retval;
1171  if(s2)
1172  {
1173    retval=concat(data,s2);
1174  }else
1175  {
1176    retval=const_cast<GStringRep *>(this);
1177  }
1178  return retval;
1179}
1180
1181GP<GStringRep>
1182GStringRep::UTF8::append(const GP<GStringRep> &s2) const
1183{
1184  GP<GStringRep> retval;
1185  if(s2)
1186  {
1187    if(s2->isNative())
1188    {
1189      G_THROW( ERR_MSG("GStringRep.appendNativeToUTF8") );
1190    }
1191    retval=concat(data,s2->data);
1192  }else
1193  {
1194    retval=const_cast<GStringRep::UTF8 *>(this); 
1195  }
1196  return retval;
1197}
1198
1199GP<GStringRep>
1200GStringRep::concat(const char *s1,const char *s2) const
1201{
1202  const int length1=(s1?strlen(s1):0);
1203  const int length2=(s2?strlen(s2):0);
1204  const int length=length1+length2;
1205  GP<GStringRep> retval;
1206  if(length>0)
1207  {
1208    retval=blank(length);
1209    GStringRep &r=*retval;
1210    if(length1)
1211    {
1212      strcpy(r.data,s1);
1213      if(length2)
1214        strcat(r.data,s2);
1215    }else
1216    {
1217      strcpy(r.data,s2);
1218    }
1219  }
1220  return retval;
1221}
1222
1223const char *GBaseString::nullstr = "";
1224
1225void
1226GBaseString::empty( void )
1227{
1228  init(0);
1229}
1230
1231GP<GStringRep>
1232GStringRep::getbuf(int n) const
1233{
1234  GP<GStringRep> retval;
1235  if(n< 0)
1236    n=strlen(data);
1237  if(n>0)
1238  {
1239    retval=blank(n);
1240    char *ndata=retval->data;
1241    strncpy(ndata,data,n);
1242    ndata[n]=0;
1243  }
1244  return retval;
1245}
1246
1247const char *
1248GStringRep::isCharType(
1249  bool (*xiswtest)(const unsigned long wc), const char *ptr, const bool reverse) const
1250{
1251  char const * xptr=ptr;
1252  const unsigned long w=getValidUCS4(xptr);
1253  if((ptr != xptr)
1254    &&(((sizeof(wchar_t) == 2)&&(w&~0xffff))
1255      ||(reverse?(!xiswtest(w)):xiswtest(w))))
1256  {
1257    ptr=xptr;
1258  }
1259  return ptr;
1260}
1261
1262int
1263GStringRep::nextCharType(
1264  bool (*xiswtest)(const unsigned long wc), const int from, const int len,
1265  const bool reverse) const
1266{
1267  // We want to return the position of the next
1268  // non white space starting from the #from#
1269  // location.  isspace should work in any locale
1270  // so we should only need to do this for the non-
1271  // native locales (UTF8)
1272  int retval;
1273  if(from<size)
1274  {
1275    retval=from;
1276    const char * ptr = data+from;
1277    for( const char * const eptr=ptr+((len<0)?(size-from):len);
1278      (ptr<eptr) && *ptr;)
1279    {
1280       // Skip characters that fail the isCharType test
1281      char const * const xptr=isCharType(xiswtest,ptr,!reverse);
1282      if(xptr == ptr)
1283        break;
1284      ptr=xptr;
1285    }
1286    retval=(int)((size_t)ptr-(size_t)data);
1287  }else
1288  {
1289    retval=size;
1290  }
1291  return retval;
1292}
1293
1294bool
1295GStringRep::giswspace(const unsigned long w)
1296{
1297#if HAS_WCTYPE
1298  return 
1299    ((sizeof(wchar_t) == 2)&&(w&~0xffff))
1300    ||((unsigned long)iswspace((wchar_t)w))
1301    ||((w == '\r')||(w == '\n'));
1302#else
1303  return 
1304    (w&~0xff)?(true):(((unsigned long)isspace((char)w))||((w == '\r')||(w == '\n')));
1305#endif
1306}
1307
1308bool
1309GStringRep::giswupper(const unsigned long w)
1310{
1311#if HAS_WCTYPE
1312  return ((sizeof(wchar_t) == 2)&&(w&~0xffff))
1313    ?(true):((unsigned long)iswupper((wchar_t)w)?true:false);
1314#else
1315  return (w&~0xff)?(true):((unsigned long)isupper((char)w)?true:false);
1316#endif
1317}
1318
1319bool
1320GStringRep::giswlower(const unsigned long w)
1321{
1322#if HAS_WCTYPE
1323  return ((sizeof(wchar_t) == 2)&&(w&~0xffff))
1324    ?(true):((unsigned long)iswlower((wchar_t)w)?true:false);
1325#else
1326  return (w&~0xff)?(true):((unsigned long)islower((char)w)?true:false);
1327#endif
1328}
1329
1330unsigned long
1331GStringRep::gtowupper(const unsigned long w)
1332{
1333#if HAS_WCTYPE
1334  return ((sizeof(wchar_t) == 2)&&(w&~0xffff))
1335    ?w:((unsigned long)towupper((wchar_t)w));
1336#else
1337  return (w&~0xff)?w:((unsigned long)toupper((char)w));
1338#endif
1339}
1340
1341unsigned long
1342GStringRep::gtowlower(const unsigned long w)
1343{
1344#if HAS_WCTYPE
1345  return ((sizeof(wchar_t) == 2)&&(w&~0xffff))
1346    ?w:((unsigned long)towlower((wchar_t)w));
1347#else
1348  return (w&~0xff)?w:((unsigned long)tolower((char)w));
1349#endif
1350}
1351
1352GP<GStringRep>
1353GStringRep::tocase(
1354  bool (*xiswcase)(const unsigned long wc),
1355  unsigned long (*xtowcase)(const unsigned long wc)) const
1356{
1357  GP<GStringRep> retval;
1358  char const * const eptr=data+size;
1359  char const *ptr=data;
1360  while(ptr<eptr)
1361  {
1362    char const * const xptr=isCharType(xiswcase,ptr,false);
1363    if(ptr == xptr)
1364      break;
1365    ptr=xptr;
1366  }
1367  if(ptr<eptr)
1368  {
1369    const int n=(int)((size_t)ptr-(size_t)data);
1370    unsigned char *buf;
1371    GPBuffer<unsigned char> gbuf(buf,n+(1+size-n)*6);
1372    if(n>0)
1373    {
1374      strncpy((char *)buf,data,n);
1375    }
1376    unsigned char *buf_ptr=buf+n;
1377    for(char const *ptr=data+n;ptr<eptr;)
1378    {
1379      char const * const xptr=ptr;
1380      const unsigned long w=getValidUCS4(ptr);
1381      if(ptr == xptr)
1382        break;
1383      if(xiswcase(w))
1384      {
1385        const int len=(int)((size_t)ptr-(size_t)xptr);
1386        strncpy((char *)buf_ptr,xptr,len);
1387        buf_ptr+=len;
1388      }else
1389      {
1390        mbstate_t ps;
1391        memset(&ps,0,sizeof(mbstate_t));
1392        buf_ptr=UCS4toString(xtowcase(w),buf_ptr,&ps);
1393      }
1394    }
1395    buf_ptr[0]=0;
1396    retval=substr((const char *)buf,0,(int)((size_t)buf_ptr-(size_t)buf));
1397  }else
1398  {
1399    retval=const_cast<GStringRep *>(this);
1400  }
1401  return retval;
1402}
1403
1404// Returns a copy of this string with characters used in XML escaped as follows:
1405//      '<'  -->  "&lt;"
1406//      '>'  -->  "&gt;"
1407//      '&'  -->  "&amp;"
1408//      '\'' -->  "&apos;"
1409//      '\"' -->  "&quot;"
1410//  Also escapes characters 0x00 through 0x1f and 0x7e through 0x7f.
1411GP<GStringRep>
1412GStringRep::toEscaped( const bool tosevenbit ) const
1413{
1414  bool modified=false;
1415  char *ret;
1416  GPBuffer<char> gret(ret,size*7);
1417  ret[0]=0;
1418  char *retptr=ret;
1419  char const *start=data;
1420  char const *s=start;
1421  char const *last=s;
1422  GP<GStringRep> special;
1423  for(unsigned long w;(w=getValidUCS4(s));last=s)
1424  {
1425    char const *ss=0;
1426    switch(w)
1427    {
1428    case '<':
1429      ss="&lt;";
1430      break;
1431    case '>':
1432      ss="&gt;";
1433      break;
1434    case '&':
1435      ss="&amp;";
1436      break;
1437    case '\47':
1438      ss="&apos;";
1439      break;
1440    case '\42':
1441      ss="&quot;";
1442      break;
1443    default:
1444      if((w<' ')||(w>=0x7e && (tosevenbit || (w < 0x80))))
1445      {
1446        special=toThis(UTF8::create_format("&#%lu;",w));
1447        ss=special->data;
1448      }
1449      break;
1450    }
1451    if(ss)
1452    {
1453      modified=true;
1454      if(s!=start)
1455      {
1456        size_t len=(size_t)last-(size_t)start;
1457        strncpy(retptr,start,len);
1458        retptr+=len;
1459        start=s;
1460      }
1461      if(ss[0])
1462      {
1463        size_t len=strlen(ss);
1464        strcpy(retptr,ss);
1465        retptr+=len;
1466      }
1467    }
1468  }
1469  GP<GStringRep> retval;
1470  if(modified)
1471  {
1472    strcpy(retptr,start);
1473    retval=strdup( ret );
1474  }else
1475  {
1476    retval=const_cast<GStringRep *>(this);
1477  }
1478//  DEBUG_MSG( "Escaped string is '" << ret << "'\n" );
1479  return retval;
1480}
1481
1482
1483static const GMap<GUTF8String,GUTF8String> &
1484BasicMap( void )
1485{
1486  static GMap<GUTF8String,GUTF8String> Basic;
1487  if (! Basic.size())
1488    {
1489      Basic["lt"]   = GUTF8String('<');
1490      Basic["gt"]   = GUTF8String('>');
1491      Basic["amp"]  = GUTF8String('&');
1492      Basic["apos"] = GUTF8String('\47');
1493      Basic["quot"] = GUTF8String('\42');
1494    }
1495  return Basic;
1496}
1497
1498GUTF8String
1499GUTF8String::fromEscaped( const GMap<GUTF8String,GUTF8String> ConvMap ) const
1500{
1501  GUTF8String ret;                  // Build output string here
1502  int start_locn = 0;           // Beginning of substring to skip
1503  int amp_locn;                 // Location of a found ampersand
1504
1505  while( (amp_locn = search( '&', start_locn )) > -1 )
1506  {
1507      // Found the next apostrophe
1508      // Locate the closing semicolon
1509    const int semi_locn = search( ';', amp_locn );
1510      // No closing semicolon, exit and copy
1511      //  the rest of the string.
1512    if( semi_locn < 0 )
1513      break;
1514    ret += substr( start_locn, amp_locn - start_locn );
1515    int const len = semi_locn - amp_locn - 1;
1516    if(len)
1517    {
1518      GUTF8String key = substr( amp_locn+1, len);
1519      //DEBUG_MSG( "key = '" << key << "'\n" );
1520      char const * s=key;
1521      if( s[0] == '#')
1522      {
1523        unsigned long value;
1524        char *ptr=0;
1525        if(s[1] == 'x' || s[1] == 'X')
1526        {
1527          value=strtoul((char const *)(s+2),&ptr,16);
1528        }else
1529        {
1530          value=strtoul((char const *)(s+1),&ptr,10);
1531        }
1532        if(ptr)
1533        {
1534          unsigned char utf8char[7];
1535          unsigned char const * const end=GStringRep::UCS4toUTF8(value,utf8char);
1536          ret+=GUTF8String((char const *)utf8char,(size_t)end-(size_t)utf8char);
1537        }else
1538        {
1539          ret += substr( amp_locn, semi_locn - amp_locn + 1 );
1540        }
1541      }else
1542      { 
1543        GPosition map_entry = ConvMap.contains( key );
1544        if( map_entry )
1545        {                           // Found in the conversion map, substitute
1546          ret += ConvMap[map_entry];
1547        } else
1548        {
1549          static const GMap<GUTF8String,GUTF8String> &Basic = BasicMap();
1550          GPosition map_entry = Basic.contains( key );
1551          if ( map_entry )
1552          {
1553            ret += Basic[map_entry];
1554          }else
1555          {
1556            ret += substr( amp_locn, len+2 );
1557          }
1558        }
1559      }
1560    }else
1561    {
1562      ret += substr( amp_locn, len+2 );
1563    }
1564    start_locn = semi_locn + 1;
1565//    DEBUG_MSG( "ret = '" << ret << "'\n" );
1566  }
1567
1568                                // Copy the end of the string to the output
1569  ret += substr( start_locn, length()-start_locn );
1570
1571//  DEBUG_MSG( "Unescaped string is '" << ret << "'\n" );
1572  return (ret == *this)?(*this):ret;
1573}
1574
1575GUTF8String
1576GUTF8String::fromEscaped(void) const
1577{
1578  const GMap<GUTF8String,GUTF8String> nill;
1579  return fromEscaped(nill);
1580}
1581
1582GP<GStringRep>
1583GStringRep::setat(int n, char ch) const
1584{
1585  GP<GStringRep> retval;
1586  if(n<0)
1587    n+=size;
1588  if (n < 0 || n>size) 
1589    GBaseString::throw_illegal_subscript();
1590  if(ch == data[n])
1591  {
1592    retval=const_cast<GStringRep *>(this);
1593  }else if(!ch)
1594  {
1595    retval=getbuf(n);
1596  }else
1597  {
1598    retval=getbuf((n<size)?size:n);
1599    retval->data[n]=ch;
1600    if(n == size)
1601      retval->data[n+1]=0;
1602  }
1603  return retval;
1604}
1605
1606#ifdef WIN32
1607#define USE_VSNPRINTF _vsnprintf
1608#endif
1609
1610#ifdef AUTOCONF
1611# ifdef HAVE_VSNPRINTF
1612#  define USE_VSNPRINTF vsnprintf
1613# endif
1614#else
1615# ifdef linux
1616#  define USE_VSNPRINTF vsnprintf
1617# endif
1618#endif
1619
1620GUTF8String &
1621GUTF8String::format(const char fmt[], ... )
1622{
1623  va_list args;
1624  va_start(args, fmt);
1625  return init(GStringRep::UTF8::create(fmt,args));
1626}
1627
1628GP<GStringRep>
1629GStringRep::UTF8::create_format(const char fmt[],...)
1630{
1631  va_list args;
1632  va_start(args, fmt);
1633  return create(fmt,args);
1634}
1635
1636GP<GStringRep>
1637GStringRep::vformat(va_list args) const
1638{
1639  GP<GStringRep> retval;
1640  if(size)
1641  {
1642#ifndef WIN32
1643    char *nfmt;
1644    GPBuffer<char> gnfmt(nfmt,size+1);
1645    nfmt[0]=0;
1646    int start=0;
1647#endif
1648    int from=0;
1649    while((from=search('%',from)) >= 0)
1650    {
1651      if(data[++from] != '%')
1652      {
1653        int m,n=0;
1654        sscanf(data+from,"%d!%n",&m,&n);
1655        if(n)
1656        {
1657#ifdef WIN32
1658          char *lpszFormat=data;
1659          LPTSTR lpszTemp;
1660          if((!::FormatMessage(
1661            FORMAT_MESSAGE_FROM_STRING|FORMAT_MESSAGE_ALLOCATE_BUFFER,
1662              lpszFormat, 0, 0, (LPTSTR)&lpszTemp,0,&args))
1663            || !lpszTemp)
1664          {
1665            G_THROW(GException::outofmemory);
1666          }
1667          va_end(args); 
1668          retval=strdup((const char *)lpszTemp);
1669          LocalFree(lpszTemp);
1670          break;
1671#else
1672          from+=n;
1673          const int end=search('!',from);
1674          if(end>=0)
1675          {
1676            strncat(nfmt,data+start,(int)(end-start));
1677            strncat(nfmt,"$",1);
1678            start=from=end+1;
1679          }else
1680          {
1681            gnfmt.resize(0);
1682            from=(-1);
1683            break;
1684          }
1685#endif
1686        }else
1687        {
1688#ifndef WIN32
1689          gnfmt.resize(0);
1690#endif
1691          from=(-1);
1692          break;
1693        }
1694      }
1695    }
1696    if(from < 0)
1697    {
1698#ifndef WIN32
1699      char const * const fmt=(nfmt&&nfmt[0])?nfmt:data;
1700#else
1701      char const * const fmt=data;
1702#endif
1703      int buflen=32768;
1704      char *buffer;
1705      GPBuffer<char> gbuffer(buffer,buflen);
1706
1707      ChangeLocale locale(LC_NUMERIC,(isNative()?0:"C"));
1708
1709      // Format string
1710#ifdef USE_VSNPRINTF
1711      while(USE_VSNPRINTF(buffer, buflen, fmt, args)<0)
1712      {
1713        gbuffer.resize(0);
1714        gbuffer.resize(buflen+32768);
1715      }
1716      va_end(args);
1717#else
1718      buffer[buflen-1] = 0;
1719      vsprintf(buffer, fmt, args);
1720      va_end(args);
1721      if (buffer[buflen-1])
1722      {
1723        // This isn't as fatal since it is on the stack, but we
1724        // definitely should stop the current operation.
1725        G_THROW( ERR_MSG("GString.overwrite") );
1726      }
1727#endif
1728      retval=strdup((const char *)buffer);
1729    }
1730  }
1731  // Go altering the string
1732  return retval;
1733}
1734
1735int 
1736GStringRep::search(char c, int from) const
1737{
1738  if (from<0)
1739    from += size;
1740  int retval=(-1);
1741  if (from>=0 && from<size)
1742  {
1743    char const *const s = strchr(data+from,c);
1744    if(s)
1745      retval=(int)((size_t)s-(size_t)data);
1746  }
1747  return retval;
1748}
1749
1750int 
1751GStringRep::search(char const *ptr, int from) const
1752{
1753  if(from<0)
1754  {
1755    from+=size;
1756    if(from<0)
1757      G_THROW( ERR_MSG("GString.bad_subscript") );
1758  }
1759  int retval=(-1);
1760  if (from>=0 && from<size)
1761  {
1762    char const *const s = strstr(data+from,ptr);
1763    if(s)
1764      retval=(int)((size_t)s-(size_t)data);
1765  }
1766  return retval;
1767}
1768
1769int 
1770GStringRep::rsearch(char c, int from) const
1771{
1772  if(from<0)
1773  {
1774    from+=size;
1775    if(from<0)
1776      G_THROW( ERR_MSG("GString.bad_subscript") );
1777  }
1778  int retval=(-1);
1779  if ((from>=0) && (from<size))
1780  {
1781    char const *const s = strrchr(data+from,c);
1782    if(s)
1783      retval=(int)((size_t)s-(size_t)data);
1784  }
1785  return retval;
1786}
1787
1788int 
1789GStringRep::rsearch(char const *ptr, int from) const
1790{
1791  if(from<0)
1792  {
1793    from+=size;
1794    if(from<0)
1795      G_THROW( ERR_MSG("GString.bad_subscript") );
1796  }
1797  int retval=(-1);
1798  for(int loc=from;(loc=search(ptr,loc)) >= 0;++loc)
1799    retval=loc;
1800  return retval;
1801}
1802
1803int
1804GStringRep::contains(const char accept[],int from) const
1805{
1806  if(from<0)
1807  {
1808    from+=size;
1809    if(from<0)
1810      G_THROW( ERR_MSG("GString.bad_subscript") );
1811  }
1812  int retval=(-1);
1813  if (accept && accept[0] && from>=0 && from<size)
1814  {
1815    char const * const src = data+from;
1816    char const *ptr=strpbrk(src,accept);
1817    if(ptr)
1818    {
1819      retval=(int)(ptr-src)+from;
1820    }
1821  }
1822  return retval;
1823}
1824
1825int
1826GStringRep::rcontains(const char accept[],int from) const
1827{
1828  int retval=(-1);
1829  while((from=contains(accept,from)) >= 0)
1830  {
1831    retval=from++;
1832  }
1833  return retval;
1834}
1835
1836bool
1837GBaseString::is_int(void) const
1838{
1839  bool isLong=!!ptr;
1840  if(isLong)
1841  {
1842    int endpos;
1843    (*this)->toLong(0,endpos);
1844    if(endpos>=0)
1845    {
1846      isLong=((*this)->nextNonSpace(endpos) == (int)length());
1847    }
1848  }
1849  return isLong;
1850}
1851
1852bool
1853GBaseString::is_float(void) const
1854{
1855  bool isDouble=!!ptr;
1856  if(isDouble)
1857  {
1858    int endpos;
1859    (*this)->toDouble(0,endpos);
1860    if(endpos>=0)
1861    {
1862      isDouble=((*this)->nextNonSpace(endpos) == (int)length());
1863    }
1864  }
1865  return isDouble;
1866}
1867
1868unsigned int 
1869hash(const GBaseString &str)
1870{
1871  unsigned int x = 0;
1872  const char *s = (const char*)str;
1873  while (*s) 
1874    x = x ^ (x<<6) ^ (unsigned char)(*s++);
1875  return x;
1876}
1877
1878void 
1879GBaseString::throw_illegal_subscript()
1880{
1881  G_THROW( ERR_MSG("GString.bad_subscript") );
1882}
1883
1884unsigned char *
1885GStringRep::UTF8::UCS4toString(
1886  const unsigned long w0,unsigned char *ptr, mbstate_t *) const
1887{
1888  return UCS4toUTF8(w0,ptr);
1889}
1890
1891int
1892GStringRep::UTF8::ncopy(
1893  wchar_t * const buf, const int buflen ) const
1894{
1895  int retval=(-1);
1896  if(buf && buflen)
1897  {
1898        buf[0]=0;
1899    if(data[0])
1900        {
1901      const size_t length=strlen(data);
1902      const unsigned char * const eptr=(const unsigned char *)(data+length);
1903          wchar_t *r=buf;
1904          wchar_t const * const rend=buf+buflen;
1905      for(const unsigned char *s=(const unsigned char *)data;(r<rend)&&(s<eptr)&&*s;)
1906          {
1907        const unsigned long w0=UTF8toUCS4(s,eptr);
1908        unsigned short w1;
1909        unsigned short w2=1;
1910        for(int count=(sizeof(wchar_t) == sizeof(w1))?UCS4toUTF16(w0,w1,w2):1;
1911            count&&(r<rend);
1912            --count,w1=w2,++r)
1913                {
1914                  r[0]=(sizeof(wchar_t) == sizeof(w1))?(wchar_t)w1:(wchar_t)w0;
1915                }
1916          }
1917          if(r<rend)
1918          {
1919            r[0]=0;
1920                retval=((size_t)r-(size_t)buf)/sizeof(wchar_t);
1921          }
1922        }else
1923        {
1924          retval=0;
1925        }
1926  }
1927  return retval;
1928}
1929
1930GP<GStringRep> 
1931GStringRep::UTF8::toNative(const EscapeMode escape) const
1932{
1933  GP<GStringRep> retval;
1934  if(data[0])
1935  {
1936    const size_t length=strlen(data);
1937    const unsigned char * const eptr=(const unsigned char *)(data+length);
1938    unsigned char *buf;
1939    GPBuffer<unsigned char> gbuf(buf,12*length+12); 
1940    unsigned char *r=buf;
1941    mbstate_t ps;
1942    memset(&ps,0,sizeof(mbstate_t));
1943    for(const unsigned char *s=(const unsigned char *)data;(s<eptr)&& *s;)
1944    {
1945      const unsigned long w0=UTF8toUCS4(s,eptr);
1946      const unsigned char * const r0=r;
1947      r=UCS4toNative(w0,r,&ps);
1948      if(r == r0)
1949      {
1950        if(escape == IS_ESCAPED)
1951        {
1952          sprintf((char *)r,"&#%lu;",w0);
1953          r+=strlen((char *)r);
1954        }else
1955        {
1956          r=buf;
1957          break;
1958        }
1959      }
1960    }
1961    r[0]=0;
1962    retval = NATIVE_CREATE( (const char *)buf );
1963  } else
1964  {
1965    retval = NATIVE_CREATE( (unsigned int)0 );
1966  }
1967  return retval;
1968}
1969
1970GP<GStringRep>
1971GStringRep::UTF8::toUTF8(const bool nothrow) const
1972{
1973  if(!nothrow)
1974    G_THROW( ERR_MSG("GStringRep.UTF8ToUTF8") );
1975  return const_cast<GStringRep::UTF8 *>(this);
1976}
1977
1978// Tests if a string is legally encoded in the current character set.
1979bool 
1980GStringRep::UTF8::is_valid(void) const
1981{
1982  bool retval=true;
1983  if(data && size)
1984  {
1985    const unsigned char * const eptr=(const unsigned char *)(data+size);
1986    for(const unsigned char *s=(const unsigned char *)data;(s<eptr)&& *s;)
1987    {
1988      const unsigned char * const r=s;
1989      (void)UTF8toUCS4(s,eptr);
1990      if(r == s)
1991      {
1992        retval=false;
1993        break;
1994      }
1995    }
1996  }
1997  return retval;
1998}
1999
2000static inline unsigned long
2001add_char(unsigned long const U, unsigned char const * const r)
2002{
2003  unsigned long const C=r[0];
2004  return ((C|0x3f) == 0xbf)?((U<<6)|(C&0x3f)):0;
2005}
2006
2007unsigned long
2008GStringRep::UTF8toUCS4(
2009  unsigned char const *&s,void const * const eptr)
2010{
2011  unsigned long U=0;
2012  unsigned char const *r=s;
2013  if(r < eptr)
2014  {
2015    unsigned long const C1=r++[0];
2016    if(C1&0x80)
2017    {
2018      if(r < eptr)
2019      {
2020        U=C1;
2021        if((U=((C1&0x40)?add_char(U,r++):0)))
2022        {
2023          if(C1&0x20)
2024          {
2025            if(r < eptr)
2026            {
2027              if((U=add_char(U,r++)))
2028              {
2029                if(C1&0x10)
2030                {
2031                  if(r < eptr)
2032                  {
2033                    if((U=add_char(U,r++)))
2034                    {
2035                      if(C1&0x8)
2036                      {
2037                        if(r < eptr)
2038                        {
2039                          if((U=add_char(U,r++)))
2040                          {
2041                            if(C1&0x4)
2042                            {
2043                              if(r < eptr)
2044                              {
2045                                if((U=((!(C1&0x2))?(add_char(U,r++)&0x7fffffff):0)))
2046                                {
2047                                  s=r;
2048                                }else
2049                                {
2050                                  U=(unsigned int)(-1)-s++[0];
2051                                }
2052                              }else
2053                              {
2054                                U=0;
2055                              }
2056                            }else if((U=((U&0x4000000)?0:(U&0x3ffffff))))
2057                            {
2058                              s=r;
2059                            }
2060                          }else
2061                          {
2062                            U=(unsigned int)(-1)-s++[0];
2063                          }
2064                        }else
2065                        {
2066                          U=0;
2067                        }
2068                      }else if((U=((U&0x200000)?0:(U&0x1fffff))))
2069                      {
2070                        s=r;
2071                      }
2072                    }else
2073                    {
2074                      U=(unsigned int)(-1)-s++[0];
2075                    }
2076                  }else
2077                  {
2078                    U=0;
2079                  }
2080                }else if((U=((U&0x10000)?0:(U&0xffff))))
2081                {
2082                  s=r;
2083                }
2084              }else
2085              {
2086                U=(unsigned int)(-1)-s++[0];
2087              }
2088            }else
2089            {
2090              U=0;
2091            }
2092          }else if((U=((U&0x800)?0:(U&0x7ff))))
2093          {
2094            s=r;
2095          }
2096        }else
2097        {
2098          U=(unsigned int)(-1)-s++[0];
2099        }
2100      }else
2101      {
2102        U=0;
2103      }
2104    }else if((U=C1))
2105    {
2106      s=r;
2107    }
2108  }
2109  return U;
2110}
2111
2112unsigned char *
2113GStringRep::UCS4toUTF8(const unsigned long w,unsigned char *ptr)
2114{
2115  if(w <= 0x7f)
2116  {
2117    *ptr++ = (unsigned char)w;
2118  }
2119  else if(w <= 0x7ff)
2120  {
2121    *ptr++ = (unsigned char)((w>>6)|0xC0);
2122    *ptr++ = (unsigned char)((w|0x80)&0xBF);
2123  }
2124  else if(w <= 0xFFFF)
2125  {
2126    *ptr++ = (unsigned char)((w>>12)|0xE0);
2127    *ptr++ = (unsigned char)(((w>>6)|0x80)&0xBF);
2128    *ptr++ = (unsigned char)((w|0x80)&0xBF);
2129  }
2130  else if(w <= 0x1FFFFF)
2131  {
2132    *ptr++ = (unsigned char)((w>>18)|0xF0);
2133    *ptr++ = (unsigned char)(((w>>12)|0x80)&0xBF);
2134    *ptr++ = (unsigned char)(((w>>6)|0x80)&0xBF);
2135    *ptr++ = (unsigned char)((w|0x80)&0xBF);
2136  }
2137  else if(w <= 0x3FFFFFF)
2138  {
2139    *ptr++ = (unsigned char)((w>>24)|0xF8);
2140    *ptr++ = (unsigned char)(((w>>18)|0x80)&0xBF);
2141    *ptr++ = (unsigned char)(((w>>12)|0x80)&0xBF);
2142    *ptr++ = (unsigned char)(((w>>6)|0x80)&0xBF);
2143    *ptr++ = (unsigned char)((w|0x80)&0xBF);
2144  }
2145  else if(w <= 0x7FFFFFFF)
2146  {
2147    *ptr++ = (unsigned char)((w>>30)|0xFC);
2148    *ptr++ = (unsigned char)(((w>>24)|0x80)&0xBF);
2149    *ptr++ = (unsigned char)(((w>>18)|0x80)&0xBF);
2150    *ptr++ = (unsigned char)(((w>>12)|0x80)&0xBF);
2151    *ptr++ = (unsigned char)(((w>>6)|0x80)&0xBF);
2152    *ptr++ = (unsigned char)((w|0x80)&0xBF);
2153  }
2154  else
2155  { 
2156    *ptr++ = '?';
2157  }
2158  return ptr;
2159}
2160
2161   // Creates with a concat operation.
2162GP<GStringRep> 
2163GStringRep::concat( const char *s1, const GP<GStringRep> &s2) const
2164{
2165  GP<GStringRep> retval;
2166  if(s2)
2167  {
2168    retval=toThis(s2);
2169    if(s1 && s1[0])
2170    {
2171      if(retval)
2172      {
2173        retval=concat(s1,retval->data);
2174      }else
2175      {
2176        retval=strdup(s1);
2177      }
2178    }
2179  }else if(s1 && s1[0])
2180  {
2181    retval=strdup(s1);
2182  }
2183  return retval;
2184}
2185
2186   // Creates with a concat operation.
2187
2188GP<GStringRep> 
2189GStringRep::concat( const GP<GStringRep> &s1,const char *s2) const
2190{
2191  GP<GStringRep> retval;
2192  if(s1)
2193  {
2194    retval=toThis(s1);
2195    if(s2 && s2[0])
2196    {
2197      if(retval)
2198      {
2199        retval=retval->append(s2);
2200      }else
2201      {
2202        retval=strdup(s2);
2203      }
2204    }
2205  }else if(s2 && s2[0])
2206  {
2207    retval=strdup(s2);
2208  }
2209  return retval;
2210}
2211
2212GP<GStringRep> 
2213GStringRep::concat(const GP<GStringRep> &s1,const GP<GStringRep> &s2) const
2214{ 
2215  GP<GStringRep> retval; 
2216  if(s1)
2217  {
2218    retval=toThis(s1,s2);
2219    if(retval && s2)
2220    {
2221      retval=retval->append(toThis(s2));
2222    }
2223  }else if(s2)
2224  {
2225    retval=toThis(s2);
2226  }
2227  return retval;
2228}
2229
2230#ifdef WIN32
2231static const char *setlocale_win32(void)
2232{
2233  static const char *locale=setlocale(LC_ALL,0);
2234  if(! locale || (locale[0] == 'C' && !locale[1]))
2235  {
2236    locale=setlocale(LC_ALL,"");
2237  }
2238  return locale;
2239}
2240#endif
2241
2242GStringRep::GStringRep(void)
2243{
2244#ifdef WIN32
2245  static const char *locale=setlocale_win32();
2246#endif
2247  size=0;
2248  data=0;
2249}
2250
2251GStringRep::~GStringRep()
2252{
2253  if(data)
2254  {
2255    data[0]=0;
2256    ::operator delete(data);
2257  }
2258  data=0;
2259}
2260
2261GStringRep::UTF8::UTF8(void) {}
2262
2263GStringRep::UTF8::~UTF8() {}
2264
2265int
2266GStringRep::cmp(const char *s1,const int len) const
2267{
2268  return cmp(data,s1,len);
2269}
2270
2271int
2272GStringRep::cmp(const char *s1, const char *s2,const int len)
2273{
2274  return (len
2275   ?((s1&&s1[0])
2276      ?((s2&&s2[0])
2277        ?((len>0)
2278          ?strncmp(s1,s2,len)
2279          :strcmp(s1,s2))
2280        :1)
2281      :((s2&&s2[0])?(-1):0))
2282   :0);
2283}
2284
2285int 
2286GStringRep::cmp(const GP<GStringRep> &s1, const GP<GStringRep> &s2,
2287  const int len )
2288{
2289  return (s1?(s1->cmp(s2,len)):cmp(0,(s2?(s2->data):0),len));
2290}
2291
2292int 
2293GStringRep::cmp(const GP<GStringRep> &s1, const char *s2, 
2294  const int len )
2295{
2296  return cmp((s1?s1->data:0),s2,len);
2297}
2298
2299int 
2300GStringRep::cmp(const char *s1, const GP<GStringRep> &s2,
2301  const int len )
2302{
2303  return cmp(s1,(s2?(s2->data):0),len);
2304}
2305
2306int
2307GStringRep::UTF8::cmp(const GP<GStringRep> &s2,const int len) const
2308{
2309  int retval;
2310  if(s2)
2311  {
2312    if(s2->isNative())
2313    {
2314      GP<GStringRep> r(s2->toUTF8(true));
2315      if(r)
2316      {
2317        retval=GStringRep::cmp(data,r->data,len);
2318      }else
2319      {
2320        retval=-(s2->cmp(toNative(NOT_ESCAPED),len));
2321      }
2322    }else
2323    {
2324      retval=GStringRep::cmp(data,s2->data,len);
2325    }
2326  }else
2327  { 
2328    retval=GStringRep::cmp(data,0,len);
2329  }
2330  return retval;
2331} 
2332
2333int
2334GStringRep::UTF8::toInt() const
2335{
2336  int endpos;
2337  return (int)toLong(0,endpos);
2338}
2339
2340static inline long
2341Cstrtol(char *data,char **edata, const int base)
2342{
2343  GStringRep::ChangeLocale locale(LC_NUMERIC,"C");
2344  while (data && *data==' ') data++;
2345  return strtol(data,edata,base);
2346}
2347
2348long 
2349GStringRep::UTF8::toLong(
2350  const int pos, int &endpos, const int base) const
2351{
2352  char *edata=0;
2353  long retval=Cstrtol(data+pos,&edata, base);
2354  if(edata)
2355  {
2356    endpos=edata-data;
2357  }else
2358  {
2359    endpos=(-1);
2360    GP<GStringRep> ptr=ptr->strdup(data+pos);
2361    if(ptr)
2362      ptr=ptr->toNative(NOT_ESCAPED);
2363    if(ptr)
2364    {
2365      int xendpos;
2366      retval=ptr->toLong(0,xendpos,base);
2367      if(xendpos> 0)
2368      {
2369        endpos=(int)size;
2370        ptr=ptr->strdup(data+xendpos);
2371        if(ptr)
2372        {
2373          ptr=ptr->toUTF8(true);
2374          if(ptr)
2375          {
2376            endpos-=(int)(ptr->size);
2377          }
2378        }
2379      }
2380    }
2381  }
2382  return retval;
2383}
2384
2385static inline unsigned long
2386Cstrtoul(char *data,char **edata, const int base)
2387{
2388  GStringRep::ChangeLocale locale(LC_NUMERIC,"C");
2389  while (data && *data==' ') data++;
2390  return strtoul(data,edata,base);
2391}
2392
2393unsigned long 
2394GStringRep::UTF8::toULong(
2395  const int pos, int &endpos, const int base) const
2396{
2397  char *edata=0;
2398  unsigned long retval=Cstrtoul(data+pos,&edata, base);
2399  if(edata)
2400  {
2401    endpos=edata-data;
2402  }else
2403  {
2404    endpos=(-1);
2405    GP<GStringRep> ptr=ptr->strdup(data+pos);
2406    if(ptr)
2407      ptr=ptr->toNative(NOT_ESCAPED);
2408    if(ptr)
2409    {
2410      int xendpos;
2411      retval=ptr->toULong(0,xendpos,base);
2412      if(xendpos> 0)
2413      {
2414        endpos=(int)size;
2415        ptr=ptr->strdup(data+xendpos);
2416        if(ptr)
2417        {
2418          ptr=ptr->toUTF8(true);
2419          if(ptr)
2420          {
2421            endpos-=(int)(ptr->size);
2422          }
2423        }
2424      }
2425    }
2426  }
2427  return retval;
2428}
2429
2430static inline double
2431Cstrtod(char *data,char **edata)
2432{
2433  GStringRep::ChangeLocale locale(LC_NUMERIC,"C");
2434  while (data && *data==' ') data++;
2435  return strtod(data,edata);
2436}
2437
2438double
2439GStringRep::UTF8::toDouble(const int pos, int &endpos) const
2440{
2441  char *edata=0;
2442  double retval=Cstrtod(data+pos,&edata);
2443  if(edata)
2444  {
2445    endpos=edata-data;
2446  }else
2447  {
2448    endpos=(-1);
2449    GP<GStringRep> ptr=ptr->strdup(data+pos);
2450    if(ptr)
2451      ptr=ptr->toNative(NOT_ESCAPED);
2452    if(ptr)
2453    {
2454      int xendpos;
2455      retval=ptr->toDouble(0,xendpos);
2456      if(xendpos >= 0)
2457      {
2458        endpos=(int)size;
2459        ptr=ptr->strdup(data+xendpos);
2460        if(ptr)
2461        {
2462          ptr=ptr->toUTF8(true);
2463          if(ptr)
2464          {
2465            endpos-=(int)(ptr->size);
2466          }
2467        }
2468      }
2469    }
2470  }
2471  return retval;
2472}
2473
2474int 
2475GStringRep::getUCS4(unsigned long &w, const int from) const
2476{
2477  int retval;
2478  if(from>=size)
2479  {
2480    w=0;
2481    retval=size;
2482  }else if(from<0)
2483  {
2484    w=(unsigned int)(-1);
2485    retval=(-1);
2486  }else
2487  {
2488    const char *source=data+from;
2489    w=getValidUCS4(source);
2490    retval=(int)((size_t)source-(size_t)data);
2491  } 
2492  return retval;
2493}
2494
2495
2496unsigned long
2497GStringRep::UTF8::getValidUCS4(const char *&source) const
2498{
2499  return GStringRep::UTF8toUCS4((const unsigned char *&)source,data+size);
2500}
2501
2502int
2503GStringRep::nextNonSpace(const int from,const int len) const
2504{
2505  return nextCharType(giswspace,from,len,true);
2506}
2507
2508int
2509GStringRep::nextSpace(const int from,const int len) const
2510{
2511  return nextCharType(giswspace,from,len,false);
2512}
2513
2514int
2515GStringRep::nextChar(const int from) const
2516{
2517  char const * xptr=data+from;
2518  (void)getValidUCS4(xptr);
2519  return (int)((size_t)xptr-(size_t)data);
2520}
2521
2522int 
2523GStringRep::firstEndSpace(int from,const int len) const
2524{
2525  const int xsize=(len<0)?size:(from+len);
2526  const int ysize=(size<xsize)?size:xsize;
2527  int retval=ysize;
2528  while(from<ysize)
2529  {
2530    from=nextNonSpace(from,ysize-from);
2531    if(from < size)
2532    {
2533      const int r=nextSpace(from,ysize-from);
2534      // If a character isn't legal, then it will return
2535      // tru for both nextSpace and nextNonSpace.
2536      if(r == from)
2537      {
2538        from++;
2539      }else
2540      {
2541        from=retval=r;
2542      }
2543    }
2544  }
2545  return retval;
2546}
2547
2548int
2549GStringRep::UCS4toUTF16(
2550  const unsigned long w,unsigned short &w1, unsigned short &w2)
2551{
2552  int retval;
2553  if(w<0x10000)
2554  {
2555    w1=(unsigned short)w;
2556    w2=0;
2557    retval=1;
2558  }else
2559  {
2560    w1=(unsigned short)((((w-0x10000)>>10)&0x3ff)+0xD800);
2561    w2=(unsigned short)((w&0x3ff)+0xDC00);
2562    retval=2;
2563  }
2564  return retval;
2565}
2566
2567int
2568GStringRep::UTF16toUCS4(
2569  unsigned long &U,unsigned short const * const s,void const * const eptr)
2570{
2571  int retval=0;
2572  U=0;
2573  unsigned short const * const r=s+1;
2574  if(r <= eptr)
2575  {
2576    unsigned long const W1=s[0];
2577    if((W1<0xD800)||(W1>0xDFFF))
2578    {
2579      if((U=W1))
2580      {
2581        retval=1;
2582      }
2583    }else if(W1<=0xDBFF)
2584    {
2585      unsigned short const * const rr=r+1;
2586      if(rr <= eptr)
2587      {
2588        unsigned long const W2=s[1];
2589        if(((W2>=0xDC00)||(W2<=0xDFFF))&&((U=(0x10000+((W1&0x3ff)<<10))|(W2&0x3ff))))
2590        {
2591          retval=2;
2592        }else
2593        {
2594          retval=(-1);
2595        }
2596      }
2597    }
2598  }
2599  return retval;
2600}
2601
2602
2603//bcr
2604
2605GUTF8String&
2606GUTF8String::operator+= (char ch)
2607{
2608  return init(
2609    GStringRep::UTF8::create((const char*)*this,
2610    GStringRep::UTF8::create(&ch,0,1)));
2611}
2612
2613GUTF8String&
2614GUTF8String::operator+= (const char *str)
2615{
2616  return init(GStringRep::UTF8::create(*this,str));
2617}
2618
2619GUTF8String&
2620GUTF8String::operator+= (const GBaseString &str)
2621{
2622  return init(GStringRep::UTF8::create(*this,str));
2623}
2624
2625GUTF8String
2626GUTF8String::substr(int from, int len) const
2627{ return GUTF8String(*this, from, len); }
2628
2629GUTF8String
2630GUTF8String::operator+(const GBaseString &s2) const
2631{ return GStringRep::UTF8::create(*this,s2); }
2632
2633GUTF8String
2634GUTF8String::operator+(const GUTF8String &s2) const
2635{ return GStringRep::UTF8::create(*this,s2); }
2636
2637GUTF8String
2638GUTF8String::operator+(const char    *s2) const
2639{ return GStringRep::UTF8::create(*this,s2); }
2640
2641char *
2642GUTF8String::getbuf(int n)
2643{
2644  if(ptr)
2645    init((*this)->getbuf(n));
2646  else if(n>0)
2647    init(GStringRep::UTF8::create(n));
2648  else
2649    init(0);
2650  return ptr?((*this)->data):0;
2651}
2652
2653void 
2654GUTF8String::setat(const int n, const char ch)
2655{
2656  if((!n)&&(!ptr))
2657  {
2658    init(GStringRep::UTF8::create(&ch,0,1));
2659  }else
2660  {
2661    init((*this)->setat(CheckSubscript(n),ch));
2662  }
2663}
2664
2665GP<GStringRep>
2666GStringRep::UTF8ToNative( const char *s, const EscapeMode escape )
2667{
2668  return GStringRep::UTF8::create(s)->toNative(escape);
2669}
2670
2671GUTF8String::GUTF8String(const char dat)
2672{ init(GStringRep::UTF8::create(&dat,0,1)); }
2673
2674GUTF8String::GUTF8String(const GUTF8String &fmt, va_list &args)
2675{ 
2676  if (fmt.ptr)
2677    init(fmt->vformat(args));
2678  else 
2679    init(fmt); 
2680}
2681
2682GUTF8String::GUTF8String(const char *str)
2683{ init(GStringRep::UTF8::create(str)); }
2684
2685GUTF8String::GUTF8String(const unsigned char *str)
2686{ init(GStringRep::UTF8::create((const char *)str)); }
2687
2688GUTF8String::GUTF8String(const unsigned short *str)
2689{ init(GStringRep::UTF8::create(str,0,-1)); }
2690
2691GUTF8String::GUTF8String(const unsigned long *str)
2692{ init(GStringRep::UTF8::create(str,0,-1)); }
2693
2694GUTF8String::GUTF8String(const char *dat, unsigned int len)
2695{ init(GStringRep::UTF8::create(dat,0,((int)len<0)?(-1):(int)len)); }
2696
2697GUTF8String::GUTF8String(const unsigned short *dat, unsigned int len)
2698{ init(GStringRep::UTF8::create(dat,0,((int)len<0)?(-1):(int)len)); }
2699
2700GUTF8String::GUTF8String(const unsigned long *dat, unsigned int len)
2701{ init(GStringRep::UTF8::create(dat,0,((int)len<0)?(-1):(int)len)); }
2702
2703GUTF8String::GUTF8String(const GBaseString &gs, int from, int len)
2704{ init(GStringRep::UTF8::create(gs,from,((int)len<0)?(-1):(int)len)); }
2705
2706GUTF8String::GUTF8String(const int number)
2707{ init(GStringRep::UTF8::create_format("%d",number)); }
2708
2709GUTF8String::GUTF8String(const double number)
2710{ init(GStringRep::UTF8::create_format("%f",number)); }
2711
2712GUTF8String& GUTF8String::operator= (const char str)
2713{ return init(GStringRep::UTF8::create(&str,0,1)); }
2714
2715GUTF8String& GUTF8String::operator= (const char *str)
2716{ return init(GStringRep::UTF8::create(str)); }
2717
2718GUTF8String GBaseString::operator+(const GUTF8String &s2) const
2719{ return GStringRep::UTF8::create(*this,s2); }
2720
2721#if HAS_WCHAR
2722GUTF8String
2723GNativeString::operator+(const GUTF8String &s2) const
2724{
2725  if (ptr)
2726    return GStringRep::UTF8::create((*this)->toUTF8(true),s2);
2727  else
2728    return GStringRep::UTF8::create((*this),s2);
2729}
2730#endif
2731
2732GUTF8String
2733GUTF8String::operator+(const GNativeString &s2) const
2734{
2735  GP<GStringRep> g = s2;
2736  if (s2.ptr)
2737    g = s2->toUTF8(true);
2738  return GStringRep::UTF8::create(*this,g);
2739}
2740
2741GUTF8String
2742operator+(const char    *s1, const GUTF8String &s2)
2743{ return GStringRep::UTF8::create(s1,s2); }
2744
2745#if HAS_WCHAR
2746GNativeString
2747operator+(const char    *s1, const GNativeString &s2)
2748{ return GStringRep::Native::create(s1,s2); }
2749
2750GNativeString&
2751GNativeString::operator+= (char ch)
2752{
2753  char s[2]; s[0]=ch; s[1]=0;
2754  return init(GStringRep::Native::create((const char*)*this, s));
2755}
2756
2757GNativeString&
2758GNativeString::operator+= (const char *str)
2759{
2760  return init(GStringRep::Native::create(*this,str));
2761}
2762
2763GNativeString&
2764GNativeString::operator+= (const GBaseString &str)
2765{
2766  return init(GStringRep::Native::create(*this,str));
2767}
2768
2769GNativeString
2770GNativeString::operator+(const GBaseString &s2) const
2771{ return GStringRep::Native::create(*this,s2); }
2772
2773GNativeString
2774GNativeString::operator+(const GNativeString &s2) const
2775{ return GStringRep::Native::create(*this,s2); }
2776
2777GNativeString
2778GNativeString::operator+(const char    *s2) const
2779{ return GStringRep::Native::create(*this,s2); }
2780
2781char *
2782GNativeString::getbuf(int n)
2783{
2784  if(ptr)
2785    init((*this)->getbuf(n));
2786  else if(n>0)
2787    init(GStringRep::Native::create(n));
2788  else
2789    init(0);
2790  return ptr?((*this)->data):0;
2791}
2792
2793void
2794GNativeString::setat(const int n, const char ch)
2795{
2796  if((!n)&&(!ptr))
2797  {
2798    init(GStringRep::Native::create(&ch,0,1));
2799  }else
2800  {
2801    init((*this)->setat(CheckSubscript(n),ch));
2802  }
2803}
2804
2805#endif
2806
2807
2808#ifdef HAVE_NAMESPACES
2809}
2810# ifndef NOT_USING_DJVU_NAMESPACE
2811using namespace DJVU;
2812# endif
2813#endif
Note: See TracBrowser for help on using the repository browser.