Diff for /parser3/src/main/pa_common.C between versions 1.229 and 1.254

version 1.229, 2008/05/22 17:29:30 version 1.254, 2009/10/06 00:49:28
Line 1 Line 1
 /** @file  /** @file
         Parser: commonly functions.          Parser: commonly functions.
   
         Copyright(c) 2001-2005 ArtLebedev Group (http://www.artlebedev.com)          Copyright(c) 2001-2009 ArtLebedev Group (http://www.artlebedev.com)
         Author: Alexandr Petrosian <paf@design.ru> (http://paf.design.ru)          Author: Alexandr Petrosian <paf@design.ru> (http://paf.design.ru)
   
  * BASE64 part   * BASE64 part
Line 35  static const char * const IDENT_COMMON_C Line 35  static const char * const IDENT_COMMON_C
 #include "pa_charsets.h"  #include "pa_charsets.h"
 #include "pa_http.h"  #include "pa_http.h"
 #include "pa_request_charsets.h"  #include "pa_request_charsets.h"
   #include "pcre.h"
   #include "pa_request.h"
   
 // some maybe-undefined constants  // some maybe-undefined constants
   
Line 65  const String file_status_name(FILE_STATU Line 67  const String file_status_name(FILE_STATU
   
 // functions  // functions
   
   const char* capitalize(const char* s){
           char* result=pa_strdup(s);
           if(result){
                   bool upper=true;
                   for(char* c=result; *c; c++){
                           *c=upper ? (char)toupper((unsigned char)*c) : (char)tolower((unsigned char)*c);
                           upper=strchr("-_ ", *c) != 0;
                   }
           }
           return (const char*)result;
   }
   
 void fix_line_breaks(char *str, size_t& length) {  void fix_line_breaks(char *str, size_t& length) {
         //_asm int 3;          //_asm int 3;
         const char* const eob=str+length;          const char* const eob=str+length;
Line 94  void fix_line_breaks(char *str, size_t& Line 108  void fix_line_breaks(char *str, size_t&
 char* file_read_text(Request_charsets& charsets,   char* file_read_text(Request_charsets& charsets, 
                         const String& file_spec,                           const String& file_spec, 
                         bool fail_on_read_problem,                          bool fail_on_read_problem,
                         HashStringValue* params/*, HashStringValue* * out_fields*/) {                          HashStringValue* params,
                           bool transcode_result) {
         File_read_result file=          File_read_result file=
                 file_read(charsets, file_spec, true, params, fail_on_read_problem);                  file_read(charsets, file_spec, true, params, fail_on_read_problem, 0, 0, 0, transcode_result);
           return file.success?file.str:0;
   }
   
   char* file_load_text(Request& r, 
                           const String& file_spec, 
                           bool fail_on_read_problem,
                           HashStringValue* params,
                           bool transcode_result) {
           File_read_result file=
                   file_load(r, file_spec, true, params, fail_on_read_problem, 0, 0, 0, transcode_result);
         return file.success?file.str:0;          return file.success?file.str:0;
 }  }
   
 /// these options were handled but not checked elsewhere, now check them  /// these options were handled but not checked elsewhere, now check them
 int pa_get_valid_file_options_count(HashStringValue& options)  int pa_get_valid_file_options_count(HashStringValue& options) {
 {  
         int result=0;          int result=0;
         if(options.get(PA_SQL_LIMIT_NAME))          if(options.get(PA_SQL_LIMIT_NAME))
                 result++;                  result++;
Line 138  static void file_read_action( Line 162  static void file_read_action(
                         lseek(f, info.offset, SEEK_SET);                          lseek(f, info.offset, SEEK_SET);
                 *info.data=info.buf                  *info.data=info.buf
                         ? info.buf                          ? info.buf
                         : new(PointerFreeGC) char[to_read_size+(as_text?1:0)];                           : (char *)pa_malloc_atomic(to_read_size+1);
                 *info.data_size=(size_t)read(f, *info.data, to_read_size);                   *info.data_size=(size_t)read(f, *info.data, to_read_size); 
   
                 if(ssize_t(*info.data_size)<0 || *info.data_size>to_read_size)                  if(ssize_t(*info.data_size)<0 || *info.data_size>to_read_size)
                         throw Exception(0,                           throw Exception("file.read", 
                                 &file_spec,                                   &file_spec, 
                                 "read failed: actually read %u bytes count not in [0..%u] valid range",                                   "read failed: actually read %u bytes count not in [0..%u] valid range", 
                                         *info.data_size, to_read_size);                                           *info.data_size, to_read_size); 
         } else { // empty file          } else { // empty file
                 // for both, text and binary: for text we need that terminator, for binary we need nonzero pointer to be able to save such files                  // for both, text and binary: for text we need that terminator, for binary we need nonzero pointer to be able to save such files
                 *info.data=new(PointerFreeGC) char[1];                   *info.data=(char *)pa_malloc_atomic(1);
                 *(char*)(*info.data)=0;                  *(char*)(*info.data)=0;
                 *info.data_size=0;                  *info.data_size=0;
                 return;                  return;
         }          }
 }  }
   
 File_read_result file_read(Request_charsets& charsets, const String& file_spec,   File_read_result file_read(Request_charsets& charsets, const String& file_spec, 
                         bool as_text, HashStringValue *params,                          bool as_text, HashStringValue *params,
                         bool fail_on_read_problem,                          bool fail_on_read_problem,
                         char* buf, size_t offset, size_t count) {                          char* buf, size_t offset, size_t count, bool transcode_text_result) {
           File_read_result result={false, 0, 0, 0};
           if(params){
                   int valid_options=pa_get_valid_file_options_count(*params);
                   if(valid_options!=params->count())
                           throw Exception(PARSER_RUNTIME,
                                   0,
                                   INVALID_OPTION_PASSED);
           }
   
           File_read_action_info info={&result.str, &result.length, buf, offset, count}; 
   
           result.success=file_read_action_under_lock(file_spec, 
                   "read", file_read_action, &info, 
                   as_text, fail_on_read_problem); 
   
           if(as_text){
                   if(result.success){
                           if(result.length>=3 && strncmp(result.str, "\xEF\xBB\xBF", 3)==0){
                                   // skip UTF-8 signature (BOM code)
                                   result.str+=3;
                                   result.length-=3;
                           }
                           
                           if(result.length && transcode_text_result && params){ // must be checked because transcode returns CONST string in case length==0, which contradicts hacking few lines below
                                   if(Value* vcharset_name=params->get(PA_CHARSET_NAME)){
                                           Charset asked_charset=::charsets.get(vcharset_name->as_string().
                                                   change_case(charsets.source(), String::CC_UPPER));
   
                                           String::C body=String::C(result.str, result.length);
                                           body=Charset::transcode(body, asked_charset, charsets.source());
   
                                           result.str=const_cast<char*>(body.str); // hacking a little
                                           result.length=body.length;
                                   }
                           }
                   }
                   if(result.length)
                           fix_line_breaks(result.str, result.length);
           }
   
           return result;
   }
   
   File_read_result file_load(Request& r, const String& file_spec, 
                           bool as_text, HashStringValue *params,
                           bool fail_on_read_problem,
                           char* buf, size_t offset, size_t count, bool transcode_text_result) {
   
         File_read_result result={false, 0, 0, 0};          File_read_result result={false, 0, 0, 0};
         if(file_spec.starts_with("http://")) {          if(file_spec.starts_with("http://")) {
                 if(offset || count)                  if(offset || count)
Line 166  File_read_result file_read(Request_chars Line 239  File_read_result file_read(Request_chars
                                 "offset and load options are not supported for HTTP:// file load");                                  "offset and load options are not supported for HTTP:// file load");
   
                 // fail on read problem                  // fail on read problem
                 File_read_http_result http=pa_internal_file_read_http(charsets, file_spec, as_text, params);                  File_read_http_result http=pa_internal_file_read_http(r, file_spec, as_text, params, transcode_text_result);
                 result.success=true;                  result.success=true;
                 result.str=http.str;                  result.str=http.str;
                 result.length=http.length;                  result.length=http.length;
                 result.headers=http.headers;                   result.headers=http.headers; 
         } else {          } else
                 if(params) {                  result=
                         int valid_options=pa_get_valid_file_options_count(*params);                          file_read(r.charsets, file_spec, as_text, params, fail_on_read_problem, buf, offset, count, transcode_text_result);
                         if(valid_options!=params->count())  
                                 throw Exception(PARSER_RUNTIME,  
                                         0,  
                                         "invalid option passed");  
                 }  
   
                 File_read_action_info info={&result.str, &result.length,  
                         buf, offset, count};   
                 result.success=file_read_action_under_lock(file_spec,   
                         "read", file_read_action, &info,   
                         as_text, fail_on_read_problem);   
   
                 if(result.length && as_text && params) {  
                         if( Value* vcharset_name=params->get(PA_CHARSET_NAME) ) {  
                                 Charset asked_charset=::charsets.get(vcharset_name->as_string().  
                                         change_case(charsets.source(), String::CC_UPPER));  
   
                                 String::C body=String::C(result.str, result.length);  
                                 body=Charset::transcode(body, asked_charset, charsets.source());  
   
                                 result.str=const_cast<char *>(body.str); // hacking a little  
                                 result.length=body.length;  
                         }   
                 }  
         }  
   
         if(result.success && as_text) {  
                 // UTF-8 signature: EF BB BF  
                 if(result.length>=3) {  
                         char *in=(char *)result.str;  
                         if(strncmp(in, "\xEF\xBB\xBF", 3)==0) {  
                                 result.str=in+3; result.length-=3;// skip prefix  
                         }  
                 }  
   
                 fix_line_breaks((char *)(result.str), result.length);   
         }  
   
         return result;          return result;
 }  }
Line 236  bool file_read_action_under_lock(const S Line 272  bool file_read_action_under_lock(const S
                                 const char* action_name, File_read_action action, void *context,                                   const char* action_name, File_read_action action, void *context, 
                                 bool as_text,                                   bool as_text, 
                                 bool fail_on_read_problem) {                                  bool fail_on_read_problem) {
         const char* fname=file_spec.cstr(String::L_FILE_SPEC);           const char* fname=file_spec.taint_cstr(String::L_FILE_SPEC); 
         int f;          int f;
   
         // first open, next stat:          // first open, next stat:
Line 257  bool file_read_action_under_lock(const S Line 293  bool file_read_action_under_lock(const S
                                                         strerror(errno), errno, fname);                                                          strerror(errno), errno, fname);
   
                         struct stat finfo;                          struct stat finfo;
                         if(stat(fname, &finfo)!=0)                          if(fstat(f, &finfo)!=0)
                                 throw Exception("file.missing", // hardly possible: we just opened it OK                                  throw Exception("file.missing", // hardly possible: we just opened it OK
                                         &file_spec,                                           &file_spec, 
                                         "stat failed: %s (%d), actual filename '%s'",                                           "stat failed: %s (%d), actual filename '%s'", 
Line 291  void create_dir_for_file(const String& f Line 327  void create_dir_for_file(const String& f
         size_t pos_after=1;          size_t pos_after=1;
         size_t pos_before;          size_t pos_before;
         while((pos_before=file_spec.pos('/', pos_after))!=STRING_NOT_FOUND) {          while((pos_before=file_spec.pos('/', pos_after))!=STRING_NOT_FOUND) {
                 mkdir(file_spec.mid(0, pos_before).cstr(String::L_FILE_SPEC), 0775);                   mkdir(file_spec.mid(0, pos_before).taint_cstr(String::L_FILE_SPEC), 0775); 
                 pos_after=pos_before+1;                  pos_after=pos_before+1;
         }          }
 }  }
Line 305  bool file_write_action_under_lock( Line 341  bool file_write_action_under_lock(
                                 bool do_append,                                   bool do_append, 
                                 bool do_block,                                   bool do_block, 
                                 bool fail_on_lock_problem) {                                  bool fail_on_lock_problem) {
         const char* fname=file_spec.cstr(String::L_FILE_SPEC);           const char* fname=file_spec.taint_cstr(String::L_FILE_SPEC); 
         int f;          int f;
         if(access(fname, W_OK)!=0) // no          if(access(fname, W_OK)!=0) // no
                 create_dir_for_file(file_spec);                   create_dir_for_file(file_spec); 
Line 326  bool file_write_action_under_lock( Line 362  bool file_write_action_under_lock(
                 }                  }
   
                 try {                  try {
                         action(f, context);   #if (defined(HAVE_FCHMOD) && defined(PA_SAFE_MODE))
                           struct stat finfo;
                           if(fstat(f, &finfo)==0 && finfo.st_mode & 0111)
                                   fchmod(f, finfo.st_mode & 0666/*clear executable bits*/); // backward: ignore errors if any
   #endif
                           action(f, context);
                 } catch(...) {                  } catch(...) {
 #ifdef HAVE_FTRUNCATE  #ifdef HAVE_FTRUNCATE
                         if(!do_append)                          if(!do_append)
Line 352  bool file_write_action_under_lock( Line 393  bool file_write_action_under_lock(
   
 #ifndef DOXYGEN  #ifndef DOXYGEN
 struct File_write_action_info {  struct File_write_action_info {
         const char* str; size_t length;          const char* str;
           size_t length;
 };   }; 
 #endif  #endif
 static void file_write_action(int f, void *context) {  static void file_write_action(int f, void *context) {
Line 360  static void file_write_action(int f, voi Line 402  static void file_write_action(int f, voi
         if(info.length) {          if(info.length) {
                 int written=write(f, info.str, info.length);                   int written=write(f, info.str, info.length); 
                 if(written<0)                  if(written<0)
                         throw Exception(0,                           throw Exception("file.access", 
                                 0,                                   0, 
                                 "write failed: %s (%d)",  strerror(errno), errno);                                   "write failed: %s (%d)",  strerror(errno), errno); 
         }          }
 }  }
 void file_write(  void file_write(
                                 const String& file_spec,                                   Request_charsets& charsets,
                                 const char* data, size_t size,                                   const String& file_spec,
                                   const char* data,
                                   size_t size, 
                                 bool as_text,                                   bool as_text, 
                                 bool do_append) {                                  bool do_append,
                                   Charset* asked_charset) {
   
           if(as_text && asked_charset){
                   String::C body=String::C(data, size);
                   body=Charset::transcode(body, charsets.source(), *asked_charset);
                   data=body.str;
                   size=body.length;
           };
   
         File_write_action_info info={data, size};           File_write_action_info info={data, size}; 
   
         file_write_action_under_lock(          file_write_action_under_lock(
Line 387  static void rmdir(const String& file_spe Line 440  static void rmdir(const String& file_spe
         if((pos_before=file_spec.pos('/', pos_after))!=STRING_NOT_FOUND)          if((pos_before=file_spec.pos('/', pos_after))!=STRING_NOT_FOUND)
                 rmdir(file_spec, pos_before+1);                   rmdir(file_spec, pos_before+1); 
                   
         rmdir(file_spec.mid(0, pos_after-1/* / */).cstr(String::L_FILE_SPEC));           rmdir(file_spec.mid(0, pos_after-1/* / */).taint_cstr(String::L_FILE_SPEC)); 
 }  }
   
 bool file_delete(const String& file_spec, bool fail_on_problem) {  bool file_delete(const String& file_spec, bool fail_on_problem) {
         const char* fname=file_spec.cstr(String::L_FILE_SPEC);           const char* fname=file_spec.taint_cstr(String::L_FILE_SPEC); 
         if(unlink(fname)!=0)          if(unlink(fname)!=0)
                 if(fail_on_problem)                  if(fail_on_problem)
                         throw Exception(errno==EACCES?"file.access":errno==ENOENT?"file.missing":0,                           throw Exception(errno==EACCES?"file.access":errno==ENOENT?"file.missing":0, 
Line 403  bool file_delete(const String& file_spec Line 457  bool file_delete(const String& file_spec
         rmdir(file_spec, 1);           rmdir(file_spec, 1); 
         return true;          return true;
 }  }
   
 void file_move(const String& old_spec, const String& new_spec) {  void file_move(const String& old_spec, const String& new_spec) {
         const char* old_spec_cstr=old_spec.cstr(String::L_FILE_SPEC);           const char* old_spec_cstr=old_spec.taint_cstr(String::L_FILE_SPEC); 
         const char* new_spec_cstr=new_spec.cstr(String::L_FILE_SPEC);           const char* new_spec_cstr=new_spec.taint_cstr(String::L_FILE_SPEC); 
                   
         create_dir_for_file(new_spec);           create_dir_for_file(new_spec); 
   
Line 428  bool entry_exists(const char* fname, str Line 483  bool entry_exists(const char* fname, str
 }  }
   
 bool entry_exists(const String& file_spec) {  bool entry_exists(const String& file_spec) {
         const char* fname=file_spec.cstr(String::L_FILE_SPEC);           const char* fname=file_spec.taint_cstr(String::L_FILE_SPEC); 
         return entry_exists(fname, 0);           return entry_exists(fname, 0); 
 }  }
   
 static bool entry_readable(const String& file_spec, bool need_dir) {  static bool entry_readable(const String& file_spec, bool need_dir) {
         char* fname=file_spec.cstrm(String::L_FILE_SPEC);           char* fname=file_spec.taint_cstrm(String::L_FILE_SPEC); 
         if(need_dir) {          if(need_dir) {
                 size_t size=strlen(fname);                   size_t size=strlen(fname); 
                 while(size) {                  while(size) {
Line 451  static bool entry_readable(const String& Line 506  static bool entry_readable(const String&
         }          }
         return false;          return false;
 }  }
   
 bool file_exist(const String& file_spec) {  bool file_exist(const String& file_spec) {
         return entry_readable(file_spec, false);           return entry_readable(file_spec, false); 
 }  }
   
 bool dir_exists(const String& file_spec) {  bool dir_exists(const String& file_spec) {
         return entry_readable(file_spec, true);           return entry_readable(file_spec, true); 
 }  }
   
 const String* file_exist(const String& path, const String& name) {  const String* file_exist(const String& path, const String& name) {
         String& result=*new String(path);          String& result=*new String(path);
         result << "/";           result << "/"; 
         result << name;          result << name;
         return file_exist(result)?&result:0;          return file_exist(result)?&result:0;
 }  }
   
 bool file_executable(const String& file_spec) {  bool file_executable(const String& file_spec) {
     return access(file_spec.cstr(String::L_FILE_SPEC), X_OK)==0;          return access(file_spec.taint_cstr(String::L_FILE_SPEC), X_OK)==0;
 }  }
   
 bool file_stat(const String& file_spec,   bool file_stat(const String& file_spec, 
Line 473  bool file_stat(const String& file_spec, Line 532  bool file_stat(const String& file_spec,
                         time_t& rmtime,                          time_t& rmtime,
                         time_t& rctime,                          time_t& rctime,
                         bool fail_on_read_problem) {                          bool fail_on_read_problem) {
         const char* fname=file_spec.cstr(String::L_FILE_SPEC);           const char* fname=file_spec.taint_cstr(String::L_FILE_SPEC); 
         struct stat finfo;          struct stat finfo;
         if(stat(fname, &finfo)!=0)          if(stat(fname, &finfo)!=0)
                 if(fail_on_read_problem)                  if(fail_on_read_problem)
Line 598  FormatType format_type(char* fmt){ Line 657  FormatType format_type(char* fmt){
   
 const char* format(double value, char* fmt) {  const char* format(double value, char* fmt) {
         char local_buf[MAX_NUMBER];          char local_buf[MAX_NUMBER];
         size_t size;          int size=-1;
   
         if(fmt && strlen(fmt)){          if(fmt && strlen(fmt)){
                 switch(format_type(fmt)){                  switch(format_type(fmt)){
Line 625  const char* format(double value, char* f Line 684  const char* format(double value, char* f
                         "Error occure white executing snprintf with format string '%s'.", fmt);                          "Error occure white executing snprintf with format string '%s'.", fmt);
         }          }
   
         return pa_strdup(local_buf, size);          return pa_strdup(local_buf, (size_t)size);
 }  }
   
 size_t stdout_write(const void *buf, size_t size) {  size_t stdout_write(const void *buf, size_t size) {
Line 651  enum EscapeState { Line 710  enum EscapeState {
         EscapeSecond,          EscapeSecond,
         EscapeUnicode          EscapeUnicode
 };  };
 /*  
 char* unescape_chars(const char* cp, int len) {  
         char* s=new(PointerFreeGC) char[len + 1];   
         EscapeState escapeState=EscapeRest;  
         uint escapedValue=0;  
         int srcPos=0;  
         int dstPos=0;  
         while(srcPos < len) {  
                 uchar ch=(uchar)cp[srcPos];   
                 switch(escapeState) {  
                         case EscapeRest:  
                                 if(ch=='%') {  
                                         escapeState=EscapeFirst;  
                                 } else if(ch=='+'){  
                                         s[dstPos++]=' ';   
                                 } else {  
                                         s[dstPos++]=ch;   
                                 }  
                                 break;  
                         case EscapeFirst:  
                                 escapedValue=hex_value[ch] << 4;  
                                 escapeState=EscapeSecond;  
                                 break;  
                         case EscapeSecond:  
                                 escapedValue +=hex_value[ch];   
                                 s[dstPos++]=(char)escapedValue;  
                                 escapeState=EscapeRest;  
                                 break;  
                 }  
                 srcPos++;   
         }  
         s[dstPos]=0;  
         return s;  
 }  
 */  
   
 bool is_hex_digit(char c){  
         return (c>='0' && c<='9') || (c>='a' && c<='f') || (c>='A' && c<='F');  
 }  
   
 char* unescape_chars(const char* cp, int len, Request_charsets* charsets){  // @todo prescan for reduce required size (unescaped sting in 1 byte charset requires less memory usually)
         char* s=new(PointerFreeGC) char[len + 1];  char* unescape_chars(const char* cp, int len, Charset* charset, bool ignore_plus){
           char* s=new(PointerFreeGC) char[len+1]; // must be enough (%uXXXX==6 bytes, max utf-8 char length==6 bytes)
           char* dst=s;
         EscapeState escapeState=EscapeRest;          EscapeState escapeState=EscapeRest;
         uint escapedValue=0;          uint escapedValue=0;
         int srcPos=0;          int srcPos=0;
         int dstPos=0;          short int jsCnt=0;
         int jsCnt=0;          while(srcPos<len){
         while(srcPos < len) {  
                 uchar c=(uchar)cp[srcPos];                   uchar c=(uchar)cp[srcPos]; 
                 if(c=='%'){                  if(c=='%'){
                         escapeState=EscapeFirst;                          escapeState=EscapeFirst;
                 } else {                  } else {
                         switch(escapeState) {                          switch(escapeState) {
                                 case EscapeRest:                                  case EscapeRest:
                                         if(c=='+'){                                          if(!ignore_plus && c=='+'){
                                                 s[dstPos++]=' ';                                                  *dst++=' ';
                                         } else {                                          } else {
                                                 s[dstPos++]=c;                                                  *dst++=c;
                                         }                                          }
                                         break;                                          break;
                                 case EscapeFirst:                                  case EscapeFirst:
                                         if(charsets && c=='u'){                                          if(charset && c=='u'){
                                                 // escaped unicode value: %u0430                                                  // escaped unicode value: %u0430
                                                 jsCnt=0;                                                  jsCnt=0;
                                                 escapedValue=0;                                                  escapedValue=0;
                                                 escapeState=EscapeUnicode;                                                  escapeState=EscapeUnicode;
                                         } else {                                          } else {
                                                 if(is_hex_digit(c)){                                                  if(isxdigit(c)){
                                                         escapedValue=hex_value[c] << 4;                                                          escapedValue=hex_value[c] << 4;
                                                         escapeState=EscapeSecond;                                                          escapeState=EscapeSecond;
                                                 } else {                                                  } else {
                                                         s[dstPos++]=c;                                                          *dst++=c;
                                                         escapeState=EscapeRest;                                                          escapeState=EscapeRest;
                                                 }                                                  }
                                         }                                          }
                                         break;                                          break;
                                 case EscapeSecond:                                  case EscapeSecond:
                                         if(is_hex_digit(c)){                                          if(isxdigit(c)){
                                                 escapedValue+=hex_value[c];                                                   escapedValue+=hex_value[c]; 
                                                 s[dstPos++]=(char)escapedValue;                                                  *dst++=(char)escapedValue;
                                         }                                          }
                                         escapeState=EscapeRest;                                          escapeState=EscapeRest;
                                         break;                                          break;
                                 case EscapeUnicode:                                  case EscapeUnicode:
                                         if(is_hex_digit(c)){                                          if(isxdigit(c)){
                                                 escapedValue=(escapedValue << 4) + hex_value[c];                                                  escapedValue=(escapedValue << 4) + hex_value[c];
                                                 if(++jsCnt==4){                                                  if(++jsCnt==4){
                                                         // transcode utf8 char to source charset (we can lost some chars here)                                                          // transcode utf8 char to client charset (we can lost some chars here)
                                                         if(char ch=charsets->source().transcodeCharFromUTF8(escapedValue, '?')){                                                          charset->store_Char((XMLByte*&)dst, (XMLCh)escapedValue, '?');
                                                                 s[dstPos++]=ch;  
                                                         }  
                                                         escapeState=EscapeRest;                                                          escapeState=EscapeRest;
                                                 }                                                  }
                                         } else {                                          } else {
Line 755  char* unescape_chars(const char* cp, int Line 774  char* unescape_chars(const char* cp, int
                 srcPos++;                  srcPos++;
         }          }
   
         s[dstPos]=0; // zero-termination          *dst=0; // zero-termination
         return s;          return s;
 }  }
   
Line 776  void slashes_to_back_slashes(char* s) { Line 795  void slashes_to_back_slashes(char* s) {
 */  */
 #endif  #endif
   
 bool StrEqNc(const char* s1, const char* s2, bool strict) {  bool StrStartFromNC(const char* str, const char* substr, bool equal){
         while(true) {          while(true) {
                 if(!(*s1)) {                  if(!(*substr)){
                         if(!(*s2))                          if(!(*str))
                                 return true;                                  return true;
                         else                          else
                                 return !strict;                                  return !equal;
                 } else if(!(*s2))                  }
                         return !strict;                  if(!(*str))
                 if(isalpha((unsigned char)*s1)) {                          return false;
                         if(tolower((unsigned char)*s1) !=tolower((unsigned char)*s2))                  if(isalpha((unsigned char)*str)) {
                           if(tolower((unsigned char)*str)!=tolower((unsigned char)*substr))
                                 return false;                                  return false;
                 } else if((*s1) !=(*s2))                  } else if((*str) != (*substr))
                         return false;                          return false;
                 s1++;                   str++; 
                 s2++;                   substr++; 
         }          }
 }  }
   
   size_t strpos(const char *str, const char *substr) {
           const char *p = strstr(str, substr);
           return (p==0)?STRING_NOT_FOUND:p-str;
   }
   
   // content-type: xxx; charset=WE-NEED-THIS
   // content-type: xxx; charset="WE-NEED-THIS"
   // content-type: xxx; charset="WE-NEED-THIS";
   Charset* detect_charset(const char* content_type){
           if(content_type){
                   char* CONTENT_TYPE=pa_strdup(content_type);
   
                   for(char *p=CONTENT_TYPE; *p; p++)
                           *p=(char)toupper((unsigned char)*p);
   
                   if(const char* begin=strstr(CONTENT_TYPE, "CHARSET=")){
                           begin+=8; // skip "CHARSET="
                           char* end=0;
                           if(*begin && (*begin=='"' || *begin =='\'')){
                                   char quote=*begin;
                                   begin++;
                                   end=(char*)strchr(begin, quote);
                           }
                           if(!end)
                                   end=(char*)strchr(begin, ';');
   
                           if(end)
                                   *end=0; // terminator
   
                           return *begin?&charsets.get(begin):0;
                   }
           }
           return 0;
   }
   
   
 static bool isLeap(int year) {  static bool isLeap(int year) {
         return !(          return !(
                                 (year % 4) || ((year % 400) && !(year % 100))                                  (year % 4) || ((year % 400) && !(year % 100))
Line 896  int __vsnprintf(char* b, size_t s, const Line 952  int __vsnprintf(char* b, size_t s, const
   
 int __snprintf(char* b, size_t s, const char* f, ...) {  int __snprintf(char* b, size_t s, const char* f, ...) {
         va_list l;          va_list l;
     va_start(l, f);           va_start(l, f); 
     int r=__vsnprintf(b, s, f, l);           int r=__vsnprintf(b, s, f, l); 
     va_end(l);           va_end(l); 
         return r;          return r;
 }  }
   
Line 942  static char *base64_alphabet = Line 998  static char *base64_alphabet =
  *   *
  * Returns the number of bytes encoded.   * Returns the number of bytes encoded.
  **/   **/
   
   #define BASE64_GROUPS_IN_LINE 19
   
 static size_t  static size_t
 g_mime_utils_base64_encode_step (const unsigned char *in, size_t inlen, unsigned char *out, int *state, int *save)  g_mime_utils_base64_encode_step (const unsigned char *in, size_t inlen, unsigned char *out, int *state, int *save)
 {  {
Line 979  g_mime_utils_base64_encode_step (const u Line 1038  g_mime_utils_base64_encode_step (const u
                         *outptr++ = base64_alphabet [((c2 & 0x0f) << 2) | (c3 >> 6)];                          *outptr++ = base64_alphabet [((c2 & 0x0f) << 2) | (c3 >> 6)];
                         *outptr++ = base64_alphabet [c3 & 0x3f];                          *outptr++ = base64_alphabet [c3 & 0x3f];
                         /* this is a bit ugly ... */                          /* this is a bit ugly ... */
                         if ((++already) >= 19) {                          if ((++already) >= BASE64_GROUPS_IN_LINE) {
                                 *outptr++ = '\n';                                  *outptr++ = '\n';
                                 already = 0;                                  already = 0;
                         }                          }
Line 1144  g_mime_utils_base64_decode_step (const u Line 1203  g_mime_utils_base64_decode_step (const u
 }  }
   
   
 char* pa_base64_encode(const char *in, size_t in_size)  char* pa_base64_encode(const char *in, size_t in_size){
 {          size_t new_size = ((in_size / 3 + 1) * 4);
         /* wont go to more than 2x size (overly conservative) */          new_size += new_size / (BASE64_GROUPS_IN_LINE * 4)/*new lines*/ + 1/*zero terminator*/;
         char* result=new(PointerFreeGC) char[in_size * 2 + 6];          char* result = new(PointerFreeGC) char[new_size];
         int state=0;          int state=0;
         int save=0;          int save=0;
 #ifndef NDEBUG  #ifndef NDEBUG
         size_t filled=          size_t filled=
 #endif  #endif
                 g_mime_utils_base64_encode_close ((const unsigned char*)in, in_size,                   g_mime_utils_base64_encode_close ((const unsigned char*)in, in_size, (unsigned char*)result, &state, &save);
                 (unsigned char*)result, &state, &save);  
         assert(filled <= in_size * 2 + 6);          //throw Exception(PARSER_RUNTIME, 0, "%d %d %d", in_size, new_size, filled);
           assert(filled <= new_size);
   
         return result;          return result;
 }  }
   
   
 char* pa_base64_encode(const String& file_spec)  char* pa_base64_encode(const String& file_spec){
 {  
         unsigned char* base64=0;          unsigned char* base64=0;
         File_base64_action_info info={&base64};           File_base64_action_info info={&base64}; 
   
Line 1198  static void file_base64_file_action( Line 1257  static void file_base64_file_action(
         }          }
 }  }
   
 void pa_base64_decode(const char *in, size_t in_size, char*& result, size_t& result_size)  void pa_base64_decode(const char *in, size_t in_size, char*& result, size_t& result_size) {
 {  
         /* wont go to more than had (overly conservative) */          /* wont go to more than had (overly conservative) */
         result=new(PointerFreeGC) char[in_size+1/*terminator*/];          result=new(PointerFreeGC) char[in_size+1/*terminator*/];
         int state=0;          int state=0;
Line 1215  void pa_base64_decode(const char *in, si Line 1273  void pa_base64_decode(const char *in, si
 int file_block_read(const int f, unsigned char* buffer, const size_t size){  int file_block_read(const int f, unsigned char* buffer, const size_t size){
         int nCount = read(f, buffer, size);          int nCount = read(f, buffer, size);
         if (nCount < 0)          if (nCount < 0)
                 throw Exception(0,                   throw Exception("file.read", 
                         0,                           0, 
                         "read failed: %s (%d)",  strerror(errno), errno);                           "read failed: %s (%d)",  strerror(errno), errno); 
         return nCount;          return nCount;
 }  }
   
 const unsigned long pa_crc32(const char *in, size_t in_size)  const unsigned long pa_crc32(const char *in, size_t in_size){
 {  
         unsigned long crc32=0xFFFFFFFF;          unsigned long crc32=0xFFFFFFFF;
   
                 InitCrc32Table();          InitCrc32Table();
                 for(size_t i = 0; i < in_size; i++) CalcCrc32(in[i], crc32);          for(size_t i = 0; i<in_size; i++)
                   CalcCrc32(in[i], crc32);
   
         return ~crc32;           return ~crc32; 
 }  }
   
 const unsigned long pa_crc32(const String& file_spec)  const unsigned long pa_crc32(const String& file_spec){
 {  
         unsigned long crc32=0xFFFFFFFF;          unsigned long crc32=0xFFFFFFFF;
         file_read_action_under_lock(file_spec, "crc32", file_crc32_file_action, &crc32);          file_read_action_under_lock(file_spec, "crc32", file_crc32_file_action, &crc32);
         return ~crc32;           return ~crc32; 
Line 1242  static void file_crc32_file_action( Line 1299  static void file_crc32_file_action(
                                 struct stat& finfo,                                   struct stat& finfo, 
                                 int f,                                   int f, 
                                 const String&, const char* /*fname*/, bool,                                   const String&, const char* /*fname*/, bool, 
                                 void *context)                                  void *context) {
 {  
         unsigned long& crc32=*static_cast<unsigned long *>(context);          unsigned long& crc32=*static_cast<unsigned long *>(context);
         if(finfo.st_size) {          if(finfo.st_size) {
                 InitCrc32Table();                  InitCrc32Table();

Removed from v.1.229  
changed lines
  Added in v.1.254


E-mail: