/* * Locale support * * Copyright 1995 Martin von Loewis * Copyright 1998 David Lee Lambert * Copyright 2000 Julio César Gázquez * Copyright 2002 Alexandre Julliard for CodeWeavers * * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ #include "config.h" #include "wine/port.h" #include #include #include #include #include #include #include #include "ntstatus.h" #define WIN32_NO_STATUS #include "windef.h" #include "winbase.h" #include "winternl.h" #include "wine/unicode.h" #include "winnls.h" #include "winerror.h" #include "winver.h" #include "kernel_private.h" #include "wine/heap.h" #include "wine/debug.h" WINE_DEFAULT_DEBUG_CHANNEL(nls); extern BOOL WINAPI Internal_EnumCalendarInfo( CALINFO_ENUMPROCW proc, LCID lcid, CALID id, CALTYPE type, BOOL unicode, BOOL ex, BOOL exex, LPARAM lparam ); extern BOOL WINAPI Internal_EnumDateFormats( DATEFMT_ENUMPROCW proc, LCID lcid, DWORD flags, BOOL unicode, BOOL ex, BOOL exex, LPARAM lparam ); extern BOOL WINAPI Internal_EnumLanguageGroupLocales( LANGGROUPLOCALE_ENUMPROCW proc, LGRPID id, DWORD flags, LONG_PTR param, BOOL unicode ); extern BOOL WINAPI Internal_EnumSystemCodePages( CODEPAGE_ENUMPROCW proc, DWORD flags, BOOL unicode ); extern BOOL WINAPI Internal_EnumSystemLanguageGroups( LANGUAGEGROUP_ENUMPROCW proc, DWORD flags, LONG_PTR param, BOOL unicode ); extern BOOL WINAPI Internal_EnumTimeFormats( TIMEFMT_ENUMPROCW proc, LCID lcid, DWORD flags, BOOL unicode, BOOL ex, LPARAM lparam ); extern BOOL WINAPI Internal_EnumUILanguages( UILANGUAGE_ENUMPROCW proc, DWORD flags, LONG_PTR param, BOOL unicode ); /*********************************************************************** * get_lcid_codepage * * Retrieve the ANSI codepage for a given locale. */ static inline UINT get_lcid_codepage( LCID lcid ) { UINT ret; if (!GetLocaleInfoW( lcid, LOCALE_IDEFAULTANSICODEPAGE|LOCALE_RETURN_NUMBER, (WCHAR *)&ret, sizeof(ret)/sizeof(WCHAR) )) ret = 0; return ret; } /****************************************************************************** * SetLocaleInfoA [KERNEL32.@] * * Set information about an aspect of a locale. * * PARAMS * lcid [I] LCID of the locale * lctype [I] LCTYPE_ flags from "winnls.h" * data [I] Information to set * * RETURNS * Success: TRUE. The information given will be returned by GetLocaleInfoA() * whenever it is called without LOCALE_NOUSEROVERRIDE. * Failure: FALSE. Use GetLastError() to determine the cause. * * NOTES * - Values are only be set for the current user locale; the system locale * settings cannot be changed. * - Any settings changed by this call are lost when the locale is changed by * the control panel (in Wine, this happens every time you change LANG). * - The native implementation of this function does not check that lcid matches * the current user locale, and simply sets the new values. Wine warns you in * this case, but behaves the same. */ BOOL WINAPI SetLocaleInfoA(LCID lcid, LCTYPE lctype, LPCSTR data) { UINT codepage = CP_ACP; WCHAR *strW; DWORD len; BOOL ret; if (!(lctype & LOCALE_USE_CP_ACP)) codepage = get_lcid_codepage( lcid ); if (!data) { SetLastError( ERROR_INVALID_PARAMETER ); return FALSE; } len = MultiByteToWideChar( codepage, 0, data, -1, NULL, 0 ); if (!(strW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) { SetLastError( ERROR_NOT_ENOUGH_MEMORY ); return FALSE; } MultiByteToWideChar( codepage, 0, data, -1, strW, len ); ret = SetLocaleInfoW( lcid, lctype, strW ); HeapFree( GetProcessHeap(), 0, strW ); return ret; } /****************************************************************************** * SetCPGlobal (KERNEL32.@) * * Set the current Ansi code page Id for the system. * * PARAMS * acp [I] code page ID to be the new ACP. * * RETURNS * The previous ACP. */ UINT WINAPI SetCPGlobal( UINT acp ) { FIXME( "not supported\n" ); return GetACP(); } /*********************************************************************** * GetCPInfoExA (KERNEL32.@) * * Get extended information about a code page. * * PARAMS * codepage [I] Code page number * dwFlags [I] Reserved, must to 0. * cpinfo [O] Destination for code page information * * RETURNS * Success: TRUE. cpinfo is updated with the information about codepage. * Failure: FALSE, if codepage is invalid or cpinfo is NULL. */ BOOL WINAPI GetCPInfoExA( UINT codepage, DWORD dwFlags, LPCPINFOEXA cpinfo ) { CPINFOEXW cpinfoW; if (!GetCPInfoExW( codepage, dwFlags, &cpinfoW )) return FALSE; /* the layout is the same except for CodePageName */ memcpy(cpinfo, &cpinfoW, sizeof(CPINFOEXA)); WideCharToMultiByte(CP_ACP, 0, cpinfoW.CodePageName, -1, cpinfo->CodePageName, sizeof(cpinfo->CodePageName), NULL, NULL); return TRUE; } /********************************************************************* * GetDaylightFlag (KERNEL32.@) */ BOOL WINAPI GetDaylightFlag(void) { TIME_ZONE_INFORMATION tzinfo; return GetTimeZoneInformation( &tzinfo) == TIME_ZONE_ID_DAYLIGHT; } /*********************************************************************** * EnumSystemCodePagesA (KERNEL32.@) */ BOOL WINAPI EnumSystemCodePagesA( CODEPAGE_ENUMPROCA proc, DWORD flags ) { return Internal_EnumSystemCodePages( (CODEPAGE_ENUMPROCW)proc, flags, FALSE ); } /****************************************************************************** * GetStringTypeExA (KERNEL32.@) * * Get characteristics of the characters making up a string. * * PARAMS * locale [I] Locale Id for the string * type [I] CT_CTYPE1 = classification, CT_CTYPE2 = directionality, CT_CTYPE3 = typographic info * src [I] String to analyse * count [I] Length of src in chars, or -1 if src is NUL terminated * chartype [O] Destination for the calculated characteristics * * RETURNS * Success: TRUE. chartype is filled with the requested characteristics of each char * in src. * Failure: FALSE. Use GetLastError() to determine the cause. */ BOOL WINAPI GetStringTypeExA( LCID locale, DWORD type, LPCSTR src, INT count, LPWORD chartype ) { return GetStringTypeA(locale, type, src, count, chartype); } /************************************************************************* * FoldStringA (KERNEL32.@) * * Map characters in a string. * * PARAMS * dwFlags [I] Flags controlling chars to map (MAP_ constants from "winnls.h") * src [I] String to map * srclen [I] Length of src, or -1 if src is NUL terminated * dst [O] Destination for mapped string * dstlen [I] Length of dst, or 0 to find the required length for the mapped string * * RETURNS * Success: The length of the string written to dst, including the terminating NUL. If * dstlen is 0, the value returned is the same, but nothing is written to dst, * and dst may be NULL. * Failure: 0. Use GetLastError() to determine the cause. */ INT WINAPI FoldStringA(DWORD dwFlags, LPCSTR src, INT srclen, LPSTR dst, INT dstlen) { INT ret = 0, srclenW = 0; WCHAR *srcW = NULL, *dstW = NULL; if (!src || !srclen || dstlen < 0 || (dstlen && !dst) || src == dst) { SetLastError(ERROR_INVALID_PARAMETER); return 0; } srclenW = MultiByteToWideChar(CP_ACP, 0, src, srclen, NULL, 0); srcW = HeapAlloc(GetProcessHeap(), 0, srclenW * sizeof(WCHAR)); if (!srcW) { SetLastError(ERROR_NOT_ENOUGH_MEMORY); goto FoldStringA_exit; } MultiByteToWideChar(CP_ACP, 0, src, srclen, srcW, srclenW); ret = FoldStringW(dwFlags, srcW, srclenW, NULL, 0); if (ret && dstlen) { dstW = HeapAlloc(GetProcessHeap(), 0, ret * sizeof(WCHAR)); if (!dstW) { SetLastError(ERROR_NOT_ENOUGH_MEMORY); goto FoldStringA_exit; } ret = FoldStringW(dwFlags, srcW, srclenW, dstW, ret); if (!WideCharToMultiByte(CP_ACP, 0, dstW, ret, dst, dstlen, NULL, NULL)) { ret = 0; SetLastError(ERROR_INSUFFICIENT_BUFFER); } } HeapFree(GetProcessHeap(), 0, dstW); FoldStringA_exit: HeapFree(GetProcessHeap(), 0, srcW); return ret; } /****************************************************************************** * EnumSystemLanguageGroupsA (KERNEL32.@) */ BOOL WINAPI EnumSystemLanguageGroupsA( LANGUAGEGROUP_ENUMPROCA proc, DWORD flags, LONG_PTR param ) { return Internal_EnumSystemLanguageGroups( (LANGUAGEGROUP_ENUMPROCW)proc, flags, param, FALSE ); } /****************************************************************************** * EnumLanguageGroupLocalesA (KERNEL32.@) */ BOOL WINAPI EnumLanguageGroupLocalesA( LANGGROUPLOCALE_ENUMPROCA proc, LGRPID id, DWORD flags, LONG_PTR param ) { return Internal_EnumLanguageGroupLocales( (LANGGROUPLOCALE_ENUMPROCW)proc, id, flags, param, FALSE ); } /****************************************************************************** * EnumCalendarInfoA [KERNEL32.@] */ BOOL WINAPI EnumCalendarInfoA( CALINFO_ENUMPROCA proc, LCID lcid, CALID id, CALTYPE type ) { return Internal_EnumCalendarInfo( (CALINFO_ENUMPROCW)proc, lcid, id, type, FALSE, FALSE, FALSE, 0 ); } /****************************************************************************** * EnumCalendarInfoExA [KERNEL32.@] */ BOOL WINAPI EnumCalendarInfoExA( CALINFO_ENUMPROCEXA proc, LCID lcid, CALID id, CALTYPE type ) { return Internal_EnumCalendarInfo( (CALINFO_ENUMPROCW)proc, lcid, id, type, FALSE, TRUE, FALSE, 0 ); } /************************************************************************** * EnumDateFormatsExA (KERNEL32.@) * * FIXME: MSDN mentions only LOCALE_USE_CP_ACP, should we handle * LOCALE_NOUSEROVERRIDE here as well? */ BOOL WINAPI EnumDateFormatsExA(DATEFMT_ENUMPROCEXA proc, LCID lcid, DWORD flags) { return Internal_EnumDateFormats( (DATEFMT_ENUMPROCW)proc, lcid, flags, FALSE, TRUE, FALSE, 0 ); } /************************************************************************** * EnumDateFormatsA (KERNEL32.@) * * FIXME: MSDN mentions only LOCALE_USE_CP_ACP, should we handle * LOCALE_NOUSEROVERRIDE here as well? */ BOOL WINAPI EnumDateFormatsA(DATEFMT_ENUMPROCA proc, LCID lcid, DWORD flags) { return Internal_EnumDateFormats( (DATEFMT_ENUMPROCW)proc, lcid, flags, FALSE, FALSE, FALSE, 0 ); } /************************************************************************** * EnumTimeFormatsA (KERNEL32.@) * * FIXME: MSDN mentions only LOCALE_USE_CP_ACP, should we handle * LOCALE_NOUSEROVERRIDE here as well? */ BOOL WINAPI EnumTimeFormatsA( TIMEFMT_ENUMPROCA proc, LCID lcid, DWORD flags ) { /* EnumTimeFormatsA doesn't support flags, EnumTimeFormatsW does. */ if (flags & ~LOCALE_USE_CP_ACP) { SetLastError(ERROR_INVALID_FLAGS); return FALSE; } return Internal_EnumTimeFormats( (TIMEFMT_ENUMPROCW)proc, lcid, flags, FALSE, FALSE, 0 ); } /****************************************************************************** * InvalidateNLSCache (KERNEL32.@) * * Invalidate the cache of NLS values. * * PARAMS * None. * * RETURNS * Success: TRUE. * Failure: FALSE. */ BOOL WINAPI InvalidateNLSCache(void) { FIXME("() stub\n"); return FALSE; } /****************************************************************************** * EnumUILanguagesA (KERNEL32.@) */ BOOL WINAPI EnumUILanguagesA( UILANGUAGE_ENUMPROCA proc, DWORD flags, LONG_PTR param ) { return Internal_EnumUILanguages( (UILANGUAGE_ENUMPROCW)proc, flags, param, FALSE ); } /****************************************************************************** * GetGeoInfoA (KERNEL32.@) */ INT WINAPI GetGeoInfoA(GEOID geoid, GEOTYPE geotype, LPSTR data, int data_len, LANGID lang) { WCHAR *buffW; INT len; TRACE("%d %d %p %d %d\n", geoid, geotype, data, data_len, lang); len = GetGeoInfoW(geoid, geotype, NULL, 0, lang); if (!len) return 0; buffW = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR)); if (!buffW) return 0; GetGeoInfoW(geoid, geotype, buffW, len, lang); len = WideCharToMultiByte(CP_ACP, 0, buffW, -1, NULL, 0, NULL, NULL); if (!data || !data_len) { HeapFree(GetProcessHeap(), 0, buffW); return len; } len = WideCharToMultiByte(CP_ACP, 0, buffW, -1, data, data_len, NULL, NULL); HeapFree(GetProcessHeap(), 0, buffW); if (data_len < len) SetLastError(ERROR_INSUFFICIENT_BUFFER); return data_len < len ? 0 : len; }