Diff for /parser3/src/main/pa_charset.C between versions 1.32 and 1.86

version 1.32, 2002/12/23 08:03:03 version 1.86, 2010/08/29 21:23:40
Line 1 Line 1
 /** @file  /** @file
         Parser: Charset connection implementation.          Parser: Charset connection implementation.
   
         Copyright(c) 2001, 2002 ArtLebedev Group (http://www.artlebedev.com)          Copyright(c) 2001-2009 ArtLebedev Group (http://www.artlebedev.com)
         Author: Alexander Petrosyan<paf@design.ru>(http://paf.design.ru)          Author: Alexander Petrosyan<paf@design.ru>(http://paf.design.ru)
 */  */
   
 static const char* IDENT_CHARSET_C="$Date$";  static const char * const IDENT_CHARSET_C="$Date$";
   
 #include "pa_charset.h"  #include "pa_charset.h"
   #include "pa_charsets.h"
   
 #ifdef XML  #ifdef XML
 #include "libxml/encoding.h"  #include "libxml/encoding.h"
 #endif  #endif
   
 // globals  //#define PA_PATCHED_LIBXML_BACKWARD
   
   // reduce memory usage by pre-calculation utf-8 string length
   #define PRECALCULATE_DEST_LENGTH
   
   // globals
   
 // consts  Charset::UTF8CaseTable::Rec UTF8CaseToUpperRecords[]={
   #include "utf8-to-upper.inc"
   };
   Charset::UTF8CaseTable UTF8CaseToUpper={
           sizeof(UTF8CaseToUpperRecords)/sizeof(Charset::UTF8CaseTable::Rec),
           UTF8CaseToUpperRecords};
   
 #define MAX_CHARSET_UNI_CODES 500  Charset::UTF8CaseTable::Rec UTF8CaseToLowerRecords[]={
   #include "utf8-to-lower.inc"
   };
   Charset::UTF8CaseTable UTF8CaseToLower={
           sizeof(UTF8CaseToLowerRecords)/sizeof(Charset::UTF8CaseTable::Rec),
           UTF8CaseToLowerRecords};
   
 // helpers  // helpers
   
Line 26  inline void prepare_case_tables(unsigned Line 41  inline void prepare_case_tables(unsigned
         unsigned char *lcc_table=tables+lcc_offset;          unsigned char *lcc_table=tables+lcc_offset;
         unsigned char *fcc_table=tables+fcc_offset;          unsigned char *fcc_table=tables+fcc_offset;
         for(int i=0; i<0x100; i++)          for(int i=0; i<0x100; i++)
                 lcc_table[i]=fcc_table[i]=i;                  lcc_table[i]=fcc_table[i]=(unsigned char)i;
 }  }
 inline void cstr2ctypes(unsigned char *tables, const unsigned char *cstr,   inline void cstr2ctypes(unsigned char *tables, const unsigned char *cstr, 
                                                 unsigned char bit) {                                                  unsigned char bit) {
Line 37  inline void cstr2ctypes(unsigned char *t Line 52  inline void cstr2ctypes(unsigned char *t
                 ctypes_table[c]|=bit;                  ctypes_table[c]|=bit;
         }          }
 }  }
 inline unsigned int to_wchar_code(const char *cstr) {  inline unsigned int to_wchar_code(const char* cstr) {
         if(!cstr || !*cstr)          if(!cstr || !*cstr)
                 return 0;                  return 0;
         if(cstr[1]==0)          if(cstr[1]==0)
Line 46  inline unsigned int to_wchar_code(const Line 61  inline unsigned int to_wchar_code(const
         char *error_pos;          char *error_pos;
         return(unsigned int)strtol(cstr, &error_pos, 0);          return(unsigned int)strtol(cstr, &error_pos, 0);
 }  }
 inline bool to_bool(const char *cstr) {  inline bool to_bool(const char* cstr) {
         return cstr && *cstr!=0;          return cstr && *cstr!=0;
 }  }
 static void element2ctypes(unsigned char c, bool belongs,  static void element2ctypes(unsigned char c, bool belongs,
Line 73  static void element2case(unsigned char f Line 88  static void element2case(unsigned char f
   
 // methods  // methods
   
 extern "C" unsigned char pcre_default_tables[]; // pcre/chartables.c  Charset::Charset(Request_charsets* charsets, const String::Body ANAME, const String* afile_spec): 
 Charset::Charset(Pool& apool, const String& aname, const String *request_file_spec): Pooled(apool),          FNAME(ANAME),
         fname(aname) {          FNAME_CSTR(ANAME.cstrm()) {
   
         char *name_cstr=fname.cstr();  
     for(char *c=name_cstr; *c; c++)  
         *c = toupper(*c);  
   
         if(request_file_spec) {          if(afile_spec) {
                 fisUTF8=false;                  fisUTF8=false;
                 loadDefinition(*request_file_spec);                  load_definition(*charsets, *afile_spec);
 #ifdef XML  #ifdef XML
                 addEncoding(name_cstr);                  addEncoding(FNAME_CSTR);
 #endif  #endif
         } else {          } else {
                 fisUTF8=true;                  fisUTF8=true;
                 // grab default onces [for UTF-8 so to be able to make a-z =>A-Z                  // grab default onces [for UTF-8 so to be able to make a-z =>A-Z
                 memcpy(pcre_tables, pcre_default_tables, sizeof(pcre_tables));                  memcpy(pcre_tables, _pcre_default_tables, sizeof(pcre_tables));
         }          }
   
 #ifdef XML  #ifdef XML
         initTranscoder(&aname, name_cstr);          initTranscoder(FNAME, FNAME_CSTR);
 #endif  
 }  
   
 Charset::~Charset() {  
 #ifdef XML  
         // not deleting transcoder, that's not our business  
 #endif  #endif
 }  }
   
 void Charset::loadDefinition(const String& request_file_spec) {  void Charset::load_definition(Request_charsets& charsets, const String& afile_spec) {
         // pcre_tables          // pcre_tables
         // lowcase, flipcase, bits digit+word+whitespace, masks          // lowcase, flipcase, bits digit+word+whitespace, masks
   
Line 115  void Charset::loadDefinition(const Strin Line 120  void Charset::loadDefinition(const Strin
         cstr2ctypes(pcre_tables,(const unsigned char *)"*+?{^.$|()[", ctype_meta);          cstr2ctypes(pcre_tables,(const unsigned char *)"*+?{^.$|()[", ctype_meta);
   
         // charset          // charset
         memset(tables.fromTable, 0, sizeof(tables.fromTable));          memset(&tables, 0, sizeof(tables));
         tables.toTable=(Charset_TransRec *)calloc(sizeof(Charset_TransRec)*MAX_CHARSET_UNI_CODES);  
         tables.toTableSize=0;  
         // strangly vital  
         tables.toTable[tables.toTableSize].intCh=0;  
         tables.toTable[tables.toTableSize].extCh=(XMLByte)0;  
         tables.toTableSize++;  
   
         // loading text          // loading text
         char *data=file_read_text(pool(), request_file_spec);          char *data=file_read_text(charsets, afile_spec);
   
         // ignore header          // ignore header
         getrow(&data);          getrow(&data);
   
         // parse cells          // parse cells
         char *row;          char *row;
         while(row=getrow(&data)) {          while((row=getrow(&data))) {
                 // remove empty&comment lines                  // remove empty&comment lines
                 if(!*row || *row=='#')                  if(!*row || *row=='#')
                         continue;                          continue;
   
                 // char white-space     digit   hex-digit       letter  word    lowercase       unicode1        unicode2                          // char white-space     digit   hex-digit       letter  word    lowercase       unicode1        unicode2        
                 unsigned int c=0;                  unsigned char c=0;
                 char *cell;                  char *cell;
                 for(int column=0; cell=lsplit(&row, '\t'); column++) {                  for(int column=0; (cell=lsplit(&row, '\t')); column++) {
                         switch(column) {                          switch(column) {
                         case 0: c=to_wchar_code(cell); break;                          case 0: c=(unsigned char)to_wchar_code(cell); break;
                         // pcre_tables                          // pcre_tables
                         case 1: element2ctypes(c, to_bool(cell), pcre_tables, ctype_space, cbit_space); break;                          case 1: element2ctypes(c, to_bool(cell), pcre_tables, ctype_space, cbit_space); break;
                         case 2: element2ctypes(c, to_bool(cell), pcre_tables, ctype_digit, cbit_digit); break;                          case 2: element2ctypes(c, to_bool(cell), pcre_tables, ctype_digit, cbit_digit); break;
                         case 3: element2ctypes(c, to_bool(cell), pcre_tables, ctype_xdigit); break;                          case 3: element2ctypes(c, to_bool(cell), pcre_tables, ctype_xdigit); break;
                         case 4: element2ctypes(c, to_bool(cell), pcre_tables, ctype_letter); break;                          case 4: element2ctypes(c, to_bool(cell), pcre_tables, ctype_letter); break;
                         case 5: element2ctypes(c, to_bool(cell), pcre_tables, ctype_word, cbit_word); break;                          case 5: element2ctypes(c, to_bool(cell), pcre_tables, ctype_word, cbit_word); break;
                         case 6: element2case(c, to_wchar_code(cell), pcre_tables); break;                          case 6: element2case(c, (unsigned char)to_wchar_code(cell), pcre_tables); break;
                         case 7:                          case 7:
                         case 8:                          case 8:
                                 // charset                                  // charset
                                 if(tables.toTableSize>MAX_CHARSET_UNI_CODES)                                  if(tables.toTableSize>MAX_CHARSET_UNI_CODES)
                                         throw Exception("parser.runtime",                                          throw Exception(PARSER_RUNTIME,
                                                 &request_file_spec,                                                  &afile_spec,
                                                 "charset must contain not more then %d unicode values", MAX_CHARSET_UNI_CODES);                                                  "charset must contain not more then %d unicode values", MAX_CHARSET_UNI_CODES);
   
                                 XMLCh unicode=(XMLCh)to_wchar_code(cell);                                  XMLCh unicode=(XMLCh)to_wchar_code(cell);
Line 178  void Charset::loadDefinition(const Strin Line 177  void Charset::loadDefinition(const Strin
   
 static int sort_cmp_Trans_rec_intCh(const void *a, const void *b) {  static int sort_cmp_Trans_rec_intCh(const void *a, const void *b) {
         return           return 
                 static_cast<const Charset_TransRec *>(a)->intCh-                  static_cast<const Charset::Tables::Rec *>(a)->intCh-
                 static_cast<const Charset_TransRec *>(b)->intCh;                  static_cast<const Charset::Tables::Rec *>(b)->intCh;
 }  }
   
 void Charset::sort_ToTable() {  void Charset::sort_ToTable() {
Line 190  void Charset::sort_ToTable() { Line 189  void Charset::sort_ToTable() {
         //fclose(f);          //fclose(f);
 }  }
   
   // @todo: precache for spedup searching
 static XMLByte xlatOneTo(const XMLCh toXlat,  static XMLByte xlatOneTo(const XMLCh toXlat,
                                                  const Charset::Tables& tables,                           const Charset::Tables& tables,
                                                  XMLByte not_found) {                           XMLByte not_found) {
     unsigned int    lowOfs = 0;          int lo = 0;
     unsigned int    hiOfs = tables.toTableSize - 1;          int hi = tables.toTableSize - 1;
     XMLByte         curByte = 0;          while(lo<=hi) {
     do {                  // Calc the mid point of the low and high offset.
         // Calc the mid point of the low and high offset.                  const unsigned int i = (lo + hi) / 2;
         const unsigned int midOfs =((hiOfs - lowOfs) / 2)+lowOfs;  
                   XMLCh cur=tables.toTable[i].intCh;
         //  If our test char is greater than the mid point char, then                  if(toXlat==cur)
         //  we move up to the upper half. Else we move to the lower                          return tables.toTable[i].extCh;
         //  half. If its equal, then its our guy.                  if(toXlat>cur)
         if(toXlat>tables.toTable[midOfs].intCh)                          lo = i+1;
             lowOfs = midOfs;  
                 else if(toXlat<tables.toTable[midOfs].intCh)  
                         hiOfs = midOfs;  
                 else                  else
                         return tables.toTable[midOfs].extCh;                          hi = i-1;
         } while(lowOfs+1<hiOfs);          }
           
     return not_found;          return not_found;
 }  }
   
 void Charset::transcode(Pool& pool,  String::C Charset::transcode(const String::C src,
         const Charset& source_charset, const void *source_body, size_t source_content_length,          const Charset& source_charset, 
         const Charset& dest_charset, const void *& dest_body, size_t& dest_content_length          const Charset& dest_charset) {
         ) {          if(!src.length)
         if(!source_content_length) {                  return String::C("", 0);
                 dest_body=0;  
                 dest_content_length=0;  
                 return;  
         }  
   
         switch((source_charset.isUTF8()?0x10:0x00)|(dest_charset.isUTF8()?0x01:0x00)) {          switch((source_charset.isUTF8()?0x10:0x00)|(dest_charset.isUTF8()?0x01:0x00)) {
                 default: // 0x00                  default: // 0x00
                         source_charset.transcodeToCharset(pool, dest_charset,                          return source_charset.transcodeToCharset(src, dest_charset);
                                 source_body, source_content_length,  
                                 dest_body, dest_content_length);  
                         break;  
                 case 0x01:                  case 0x01:
                         source_charset.transcodeToUTF8(pool,                          return source_charset.transcodeToUTF8(src);
                                 source_body, source_content_length,  
                                 dest_body, dest_content_length);  
                         break;  
                 case 0x10:                  case 0x10:
                         dest_charset.transcodeFromUTF8(pool,                          return dest_charset.transcodeFromUTF8(src);
                                 source_body, source_content_length,  
                                 dest_body, dest_content_length);  
                         break;  
                 case 0x11:                  case 0x11:
                         dest_body=source_body;                          return src;
                         dest_content_length=source_content_length;  
                         break;  
         }          }
 }  }
   
Line 281  static const XMLByte gUTFBytes[0x100] = Line 263  static const XMLByte gUTFBytes[0x100] =
 };  };
   
 static const uint gUTFOffsets[6] = {  static const uint gUTFOffsets[6] = {
     0, 0x3080, 0xE2080, 0x3C82080, 0xFA082080, 0x82082080          0, 0x3080, 0xE2080, 0x3C82080, 0xFA082080, 0x82082080
 };  };
   
 static const XMLByte gFirstByteMark[7] = {  static const XMLByte gFirstByteMark[7] = {
     0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC          0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC
 };  };
   
 static int transcodeToUTF8(  static int transcodeToUTF8(const XMLByte* srcData, int& srcLen,
                                                         const XMLByte* srcData, size_t& srcLen,                                  XMLByte *toFill, int& toFillLen,
                                                         XMLByte *toFill, size_t& toFillLen,                                  const Charset::Tables& tables) {
                                                         const Charset::Tables& tables) {  
         const XMLByte* srcPtr=srcData;          const XMLByte* srcPtr=srcData;
         const XMLByte* srcEnd=srcData+srcLen;          const XMLByte* srcEnd=srcData+srcLen;
         XMLByte* outPtr=toFill;          XMLByte* outPtr=toFill;
         XMLByte* outEnd=toFill+toFillLen;          XMLByte* outEnd=toFill+toFillLen;
   
     while(srcPtr<srcEnd) {          while(srcPtr<srcEnd) {
         uint curVal = tables.fromTable[*srcPtr];                  uint curVal = tables.fromTable[*srcPtr];
                 if(!curVal) {                  if(!curVal) {
             // use the replacement character                          // use the replacement character
             *outPtr++= '?';                          *outPtr++= '?';
             srcPtr++;                          srcPtr++;
             continue;                          continue;
         }                  }
   
         // Figure out how many bytes we need  
         unsigned int encodedBytes;  
         if(curVal<0x80)  
             encodedBytes = 1;  
         else if(curVal<0x800)  
             encodedBytes = 2;  
         else if(curVal<0x10000)  
             encodedBytes = 3;  
         else if(curVal<0x200000)  
             encodedBytes = 4;  
         else if(curVal<0x4000000)  
             encodedBytes = 5;  
         else if(curVal<= 0x7FFFFFFF)  
             encodedBytes = 6;  
         else {  
             // use the replacement character  
             *outPtr++= '?';  
             srcPtr++;  
             continue;  
         }  
   
         //  If we cannot fully get this char into the output buffer  
         if (outPtr + encodedBytes > outEnd)  
             break;  
   
         // We can do it, so update the source index  
         srcPtr++;  
   
         //  And spit out the bytes. We spit them out in reverse order  
         //  here, so bump up the output pointer and work down as we go.  
         outPtr+= encodedBytes;  
         switch(encodedBytes) {  
             case 6: *--outPtr = XMLByte((curVal | 0x80UL) & 0xBFUL);  
                      curVal>>= 6;  
             case 5: *--outPtr = XMLByte((curVal | 0x80UL) & 0xBFUL);  
                      curVal>>= 6;  
             case 4: *--outPtr = XMLByte((curVal | 0x80UL) & 0xBFUL);  
                      curVal>>= 6;  
             case 3: *--outPtr = XMLByte((curVal | 0x80UL) & 0xBFUL);  
                      curVal>>= 6;  
             case 2: *--outPtr = XMLByte((curVal | 0x80UL) & 0xBFUL);  
                      curVal>>= 6;  
             case 1: *--outPtr = XMLByte(curVal | gFirstByteMark[encodedBytes]);  
         }  
   
         // Add the encoded bytes back in again to indicate we've eaten them  
         outPtr+= encodedBytes;  
     }  
   
     // Update the bytes eaten  
     srcLen = srcPtr - srcData;  
   
     // Return the characters read                  // Figure out how many bytes we need
     toFillLen = outPtr - toFill;                  unsigned int encodedBytes;
                   if(curVal<0x80)
                           encodedBytes = 1;
                   else if(curVal<0x800)
                           encodedBytes = 2;
                   else if(curVal<0x10000)
                           encodedBytes = 3;
                   else if(curVal<0x200000)
                           encodedBytes = 4;
                   else if(curVal<0x4000000)
                           encodedBytes = 5;
                   else if(curVal<= 0x7FFFFFFF)
                           encodedBytes = 6;
                   else {
                           // use the replacement character
                           *outPtr++= '?';
                           srcPtr++;
                           continue;
                   }
   
                   //  If we cannot fully get this char into the output buffer
                   if (outPtr + encodedBytes > outEnd)
                           break;
                   
                   // We can do it, so update the source index
                   srcPtr++;
                   
                   //  And spit out the bytes. We spit them out in reverse order
                   //  here, so bump up the output pointer and work down as we go.
                   outPtr+= encodedBytes;
                   switch(encodedBytes) {
                           case 6: *--outPtr = XMLByte((curVal | 0x80UL) & 0xBFUL);
                                   curVal>>= 6;
                           case 5: *--outPtr = XMLByte((curVal | 0x80UL) & 0xBFUL);
                                   curVal>>= 6;
                           case 4: *--outPtr = XMLByte((curVal | 0x80UL) & 0xBFUL);
                                   curVal>>= 6;
                           case 3: *--outPtr = XMLByte((curVal | 0x80UL) & 0xBFUL);
                                   curVal>>= 6;
                           case 2: *--outPtr = XMLByte((curVal | 0x80UL) & 0xBFUL);
                                   curVal>>= 6;
                           case 1: *--outPtr = XMLByte(curVal | gFirstByteMark[encodedBytes]);
                   }
                   
                   // Add the encoded bytes back in again to indicate we've eaten them
                   outPtr+= encodedBytes;
           }
           
           // Update the bytes eaten
           srcLen = srcPtr - srcData;
           
           // Return the characters read
           toFillLen = outPtr - toFill;
           
         //return srcPtr==srcEnd?(int)toFillLen:-1;          //return srcPtr==srcEnd?(int)toFillLen:-1;
 /*  /*
 xmlCharEncodingInputFunc  xmlCharEncodingInputFunc
Line 372  of ocetes consumed. Line 353  of ocetes consumed.
         return 0;          return 0;
 }  }
 /// @todo digital entites only when xml/html output [at output in html/xml mode, in html part of a letter]  /// @todo digital entites only when xml/html output [at output in html/xml mode, in html part of a letter]
 static int transcodeFromUTF8(  static int transcodeFromUTF8(const XMLByte* srcData, int& srcLen,
                                                                 const XMLByte *srcData, size_t& srcLen,                                  XMLByte* toFill, int& toFillLen,
                                                                 XMLByte* toFill, size_t& toFillLen,                                  const Charset::Tables& tables) {
                                                                 const Charset::Tables& tables) {  
         const XMLByte* srcPtr=srcData;          const XMLByte* srcPtr=srcData;
         const XMLByte* srcEnd=srcData+srcLen;          const XMLByte* srcEnd=srcData+srcLen;
         XMLByte* outPtr=toFill;          XMLByte* outPtr=toFill;
         XMLByte* outEnd=toFill+toFillLen;          XMLByte* outEnd=toFill+toFillLen;
   
     //  We now loop until we either run out of input data, or room to store          //  We now loop until we either run out of input data, or room to store
     while ((srcPtr < srcEnd) && (outPtr < outEnd)) {          while ((srcPtr < srcEnd) && (outPtr < outEnd)) {
         // Get the next leading byte out                  // Get the next leading byte out
         const XMLByte firstByte = *srcPtr;                  const XMLByte firstByte =* srcPtr;
                   
         // Special-case ASCII, which is a leading byte value of<= 127                  // Special-case ASCII, which is a leading byte value of<= 127
         if(firstByte<= 127) {                  if(firstByte<=127) {
             *outPtr++= firstByte;                          *outPtr++= firstByte;
             srcPtr++;                          srcPtr++;
             continue;                          continue;
         }                  }
                   
         // See how many trailing src bytes this sequence is going to require                  // See how many trailing src bytes this sequence is going to require
         const unsigned int trailingBytes = gUTFBytes[firstByte];                  const unsigned int trailingBytes = gUTFBytes[firstByte];
                   
         //  If there are not enough source bytes to do this one, then we                  //  If there are not enough source bytes to do this one, then we
         //  are done. Note that we done>= here because we are implicitly                  //  are done. Note that we done>= here because we are implicitly
         //  counting the 1 byte we get no matter what.                  //  counting the 1 byte we get no matter what.
         if(srcPtr+trailingBytes>= srcEnd)                  if(srcPtr+trailingBytes>= srcEnd)
             break;                          break;
                   
         // Looks ok, so lets build up the value                  // Looks ok, so lets build up the value
         uint tmpVal=0;                  uint tmpVal=0;
         switch(trailingBytes) {                  switch(trailingBytes) {
             case 5: tmpVal+=*srcPtr++; tmpVal<<=6;                  case 5: tmpVal+=*srcPtr++; tmpVal<<=6;
             case 4: tmpVal+=*srcPtr++; tmpVal<<=6;                  case 4: tmpVal+=*srcPtr++; tmpVal<<=6;
             case 3: tmpVal+=*srcPtr++; tmpVal<<=6;                  case 3: tmpVal+=*srcPtr++; tmpVal<<=6;
             case 2: tmpVal+=*srcPtr++; tmpVal<<=6;                  case 2: tmpVal+=*srcPtr++; tmpVal<<=6;
             case 1: tmpVal+=*srcPtr++; tmpVal<<=6;                  case 1: tmpVal+=*srcPtr++; tmpVal<<=6;
             case 0: tmpVal+=*srcPtr++;                  case 0: tmpVal+=*srcPtr++;
                      break;                          break;
                           
             default:                  default:
                 throw Exception(0,  
                                         0,  
                                         "transcodeFromUTF8 error: wrong trailingBytes value(%d)", trailingBytes);  
         }  
         tmpVal-=gUTFOffsets[trailingBytes];  
   
         //  If it will fit into a single char, then put it in. Otherwise  
         //  fail [*encode it as a surrogate pair. If its not valid, use the  
         //  replacement char.*]  
         if(!(tmpVal & 0xFFFF0000)) {  
                         if(XMLByte xlat=xlatOneTo(tmpVal, tables, 0))  
                                 *outPtr++=xlat;  
                         else   
                                 outPtr+=sprintf((char *)outPtr, "&#%d;", tmpVal); // &#decimal;  
                 } else  
                         throw Exception(0,                          throw Exception(0,
                                 0,                                  0,
                                 "transcodeFromUTF8 error: too big tmpVal(0x%08X)", tmpVal);                                  "transcodeFromUTF8 error: wrong trailingBytes value(%d)", trailingBytes); // never
                   }
                   tmpVal-=gUTFOffsets[trailingBytes];
                   
                   //  If it will fit into a single char, then put it in. Otherwise
                   //  fail [*encode it as a surrogate pair. If its not valid, use the
                   //  replacement char.*]
                   if(!(tmpVal & 0xFFFF0000)) {
                           if(XMLByte xlat=xlatOneTo(tmpVal, tables, 0))
                                   *outPtr++=xlat;
                           else {
                                   outPtr+=sprintf((char *)outPtr, "&#%u;", tmpVal); // &#decimal;
                           }
                   } else {
                           const XMLByte* recoverPtr=srcPtr-trailingBytes-1;
                           for(uint i=0; i<=trailingBytes; i++)
                                   outPtr+=sprintf((char*)outPtr, "%%%02X", *recoverPtr++);
                   }
         }          }
           
     // Update the bytes eaten          // Update the bytes eaten
     srcLen = srcPtr - srcData;          srcLen = srcPtr - srcData;
           
     // Return the characters read          // Return the characters read
     toFillLen = outPtr - toFill;          toFillLen = outPtr - toFill;
   
         //return srcPtr==srcEnd?(int)toFillLen:-1;          //return srcPtr==srcEnd?(int)toFillLen:-1;
 /*  /*
Line 451  of ocetes consumed. Line 433  of ocetes consumed.
         return 0;          return 0;
 }  }
   
 /// @todo not so memory-hungry with prescan  static bool need_escape(XMLByte c){
 void Charset::transcodeToUTF8(Pool& pool,          return
                                                                  const void *source_body, size_t source_content_length,                  !(
                                                                  const void *& adest_body, size_t& dest_content_length) const {                          (c<=127)
         dest_content_length=source_content_length*6/*so that surly enough, max utf8 seq len=6*/;                          && (
         XMLByte *dest_body=(XMLByte*)pool.malloc(dest_content_length);                                  ((c>='0') && (c<='9'))
                                   || ((c>='A') && (c<='Z'))
                                   || ((c>='a') && (c<='z'))
                                   || strchr("*@-_+./", c)!=0
                           )
                   );
   }
   
   // read one UTF8 char and return length of this char (in bytes)
   static unsigned int readUTF8Char(const XMLByte*& srcPtr, const XMLByte* srcEnd, XMLByte& firstByte, XMLCh& UTF8Char){
           if(!srcPtr || !*srcPtr || srcPtr>=srcEnd)
                   return 0;
   
           firstByte=*srcPtr;
   
           if(firstByte<=127){
                   UTF8Char=firstByte;
                   srcPtr++;
                   return 1;
           }
   
           unsigned int trailingBytes=gUTFBytes[firstByte];
   
           if(srcPtr+trailingBytes>=srcEnd){
                   return 0; // not enough bytes in source string for reading
           }
   
           uint tmpVal=0;
           switch(trailingBytes){
                   case 5: tmpVal+=*srcPtr++; tmpVal<<=6;
                   case 4: tmpVal+=*srcPtr++; tmpVal<<=6;
                   case 3: tmpVal+=*srcPtr++; tmpVal<<=6;
                   case 2: tmpVal+=*srcPtr++; tmpVal<<=6;
                   case 1: tmpVal+=*srcPtr++; tmpVal<<=6;
                   case 0: tmpVal+=*srcPtr++;
           }
   
           tmpVal-=gUTFOffsets[trailingBytes];
           UTF8Char=tmpVal;
   
           return trailingBytes+1;
   }
   
   // skip UTF8 char and return length of this char (in bytes)
   static unsigned int skipUTF8Char(const XMLByte*& srcPtr, const XMLByte* srcEnd){
           if(!srcPtr || !*srcPtr || srcPtr>=srcEnd)
                   return 0;
   
           unsigned int trailingBytes=gUTFBytes[*srcPtr]+1;
           srcPtr+=trailingBytes;
   
           return trailingBytes;
   }
   
   // read non-UTF8 char, and return number of bytes needed for storing this char in UTF8
   static unsigned int readChar(const XMLByte*& srcPtr, const XMLByte* srcEnd, XMLByte& firstByte, XMLCh& UTF8Char, const Charset::Tables& tables){
           if(!srcPtr || !*srcPtr || srcPtr>=srcEnd)
                   return 0;
   
           firstByte=*srcPtr++;
           UTF8Char=tables.fromTable[firstByte];
   
           if(UTF8Char<0x80)
                   return 1;
           else if(UTF8Char<0x800)
                   return 2;
           else if(UTF8Char<0x10000)
                   return 3;
           else if(UTF8Char<0x200000)
                   return 4;
           else if(UTF8Char<0x4000000)
                   return 5;
           else if(UTF8Char<= 0x7FFFFFFF)
                   return 6;
   
           // will use the replacement character '?'
           firstByte=0;
           return 1;
   }
   
   size_t Charset::calc_escaped_length_UTF8(XMLByte* src, size_t src_length){
           size_t dest_length=0;
   
           for(UTF8_string_iterator i(src, src_length); i.has_next(); ){
                   if(i.getCharSize()==1)
                           dest_length+=!need_escape(i.getFirstByte())?1/*as-is*/:3/*%XX*/;
                   else
                           dest_length+=6; // %uXXXX
           }
   
           return dest_length;
   }
   
   size_t Charset::calc_escaped_length(const XMLByte* src, size_t src_length, const Charset::Tables& tables){
           const XMLByte* src_end=src+src_length;
           XMLByte first_byte;
           XMLCh UTF8_char;
           size_t dest_length=0;
   
           while(uint char_size=readChar(src, src_end, first_byte, UTF8_char, tables)){
                   if(char_size==1)
                           dest_length+=(!first_byte/*replacement char '?'*/ || !need_escape(first_byte))?1:3/*'%XX'*/;
                   else
                           dest_length+=6; // %uXXXX
           }
   
           return dest_length;
   }
   
   size_t Charset::calc_escaped_length(const String::C src, const Charset& source_charset){
           if(!src.length)
                   return 0;
   
   #ifdef PRECALCULATE_DEST_LENGTH
           if(source_charset.isUTF8())
                   return calc_escaped_length_UTF8((XMLByte *)src.str, src.length);
           else
                   return calc_escaped_length((XMLByte *)src.str, src.length, source_charset.tables);
   #else
           return src_length*6; // enough for %uXXXX but too memory-hungry
   #endif
   }
   
   #define escape_char(dest_ptr, char_size, first_byte, UTF8_char) \
           if(char_size==1) \
                   if(first_byte){ \
                           if(need_escape(first_byte)) \
                                   dest_ptr+=sprintf((char*)dest_ptr, "%%%02X", first_byte); /* %XX */ \
                           else \
                                   *dest_ptr++=first_byte; /*as is*/ \
                   } else \
                           *dest_ptr++='?'; /* replacement char '?' */ \
           else \
                   dest_ptr+=sprintf((char*)dest_ptr, "%%u%04X", UTF8_char); // %uXXXX
   
   
   size_t Charset::escape_UTF8(const XMLByte* src, size_t src_length, XMLByte* dest) {
           XMLByte* dest_ptr=dest;
   
           // loop until we either run out of input data
           for(UTF8_string_iterator i((XMLByte *)src, src_length); i.has_next(); )
                   escape_char(dest_ptr, i.getCharSize(), i.getFirstByte(), i.next())
           
           return dest_ptr - dest;
   }
   
   size_t Charset::escape(const XMLByte* src, size_t src_length, XMLByte* dest, const Charset::Tables& tables) {
           const XMLByte* src_end=src+src_length;
           XMLByte* dest_ptr=dest;
   
           XMLByte first_byte;
           XMLCh UTF8_char;
           uint char_size;
   
           while(char_size=readChar(src, src_end, first_byte, UTF8_char, tables))
                   escape_char(dest_ptr, char_size, first_byte, UTF8_char)
   
           return dest_ptr - dest;
   }
   
   String::C Charset::escape(const String::C src, const Charset& source_charset){
           if(!src.length)
                   return String::C("", 0);
   
           size_t dest_calculated_length=calc_escaped_length(src, source_charset);
           XMLByte *dest_body=new(PointerFreeGC) XMLByte[dest_calculated_length+1/*terminator*/];
   
           size_t dest_length;
           if(source_charset.isUTF8())
                   dest_length=escape_UTF8((XMLByte *)src.str, src.length, dest_body);
           else
                   dest_length=escape((XMLByte *)src.str, src.length, dest_body, source_charset.tables);
   
           if(dest_length>dest_calculated_length)
                   throw Exception(0, 0, "Charset::escape buffer overflow");
   
           dest_body[dest_length]=0; // terminator
           return String::C((char*)dest_body, dest_length);
   }
   
   String::Body Charset::escape(const String::Body src, const Charset& source_charset) {
           String::C dest=Charset::escape(String::C(src.cstr(), src.length()), source_charset);
           return String::Body(dest.length ? dest.str:0);
   }
   
   String& Charset::escape(const String& src, const Charset& source_charset) {
           if(src.is_empty())
                   return *new String();
   
           return *new String(escape((String::Body)src, source_charset), String::L_CLEAN);
   }
   
   inline bool need_json_escape(unsigned char c){
           return strchr("\n\"\\/\t\r\b\f", c)!=0;
   }
   
   size_t Charset::calc_JSON_escaped_length_UTF8(XMLByte* src, size_t src_length){
           size_t dest_length=0;
   
           for(UTF8_string_iterator i(src, src_length); i.has_next(); ){
                   if(i.getCharSize()==1)
                           dest_length+=need_json_escape(i.getFirstByte()) ? 2 : 1;
                   else
                           dest_length+=6; // \uXXXX
           }
   
           return dest_length;
   }
   
   size_t Charset::calc_JSON_escaped_length(const XMLByte* src, size_t src_length, const Charset::Tables& tables){
           const XMLByte* src_end=src+src_length;
           XMLByte first_byte;
           XMLCh UTF8_char;
           size_t dest_length=0;
   
           while(uint char_size=readChar(src, src_end, first_byte, UTF8_char, tables)){
                   if(char_size==1)
                           dest_length+=(!first_byte/*replacement char '?'*/ || !need_json_escape(first_byte))? 1 : 2;
                   else
                           dest_length+=6; // \uXXXX
           }
   
           return dest_length;
   }
   
   size_t Charset::calc_JSON_escaped_length(const String::C src, const Charset& source_charset){
           if(!src.length)
                   return 0;
   
   #ifdef PRECALCULATE_DEST_LENGTH
           if(source_charset.isUTF8())
                   return calc_JSON_escaped_length_UTF8((XMLByte *)src.str, src.length);
           else
                   return calc_JSON_escaped_length((XMLByte *)src.str, src.length, source_charset.tables);
   #else
           return src_length*6; // enough for \uXXXX but too memory-hungry
   #endif
   }
   
   #define escape_char_JSON(dest_ptr, char_size, first_byte, UTF8_char) \
           if(char_size==1) \
                   switch(first_byte){ \
                           case '\n': *dest_ptr++='\\'; *dest_ptr++='n';  break; \
                           case '"' : *dest_ptr++='\\'; *dest_ptr++='"';  break; \
                           case '\\': *dest_ptr++='\\'; *dest_ptr++='\\'; break; \
                           case '/' : *dest_ptr++='\\'; *dest_ptr++='/';  break; \
                           case '\t': *dest_ptr++='\\'; *dest_ptr++='t';  break; \
                           case '\r': *dest_ptr++='\\'; *dest_ptr++='r';  break; \
                           case '\b': *dest_ptr++='\\'; *dest_ptr++='b';  break; \
                           case '\f': *dest_ptr++='\\'; *dest_ptr++='f';  break; \
                           case   0 : *dest_ptr++='?'; break; /*replacement char*/ \
                           default  : *dest_ptr++=first_byte; \
                   } \
           else \
                   dest_ptr+=sprintf((char*)dest_ptr, "\\u%04X", UTF8_char); // \uXXXX
   
   
   size_t Charset::escape_JSON_UTF8(const XMLByte* src, size_t src_length, XMLByte* dest) {
           XMLByte* dest_ptr=dest;
   
           // loop until we either run out of input data
           for(UTF8_string_iterator i((XMLByte *)src, src_length); i.has_next(); )
                   escape_char_JSON(dest_ptr, i.getCharSize(), i.getFirstByte(), i.next())
   
           return dest_ptr - dest;
   }
   
   size_t Charset::escape_JSON(const XMLByte* src, size_t src_length, XMLByte* dest, const Charset::Tables& tables) {
           const XMLByte* src_end=src+src_length;
           XMLByte* dest_ptr=dest;
   
           XMLByte first_byte;
           XMLCh UTF8_char;
           uint char_size;
   
           while(char_size=readChar(src, src_end, first_byte, UTF8_char, tables))
                   escape_char_JSON(dest_ptr, char_size, first_byte, UTF8_char)
   
           return dest_ptr - dest;
   }
   
   String::C Charset::escape_JSON(const String::C src, const Charset& source_charset){
           if(!src.length)
                   return String::C("", 0);
   
           size_t dest_calculated_length=calc_JSON_escaped_length(src, source_charset);
           XMLByte *dest_body=new(PointerFreeGC) XMLByte[dest_calculated_length+1/*terminator*/];
   
           size_t dest_length;
           if(source_charset.isUTF8())
                   dest_length=escape_JSON_UTF8((XMLByte *)src.str, src.length, dest_body);
           else
                   dest_length=escape_JSON((XMLByte *)src.str, src.length, dest_body, source_charset.tables);
   
           if(dest_length>dest_calculated_length)
                   throw Exception(0, 0, "Charset::escape_JSON buffer overflow");
   
           dest_body[dest_length]=0; // terminator
           return String::C((char*)dest_body, dest_length);
   }
   
   String::Body Charset::escape_JSON(const String::Body src, const Charset& source_charset) {
           String::C dest=Charset::escape_JSON(String::C(src.cstr(), src.length()), source_charset);
           return String::Body(dest.length ? dest.str:0);
   }
   
   String& Charset::escape_JSON(const String& src, const Charset& source_charset) {
           if(src.is_empty())
                   return *new String();
   
           return *new String(escape_JSON((String::Body)src, source_charset), String::L_CLEAN);
   }
   
   const String::C Charset::transcodeToUTF8(const String::C src) const {
           int src_length=src.length;
   
   #ifdef PRECALCULATE_DEST_LENGTH
           int dest_length=0;
           const XMLByte* srcPtr=(XMLByte*)src.str;
           const XMLByte* srcEnd=srcPtr+src_length;
           XMLByte firstByte;
           XMLCh UTF8Char;
           while(uint charSize=readChar(srcPtr, srcEnd, firstByte, UTF8Char, tables))
                   dest_length+=charSize;
   #else
           int dest_length=src_length*6; // so that surly enough (max utf8 seq len=6) but too memory-hungry
   #endif
   
   #ifndef NDEBUG
           int saved_dest_length=dest_length;
   #endif
           XMLByte *dest_body=new(PointerFreeGC) XMLByte[dest_length+1/*for terminator*/];
   
         if(::transcodeToUTF8(          if(::transcodeToUTF8(
                 (XMLByte *)source_body, source_content_length,                  (XMLByte *)src.str, src_length,
                 dest_body, dest_content_length,                  dest_body, dest_length,
                 tables)<0)                  tables)<0)
                 throw(0, 0,                  throw Exception(0,
                         0,                          0,
                         "Charset::transcodeToUTF8 buffer overflow");                          "Charset::transcodeToUTF8 buffer overflow");
   
         // return          assert(dest_length<=saved_dest_length);
         adest_body=dest_body;          dest_body[dest_length]=0; // terminator
           return String::C((char*)dest_body, dest_length);
   }
   
   static XMLCh change_case_UTF8(const XMLCh src, const Charset::UTF8CaseTable& table) {
           int lo = 0;
           int hi = table.size - 1;
           while(lo<=hi) {
                   // Calc the mid point of the low and high offset.
                   const unsigned int i = (lo + hi) / 2;
   
                   XMLCh cur=table.records[i].from;
                   if(src==cur)
                           return table.records[i].to;
                   if(src>cur)
                           lo = i+1;
                   else
                           hi = i-1;
           }
   
           // not found
           return src;
 }  }
 void Charset::transcodeFromUTF8(Pool& pool,  
                                                                    const void *source_body, size_t source_content_length,  static void store_UTF8(XMLCh src, XMLByte*& outPtr){
                                                                    const void *& adest_body, size_t& dest_content_length) const {          if(!src) {
         dest_content_length=source_content_length*6/*so that surly enough, "&#255;" has max ratio */;                  // use the replacement character
         XMLByte *dest_body=(XMLByte*)pool.malloc(dest_content_length);                  *outPtr++= '?';
                   return;
           }
   
           // Figure out how many bytes we need
           unsigned int encodedBytes;
           if(src<0x80)
                   encodedBytes = 1;
           else if(src<0x800)
                   encodedBytes = 2;
           else if(src<0x10000)
                   encodedBytes = 3;
           else if(src<0x200000)
                   encodedBytes = 4;
           else if(src<0x4000000)
                   encodedBytes = 5;
           else if(src<= 0x7FFFFFFF)
                   encodedBytes = 6;
           else {
                   // use the replacement character
                   *outPtr++= '?';
                   return;
           }
   
           //  And spit out the bytes. We spit them out in reverse order
           //  here, so bump up the output pointer and work down as we go.
           outPtr+= encodedBytes;
           switch(encodedBytes) {
           case 6: *--outPtr = XMLByte((src | 0x80UL) & 0xBFUL);
                   src>>= 6;
           case 5: *--outPtr = XMLByte((src | 0x80UL) & 0xBFUL);
                   src>>= 6;
           case 4: *--outPtr = XMLByte((src | 0x80UL) & 0xBFUL);
                   src>>= 6;
           case 3: *--outPtr = XMLByte((src | 0x80UL) & 0xBFUL);
                   src>>= 6;
           case 2: *--outPtr = XMLByte((src | 0x80UL) & 0xBFUL);
                   src>>= 6;
           case 1: *--outPtr = XMLByte(src | gFirstByteMark[encodedBytes]);
           }
           
           // Add the encoded bytes back in again to indicate we've eaten them
           outPtr+= encodedBytes;
   }
   
   static void change_case_UTF8(XMLCh src, XMLByte*& outPtr, 
                                                   const Charset::UTF8CaseTable& table) {
           store_UTF8(change_case_UTF8(src, table), outPtr);
   };
   void change_case_UTF8(const XMLByte* srcData, size_t srcLen,
                                             XMLByte* toFill, size_t toFillLen,
                                             const Charset::UTF8CaseTable& table) {
           const XMLByte* srcPtr=srcData;
           const XMLByte* srcEnd=srcData+srcLen;
           XMLByte* outPtr=toFill;
           XMLByte* outEnd=toFill+toFillLen;
   
           //  We now loop until we either run out of input data, or room to store
           while ((srcPtr < srcEnd) && (outPtr < outEnd)) {
                   // Get the next leading byte out
                   const XMLByte firstByte =* srcPtr;
   
                   if(firstByte<=127) {
                           change_case_UTF8(firstByte, outPtr, table);
                           srcPtr++;
                           continue;
                   }
                   
                   // See how many trailing src bytes this sequence is going to require
                   const unsigned int trailingBytes = gUTFBytes[firstByte];
                   
                   // Looks ok, so lets build up the value
                   uint tmpVal=0;
                   switch(trailingBytes) {
                   case 5: tmpVal+=*srcPtr++; tmpVal<<=6;
                   case 4: tmpVal+=*srcPtr++; tmpVal<<=6;
                   case 3: tmpVal+=*srcPtr++; tmpVal<<=6;
                   case 2: tmpVal+=*srcPtr++; tmpVal<<=6;
                   case 1: tmpVal+=*srcPtr++; tmpVal<<=6;
                   case 0: tmpVal+=*srcPtr++;
                           break;
                           
                   default:
                           throw Exception(0,
                                   0,
                                   "change_case_UTF8 error: wrong trailingBytes value(%d)", trailingBytes);
                   }
                   tmpVal-=gUTFOffsets[trailingBytes];
                   
                   //  If it will fit into a single char, then put it in. Otherwise
                   //  fail [*encode it as a surrogate pair. If its not valid, use the
                   //  replacement char.*]
                   if(!(tmpVal & 0xFFFF0000))
                           change_case_UTF8(tmpVal, outPtr, table);
                   else
                           throw Exception(0,
                                   0,
                                   "change_case_UTF8 error: too big tmpVal(0x%08X)", tmpVal);
           }
           
           if(srcPtr!=outPtr)
                   throw Exception(0,  
                           0,
                           "change_case_UTF8 error: end pointers do not match");
   }
   
   static size_t getDecNumLength(XMLCh UTF8Char){
           return
                   (UTF8Char < 100)
                           ?2
                           :(UTF8Char < 1000)
                                   ?3
                                   :(UTF8Char < 10000)
                                           ?4
                                           :5;
   }
   
   const String::C Charset::transcodeFromUTF8(const String::C src) const {
           int src_length=src.length;
   #ifdef PRECALCULATE_DEST_LENGTH
           int dest_length=0;
           for(UTF8_string_iterator i((XMLByte *)src.str, src_length); i.has_next(); ){
                   if(i.getCharSize()==1)
                           dest_length++;
                   else
                           dest_length+=(i.next() & 0xFFFF0000)
                                                           ?i.getCharSize()*3      // '%XX' for each byte
                                                           :(xlatOneTo(i.next(), tables, 0)!=0)
                                                                   ?1              // can convert it to single char
                                                                   :getDecNumLength(i.next())+3;           // &#XX; - &#XXXXX;
           }
   #else
           // so that surly enough, "&#XXX;" has max ratio (huh? 8 bytes needed for '&#XXXXX;')
           int dest_length=src_length*6;
   #endif
   
   #ifndef NDEBUG
           int saved_dest_length=dest_length;
   #endif
           XMLByte *dest_body=new(PointerFreeGC) XMLByte[dest_length+1/*for terminator*/];
   
         if(::transcodeFromUTF8(          if(::transcodeFromUTF8(
                 (XMLByte *)source_body, source_content_length,                  (XMLByte *)src.str, src_length,
                 dest_body, dest_content_length,                  dest_body, dest_length,
                 tables)<0)                  tables)<0)
                 throw(0, 0,                  throw Exception(0, 
                         0,                          0,
                         "Charset::transcodeToUTF8 buffer overflow");                          "Charset::transcodeFromUTF8 buffer overflow");
   
         // return          assert(dest_length<=saved_dest_length);
         adest_body=dest_body;          dest_body[dest_length]=0; // terminator
           return String::C((char*)dest_body, dest_length);
 }  }
   
 /// transcode using both charsets  /// transcode using both charsets
 void Charset::transcodeToCharset(Pool& pool,  const String::C Charset::transcodeToCharset(const String::C src, 
                                                                            const Charset& dest_charset,                                                  const Charset& dest_charset) const {
                                                                            const void *source_body, size_t source_content_length,          if(&dest_charset==this) 
                                                                            const void *& adest_body, size_t& adest_content_length) const {                  return src;
         if(&dest_charset==this) {          else {
                 adest_body=source_body;                  size_t dest_length=src.length;
                 adest_content_length=source_content_length;                  XMLByte* dest_body=new(PointerFreeGC) XMLByte[dest_length+1/*for terminator*/];
         } else {  
                 size_t dest_content_length=source_content_length;                  XMLByte* output=dest_body;
                 unsigned char *dest_body=(unsigned char *)pool.malloc(dest_content_length);                  const XMLByte* input=(XMLByte *)src.str;
                   while(XMLCh c=*input++) {
                 const XMLByte* srcPtr=(XMLByte *)source_body;                          XMLCh curVal = tables.fromTable[c];
                 const XMLByte* srcEnd=(XMLByte *)source_body+source_content_length;                          *output++=curVal?
                                   xlatOneTo(curVal, dest_charset.tables, '?') // OK
                 for(XMLByte* outPtr=dest_body; srcPtr<srcEnd; srcPtr++) {                                  :'?'; // use the replacement character
                         XMLCh curVal = tables.fromTable[*srcPtr];  
                         if(curVal)   
                                 *outPtr++=xlatOneTo(curVal, dest_charset.tables, '?');  
                         else {  
                                 // use the replacement character  
                                 *outPtr++= '?';  
                         }         
                 }                  }
   
                 adest_body=dest_body;                  dest_body[dest_length]=0; // terminator
                 adest_content_length=dest_content_length;                  return String::C((char*)dest_body, dest_length);
         }          }
 }                         }                       
   
 #ifdef XML  void Charset::store_Char(XMLByte*& outPtr, XMLCh src, XMLByte not_found){
 static int         xml256CharEncodingInputFunc     (          if(isUTF8())
                                                                                                         unsigned char *out,                  store_UTF8(src, outPtr);
                                                                                                         int *outlen,          else if(char ch=xlatOneTo(src, tables, not_found))
                                                                                                         const unsigned char *in,                          *outPtr++=ch;
                                                                                                         int *inlen,   
                                                                                                         void *info) {  
         return transcodeToUTF8(  
                                                         in, *(size_t*)inlen,  
                                                         out, *(size_t*)outlen,  
                                                         *(const Charset::Tables *)info);  
 }  
   
 static int         xml256CharEncodingOutputFunc    (  
                                                                                                         unsigned char *out,  
                                                                                                         int *outlen,  
                                                                                                         const unsigned char *in,  
                                                                                                         int *inlen,   
                                                                                                         void *info) {  
         return transcodeFromUTF8(  
                                                         in, *(size_t*)inlen,  
                                                         out, *(size_t*)outlen,  
                                                         *(const Charset::Tables *)info);  
 }  }
   
   #ifdef XML
   
   static const Charset::Tables* tables[MAX_CHARSETS];
   
   #ifdef PA_PATCHED_LIBXML_BACKWARD
   
   #define declareXml256ioFuncs(i) \
           static int xml256CharEncodingInputFunc##i( \
                   unsigned char *out, int *outlen, \
                   const unsigned char *in, int *inlen, void*) { \
                   return transcodeToUTF8( \
                           in, *inlen, \
                           out, *outlen, \
                           *tables[i]); \
           } \
           static int xml256CharEncodingOutputFunc##i( \
                   unsigned char *out, int *outlen, \
                   const unsigned char *in, int *inlen, void*) { \
                   return transcodeFromUTF8( \
                           in, *inlen, \
                           out, *outlen, \
                           *tables[i]); \
           }
   
   #else
   
   #define declareXml256ioFuncs(i) \
           static int xml256CharEncodingInputFunc##i( \
                   unsigned char *out, int *outlen, \
                   const unsigned char *in, int *inlen) { \
                   return transcodeToUTF8( \
                           in, *inlen, \
                           out, *outlen, \
                           *tables[i]); \
           } \
           static int xml256CharEncodingOutputFunc##i( \
                   unsigned char *out, int *outlen, \
                   const unsigned char *in, int *inlen) { \
                   return transcodeFromUTF8( \
                           in, *inlen, \
                           out, *outlen, \
                           *tables[i]); \
           }
   
   #endif
   
   
   declareXml256ioFuncs(0) declareXml256ioFuncs(1)
   declareXml256ioFuncs(2) declareXml256ioFuncs(3)
   declareXml256ioFuncs(4) declareXml256ioFuncs(5)
   declareXml256ioFuncs(6) declareXml256ioFuncs(7)
   declareXml256ioFuncs(8) declareXml256ioFuncs(9)
   
   static xmlCharEncodingInputFunc inputFuncs[MAX_CHARSETS]={
           xml256CharEncodingInputFunc0,   xml256CharEncodingInputFunc1,
           xml256CharEncodingInputFunc2,   xml256CharEncodingInputFunc3,
           xml256CharEncodingInputFunc4,   xml256CharEncodingInputFunc5,
           xml256CharEncodingInputFunc6,   xml256CharEncodingInputFunc7,
           xml256CharEncodingInputFunc8,   xml256CharEncodingInputFunc9
   };
   static xmlCharEncodingOutputFunc outputFuncs[MAX_CHARSETS]={
           xml256CharEncodingOutputFunc0,  xml256CharEncodingOutputFunc1,
           xml256CharEncodingOutputFunc2,  xml256CharEncodingOutputFunc3,
           xml256CharEncodingOutputFunc4,  xml256CharEncodingOutputFunc5,
           xml256CharEncodingOutputFunc6,  xml256CharEncodingOutputFunc7,
           xml256CharEncodingOutputFunc8,  xml256CharEncodingOutputFunc9
   };
   static size_t handlers_count=0;
   
 void Charset::addEncoding(char *name_cstr) {  void Charset::addEncoding(char *name_cstr) {
         xmlCharEncodingHandler *handler=          if(handlers_count==MAX_CHARSETS)
                 (xmlCharEncodingHandler *)malloc(sizeof(xmlCharEncodingHandler));                  throw Exception(0,
         handler->name=name_cstr;                          0,
         handler->input=xml256CharEncodingInputFunc; handler->inputInfo=&tables;                          "already allocated %d handlers, no space for new encoding '%s'",
         handler->output=xml256CharEncodingOutputFunc; handler->outputInfo=&tables;                                  MAX_CHARSETS, name_cstr);
   
           xmlCharEncodingHandler* handler=new(UseGC) xmlCharEncodingHandler;
           {
                   handler->name=name_cstr;
                   handler->input=inputFuncs[handlers_count]; 
                   handler->output=outputFuncs[handlers_count]; 
                   ::tables[handlers_count]=&tables;
                   handlers_count++;
           }
                   
         xmlRegisterCharEncodingHandler(handler);          xmlRegisterCharEncodingHandler(handler);
   
 }  }
   
 void Charset::initTranscoder(const String *source, const char *name_cstr) {  void Charset::initTranscoder(const String::Body NAME, const char* name_cstr) {
         ftranscoder=xmlFindCharEncodingHandler(name_cstr);          ftranscoder=xmlFindCharEncodingHandler(name_cstr);
         transcoder(source); // check right way          transcoder(NAME); // check right way
 }  }
   
 xmlCharEncodingHandler *Charset::transcoder(const String *source) {  xmlCharEncodingHandler& Charset::transcoder(const String::Body NAME) {
         if(!ftranscoder)          if(!ftranscoder)
                 throw Exception("parser.runtime",                  throw Exception(PARSER_RUNTIME,
                         source,                          new String(NAME, String::L_TAINTED),
                         "unsupported encoding");                          "unsupported encoding");
         return ftranscoder;          return *ftranscoder;
 }  }
   
 const char *Charset::transcode_cstr(xmlChar *s) {  String::C Charset::transcode_cstr(const xmlChar* s) {
         if(!s)          if(!s)
                 return "";                  return String::C("", 0);
   
         int inlen=strlen((const char *)s);          int inlen=strlen((const char*)s);
         int outlen=inlen+1; // max          int outlen=inlen*6/*strlen("&#255;")*/; // max
         char *out=(char *)malloc(outlen*sizeof(char));  #ifndef NDEBUG
           int saved_outlen=outlen;
   #endif
           char *out=new(PointerFreeGC) char[outlen+1];
                   
         int error;          int error;
         if(xmlCharEncodingOutputFunc output=transcoder(0)->output) {          if(xmlCharEncodingOutputFunc output=transcoder(FNAME).output) {
                 error=output(                  error=output(
                         (unsigned char*)out, &outlen,                          (unsigned char*)out, &outlen,
                         (const unsigned char*)s, &inlen,                          (const unsigned char*)s, &inlen
                         transcoder(0)->outputInfo);  #ifdef PA_PATCHED_LIBXML_BACKWARD
                           ,0
   #endif
                           );
         } else {          } else {
                 memcpy(out, s, outlen=inlen);                  memcpy(out, s, outlen=inlen);
                 error=0;                  error=0;
Line 589  const char *Charset::transcode_cstr(xmlC Line 1122  const char *Charset::transcode_cstr(xmlC
                         0,                          0,
                         "transcode_cstr failed (%d)", error);                          "transcode_cstr failed (%d)", error);
   
         out[outlen/*surely would be less then on input*/]=0;          assert(outlen<=saved_outlen); out[outlen]=0;
         return out;          return String::C(out, outlen);
 }  }
 String& Charset::transcode(xmlChar *s  const String& Charset::transcode(const xmlChar* s) { 
 #ifndef NO_STRING_ORIGIN          String::C cstr=transcode_cstr(s);
                 , const String *origin          return *new String(cstr.str, String::L_TAINTED);
 #endif  
                                                    ) {   
         String& result=*NEW String(pool());  
         result.APPEND_CLEAN(transcode_cstr(s), 0/*auto-size*/, origin->origin().file, origin->origin().line);  
         return result;   
 }  
 const char *Charset::transcode_cstr(GdomeDOMString *s) {   
         return s?transcode_cstr(BAD_CAST s->str):"";  
 }  
 String& Charset::transcode(GdomeDOMString *s  
 #ifndef NO_STRING_ORIGIN  
                 , const String *origin  
 #endif  
                                                    ) {   
         String& result=*NEW String(pool());  
         result.APPEND_CLEAN(transcode_cstr(s), 0/*auto-size*/, origin->origin().file, origin->origin().line);  
         return result;   
 }  }
   
 /// @test less memory using -maybe- xmlParserInputBufferCreateMem  /// @test less memory using -maybe- xmlParserInputBufferCreateMem
 xmlChar *Charset::transcode_buf2xchar(const char *buf, size_t buf_size) {  xmlChar* Charset::transcode_buf2xchar(const char* buf, size_t buf_size) {
         unsigned char *out;          xmlChar* out;
         int outlen;          int outlen;
         int error;          int error;
         if(xmlCharEncodingInputFunc input=transcoder(0)->input) {  #ifndef NDEBUG
                 outlen=buf_size*6/*max*/;          int saved_outlen;
                 out=(unsigned char*)malloc((outlen+1)*sizeof(unsigned char));  #endif
           if(xmlCharEncodingInputFunc input=transcoder(FNAME).input) {
                   outlen=buf_size*6/*max UTF8 bytes per char*/;
   #ifndef NDEBUG
                   saved_outlen=outlen;
   #endif
                   out=(xmlChar*)xmlMalloc(outlen+1);
                 error=input(                  error=input(
                         out, &outlen,                          out, &outlen,
                         (const unsigned char *)buf,  (int *)&buf_size,                          (const unsigned char*)buf, (int*)&buf_size
                         transcoder(0)->inputInfo);  #ifdef PA_PATCHED_LIBXML_BACKWARD
                           ,0
   #endif
                           );
         } else {          } else {
                 outlen=buf_size;                  outlen=buf_size;
                 out=(unsigned char*)malloc((outlen+1)*sizeof(unsigned char));  #ifndef NDEBUG
                   saved_outlen=outlen;
   #endif
                   out=(xmlChar*)xmlMalloc(outlen+1);
                 memcpy(out, buf, outlen);                  memcpy(out, buf, outlen);
                 error=0;                  error=0;
         }          }
Line 638  xmlChar *Charset::transcode_buf2xchar(co Line 1166  xmlChar *Charset::transcode_buf2xchar(co
                         0,                          0,
                         "transcode_buf failed (%d)", error);                          "transcode_buf failed (%d)", error);
   
         out[outlen/*surely would be less then on input*/]=0;          assert(outlen<=saved_outlen); out[outlen]=0;
         return (xmlChar *)out;          return out;
   }
   
   xmlChar* Charset::transcode(const String& s) {
           String::Body sbody=s.cstr_to_string_body_untaint(String::L_AS_IS);
           return transcode_buf2xchar(sbody.cstr(), sbody.length()); 
   }
   
   xmlChar* Charset::transcode(const String::Body s) {
           return transcode_buf2xchar(s.cstr(), s.length()); 
   }
   #endif
   
   String::Body Charset::transcode(const String::Body src, 
           const Charset& source_transcoder, 
           const Charset& dest_transcoder) {
   
           const char *src_ptr=src.cstr();
           size_t src_size=src.length();
   
           String::C dest=Charset::transcode(String::C(src_ptr, src_size), source_transcoder, dest_transcoder);
   
           return String::Body(dest.length ? dest.str:0);
 }  }
 GdomeDOMString_auto_ptr Charset::transcode_buf2dom(const char *buf, size_t buf_size) {   
         return GdomeDOMString_auto_ptr((gchar*)transcode_buf2xchar(buf, buf_size));  String& Charset::transcode(const String& src, 
           const Charset& source_transcoder, 
           const Charset& dest_transcoder) {
           if(src.is_empty())
                   return *new String();
   
           return *new String(transcode((String::Body)src, source_transcoder, dest_transcoder), String::L_CLEAN);
 }  }
 GdomeDOMString_auto_ptr Charset::transcode(const String& s) {   
         const char *cstr=s.cstr(String::UL_UNSPECIFIED);  
   
         return transcode_buf2dom(cstr, strlen(cstr));   void Charset::transcode(ArrayString& src,
           const Charset& source_transcoder, 
           const Charset& dest_transcoder) {
           for(size_t i=0; i<src.count(); i++)
                   src.put(i, &transcode(*src[i], source_transcoder, dest_transcoder));
 }  }
   
   #ifndef DOXYGEN
   struct Transcode_pair_info {
           const Charset* source_transcoder;
           const Charset* dest_transcoder;
   };
 #endif  #endif
   static void transcode_pair(HashStringValue::key_type /*akey*/, 
                            String::Body& avalue, 
                            Transcode_pair_info* info) {
           avalue=Charset::transcode(avalue,
                   *info->source_transcoder, 
                   *info->dest_transcoder);
   }
   
   void Charset::transcode(HashStringString& src,
           const Charset& source_transcoder, 
           const Charset& dest_transcoder) {
           Transcode_pair_info info={&source_transcoder, &dest_transcoder};
           src.for_each_ref<Transcode_pair_info*>(transcode_pair, &info);
   }
   
   size_t getUTF8BytePos(const XMLByte* srcBegin, const XMLByte* srcEnd, size_t charPos){
           const XMLByte* ptr=srcBegin;
           while(charPos-- && skipUTF8Char(ptr, srcEnd));
   
           return ptr-srcBegin;
   }
   
   size_t getUTF8CharPos(const XMLByte* srcBegin, const XMLByte* srcEnd, size_t bytePos){
           size_t charPos=0;
           const XMLByte* ptr=srcBegin;
           const XMLByte* ptrEnd=srcBegin+bytePos;
           while(skipUTF8Char(ptr, srcEnd)){
                   if(ptr>ptrEnd)
                           return charPos;
                   charPos++;
           }
   
           // scan till end but position in bytes still too low
           throw Exception(0,
                                           0,
                                           "Error convertion byte pos to char pos");
   }
   
   size_t lengthUTF8(const XMLByte* srcBegin, const XMLByte* srcEnd){
           size_t size=0;
           while(skipUTF8Char(srcBegin, srcEnd))
                   size++;
   
           return size;
   }
   
   unsigned int lengthUTF8Char(const XMLByte c){
           return gUTFBytes[c]+1;
   }
   
   bool UTF8_string_iterator::has_next(){
           fcharSize=readUTF8Char(fsrcPtr, fsrcEnd, ffirstByte, fUTF8Char);
           return fcharSize!=0;
   }

Removed from v.1.32  
changed lines
  Added in v.1.86


E-mail: