Diff for /parser3/src/main/pa_charset.C between versions 1.6 and 1.49

version 1.6, 2001/12/19 16:41:02 version 1.49, 2004/07/07 09:50:25
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-2004 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 * const IDENT_CHARSET_C="$Date$";
   
 #include "pa_charset.h"  #include "pa_charset.h"
 //#include "pa_exception.h"  #include "pa_charsets.h"
 //#include "pa_common.h"  
 //#include "pa_threads.h"  
   
 #ifdef XML  #ifdef XML
 #       include<util/TransENameMap.hpp>  #include "libxml/encoding.h"
 #       include<util/XML256TableTranscoder.hpp>  
 #       include<util/PlatformUtils.hpp>  
 #       include<PlatformSupport/XalanTranscodingServices.hpp>  
 #endif  #endif
   
 // globals  //#define PA_PATCHED_LIBXML_BACKWARD
   
   // globals
   
 // consts  Charset::UTF8CaseTable::Rec UTF8CaseToUpperRecords[]={
   #include "utf8-to-upper.inc"
   };
   Charset::UTF8CaseTable UTF8CaseToUpper={
           sizeof(UTF8CaseToUpperRecords)/sizeof(Charset::UTF8CaseTable::Rec),
           UTF8CaseToUpperRecords};
   
 #define MAX_CHARSET_UNI_CODES 500  Charset::UTF8CaseTable::Rec UTF8CaseToLowerRecords[]={
   #include "utf8-to-lower.inc"
   };
   Charset::UTF8CaseTable UTF8CaseToLower={
           sizeof(UTF8CaseToLowerRecords)/sizeof(Charset::UTF8CaseTable::Rec),
           UTF8CaseToLowerRecords};
   
 // helpers  // helpers
   
Line 43  inline void cstr2ctypes(unsigned char *t Line 49  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 52  inline unsigned int to_wchar_code(const Line 58  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 77  static void element2case(unsigned char f Line 83  static void element2case(unsigned char f
         fcc_table[from]=to; fcc_table[to]=from;          fcc_table[from]=to; fcc_table[to]=from;
 }  }
   
 #ifdef XML  
 template <class TType> class ENameMapFor2 : public ENameMap {  
 public:  
     // -----------------------------------------------------------------------  
     //  Constructors and Destructor  
     // -----------------------------------------------------------------------  
     ENameMapFor2(  
                 const XMLCh* const encodingName  
         , const XMLCh* const                        fromTable  
         , const XMLTransService::TransRec* const    toTable  
         , const unsigned int                        toTableSize  
                 ): ENameMap(encodingName),  
                 ffromTable(fromTable),  
                 ftoTable(toTable),  
                 ftoTableSize(toTableSize) {}  
   
     // -----------------------------------------------------------------------  
     //  Implementation of virtual factory method  
     // -----------------------------------------------------------------------  
     virtual XMLTranscoder* makeNew(const unsigned int blockSize) const {  
                 return new TType(  
                         getKey(),   
                         blockSize,  
                         ffromTable,  
                         ftoTable, ftoTableSize);  
         }  
 private:  
         const XMLCh* const                        ffromTable;  
         const XMLTransService::TransRec* const    ftoTable;  
         const unsigned int                        ftoTableSize;  
   
 private:  
     // -----------------------------------------------------------------------  
     //  Unimplemented constructors and operators  
     // -----------------------------------------------------------------------  
     ENameMapFor2();  
     ENameMapFor2(const ENameMapFor2<TType>&);  
     void operator=(const ENameMapFor2<TType>&);  
 };  
   
 class XML256TableTranscoder2 : public XML256TableTranscoder {  
 public :  
     XML256TableTranscoder2(  
         const   XMLCh* const                        encodingName  
         , const unsigned int                        blockSize  
         , const XMLCh* const                        fromTable  
         , const XMLTransService::TransRec* const    toTable  
         , const unsigned int                        toTableSize  
                 ) : XML256TableTranscoder(encodingName, blockSize, fromTable, toTable, toTableSize) {}  
   
 private:  
     XML256TableTranscoder2();  
     XML256TableTranscoder2(const XML256TableTranscoder2&);  
     void operator=(const XML256TableTranscoder2&);  
 };  
 #endif  
   
 // 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 *file_spec): Pooled(apool),  Charset::Charset(Request_charsets* charsets, const String::Body ANAME, const String* afile_spec): 
         fname(apool) {          FNAME(ANAME),
         // fname          FNAME_CSTR(ANAME.cstrm()) {
         char *name_cstr=(char *)malloc(aname.size()+1);  
         memcpy(name_cstr, aname.cstr(String::UL_AS_IS), aname.size()+1);  
         fname.APPEND_CLEAN(name_cstr, aname.size(), 0, 0);  
   
         if(file_spec) {          if(afile_spec) {
                 fisUTF8=false;                  fisUTF8=false;
                 loadDefinition(*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 157  Charset::Charset(Pool& apool, const Stri Line 103  Charset::Charset(Pool& apool, const Stri
         }          }
   
 #ifdef XML  #ifdef XML
         initTranscoder(&aname, name_cstr);          initTranscoder(FNAME, FNAME_CSTR);
 #endif  #endif
 }  }
   
 Charset::~Charset() {  void Charset::load_definition(Request_charsets& charsets, const String& afile_spec) {
 #ifdef XML  
         delete transcoder;  
 #endif  
 }  
   
 void Charset::loadDefinition(const String& file_spec) {  
         // pcre_tables          // pcre_tables
         // lowcase, flipcase, bits digit+word+whitespace, masks          // lowcase, flipcase, bits digit+word+whitespace, masks
   
Line 178  void Charset::loadDefinition(const Strin Line 118  void Charset::loadDefinition(const Strin
         cstr2ctypes(pcre_tables,(const unsigned char *)"*+?{^.$|()[", ctype_meta);          cstr2ctypes(pcre_tables,(const unsigned char *)"*+?{^.$|()[", ctype_meta);
   
         // charset          // charset
         memset(fromTable, 0, sizeof(fromTable));          memset(&tables, 0, sizeof(tables));
         toTable=(Charset_TransRec *)calloc(sizeof(Charset_TransRec)*MAX_CHARSET_UNI_CODES);  
         toTableSize=0;  
         // strangly vital  
         toTable[toTableSize].intCh=0;  
         toTable[toTableSize].extCh=(XMLByte)0;  
         toTableSize++;  
   
         // loading text          // loading text
         char *data=file_read_text(pool(), file_spec);          char *data=file_read_text(charsets, afile_spec);
   
         // ignore header          // ignore header
         getrow(&data);          getrow(&data);
   
         // parse cells          // parse cells
         char *row;          char *row;
         while(row=getrow(&data)) {          while((row=getrow(&data))) {
                 // remove empty&comment lines                  // remove empty&comment lines
                 if(!*row || *row=='#')                  if(!*row || *row=='#')
                         continue;                          continue;
Line 202  void Charset::loadDefinition(const Strin Line 136  void Charset::loadDefinition(const Strin
                 // char white-space     digit   hex-digit       letter  word    lowercase       unicode1        unicode2                          // char white-space     digit   hex-digit       letter  word    lowercase       unicode1        unicode2        
                 unsigned int c=0;                  unsigned int c=0;
                 char *cell;                  char *cell;
                 for(int column=0; cell=lsplit(&row, '\t'); column++) {                  for(int column=0; (cell=lsplit(&row, '\t')); column++) {
                         switch(column) {                          switch(column) {
                         case 0: c=to_wchar_code(cell); break;                          case 0: c=to_wchar_code(cell); break;
                         // pcre_tables                          // pcre_tables
Line 215  void Charset::loadDefinition(const Strin Line 149  void Charset::loadDefinition(const Strin
                         case 7:                          case 7:
                         case 8:                          case 8:
                                 // charset                                  // charset
                                 if(toTableSize>MAX_CHARSET_UNI_CODES)                                  if(tables.toTableSize>MAX_CHARSET_UNI_CODES)
                                         throw Exception(0, 0,                                          throw Exception("parser.runtime",
                                                 &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);
                                 if(!unicode && column==7/*unicode1 column*/)                                  if(!unicode && column==7/*unicode1 column*/)
                                         unicode=(XMLCh)c;                                          unicode=(XMLCh)c;
                                 if(unicode) {                                  if(unicode) {
                                         if(!fromTable[c])                                          if(!tables.fromTable[c])
                                                 fromTable[c]=unicode;                                                  tables.fromTable[c]=unicode;
                                         toTable[toTableSize].intCh=unicode;                                          tables.toTable[tables.toTableSize].intCh=unicode;
                                         toTable[toTableSize].extCh=(XMLByte)c;                                          tables.toTable[tables.toTableSize].extCh=(XMLByte)c;
                                         toTableSize++;                                          tables.toTableSize++;
                                 }                                  }
                                 break;                                  break;
                         }                          }
Line 239  void Charset::loadDefinition(const Strin Line 173  void Charset::loadDefinition(const Strin
         sort_ToTable();          sort_ToTable();
 }  }
   
 #ifdef XML  
 void Charset::addEncoding(const char *name_cstr) {  
         // addEncoding  
         XalanDOMString sencoding(name_cstr);  
         const XMLCh* const auto_encoding_cstr=sencoding.c_str();  
         int size=sizeof(XMLCh)*(sencoding.size()+1);  
         XMLCh* pool_encoding_cstr=(XMLCh*)malloc(size);  
         memcpy(pool_encoding_cstr, auto_encoding_cstr, size);  
     XMLString::upperCase(pool_encoding_cstr);  
   
     XMLPlatformUtils::fgTransService->addEncoding(  
                 pool_encoding_cstr,   
                 new ENameMapFor2<XML256TableTranscoder2>(  
                         pool_encoding_cstr  
                         , fromTable  
                         , toTable  
                         , toTableSize  
                 ));  
 }  
   
 void Charset::initTranscoder(const String *source, const char *name_cstr) {  
         XMLTransService::Codes resValue;  
         transcoder=XMLPlatformUtils::fgTransService->makeNewTranscoderFor(name_cstr, resValue, 60);  
         if(!transcoder)  
                 throw Exception(0, 0,  
                         source,  
                         "unsupported encoding");  
 }  
 #endif  
   
 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() {
         _qsort(toTable, toTableSize, sizeof(*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(toTable, toTableSize, sizeof(*toTable), f);          //fwrite(tables.toTable, tables.toTableSize, sizeof(*tables.toTable), f);
         //fclose(f);          //fclose(f);
 }  }
   
 XMLByte Charset::xlatOneTo(const XMLCh toXlat) const {  static XMLByte xlatOneTo(const XMLCh toXlat,
     unsigned int    lowOfs = 0;                           const Charset::Tables& tables,
     unsigned int    hiOfs = toTableSize - 1;                           XMLByte not_found) {
     XMLByte         curByte = 0;          int    lo = 0;
     do {          int    hi = tables.toTableSize - 1;
         // Calc the mid point of the low and high offset.          while(lo<=hi) {
         const unsigned int midOfs =((hiOfs - lowOfs) / 2)+lowOfs;                  // Calc the mid point of the low and high offset.
                   const unsigned int i = (lo + hi) / 2;
         //  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                  XMLCh cur=tables.toTable[i].intCh;
         //  half. If its equal, then its our guy.                  if(toXlat==cur)
         if(toXlat>toTable[midOfs].intCh)                          return tables.toTable[i].extCh;
             lowOfs = midOfs;                  if(toXlat>cur)
                 else if(toXlat<toTable[midOfs].intCh)                          lo = i+1;
                         hiOfs = midOfs;  
                 else                  else
                         return toTable[midOfs].extCh;                          hi = i-1;
         } 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 379  static const XMLByte gFirstByteMark[7] = Line 267  static const XMLByte gFirstByteMark[7] =
     0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC      0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC
 };  };
   
 /// @todo not so memory-hungry with prescan  static int transcodeToUTF8(const XMLByte* srcData, size_t& srcLen,
 void Charset::transcodeToUTF8(Pool& pool,                             XMLByte *toFill, size_t& toFillLen,
                                                                  const void *source_body, size_t source_content_length,                             const Charset::Tables& tables) {
                                                                  const void *& adest_body, size_t& adest_content_length) const {          const XMLByte* srcPtr=srcData;
                   const XMLByte* srcEnd=srcData+srcLen;
         size_t dest_content_length=0;          XMLByte* outPtr=toFill;
         XMLByte *dest_body=(XMLByte*)pool.malloc(source_content_length*6/*so that surly enough*/);          XMLByte* outEnd=toFill+toFillLen;
   
         const XMLByte* srcPtr=(const XMLByte*)source_body;  
         const XMLByte* srcEnd=(const XMLByte*)source_body+source_content_length;  
         XMLByte* outPtr=dest_body;  
   
     while(srcPtr<srcEnd) {          while(srcPtr<srcEnd) {
         uint curVal = 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
                 // never                  if (outPtr + encodedBytes > outEnd)
                           break;
         // We can do it, so update the source index                  
         srcPtr++;                  // We can do it, so update the source index
                   srcPtr++;
         //  And spit out the bytes. We spit them out in reverse order                  
         //  here, so bump up the output pointer and work down as we go.                  //  And spit out the bytes. We spit them out in reverse order
         outPtr+= encodedBytes;                  //  here, so bump up the output pointer and work down as we go.
         switch(encodedBytes) {                  outPtr+= encodedBytes;
             case 6: *--outPtr = XMLByte((curVal | 0x80UL) & 0xBFUL);                  switch(encodedBytes) {
                      curVal>>= 6;                  case 6: *--outPtr = XMLByte((curVal | 0x80UL) & 0xBFUL);
             case 5: *--outPtr = XMLByte((curVal | 0x80UL) & 0xBFUL);                          curVal>>= 6;
                      curVal>>= 6;                  case 5: *--outPtr = XMLByte((curVal | 0x80UL) & 0xBFUL);
             case 4: *--outPtr = XMLByte((curVal | 0x80UL) & 0xBFUL);                          curVal>>= 6;
                      curVal>>= 6;                  case 4: *--outPtr = XMLByte((curVal | 0x80UL) & 0xBFUL);
             case 3: *--outPtr = XMLByte((curVal | 0x80UL) & 0xBFUL);                          curVal>>= 6;
                      curVal>>= 6;                  case 3: *--outPtr = XMLByte((curVal | 0x80UL) & 0xBFUL);
             case 2: *--outPtr = XMLByte((curVal | 0x80UL) & 0xBFUL);                          curVal>>= 6;
                      curVal>>= 6;                  case 2: *--outPtr = XMLByte((curVal | 0x80UL) & 0xBFUL);
             case 1: *--outPtr = XMLByte(curVal | gFirstByteMark[encodedBytes]);                          curVal>>= 6;
         }                  case 1: *--outPtr = XMLByte(curVal | gFirstByteMark[encodedBytes]);
                   }
         // Add the encoded bytes back in again to indicate we've eaten them                  
         outPtr+= encodedBytes;                  // Add the encoded bytes back in again to indicate we've eaten them
     }                  outPtr+= encodedBytes;
           }
         // return          
         adest_body=dest_body;          // Update the bytes eaten
         adest_content_length=outPtr-dest_body;          srcLen = srcPtr - srcData;
 }          
 void Charset::transcodeFromUTF8(Pool& pool,          // Return the characters read
                                                                    const void *source_body, size_t source_content_length,          toFillLen = outPtr - toFill;
                                                                    const void *& adest_body, size_t& adest_content_length) const {          
         size_t dest_content_length=0;          //return srcPtr==srcEnd?(int)toFillLen:-1;
         XMLByte *dest_body=(XMLByte*)pool.malloc(source_content_length/*surly enough*/);  /*
   xmlCharEncodingInputFunc
         const XMLByte* srcPtr=(const XMLByte*)source_body;  Returns :
         const XMLByte* srcEnd=(const XMLByte*)source_body+source_content_length;  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
         XMLByte* outPtr=dest_body;  number of octets consumed as the return value is positive, else unpredictiable. The value of outlen after return is the number
   of ocetes consumed.
     //  We now loop until we either run out of input data  */
     while(srcPtr<srcEnd) {          return 0;
         // Get the next leading byte out  }
         const XMLByte firstByte = *srcPtr;  /// @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,
         // Special-case ASCII, which is a leading byte value of<= 127                               XMLByte* toFill, size_t& toFillLen,
         if(firstByte<= 127) {                               const Charset::Tables& tables) {
             *outPtr++= firstByte;          const XMLByte* srcPtr=srcData;
             srcPtr++;          const XMLByte* srcEnd=srcData+srcLen;
             continue;          XMLByte* outPtr=toFill;
         }          XMLByte* outEnd=toFill+toFillLen;
   
         // See how many trailing src bytes this sequence is going to require          //  We now loop until we either run out of input data, or room to store
         const unsigned int trailingBytes = gUTFBytes[firstByte];          while ((srcPtr < srcEnd) && (outPtr < outEnd)) {
                   // Get the next leading byte out
         //  If there are not enough source bytes to do this one, then we                  const XMLByte firstByte =* srcPtr;
         //  are done. Note that we done>= here because we are implicitly                  
         //  counting the 1 byte we get no matter what.                  // Special-case ASCII, which is a leading byte value of<= 127
         if(srcPtr+trailingBytes>= srcEnd)                  if(firstByte<= 127) {
             break;                          *outPtr++= firstByte;
                           srcPtr++;
         // Looks ok, so lets build up the value                          continue;
         uint tmpVal=0;                  }
         switch(trailingBytes) {                  
             case 5: tmpVal+=*srcPtr++; tmpVal<<=6;                  // See how many trailing src bytes this sequence is going to require
             case 4: tmpVal+=*srcPtr++; tmpVal<<=6;                  const unsigned int trailingBytes = gUTFBytes[firstByte];
             case 3: tmpVal+=*srcPtr++; tmpVal<<=6;                  
             case 2: tmpVal+=*srcPtr++; tmpVal<<=6;                  //  If there are not enough source bytes to do this one, then we
             case 1: tmpVal+=*srcPtr++; tmpVal<<=6;                  //  are done. Note that we done>= here because we are implicitly
             case 0: tmpVal+=*srcPtr++;                  //  counting the 1 byte we get no matter what.
                      break;                  if(srcPtr+trailingBytes>= srcEnd)
                           break;
             default:                  
                 throw Exception(0, 0,                  // Looks ok, so lets build up the value
                                         0,                  uint tmpVal=0;
                                         "transcodeFromUTF8 error: wrong trailingBytes value(%d)", trailingBytes);                  switch(trailingBytes) {
         }                  case 5: tmpVal+=*srcPtr++; tmpVal<<=6;
         tmpVal-=gUTFOffsets[trailingBytes];                  case 4: tmpVal+=*srcPtr++; tmpVal<<=6;
                   case 3: tmpVal+=*srcPtr++; tmpVal<<=6;
         //  If it will fit into a single char, then put it in. Otherwise                  case 2: tmpVal+=*srcPtr++; tmpVal<<=6;
         //  fail [*encode it as a surrogate pair. If its not valid, use the                  case 1: tmpVal+=*srcPtr++; tmpVal<<=6;
         //  replacement char.*]                  case 0: tmpVal+=*srcPtr++;
         if(!(tmpVal & 0xFFFF0000))                          break;
             *outPtr++= xlatOneTo(tmpVal);                          
                 else                  default:
                         throw Exception(0, 0,                          throw Exception(0,
                                 0,                                  0,
                                 "transcodeFromUTF8 error: too big tmpVal(0x%08X)", tmpVal);                                  "transcodeFromUTF8 error: wrong trailingBytes value(%d)", trailingBytes); // never
                   }
                   tmpVal-=gUTFOffsets[trailingBytes];
                   
                   //  If it will fit into a single char, then put it in. Otherwise
                   //  fail [*encode it as a surrogate pair. If its not valid, use the
                   //  replacement char.*]
                   if(!(tmpVal & 0xFFFF0000)) {
                           if(XMLByte xlat=xlatOneTo(tmpVal, tables, 0))
                                   *outPtr++=xlat;
                           else {
                                   if(tmpVal & 0xFFFFFF00)
                                           goto fail;
                                   outPtr+=sprintf((char *)outPtr, "&#%d;", tmpVal); // &#decimal;
                           }
                   } else {
   fail:
                           const XMLByte* recoverPtr=srcPtr-trailingBytes-1;
                           for(uint i=0; i<=trailingBytes; i++)
                                   outPtr+=sprintf((char*)outPtr, "%%%02X", *recoverPtr++);
                   }
         }          }
           
           // Update the bytes eaten
           srcLen = srcPtr - srcData;
           
           // Return the characters read
           toFillLen = outPtr - toFill;
   
         // return          //return srcPtr==srcEnd?(int)toFillLen:-1;
         adest_body=dest_body;  /*
         adest_content_length=outPtr-dest_body;  xmlCharEncodingOutputFunc
   Returns :
   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
   of ocetes consumed.
   */
           return 0;
 }  }
   
 /// transcode using both charsets  /// @todo not so memory-hungry with prescan
 void Charset::transcodeToCharset(Pool& pool,  const String::C Charset::transcodeToUTF8(const String::C src) const {
                                                                            const Charset& dest_charset,          size_t src_length=src.length;
                                                                            const void *source_body, size_t source_content_length,          size_t dest_length=src.length*6/*so that surly enough, max utf8 seq len=6*/;
                                                                            const void *& adest_body, size_t& adest_content_length) const {  #ifndef NDEBUG
         if(&dest_charset==this) {          size_t saved_dest_length=dest_length;
                 adest_body=source_body;  #endif
                 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;  
                 unsigned char *dest_body=(unsigned char *)pool.malloc(dest_content_length);  
   
                 const XMLByte* srcPtr=(const XMLByte*)source_body;          if(::transcodeToUTF8(
                 const XMLByte* srcEnd=(const XMLByte*)source_body+source_content_length;                  (XMLByte *)src.str, src_length,
                   dest_body, dest_length,
                   tables)<0)
                   throw Exception(0,
                           0,
                           "Charset::transcodeToUTF8 buffer overflow");
   
           assert(dest_length<=saved_dest_length); dest_body[dest_length]=0; // terminator
           return String::C((char*)dest_body, dest_length);
   }
   
   static XMLCh change_case_UTF8(const XMLCh src, const Charset::UTF8CaseTable& table) {
           int    lo = 0;
           int    hi = table.size - 1;
           while(lo<=hi) {
                   // Calc the mid point of the low and high offset.
                   const unsigned int i = (lo + hi) / 2;
   
                   XMLCh cur=table.records[i].from;
                   if(src==cur)
                           return table.records[i].to;
                   if(src>cur)
                           lo = i+1;
                   else
                           hi = i-1;
           }
   
                 for(XMLByte* outPtr=dest_body; srcPtr<srcEnd; srcPtr++) {          // not found
                         XMLCh curVal = fromTable[*srcPtr];          return src;
                         if(curVal)   }
                                 *outPtr++=dest_charset.xlatOneTo(curVal);  
                         else {  static void store_UTF8(XMLCh src, XMLByte*& outPtr ) {
                                 // use the replacement character          if(!src) {
                                 *outPtr++= '?';                  // use the replacement character
                         }                         *outPtr++= '?';
                   return;
           }
   
           // Figure out how many bytes we need
           unsigned int encodedBytes;
           if(src<0x80)
                   encodedBytes = 1;
           else if(src<0x800)
                   encodedBytes = 2;
           else if(src<0x10000)
                   encodedBytes = 3;
           else if(src<0x200000)
                   encodedBytes = 4;
           else if(src<0x4000000)
                   encodedBytes = 5;
           else if(src<= 0x7FFFFFFF)
                   encodedBytes = 6;
           else {
                   // use the replacement character
                   *outPtr++= '?';
                   return;
           }
   
           //  And spit out the bytes. We spit them out in reverse order
           //  here, so bump up the output pointer and work down as we go.
           outPtr+= encodedBytes;
           switch(encodedBytes) {
           case 6: *--outPtr = XMLByte((src | 0x80UL) & 0xBFUL);
                   src>>= 6;
           case 5: *--outPtr = XMLByte((src | 0x80UL) & 0xBFUL);
                   src>>= 6;
           case 4: *--outPtr = XMLByte((src | 0x80UL) & 0xBFUL);
                   src>>= 6;
           case 3: *--outPtr = XMLByte((src | 0x80UL) & 0xBFUL);
                   src>>= 6;
           case 2: *--outPtr = XMLByte((src | 0x80UL) & 0xBFUL);
                   src>>= 6;
           case 1: *--outPtr = XMLByte(src | gFirstByteMark[encodedBytes]);
           }
           
           // Add the encoded bytes back in again to indicate we've eaten them
           outPtr+= encodedBytes;
   }
   
   static void change_case_UTF8(XMLCh src, XMLByte*& outPtr, 
                                                   const Charset::UTF8CaseTable& table) {
           store_UTF8(change_case_UTF8(src, table), outPtr);
   };
   void change_case_UTF8(const XMLByte* srcData, size_t srcLen,
                                             XMLByte* toFill, size_t toFillLen,
                                             const Charset::UTF8CaseTable& table) {
           const XMLByte* srcPtr=srcData;
           const XMLByte* srcEnd=srcData+srcLen;
           XMLByte* outPtr=toFill;
           XMLByte* outEnd=toFill+toFillLen;
   
           //  We now loop until we either run out of input data, or room to store
           while ((srcPtr < srcEnd) && (outPtr < outEnd)) {
                   // Get the next leading byte out
                   const XMLByte firstByte =* srcPtr;
   
                   if(firstByte<= 127) {
                           change_case_UTF8(firstByte, outPtr, table);
                           srcPtr++;
                           continue;
                   }
                   
                   // See how many trailing src bytes this sequence is going to require
                   const unsigned int trailingBytes = gUTFBytes[firstByte];
                   
                   // Looks ok, so lets build up the value
                   uint tmpVal=0;
                   switch(trailingBytes) {
                   case 5: tmpVal+=*srcPtr++; tmpVal<<=6;
                   case 4: tmpVal+=*srcPtr++; tmpVal<<=6;
                   case 3: tmpVal+=*srcPtr++; tmpVal<<=6;
                   case 2: tmpVal+=*srcPtr++; tmpVal<<=6;
                   case 1: tmpVal+=*srcPtr++; tmpVal<<=6;
                   case 0: tmpVal+=*srcPtr++;
                           break;
                           
                   default:
                           throw Exception(0,
                                   0,
                                   "change_case_UTF8 error: wrong trailingBytes value(%d)", trailingBytes);
                 }                  }
                   tmpVal-=gUTFOffsets[trailingBytes];
                   
                   //  If it will fit into a single char, then put it in. Otherwise
                   //  fail [*encode it as a surrogate pair. If its not valid, use the
                   //  replacement char.*]
                   if(!(tmpVal & 0xFFFF0000))
                           change_case_UTF8(tmpVal, outPtr, table);
                   else
                           throw Exception(0,
                                   0,
                                   "change_case_UTF8 error: too big tmpVal(0x%08X)", tmpVal);
           }
           
           if(srcPtr!=outPtr)
                   throw Exception(0,  
                           0,
                           "change_case_UTF8 error: end pointers do not match");
   }
   
   
   const String::C Charset::transcodeFromUTF8(const String::C src) const {
           size_t src_length=src.length;
           size_t dest_length=src.length*6/*so that surly enough, "&#255;" has max ratio */;
   #ifndef NDEBUG
           size_t saved_dest_length=dest_length;
   #endif
           XMLByte *dest_body=new(PointerFreeGC) XMLByte[dest_length+1/*for terminator*/];
   
                 adest_body=dest_body;          if(::transcodeFromUTF8(
                 adest_content_length=dest_content_length;                  (XMLByte *)src.str, src_length,
                   dest_body, dest_length,
                   tables)<0)
                   throw Exception(0, 
                           0,
                           "Charset::transcodeFromUTF8 buffer overflow");
   
           assert(dest_length<=saved_dest_length); dest_body[dest_length]=0; // terminator
           return String::C((char*)dest_body, dest_length);
   }
   
   /// transcode using both charsets
   const String::C Charset::transcodeToCharset(const String::C src, 
                                               const Charset& dest_charset) const {
           if(&dest_charset==this) 
                   return src;
           else {
                   size_t dest_length=src.length;
                   XMLByte* dest_body=new(PointerFreeGC) XMLByte[dest_length+1/*for terminator*/];
   
                   XMLByte* output=dest_body;
                   const XMLByte* input=(XMLByte *)src.str;
                   while(XMLCh c=*input++) {
                           XMLCh curVal = tables.fromTable[c];
                           *output++=curVal?
                                   xlatOneTo(curVal, dest_charset.tables, '?') // OK
                                   :'?'; // use the replacement character
                   }
   
                   dest_body[dest_length]=0; // terminator
                   return String::C((char*)dest_body, dest_length);
         }          }
 }                         }                       
   
 #ifdef XML  #ifdef XML
 const char *Charset::transcode_cstr(const XalanDOMString& s) {   
         const unsigned int len=s.size()*2;  static const Charset::Tables* tables[MAX_CHARSETS];
         XMLByte* dest=(XMLByte *)malloc((len+1)*sizeof(XMLByte));  
         bool error=true;  #ifdef PA_PATCHED_LIBXML_BACKWARD
         try {  
                 if(transcoder) {  #define declareXml256ioFuncs(i) \
                         unsigned int charsEaten;          static int xml256CharEncodingInputFunc##i( \
                         unsigned int size=transcoder->transcodeTo(                  unsigned char *out, int *outlen, \
                                 s.c_str(), s.length(),                  const unsigned char *in, int *inlen, void*) { \
                                 dest, len,                  return transcodeToUTF8( \
                                 charsEaten,                          in, *(size_t*)inlen, \
                                 XMLTranscoder::UnRep_RepChar //UnRep_Throw                          out, *(size_t*)outlen, \
                         );                          *tables[i]); \
                         dest[size]=0;          } \
                         error=false;          static int xml256CharEncodingOutputFunc##i( \
                 }                  unsigned char *out, int *outlen, \
         } catch(XMLException& e) {                  const unsigned char *in, int *inlen, void*) { \
                 Exception::provide_source(pool(), 0, e);                  return transcodeFromUTF8( \
                           in, *(size_t*)inlen, \
                           out, *(size_t*)outlen, \
                           *tables[i]); \
           }
   
   #else
   
   #define declareXml256ioFuncs(i) \
           static int xml256CharEncodingInputFunc##i( \
                   unsigned char *out, int *outlen, \
                   const unsigned char *in, int *inlen) { \
                   return transcodeToUTF8( \
                           in, *(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]); \
           }
   
   #endif
   
   
   declareXml256ioFuncs(0) declareXml256ioFuncs(1)
   declareXml256ioFuncs(2) declareXml256ioFuncs(3)
   declareXml256ioFuncs(4) declareXml256ioFuncs(5)
   declareXml256ioFuncs(6) declareXml256ioFuncs(7)
   declareXml256ioFuncs(8) declareXml256ioFuncs(9)
   
   static xmlCharEncodingInputFunc inputFuncs[MAX_CHARSETS]={
           xml256CharEncodingInputFunc0,   xml256CharEncodingInputFunc1,
           xml256CharEncodingInputFunc2,   xml256CharEncodingInputFunc3,
           xml256CharEncodingInputFunc4,   xml256CharEncodingInputFunc5,
           xml256CharEncodingInputFunc6,   xml256CharEncodingInputFunc7,
           xml256CharEncodingInputFunc8,   xml256CharEncodingInputFunc9
   };
   static xmlCharEncodingOutputFunc outputFuncs[MAX_CHARSETS]={
           xml256CharEncodingOutputFunc0,  xml256CharEncodingOutputFunc1,
           xml256CharEncodingOutputFunc2,  xml256CharEncodingOutputFunc3,
           xml256CharEncodingOutputFunc4,  xml256CharEncodingOutputFunc5,
           xml256CharEncodingOutputFunc6,  xml256CharEncodingOutputFunc7,
           xml256CharEncodingOutputFunc8,  xml256CharEncodingOutputFunc9
   };
   static size_t handlers_count=0;
   
   void Charset::addEncoding(char *name_cstr) {
           if(handlers_count==MAX_CHARSETS)
                   throw Exception(0,
                           0,
                           "already allocated %d handlers, no space for new encoding '%s'",
                                   MAX_CHARSETS, name_cstr);
   
           xmlCharEncodingHandler* handler=new(UseGC) xmlCharEncodingHandler;
           {
                   handler->name=name_cstr;
                   handler->input=inputFuncs[handlers_count]; 
                   handler->output=outputFuncs[handlers_count]; 
                   ::tables[handlers_count]=&tables;
                   handlers_count++;
         }          }
         return(const char *)dest;          
           xmlRegisterCharEncodingHandler(handler);
   
 }  }
 String& Charset::transcode(const XalanDOMString& s) {   
         return *NEW String(pool(), transcode_cstr(s));   void Charset::initTranscoder(const String::Body NAME, const char* name_cstr) {
           ftranscoder=xmlFindCharEncodingHandler(name_cstr);
           transcoder(NAME); // check right way
   }
   
   xmlCharEncodingHandler& Charset::transcoder(const String::Body NAME) {
           if(!ftranscoder)
                   throw Exception("parser.runtime",
                           new String(NAME, String::L_TAINTED),
                           "unsupported encoding");
           return *ftranscoder;
 }  }
   
 std::auto_ptr<XalanDOMString>Charset::transcode_buf(const char *buf, size_t buf_size) {   String::C Charset::transcode_cstr(xmlChar* s) {
         unsigned int dest_size=0;          if(!s)
         XMLCh* dest=(XMLCh *)malloc((buf_size+1)*sizeof(XMLCh));                  return String::C("", 0);
         unsigned char *charSizes=(unsigned char *)malloc(buf_size*sizeof(unsigned char));  
         XalanDOMString *result;          int inlen=strlen((const char*)s);
         try {          int outlen=inlen; // max
                 if(transcoder) {  #ifndef NDEBUG
                         unsigned int bytesEaten;          int saved_outlen=outlen;
                         unsigned int dest_size=transcoder->transcodeFrom(  #endif
                                 (unsigned char *)buf,          char *out=new(PointerFreeGC) char[outlen+1];
                                 (const unsigned int)buf_size,          
                                 dest,(const unsigned int)buf_size,          int error;
                                 bytesEaten,          if(xmlCharEncodingOutputFunc output=transcoder(FNAME).output) {
                                 charSizes                  error=output(
                           (unsigned char*)out, &outlen,
                           (const unsigned char*)s, &inlen
   #ifdef PA_PATCHED_LIBXML_BACKWARD
                           ,0
   #endif
                         );                          );
                         result=new XalanDOMString(dest, dest_size);          } else {
                 }                  memcpy(out, s, outlen=inlen);
         } catch(XMLException& e) {                  error=0;
                 Exception::provide_source(pool(), 0, e);          }
                 result=0; //calm, compiler          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);
   }
   
   /// @test less memory using -maybe- xmlParserInputBufferCreateMem
   xmlChar* Charset::transcode_buf2xchar(const char* buf, size_t buf_size) {
           xmlChar* out;
           int outlen;
           int error;
   #ifndef NDEBUG
           int saved_outlen;
   #endif
           if(xmlCharEncodingInputFunc input=transcoder(FNAME).input) {
                   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
   #ifdef PA_PATCHED_LIBXML_BACKWARD
                           ,0
   #endif
                           );
           } else {
                   outlen=buf_size;
   #ifndef NDEBUG
                   saved_outlen=outlen;
   #endif
                   out=(xmlChar*)xmlMalloc(outlen+1);
                   memcpy(out, buf, outlen);
                   error=0;
         }          }
                   
         return std::auto_ptr<XalanDOMString>(result);          if(error<0)
                   throw Exception(0,
                           0,
                           "transcode_buf failed (%d)", error);
   
           assert(outlen<=saved_outlen); out[outlen]=0;
           return out;
   }
   GdomeDOMString_auto_ptr Charset::transcode_buf2dom(const char* buf, size_t buf_size) { 
           return GdomeDOMString_auto_ptr(transcode_buf2xchar(buf, buf_size));
   }
   GdomeDOMString_auto_ptr Charset::transcode(const String& s) { 
           const char* cstr=s.cstr(String::L_UNSPECIFIED);
   
           return transcode_buf2dom(cstr, strlen(cstr)); 
   }
   GdomeDOMString_auto_ptr Charset::transcode(const String::Body s) { 
           const char* cstr=s.cstr();
   
           return transcode_buf2dom(cstr, s.length()); 
   }
   #endif
   
   String::Body Charset::transcode(const String::Body src, 
           const Charset& source_transcoder, 
           const Charset& dest_transcoder) {
   
           const char *src_ptr=src.cstr();
           size_t src_size=strlen(src_ptr);
   
           String::C dest=Charset::transcode(String::C(src_ptr, src_size),
                   source_transcoder,
                   dest_transcoder);
   
           return String::Body(dest.str, dest.length);
 }  }
 std::auto_ptr<XalanDOMString>Charset::transcode(const String& s) {   
         const char *cstr=s.cstr(String::UL_UNSPECIFIED);  
   
         return transcode_buf(cstr, strlen(cstr));   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);
 }  }
   
   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.6  
changed lines
  Added in v.1.49


E-mail: