Diff for /parser3/src/main/pa_charset.C between versions 1.35 and 1.60

version 1.35, 2003/07/24 11:31:23 version 1.60, 2008/07/15 12:53:10
Line 1 Line 1
 /** @file  /** @file
         Parser: Charset connection implementation.          Parser: Charset connection implementation.
   
         Copyright(c) 2001-2003 ArtLebedev Group (http://www.artlebedev.com)          Copyright(c) 2001-2005 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"  #include "pa_charsets.h"
Line 14  static const char* IDENT_CHARSET_C="$Dat Line 14  static const char* IDENT_CHARSET_C="$Dat
 #include "libxml/encoding.h"  #include "libxml/encoding.h"
 #endif  #endif
   
   //#define PA_PATCHED_LIBXML_BACKWARD
   #define PRECALCULATE_DEST_LENGTH
   
   // globals
   
   Charset::UTF8CaseTable::Rec UTF8CaseToUpperRecords[]={
   #include "utf8-to-upper.inc"
   };
   Charset::UTF8CaseTable UTF8CaseToUpper={
           sizeof(UTF8CaseToUpperRecords)/sizeof(Charset::UTF8CaseTable::Rec),
           UTF8CaseToUpperRecords};
   
   Charset::UTF8CaseTable::Rec UTF8CaseToLowerRecords[]={
   #include "utf8-to-lower.inc"
   };
   Charset::UTF8CaseTable UTF8CaseToLower={
           sizeof(UTF8CaseToLowerRecords)/sizeof(Charset::UTF8CaseTable::Rec),
           UTF8CaseToLowerRecords};
   
 // helpers  // helpers
   
 inline void prepare_case_tables(unsigned char *tables) {  inline void prepare_case_tables(unsigned char *tables) {
         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 68  static void element2case(unsigned char f Line 87  static void element2case(unsigned char f
 // methods  // methods
   
 extern "C" unsigned char pcre_default_tables[]; // pcre/chartables.c  extern "C" unsigned char pcre_default_tables[]; // pcre/chartables.c
 Charset::Charset(Request_charsets* charsets, const StringBody ANAME, const String* afile_spec):   Charset::Charset(Request_charsets* charsets, const String::Body ANAME, const String* afile_spec): 
         FNAME(ANAME),          FNAME(ANAME),
         FNAME_CSTR(ANAME.cstrm()) {          FNAME_CSTR(ANAME.cstrm()) {
   
Line 101  void Charset::load_definition(Request_ch Line 120  void Charset::load_definition(Request_ch
   
         // charset          // charset
         memset(&tables, 0, sizeof(tables));          memset(&tables, 0, sizeof(tables));
         // 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(charsets, afile_spec);          char *data=file_read_text(charsets, afile_spec);
Line 114  void Charset::load_definition(Request_ch Line 129  void Charset::load_definition(Request_ch
   
         // 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,
                                                 &afile_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);
   
Line 161  void Charset::load_definition(Request_ch Line 176  void Charset::load_definition(Request_ch
   
 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 173  void Charset::sort_ToTable() { Line 188  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 midOfs =((hiOfs - lowOfs) / 2)+lowOfs;                  const unsigned int i = (lo + hi) / 2;
                   
                 //  If our test char is greater than the mid point char, then                  XMLCh cur=tables.toTable[i].intCh;
                 //  we move up to the upper half. Else we move to the lower                  if(toXlat==cur)
                 //  half. If its equal, then its our guy.                          return tables.toTable[i].extCh;
                 if(toXlat>tables.toTable[midOfs].intCh)                  if(toXlat>cur)
                         lowOfs = midOfs;                          lo = i+1;
                 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;
 }  }
Line 305  static int transcodeToUTF8(const XMLByte Line 318  static int transcodeToUTF8(const XMLByte
                 //  here, so bump up the output pointer and work down as we go.                  //  here, so bump up the output pointer and work down as we go.
                 outPtr+= encodedBytes;                  outPtr+= encodedBytes;
                 switch(encodedBytes) {                  switch(encodedBytes) {
                 case 6: *--outPtr = XMLByte((curVal | 0x80UL) & 0xBFUL);                          case 6: *--outPtr = XMLByte((curVal | 0x80UL) & 0xBFUL);
                         curVal>>= 6;                                  curVal>>= 6;
                 case 5: *--outPtr = XMLByte((curVal | 0x80UL) & 0xBFUL);                          case 5: *--outPtr = XMLByte((curVal | 0x80UL) & 0xBFUL);
                         curVal>>= 6;                                  curVal>>= 6;
                 case 4: *--outPtr = XMLByte((curVal | 0x80UL) & 0xBFUL);                          case 4: *--outPtr = XMLByte((curVal | 0x80UL) & 0xBFUL);
                         curVal>>= 6;                                  curVal>>= 6;
                 case 3: *--outPtr = XMLByte((curVal | 0x80UL) & 0xBFUL);                          case 3: *--outPtr = XMLByte((curVal | 0x80UL) & 0xBFUL);
                         curVal>>= 6;                                  curVal>>= 6;
                 case 2: *--outPtr = XMLByte((curVal | 0x80UL) & 0xBFUL);                          case 2: *--outPtr = XMLByte((curVal | 0x80UL) & 0xBFUL);
                         curVal>>= 6;                                  curVal>>= 6;
                 case 1: *--outPtr = XMLByte(curVal | gFirstByteMark[encodedBytes]);                          case 1: *--outPtr = XMLByte(curVal | gFirstByteMark[encodedBytes]);
                 }                  }
                                   
                 // Add the encoded bytes back in again to indicate we've eaten them                  // Add the encoded bytes back in again to indicate we've eaten them
Line 353  static int transcodeFromUTF8(const XMLBy Line 366  static int transcodeFromUTF8(const XMLBy
                 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;
Line 382  static int transcodeFromUTF8(const XMLBy Line 395  static int transcodeFromUTF8(const XMLBy
                 default:                  default:
                         throw Exception(0,                          throw Exception(0,
                                 0,                                  0,
                                 "transcodeFromUTF8 error: wrong trailingBytes value(%d)", trailingBytes);                                  "transcodeFromUTF8 error: wrong trailingBytes value(%d)", trailingBytes); // never
                 }                  }
                 tmpVal-=gUTFOffsets[trailingBytes];                  tmpVal-=gUTFOffsets[trailingBytes];
                                   
Line 392  static int transcodeFromUTF8(const XMLBy Line 405  static int transcodeFromUTF8(const XMLBy
                 if(!(tmpVal & 0xFFFF0000)) {                  if(!(tmpVal & 0xFFFF0000)) {
                         if(XMLByte xlat=xlatOneTo(tmpVal, tables, 0))                          if(XMLByte xlat=xlatOneTo(tmpVal, tables, 0))
                                 *outPtr++=xlat;                                  *outPtr++=xlat;
                         else                           else {
                                 outPtr+=sprintf((char *)outPtr, "&#%d;", tmpVal); // &#decimal;                                  outPtr+=sprintf((char *)outPtr, "&#%u;", tmpVal); // &#decimal;
                 } else                          }
                         throw Exception(0,                  } else {
                         0,                          const XMLByte* recoverPtr=srcPtr-trailingBytes-1;
                         "transcodeFromUTF8 error: too big tmpVal(0x%08X)", tmpVal);                          for(uint i=0; i<=trailingBytes; i++)
                                   outPtr+=sprintf((char*)outPtr, "%%%02X", *recoverPtr++);
                   }
         }          }
                   
         // Update the bytes eaten          // Update the bytes eaten
Line 417  of ocetes consumed. Line 432  of ocetes consumed.
         return 0;          return 0;
 }  }
   
 /// @todo not so memory-hungry with prescan  static bool is_escaped(char c){
           return
                   !(c<=127
                   && (
                           ((c>='0') && (c<='9'))
                           || ((c>='A') && (c<='Z'))
                           || ((c>='a') && (c<='z'))
                           || strchr("*@-_+./", c)!=0
                   ));
   }
   
   // read one utf8 character, return number of bytes needed for store it
   static unsigned int readChar(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;
   }
   
   // read char, return number of bytes needed for store it as 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;
   }
   
   static int escape(const XMLByte* srcData, size_t& srcLen,
                                XMLByte* toFill, size_t& toFillLen) {
           const XMLByte* srcPtr=srcData;
           const XMLByte* srcEnd=srcData+srcLen;
           XMLByte* outPtr=toFill;
           XMLByte* outEnd=toFill+toFillLen;
           XMLByte firstByte;
           XMLCh UTF8Char;
           uint charSize;
   
           // loop until we either run out of input data, or room to store
           while((outPtr < outEnd) && (charSize=readChar(srcPtr, srcEnd, firstByte, UTF8Char))){
                   if(charSize==1){
                           if(is_escaped(firstByte)) // %XX
                                   outPtr+=sprintf((char*)outPtr, "%%%02X", firstByte);
                           else
                                   *outPtr++=firstByte;
                   } else
                           outPtr+=sprintf((char*)outPtr, "%%u%04X", UTF8Char); // %uXXXX
           }
           
           // Update the bytes eaten
           srcLen=srcPtr-srcData;
           
           // Return the characters read
           toFillLen=outPtr-toFill;
   
           return 0;
   }
   
   static int escape(const XMLByte* srcData, size_t& srcLen,
                              XMLByte *toFill, size_t& toFillLen,
                              const Charset::Tables& tables) {
           const XMLByte* srcPtr=srcData;
           const XMLByte* srcEnd=srcData+srcLen;
           XMLByte* outPtr=toFill;
           //XMLByte* outEnd=toFill+toFillLen;
           XMLByte firstByte;
           XMLCh UTF8Char;
           uint charSize;
   
           while(charSize=readChar(srcPtr, srcEnd, firstByte, UTF8Char, tables)){
                   if(charSize==1){
                           if(firstByte){
                                   if(is_escaped(firstByte)) // %XX
                                           outPtr+=sprintf((char*)outPtr, "%%%02X", firstByte);
                                   else
                                           *outPtr++=firstByte;
                           } else // add replacement char '?'
                                   *outPtr++='?';
                   } else
                           outPtr+=sprintf((char*)outPtr, "%%u%04X", UTF8Char); // %uXXXX
           }
   
           // Update the bytes eaten
           srcLen = srcPtr - srcData;
           
           // Return the characters read
           toFillLen = outPtr - toFill;
           
           return 0;
   }
   
   
   String::C Charset::escape(const String::C src, const Charset& source_charset){
           size_t src_length=src.length;
           if(!src_length)
                   return String::C("", 0);
   
   #ifdef PRECALCULATE_DEST_LENGTH
           size_t dest_length=0;
           const XMLByte* srcPtr=(XMLByte*)src.str;
           const XMLByte* srcEnd=srcPtr+src_length;
           XMLByte firstByte;
           XMLCh UTF8Char;
   
           if(source_charset.isUTF8()){
                   while(uint charSize=readChar(srcPtr, srcEnd, firstByte, UTF8Char)){
                           if(charSize==1)
                                   dest_length+=!is_escaped(firstByte)?1:3/*%XX*/;
                           else
                                   dest_length+=6; // '%uXXXX'
                   }
           } else {
                   while(uint charSize=readChar(srcPtr, srcEnd, firstByte, UTF8Char, source_charset.tables)){
                           if(charSize==1)
                                   dest_length+=(!firstByte/*replacement char '?'*/ || !is_escaped(firstByte))?1:3/*'%XX'*/;
                           else
                                   dest_length+=6; // '%uXXXX'
                   }
           }
   #else
           size_t dest_length=src_length*6; // enough for %uXXXX but too memory-hungry
   #endif
   
           //throw Exception(0,0,"%u",dest_length);
   
   #ifndef NDEBUG
           size_t saved_dest_length=dest_length;
   #endif
           XMLByte *dest_body=new(PointerFreeGC) XMLByte[dest_length+1/*for terminator*/];
   
           int status;
           if(source_charset.isUTF8()){
                   status=::escape((XMLByte *)src.str, src_length, dest_body, dest_length);
           } else {
                   status=::escape((XMLByte *)src.str, src_length, dest_body, dest_length, source_charset.tables);
           }
   
           if(status<0)
                   throw Exception(0,
                           0,
                           "Charset::escapeString buffer overflow");
   
           assert(dest_length<=saved_dest_length);
           dest_body[dest_length]=0; // terminator
           return String::C((char*)dest_body, dest_length);
   }
           
   
 const String::C Charset::transcodeToUTF8(const String::C src) const {  const String::C Charset::transcodeToUTF8(const String::C src) const {
         size_t src_length=src.length;          size_t src_length=src.length;
         size_t dest_length=src.length*6/*so that surly enough, max utf8 seq len=6*/;  
   #ifdef PRECALCULATE_DEST_LENGTH
           size_t 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
           size_t dest_length=src_length*6; // so that surly enough (max utf8 seq len=6) but too memory-hyngry
   #endif
   
           //throw Exception(0,0,"%u",dest_length);
   
 #ifndef NDEBUG  #ifndef NDEBUG
         size_t saved_dest_length=dest_length;          size_t saved_dest_length=dest_length;
 #endif  #endif
Line 430  const String::C Charset::transcodeToUTF8 Line 650  const String::C Charset::transcodeToUTF8
                 (XMLByte *)src.str, src_length,                  (XMLByte *)src.str, src_length,
                 dest_body, dest_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");
   
         assert(dest_length<=saved_dest_length); dest_body[dest_length]=0; // terminator          assert(dest_length<=saved_dest_length);
           dest_body[dest_length]=0; // terminator
         return String::C((char*)dest_body, dest_length);          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;
   }
   
   static void store_UTF8(XMLCh src, XMLByte*& outPtr){
           if(!src) {
                   // use the replacement character
                   *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 {  const String::C Charset::transcodeFromUTF8(const String::C src) const {
         size_t src_length=src.length;          size_t src_length=src.length;
         size_t dest_length=src.length*6/*so that surly enough, "&#255;" has max ratio */;  
   #ifdef PRECALCULATE_DEST_LENGTH
           size_t 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)){
                   if(charSize==1)
                           dest_length++;
                   else
                           dest_length+=(UTF8Char & 0xFFFF0000)
                                                           ?charSize*3     // '%XX' for each byte
                                                           :(xlatOneTo(UTF8Char, tables, 0)!=0)
                                                                   ?1              // can convert it to single char
                                                                   :getDecNumLength(UTF8Char)+3;           // &#XX; - &#XXXXX;
           }
   #else
           // so that surly enough, "&#XXX;" has max ratio (huh? 8 bytes needed for '&#XXXXX;')
           size_t dest_length=src_length*6;
   #endif
   
           //throw Exception(0,0,"%u",dest_length);
   
 #ifndef NDEBUG  #ifndef NDEBUG
         size_t saved_dest_length=dest_length;          size_t saved_dest_length=dest_length;
 #endif  #endif
Line 449  const String::C Charset::transcodeFromUT Line 834  const String::C Charset::transcodeFromUT
                 (XMLByte *)src.str, src_length,                  (XMLByte *)src.str, src_length,
                 dest_body, dest_length,                  dest_body, dest_length,
                 tables)<0)                  tables)<0)
                 throw(0, 0,                  throw Exception(0, 
                         0,                          0,
                         "Charset::transcodeFromUTF8 buffer overflow");                          "Charset::transcodeFromUTF8 buffer overflow");
   
         assert(dest_length<=saved_dest_length); dest_body[dest_length]=0; // terminator          assert(dest_length<=saved_dest_length);
           dest_body[dest_length]=0; // terminator
         return String::C((char*)dest_body, dest_length);          return String::C((char*)dest_body, dest_length);
 }  }
   
Line 480  const String::C Charset::transcodeToChar Line 866  const String::C Charset::transcodeToChar
         }          }
 }                         }                       
   
   void Charset::store_Char(XMLByte*& outPtr, XMLCh src, XMLByte not_found){
           if(isUTF8())
                   store_UTF8(src, outPtr);
           else if(char ch=xlatOneTo(src, tables, not_found))
                           *outPtr++=ch;
   }
   
 #ifdef XML  #ifdef XML
   
 static const Charset::Tables* tables[MAX_CHARSETS];  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, *(size_t*)inlen, \
                           out, *(size_t*)outlen, \
                           *tables[i]); \
           } \
           static int xml256CharEncodingOutputFunc##i( \
                   unsigned char *out, int *outlen, \
                   const unsigned char *in, int *inlen, void*) { \
                   return transcodeFromUTF8( \
                           in, *(size_t*)inlen, \
                           out, *(size_t*)outlen, \
                           *tables[i]); \
           }
   
   #else
   
 #define declareXml256ioFuncs(i) \  #define declareXml256ioFuncs(i) \
         static int xml256CharEncodingInputFunc##i( \          static int xml256CharEncodingInputFunc##i( \
                 unsigned char *out, int *outlen, \                  unsigned char *out, int *outlen, \
Line 502  static const Charset::Tables* tables[MAX Line 917  static const Charset::Tables* tables[MAX
                         *tables[i]); \                          *tables[i]); \
         }          }
   
   #endif
   
   
 declareXml256ioFuncs(0) declareXml256ioFuncs(1)  declareXml256ioFuncs(0) declareXml256ioFuncs(1)
 declareXml256ioFuncs(2) declareXml256ioFuncs(3)  declareXml256ioFuncs(2) declareXml256ioFuncs(3)
 declareXml256ioFuncs(4) declareXml256ioFuncs(5)  declareXml256ioFuncs(4) declareXml256ioFuncs(5)
Line 531  void Charset::addEncoding(char *name_cst Line 949  void Charset::addEncoding(char *name_cst
                         "already allocated %d handlers, no space for new encoding '%s'",                          "already allocated %d handlers, no space for new encoding '%s'",
                                 MAX_CHARSETS, name_cstr);                                  MAX_CHARSETS, name_cstr);
   
         xmlCharEncodingHandler* handler=new(PointerFreeGC) xmlCharEncodingHandler;          xmlCharEncodingHandler* handler=new(UseGC) xmlCharEncodingHandler;
         {          {
                 handler->name=name_cstr;                  handler->name=name_cstr;
                 handler->input=inputFuncs[handlers_count];                   handler->input=inputFuncs[handlers_count]; 
Line 544  void Charset::addEncoding(char *name_cst Line 962  void Charset::addEncoding(char *name_cst
   
 }  }
   
 void Charset::initTranscoder(const StringBody NAME, const char* name_cstr) {  void Charset::initTranscoder(const String::Body NAME, const char* name_cstr) {
         ftranscoder=xmlFindCharEncodingHandler(name_cstr);          ftranscoder=xmlFindCharEncodingHandler(name_cstr);
         transcoder(NAME); // check right way          transcoder(NAME); // check right way
 }  }
   
 xmlCharEncodingHandler& Charset::transcoder(const StringBody NAME) {  xmlCharEncodingHandler& Charset::transcoder(const String::Body NAME) {
         if(!ftranscoder)          if(!ftranscoder)
                 throw Exception("parser.runtime",                  throw Exception(PARSER_RUNTIME,
                         new String(NAME, String::L_TAINTED),                          new String(NAME, String::L_TAINTED),
                         "unsupported encoding");                          "unsupported encoding");
         return *ftranscoder;          return *ftranscoder;
 }  }
   
 String::C Charset::transcode_cstr(xmlChar* s) {  String::C Charset::transcode_cstr(const xmlChar* s) {
         if(!s)          if(!s)
                 return String::C("", 0);                  return String::C("", 0);
   
         int inlen=strlen((const char*)s);          int inlen=strlen((const char*)s);
         int outlen=inlen; // max          int outlen=inlen*6/*strlen("&#255;")*/; // max
 #ifndef NDEBUG  #ifndef NDEBUG
         int saved_outlen=outlen;          int saved_outlen=outlen;
 #endif  #endif
Line 572  String::C Charset::transcode_cstr(xmlCha Line 990  String::C Charset::transcode_cstr(xmlCha
         if(xmlCharEncodingOutputFunc output=transcoder(FNAME).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
   #ifdef PA_PATCHED_LIBXML_BACKWARD
                           ,0
   #endif
                           );
         } else {          } else {
                 memcpy(out, s, outlen=inlen);                  memcpy(out, s, outlen=inlen);
                 error=0;                  error=0;
Line 585  String::C Charset::transcode_cstr(xmlCha Line 1007  String::C Charset::transcode_cstr(xmlCha
         assert(outlen<=saved_outlen); out[outlen]=0;          assert(outlen<=saved_outlen); out[outlen]=0;
         return String::C(out, outlen);          return String::C(out, outlen);
 }  }
 const String& Charset::transcode(xmlChar* s) {   const String& Charset::transcode(const xmlChar* s) { 
         String::C cstr=transcode_cstr(s);  
         return *new String(cstr.str, cstr.length, true);  
 }  
 String::C Charset::transcode_cstr(GdomeDOMString* s) {   
         return s?transcode_cstr(BAD_CAST s->str)  
                 :String::C("", 0);  
 }  
 const String& Charset::transcode(GdomeDOMString* s) {   
         String::C cstr=transcode_cstr(s);          String::C cstr=transcode_cstr(s);
         return *new String(cstr.str, cstr.length, true);          return *new String(cstr.str, cstr.length, true);
 }  }
Line 607  xmlChar* Charset::transcode_buf2xchar(co Line 1021  xmlChar* Charset::transcode_buf2xchar(co
         int saved_outlen;          int saved_outlen;
 #endif  #endif
         if(xmlCharEncodingInputFunc input=transcoder(FNAME).input) {          if(xmlCharEncodingInputFunc input=transcoder(FNAME).input) {
                 outlen=buf_size*6/*max*/;                  outlen=buf_size*6/*max UTF8 bytes per char*/;
 #ifndef NDEBUG  #ifndef NDEBUG
                 saved_outlen=outlen;                  saved_outlen=outlen;
 #endif  #endif
                 out=(xmlChar*)xmlMalloc(outlen+1);                  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
   #ifdef PA_PATCHED_LIBXML_BACKWARD
                           ,0
   #endif
                           );
         } else {          } else {
                 outlen=buf_size;                  outlen=buf_size;
 #ifndef NDEBUG  #ifndef NDEBUG
Line 633  xmlChar* Charset::transcode_buf2xchar(co Line 1051  xmlChar* Charset::transcode_buf2xchar(co
         assert(outlen<=saved_outlen); out[outlen]=0;          assert(outlen<=saved_outlen); out[outlen]=0;
         return out;          return out;
 }  }
 GdomeDOMString_auto_ptr Charset::transcode_buf2dom(const char* buf, size_t buf_size) {   xmlChar* Charset::transcode(const String& s) { 
         return GdomeDOMString_auto_ptr(transcode_buf2xchar(buf, buf_size));  
 }  
 GdomeDOMString_auto_ptr Charset::transcode(const String& s) {   
         const char* cstr=s.cstr(String::L_UNSPECIFIED);          const char* cstr=s.cstr(String::L_UNSPECIFIED);
   
         return transcode_buf2dom(cstr, strlen(cstr));           return transcode_buf2xchar(cstr, strlen(cstr)); 
 }  }
 GdomeDOMString_auto_ptr Charset::transcode(const StringBody s) {   xmlChar* Charset::transcode(const String::Body s) { 
         const char* cstr=s.cstr();          const char* cstr=s.cstr();
   
         return transcode_buf2dom(cstr, s.length());           return transcode_buf2xchar(cstr, s.length()); 
 }  }
   #endif
   
 StringBody Charset::transcode(const StringBody src,   String::Body Charset::transcode(const String::Body src, 
         const Charset& source_transcoder,           const Charset& source_transcoder, 
         const Charset& dest_transcoder) {          const Charset& dest_transcoder) {
   
Line 658  StringBody Charset::transcode(const Stri Line 1074  StringBody Charset::transcode(const Stri
                 source_transcoder,                  source_transcoder,
                 dest_transcoder);                  dest_transcoder);
   
         return StringBody(dest.str, dest.length);          return String::Body(dest.str, dest.length);
 }  }
   
 String& Charset::transcode(const String& src,   String& Charset::transcode(const String& src, 
Line 667  String& Charset::transcode(const String& Line 1083  String& Charset::transcode(const String&
         if(!src.length())          if(!src.length())
                 return *new String("", 0, false);                  return *new String("", 0, false);
   
         return *new String(transcode((StringBody)src, source_transcoder, dest_transcoder), String::L_CLEAN);          return *new String(transcode((String::Body)src, source_transcoder, dest_transcoder), String::L_CLEAN);
 }  }
   
 void Charset::transcode(ArrayString& src,  void Charset::transcode(ArrayString& src,
Line 683  struct Transcode_pair_info { Line 1099  struct Transcode_pair_info {
         const Charset* dest_transcoder;          const Charset* dest_transcoder;
 };  };
 #endif  #endif
 static void transcode_pair(const StringBody akey,   static void transcode_pair(const String::Body /*akey*/, 
                          StringBody& avalue,                            String::Body& avalue, 
                          Transcode_pair_info* info) {                           Transcode_pair_info* info) {
         avalue=Charset::transcode(avalue,          avalue=Charset::transcode(avalue,
                 *info->source_transcoder,                   *info->source_transcoder, 
Line 694  void Charset::transcode(HashStringString Line 1110  void Charset::transcode(HashStringString
         const Charset& source_transcoder,           const Charset& source_transcoder, 
         const Charset& dest_transcoder) {          const Charset& dest_transcoder) {
         Transcode_pair_info info={&source_transcoder, &dest_transcoder};          Transcode_pair_info info={&source_transcoder, &dest_transcoder};
         src.for_each_ref(transcode_pair, &info);          src.for_each_ref<Transcode_pair_info*>(transcode_pair, &info);
 }  }
 #endif  

Removed from v.1.35  
changed lines
  Added in v.1.60


E-mail: