diff --git a/ole/ole2nls.c b/ole/ole2nls.c index 0af57a47940..2e19539ebbd 100644 --- a/ole/ole2nls.c +++ b/ole/ole2nls.c @@ -10,6 +10,7 @@ #include #include #include +#include #include "windef.h" #include "wingdi.h" #include "winuser.h" @@ -2215,6 +2216,7 @@ INT WINAPI LCMapStringA( return j; } + /* FIXME: This function completely ignores the "lcid" parameter. */ /* else ... (mapflags & LCMAP_SORTKEY) */ { int unicode_len=0; @@ -2365,8 +2367,8 @@ INT WINAPI LCMapStringW( int i; TRACE_(string)("(0x%04lx,0x%08lx,%p,%d,%p,%d)\n", - lcid,mapflags,srcstr,srclen,dststr,dstlen); - + lcid, mapflags, srcstr, srclen, dststr, dstlen); + if ( ((dstlen!=0) && (dststr==NULL)) || (srcstr==NULL) ) { ERR("(src=%p,dst=%p): Invalid NULL string\n", srcstr, dststr); @@ -2376,25 +2378,267 @@ INT WINAPI LCMapStringW( if (srclen==-1) srclen = lstrlenW(srcstr)+1; - if (dstlen==0) - return srclen; - if (dstlen"); + SetLastError(ERROR_INVALID_PARAMETER); + if(srcstr_libc) HeapFree(GetProcessHeap(), 0, srcstr_libc); + if(src_native) HeapFree(GetProcessHeap(), 0, src_native); + return 0; + } + + TRACE_(string)("lc_collate_default = %s\n", lc_collate_default); + TRACE_(string)("lc_collate_env = %s\n", lc_collate_env); + + /* Convert the libc Unicode string to a native multibyte character + * string. */ + returned_len = wcstombs(src_native, srcstr_libc, src_native_len) + 1; + if(returned_len == 0) + { + LPSTR srcstr_ascii = (LPSTR)HEAP_strdupWtoA(GetProcessHeap(), + 0, srcstr); + ERR("wcstombs failed. The string specified (%s) may contains an " + "invalid character.\n", srcstr_ascii); + SetLastError(ERROR_INVALID_PARAMETER); + if(srcstr_ascii) HeapFree(GetProcessHeap(), 0, srcstr_ascii); + if(srcstr_libc) HeapFree(GetProcessHeap(), 0, srcstr_libc); + if(src_native) HeapFree(GetProcessHeap(), 0, src_native); + setlocale(LC_COLLATE, lc_collate_default); + return 0; + } + else if(returned_len > src_native_len) + { + src_native[src_native_len - 1] = 0; + ERR("wcstombs returned a string (%s) that was longer (%d bytes) " + "than expected (%d bytes).\n", src_native, returned_len, + dst_native_len); + + /* Since this is an internal error I'm not sure what the correct + * error code is. */ + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + + if(srcstr_libc) HeapFree(GetProcessHeap(), 0, srcstr_libc); + if(src_native) HeapFree(GetProcessHeap(), 0, src_native); + setlocale(LC_COLLATE, lc_collate_default); + return 0; + } + src_native_len = returned_len; + + TRACE_(string)("src_native = %s src_native_len = %d\n", + src_native, src_native_len); + + /* dst_native seems to contain at most 4 bytes for each byte in + * the original src_native string. Change if need be since this + * isn't documented by the strxfrm() man page. */ + dst_native_len = 4 * src_native_len; + if(!(dst_native = (LPSTR)HeapAlloc(GetProcessHeap(), 0, dst_native_len))) + { + ERR("Unable to allocate %d bytes for dst_native\n", dst_native_len); + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + if(srcstr_libc) HeapFree(GetProcessHeap(), 0, srcstr_libc); + if(src_native) HeapFree(GetProcessHeap(), 0, src_native); + setlocale(LC_COLLATE, lc_collate_default); + return 0; + } + + /* The actual translation is done by the following call to + * strxfrm(). The surrounding code could have been simplified + * by calling wcsxfrm() instead except that wcsxfrm() is not + * available on older Linux systems (RedHat 4.1 with + * libc-5.3.12-17). + * + * Also, it is possible that the translation could be done by + * various tables as it is done in LCMapStringA(). However, I'm + * not sure what those tables are. */ + returned_len = strxfrm(dst_native, src_native, dst_native_len) + 1; + + if(returned_len > dst_native_len) + { + dst_native[dst_native_len - 1] = 0; + ERR("strxfrm returned a string (%s) that was longer (%d bytes) " + "than expected (%d bytes).\n", dst_native, returned_len, + dst_native_len); + + /* Since this is an internal error I'm not sure what the correct + * error code is. */ + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + + if(srcstr_libc) HeapFree(GetProcessHeap(), 0, srcstr_libc); + if(src_native) HeapFree(GetProcessHeap(), 0, src_native); + if(dst_native) HeapFree(GetProcessHeap(), 0, dst_native); + setlocale(LC_COLLATE, lc_collate_default); + return 0; + } + dst_native_len = returned_len; + + TRACE_(string)("dst_native = %s dst_native_len = %d\n", + dst_native, dst_native_len); + + dststr_libc_len = dst_native_len; + if(!(dststr_libc = (wchar_t *)HeapAlloc(GetProcessHeap(), 0, + dststr_libc_len * sizeof(wchar_t)))) + { + ERR("Unable to allocate %d bytes for dststr_libc\n", + dststr_libc_len * sizeof(wchar_t)); + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + if(srcstr_libc) HeapFree(GetProcessHeap(), 0, srcstr_libc); + if(src_native) HeapFree(GetProcessHeap(), 0, src_native); + if(dst_native) HeapFree(GetProcessHeap(), 0, dst_native); + setlocale(LC_COLLATE, lc_collate_default); + return 0; + } + + /* Convert the native multibyte string to a libc Unicode string. */ + returned_len = mbstowcs(dststr_libc, dst_native, dst_native_len) + 1; + + /* Restore LC_COLLATE now that the last LC_COLLATE sensitive + * function has returned. */ + setlocale(LC_COLLATE, lc_collate_default); + + if(returned_len == 0) + { + ERR("mbstowcs failed. The native version of the translated string " + "(%s) may contain an invalid character.\n", dst_native); + SetLastError(ERROR_INVALID_PARAMETER); + if(srcstr_libc) HeapFree(GetProcessHeap(), 0, srcstr_libc); + if(src_native) HeapFree(GetProcessHeap(), 0, src_native); + if(dst_native) HeapFree(GetProcessHeap(), 0, dst_native); + if(dststr_libc) HeapFree(GetProcessHeap(), 0, dststr_libc); + return 0; + } + if(dstlen) + { + if(returned_len > dstlen) + { + ERR("mbstowcs returned a string that was longer (%d chars) " + "than the buffer provided (%d chars).\n", returned_len, + dstlen); + SetLastError(ERROR_INSUFFICIENT_BUFFER); + if(srcstr_libc) HeapFree(GetProcessHeap(), 0, srcstr_libc); + if(src_native) HeapFree(GetProcessHeap(), 0, src_native); + if(dst_native) HeapFree(GetProcessHeap(), 0, dst_native); + if(dststr_libc) HeapFree(GetProcessHeap(), 0, dststr_libc); + return 0; + } + dstlen = returned_len; + + /* Convert a libc Unicode string to the destination string. */ + for(str_idx = 0; str_idx < dstlen; str_idx++) + { + dststr[str_idx] = dststr_libc[str_idx]; + } + TRACE_(string)("1st 4 int sized chunks of dststr = %x %x %x %x\n", + *(((int *)dststr) + 0), + *(((int *)dststr) + 1), + *(((int *)dststr) + 2), + *(((int *)dststr) + 3)); + } + else + { + dstlen = returned_len; + } + TRACE_(string)("dstlen (return) = %d\n", dstlen); + if(srcstr_libc) HeapFree(GetProcessHeap(), 0, srcstr_libc); + if(src_native) HeapFree(GetProcessHeap(), 0, src_native); + if(dst_native) HeapFree(GetProcessHeap(), 0, dst_native); + if(dststr_libc) HeapFree(GetProcessHeap(), 0, dststr_libc); + return dstlen; } else { int (*f)(int)=identity; + if (dstlen==0) + return srclen; + if (dstlen