Diff for /parser3/src/main/pa_common.C between versions 1.253 and 1.265

version 1.253, 2009/10/02 01:19:24 version 1.265, 2012/03/03 00:22:04
Line 1 Line 1
 /** @file  /** @file
         Parser: commonly functions.          Parser: commonly functions.
   
         Copyright(c) 2001-2009 ArtLebedev Group (http://www.artlebedev.com)          Copyright(c) 2001-2012 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 67  const String file_status_name(FILE_STATU Line 67  const String file_status_name(FILE_STATU
   
 // functions  // functions
   
   bool capitalized(const char* s){
           bool upper=true;
           for(const char* c=s; *c; c++){
                   if(*c != (upper ? toupper((unsigned char)*c) : tolower((unsigned char)*c)))
                           return false;
                   upper=strchr("-_ ", *c) != 0;
           }
           return true;
   }
   
 const char* capitalize(const char* s){  const char* capitalize(const char* s){
           if(!s || capitalized(s))
                   return s;
   
         char* result=pa_strdup(s);          char* result=pa_strdup(s);
         if(result){          if(result){
                 bool upper=true;                  bool upper=true;
Line 89  void fix_line_breaks(char *str, size_t& Line 102  void fix_line_breaks(char *str, size_t&
         while(char* eol=(char*)memchr(bol, '\r', eob -bol)) {          while(char* eol=(char*)memchr(bol, '\r', eob -bol)) {
                 size_t len=eol-bol;                  size_t len=eol-bol;
                 if(dest!=bol)                  if(dest!=bol)
                         memcpy(dest, bol, len);                           memmove(dest, bol, len); 
                 dest+=len;                  dest+=len;
                 *dest++='\n';                   *dest++='\n'; 
   
Line 101  void fix_line_breaks(char *str, size_t& Line 114  void fix_line_breaks(char *str, size_t&
         }          }
         // last piece without \r          // last piece without \r
         if(dest!=bol)          if(dest!=bol)
                 memcpy(dest, bol, eob-bol);                   memmove(dest, bol, eob-bol); 
         str[length]=0; // terminating          str[length]=0; // terminating
 }  }
   
Line 187  File_read_result file_read(Request_chars Line 200  File_read_result file_read(Request_chars
         if(params){          if(params){
                 int valid_options=pa_get_valid_file_options_count(*params);                  int valid_options=pa_get_valid_file_options_count(*params);
                 if(valid_options!=params->count())                  if(valid_options!=params->count())
                         throw Exception(PARSER_RUNTIME,                          throw Exception(PARSER_RUNTIME, 0, CALLED_WITH_INVALID_OPTION);
                                 0,  
                                 INVALID_OPTION_PASSED);  
         }          }
   
         File_read_action_info info={&result.str, &result.length, buf, offset, count};           File_read_action_info info={&result.str, &result.length, buf, offset, count}; 
Line 200  File_read_result file_read(Request_chars Line 211  File_read_result file_read(Request_chars
   
         if(as_text){          if(as_text){
                 if(result.success){                  if(result.success){
                           Charset* asked_charset=0;
                         if(result.length>=3 && strncmp(result.str, "\xEF\xBB\xBF", 3)==0){                          if(result.length>=3 && strncmp(result.str, "\xEF\xBB\xBF", 3)==0){
                                 // skip UTF-8 signature (BOM code)                                  // skip UTF-8 signature (BOM code)
                                 result.str+=3;                                  result.str+=3;
                                 result.length-=3;                                  result.length-=3;
                                   asked_charset=&UTF8_charset;
                         }                          }
                                                   
                         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(params)
                                 if(Value* vcharset_name=params->get(PA_CHARSET_NAME)){                                  if(Value* vcharset_name=params->get(PA_CHARSET_NAME))
                                         Charset asked_charset=::charsets.get(vcharset_name->as_string().                                          asked_charset=&::charsets.get(vcharset_name->as_string().change_case(charsets.source(), String::CC_UPPER));
                                                 change_case(charsets.source(), String::CC_UPPER));  
                           if(result.length && transcode_text_result && asked_charset){ // length must be checked because transcode returns CONST string in case length==0, which contradicts hacking few lines below
                                         String::C body=String::C(result.str, result.length);                                  String::C body=String::C(result.str, result.length);
                                         body=Charset::transcode(body, asked_charset, charsets.source());                                  body=Charset::transcode(body, *asked_charset, charsets.source());
   
                                         result.str=const_cast<char*>(body.str); // hacking a little                                  result.str=const_cast<char*>(body.str); // hacking a little
                                         result.length=body.length;                                  result.length=body.length;
                                 }  
                         }                          }
                 }                  }
                 if(result.length)                  if(result.length)
Line 251  File_read_result file_load(Request& r, c Line 263  File_read_result file_load(Request& r, c
         return result;          return result;
 }  }
   
   
 #ifdef PA_SAFE_MODE   #ifdef PA_SAFE_MODE 
 void check_safe_mode(struct stat finfo, const String& file_spec, const char* fname) {   void check_safe_mode(struct stat finfo, const String& file_spec, const char* fname) {
         if(finfo.st_uid/*foreign?*/!=geteuid()           if(finfo.st_uid/*foreign?*/!=geteuid() 
                 && finfo.st_gid/*foreign?*/!=getegid())                   && finfo.st_gid/*foreign?*/!=getegid()) 
                 throw Exception(PARSER_RUNTIME,                    throw Exception(PARSER_RUNTIME,  
Line 264  void check_safe_mode(struct stat finfo, Line 277  void check_safe_mode(struct stat finfo,
                         "fuid(%d)!=euid(%d) or fgid(%d)!=egid(%d)",                            "fuid(%d)!=euid(%d) or fgid(%d)!=egid(%d)",  
                                 fname,                                   fname, 
                                 finfo.st_uid, geteuid(),                                   finfo.st_uid, geteuid(), 
                                 finfo.st_gid, getegid());                                   finfo.st_gid, getegid());
 }   }
 #endif   #else
   void check_safe_mode(struct stat, const String&, const char*) {
   }
   #endif
   
   
   
 bool file_read_action_under_lock(const String& file_spec,   bool file_read_action_under_lock(const String& file_spec, 
                                 const char* action_name, File_read_action action, void *context,                                   const char* action_name, File_read_action action, void *context, 
Line 293  bool file_read_action_under_lock(const S Line 311  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'", 
                                                 strerror(errno), errno, fname);                                                  strerror(errno), errno, fname);
   
 #ifdef PA_SAFE_MODE  
                         check_safe_mode(finfo, file_spec, fname);                          check_safe_mode(finfo, file_spec, fname);
 #endif  
   
                         action(finfo, f, file_spec, fname, as_text, context);                           action(finfo, f, file_spec, fname, as_text, context); 
                 } catch(...) {                  } catch(...) {
Line 315  bool file_read_action_under_lock(const S Line 331  bool file_read_action_under_lock(const S
                 return true;                  return true;
         } else {          } else {
                 if(fail_on_read_problem)                  if(fail_on_read_problem)
                         throw Exception(errno==EACCES?"file.access":errno==ENOENT?"file.missing":0,                           throw Exception(errno==EACCES?"file.access"
                                                           :(errno==ENOENT || errno==ENOTDIR || errno==ENODEV)?"file.missing":0, 
                                 &file_spec,                                   &file_spec, 
                                 "%s failed: %s (%d), actual filename '%s'",                                   "%s failed: %s (%d), actual filename '%s'", 
                                         action_name, strerror(errno), errno, fname);                                          action_name, strerror(errno), errno, fname);
Line 362  bool file_write_action_under_lock( Line 379  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 429  void file_write( Line 451  void file_write(
                 do_append);                   do_append); 
 }  }
   
   static size_t get_dir(char* fname, size_t helper_length){
           bool dir=false;
           size_t pos=0;
           for(pos=helper_length; pos; pos--){
                   char c=fname[pos-1];
                   if(c=='/' || c=='\\'){
                           fname[pos-1]=0;
                           dir=true;
                   } else if(dir) break;
           }
           return pos;
   }
   
   static bool entry_readable(char* fname, bool need_dir) {
           if(need_dir){
                   size_t size=strlen(fname);
                   while(size) {
                           char c=fname[size-1];
                           if(c=='/' || c=='\\')
                                   fname[--size]=0;
                           else
                                   break;
                   }
           }
   
           struct stat finfo;
           if(access(fname, R_OK)==0 && entry_exists(fname, &finfo)) {
                   bool is_dir=(finfo.st_mode&S_IFDIR) != 0;
                   return is_dir==need_dir;
           }
           return false;
   }
   
   static bool entry_readable(const String& file_spec, bool need_dir) {
           return entry_readable(file_spec.taint_cstrm(String::L_FILE_SPEC), need_dir);
   }
   
 // throws nothing! [this is required in file_move & file_delete]  // throws nothing! [this is required in file_move & file_delete]
 static void rmdir(const String& file_spec, size_t pos_after) {  static void rmdir(const String& file_spec, size_t pos_after=0) {
         size_t pos_before;          char* dir_spec=file_spec.taint_cstrm(String::L_FILE_SPEC);
         if((pos_before=file_spec.pos('/', pos_after))!=STRING_NOT_FOUND)          size_t length=strlen(dir_spec);
                 rmdir(file_spec, pos_before+1);           while( (length=get_dir(dir_spec, length)) && (length > pos_after) ){
           #ifdef WIN32
         rmdir(file_spec.mid(0, pos_after-1/* / */).taint_cstr(String::L_FILE_SPEC));                   if(!entry_readable(dir_spec, true))
                           break;
                   DWORD attrs=GetFileAttributes(dir_spec);
                   if(
                           (attrs==INVALID_FILE_ATTRIBUTES)
                           || !(attrs & FILE_ATTRIBUTE_DIRECTORY)
                           || (attrs & FILE_ATTRIBUTE_REPARSE_POINT)
                   )
                           break;
   #endif
                   if( rmdir(dir_spec) )
                           break;
           };
 }  }
   
 bool file_delete(const String& file_spec, bool fail_on_problem) {  bool file_delete(const String& file_spec, bool fail_on_problem) {
Line 482  bool entry_exists(const String& file_spe Line 553  bool entry_exists(const String& file_spe
         return entry_exists(fname, 0);           return entry_exists(fname, 0); 
 }  }
   
 static bool entry_readable(const String& file_spec, bool need_dir) {  
         char* fname=file_spec.taint_cstrm(String::L_FILE_SPEC);   
         if(need_dir) {  
                 size_t size=strlen(fname);   
                 while(size) {  
                         char c=fname[size-1];   
                         if(c=='/' || c=='\\')  
                                 fname[--size]=0;  
                         else  
                                 break;  
                 }  
         }  
         struct stat finfo;  
         if(access(fname, R_OK)==0 && entry_exists(fname, &finfo)) {  
                 bool is_dir=(finfo.st_mode&S_IFDIR) != 0;  
                 return is_dir==need_dir;  
         }  
         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); 
 }  }
Line 707  enum EscapeState { Line 758  enum EscapeState {
 };  };
   
 // @todo prescan for reduce required size (unescaped sting in 1 byte charset requires less memory usually)  // @todo prescan for reduce required size (unescaped sting in 1 byte charset requires less memory usually)
 char* unescape_chars(const char* cp, int len, Charset* charset, bool ignore_plus){  char* unescape_chars(const char* cp, int len, Charset* charset, bool js){
         char* s=new(PointerFreeGC) char[len+1]; // must be enough (%uXXXX==6 bytes, max utf-8 char length==6 bytes)          char* s=new(PointerFreeGC) char[len+1]; // must be enough (%uXXXX==6 bytes, max utf-8 char length==6 bytes)
         char* dst=s;          char* dst=s;
         EscapeState escapeState=EscapeRest;          EscapeState escapeState=EscapeRest;
Line 716  char* unescape_chars(const char* cp, int Line 767  char* unescape_chars(const char* cp, int
         short int jsCnt=0;          short int jsCnt=0;
         while(srcPos<len){          while(srcPos<len){
                 uchar c=(uchar)cp[srcPos];                   uchar c=(uchar)cp[srcPos]; 
                 if(c=='%'){                  if(c=='%' || (c=='\\' && js)){
                         escapeState=EscapeFirst;                          escapeState=EscapeFirst;
                 } else {                  } else {
                         switch(escapeState) {                          switch(escapeState) {
                                 case EscapeRest:                                  case EscapeRest:
                                         if(!ignore_plus && c=='+'){                                          if(!js && c=='+'){
                                                 *dst++=' ';                                                  *dst++=' ';
                                         } else {                                          } else {
                                                 *dst++=c;                                                  *dst++=c;
Line 1252  static void file_base64_file_action( Line 1303  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, bool strict) {
         /* wont go to more than had (overly conservative) */          // every 4 base64 bytes are converted into 3 normal bytes
         result=new(PointerFreeGC) char[in_size+1/*terminator*/];          // not full set (tail) of 4-bytes set is ignored
           size_t new_size=in_size/4*3;
           result=new(PointerFreeGC) char[new_size+1/*terminator*/];
   
         int state=0;          int state=0;
         int save=0;          int save=0;
         result_size=          result_size=
                 g_mime_utils_base64_decode_step ((const unsigned char*)in, in_size,                   g_mime_utils_base64_decode_step ((const unsigned char*)in, in_size, 
                 (unsigned char*)result, &state, &save);                  (unsigned char*)result, &state, &save);
         assert(result_size <= in_size);          assert(result_size <= new_size);
         result[result_size]=0; // for text files          result[result_size]=0; // for text files
   
           if(strict && state!=0)
                   throw Exception(PARSER_RUNTIME, 0, "Unexpected end of base64 chars during base64-decoding");
 }  }
   
   

Removed from v.1.253  
changed lines
  Added in v.1.265


E-mail: