--- parser3/src/main/pa_common.C 2013/07/16 14:55:45 1.272 +++ parser3/src/main/pa_common.C 2015/04/21 22:12:27 1.283 @@ -36,7 +36,21 @@ #include "pcre.h" #include "pa_request.h" -volatile const char * IDENT_PA_COMMON_C="$Id: pa_common.C,v 1.272 2013/07/16 14:55:45 moko Exp $" IDENT_PA_COMMON_H IDENT_PA_HASH_H IDENT_PA_ARRAY_H IDENT_PA_STACK_H; +#include "pa_idna.h" +#include "pa_convert_utf.h" + +#ifdef _MSC_VER +#include +#include +#endif + +#ifdef _MSC_VER +#define pa_mkdir(path, mode) _mkdir(path) +#else +#define pa_mkdir(path, mode) mkdir(path, mode) +#endif + +volatile const char * IDENT_PA_COMMON_C="$Id: pa_common.C,v 1.283 2015/04/21 22:12:27 moko Exp $" IDENT_PA_COMMON_H IDENT_PA_HASH_H IDENT_PA_ARRAY_H IDENT_PA_STACK_H; // some maybe-undefined constants @@ -67,57 +81,6 @@ const String file_status_name(FILE_STATU // 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){ - if(!s || capitalized(s)) - return 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) { - //_asm int 3; - const char* const eob=str+length; - char* dest=str; - // fix DOS: \r\n -> \n - // fix Macintosh: \r -> \n - char* bol=str; - while(char* eol=(char*)memchr(bol, '\r', eob -bol)) { - size_t len=eol-bol; - if(dest!=bol) - memmove(dest, bol, len); - dest+=len; - *dest++='\n'; - - if(&eol[1] pos_after) ){ -#ifdef WIN32 +#ifdef _MSC_VER if(!entry_readable(dir_spec, true)) break; DWORD attrs=GetFileAttributes(dir_spec); @@ -495,7 +458,7 @@ static void rmdir(const String& file_spe bool file_delete(const String& file_spec, bool fail_on_problem, bool keep_empty_dirs) { const char* fname=file_spec.taint_cstr(String::L_FILE_SPEC); - if(unlink(fname)!=0) + if(unlink(fname)!=0) { if(fail_on_problem) throw Exception(errno==EACCES?"file.access":errno==ENOENT?"file.missing":0, &file_spec, @@ -503,6 +466,7 @@ bool file_delete(const String& file_spec strerror(errno), errno, fname); else return false; + } if(!keep_empty_dirs) rmdir(file_spec, 1); @@ -568,7 +532,7 @@ bool file_stat(const String& file_spec, bool fail_on_read_problem) { const char* fname=file_spec.taint_cstr(String::L_FILE_SPEC); struct stat finfo; - if(stat(fname, &finfo)!=0) + if(stat(fname, &finfo)!=0) { if(fail_on_read_problem) throw Exception("file.missing", &file_spec, @@ -576,6 +540,7 @@ bool file_stat(const String& file_spec, strerror(errno), errno, fname); else return false; + } rsize=finfo.st_size; ratime=finfo.st_atime; rmtime=finfo.st_mtime; @@ -583,6 +548,68 @@ bool file_stat(const String& file_spec, return true; } +/** + String related 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){ + if(!s || capitalized(s)) + return 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) { + //_asm int 3; + const char* const eob=str+length; + char* dest=str; + // fix DOS: \r\n -> \n + // fix Macintosh: \r -> \n + char* bol=str; + while(char* eol=(char*)memchr(bol, '\r', eob -bol)) { + size_t len=eol-bol; + if(dest!=bol) + memmove(dest, bol, len); + dest+=len; + *dest++='\n'; + + if(&eol[1]hh*/+1/*for zero-teminator*/]; + unsigned char *src=bytes; + unsigned char *end=bytes+size; + char *dest=bytes_hex; + + const char *hex=upcase? hex_digits : "0123456789abcdef"; + + for(; src 0; j--) + { + if(dwCrc & 1) + dwCrc = (dwCrc >> 1) ^ dwPolynomial; + else + dwCrc >>= 1; + } + crc32Table[i] = dwCrc; + } + } +} + +inline void CalcCrc32(const unsigned char byte, unsigned long &crc32) +{ + crc32 = ((crc32) >> 8) ^ crc32Table[(byte) ^ ((crc32) & 0x000000FF)]; +} + + const unsigned long pa_crc32(const char *in, size_t in_size){ unsigned long crc32=0xFFFFFFFF; @@ -1356,12 +1349,6 @@ const unsigned long pa_crc32(const char return ~crc32; } -const unsigned long pa_crc32(const String& file_spec){ - unsigned long crc32=0xFFFFFFFF; - file_read_action_under_lock(file_spec, "crc32", file_crc32_file_action, &crc32); - return ~crc32; -} - static void file_crc32_file_action( struct stat& finfo, int f, @@ -1379,3 +1366,145 @@ static void file_crc32_file_action( } } +const unsigned long pa_crc32(const String& file_spec){ + unsigned long crc32=0xFFFFFFFF; + file_read_action_under_lock(file_spec, "crc32", file_crc32_file_action, &crc32); + return ~crc32; +} + +// 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 is_latin(const char *in){ + for(; *in; in++){ + if ((unsigned char)(*in) > 0x7F) + return false; + } + return true; +} + +#define MAX_IDNA_LENGTH 256 + +const char *pa_idna_encode(const char *in, Charset &source_charset){ + if(!in || is_latin(in)) + return in; + + uint32_t utf32[MAX_IDNA_LENGTH]; + uint32_t *utf32_end=utf32; + + String::C sIn(in,strlen(in)); + + if(!source_charset.isUTF8()) + sIn=Charset::transcode(sIn, source_charset, UTF8_charset); + + int status=pa_convertUTF8toUTF32((const UTF8**)&sIn.str, (const UTF8*)(sIn.str+sIn.length), &utf32_end, utf32+MAX_IDNA_LENGTH-1, strictConversion); + if(status != conversionOK) + throw Exception("idna encode", new String(in), "utf conversion failed (%d)", status); + + *utf32_end=0; + + char *result = (char *)pa_malloc(MAX_IDNA_LENGTH); + status=pa_idna_to_ascii_4z(utf32, result, MAX_IDNA_LENGTH, 0); + if(status != IDNA_SUCCESS) + throw Exception("idna encode", new String(in), "encode failed: %s", pa_idna_strerror(status)); + + return result; +} + +const char *pa_idna_decode(const char *in, Charset &asked_charset){ + if(!in || !(*in)) + return in; + + uint32_t utf32[MAX_IDNA_LENGTH]; + const uint32_t *utf32_start=utf32; + uint32_t *utf32_end; + + int status=pa_idna_to_unicode_4z(in, utf32, MAX_IDNA_LENGTH, 0); + if(status != IDNA_SUCCESS) + throw Exception("idna decode", new String(in), "decode failed: %s", pa_idna_strerror(status)); + + for(utf32_end=utf32; *utf32_end; utf32_end++); + + char *result = (char *)pa_malloc(MAX_IDNA_LENGTH); + char *result_end = result; + + status=pa_convertUTF32toUTF8(&utf32_start, utf32_end, (UTF8**)&result_end, (UTF8*)(result+MAX_IDNA_LENGTH-1), strictConversion); + + if(status != conversionOK) + throw Exception("idna decode", new String(in), "utf conversion failed (%d)", status); + + *result_end='\0'; + + if(!asked_charset.isUTF8()) + result = (char *)Charset::transcode(result, UTF8_charset, asked_charset).cstr(); + + return result; +} + + +static bool isLeap(int year) { + return !( + (year % 4) || ((year % 400) && !(year % 100)) + ); +} + +int getMonthDays(int year, int month) { + static int monthDays[]={ + 31, + 28, + 31, + 30, + 31, + 30, + 31, + 31, + 30, + 31, + 30, + 31 + }; + return (month == 1 /* january -- 0 */ && isLeap(year)) ? 29 : monthDays[month]; +} + +String::C date_gmt_string(tm* tms) { + /// http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.3 + static const char month_names[12][4]={ + "Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"}; + static const char days[7][4]={ + "Sun","Mon","Tue","Wed","Thu","Fri","Sat"}; + + char *buf=new(PointerFreeGC) char[MAX_STRING]; + return String::C(buf, + snprintf(buf, MAX_STRING, "%s, %.2d %s %.4d %.2d:%.2d:%.2d GMT", + days[tms->tm_wday], + tms->tm_mday,month_names[tms->tm_mon],tms->tm_year+1900, + tms->tm_hour,tms->tm_min,tms->tm_sec)); +}