From 85d4281616d685fdbd1bb6ec89c5e85c25888c23 Mon Sep 17 00:00:00 2001 From: Dmitry Timoshkov Date: Fri, 27 Jun 2003 19:02:23 +0000 Subject: [PATCH] Implement LCMapString using unicode collation tables. Move CompareString and LCMapString to dlls/kernel/locale.c. --- configure | 5 - configure.ac | 1 - dlls/kernel/Makefile.in | 3 +- dlls/kernel/locale.c | 333 ++++++++++- dlls/kernel/tests/locale.c | 272 ++++++++- dlls/ntdll/debugtools.c | 7 +- include/wine/unicode.h | 4 + include/winnls.h | 4 + libs/unicode/Makefile.in | 2 + libs/unicode/mbtowc.c | 3 +- libs/unicode/sortkey.c | 154 ++++++ libs/unicode/utf8.c | 1 - libs/unicode/wctomb.c | 1 - libs/unicode/wine_unicode.def | 1 + ole/ole2nls.c | 1218 ----------------------------------------- 15 files changed, 758 insertions(+), 1251 deletions(-) create mode 100644 libs/unicode/sortkey.c delete mode 100644 ole/ole2nls.c diff --git a/configure b/configure index c63f3bd3889..f33b0d550ad 100755 --- a/configure +++ b/configure @@ -16344,8 +16344,6 @@ esac ac_config_commands="$ac_config_commands objects" - ac_config_commands="$ac_config_commands ole" - ac_config_commands="$ac_config_commands programs/regapi/tests" ac_config_commands="$ac_config_commands programs/regedit/tests" @@ -17118,7 +17116,6 @@ do "misc" ) CONFIG_COMMANDS="$CONFIG_COMMANDS misc" ;; "msdos" ) CONFIG_COMMANDS="$CONFIG_COMMANDS msdos" ;; "objects" ) CONFIG_COMMANDS="$CONFIG_COMMANDS objects" ;; - "ole" ) CONFIG_COMMANDS="$CONFIG_COMMANDS ole" ;; "programs/regapi/tests" ) CONFIG_COMMANDS="$CONFIG_COMMANDS programs/regapi/tests" ;; "programs/regedit/tests" ) CONFIG_COMMANDS="$CONFIG_COMMANDS programs/regedit/tests" ;; "relay32" ) CONFIG_COMMANDS="$CONFIG_COMMANDS relay32" ;; @@ -17857,8 +17854,6 @@ echo "$as_me: creating misc" >&6;} && mkdir "misc") ;; echo "$as_me: creating msdos" >&6;} && mkdir "msdos") ;; objects ) test -d "objects" || ({ echo "$as_me:$LINENO: creating objects" >&5 echo "$as_me: creating objects" >&6;} && mkdir "objects") ;; - ole ) test -d "ole" || ({ echo "$as_me:$LINENO: creating ole" >&5 -echo "$as_me: creating ole" >&6;} && mkdir "ole") ;; programs/regapi/tests ) test -d "programs/regapi/tests" || ({ echo "$as_me:$LINENO: creating programs/regapi/tests" >&5 echo "$as_me: creating programs/regapi/tests" >&6;} && mkdir "programs/regapi/tests") ;; programs/regedit/tests ) test -d "programs/regedit/tests" || ({ echo "$as_me:$LINENO: creating programs/regedit/tests" >&5 diff --git a/configure.ac b/configure.ac index 01cf40ea50a..dd71ef07882 100644 --- a/configure.ac +++ b/configure.ac @@ -1351,7 +1351,6 @@ WINE_CONFIG_EXTRA_DIR(memory) WINE_CONFIG_EXTRA_DIR(misc) WINE_CONFIG_EXTRA_DIR(msdos) WINE_CONFIG_EXTRA_DIR(objects) -WINE_CONFIG_EXTRA_DIR(ole) WINE_CONFIG_EXTRA_DIR(programs/regapi/tests) WINE_CONFIG_EXTRA_DIR(programs/regedit/tests) WINE_CONFIG_EXTRA_DIR(relay32) diff --git a/dlls/kernel/Makefile.in b/dlls/kernel/Makefile.in index 403951a98b3..9ddddfcba15 100644 --- a/dlls/kernel/Makefile.in +++ b/dlls/kernel/Makefile.in @@ -20,7 +20,6 @@ SPEC_SRCS16 = \ windebug.spec C_SRCS = \ - $(TOPOBJDIR)/ole/ole2nls.c \ atom.c \ change.c \ comm.c \ @@ -65,7 +64,7 @@ MC_SRCS = \ messages/winerr_enu.mc SUBDIRS = tests -EXTRASUBDIRS = messages nls $(TOPOBJDIR)/ole +EXTRASUBDIRS = messages nls @MAKE_DLL_RULES@ diff --git a/dlls/kernel/locale.c b/dlls/kernel/locale.c index 0ddbd4cf4fe..b99051962c2 100644 --- a/dlls/kernel/locale.c +++ b/dlls/kernel/locale.c @@ -535,7 +535,7 @@ static INT get_registry_locale_info( LPCWSTR value, LPWSTR buffer, INT len ) * GetLocaleInfoA (KERNEL32.@) * * NOTES - * LANG_NEUTRAL is equal to LOCALE_SYSTEM_DEFAULT + * LOCALE_NEUTRAL is equal to LOCALE_SYSTEM_DEFAULT * * MS online documentation states that the string returned is NULL terminated * except for LOCALE_FONTSIGNATURE which "will return a non-NULL @@ -593,7 +593,7 @@ INT WINAPI GetLocaleInfoA( LCID lcid, LCTYPE lctype, LPSTR buffer, INT len ) * GetLocaleInfoW (KERNEL32.@) * * NOTES - * LANG_NEUTRAL is equal to LOCALE_SYSTEM_DEFAULT + * LOCALE_NEUTRAL is equal to LOCALE_SYSTEM_DEFAULT * * MS online documentation states that the string returned is NULL terminated * except for LOCALE_FONTSIGNATURE which "will return a non-NULL @@ -617,8 +617,8 @@ INT WINAPI GetLocaleInfoW( LCID lcid, LCTYPE lctype, LPWSTR buffer, INT len ) } if (!len) buffer = NULL; - if (lcid == LOCALE_NEUTRAL || lcid == LANG_SYSTEM_DEFAULT) lcid = GetSystemDefaultLCID(); - else if (lcid == LANG_USER_DEFAULT) lcid = GetUserDefaultLCID(); + if (lcid == LOCALE_NEUTRAL || lcid == LOCALE_SYSTEM_DEFAULT) lcid = GetSystemDefaultLCID(); + else if (lcid == LOCALE_USER_DEFAULT) lcid = GetUserDefaultLCID(); lcflags = lctype & LOCALE_LOCALEINFOFLAGSMASK; lctype &= ~LOCALE_LOCALEINFOFLAGSMASK; @@ -705,8 +705,8 @@ BOOL WINAPI SetLocaleInfoA(LCID lcid, LCTYPE lctype, LPCSTR data) DWORD len; BOOL ret; - if (lcid == LOCALE_NEUTRAL || lcid == LANG_SYSTEM_DEFAULT) lcid = GetSystemDefaultLCID(); - else if (lcid == LANG_USER_DEFAULT) lcid = GetUserDefaultLCID(); + if (lcid == LOCALE_NEUTRAL || lcid == LOCALE_SYSTEM_DEFAULT) lcid = GetSystemDefaultLCID(); + else if (lcid == LOCALE_USER_DEFAULT) lcid = GetUserDefaultLCID(); if (!(lctype & LOCALE_USE_CP_ACP)) codepage = get_lcid_codepage( lcid ); len = MultiByteToWideChar( codepage, 0, data, -1, NULL, 0 ); @@ -733,8 +733,8 @@ BOOL WINAPI SetLocaleInfoW( LCID lcid, LCTYPE lctype, LPCWSTR data ) NTSTATUS status; HKEY hkey; - if (lcid == LOCALE_NEUTRAL || lcid == LANG_SYSTEM_DEFAULT) lcid = GetSystemDefaultLCID(); - else if (lcid == LANG_USER_DEFAULT) lcid = GetUserDefaultLCID(); + if (lcid == LOCALE_NEUTRAL || lcid == LOCALE_SYSTEM_DEFAULT) lcid = GetSystemDefaultLCID(); + else if (lcid == LOCALE_USER_DEFAULT) lcid = GetUserDefaultLCID(); if (!(value = get_locale_value_name( lctype ))) { @@ -780,8 +780,8 @@ LCID WINAPI GetThreadLocale(void) */ BOOL WINAPI SetThreadLocale( LCID lcid ) /* [in] Locale identifier */ { - if (lcid == LOCALE_NEUTRAL || lcid == LANG_SYSTEM_DEFAULT) lcid = GetSystemDefaultLCID(); - else if (lcid == LANG_USER_DEFAULT) lcid = GetUserDefaultLCID(); + if (lcid == LOCALE_NEUTRAL || lcid == LOCALE_SYSTEM_DEFAULT) lcid = GetSystemDefaultLCID(); + else if (lcid == LOCALE_USER_DEFAULT) lcid = GetUserDefaultLCID(); NtCurrentTeb()->CurrentLocale = lcid; NtCurrentTeb()->code_page = get_lcid_codepage( lcid ); @@ -994,6 +994,319 @@ BOOL WINAPI GetStringTypeExA( LCID locale, DWORD type, LPCSTR src, INT count, LP } +/************************************************************************* + * LCMapStringW (KERNEL32.@) + */ +INT WINAPI LCMapStringW(LCID lcid, DWORD flags, LPCWSTR src, INT srclen, + LPWSTR dst, INT dstlen) +{ + LPWSTR dst_ptr; + + if (!src || !srclen || dstlen < 0) + { + SetLastError(ERROR_INVALID_PARAMETER); + return 0; + } + + /* mutually exclusive flags */ + if ((flags & (LCMAP_LOWERCASE | LCMAP_UPPERCASE)) == (LCMAP_LOWERCASE | LCMAP_UPPERCASE) || + (flags & (LCMAP_HIRAGANA | LCMAP_KATAKANA)) == (LCMAP_HIRAGANA | LCMAP_KATAKANA) || + (flags & (LCMAP_HALFWIDTH | LCMAP_FULLWIDTH)) == (LCMAP_HALFWIDTH | LCMAP_FULLWIDTH) || + (flags & (LCMAP_TRADITIONAL_CHINESE | LCMAP_SIMPLIFIED_CHINESE)) == (LCMAP_TRADITIONAL_CHINESE | LCMAP_SIMPLIFIED_CHINESE)) + { + SetLastError(ERROR_INVALID_FLAGS); + return 0; + } + + if (!dstlen) dst = NULL; + + if (lcid == LOCALE_NEUTRAL || lcid == LOCALE_SYSTEM_DEFAULT) lcid = GetSystemDefaultLCID(); + else if (lcid == LOCALE_USER_DEFAULT) lcid = GetUserDefaultLCID(); + + if (flags & LCMAP_SORTKEY) + { + if (src == dst) + { + SetLastError(ERROR_INVALID_FLAGS); + return 0; + } + + if (srclen < 0) srclen = strlenW(src); + + TRACE("(0x%04lx,0x%08lx,%s,%d,%p,%d)\n", + lcid, flags, debugstr_wn(src, srclen), srclen, dst, dstlen); + + return wine_get_sortkey(flags, src, srclen, (char *)dst, dstlen); + } + + /* SORT_STRINGSORT must be used exclusively with LCMAP_SORTKEY */ + if (flags & SORT_STRINGSORT) + { + SetLastError(ERROR_INVALID_FLAGS); + return 0; + } + + if (srclen < 0) srclen = strlenW(src) + 1; + + TRACE("(0x%04lx,0x%08lx,%s,%d,%p,%d)\n", + lcid, flags, debugstr_wn(src, srclen), srclen, dst, dstlen); + + if (!dst) /* return required string length */ + { + INT len; + + for (len = 0; srclen; src++, srclen--) + { + WCHAR wch = *src; + /* tests show that win2k just ignores NORM_IGNORENONSPACE, + * and skips white space and punctuation characters for + * NORM_IGNORESYMBOLS. + */ + if ((flags & NORM_IGNORESYMBOLS) && (get_char_typeW(wch) & (C1_PUNCT | C1_SPACE))) + continue; + len++; + } + return len; + } + + if (flags & LCMAP_UPPERCASE) + { + for (dst_ptr = dst; srclen && dstlen; src++, srclen--) + { + WCHAR wch = *src; + if ((flags & NORM_IGNORESYMBOLS) && (get_char_typeW(wch) & (C1_PUNCT | C1_SPACE))) + continue; + *dst_ptr++ = toupperW(wch); + dstlen--; + } + } + else if (flags & LCMAP_LOWERCASE) + { + for (dst_ptr = dst; srclen && dstlen; src++, srclen--) + { + WCHAR wch = *src; + if ((flags & NORM_IGNORESYMBOLS) && (get_char_typeW(wch) & (C1_PUNCT | C1_SPACE))) + continue; + *dst_ptr++ = tolowerW(wch); + dstlen--; + } + } + else + { + if (src == dst) + { + SetLastError(ERROR_INVALID_FLAGS); + return 0; + } + for (dst_ptr = dst; srclen && dstlen; src++, srclen--) + { + WCHAR wch = *src; + if ((flags & NORM_IGNORESYMBOLS) && (get_char_typeW(wch) & (C1_PUNCT | C1_SPACE))) + continue; + *dst_ptr++ = wch; + dstlen--; + } + } + + return dst_ptr - dst; +} + +/************************************************************************* + * LCMapStringA (KERNEL32.@) + */ +INT WINAPI LCMapStringA(LCID lcid, DWORD flags, LPCSTR src, INT srclen, + LPSTR dst, INT dstlen) +{ + WCHAR bufW[128]; + LPWSTR srcW, dstW; + INT ret = 0, srclenW, dstlenW; + UINT locale_cp; + + if (!src || !srclen || dstlen < 0) + { + SetLastError(ERROR_INVALID_PARAMETER); + return 0; + } + + GetLocaleInfoW(lcid, LOCALE_IDEFAULTANSICODEPAGE | LOCALE_RETURN_NUMBER, + (WCHAR *)&locale_cp, (sizeof(locale_cp)/sizeof(WCHAR))); + + srclenW = MultiByteToWideChar(locale_cp, 0, src, srclen, bufW, 128); + if (srclenW) + srcW = bufW; + else + { + srclenW = MultiByteToWideChar(locale_cp, 0, src, srclen, NULL, 0); + srcW = HeapAlloc(GetProcessHeap(), 0, srclenW * sizeof(WCHAR)); + if (!srcW) + { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + return 0; + } + MultiByteToWideChar(locale_cp, 0, src, srclen, srcW, srclenW); + } + + if (flags & LCMAP_SORTKEY) + { + if (src == dst) + { + SetLastError(ERROR_INVALID_FLAGS); + goto map_string_exit; + } + ret = wine_get_sortkey(flags, srcW, srclenW, dst, dstlen); + } + + if (flags & SORT_STRINGSORT) + { + SetLastError(ERROR_INVALID_FLAGS); + goto map_string_exit; + } + + dstlenW = LCMapStringW(lcid, flags, srcW, srclenW, NULL, 0); + dstW = HeapAlloc(GetProcessHeap(), 0, dstlenW * sizeof(WCHAR)); + if (!dstW) + { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + goto map_string_exit; + } + + LCMapStringW(lcid, flags, srcW, srclenW, dstW, dstlenW); + ret = WideCharToMultiByte(locale_cp, 0, dstW, dstlenW, dst, dstlen, NULL, NULL); + HeapFree(GetProcessHeap(), 0, dstW); + +map_string_exit: + if (srcW != bufW) HeapFree(GetProcessHeap(), 0, srcW); + return ret; +} + +/****************************************************************************** + * CompareStringW (KERNEL32.@) + */ +INT WINAPI CompareStringW(LCID lcid, DWORD style, + LPCWSTR str1, INT len1, LPCWSTR str2, INT len2) +{ + INT ret, len; + + if (!str1 || !str2) + { + SetLastError(ERROR_INVALID_PARAMETER); + return 0; + } + + if (len1 < 0) len1 = lstrlenW(str1); + if (len2 < 0) len2 = lstrlenW(str2); + + len = (len1 < len2) ? len1 : len2; + ret = (style & NORM_IGNORECASE) ? strncmpiW(str1, str2, len) : + strncmpW(str1, str2, len); + + if (ret) /* need to translate result */ + return (ret < 0) ? CSTR_LESS_THAN : CSTR_GREATER_THAN; + + if (len1 == len2) return CSTR_EQUAL; + /* the longer one is lexically greater */ + return (len1 < len2) ? CSTR_LESS_THAN : CSTR_GREATER_THAN; +} + +/****************************************************************************** + * CompareStringA (KERNEL32.@) + */ +INT WINAPI CompareStringA(LCID lcid, DWORD style, + LPCSTR str1, INT len1, LPCSTR str2, INT len2) +{ + WCHAR buf1W[128], buf2W[128]; + LPWSTR str1W, str2W; + INT len1W, len2W, ret; + UINT locale_cp; + + if (!str1 || !str2) + { + SetLastError(ERROR_INVALID_PARAMETER); + return 0; + } + + GetLocaleInfoW(lcid, LOCALE_IDEFAULTANSICODEPAGE | LOCALE_RETURN_NUMBER, + (WCHAR *)&locale_cp, (sizeof(locale_cp)/sizeof(WCHAR))); + + len1W = MultiByteToWideChar(locale_cp, 0, str1, len1, buf1W, 128); + if (len1W) + str1W = buf1W; + else + { + len1W = MultiByteToWideChar(locale_cp, 0, str1, len1, NULL, 0); + str1W = HeapAlloc(GetProcessHeap(), 0, len1W * sizeof(WCHAR)); + if (!str1W) + { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + return 0; + } + MultiByteToWideChar(locale_cp, 0, str1, len1, str1W, len1W); + } + len2W = MultiByteToWideChar(locale_cp, 0, str2, len2, buf2W, 128); + if (len2W) + str2W = buf2W; + else + { + len2W = MultiByteToWideChar(locale_cp, 0, str2, len2, NULL, 0); + str2W = HeapAlloc(GetProcessHeap(), 0, len2W * sizeof(WCHAR)); + if (!str2W) + { + if (str1W != buf1W) HeapFree(GetProcessHeap(), 0, str1W); + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + return 0; + } + MultiByteToWideChar(locale_cp, 0, str2, len2, str2W, len2W); + } + + ret = CompareStringW(lcid, style, str1W, len1W, str2W, len2W); + + if (str1W != buf1W) HeapFree(GetProcessHeap(), 0, str1W); + if (str2W != buf2W) HeapFree(GetProcessHeap(), 0, str2W); + return ret; +} + +/************************************************************************* + * lstrcmp (KERNEL32.@) + * lstrcmpA (KERNEL32.@) + */ +int WINAPI lstrcmpA(LPCSTR str1, LPCSTR str2) +{ + int ret = CompareStringA(GetThreadLocale(), 0, str1, -1, str2, -1); + if (ret) ret -= 2; + return ret; +} + +/************************************************************************* + * lstrcmpi (KERNEL32.@) + * lstrcmpiA (KERNEL32.@) + */ +int WINAPI lstrcmpiA(LPCSTR str1, LPCSTR str2) +{ + int ret = CompareStringA(GetThreadLocale(), NORM_IGNORECASE, str1, -1, str2, -1); + if (ret) ret -= 2; + return ret; +} + +/************************************************************************* + * lstrcmpW (KERNEL32.@) + */ +int WINAPI lstrcmpW(LPCWSTR str1, LPCWSTR str2) +{ + int ret = CompareStringW(GetThreadLocale(), 0, str1, -1, str2, -1); + if (ret) ret -= 2; + return ret; +} + +/************************************************************************* + * lstrcmpiW (KERNEL32.@) + */ +int WINAPI lstrcmpiW(LPCWSTR str1, LPCWSTR str2) +{ + int ret = CompareStringW(GetThreadLocale(), NORM_IGNORECASE, str1, -1, str2, -1); + if (ret) ret -= 2; + return ret; +} + /****************************************************************************** * LOCALE_Init */ diff --git a/dlls/kernel/tests/locale.c b/dlls/kernel/tests/locale.c index 063cff4aafa..b985ae68276 100644 --- a/dlls/kernel/tests/locale.c +++ b/dlls/kernel/tests/locale.c @@ -3,6 +3,7 @@ * Test run on win2K (French) * * Copyright (c) 2002 YASAR Mehmet + * Copyright 2003 Dmitry Timoshkov * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -696,30 +697,282 @@ char buffer1[BUFFER_SIZE], buffer2[BUFFER_SIZE]; strcpy(buffer1, "Salut"); strcpy(buffer2, "Salute"); ret = CompareStringA(lcid, NORM_IGNORECASE, buffer1, -1, buffer2, -1); - ok (ret== 1, "CompareStringA (st1=%s str2=%s) expected result=1", buffer1, buffer2); + ok(ret == 1, "CompareStringA (st1=%s str2=%s) expected result=1, got %d", buffer1, buffer2, ret); strcpy(buffer1, "Salut"); strcpy(buffer2, "saLuT"); ret = CompareStringA(lcid, NORM_IGNORECASE, buffer1, -1, buffer2, -1); - ok (ret== 2, "CompareStringA (st1=%s str2=%s) expected result=2", buffer1, buffer2); + ok(ret == 2, "CompareStringA (st1=%s str2=%s) expected result=2, got %d", buffer1, buffer2, ret); strcpy(buffer1, "Salut"); strcpy(buffer2, "hola"); ret = CompareStringA(lcid, NORM_IGNORECASE, buffer1, -1, buffer2, -1); - ok (ret== 3, "CompareStringA (st1=%s str2=%s) expected result=3", buffer1, buffer2); + ok(ret == 3, "CompareStringA (st1=%s str2=%s) expected result=3, got %d", buffer1, buffer2, ret); - strcpy(buffer1, "héhé"); strcpy(buffer2, "hèhè"); + strcpy(buffer1, "haha"); strcpy(buffer2, "hoho"); ret = CompareStringA(lcid, NORM_IGNORECASE, buffer1, -1, buffer2, -1); - ok (ret== 1, "CompareStringA (st1=%s str2=%s) expected result=1", buffer1, buffer2); + ok (ret == 1, "CompareStringA (st1=%s str2=%s) expected result=1, got %d", buffer1, buffer2, ret); lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT ); - strcpy(buffer1, "héhé"); strcpy(buffer2, "hèhè"); + strcpy(buffer1, "haha"); strcpy(buffer2, "hoho"); ret = CompareStringA(lcid, NORM_IGNORECASE, buffer1, -1, buffer2, -1); - ok (ret== 1, "CompareStringA (st1=%s str2=%s) expected result=1", buffer1, buffer2); + ok (ret == 1, "CompareStringA (st1=%s str2=%s) expected result=1, got %d", buffer1, buffer2, ret); ret = CompareStringA(lcid, NORM_IGNORECASE, buffer1, -1, buffer2, 0); - ok (ret== 3, "CompareStringA (st1=%s str2=%s) expected result=3", buffer1, buffer2); + ok (ret == 3, "CompareStringA (st1=%s str2=%s) expected result=3, got %d", buffer1, buffer2, ret); } +void test_LCMapStringA(void) +{ + int ret, ret2; + char buf[256], buf2[256]; + static const char upper_case[] = "\tJUST! A, TEST; STRING 1/*+-.\r\n"; + static const char lower_case[] = "\tjust! a, test; string 1/*+-.\r\n"; + static const char symbols_stripped[] = "justateststring1"; + + ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE | LCMAP_UPPERCASE, + upper_case, -1, buf, sizeof(buf)); + ok(!ret, "LCMAP_LOWERCASE and LCMAP_UPPERCASE are mutually exclusive\n"); + ok(GetLastError() == ERROR_INVALID_FLAGS, + "unexpected error code %ld\n", GetLastError()); + + ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_HIRAGANA | LCMAP_KATAKANA, + upper_case, -1, buf, sizeof(buf)); + ok(!ret, "LCMAP_HIRAGANA and LCMAP_KATAKANA are mutually exclusive\n"); + ok(GetLastError() == ERROR_INVALID_FLAGS, + "unexpected error code %ld\n", GetLastError()); + + ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_HALFWIDTH | LCMAP_FULLWIDTH, + + upper_case, -1, buf, sizeof(buf)); + ok(!ret, "LCMAP_HALFWIDTH | LCMAP_FULLWIDTH are mutually exclusive\n"); + ok(GetLastError() == ERROR_INVALID_FLAGS, + "unexpected error code %ld\n", GetLastError()); + + ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_TRADITIONAL_CHINESE | LCMAP_SIMPLIFIED_CHINESE, + upper_case, -1, buf, sizeof(buf)); + ok(!ret, "LCMAP_TRADITIONAL_CHINESE and LCMAP_SIMPLIFIED_CHINESE are mutually exclusive\n"); + ok(GetLastError() == ERROR_INVALID_FLAGS, + "unexpected error code %ld\n", GetLastError()); + + /* SORT_STRINGSORT must be used exclusively with LCMAP_SORTKEY */ + SetLastError(0xdeadbeef); + ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE | SORT_STRINGSORT, + upper_case, -1, buf, sizeof(buf)); + ok(GetLastError() == ERROR_INVALID_FLAGS, "expected ERROR_INVALID_FLAGS, got %ld\n", GetLastError()); + ok(!ret, "SORT_STRINGSORT without LCMAP_SORTKEY must fail\n"); + + /* test LCMAP_LOWERCASE */ + ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE, + upper_case, -1, buf, sizeof(buf)); + ok(ret == lstrlenA(upper_case) + 1, + "ret %d, error %ld, expected value %d\n", + ret, GetLastError(), lstrlenA(upper_case) + 1); + ok(!lstrcmpA(buf, lower_case), "LCMapStringA should return %s, but not %s\n", lower_case, buf); + + /* test LCMAP_UPPERCASE */ + ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE, + lower_case, -1, buf, sizeof(buf)); + ok(ret == lstrlenA(lower_case) + 1, + "ret %d, error %ld, expected value %d\n", + ret, GetLastError(), lstrlenA(lower_case) + 1); + ok(!lstrcmpA(buf, upper_case), "LCMapStringA should return %s, but not %s\n", upper_case, buf); + + /* LCMAP_UPPERCASE or LCMAP_LOWERCASE should accept src == dst */ + lstrcpyA(buf, lower_case); + ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE, + buf, -1, buf, sizeof(buf)); + if (!ret) /* Win9x */ + trace("Ignoring LCMapStringA(LCMAP_UPPERCASE, buf, buf) error on Win9x\n"); + else + { + ok(ret == lstrlenA(lower_case) + 1, + "ret %d, error %ld, expected value %d\n", + ret, GetLastError(), lstrlenA(lower_case) + 1); + ok(!lstrcmpA(buf, upper_case), "LCMapStringA should return %s, but not %s\n", upper_case, buf); + } + lstrcpyA(buf, upper_case); + ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE, + buf, -1, buf, sizeof(buf)); + if (!ret) /* Win9x */ + trace("Ignoring LCMapStringA(LCMAP_LOWERCASE, buf, buf) error on Win9x\n"); + else + { + ok(ret == lstrlenA(upper_case) + 1, + "ret %d, error %ld, expected value %d\n", + ret, GetLastError(), lstrlenA(lower_case) + 1); + ok(!lstrcmpA(buf, lower_case), "LCMapStringA should return %s, but not %s\n", lower_case, buf); + } + + /* otherwise src == dst should fail */ + SetLastError(0xdeadbeef); + ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | LCMAP_UPPERCASE, + buf, 10, buf, sizeof(buf)); + ok(GetLastError() == ERROR_INVALID_FLAGS /* NT */ || + GetLastError() == ERROR_INVALID_PARAMETER /* Win9x */, + "unexpected error code %ld\n", GetLastError()); + ok(!ret, "src == dst without LCMAP_UPPERCASE or LCMAP_LOWERCASE must fail\n"); + + /* test whether '\0' is always appended */ + ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY, + upper_case, -1, buf, sizeof(buf)); + ok(ret, "LCMapStringA must succeed\n"); + ret2 = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY, + upper_case, lstrlenA(upper_case), buf2, sizeof(buf2)); + ok(ret, "LCMapStringA must succeed\n"); + ok(ret == ret2, "lengths of sort keys must be equal\n"); + ok(!lstrcmpA(buf, buf2), "sort keys must be equal\n"); + + /* test LCMAP_SORTKEY | NORM_IGNORECASE */ + ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | NORM_IGNORECASE, + upper_case, -1, buf, sizeof(buf)); + ok(ret, "LCMapStringA must succeed\n"); + ret2 = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_SORTKEY, + lower_case, -1, buf2, sizeof(buf2)); + ok(ret2, "LCMapStringA must succeed\n"); + ok(ret == ret2, "lengths of sort keys must be equal\n"); + ok(!lstrcmpA(buf, buf2), "sort keys must be equal\n"); + + /* test NORM_IGNORENONSPACE */ + lstrcpyA(buf, "foo"); + ret = LCMapStringA(LOCALE_USER_DEFAULT, NORM_IGNORENONSPACE, + lower_case, -1, buf, sizeof(buf)); + ok(ret == lstrlenA(lower_case) + 1, "LCMapStringA should return %d, ret = %d\n", + lstrlenA(lower_case) + 1, ret); + ok(!lstrcmpA(buf, lower_case), "LCMapStringA should return %s, but not %s\n", lower_case, buf); + + /* test NORM_IGNORESYMBOLS */ + lstrcpyA(buf, "foo"); + ret = LCMapStringA(LOCALE_USER_DEFAULT, NORM_IGNORESYMBOLS, + lower_case, -1, buf, sizeof(buf)); + ok(ret == lstrlenA(symbols_stripped) + 1, "LCMapStringA should return %d, ret = %d\n", + lstrlenA(symbols_stripped) + 1, ret); + ok(!lstrcmpA(buf, symbols_stripped), "LCMapStringA should return %s, but not %s\n", lower_case, buf); +} + +void test_LCMapStringW(void) +{ + int ret, ret2; + WCHAR buf[256], buf2[256]; + char *p_buf = (char *)buf, *p_buf2 = (char *)buf2; + static const WCHAR upper_case[] = {'\t','J','U','S','T','!',' ','A',',',' ','T','E','S','T',';',' ','S','T','R','I','N','G',' ','1','/','*','+','-','.','\r','\n',0}; + static const WCHAR lower_case[] = {'\t','j','u','s','t','!',' ','a',',',' ','t','e','s','t',';',' ','s','t','r','i','n','g',' ','1','/','*','+','-','.','\r','\n',0}; + static const WCHAR symbols_stripped[] = {'j','u','s','t','a','t','e','s','t','s','t','r','i','n','g','1',0}; + static const WCHAR fooW[] = {'f','o','o',0}; + + ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE | LCMAP_UPPERCASE, + upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR)); + if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) + { + trace("Skipping LCMapStringW tests on Win9x\n"); + return; + } + ok(!ret, "LCMAP_LOWERCASE and LCMAP_UPPERCASE are mutually exclusive\n"); + ok(GetLastError() == ERROR_INVALID_FLAGS, + "unexpected error code %ld\n", GetLastError()); + + ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_HIRAGANA | LCMAP_KATAKANA, + upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR)); + ok(!ret, "LCMAP_HIRAGANA and LCMAP_KATAKANA are mutually exclusive\n"); + ok(GetLastError() == ERROR_INVALID_FLAGS, + "unexpected error code %ld\n", GetLastError()); + + ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_HALFWIDTH | LCMAP_FULLWIDTH, + upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR)); + ok(!ret, "LCMAP_HALFWIDTH | LCMAP_FULLWIDTH are mutually exclusive\n"); + ok(GetLastError() == ERROR_INVALID_FLAGS, + "unexpected error code %ld\n", GetLastError()); + + ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_TRADITIONAL_CHINESE | LCMAP_SIMPLIFIED_CHINESE, + upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR)); + ok(!ret, "LCMAP_TRADITIONAL_CHINESE and LCMAP_SIMPLIFIED_CHINESE are mutually exclusive\n"); + ok(GetLastError() == ERROR_INVALID_FLAGS, + "unexpected error code %ld\n", GetLastError()); + + /* SORT_STRINGSORT must be used exclusively with LCMAP_SORTKEY */ + SetLastError(0xdeadbeef); + ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE | SORT_STRINGSORT, + upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR)); + ok(GetLastError() == ERROR_INVALID_FLAGS, "expected ERROR_INVALID_FLAGS, got %ld\n", GetLastError()); + ok(!ret, "SORT_STRINGSORT without LCMAP_SORTKEY must fail\n"); + + /* test LCMAP_LOWERCASE */ + ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE, + upper_case, -1, buf, sizeof(buf)/sizeof(WCHAR)); + ok(ret == lstrlenW(upper_case) + 1, + "ret %d, error %ld, expected value %d\n", + ret, GetLastError(), lstrlenW(upper_case) + 1); + ok(!lstrcmpW(buf, lower_case), "string compare mismatch\n"); + + /* test LCMAP_UPPERCASE */ + ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE, + lower_case, -1, buf, sizeof(buf)/sizeof(WCHAR)); + ok(ret == lstrlenW(lower_case) + 1, + "ret %d, error %ld, expected value %d\n", + ret, GetLastError(), lstrlenW(lower_case) + 1); + ok(!lstrcmpW(buf, upper_case), "string compare mismatch\n"); + + /* LCMAP_UPPERCASE or LCMAP_LOWERCASE should accept src == dst */ + lstrcpyW(buf, lower_case); + ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE, + buf, -1, buf, sizeof(buf)/sizeof(WCHAR)); + ok(ret == lstrlenW(lower_case) + 1, + "ret %d, error %ld, expected value %d\n", + ret, GetLastError(), lstrlenW(lower_case) + 1); + ok(!lstrcmpW(buf, upper_case), "string compare mismatch\n"); + + lstrcpyW(buf, upper_case); + ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE, + buf, -1, buf, sizeof(buf)/sizeof(WCHAR)); + ok(ret == lstrlenW(upper_case) + 1, + "ret %d, error %ld, expected value %d\n", + ret, GetLastError(), lstrlenW(lower_case) + 1); + ok(!lstrcmpW(buf, lower_case), "string compare mismatch\n"); + + /* otherwise src == dst should fail */ + SetLastError(0xdeadbeef); + ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | LCMAP_UPPERCASE, + buf, 10, buf, sizeof(buf)); + ok(GetLastError() == ERROR_INVALID_FLAGS /* NT */ || + GetLastError() == ERROR_INVALID_PARAMETER /* Win9x */, + "unexpected error code %ld\n", GetLastError()); + ok(!ret, "src == dst without LCMAP_UPPERCASE or LCMAP_LOWERCASE must fail\n"); + + /* test whether '\0' is always appended */ + ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_SORTKEY, + upper_case, -1, buf, sizeof(buf)); + ok(ret, "LCMapStringW must succeed\n"); + ret2 = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_SORTKEY, + upper_case, lstrlenW(upper_case), buf2, sizeof(buf2)); + ok(ret, "LCMapStringW must succeed\n"); + ok(ret == ret2, "lengths of sort keys must be equal\n"); + ok(!lstrcmpA(p_buf, p_buf2), "sort keys must be equal\n"); + + /* test LCMAP_SORTKEY | NORM_IGNORECASE */ + ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | NORM_IGNORECASE, + upper_case, -1, buf, sizeof(buf)); + ok(ret, "LCMapStringW must succeed\n"); + ret2 = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_SORTKEY, + lower_case, -1, buf2, sizeof(buf2)); + ok(ret2, "LCMapStringW must succeed\n"); + ok(ret == ret2, "lengths of sort keys must be equal\n"); + ok(!lstrcmpA(p_buf, p_buf2), "sort keys must be equal\n"); + + /* test NORM_IGNORENONSPACE */ + lstrcpyW(buf, fooW); + ret = LCMapStringW(LOCALE_USER_DEFAULT, NORM_IGNORENONSPACE, + lower_case, -1, buf, sizeof(buf)/sizeof(WCHAR)); + ok(ret == lstrlenW(lower_case) + 1, "LCMapStringW should return %d, ret = %d\n", + lstrlenW(lower_case) + 1, ret); + ok(!lstrcmpW(buf, lower_case), "string comparison mismatch\n"); + + /* test NORM_IGNORESYMBOLS */ + lstrcpyW(buf, fooW); + ret = LCMapStringW(LOCALE_USER_DEFAULT, NORM_IGNORESYMBOLS, + lower_case, -1, buf, sizeof(buf)/sizeof(WCHAR)); + ok(ret == lstrlenW(symbols_stripped) + 1, "LCMapStringW should return %d, ret = %d\n", + lstrlenW(symbols_stripped) + 1, ret); + ok(!lstrcmpW(buf, symbols_stripped), "string comparison mismatch\n"); +} START_TEST(locale) { @@ -733,4 +986,7 @@ START_TEST(locale) TestGetNumberFormat(); TestGetCurrencyFormat(); TestCompareStringA(); + + test_LCMapStringW(); + test_LCMapStringA(); } diff --git a/dlls/ntdll/debugtools.c b/dlls/ntdll/debugtools.c index 2f0f292a1f5..8b0665d18b9 100644 --- a/dlls/ntdll/debugtools.c +++ b/dlls/ntdll/debugtools.c @@ -100,6 +100,7 @@ static inline void release( void *ptr ) /* put an ASCII string into the debug buffer */ inline static char *put_string_a( const char *src, int n ) { + static const char hex[16] = "0123456789abcdef"; char *dst, *res; if (n == -1) n = strlen(src); @@ -123,9 +124,9 @@ inline static char *put_string_a( const char *src, int n ) else { *dst++ = '\\'; - *dst++ = '0' + ((c >> 6) & 7); - *dst++ = '0' + ((c >> 3) & 7); - *dst++ = '0' + ((c >> 0) & 7); + *dst++ = 'x'; + *dst++ = hex[(c >> 4) & 0x0f]; + *dst++ = hex[c & 0x0f]; } } } diff --git a/include/wine/unicode.h b/include/wine/unicode.h index 0dd74c62a55..bea60989ae4 100644 --- a/include/wine/unicode.h +++ b/include/wine/unicode.h @@ -21,6 +21,8 @@ #ifndef __WINE_UNICODE_H #define __WINE_UNICODE_H +#include + #include "windef.h" #include "winnls.h" @@ -71,6 +73,8 @@ extern int wine_cp_wcstombs( const union cptable *table, int flags, extern int wine_utf8_wcstombs( const WCHAR *src, int srclen, char *dst, int dstlen ); extern int wine_utf8_mbstowcs( int flags, const char *src, int srclen, WCHAR *dst, int dstlen ); +extern int wine_get_sortkey( int flags, const WCHAR *src, int srclen, char *dst, int dstlen ); + extern int strcmpiW( const WCHAR *str1, const WCHAR *str2 ); extern int strncmpiW( const WCHAR *str1, const WCHAR *str2, int n ); extern WCHAR *strstrW( const WCHAR *str, const WCHAR *sub ); diff --git a/include/winnls.h b/include/winnls.h index 497ee361b87..cc90af3316b 100644 --- a/include/winnls.h +++ b/include/winnls.h @@ -196,6 +196,10 @@ extern "C" { #define LCMAP_HALFWIDTH 0x00400000 /* map double byte to single byte */ #define LCMAP_FULLWIDTH 0x00800000 /* map single byte to double byte */ +#define LCMAP_LINGUISTIC_CASING 0x01000000 /* use linguistic rules for casing */ +#define LCMAP_SIMPLIFIED_CHINESE 0x02000000 /* map traditional chinese to simplified chinese */ +#define LCMAP_TRADITIONAL_CHINESE 0x04000000 /* map simplified chinese to traditional chinese */ + /* Date Flags for GetDateFormat. */ #define DATE_SHORTDATE 0x00000001 /* use short date picture */ diff --git a/libs/unicode/Makefile.in b/libs/unicode/Makefile.in index b1753fef8cd..d032698359c 100644 --- a/libs/unicode/Makefile.in +++ b/libs/unicode/Makefile.in @@ -70,9 +70,11 @@ CODEPAGES = \ C_SRCS = \ casemap.c \ + collation.c \ compose.c \ cptable.c \ mbtowc.c \ + sortkey.c \ string.c \ utf8.c \ wctomb.c \ diff --git a/libs/unicode/mbtowc.c b/libs/unicode/mbtowc.c index 0494cc58743..27af0902c46 100644 --- a/libs/unicode/mbtowc.c +++ b/libs/unicode/mbtowc.c @@ -20,11 +20,10 @@ #include -#include "winnls.h" #include "wine/unicode.h" /* get the decomposition of a Unicode char */ -static int get_decomposition( WCHAR src, WCHAR *dst, unsigned int dstlen ) +int get_decomposition( WCHAR src, WCHAR *dst, unsigned int dstlen ) { extern const WCHAR unicode_decompose_table[]; const WCHAR *ptr = unicode_decompose_table; diff --git a/libs/unicode/sortkey.c b/libs/unicode/sortkey.c new file mode 100644 index 00000000000..4e8911405f6 --- /dev/null +++ b/libs/unicode/sortkey.c @@ -0,0 +1,154 @@ +/* + * Unicode sort key generation + * + * Copyright 2003 Dmitry Timoshkov + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include "wine/unicode.h" + +extern int get_decomposition(WCHAR src, WCHAR *dst, unsigned int dstlen); + +/* + * flags - normalization NORM_* flags + * + * FIXME: 'variable' flag not handled + */ +int wine_get_sortkey(int flags, const WCHAR *src, int srclen, char *dst, int dstlen) +{ + extern const unsigned int collation_table[]; + WCHAR dummy[4]; /* no decomposition is larger than 4 chars */ + int key_len[4]; + char *key_ptr[4]; + const WCHAR *src_save = src; + int srclen_save = srclen; + + key_len[0] = key_len[1] = key_len[2] = key_len[3] = 0; + for (; srclen; srclen--, src++) + { + int decomposed_len = get_decomposition(*src, dummy, 4); + if (decomposed_len) + { + int i; + for (i = 0; i < decomposed_len; i++) + { + WCHAR wch = dummy[i]; + unsigned int ce; + + /* tests show that win2k just ignores NORM_IGNORENONSPACE, + * and skips white space and punctuation characters for + * NORM_IGNORESYMBOLS. + */ + if ((flags & NORM_IGNORESYMBOLS) && (get_char_typeW(wch) & (C1_PUNCT | C1_SPACE))) + continue; + + if (flags & NORM_IGNORECASE) wch = tolowerW(wch); + + ce = collation_table[collation_table[wch >> 8] + (wch & 0xff)]; + if (ce != (unsigned int)-1) + { + if (ce >> 16) key_len[0] += 2; + if ((ce >> 8) & 0xff) key_len[1]++; + if ((ce >> 4) & 0x0f) key_len[2]++; + /*if (ce & 1) + { + if (wch >> 8) key_len[3]++; + key_len[3]++; + }*/ + } + /*else + { + key_len[0] += 2; + if (wch >> 8) key_len[0]++; + if (wch & 0xff) key_len[0]++; + }*/ + } + } + } + + if (!dstlen) /* compute length */ + /* 4 * '\1' + 1 * '\0' + key length */ + return key_len[0] + key_len[1] + key_len[2] + key_len[3] + 4 + 1; + + if (dstlen < key_len[0] + key_len[1] + key_len[2] + key_len[3] + 4 + 1) + return 0; /* overflow */ + + src = src_save; + srclen = srclen_save; + + key_ptr[0] = dst; + key_ptr[1] = key_ptr[0] + key_len[0] + 1; + key_ptr[2] = key_ptr[1] + key_len[1] + 1; + key_ptr[3] = key_ptr[2] + key_len[2] + 1; + + for (; srclen; srclen--, src++) + { + int decomposed_len = get_decomposition(*src, dummy, 4); + if (decomposed_len) + { + int i; + for (i = 0; i < decomposed_len; i++) + { + WCHAR wch = dummy[i]; + unsigned int ce; + + /* tests show that win2k just ignores NORM_IGNORENONSPACE, + * and skips white space and punctuation characters for + * NORM_IGNORESYMBOLS. + */ + if ((flags & NORM_IGNORESYMBOLS) && (get_char_typeW(wch) & (C1_PUNCT | C1_SPACE))) + continue; + + if (flags & NORM_IGNORECASE) wch = tolowerW(wch); + + ce = collation_table[collation_table[wch >> 8] + (wch & 0xff)]; + if (ce != (unsigned int)-1) + { + WCHAR key; + if ((key = ce >> 16)) + { + *key_ptr[0]++ = key >> 8; + *key_ptr[0]++ = key & 0xff; + } + /* make key 1 start from 2 */ + if ((key = (ce >> 8) & 0xff)) *key_ptr[1]++ = key + 1; + /* make key 2 start from 2 */ + if ((key = (ce >> 4) & 0x0f)) *key_ptr[2]++ = key + 1; + /* key 3 is always a character code */ + /*if (ce & 1) + { + if (wch >> 8) *key_ptr[3]++ = wch >> 8; + if (wch & 0xff) *key_ptr[3]++ = wch & 0xff; + }*/ + } + /*else + { + *key_ptr[0]++ = 0xff; + *key_ptr[0]++ = 0xfe; + if (wch >> 8) *key_ptr[0]++ = wch >> 8; + if (wch & 0xff) *key_ptr[0]++ = wch & 0xff; + }*/ + } + } + } + + *key_ptr[0] = '\1'; + *key_ptr[1] = '\1'; + *key_ptr[2] = '\1'; + *key_ptr[3]++ = '\1'; + *key_ptr[3] = 0; + + return key_ptr[3] - dst; +} diff --git a/libs/unicode/utf8.c b/libs/unicode/utf8.c index 7db6d34afb3..6f6781aa186 100644 --- a/libs/unicode/utf8.c +++ b/libs/unicode/utf8.c @@ -20,7 +20,6 @@ #include -#include "winnls.h" #include "wine/unicode.h" /* number of following bytes in sequence based on first byte value (for bytes above 0x7f) */ diff --git a/libs/unicode/wctomb.c b/libs/unicode/wctomb.c index 7a501d0aa52..ef09fcbb0b2 100644 --- a/libs/unicode/wctomb.c +++ b/libs/unicode/wctomb.c @@ -20,7 +20,6 @@ #include -#include "winnls.h" #include "wine/unicode.h" /* search for a character in the unicode_compose_table; helper for compose() */ diff --git a/libs/unicode/wine_unicode.def b/libs/unicode/wine_unicode.def index 8dc4698695a..59c5d6bfe34 100644 --- a/libs/unicode/wine_unicode.def +++ b/libs/unicode/wine_unicode.def @@ -16,6 +16,7 @@ EXPORTS wine_cp_get_table wine_cp_mbstowcs wine_cp_wcstombs + wine_get_sortkey wine_utf8_mbstowcs wine_utf8_wcstombs wine_wctype_table diff --git a/ole/ole2nls.c b/ole/ole2nls.c deleted file mode 100644 index a812f0be25a..00000000000 --- a/ole/ole2nls.c +++ /dev/null @@ -1,1218 +0,0 @@ -/* - * National Language Support library - * - * Copyright 1995 Martin von Loewis - * Copyright 1998 David Lee Lambert - * Copyright 2000 Julio César Gázquez - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "config.h" -#include "wine/port.h" - -#include -#include -#include -#include -#include - -#include "windef.h" -#include "winbase.h" -#include "wingdi.h" -#include "winuser.h" -#include "winternl.h" -#include "wine/unicode.h" -#include "winver.h" -#include "winnls.h" -#include "winreg.h" -#include "winerror.h" -#include "wine/debug.h" - -WINE_DEFAULT_DEBUG_CHANNEL(nls); - - -static const unsigned char LCM_Unicode_LUT[] = { - 6 , 3, /* - 1 */ - 6 , 4, /* - 2 */ - 6 , 5, /* - 3 */ - 6 , 6, /* - 4 */ - 6 , 7, /* - 5 */ - 6 , 8, /* - 6 */ - 6 , 9, /* - 7 */ - 6 , 10, /* - 8 */ - 7 , 5, /* - 9 */ - 7 , 6, /* - 10 */ - 7 , 7, /* - 11 */ - 7 , 8, /* - 12 */ - 7 , 9, /* - 13 */ - 6 , 11, /* - 14 */ - 6 , 12, /* - 15 */ - 6 , 13, /* - 16 */ - 6 , 14, /* - 17 */ - 6 , 15, /* - 18 */ - 6 , 16, /* - 19 */ - 6 , 17, /* - 20 */ - 6 , 18, /* - 21 */ - 6 , 19, /* - 22 */ - 6 , 20, /* - 23 */ - 6 , 21, /* - 24 */ - 6 , 22, /* - 25 */ - 6 , 23, /* - 26 */ - 6 , 24, /* - 27 */ - 6 , 25, /* - 28 */ - 6 , 26, /* - 29 */ - 6 , 27, /* - 30 */ - 6 , 28, /* - 31 */ - 7 , 2, /* - 32 */ - 7 , 28, /* ! - 33 */ - 7 , 29, /* " - 34 */ /* " */ - 7 , 31, /* # - 35 */ - 7 , 33, /* $ - 36 */ - 7 , 35, /* % - 37 */ - 7 , 37, /* & - 38 */ - 6 , 128, /* ' - 39 */ - 7 , 39, /* ( - 40 */ - 7 , 42, /* ) - 41 */ - 7 , 45, /* * - 42 */ - 8 , 3, /* + - 43 */ - 7 , 47, /* , - 44 */ - 6 , 130, /* - - 45 */ - 7 , 51, /* . - 46 */ - 7 , 53, /* / - 47 */ - 12 , 3, /* 0 - 48 */ - 12 , 33, /* 1 - 49 */ - 12 , 51, /* 2 - 50 */ - 12 , 70, /* 3 - 51 */ - 12 , 88, /* 4 - 52 */ - 12 , 106, /* 5 - 53 */ - 12 , 125, /* 6 - 54 */ - 12 , 144, /* 7 - 55 */ - 12 , 162, /* 8 - 56 */ - 12 , 180, /* 9 - 57 */ - 7 , 55, /* : - 58 */ - 7 , 58, /* ; - 59 */ - 8 , 14, /* < - 60 */ - 8 , 18, /* = - 61 */ - 8 , 20, /* > - 62 */ - 7 , 60, /* ? - 63 */ - 7 , 62, /* @ - 64 */ - 14 , 2, /* A - 65 */ - 14 , 9, /* B - 66 */ - 14 , 10, /* C - 67 */ - 14 , 26, /* D - 68 */ - 14 , 33, /* E - 69 */ - 14 , 35, /* F - 70 */ - 14 , 37, /* G - 71 */ - 14 , 44, /* H - 72 */ - 14 , 50, /* I - 73 */ - 14 , 53, /* J - 74 */ - 14 , 54, /* K - 75 */ - 14 , 72, /* L - 76 */ - 14 , 81, /* M - 77 */ - 14 , 112, /* N - 78 */ - 14 , 124, /* O - 79 */ - 14 , 126, /* P - 80 */ - 14 , 137, /* Q - 81 */ - 14 , 138, /* R - 82 */ - 14 , 145, /* S - 83 */ - 14 , 153, /* T - 84 */ - 14 , 159, /* U - 85 */ - 14 , 162, /* V - 86 */ - 14 , 164, /* W - 87 */ - 14 , 166, /* X - 88 */ - 14 , 167, /* Y - 89 */ - 14 , 169, /* Z - 90 */ - 7 , 63, /* [ - 91 */ - 7 , 65, /* \ - 92 */ - 7 , 66, /* ] - 93 */ - 7 , 67, /* ^ - 94 */ - 7 , 68, /* _ - 95 */ - 7 , 72, /* ` - 96 */ - 14 , 2, /* a - 97 */ - 14 , 9, /* b - 98 */ - 14 , 10, /* c - 99 */ - 14 , 26, /* d - 100 */ - 14 , 33, /* e - 101 */ - 14 , 35, /* f - 102 */ - 14 , 37, /* g - 103 */ - 14 , 44, /* h - 104 */ - 14 , 50, /* i - 105 */ - 14 , 53, /* j - 106 */ - 14 , 54, /* k - 107 */ - 14 , 72, /* l - 108 */ - 14 , 81, /* m - 109 */ - 14 , 112, /* n - 110 */ - 14 , 124, /* o - 111 */ - 14 , 126, /* p - 112 */ - 14 , 137, /* q - 113 */ - 14 , 138, /* r - 114 */ - 14 , 145, /* s - 115 */ - 14 , 153, /* t - 116 */ - 14 , 159, /* u - 117 */ - 14 , 162, /* v - 118 */ - 14 , 164, /* w - 119 */ - 14 , 166, /* x - 120 */ - 14 , 167, /* y - 121 */ - 14 , 169, /* z - 122 */ - 7 , 74, /* { - 123 */ - 7 , 76, /* | - 124 */ - 7 , 78, /* } - 125 */ - 7 , 80, /* ~ - 126 */ - 6 , 29, /*  - 127 */ - 6 , 30, /* € - 128 */ - 6 , 31, /* � - 129 */ - 7 , 123, /* ‚ - 130 */ - 14 , 35, /* ƒ - 131 */ - 7 , 127, /* „ - 132 */ - 10 , 21, /* … - 133 */ - 10 , 15, /* † - 134 */ - 10 , 16, /* ‡ - 135 */ - 7 , 67, /* ˆ - 136 */ - 10 , 22, /* ‰ - 137 */ - 14 , 145, /* Š - 138 */ - 7 , 136, /* ‹ - 139 */ - 14 + 16 , 124, /* Œ - 140 */ - 6 , 43, /* � - 141 */ - 6 , 44, /* Ž - 142 */ - 6 , 45, /* � - 143 */ - 6 , 46, /* � - 144 */ - 7 , 121, /* ‘ - 145 */ - 7 , 122, /* ’ - 146 */ - 7 , 125, /* “ - 147 */ - 7 , 126, /* ” - 148 */ - 10 , 17, /* • - 149 */ - 6 , 137, /* – - 150 */ - 6 , 139, /* — - 151 */ - 7 , 93, /* ˜ - 152 */ - 14 , 156, /* ™ - 153 */ - 14 , 145, /* š - 154 */ - 7 , 137, /* › - 155 */ - 14 + 16 , 124, /* œ - 156 */ - 6 , 59, /* � - 157 */ - 6 , 60, /* ž - 158 */ - 14 , 167, /* Ÿ - 159 */ - 7 , 4, /*   - 160 */ - 7 , 81, /* ¡ - 161 */ - 10 , 2, /* ¢ - 162 */ - 10 , 3, /* £ - 163 */ - 10 , 4, /* ¤ - 164 */ - 10 , 5, /* ¥ - 165 */ - 7 , 82, /* ¦ - 166 */ - 10 , 6, /* § - 167 */ - 7 , 83, /* ¨ - 168 */ - 10 , 7, /* © - 169 */ - 14 , 2, /* ª - 170 */ - 8 , 24, /* « - 171 */ - 10 , 8, /* ¬ - 172 */ - 6 , 131, /* ­ - 173 */ - 10 , 9, /* ® - 174 */ - 7 , 84, /* ¯ - 175 */ - 10 , 10, /* ° - 176 */ - 8 , 23, /* ± - 177 */ - 12 , 51, /* ² - 178 */ - 12 , 70, /* ³ - 179 */ - 7 , 85, /* ´ - 180 */ - 10 , 11, /* µ - 181 */ - 10 , 12, /* ¶ - 182 */ - 10 , 13, /* · - 183 */ - 7 , 86, /* ¸ - 184 */ - 12 , 33, /* ¹ - 185 */ - 14 , 124, /* º - 186 */ - 8 , 26, /* » - 187 */ - 12 , 21, /* ¼ - 188 */ - 12 , 25, /* ½ - 189 */ - 12 , 29, /* ¾ - 190 */ - 7 , 87, /* ¿ - 191 */ - 14 , 2, /* À - 192 */ - 14 , 2, /* Á - 193 */ - 14 , 2, /*  - 194 */ - 14 , 2, /* à - 195 */ - 14 , 2, /* Ä - 196 */ - 14 , 2, /* Å - 197 */ - 14 + 16 , 2, /* Æ - 198 */ - 14 , 10, /* Ç - 199 */ - 14 , 33, /* È - 200 */ - 14 , 33, /* É - 201 */ - 14 , 33, /* Ê - 202 */ - 14 , 33, /* Ë - 203 */ - 14 , 50, /* Ì - 204 */ - 14 , 50, /* Í - 205 */ - 14 , 50, /* Î - 206 */ - 14 , 50, /* Ï - 207 */ - 14 , 26, /* Ð - 208 */ - 14 , 112, /* Ñ - 209 */ - 14 , 124, /* Ò - 210 */ - 14 , 124, /* Ó - 211 */ - 14 , 124, /* Ô - 212 */ - 14 , 124, /* Õ - 213 */ - 14 , 124, /* Ö - 214 */ - 8 , 28, /* × - 215 */ - 14 , 124, /* Ø - 216 */ - 14 , 159, /* Ù - 217 */ - 14 , 159, /* Ú - 218 */ - 14 , 159, /* Û - 219 */ - 14 , 159, /* Ü - 220 */ - 14 , 167, /* Ý - 221 */ - 14 + 32 , 153, /* Þ - 222 */ - 14 + 48 , 145, /* ß - 223 */ - 14 , 2, /* à - 224 */ - 14 , 2, /* á - 225 */ - 14 , 2, /* â - 226 */ - 14 , 2, /* ã - 227 */ - 14 , 2, /* ä - 228 */ - 14 , 2, /* å - 229 */ - 14 + 16 , 2, /* æ - 230 */ - 14 , 10, /* ç - 231 */ - 14 , 33, /* è - 232 */ - 14 , 33, /* é - 233 */ - 14 , 33, /* ê - 234 */ - 14 , 33, /* ë - 235 */ - 14 , 50, /* ì - 236 */ - 14 , 50, /* í - 237 */ - 14 , 50, /* î - 238 */ - 14 , 50, /* ï - 239 */ - 14 , 26, /* ð - 240 */ - 14 , 112, /* ñ - 241 */ - 14 , 124, /* ò - 242 */ - 14 , 124, /* ó - 243 */ - 14 , 124, /* ô - 244 */ - 14 , 124, /* õ - 245 */ - 14 , 124, /* ö - 246 */ - 8 , 29, /* ÷ - 247 */ - 14 , 124, /* ø - 248 */ - 14 , 159, /* ù - 249 */ - 14 , 159, /* ú - 250 */ - 14 , 159, /* û - 251 */ - 14 , 159, /* ü - 252 */ - 14 , 167, /* ý - 253 */ - 14 + 32 , 153, /* þ - 254 */ - 14 , 167 /* ÿ - 255 */ }; - -static const unsigned char LCM_Unicode_LUT_2[] = { 33, 44, 145 }; - -#define LCM_Diacritic_Start 131 - -static const unsigned char LCM_Diacritic_LUT[] = { -123, /* ƒ - 131 */ - 2, /* „ - 132 */ - 2, /* … - 133 */ - 2, /* † - 134 */ - 2, /* ‡ - 135 */ - 3, /* ˆ - 136 */ - 2, /* ‰ - 137 */ - 20, /* Š - 138 */ - 2, /* ‹ - 139 */ - 2, /* Œ - 140 */ - 2, /* � - 141 */ - 2, /* Ž - 142 */ - 2, /* � - 143 */ - 2, /* � - 144 */ - 2, /* ‘ - 145 */ - 2, /* ’ - 146 */ - 2, /* “ - 147 */ - 2, /* ” - 148 */ - 2, /* • - 149 */ - 2, /* – - 150 */ - 2, /* — - 151 */ - 2, /* ˜ - 152 */ - 2, /* ™ - 153 */ - 20, /* š - 154 */ - 2, /* › - 155 */ - 2, /* œ - 156 */ - 2, /* � - 157 */ - 2, /* ž - 158 */ - 19, /* Ÿ - 159 */ - 2, /*   - 160 */ - 2, /* ¡ - 161 */ - 2, /* ¢ - 162 */ - 2, /* £ - 163 */ - 2, /* ¤ - 164 */ - 2, /* ¥ - 165 */ - 2, /* ¦ - 166 */ - 2, /* § - 167 */ - 2, /* ¨ - 168 */ - 2, /* © - 169 */ - 3, /* ª - 170 */ - 2, /* « - 171 */ - 2, /* ¬ - 172 */ - 2, /* ­ - 173 */ - 2, /* ® - 174 */ - 2, /* ¯ - 175 */ - 2, /* ° - 176 */ - 2, /* ± - 177 */ - 2, /* ² - 178 */ - 2, /* ³ - 179 */ - 2, /* ´ - 180 */ - 2, /* µ - 181 */ - 2, /* ¶ - 182 */ - 2, /* · - 183 */ - 2, /* ¸ - 184 */ - 2, /* ¹ - 185 */ - 3, /* º - 186 */ - 2, /* » - 187 */ - 2, /* ¼ - 188 */ - 2, /* ½ - 189 */ - 2, /* ¾ - 190 */ - 2, /* ¿ - 191 */ - 15, /* À - 192 */ - 14, /* Á - 193 */ - 18, /*  - 194 */ - 25, /* à - 195 */ - 19, /* Ä - 196 */ - 26, /* Å - 197 */ - 2, /* Æ - 198 */ - 28, /* Ç - 199 */ - 15, /* È - 200 */ - 14, /* É - 201 */ - 18, /* Ê - 202 */ - 19, /* Ë - 203 */ - 15, /* Ì - 204 */ - 14, /* Í - 205 */ - 18, /* Î - 206 */ - 19, /* Ï - 207 */ -104, /* Ð - 208 */ - 25, /* Ñ - 209 */ - 15, /* Ò - 210 */ - 14, /* Ó - 211 */ - 18, /* Ô - 212 */ - 25, /* Õ - 213 */ - 19, /* Ö - 214 */ - 2, /* × - 215 */ - 33, /* Ø - 216 */ - 15, /* Ù - 217 */ - 14, /* Ú - 218 */ - 18, /* Û - 219 */ - 19, /* Ü - 220 */ - 14, /* Ý - 221 */ - 2, /* Þ - 222 */ - 2, /* ß - 223 */ - 15, /* à - 224 */ - 14, /* á - 225 */ - 18, /* â - 226 */ - 25, /* ã - 227 */ - 19, /* ä - 228 */ - 26, /* å - 229 */ - 2, /* æ - 230 */ - 28, /* ç - 231 */ - 15, /* è - 232 */ - 14, /* é - 233 */ - 18, /* ê - 234 */ - 19, /* ë - 235 */ - 15, /* ì - 236 */ - 14, /* í - 237 */ - 18, /* î - 238 */ - 19, /* ï - 239 */ -104, /* ð - 240 */ - 25, /* ñ - 241 */ - 15, /* ò - 242 */ - 14, /* ó - 243 */ - 18, /* ô - 244 */ - 25, /* õ - 245 */ - 19, /* ö - 246 */ - 2, /* ÷ - 247 */ - 33, /* ø - 248 */ - 15, /* ù - 249 */ - 14, /* ú - 250 */ - 18, /* û - 251 */ - 19, /* ü - 252 */ - 14, /* ý - 253 */ - 2, /* þ - 254 */ - 19, /* ÿ - 255 */ -} ; - -/****************************************************************************** - * OLE2NLS_isPunctuation [INTERNAL] - */ -static int OLE2NLS_isPunctuation(unsigned char c) -{ - /* "punctuation character" in this context is a character which is - considered "less important" during word sort comparison. - See LCMapString implementation for the precise definition - of "less important". */ - - return (LCM_Unicode_LUT[-2+2*c]==6); -} - -/****************************************************************************** - * OLE2NLS_isNonSpacing [INTERNAL] - */ -static int OLE2NLS_isNonSpacing(unsigned char c) -{ - /* This function is used by LCMapStringA. Characters - for which it returns true are ignored when mapping a - string with NORM_IGNORENONSPACE */ - return ((c==136) || (c==170) || (c==186)); -} - -/****************************************************************************** - * OLE2NLS_isSymbol [INTERNAL] - * FIXME: handle current locale - */ -static int OLE2NLS_isSymbol(unsigned char c) -{ - /* This function is used by LCMapStringA. Characters - for which it returns true are ignored when mapping a - string with NORM_IGNORESYMBOLS */ - return ( (c!=0) && !(isalpha(c) || isdigit(c)) ); -} - -/****************************************************************************** - * identity [Internal] - */ -static int identity(int c) -{ - return c; -} - -/************************************************************************* - * LCMapStringA [KERNEL32.@] - * - * Convert a string, or generate a sort key from it. - * - * RETURNS - * Success: The length of the string written to dststr. - * Failure: 0. - * - * NOTES - * -If mapflags includes LCMAP_SORTKEY, the function will generate a - * sort key for srcstr. Otherwise, srcstr is converted according to - * mapflags. - * -If scrlen is -1, the function will compute the length of strsrc - * (which must be NUL terminated) itself. - * -If dstlen is 0, The return value is the buffer length that is needed. - * -NORM_IGNOREWIDTH means to compare ASCII and wide characters - * as if they are equal. - * In the only code page implemented so far, there may not be - * wide characters in strings passed to this function, - * so there is nothing to be done for this flag. - */ -INT WINAPI LCMapStringA( - LCID lcid, /* [in] Locale Id */ - DWORD mapflags, /* [in] Flags */ - LPCSTR srcstr, /* [in] Source buffer */ - INT srclen, /* [in] Length of srcstr */ - LPSTR dststr, /* [out] Destination buffer */ - INT dstlen) /* [in] Length of dststr */ -{ - int i; - - TRACE("(0x%04lx,0x%08lx,%s,%d,%p,%d)\n", - lcid,mapflags,debugstr_an(srcstr,srclen),srclen,dststr,dstlen); - - if ( ((dstlen!=0) && (dststr==NULL)) || (srcstr==NULL) ) - { - ERR("(src=%s,dest=%s): Invalid NULL string\n", - debugstr_an(srcstr,srclen), dststr); - SetLastError(ERROR_INVALID_PARAMETER); - return 0; - } - if (srclen == -1) - srclen = strlen(srcstr) + 1 ; /* (include final '\0') */ - -#define LCMAPSTRINGA_SUPPORTED_FLAGS (LCMAP_UPPERCASE | \ - LCMAP_LOWERCASE | \ - LCMAP_SORTKEY | \ - NORM_IGNORECASE | \ - NORM_IGNORENONSPACE | \ - SORT_STRINGSORT | \ - NORM_IGNOREWIDTH | \ - NORM_IGNOREKANATYPE) - /* FIXME: as long as we don't support Katakana nor Hiragana - * characters, we can support NORM_IGNOREKANATYPE - */ - if (mapflags & ~LCMAPSTRINGA_SUPPORTED_FLAGS) - { - FIXME("(0x%04lx,0x%08lx,%p,%d,%p,%d): " - "unimplemented flags: 0x%08lx\n", - lcid, - mapflags, - srcstr, - srclen, - dststr, - dstlen, - mapflags & ~LCMAPSTRINGA_SUPPORTED_FLAGS - ); - } - - if ( !(mapflags & LCMAP_SORTKEY) ) - { - int i,j; - int (*f)(int) = identity; - int flag_ignorenonspace = mapflags & NORM_IGNORENONSPACE; - int flag_ignoresymbols = mapflags & NORM_IGNORESYMBOLS; - - if (flag_ignorenonspace || flag_ignoresymbols) - { - /* For some values of mapflags, the length of the resulting - string is not known at this point. Windows does map the string - and does not SetLastError ERROR_INSUFFICIENT_BUFFER in - these cases. */ - if (dstlen==0) - { - /* Compute required length */ - for (i=j=0; i < srclen; i++) - { - if ( !(flag_ignorenonspace && OLE2NLS_isNonSpacing(srcstr[i])) - && !(flag_ignoresymbols && OLE2NLS_isSymbol(srcstr[i])) ) - j++; - } - return j; - } - } - else - { - if (dstlen==0) - return srclen; - if (dstlen=0) && (LCM_Diacritic_LUT[ofs]!=2)) - diacritic_len=unicode_len; - } - - if (mapflags & NORM_IGNORECASE) - case_len=0; - if (mapflags & NORM_IGNORENONSPACE) - diacritic_len=0; - - room = 2 * unicode_len /* "unicode" component */ - + diacritic_len /* "diacritic" component */ - + case_len /* "case" component */ - + 4 * delayed_punctuation_len /* punctuation in word sort mode */ - + 4 /* four '\1' separators */ - + 1 ; /* terminal '\0' */ - if (dstlen==0) - return room; - else if (dstlen> 4; - type &= 15; - if (!flag_stringsort && OLE2NLS_isPunctuation(source_char)) - { - WORD encrypted_location = (1<<15) + 7 + 4*count; - *delayed_punctuation_component++ = (unsigned char) (encrypted_location>>8); - *delayed_punctuation_component++ = (unsigned char) (encrypted_location&255); - /* big-endian is used here because it lets string comparison be - compatible with numerical comparison */ - - *delayed_punctuation_component++ = type; - *delayed_punctuation_component++ = LCM_Unicode_LUT[-1+2*source_char]; - /* assumption : a punctuation character is never a - double or accented letter */ - } - else - { - dststr[2*count] = type; - dststr[2*count+1] = LCM_Unicode_LUT[-1+2*source_char]; - if (longcode) - { - if (count longcode = 1 - 32 in the first column of LCM_Unicode_LUT --> longcode = 2 - 48 in the first column of LCM_Unicode_LUT --> longcode = 3 */ - } - - if (count=0 ? LCM_Diacritic_LUT[ofs] : 2); - } - count++; - } - } - } - dststr[room-1] = '\0'; - return room; - } -} - -/************************************************************************* - * LCMapStringW [KERNEL32.@] - * - * See LCMapStringA. - */ -INT WINAPI LCMapStringW( - LCID lcid,DWORD mapflags,LPCWSTR srcstr,INT srclen,LPWSTR dststr, - INT dstlen) -{ - int i; - - TRACE("(0x%04lx,0x%08lx,%p,%d,%p,%d)\n", - lcid, mapflags, srcstr, srclen, dststr, dstlen); - - if ( ((dstlen!=0) && (dststr==NULL)) || (srcstr==NULL) ) - { - ERR("(src=%p,dst=%p): Invalid NULL string\n", srcstr, dststr); - SetLastError(ERROR_INVALID_PARAMETER); - return 0; - } - if (srclen==-1) - srclen = strlenW(srcstr)+1; - - /* FIXME: Both this function and it's companion LCMapStringA() - * completely ignore the "lcid" parameter. In place of the "lcid" - * parameter the application must set the "LC_COLLATE" or "LC_ALL" - * environment variable prior to invoking this function. */ - if (mapflags & LCMAP_SORTKEY) - { - /* Possible values of LC_COLLATE. */ - char *lc_collate_default = 0; /* value prior to this function */ - char *lc_collate_env = 0; /* value retrieved from the environment */ - - /* General purpose index into strings of any type. */ - int str_idx = 0; - - /* Lengths of various strings where the length is measured in - * wide characters for wide character strings and in bytes for - * native strings. The lengths include the NULL terminator. */ - size_t returned_len = 0; - size_t src_native_len = 0; - size_t dst_native_len = 0; - size_t dststr_libc_len = 0; - - /* Native (character set determined by locale) versions of the - * strings source and destination strings. */ - LPSTR src_native = 0; - LPSTR dst_native = 0; - - /* Version of the source and destination strings using the - * "wchar_t" Unicode data type needed by various libc functions. */ - wchar_t *srcstr_libc = 0; - wchar_t *dststr_libc = 0; - - if(!(srcstr_libc = (wchar_t *)HeapAlloc(GetProcessHeap(), 0, - srclen * sizeof(wchar_t)))) - { - ERR("Unable to allocate %d bytes for srcstr_libc\n", - srclen * sizeof(wchar_t)); - SetLastError(ERROR_NOT_ENOUGH_MEMORY); - return 0; - } - - /* Convert source string to a libc Unicode string. */ - for(str_idx = 0; str_idx < srclen; str_idx++) - { - srcstr_libc[str_idx] = srcstr[str_idx]; - } - - /* src_native should contain at most 3 bytes for each - * multibyte characters in the original srcstr string. */ - src_native_len = 3 * srclen; - if(!(src_native = (LPSTR)HeapAlloc(GetProcessHeap(), 0, - src_native_len))) - { - ERR("Unable to allocate %d bytes for src_native\n", src_native_len); - SetLastError(ERROR_NOT_ENOUGH_MEMORY); - if(srcstr_libc) HeapFree(GetProcessHeap(), 0, srcstr_libc); - return 0; - } - - /* FIXME: Prior to to setting the LC_COLLATE locale category the - * current value is backed up so it can be restored after the - * last LC_COLLATE sensitive function returns. - * - * Even though the locale is adjusted for a minimum amount of - * time a race condition exists where other threads may be - * affected if they invoke LC_COLLATE sensitive functions. One - * possible solution is to wrap all LC_COLLATE sensitive Wine - * functions, like LCMapStringW(), in a mutex. - * - * Another enhancement to the following would be to set the - * LC_COLLATE locale category as a function of the "lcid" - * parameter instead of the "LC_COLLATE" environment variable. */ - if(!(lc_collate_default = setlocale(LC_COLLATE, NULL))) - { - ERR("Unable to query the LC_COLLATE catagory\n"); - SetLastError(ERROR_INVALID_PARAMETER); - if(srcstr_libc) HeapFree(GetProcessHeap(), 0, srcstr_libc); - if(src_native) HeapFree(GetProcessHeap(), 0, src_native); - return 0; - } - - if(!(lc_collate_env = setlocale(LC_COLLATE, ""))) - { - ERR("Unable to inherit the LC_COLLATE locale category from the " - "environment. The \"LC_COLLATE\" environment variable is " - "\"%s\".\n", getenv("LC_COLLATE") ? - getenv("LC_COLLATE") : ""); - SetLastError(ERROR_INVALID_PARAMETER); - if(srcstr_libc) HeapFree(GetProcessHeap(), 0, srcstr_libc); - if(src_native) HeapFree(GetProcessHeap(), 0, src_native); - return 0; - } - - TRACE("lc_collate_default = %s\n", lc_collate_default); - TRACE("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) - { - ERR("wcstombs failed. The string specified (%s) may contain an invalid character.\n", - debugstr_w(srcstr)); - SetLastError(ERROR_INVALID_PARAMETER); - 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("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("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("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("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