Diff for /parser3/src/main/pa_charset.C between versions 1.73 and 1.96

version 1.73, 2009/05/13 07:35:41 version 1.96, 2014/08/28 17:09:36
Line 1 Line 1
 /** @file  /** @file
         Parser: Charset connection implementation.          Parser: Charset connection implementation.
   
         Copyright(c) 2001-2009 ArtLebedev Group (http://www.artlebedev.com)          Copyright (c) 2001-2012 Art. Lebedev Studio (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 * const IDENT_CHARSET_C="$Date$";  
   
 #include "pa_charset.h"  #include "pa_charset.h"
 #include "pa_charsets.h"  #include "pa_charsets.h"
   
   // we are using some pcre_internal.h stuff as well
   #include "../lib/pcre/pa_pcre_internal.h"
   
   volatile const char * IDENT_PA_CHARSET_C="$Id$" IDENT_PA_CHARSET_H;
   
 #ifdef XML  #ifdef XML
 #include "libxml/encoding.h"  #include "libxml/encoding.h"
 #endif  #endif
Line 58  inline unsigned int to_wchar_code(const Line 61  inline unsigned int to_wchar_code(const
         if(cstr[1]==0)          if(cstr[1]==0)
                 return(unsigned int)(unsigned char)cstr[0];                  return(unsigned int)(unsigned char)cstr[0];
   
         char *error_pos;          return pa_atoui(cstr,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;
Line 86  static void element2case(unsigned char f Line 88  static void element2case(unsigned char f
         fcc_table[from]=to; fcc_table[to]=from;          fcc_table[from]=to; fcc_table[to]=from;
 }  }
   
   inline XMLByte *append_hex_8(XMLByte *dest, unsigned char c, const char* prefix=0) {
       if(prefix) {
           strcpy((char *)dest, prefix);
           dest+=strlen(prefix);
       }
       *dest++=hex_digits[c >> 4];
       *dest++=hex_digits[c & 0x0F];
       return dest;
   }
   
   inline XMLByte *append_hex_16(XMLByte *dest, unsigned int c, const char* prefix=0) {
       if(prefix) {
           strcpy((char *)dest, prefix);
           dest+=strlen(prefix);
       }
       *dest++=hex_digits[(c >> 12) & 0x0F];
       *dest++=hex_digits[(c >> 8) & 0x0F];
       *dest++=hex_digits[(c >> 4) & 0x0F];
       *dest++=hex_digits[(c) & 0x0F];
       return dest;
   }
   
 // methods  // methods
   
 Charset::Charset(Request_charsets* charsets, const String::Body ANAME, const String* afile_spec):   Charset::Charset(Request_charsets* charsets, const String::Body ANAME, const String* afile_spec): 
Line 101  Charset::Charset(Request_charsets* chars Line 125  Charset::Charset(Request_charsets* chars
         } 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, pa_pcre_default_tables, sizeof(pcre_tables));
         }          }
   
 #ifdef XML  #ifdef XML
Line 171  void Charset::load_definition(Request_ch Line 195  void Charset::load_definition(Request_ch
                 }                  }
         };          };
   
           // parser charset tables declare only white-space before 0x20, thus adding the missing chars
           for(uint i=0; i<0x20; i++)
                   if(!tables.fromTable[i]){
                           tables.fromTable[i]=i;
                           tables.toTable[tables.toTableSize].intCh=i;
                           tables.toTable[tables.toTableSize].extCh=(XMLByte)i;
                           tables.toTableSize++;
                   }
   
         // sort by the Unicode code point          // sort by the Unicode code point
         sort_ToTable();          sort_ToTable();
 }  }
Line 182  static int sort_cmp_Trans_rec_intCh(cons Line 215  static int sort_cmp_Trans_rec_intCh(cons
 }  }
   
 void Charset::sort_ToTable() {  void Charset::sort_ToTable() {
         _qsort(tables.toTable, tables.toTableSize, sizeof(*tables.toTable),           qsort(tables.toTable, tables.toTableSize, sizeof(*tables.toTable), sort_cmp_Trans_rec_intCh);
                 sort_cmp_Trans_rec_intCh);  
         //FILE *f=fopen("c:\\temp\\a", "wb");          //FILE *f=fopen("c:\\temp\\a", "wb");
         //fwrite(tables.toTable, tables.toTableSize, sizeof(*tables.toTable), f);          //fwrite(tables.toTable, tables.toTableSize, sizeof(*tables.toTable), f);
         //fclose(f);          //fclose(f);
Line 193  void Charset::sort_ToTable() { Line 225  void Charset::sort_ToTable() {
 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) {
         int    lo = 0;          int lo = 0;
         int    hi = tables.toTableSize - 1;          int hi = tables.toTableSize - 1;
         while(lo<=hi) {          while(lo<=hi) {
                 // 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 i = (lo + hi) / 2;
Line 263  static const XMLByte gUTFBytes[0x100] = Line 295  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(const XMLByte* srcData, int& srcLen,  static int transcodeToUTF8(const XMLByte* srcData, int& srcLen,
Line 433  of ocetes consumed. Line 465  of ocetes consumed.
         return 0;          return 0;
 }  }
   
 static bool isEscaped(XMLByte c){  static bool need_escape(XMLByte c){
         return          return
                 !(                  !(
                         (c<=127)                          (c<=127)
                         && (                          && (
                                 ((c>='0') && (c<='9'))                                  pa_isalnum((unsigned char)c)
                                 || ((c>='A') && (c<='Z'))  
                                 || ((c>='a') && (c<='z'))  
                                 || strchr("*@-_+./", c)!=0                                  || strchr("*@-_+./", c)!=0
                         )                          )
                 );                  );
Line 492  static unsigned int skipUTF8Char(const X Line 522  static unsigned int skipUTF8Char(const X
         return trailingBytes;          return trailingBytes;
 }  }
   
 // read non-UTF8 char, and return number of bytes needed for store this char in UTF8  // 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){  static unsigned int readChar(const XMLByte*& srcPtr, const XMLByte* srcEnd, XMLByte& firstByte, XMLCh& UTF8Char, const Charset::Tables& tables){
         if(!srcPtr || !*srcPtr || srcPtr>=srcEnd)          if(!srcPtr || !*srcPtr || srcPtr>=srcEnd)
                 return 0;                  return 0;
Line 518  static unsigned int readChar(const XMLBy Line 548  static unsigned int readChar(const XMLBy
         return 1;          return 1;
 }  }
   
 static int escapeUTF8(const XMLByte* srcData, size_t& srcLen,  size_t Charset::calc_escaped_length_UTF8(XMLByte* src, size_t src_length){
                              XMLByte* toFill, size_t& toFillLen) {          size_t dest_length=0;
         const XMLByte* srcPtr=srcData;  
         const XMLByte* srcEnd=srcData+srcLen;          for(UTF8_string_iterator i(src, src_length); i.has_next(); ){
         XMLByte* outPtr=toFill;                  if(i.getCharSize()==1)
         XMLByte* outEnd=toFill+toFillLen;                          dest_length+=!need_escape(i.getFirstByte())?1/*as-is*/:3/*%XX*/;
         XMLByte firstByte;                  else
         XMLCh UTF8Char;                          dest_length+=6; // %uXXXX
         uint charSize;  
   
         // loop until we either run out of input data, or room to store  
         while((outPtr < outEnd) && (charSize=readUTF8Char(srcPtr, srcEnd, firstByte, UTF8Char))){  
                 if(charSize==1){  
                         if(isEscaped(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;          return dest_length;
 }  }
   
 static int escape(const XMLByte* srcData, size_t& srcLen,  size_t Charset::calc_escaped_length(const XMLByte* src, size_t src_length, const Charset::Tables& tables){
                            XMLByte *toFill, size_t& toFillLen,          const XMLByte* src_end=src+src_length;
                            const Charset::Tables& tables) {          XMLByte first_byte;
         const XMLByte* srcPtr=srcData;          XMLCh UTF8_char;
         const XMLByte* srcEnd=srcData+srcLen;          size_t dest_length=0;
         XMLByte* outPtr=toFill;  
         XMLByte firstByte;          while(uint char_size=readChar(src, src_end, first_byte, UTF8_char, tables)){
         XMLCh UTF8Char;                  if(char_size==1)
         uint charSize;                          dest_length+=(!first_byte/*replacement char '?'*/ || !need_escape(first_byte))?1:3/*'%XX'*/;
                   else
         while(charSize=readChar(srcPtr, srcEnd, firstByte, UTF8Char, tables)){                          dest_length+=6; // %uXXXX
                 if(charSize==1){  
                         if(firstByte){  
                                 if(isEscaped(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          return dest_length;
         srcLen = srcPtr - srcData;  }
           
         // Return the characters read  size_t Charset::calc_escaped_length(const String::C src, const Charset& source_charset){
         toFillLen = outPtr - toFill;          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=append_hex_8(dest_ptr, first_byte, "%");  /* %XX */ \
                           else \
                                   *dest_ptr++=first_byte; /*as is*/ \
                   } else \
                           *dest_ptr++='?'; /* replacement char '?' */ \
           else \
                   dest_ptr=append_hex_16(dest_ptr, UTF8_char, "%u"); /* %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 0;          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){  String::C Charset::escape(const String::C src, const Charset& source_charset){
         size_t src_length=src.length;          if(!src.length)
         if(!src_length)  
                 return String::C("", 0);                  return String::C("", 0);
   
 #ifdef PRECALCULATE_DEST_LENGTH          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;          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()){          for(UTF8_string_iterator i(src, src_length); i.has_next(); ){
                 while(uint charSize=readUTF8Char(srcPtr, srcEnd, firstByte, UTF8Char)){                  if(i.getCharSize()==1){
                         if(charSize==1)                          XMLByte first_byte=i.getFirstByte();
                                 dest_length+=!isEscaped(firstByte)?1:3/*%XX*/;                          dest_length+=need_json_escape(first_byte) ? 2 : (first_byte < 0x20 && first_byte /* 0 replacement char is '?' */) ? 6 : 1;
                         else                  } else
                                 dest_length+=6; // '%uXXXX'                          dest_length+=6; // \uXXXX
                 }  
         } else {  
                 while(uint charSize=readChar(srcPtr, srcEnd, firstByte, UTF8Char, source_charset.tables)){  
                         if(charSize==1)  
                                 dest_length+=(!firstByte/*replacement char '?'*/ || !isEscaped(firstByte))?1:3/*'%XX'*/;  
                         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+=need_json_escape(first_byte) ? 2 : (first_byte < 0x20 && first_byte /* 0 replacement char is '?' */) ? 6 : 1;
                   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  #else
         size_t dest_length=src_length*6; // enough for %uXXXX but too memory-hungry          return src_length*6; // enough for \uXXXX but too memory-hungry
 #endif  #endif
   }
   
         //throw Exception(0,0,"%u",dest_length);  #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  : if(first_byte < 0x20) dest_ptr=append_hex_16(dest_ptr, UTF8_char, "\\u"); \
                                                   else *dest_ptr++=first_byte; \
                   } \
           else \
                   dest_ptr=append_hex_16(dest_ptr, UTF8_char, "\\u"); // \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;
   
 #ifndef NDEBUG          while(char_size=readChar(src, src_end, first_byte, UTF8_char, tables))
         size_t saved_dest_length=dest_length;                  escape_char_JSON(dest_ptr, char_size, first_byte, UTF8_char)
 #endif  
         XMLByte *dest_body=new(PointerFreeGC) XMLByte[dest_length+1/*for terminator*/];  
   
         int status;          return dest_ptr - dest;
         if(source_charset.isUTF8()){  }
                 status=::escapeUTF8((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)  String::C Charset::escape_JSON(const String::C src, const Charset& source_charset){
                 throw Exception(0,          if(!src.length)
                         0,                  return String::C("", 0);
                         "Charset::escape buffer overflow");  
           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");
   
         assert(dest_length<=saved_dest_length);  
         dest_body[dest_length]=0; // terminator          dest_body[dest_length]=0; // terminator
         return String::C((char*)dest_body, dest_length);          return String::C((char*)dest_body, dest_length);
 }  }
           
 String::Body Charset::escape(const String::Body src, const Charset& source_charset) {  
         const char *src_ptr=src.cstr();  
         size_t src_size=strlen(src_ptr);  
   
         String::C dest=Charset::escape(String::C(src_ptr, src_size), source_charset);  
   
         return String::Body(dest.str);  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(const String& src, const Charset& source_charset) {  String& Charset::escape_JSON(const String& src, const Charset& source_charset) {
         if(src.is_empty())          if(src.is_empty())
                 return *new String();                  return *new String();
   
         return *new String(escape((String::Body)src, source_charset), String::L_CLEAN);          return *new String(escape_JSON((String::Body)src, source_charset), String::L_CLEAN);
 }  }
   
 const String::C Charset::transcodeToUTF8(const String::C src) const {  const String::C Charset::transcodeToUTF8(const String::C src) const {
Line 664  const String::C Charset::transcodeToUTF8 Line 795  const String::C Charset::transcodeToUTF8
         while(uint charSize=readChar(srcPtr, srcEnd, firstByte, UTF8Char, tables))          while(uint charSize=readChar(srcPtr, srcEnd, firstByte, UTF8Char, tables))
                 dest_length+=charSize;                  dest_length+=charSize;
 #else  #else
         int dest_length=src_length*6; // so that surly enough (max utf8 seq len=6) but too memory-hyngry          int dest_length=src_length*6; // so that surly enough (max utf8 seq len=6) but too memory-hungry
 #endif  #endif
   
         //throw Exception(0,0,"%u",dest_length);  
   
 #ifndef NDEBUG  #ifndef NDEBUG
         int saved_dest_length=dest_length;          int saved_dest_length=dest_length;
 #endif  #endif
Line 688  const String::C Charset::transcodeToUTF8 Line 817  const String::C Charset::transcodeToUTF8
 }  }
   
 static XMLCh change_case_UTF8(const XMLCh src, const Charset::UTF8CaseTable& table) {  static XMLCh change_case_UTF8(const XMLCh src, const Charset::UTF8CaseTable& table) {
         int    lo = 0;          int lo = 0;
         int    hi = table.size - 1;          int hi = table.size - 1;
         while(lo<=hi) {          while(lo<=hi) {
                 // 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 i = (lo + hi) / 2;
Line 829  static size_t getDecNumLength(XMLCh UTF8 Line 958  static size_t getDecNumLength(XMLCh UTF8
   
 const String::C Charset::transcodeFromUTF8(const String::C src) const {  const String::C Charset::transcodeFromUTF8(const String::C src) const {
         int src_length=src.length;          int src_length=src.length;
   
 #ifdef PRECALCULATE_DEST_LENGTH  #ifdef PRECALCULATE_DEST_LENGTH
         int dest_length=0;          int dest_length=0;
         const XMLByte* srcPtr=(XMLByte*)src.str;          for(UTF8_string_iterator i((XMLByte *)src.str, src_length); i.has_next(); ){
         const XMLByte* srcEnd=srcPtr+src_length;                  dest_length += ( i.next() & 0xFFFF0000 )
         XMLByte firstByte;                                                  ? 3*i.getCharSize()                                             // %XX for each byte
         XMLCh UTF8Char;                                                  : ( xlatOneTo(i.next(), tables, 0) != 0 )
         while(uint charSize=readUTF8Char(srcPtr, srcEnd, firstByte, UTF8Char)){                                                          ? 1                                                                     // can convert it to a single char
                 if(charSize==1)                                                          : 3+getDecNumLength( i.next() );        // print char as &#XX;, &#XXX;, &#XXXX; or &#XXXXX;
                         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  #else
         // so that surly enough, "&#XXX;" has max ratio (huh? 8 bytes needed for '&#XXXXX;')          // so that surly enough, "&#XXX;" has max ratio (huh? 8 bytes needed for '&#XXXXX;')
Line 871  const String::C Charset::transcodeFromUT Line 992  const String::C Charset::transcodeFromUT
   
 /// transcode using both charsets  /// transcode using both charsets
 const String::C Charset::transcodeToCharset(const String::C src,   const String::C Charset::transcodeToCharset(const String::C src, 
                                             const Charset& dest_charset) const {                                                  const Charset& dest_charset) const {
         if(&dest_charset==this)           if(&dest_charset==this) 
                 return src;                  return src;
         else {          else {
Line 1035  String::C Charset::transcode_cstr(const Line 1156  String::C Charset::transcode_cstr(const
 }  }
 const String& Charset::transcode(const xmlChar* s) {   const String& Charset::transcode(const xmlChar* s) { 
         String::C cstr=transcode_cstr(s);          String::C cstr=transcode_cstr(s);
         return *new String(cstr.str, true);          return *new String(cstr.str, String::L_TAINTED);
 }  }
   
 /// @test less memory using -maybe- xmlParserInputBufferCreateMem  /// @test less memory using -maybe- xmlParserInputBufferCreateMem
Line 1077  xmlChar* Charset::transcode_buf2xchar(co Line 1198  xmlChar* Charset::transcode_buf2xchar(co
         assert(outlen<=saved_outlen); out[outlen]=0;          assert(outlen<=saved_outlen); out[outlen]=0;
         return out;          return out;
 }  }
 xmlChar* Charset::transcode(const String& s) {   
         const char* cstr=s.cstr(String::L_UNSPECIFIED);  
   
         return transcode_buf2xchar(cstr, strlen(cstr));   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) {   
         const char* cstr=s.cstr();  
   
         return transcode_buf2xchar(cstr, s.length());   xmlChar* Charset::transcode(const String::Body s) {
           return transcode_buf2xchar(s.cstr(), s.length()); 
 }  }
 #endif  #endif
   
Line 1094  String::Body Charset::transcode(const St Line 1214  String::Body Charset::transcode(const St
         const Charset& dest_transcoder) {          const Charset& dest_transcoder) {
   
         const char *src_ptr=src.cstr();          const char *src_ptr=src.cstr();
         size_t src_size=strlen(src_ptr);          size_t src_size=src.length();
   
         String::C dest=Charset::transcode(String::C(src_ptr, src_size),          String::C dest=Charset::transcode(String::C(src_ptr, src_size), source_transcoder, dest_transcoder);
                 source_transcoder,  
                 dest_transcoder);  
   
         return String::Body(dest.str);          return String::Body(dest.length ? dest.str:0);
 }  }
   
 String& Charset::transcode(const String& src,   String& Charset::transcode(const String& src, 
Line 1125  struct Transcode_pair_info { Line 1243  struct Transcode_pair_info {
         const Charset* dest_transcoder;          const Charset* dest_transcoder;
 };  };
 #endif  #endif
 static void transcode_pair(const String::Body /*akey*/,   static void transcode_pair(HashStringValue::key_type /*akey*/, 
                          String::Body& avalue,                            String::Body& avalue, 
                          Transcode_pair_info* info) {                           Transcode_pair_info* info) {
         avalue=Charset::transcode(avalue,          avalue=Charset::transcode(avalue,
Line 1170  size_t lengthUTF8(const XMLByte* srcBegi Line 1288  size_t lengthUTF8(const XMLByte* srcBegi
   
         return size;          return size;
 }  }
   
   unsigned int lengthUTF8Char(const XMLByte c){
           return gUTFBytes[c]+1;
   }
   
   const char *fixUTF8(const char *src){
           if(src && *src){
                   size_t length=strlen(src);
   
                   int error_offset;
                   if(pa_pcre_valid_utf((unsigned char *)src, length, &error_offset)){
   
                           char *result=(char *)pa_malloc_atomic(length+1);
                           char *dst=result;
   
                           do {
   
                                   if(error_offset){
                                           strncpy(dst, src, error_offset);
                                           dst+=error_offset;
   
                                           src+=error_offset;
                                           length-=error_offset;
   
                                   }
   
                                   *dst++='?';
                                   src++;
                                   length--;
   
                           } while (length && pa_pcre_valid_utf((unsigned char *)src, length, &error_offset));
   
                           if(length){
                                   strcpy(dst, src);
                           } else {
                                   *dst='\0';
                           }
   
                           return result;
                   }
           }
           return src;
   }
   
   bool UTF8_string_iterator::has_next(){
           fcharSize=readUTF8Char(fsrcPtr, fsrcEnd, ffirstByte, fUTF8Char);
           return fcharSize!=0;
   }

Removed from v.1.73  
changed lines
  Added in v.1.96


E-mail: