source: trunk/libdjvu/GString.cpp @ 207

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

DJVU plugin: djvulibre, fix opening filenames with non-latin chars

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