Diff for /parser3/src/main/pa_charset.C between versions 1.14 and 1.38

version 1.14, 2002/01/14 17:48:57 version 1.38, 2003/09/29 09:42:12
Line 1 Line 1
 /** @file  /** @file
         Parser: Charset connection implementation.          Parser: Charset connection implementation.
   
         Copyright(c) 2001 ArtLebedev Group(http://www.artlebedev.com)          Copyright(c) 2001-2003 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)
   
         $Id$  
 */  */
   
   static const char* IDENT_CHARSET_C="$Date$";
   
 #include "pa_charset.h"  #include "pa_charset.h"
   #include "pa_charsets.h"
   
 #ifdef XML  #ifdef XML
 #include "libxml/encoding.h"  #include "libxml/encoding.h"
Line 15 Line 16
   
 // globals  // globals
   
   Charset::UTF8CaseTable::Rec UTF8CaseToUpperRecords[]={
   #include "utf8-to-upper.inc"
   };
   Charset::UTF8CaseTable UTF8CaseToUpper={
           sizeof(UTF8CaseToUpperRecords)/sizeof(Charset::UTF8CaseTable::Rec),
           UTF8CaseToUpperRecords};
   
 // consts  Charset::UTF8CaseTable::Rec UTF8CaseToLowerRecords[]={
   #include "utf8-to-lower.inc"
 #define MAX_CHARSET_UNI_CODES 500  };
   Charset::UTF8CaseTable UTF8CaseToLower={
           sizeof(UTF8CaseToLowerRecords)/sizeof(Charset::UTF8CaseTable::Rec),
           UTF8CaseToLowerRecords};
   
 // helpers  // helpers
   
Line 37  inline void cstr2ctypes(unsigned char *t Line 47  inline void cstr2ctypes(unsigned char *t
                 ctypes_table[c]|=bit;                  ctypes_table[c]|=bit;
         }          }
 }  }
 inline unsigned int to_wchar_code(const char *cstr) {  inline unsigned int to_wchar_code(const char* cstr) {
         if(!cstr || !*cstr)          if(!cstr || !*cstr)
                 return 0;                  return 0;
         if(cstr[1]==0)          if(cstr[1]==0)
Line 46  inline unsigned int to_wchar_code(const Line 56  inline unsigned int to_wchar_code(const
         char *error_pos;          char *error_pos;
         return(unsigned int)strtol(cstr, &error_pos, 0);          return(unsigned int)strtol(cstr, &error_pos, 0);
 }  }
 inline bool to_bool(const char *cstr) {  inline bool to_bool(const char* cstr) {
         return cstr && *cstr!=0;          return cstr && *cstr!=0;
 }  }
 static void element2ctypes(unsigned char c, bool belongs,  static void element2ctypes(unsigned char c, bool belongs,
Line 74  static void element2case(unsigned char f Line 84  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(Pool& apool, const String& aname, const String *request_file_spec): Pooled(apool),  Charset::Charset(Request_charsets* charsets, const String::Body ANAME, const String* afile_spec): 
         fname(aname) {          FNAME(ANAME),
           FNAME_CSTR(ANAME.cstrm()) {
         char *name_cstr=fname.cstr();  
     for(char *c=name_cstr; *c; c++)  
         *c = toupper(*c);  
   
         if(request_file_spec) {          if(afile_spec) {
                 fisUTF8=false;                  fisUTF8=false;
                 loadDefinition(*request_file_spec);                  load_definition(*charsets, *afile_spec);
 #ifdef XML  #ifdef XML
                 addEncoding(name_cstr);                  addEncoding(FNAME_CSTR);
 #endif  #endif
         } else {          } else {
                 fisUTF8=true;                  fisUTF8=true;
Line 94  Charset::Charset(Pool& apool, const Stri Line 101  Charset::Charset(Pool& apool, const Stri
         }          }
   
 #ifdef XML  #ifdef XML
         initTranscoder(&aname, name_cstr);          initTranscoder(FNAME, FNAME_CSTR);
 #endif  
 }  
   
 Charset::~Charset() {  
 #ifdef XML  
         // not deleting transcoder, that's not our business  
 #endif  #endif
 }  }
   
 void Charset::loadDefinition(const String& request_file_spec) {  void Charset::load_definition(Request_charsets& charsets, const String& afile_spec) {
         // pcre_tables          // pcre_tables
         // lowcase, flipcase, bits digit+word+whitespace, masks          // lowcase, flipcase, bits digit+word+whitespace, masks
   
Line 115  void Charset::loadDefinition(const Strin Line 116  void Charset::loadDefinition(const Strin
         cstr2ctypes(pcre_tables,(const unsigned char *)"*+?{^.$|()[", ctype_meta);          cstr2ctypes(pcre_tables,(const unsigned char *)"*+?{^.$|()[", ctype_meta);
   
         // charset          // charset
         memset(tables.fromTable, 0, sizeof(tables.fromTable));          memset(&tables, 0, sizeof(tables));
         tables.toTable=(Charset_TransRec *)calloc(sizeof(Charset_TransRec)*MAX_CHARSET_UNI_CODES);  
         tables.toTableSize=0;  
         // strangly vital          // strangly vital
         tables.toTable[tables.toTableSize].intCh=0;          tables.toTable[tables.toTableSize].intCh=0;
         tables.toTable[tables.toTableSize].extCh=(XMLByte)0;          tables.toTable[tables.toTableSize].extCh=(XMLByte)0;
         tables.toTableSize++;          tables.toTableSize++;
   
         // loading text          // loading text
         char *data=file_read_text(pool(), request_file_spec);          char *data=file_read_text(charsets, afile_spec);
   
         // ignore header          // ignore header
         getrow(&data);          getrow(&data);
Line 153  void Charset::loadDefinition(const Strin Line 152  void Charset::loadDefinition(const Strin
                         case 8:                          case 8:
                                 // charset                                  // charset
                                 if(tables.toTableSize>MAX_CHARSET_UNI_CODES)                                  if(tables.toTableSize>MAX_CHARSET_UNI_CODES)
                                         throw Exception(0, 0,                                          throw Exception("parser.runtime",
                                                 &request_file_spec,                                                  &afile_spec,
                                                 "charset must contain not more then %d unicode values", MAX_CHARSET_UNI_CODES);                                                  "charset must contain not more then %d unicode values", MAX_CHARSET_UNI_CODES);
   
                                 XMLCh unicode=(XMLCh)to_wchar_code(cell);                                  XMLCh unicode=(XMLCh)to_wchar_code(cell);
Line 178  void Charset::loadDefinition(const Strin Line 177  void Charset::loadDefinition(const Strin
   
 static int sort_cmp_Trans_rec_intCh(const void *a, const void *b) {  static int sort_cmp_Trans_rec_intCh(const void *a, const void *b) {
         return           return 
                 static_cast<const Charset_TransRec *>(a)->intCh-                  static_cast<const Charset::Tables::Rec *>(a)->intCh-
                 static_cast<const Charset_TransRec *>(b)->intCh;                  static_cast<const Charset::Tables::Rec *>(b)->intCh;
 }  }
   
 void Charset::sort_ToTable() {  void Charset::sort_ToTable() {
Line 191  void Charset::sort_ToTable() { Line 190  void Charset::sort_ToTable() {
 }  }
   
 static XMLByte xlatOneTo(const XMLCh toXlat,  static XMLByte xlatOneTo(const XMLCh toXlat,
                                                  const Charset::Tables& tables) {                           const Charset::Tables& tables,
     unsigned int    lowOfs = 0;                           XMLByte not_found) {
     unsigned int    hiOfs = tables.toTableSize - 1;          unsigned int    lowOfs = 0;
     XMLByte         curByte = 0;          unsigned int    hiOfs = tables.toTableSize - 1;
     do {          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 midOfs =((hiOfs - lowOfs) / 2)+lowOfs;
                   
         //  If our test char is greater than the mid point char, then                  //  If our test char is greater than the mid point char, then
         //  we move up to the upper half. Else we move to the lower                  //  we move up to the upper half. Else we move to the lower
         //  half. If its equal, then its our guy.                  //  half. If its equal, then its our guy.
         if(toXlat>tables.toTable[midOfs].intCh)                  if(toXlat>tables.toTable[midOfs].intCh)
             lowOfs = midOfs;                          lowOfs = midOfs;
                 else if(toXlat<tables.toTable[midOfs].intCh)                  else if(toXlat<tables.toTable[midOfs].intCh)
                         hiOfs = midOfs;                          hiOfs = midOfs;
                 else                  else
                         return tables.toTable[midOfs].extCh;                          return tables.toTable[midOfs].extCh;
         } while(lowOfs+1<hiOfs);          } while(lowOfs+1<hiOfs);
           
     return '?';          return not_found;
 }  }
   
 void Charset::transcode(Pool& pool,  String::C Charset::transcode(const String::C src,
         const Charset& source_charset, const void *source_body, size_t source_content_length,          const Charset& source_charset, 
         const Charset& dest_charset, const void *& dest_body, size_t& dest_content_length          const Charset& dest_charset) {
         ) {          if(!src.length)
         if(!source_content_length) {                  return String::C("", 0);
                 dest_body=0;  
                 dest_content_length=0;  
                 return;  
         }  
   
         switch((source_charset.isUTF8()?0x10:0x00)|(dest_charset.isUTF8()?0x01:0x00)) {          switch((source_charset.isUTF8()?0x10:0x00)|(dest_charset.isUTF8()?0x01:0x00)) {
                 default: // 0x00                  default: // 0x00
                         source_charset.transcodeToCharset(pool, dest_charset,                          return source_charset.transcodeToCharset(src, dest_charset);
                                 source_body, source_content_length,  
                                 dest_body, dest_content_length);  
                         break;  
                 case 0x01:                  case 0x01:
                         source_charset.transcodeToUTF8(pool,                          return source_charset.transcodeToUTF8(src);
                                 source_body, source_content_length,  
                                 dest_body, dest_content_length);  
                         break;  
                 case 0x10:                  case 0x10:
                         dest_charset.transcodeFromUTF8(pool,                          return dest_charset.transcodeFromUTF8(src);
                                 source_body, source_content_length,  
                                 dest_body, dest_content_length);  
                         break;  
                 case 0x11:                  case 0x11:
                         dest_body=source_body;                          return src;
                         dest_content_length=source_content_length;  
                         break;  
         }          }
 }  }
   
Line 287  static const XMLByte gFirstByteMark[7] = Line 271  static const XMLByte gFirstByteMark[7] =
     0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC      0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC
 };  };
   
 static int transcodeToUTF8(  static int transcodeToUTF8(const XMLByte* srcData, size_t& srcLen,
                                                         const XMLByte* srcData, size_t& srcLen,                             XMLByte *toFill, size_t& toFillLen,
                                                         XMLByte *toFill, size_t& toFillLen,                             const Charset::Tables& tables) {
                                                         const Charset::Tables& tables) {  
         const XMLByte* srcPtr=srcData;          const XMLByte* srcPtr=srcData;
         const XMLByte* srcEnd=srcData+srcLen;          const XMLByte* srcEnd=srcData+srcLen;
         XMLByte* outPtr=toFill;          XMLByte* outPtr=toFill;
         XMLByte* outEnd=toFill+toFillLen;          XMLByte* outEnd=toFill+toFillLen;
   
     while(srcPtr<srcEnd) {          while(srcPtr<srcEnd) {
         uint curVal = tables.fromTable[*srcPtr];                  uint curVal = tables.fromTable[*srcPtr];
                 if(!curVal) {                  if(!curVal) {
             // use the replacement character                          // use the replacement character
             *outPtr++= '?';                          *outPtr++= '?';
             srcPtr++;                          srcPtr++;
             continue;                          continue;
         }                  }
   
         // Figure out how many bytes we need                  // Figure out how many bytes we need
         unsigned int encodedBytes;                  unsigned int encodedBytes;
         if(curVal<0x80)                  if(curVal<0x80)
             encodedBytes = 1;                          encodedBytes = 1;
         else if(curVal<0x800)                  else if(curVal<0x800)
             encodedBytes = 2;                          encodedBytes = 2;
         else if(curVal<0x10000)                  else if(curVal<0x10000)
             encodedBytes = 3;                          encodedBytes = 3;
         else if(curVal<0x200000)                  else if(curVal<0x200000)
             encodedBytes = 4;                          encodedBytes = 4;
         else if(curVal<0x4000000)                  else if(curVal<0x4000000)
             encodedBytes = 5;                          encodedBytes = 5;
         else if(curVal<= 0x7FFFFFFF)                  else if(curVal<= 0x7FFFFFFF)
             encodedBytes = 6;                          encodedBytes = 6;
         else {                  else {
             // use the replacement character                          // use the replacement character
             *outPtr++= '?';                          *outPtr++= '?';
             srcPtr++;                          srcPtr++;
             continue;                          continue;
         }                  }
   
         //  If we cannot fully get this char into the output buffer                  //  If we cannot fully get this char into the output buffer
         if (outPtr + encodedBytes > outEnd)                  if (outPtr + encodedBytes > outEnd)
             break;                          break;
                   
         // We can do it, so update the source index                  // We can do it, so update the source index
         srcPtr++;                  srcPtr++;
                   
         //  And spit out the bytes. We spit them out in reverse order                  //  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.                  //  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
         outPtr+= encodedBytes;                  outPtr+= encodedBytes;
     }          }
           
     // Update the bytes eaten          // Update the bytes eaten
     srcLen = srcPtr - srcData;          srcLen = srcPtr - srcData;
           
     // Return the characters read          // Return the characters read
     toFillLen = outPtr - toFill;          toFillLen = outPtr - toFill;
           
         return srcPtr==srcEnd?toFillLen:-1;          //return srcPtr==srcEnd?(int)toFillLen:-1;
 }  /*
 static size_t transcodeFromUTF8(  xmlCharEncodingInputFunc
                                                                 const XMLByte *srcData, size_t& srcLen,  Returns :
                                                                 XMLByte* toFill, size_t& toFillLen,  the number of byte written, or -1 by lack of space, or -2 if the transcoding failed. The value of inlen after return is the
                                                                 const Charset::Tables& tables) {  number of octets consumed as the return value is positive, else unpredictiable. The value of outlen after return is the number
   of ocetes consumed.
   */
           return 0;
   }
   /// @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,
                                XMLByte* toFill, size_t& toFillLen,
                                const Charset::Tables& tables) {
         const XMLByte* srcPtr=srcData;          const XMLByte* srcPtr=srcData;
         const XMLByte* srcEnd=srcData+srcLen;          const XMLByte* srcEnd=srcData+srcLen;
         XMLByte* outPtr=toFill;          XMLByte* outPtr=toFill;
         XMLByte* outEnd=toFill+toFillLen;          XMLByte* outEnd=toFill+toFillLen;
   
     //  We now loop until we either run out of input data, or room to store          //  We now loop until we either run out of input data, or room to store
     while ((srcPtr < srcEnd) && (outPtr < outEnd)) {          while ((srcPtr < srcEnd) && (outPtr < outEnd)) {
         // Get the next leading byte out                  // Get the next leading byte out
         const XMLByte firstByte = *srcPtr;                  const XMLByte firstByte =* srcPtr;
                   
         // Special-case ASCII, which is a leading byte value of<= 127                  // Special-case ASCII, which is a leading byte value of<= 127
         if(firstByte<= 127) {                  if(firstByte<= 127) {
             *outPtr++= firstByte;                          *outPtr++= firstByte;
             srcPtr++;                          srcPtr++;
             continue;                          continue;
         }                  }
                   
         // See how many trailing src bytes this sequence is going to require                  // See how many trailing src bytes this sequence is going to require
         const unsigned int trailingBytes = gUTFBytes[firstByte];                  const unsigned int trailingBytes = gUTFBytes[firstByte];
                   
         //  If there are not enough source bytes to do this one, then we                  //  If there are not enough source bytes to do this one, then we
         //  are done. Note that we done>= here because we are implicitly                  //  are done. Note that we done>= here because we are implicitly
         //  counting the 1 byte we get no matter what.                  //  counting the 1 byte we get no matter what.
         if(srcPtr+trailingBytes>= srcEnd)                  if(srcPtr+trailingBytes>= srcEnd)
             break;                          break;
                   
         // Looks ok, so lets build up the value                  // Looks ok, so lets build up the value
         uint tmpVal=0;                  uint tmpVal=0;
         switch(trailingBytes) {                  switch(trailingBytes) {
             case 5: tmpVal+=*srcPtr++; tmpVal<<=6;                  case 5: tmpVal+=*srcPtr++; tmpVal<<=6;
             case 4: tmpVal+=*srcPtr++; tmpVal<<=6;                  case 4: tmpVal+=*srcPtr++; tmpVal<<=6;
             case 3: tmpVal+=*srcPtr++; tmpVal<<=6;                  case 3: tmpVal+=*srcPtr++; tmpVal<<=6;
             case 2: tmpVal+=*srcPtr++; tmpVal<<=6;                  case 2: tmpVal+=*srcPtr++; tmpVal<<=6;
             case 1: tmpVal+=*srcPtr++; tmpVal<<=6;                  case 1: tmpVal+=*srcPtr++; tmpVal<<=6;
             case 0: tmpVal+=*srcPtr++;                  case 0: tmpVal+=*srcPtr++;
                      break;                          break;
                           
             default:                  default:
                 throw Exception(0, 0,                          throw Exception(0,
                                         0,  
                                         "transcodeFromUTF8 error: wrong trailingBytes value(%d)", trailingBytes);  
         }  
         tmpVal-=gUTFOffsets[trailingBytes];  
   
         //  If it will fit into a single char, then put it in. Otherwise  
         //  fail [*encode it as a surrogate pair. If its not valid, use the  
         //  replacement char.*]  
         if(!(tmpVal & 0xFFFF0000))  
             *outPtr++= xlatOneTo(tmpVal, tables);  
                 else  
                         throw Exception(0, 0,  
                                 0,                                  0,
                                 "transcodeFromUTF8 error: too big tmpVal(0x%08X)", tmpVal);                                  "transcodeFromUTF8 error: wrong trailingBytes value(%d)", trailingBytes);
                   }
                   tmpVal-=gUTFOffsets[trailingBytes];
                   
                   //  If it will fit into a single char, then put it in. Otherwise
                   //  fail [*encode it as a surrogate pair. If its not valid, use the
                   //  replacement char.*]
                   if(!(tmpVal & 0xFFFF0000)) {
                           if(XMLByte xlat=xlatOneTo(tmpVal, tables, 0))
                                   *outPtr++=xlat;
                           else 
                                   outPtr+=sprintf((char *)outPtr, "&#%d;", tmpVal); // &#decimal;
                   } else
                           throw Exception(0,
                           0,
                           "transcodeFromUTF8 error: too big tmpVal(0x%08X)", tmpVal);
         }          }
           
           // Update the bytes eaten
           srcLen = srcPtr - srcData;
           
           // Return the characters read
           toFillLen = outPtr - toFill;
   
     // Update the bytes eaten          //return srcPtr==srcEnd?(int)toFillLen:-1;
     srcLen = srcPtr - srcData;  /*
   xmlCharEncodingOutputFunc
     // Return the characters read  Returns :
     toFillLen = outPtr - toFill;  the number of byte written, or -1 by lack of space, or -2 if the transcoding failed. The value of inlen after return is the
   number of octets consumed as the return value is positive, else unpredictiable. The value of outlen after return is the number
         return srcPtr==srcEnd?toFillLen:-1;  of ocetes consumed.
   */
           return 0;
 }  }
   
 /// @todo not so memory-hungry with prescan  /// @todo not so memory-hungry with prescan
 void Charset::transcodeToUTF8(Pool& pool,  const String::C Charset::transcodeToUTF8(const String::C src) const {
                                                                  const void *source_body, size_t source_content_length,          size_t src_length=src.length;
                                                                  const void *& adest_body, size_t& dest_content_length) const {          size_t dest_length=src.length*6/*so that surly enough, max utf8 seq len=6*/;
         dest_content_length=source_content_length*6/*so that surly enough*/;  #ifndef NDEBUG
         XMLByte *dest_body=(XMLByte*)pool.malloc(dest_content_length);          size_t saved_dest_length=dest_length;
   #endif
           XMLByte *dest_body=new(PointerFreeGC) XMLByte[dest_length+1/*for terminator*/];
   
         if(::transcodeToUTF8(          if(::transcodeToUTF8(
                 (XMLByte *)source_body, source_content_length,                  (XMLByte *)src.str, src_length,
                 dest_body, dest_content_length,                  dest_body, dest_length,
                 tables)<0)                  tables)<0)
                 throw(0, 0,                  throw(0, 0,
                         0,                          0,
                         "Charset::transcodeToUTF8 buffer overflow");                          "Charset::transcodeToUTF8 buffer overflow");
   
         // return          assert(dest_length<=saved_dest_length); dest_body[dest_length]=0; // terminator
         adest_body=dest_body;          return String::C((char*)dest_body, dest_length);
   }
   
   static XMLCh change_case_UTF8(const XMLCh src, const Charset::UTF8CaseTable& table) {
           unsigned int    lowOfs = 0;
           unsigned int    hiOfs = table.size - 1;
           do {
                   // Calc the mid point of the low and high offset.
                   const unsigned int midOfs =((hiOfs - lowOfs) / 2)+lowOfs;
                   
                   //  If our test char is greater than the mid point char, then
                   //  we move up to the upper half. Else we move to the lower
                   //  half. If its equal, then its our guy.
                   if(src>table.records[midOfs].from)
                           lowOfs = midOfs;
                   else if(src<table.records[midOfs].from)
                           hiOfs = midOfs;
                   else
                           return table.records[midOfs].to;
           } while(lowOfs+1<hiOfs);
           
           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, XMLByte* toFill, 
                                                           const Charset::UTF8CaseTable& table) {
           const XMLByte* srcPtr=srcData;
           XMLByte* outPtr=toFill;
   
           // Get the next leading byte out
           while (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");
 }  }
 /// @test buf overflow  
 void Charset::transcodeFromUTF8(Pool& pool,  
                                                                    const void *source_body, size_t source_content_length,  const String::C Charset::transcodeFromUTF8(const String::C src) const {
                                                                    const void *& adest_body, size_t& dest_content_length) const {          size_t src_length=src.length;
         dest_content_length=source_content_length/*surly enough*/;          size_t dest_length=src.length*6/*so that surly enough, "&#255;" has max ratio */;
         XMLByte *dest_body=(XMLByte*)pool.malloc(dest_content_length);  #ifndef NDEBUG
           size_t saved_dest_length=dest_length;
   #endif
           XMLByte *dest_body=new(PointerFreeGC) XMLByte[dest_length+1/*for terminator*/];
   
         if(::transcodeFromUTF8(          if(::transcodeFromUTF8(
                 (XMLByte *)source_body, source_content_length,                  (XMLByte *)src.str, src_length,
                 dest_body, dest_content_length,                  dest_body, dest_length,
                 tables)<0)                  tables)<0)
                 throw(0, 0,                  throw(0, 0,
                         0,                          0,
                         "Charset::transcodeToUTF8 buffer overflow");                          "Charset::transcodeFromUTF8 buffer overflow");
   
         // return          assert(dest_length<=saved_dest_length); dest_body[dest_length]=0; // terminator
         adest_body=dest_body;          return String::C((char*)dest_body, dest_length);
 }  }
   
 /// transcode using both charsets  /// transcode using both charsets
 void Charset::transcodeToCharset(Pool& pool,  const String::C Charset::transcodeToCharset(const String::C src, 
                                                                            const Charset& dest_charset,                                              const Charset& dest_charset) const {
                                                                            const void *source_body, size_t source_content_length,          if(&dest_charset==this) 
                                                                            const void *& adest_body, size_t& adest_content_length) const {                  return src;
         if(&dest_charset==this) {          else {
                 adest_body=source_body;                  size_t dest_length=src.length;
                 adest_content_length=source_content_length;                  XMLByte* dest_body=new(PointerFreeGC) XMLByte[dest_length+1/*for terminator*/];
         } else {  
                 size_t dest_content_length=source_content_length;                  XMLByte* output=dest_body;
                 unsigned char *dest_body=(unsigned char *)pool.malloc(dest_content_length);                  const XMLByte* input=(XMLByte *)src.str;
                   while(XMLCh c=*input++) {
                 const XMLByte* srcPtr=(XMLByte *)source_body;                          XMLCh curVal = tables.fromTable[c];
                 const XMLByte* srcEnd=(XMLByte *)source_body+source_content_length;                          *output++=curVal?
                                   xlatOneTo(curVal, dest_charset.tables, '?') // OK
                 for(XMLByte* outPtr=dest_body; srcPtr<srcEnd; srcPtr++) {                                  :'?'; // use the replacement character
                         XMLCh curVal = tables.fromTable[*srcPtr];  
                         if(curVal)   
                                 *outPtr++=xlatOneTo(curVal, dest_charset.tables);  
                         else {  
                                 // use the replacement character  
                                 *outPtr++= '?';  
                         }         
                 }                  }
   
                 adest_body=dest_body;                  dest_body[dest_length]=0; // terminator
                 adest_content_length=dest_content_length;                  return String::C((char*)dest_body, dest_length);
         }          }
 }                         }                       
   
 #ifdef XML  #ifdef XML
 static int         xml256CharEncodingInputFunc     (  
                                                                                                         unsigned char *out,  
                                                                                                         int *outlen,  
                                                                                                         const unsigned char *in,  
                                                                                                         int *inlen,   
                                                                                                         void *info) {  
         return transcodeToUTF8(  
                                                         in, *(unsigned int*)inlen,  
                                                         out, *(unsigned int*)outlen,  
                                                         *(const Charset::Tables *)info);  
 }  
   
 static int         xml256CharEncodingOutputFunc    (  
                                                                                                         unsigned char *out,  
                                                                                                         int *outlen,  
                                                                                                         const unsigned char *in,  
                                                                                                         int *inlen,   
                                                                                                         void *info) {  
         return transcodeFromUTF8(  
                                                         in, *(unsigned int*)inlen,  
                                                         out, *(unsigned int*)outlen,  
                                                         *(const Charset::Tables *)info);  
 }  
   
   static const Charset::Tables* tables[MAX_CHARSETS];
   
   #define declareXml256ioFuncs(i) \
           static int xml256CharEncodingInputFunc##i( \
                   unsigned char *out, int *outlen, \
                   const unsigned char *in, int *inlen) { \
                   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) { \
                   return transcodeFromUTF8( \
                           in, *(size_t*)inlen, \
                           out, *(size_t*)outlen, \
                           *tables[i]); \
           }
   
   declareXml256ioFuncs(0) declareXml256ioFuncs(1)
   declareXml256ioFuncs(2) declareXml256ioFuncs(3)
   declareXml256ioFuncs(4) declareXml256ioFuncs(5)
   declareXml256ioFuncs(6) declareXml256ioFuncs(7)
   declareXml256ioFuncs(8) declareXml256ioFuncs(9)
   
   static xmlCharEncodingInputFunc inputFuncs[MAX_CHARSETS]={
           xml256CharEncodingInputFunc0,   xml256CharEncodingInputFunc1,
           xml256CharEncodingInputFunc2,   xml256CharEncodingInputFunc3,
           xml256CharEncodingInputFunc4,   xml256CharEncodingInputFunc5,
           xml256CharEncodingInputFunc6,   xml256CharEncodingInputFunc7,
           xml256CharEncodingInputFunc8,   xml256CharEncodingInputFunc9
   };
   static xmlCharEncodingOutputFunc outputFuncs[MAX_CHARSETS]={
           xml256CharEncodingOutputFunc0,  xml256CharEncodingOutputFunc1,
           xml256CharEncodingOutputFunc2,  xml256CharEncodingOutputFunc3,
           xml256CharEncodingOutputFunc4,  xml256CharEncodingOutputFunc5,
           xml256CharEncodingOutputFunc6,  xml256CharEncodingOutputFunc7,
           xml256CharEncodingOutputFunc8,  xml256CharEncodingOutputFunc9
   };
   static size_t handlers_count=0;
   
 void Charset::addEncoding(char *name_cstr) {  void Charset::addEncoding(char *name_cstr) {
         xmlCharEncodingHandler *handler=          if(handlers_count==MAX_CHARSETS)
                 (xmlCharEncodingHandler *)malloc(sizeof(xmlCharEncodingHandler));                  throw Exception(0,
         handler->name=name_cstr;                          0,
         handler->input=xml256CharEncodingInputFunc; handler->inputInfo=&tables;                          "already allocated %d handlers, no space for new encoding '%s'",
         handler->output=xml256CharEncodingOutputFunc; handler->outputInfo=&tables;                                  MAX_CHARSETS, name_cstr);
   
           xmlCharEncodingHandler* handler=new(PointerFreeGC) xmlCharEncodingHandler;
           {
                   handler->name=name_cstr;
                   handler->input=inputFuncs[handlers_count]; 
                   handler->output=outputFuncs[handlers_count]; 
                   ::tables[handlers_count]=&tables;
                   handlers_count++;
           }
                   
         xmlRegisterCharEncodingHandler(handler);          xmlRegisterCharEncodingHandler(handler);
   
   }
   
   void Charset::initTranscoder(const String::Body NAME, const char* name_cstr) {
           ftranscoder=xmlFindCharEncodingHandler(name_cstr);
           transcoder(NAME); // check right way
 }  }
   
 void Charset::initTranscoder(const String *source, const char *name_cstr) {  xmlCharEncodingHandler& Charset::transcoder(const String::Body NAME) {
         transcoder=xmlFindCharEncodingHandler(name_cstr);          if(!ftranscoder)
         if(!transcoder)                  throw Exception("parser.runtime",
                 throw Exception(0, 0,                          new String(NAME, String::L_TAINTED),
                         source,  
                         "unsupported encoding");                          "unsupported encoding");
           return *ftranscoder;
 }  }
   
 const char *Charset::transcode_cstr(xmlChar *s) {  String::C Charset::transcode_cstr(xmlChar* s) {
         if(!transcoder)  
                 throw Exception(0, 0,  
                         0,  
                         "transcode_cstr no transcoder");  
         if(!s)          if(!s)
                 return "";                  return String::C("", 0);
   
           int inlen=strlen((const char*)s);
           int outlen=inlen; // max
   #ifndef NDEBUG
           int saved_outlen=outlen;
   #endif
           char *out=new(PointerFreeGC) char[outlen+1];
           
           int error;
           if(xmlCharEncodingOutputFunc output=transcoder(FNAME).output) {
                   error=output(
                           (unsigned char*)out, &outlen,
                           (const unsigned char*)s, &inlen);
           } else {
                   memcpy(out, s, outlen=inlen);
                   error=0;
           }
           if(error<0)
                   throw Exception(0,
                           0,
                           "transcode_cstr failed (%d)", error);
   
           assert(outlen<=saved_outlen); out[outlen]=0;
           return String::C(out, outlen);
   }
   const String& Charset::transcode(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);
           return *new String(cstr.str, cstr.length, true);
   }
   
         int inlen=strlen((const char *)s);  /// @test less memory using -maybe- xmlParserInputBufferCreateMem
         int outlen=inlen+1; // max  xmlChar* Charset::transcode_buf2xchar(const char* buf, size_t buf_size) {
         char *out=(char *)malloc(outlen*sizeof(char));          xmlChar* out;
                   int outlen;
         int size=transcoder->output(          int error;
                 (unsigned char*)out, &outlen,  #ifndef NDEBUG
                 (const unsigned char*)s, &inlen,          int saved_outlen;
                 transcoder->outputInfo);  #endif
         if(size<0)          if(xmlCharEncodingInputFunc input=transcoder(FNAME).input) {
                 throw Exception(0, 0,                  outlen=buf_size*6/*max*/;
   #ifndef NDEBUG
                   saved_outlen=outlen;
   #endif
                   out=(xmlChar*)xmlMalloc(outlen+1);
                   error=input(
                           out, &outlen,
                           (const unsigned char*)buf, (int*)&buf_size);
           } else {
                   outlen=buf_size;
   #ifndef NDEBUG
                   saved_outlen=outlen;
   #endif
                   out=(xmlChar*)xmlMalloc(outlen+1);
                   memcpy(out, buf, outlen);
                   error=0;
           }
           
           if(error<0)
                   throw Exception(0,
                         0,                          0,
                         "transcode_cstr failed (%d)", size);                          "transcode_buf failed (%d)", error);
   
         out[size]=0;          assert(outlen<=saved_outlen); out[outlen]=0;
         return out;          return out;
 }  }
 String& Charset::transcode(xmlChar *s) {   GdomeDOMString_auto_ptr Charset::transcode_buf2dom(const char* buf, size_t buf_size) { 
         return *NEW String(pool(), transcode_cstr(s));           return GdomeDOMString_auto_ptr(transcode_buf2xchar(buf, buf_size));
 }  }
 const char *Charset::transcode_cstr(GdomeDOMString *s) {   GdomeDOMString_auto_ptr Charset::transcode(const String& s) { 
         return s?transcode_cstr(BAD_CAST s->str):"";          const char* cstr=s.cstr(String::L_UNSPECIFIED);
   
           return transcode_buf2dom(cstr, strlen(cstr)); 
 }  }
 String& Charset::transcode(GdomeDOMString *s) {   GdomeDOMString_auto_ptr Charset::transcode(const String::Body s) { 
         return *NEW String(pool(), transcode_cstr(s));           const char* cstr=s.cstr();
   
           return transcode_buf2dom(cstr, s.length()); 
 }  }
   #endif
   
 /// @test less memory using -maybe- xmlParserInputBufferCreateMem  String::Body Charset::transcode(const String::Body src, 
 GdomeDOMString_auto_ptr Charset::transcode_buf(const char *buf, size_t buf_size) {           const Charset& source_transcoder, 
         if(!transcoder)          const Charset& dest_transcoder) {
                 throw Exception(0, 0,  
                         0,  
                         "transcode_buf no transcoder");  
   
         int outlen=buf_size*6/*max*/+1;          const char *src_ptr=src.cstr();
         unsigned char *out=(unsigned char*)malloc(outlen*sizeof(unsigned char));          size_t src_size=strlen(src_ptr);
         int size=transcoder->input(  
                 out, &outlen,  
                 (const unsigned char *)buf,  (int *)&buf_size,  
                 transcoder->inputInfo);  
         if(size<0)  
                 throw Exception(0, 0,  
                         0,  
                         "transcode_buf failed (%d)", size);  
   
         out[size]=0;          String::C dest=Charset::transcode(String::C(src_ptr, src_size),
         return (gchar*)out;                  source_transcoder,
                   dest_transcoder);
   
           return String::Body(dest.str, dest.length);
   }
   
   String& Charset::transcode(const String& src, 
           const Charset& source_transcoder, 
           const Charset& dest_transcoder) {
           if(!src.length())
                   return *new String("", 0, false);
   
           return *new String(transcode((String::Body)src, source_transcoder, dest_transcoder), String::L_CLEAN);
 }  }
 GdomeDOMString_auto_ptr Charset::transcode(const String& s) {   
         const char *cstr=s.cstr(String::UL_UNSPECIFIED);  
   
         return transcode_buf(cstr, strlen(cstr));   void Charset::transcode(ArrayString& src,
           const Charset& source_transcoder, 
           const Charset& dest_transcoder) {
           for(size_t i=0; i<src.count(); i++)
                   src.put(i, &transcode(*src[i], source_transcoder, dest_transcoder));
 }  }
   
   #ifndef DOXYGEN
   struct Transcode_pair_info {
           const Charset* source_transcoder;
           const Charset* dest_transcoder;
   };
 #endif  #endif
   static void transcode_pair(const String::Body akey, 
                            String::Body& avalue, 
                            Transcode_pair_info* info) {
           avalue=Charset::transcode(avalue,
                   *info->source_transcoder, 
                   *info->dest_transcoder);
   }
   void Charset::transcode(HashStringString& src,
           const Charset& source_transcoder, 
           const Charset& dest_transcoder) {
           Transcode_pair_info info={&source_transcoder, &dest_transcoder};
           src.for_each_ref(transcode_pair, &info);
   }

Removed from v.1.14  
changed lines
  Added in v.1.38


E-mail: