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

version 1.60, 2008/07/15 12:53:10 version 1.87, 2010/09/21 21:45:20
Line 1 Line 1
 /** @file  /** @file
         Parser: Charset connection implementation.          Parser: Charset connection implementation.
   
         Copyright(c) 2001-2005 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)
 */  */
   
Line 15  static const char * const IDENT_CHARSET_ Line 15  static const char * const IDENT_CHARSET_
 #endif  #endif
   
 //#define PA_PATCHED_LIBXML_BACKWARD  //#define PA_PATCHED_LIBXML_BACKWARD
   
   // reduce memory usage by pre-calculation utf-8 string length
 #define PRECALCULATE_DEST_LENGTH  #define PRECALCULATE_DEST_LENGTH
   
 // globals  // globals
Line 86  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(Request_charsets* charsets, const String::Body ANAME, const String* afile_spec): 
         FNAME(ANAME),          FNAME(ANAME),
         FNAME_CSTR(ANAME.cstrm()) {          FNAME_CSTR(ANAME.cstrm()) {
Line 100  Charset::Charset(Request_charsets* chars Line 101  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, _pcre_default_tables, sizeof(pcre_tables));
         }          }
   
 #ifdef XML  #ifdef XML
Line 170  void Charset::load_definition(Request_ch Line 171  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 192  void Charset::sort_ToTable() { Line 202  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 262  static const XMLByte gUTFBytes[0x100] = Line 272  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, size_t& srcLen,  static int transcodeToUTF8(const XMLByte* srcData, int& srcLen,
                            XMLByte *toFill, size_t& toFillLen,                                  XMLByte *toFill, int& 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;
Line 352  of ocetes consumed. Line 362  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(const XMLByte* srcData, size_t& srcLen,  static int transcodeFromUTF8(const XMLByte* srcData, int& srcLen,
                              XMLByte* toFill, size_t& toFillLen,                                  XMLByte* toFill, int& 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;
Line 432  of ocetes consumed. Line 442  of ocetes consumed.
         return 0;          return 0;
 }  }
   
 static bool is_escaped(char c){  static bool need_escape(XMLByte c){
         return          return
                 !(c<=127                  !(
                 && (                          (c<=127)
                         ((c>='0') && (c<='9'))                          && (
                         || ((c>='A') && (c<='Z'))                                  ((c>='0') && (c<='9'))
                         || ((c>='a') && (c<='z'))                                  || ((c>='A') && (c<='Z'))
                         || strchr("*@-_+./", c)!=0                                  || ((c>='a') && (c<='z'))
                 ));                                  || strchr("*@-_+./", c)!=0
                           )
                   );
 }  }
   
 // read one utf8 character, return number of bytes needed for store it  // read one UTF8 char and return length of this char (in bytes)
 static unsigned int readChar(const XMLByte*& srcPtr, const XMLByte*& srcEnd, XMLByte& firstByte, XMLCh& UTF8Char){  static unsigned int readUTF8Char(const XMLByte*& srcPtr, const XMLByte* srcEnd, XMLByte& firstByte, XMLCh& UTF8Char){
         if(!srcPtr || !*srcPtr || srcPtr>=srcEnd)          if(!srcPtr || !*srcPtr || srcPtr>=srcEnd)
                 return 0;                  return 0;
   
Line 478  static unsigned int readChar(const XMLBy Line 490  static unsigned int readChar(const XMLBy
         return trailingBytes+1;          return trailingBytes+1;
 }  }
   
 // read char, return number of bytes needed for store it as UTF8  // skip UTF8 char and return length of this char (in bytes)
 static unsigned int readChar(const XMLByte*& srcPtr, const XMLByte*& srcEnd, XMLByte& firstByte, XMLCh& UTF8Char, const Charset::Tables& tables){  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)          if(!srcPtr || !*srcPtr || srcPtr>=srcEnd)
                 return 0;                  return 0;
   
Line 504  static unsigned int readChar(const XMLBy Line 527  static unsigned int readChar(const XMLBy
         return 1;          return 1;
 }  }
   
 static int escape(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=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;          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* outEnd=toFill+toFillLen;          while(uint char_size=readChar(src, src_end, first_byte, UTF8_char, tables)){
         XMLByte firstByte;                  if(char_size==1)
         XMLCh UTF8Char;                          dest_length+=(!first_byte/*replacement char '?'*/ || !need_escape(first_byte))?1:3/*'%XX'*/;
         uint charSize;                  else
                           dest_length+=6; // %uXXXX
         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          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+=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 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=readChar(srcPtr, srcEnd, firstByte, UTF8Char)){                  if(i.getCharSize()==1)
                         if(charSize==1)                          dest_length+=need_json_escape(i.getFirstByte()) ? 2 : 1;
                                 dest_length+=!is_escaped(firstByte)?1:3/*%XX*/;                  else
                         else                          dest_length+=6; // \uXXXX
                                 dest_length+=6; // '%uXXXX'          }
                 }  
         } else {          return dest_length;
                 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'*/;  size_t Charset::calc_JSON_escaped_length(const XMLByte* src, size_t src_length, const Charset::Tables& tables){
                         else          const XMLByte* src_end=src+src_length;
                                 dest_length+=6; // '%uXXXX'          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  #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  : *dest_ptr++=first_byte; \
                   } \
           else \
                   dest_ptr+=sprintf((char*)dest_ptr, "\\u%04X", UTF8_char); // \uXXXX
   
 #ifndef NDEBUG  
         size_t saved_dest_length=dest_length;  
 #endif  
         XMLByte *dest_body=new(PointerFreeGC) XMLByte[dest_length+1/*for terminator*/];  
   
         int status;  size_t Charset::escape_JSON_UTF8(const XMLByte* src, size_t src_length, XMLByte* dest) {
         if(source_charset.isUTF8()){          XMLByte* dest_ptr=dest;
                 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)          // loop until we either run out of input data
                 throw Exception(0,          for(UTF8_string_iterator i((XMLByte *)src, src_length); i.has_next(); )
                         0,                  escape_char_JSON(dest_ptr, i.getCharSize(), i.getFirstByte(), i.next())
                         "Charset::escapeString buffer overflow");  
           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");
   
         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_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 {  const String::C Charset::transcodeToUTF8(const String::C src) const {
         size_t src_length=src.length;          int src_length=src.length;
   
 #ifdef PRECALCULATE_DEST_LENGTH  #ifdef PRECALCULATE_DEST_LENGTH
         size_t dest_length=0;          int dest_length=0;
         const XMLByte* srcPtr=(XMLByte*)src.str;          const XMLByte* srcPtr=(XMLByte*)src.str;
         const XMLByte* srcEnd=srcPtr+src_length;          const XMLByte* srcEnd=srcPtr+src_length;
         XMLByte firstByte;          XMLByte firstByte;
         XMLCh UTF8Char;          XMLCh UTF8Char;
         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
         size_t 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
         size_t saved_dest_length=dest_length;          int saved_dest_length=dest_length;
 #endif  #endif
         XMLByte *dest_body=new(PointerFreeGC) XMLByte[dest_length+1/*for terminator*/];          XMLByte *dest_body=new(PointerFreeGC) XMLByte[dest_length+1/*for terminator*/];
   
Line 660  const String::C Charset::transcodeToUTF8 Line 794  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 800  static size_t getDecNumLength(XMLCh UTF8 Line 934  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 {
         size_t src_length=src.length;          int src_length=src.length;
   
 #ifdef PRECALCULATE_DEST_LENGTH  #ifdef PRECALCULATE_DEST_LENGTH
         size_t 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;                  if(i.getCharSize()==1)
         XMLByte firstByte;  
         XMLCh UTF8Char;  
         while(uint charSize=readChar(srcPtr, srcEnd, firstByte, UTF8Char)){  
                 if(charSize==1)  
                         dest_length++;                          dest_length++;
                 else                  else
                         dest_length+=(UTF8Char & 0xFFFF0000)                          dest_length+=(i.next() & 0xFFFF0000)
                                                         ?charSize*3     // '%XX' for each byte                                                          ?i.getCharSize()*3      // '%XX' for each byte
                                                         :(xlatOneTo(UTF8Char, tables, 0)!=0)                                                          :(xlatOneTo(i.next(), tables, 0)!=0)
                                                                 ?1              // can convert it to single char                                                                  ?1              // can convert it to single char
                                                                 :getDecNumLength(UTF8Char)+3;           // &#XX; - &#XXXXX;                                                                  :getDecNumLength(i.next())+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;')
         size_t dest_length=src_length*6;          int dest_length=src_length*6;
 #endif  #endif
   
         //throw Exception(0,0,"%u",dest_length);  
   
 #ifndef NDEBUG  #ifndef NDEBUG
         size_t saved_dest_length=dest_length;          int saved_dest_length=dest_length;
 #endif  #endif
         XMLByte *dest_body=new(PointerFreeGC) XMLByte[dest_length+1/*for terminator*/];          XMLByte *dest_body=new(PointerFreeGC) XMLByte[dest_length+1/*for terminator*/];
   
Line 845  const String::C Charset::transcodeFromUT Line 972  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 884  static const Charset::Tables* tables[MAX Line 1011  static const Charset::Tables* tables[MAX
                 unsigned char *out, int *outlen, \                  unsigned char *out, int *outlen, \
                 const unsigned char *in, int *inlen, void*) { \                  const unsigned char *in, int *inlen, void*) { \
                 return transcodeToUTF8( \                  return transcodeToUTF8( \
                         in, *(size_t*)inlen, \                          in, *inlen, \
                         out, *(size_t*)outlen, \                          out, *outlen, \
                         *tables[i]); \                          *tables[i]); \
         } \          } \
         static int xml256CharEncodingOutputFunc##i( \          static int xml256CharEncodingOutputFunc##i( \
                 unsigned char *out, int *outlen, \                  unsigned char *out, int *outlen, \
                 const unsigned char *in, int *inlen, void*) { \                  const unsigned char *in, int *inlen, void*) { \
                 return transcodeFromUTF8( \                  return transcodeFromUTF8( \
                         in, *(size_t*)inlen, \                          in, *inlen, \
                         out, *(size_t*)outlen, \                          out, *outlen, \
                         *tables[i]); \                          *tables[i]); \
         }          }
   
Line 904  static const Charset::Tables* tables[MAX Line 1031  static const Charset::Tables* tables[MAX
                 unsigned char *out, int *outlen, \                  unsigned char *out, int *outlen, \
                 const unsigned char *in, int *inlen) { \                  const unsigned char *in, int *inlen) { \
                 return transcodeToUTF8( \                  return transcodeToUTF8( \
                         in, *(size_t*)inlen, \                          in, *inlen, \
                         out, *(size_t*)outlen, \                          out, *outlen, \
                         *tables[i]); \                          *tables[i]); \
         } \          } \
         static int xml256CharEncodingOutputFunc##i( \          static int xml256CharEncodingOutputFunc##i( \
                 unsigned char *out, int *outlen, \                  unsigned char *out, int *outlen, \
                 const unsigned char *in, int *inlen) { \                  const unsigned char *in, int *inlen) { \
                 return transcodeFromUTF8( \                  return transcodeFromUTF8( \
                         in, *(size_t*)inlen, \                          in, *inlen, \
                         out, *(size_t*)outlen, \                          out, *outlen, \
                         *tables[i]); \                          *tables[i]); \
         }          }
   
Line 1009  String::C Charset::transcode_cstr(const Line 1136  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, cstr.length, true);          return *new String(cstr.str, String::L_TAINTED);
 }  }
   
 /// @test less memory using -maybe- xmlParserInputBufferCreateMem  /// @test less memory using -maybe- xmlParserInputBufferCreateMem
Line 1051  xmlChar* Charset::transcode_buf2xchar(co Line 1178  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 1068  String::Body Charset::transcode(const St Line 1194  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, dest.length);          return String::Body(dest.length ? dest.str:0);
 }  }
   
 String& Charset::transcode(const String& src,   String& Charset::transcode(const String& src, 
         const Charset& source_transcoder,           const Charset& source_transcoder, 
         const Charset& dest_transcoder) {          const Charset& dest_transcoder) {
         if(!src.length())          if(src.is_empty())
                 return *new String("", 0, false);                  return *new String();
   
         return *new String(transcode((String::Body)src, source_transcoder, dest_transcoder), String::L_CLEAN);          return *new String(transcode((String::Body)src, source_transcoder, dest_transcoder), String::L_CLEAN);
 }  }
Line 1099  struct Transcode_pair_info { Line 1223  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,
                 *info->source_transcoder,                   *info->source_transcoder, 
                 *info->dest_transcoder);                  *info->dest_transcoder);
 }  }
   
 void Charset::transcode(HashStringString& src,  void Charset::transcode(HashStringString& src,
         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*>(transcode_pair, &info);          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.60  
changed lines
  Added in v.1.87


E-mail: