--- parser3/src/main/pa_common.C 2013/10/14 21:17:38 1.279 +++ parser3/src/main/pa_common.C 2015/10/07 21:24:40 1.286 @@ -36,6 +36,9 @@ #include "pcre.h" #include "pa_request.h" +#include "pa_idna.h" +#include "pa_convert_utf.h" + #ifdef _MSC_VER #include #include @@ -47,7 +50,7 @@ #define pa_mkdir(path, mode) mkdir(path, mode) #endif -volatile const char * IDENT_PA_COMMON_C="$Id: pa_common.C,v 1.279 2013/10/14 21:17:38 moko Exp $" IDENT_PA_COMMON_H IDENT_PA_HASH_H IDENT_PA_ARRAY_H IDENT_PA_STACK_H; +volatile const char * IDENT_PA_COMMON_C="$Id: pa_common.C,v 1.286 2015/10/07 21:24:40 moko Exp $" IDENT_PA_COMMON_H IDENT_PA_HASH_H IDENT_PA_ARRAY_H IDENT_PA_STACK_H; // some maybe-undefined constants @@ -455,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, @@ -463,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); @@ -528,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, @@ -536,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; @@ -782,7 +787,7 @@ char* unescape_chars(const char* cp, int } else { switch(escapeState) { case EscapeRest: - if(!js && c=='+'){ + if(c=='+' && !js){ *dst++=' '; } else { *dst++=c; @@ -863,26 +868,6 @@ void back_slashes_to_slashes(char* s) { } #endif -bool StrStartFromNC(const char* str, const char* substr, bool equal){ - while(true) { - if(!(*substr)){ - if(!(*str)) - return true; - else - return !equal; - } - if(!(*str)) - return false; - if(isalpha((unsigned char)*str)) { - if(tolower((unsigned char)*str)!=tolower((unsigned char)*substr)) - return false; - } else if((*str) != (*substr)) - return false; - str++; - substr++; - } -} - size_t strpos(const char *str, const char *substr) { const char *p = strstr(str, substr); return (p==0)?STRING_NOT_FOUND:p-str; @@ -941,8 +926,9 @@ int __vsnprintf(char* b, size_t s, const return 0; int r; - // note: on win32& maybe somewhere else + // note: on win32 & maybe somewhere else // vsnprintf do not writes terminating 0 in 'buffer full' case, reducing + // http://stackoverflow.com/questions/2915672/snprintf-and-visual-studio-2010 --s; // clients do not check for negative 's', feature: ignore such prints @@ -950,22 +936,16 @@ int __vsnprintf(char* b, size_t s, const return 0; #ifdef _MSC_VER - /* - win32: - mk:@MSITStore:C:\Program%20Files\Microsoft%20Visual%20Studio\MSDN\2001APR\1033\vccore.chm::/html/_crt__vsnprintf.2c_._vsnwprintf.htm - - if the number of bytes to write exceeds buffer, then count bytes are written and Ö1 is returned - */ + // win32: if the number of bytes to write exceeds buffer, then count bytes are written and -1 is returned r=_vsnprintf(b, s, f, l); if(r<0) r=s; #else r=vsnprintf(b, s, f, l); /* - solaris: - man vsnprintf + solaris: man vsnprintf - The snprintf() function returns the number of characters + The snprintf() function returns the number of characters formatted, that is, the number of characters that would have been written to the buffer if it were large enough. If the value of n is 0 on a call to snprintf(), an unspecified @@ -1418,41 +1398,68 @@ Charset* detect_charset(const char* cont } -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)); +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; }