--- parser3/src/main/pa_common.C 2016/12/24 23:02:13 1.297 +++ parser3/src/main/pa_common.C 2017/02/07 22:00:41 1.303 @@ -1,7 +1,7 @@ /** @file Parser: commonly functions. - Copyright (c) 2000-2015 Art. Lebedev Studio (http://www.artlebedev.com) + Copyright (c) 2000-2017 Art. Lebedev Studio (http://www.artlebedev.com) Author: Alexandr Petrosian (http://paf.design.ru) * BASE64 part @@ -50,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.297 2016/12/24 23:02:13 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.303 2017/02/07 22:00:41 moko Exp $" IDENT_PA_COMMON_H IDENT_PA_HASH_H IDENT_PA_ARRAY_H IDENT_PA_STACK_H; // some maybe-undefined constants @@ -79,8 +79,32 @@ volatile const char * IDENT_PA_COMMON_C= const String file_status_name(FILE_STATUS_NAME); +// forwards + +const UTF16* pa_utf16_encode(const char* in, Charset& source_charset); + // functions +#ifdef _MSC_VER + +int pa_stat(const char *pathname, struct stat *buffer){ + const UTF16* utf16name=pa_utf16_encode(pathname, pa_thread_request().charsets.source()); + return _wstat64((const wchar_t *)utf16name, buffer); +} + +int pa_open(const char *pathname, int flags, int mode){ + const UTF16* utf16name=pa_utf16_encode(pathname, pa_thread_request().charsets.source()); + return _wopen((const wchar_t *)utf16name, flags, mode); +} + +FILE *pa_fopen(const char *pathname, const char *mode){ + const UTF16* utf16name=pa_utf16_encode(pathname, pa_thread_request().charsets.source()); + const UTF16* utf16mode=pa_utf16_encode(mode, pa_thread_request().charsets.source()); + return _wfopen((const wchar_t *)utf16name, (const wchar_t *)utf16mode); +} + +#endif + char* file_read_text(Request_charsets& charsets, const String& file_spec, bool fail_on_read_problem, HashStringValue* params, bool transcode_result) { File_read_result file=file_read(charsets, file_spec, true, params, fail_on_read_problem, 0, 0, 0, transcode_result); return file.success?file.str:0; @@ -118,7 +142,7 @@ static void file_read_action(struct stat File_read_action_info& info=*static_cast(context); size_t to_read_size=info.count; if(!to_read_size) - to_read_size=(size_t)finfo.st_size; + to_read_size=check_file_size(finfo.st_size, file_spec); if(to_read_size) { if(info.offset) lseek(f, info.offset, SEEK_SET); @@ -234,13 +258,13 @@ bool file_read_action_under_lock(const S // they delay update till open, so we would receive "!^test[" string // if would do stat, next open. // later: it seems, even this does not help sometimes - if((f=open(fname, O_RDONLY|(as_text?_O_TEXT:_O_BINARY)))>=0) { + if((f=pa_open(fname, O_RDONLY|(as_text?_O_TEXT:_O_BINARY)))>=0) { try { if(pa_lock_shared_blocking(f)!=0) throw Exception("file.lock", &file_spec, "shared lock failed: %s (%d), actual filename '%s'", strerror(errno), errno, fname); struct stat finfo; - if(fstat(f, &finfo)!=0) + if(pa_fstat(f, &finfo)!=0) throw Exception("file.missing", // hardly possible: we just opened it OK &file_spec, "stat failed: %s (%d), actual filename '%s'", strerror(errno), errno, fname); @@ -287,7 +311,7 @@ bool file_write_action_under_lock( if(access(fname, W_OK)!=0) // no create_dir_for_file(file_spec); - if((f=open(fname, + if((f=pa_open(fname, O_CREAT|O_RDWR |(as_text?_O_TEXT:_O_BINARY) |(do_append?O_APPEND:PA_O_TRUNC), 0664))>=0) { @@ -302,7 +326,7 @@ bool file_write_action_under_lock( try { #if (defined(HAVE_FCHMOD) && defined(PA_SAFE_MODE)) struct stat finfo; - if(fstat(f, &finfo)==0 && finfo.st_mode & 0111) + if(pa_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); @@ -462,7 +486,7 @@ void file_move(const String& old_spec, c bool entry_exists(const char* fname, struct stat *afinfo) { struct stat lfinfo; - bool result=stat(fname, &lfinfo)==0; + bool result=pa_stat(fname, &lfinfo)==0; if(afinfo) *afinfo=lfinfo; return result; @@ -496,19 +520,25 @@ bool file_executable(const String& file_ bool file_stat(const String& file_spec, uint64_t& rsize, time_t& ratime, time_t& rmtime, time_t& rctime, 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(pa_stat(fname, &finfo)!=0) { if(fail_on_read_problem) throw Exception("file.missing", &file_spec, "getting file size failed: %s (%d), real filename '%s'", strerror(errno), errno, fname); else return false; } rsize=finfo.st_size; - ratime=finfo.st_atime; - rmtime=finfo.st_mtime; - rctime=finfo.st_ctime; + ratime=(time_t)finfo.st_atime; + rmtime=(time_t)finfo.st_mtime; + rctime=(time_t)finfo.st_ctime; return true; } +size_t check_file_size(uint64_t size, const String& file_spec){ + if(size > pa_file_size_limit) + throw Exception(PARSER_RUNTIME, &file_spec, "content size of %.15g bytes exceeds the limit (%.15g bytes)", (double)size, (double)pa_file_size_limit); + return (size_t)size; +} + /** String related functions */ @@ -1163,11 +1193,11 @@ struct File_base64_action_info { unsigned char** base64; }; -static void file_base64_file_action(struct stat& finfo, int f, const String&, void *context) { +static void file_base64_file_action(struct stat& finfo, int f, const String& file_spec, void *context) { if(finfo.st_size) { File_base64_action_info& info=*static_cast(context); - *info.base64=new(PointerFreeGC) unsigned char[finfo.st_size * 2 + 6]; + *info.base64=new(PointerFreeGC) unsigned char[check_file_size(finfo.st_size, file_spec) * 2 + 6]; unsigned char* base64 = *info.base64; int state=0; int save=0; @@ -1302,6 +1332,51 @@ Charset* detect_charset(const char* cont return 0; } +const UTF16* pa_utf16_encode(const char* in, Charset& source_charset){ + if(!in) + return 0; + + String::C sIn(in,strlen(in)); + + UTF16* utf16=(UTF16*)pa_malloc_atomic(sIn.length*2+2); + UTF16* utf16_end=utf16; + + if(!source_charset.isUTF8()) + sIn=Charset::transcode(sIn, source_charset, pa_UTF8_charset); + + int status=pa_convertUTF8toUTF16((const UTF8**)&sIn.str, (const UTF8*)(sIn.str+sIn.length), &utf16_end, utf16+sIn.length, strictConversion); + if(status != conversionOK) + throw Exception("utf-16 encode", new String(in), "utf-16 conversion failed (%d)", status); + + *utf16_end=0; + + return utf16; +} + +const char* pa_utf16_decode(const UTF16* in, Charset& asked_charset){ + if(!in) + return 0; + + const UTF16* utf16_start=in; + const UTF16* utf16_end; + + for(utf16_end=in; *utf16_end; utf16_end++); + + char *result = (char *)pa_malloc_atomic((utf16_end-in)*6+1); + char *result_end = result; + + int status=pa_convertUTF16toUTF8(&utf16_start, utf16_end, (UTF8**)&result_end, (UTF8*)(result+(utf16_end-in)*6), strictConversion); + + if(status != conversionOK) + throw Exception("utf-16 decode", 0, "utf conversion failed (%d)", status); + + *result_end='\0'; + + if(asked_charset.isUTF8()) + return result; + + return Charset::transcode(result, pa_UTF8_charset, asked_charset).cstr(); +} static bool is_latin(const char *in){ for(; *in; in++){ @@ -1313,7 +1388,7 @@ static bool is_latin(const char *in){ #define MAX_IDNA_LENGTH 256 -const char *pa_idna_encode(const char *in, Charset &source_charset){ +const char *pa_idna_encode(const char *in, Charset& source_charset){ if(!in || is_latin(in)) return in;