ntdll: Implement NtGetNlsSectionPtr().

Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Alexandre Julliard 2019-11-26 17:25:42 +01:00
parent 179cd78f82
commit f5c4a89cf2
3 changed files with 170 additions and 0 deletions

View File

@ -40,6 +40,13 @@
WINE_DEFAULT_DEBUG_CHANNEL(nls);
enum nls_section_type
{
NLS_SECTION_CASEMAP = 10,
NLS_SECTION_CODEPAGE = 11,
NLS_SECTION_NORMALIZE = 12
};
LCID user_lcid = 0, system_lcid = 0;
static LANGID user_ui_language, system_ui_language;
@ -67,6 +74,137 @@ static NTSTATUS load_string( ULONG id, LANGID lang, WCHAR *buffer, ULONG len )
}
static NTSTATUS open_nls_data_file( ULONG type, ULONG id, HANDLE *file )
{
static const WCHAR pathfmtW[] = {'\\','?','?','\\','%','s','%','s',0};
static const WCHAR keyfmtW[] =
{'\\','R','e','g','i','s','t','r','y','\\','M','a','c','h','i','n','e','\\','S','y','s','t','e','m','\\',
'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
'C','o','n','t','r','o','l','\\','N','l','s','\\','%','s',0};
static const WCHAR cpW[] = {'C','o','d','e','p','a','g','e',0};
static const WCHAR normW[] = {'N','o','r','m','a','l','i','z','a','t','i','o','n',0};
static const WCHAR langW[] = {'L','a','n','g','u','a','g','e',0};
static const WCHAR cpfmtW[] = {'%','u',0};
static const WCHAR normfmtW[] = {'%','x',0};
static const WCHAR langfmtW[] = {'%','0','4','x',0};
static const WCHAR winedatadirW[] = {'W','I','N','E','D','A','T','A','D','I','R',0};
static const WCHAR winebuilddirW[] = {'W','I','N','E','B','U','I','L','D','D','I','R',0};
static const WCHAR dataprefixW[] = {'\\',0};
static const WCHAR buildprefixW[] = {'\\','l','o','a','d','e','r','\\',0};
static const WCHAR cpdefaultW[] = {'c','_','%','0','3','d','.','n','l','s',0};
static const WCHAR intlW[] = {'l','_','i','n','t','l','.','n','l','s',0};
static const WCHAR normnfcW[] = {'n','o','r','m','n','f','c','.','n','l','s',0};
static const WCHAR normnfdW[] = {'n','o','r','m','n','f','d','.','n','l','s',0};
static const WCHAR normnfkcW[] = {'n','o','r','m','n','f','k','c','.','n','l','s',0};
static const WCHAR normnfkdW[] = {'n','o','r','m','n','f','k','d','.','n','l','s',0};
DWORD size;
HANDLE handle;
NTSTATUS status;
IO_STATUS_BLOCK io;
OBJECT_ATTRIBUTES attr;
UNICODE_STRING nameW, valueW;
WCHAR buffer[MAX_PATH], value[10];
const WCHAR *name = NULL, *prefix = buildprefixW;
KEY_VALUE_PARTIAL_INFORMATION *info;
/* get filename from registry */
switch (type)
{
case NLS_SECTION_CASEMAP:
if (id) return STATUS_UNSUCCESSFUL;
sprintfW( buffer, keyfmtW, langW );
sprintfW( value, langfmtW, LANGIDFROMLCID(system_lcid) );
break;
case NLS_SECTION_CODEPAGE:
sprintfW( buffer, keyfmtW, cpW );
sprintfW( value, cpfmtW, id );
break;
case NLS_SECTION_NORMALIZE:
sprintfW( buffer, keyfmtW, normW );
sprintfW( value, normfmtW, id );
break;
default:
return STATUS_INVALID_PARAMETER_1;
}
RtlInitUnicodeString( &nameW, buffer );
RtlInitUnicodeString( &valueW, value );
InitializeObjectAttributes( &attr, &nameW, 0, 0, NULL );
if ((status = NtOpenKey( &handle, KEY_READ, &attr ))) return status;
info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
size = sizeof(buffer) - sizeof(WCHAR);
status = NtQueryValueKey( handle, &valueW, KeyValuePartialInformation, info, size, &size );
NtClose( handle );
if (!status)
{
((WCHAR *)info->Data)[info->DataLength / sizeof(WCHAR)] = 0;
name = (WCHAR *)info->Data;
}
else /* otherwise some hardcoded defaults */
{
switch (type)
{
case NLS_SECTION_CASEMAP:
name = intlW;
break;
case NLS_SECTION_CODEPAGE:
sprintfW( buffer, cpdefaultW, id );
name = buffer;
break;
case NLS_SECTION_NORMALIZE:
switch (id)
{
case NormalizationC: name = normnfcW; break;
case NormalizationD: name = normnfdW; break;
case NormalizationKC: name = normnfkcW; break;
case NormalizationKD: name = normnfkdW; break;
}
break;
}
if (!name) return status;
}
/* try to open file in system dir */
valueW.MaximumLength = (strlenW(name) + strlenW(system_dir) + 5) * sizeof(WCHAR);
if (!(valueW.Buffer = RtlAllocateHeap( GetProcessHeap(), 0, valueW.MaximumLength )))
return STATUS_NO_MEMORY;
valueW.Length = sprintfW( valueW.Buffer, pathfmtW, system_dir, name ) * sizeof(WCHAR);
InitializeObjectAttributes( &attr, &valueW, 0, 0, NULL );
status = NtOpenFile( file, GENERIC_READ, &attr, &io, FILE_SHARE_READ, FILE_SYNCHRONOUS_IO_ALERT );
if (!status) TRACE( "found %s\n", debugstr_w( valueW.Buffer ));
RtlFreeUnicodeString( &valueW );
if (status != STATUS_OBJECT_NAME_NOT_FOUND) return status;
/* not found, try in build or data dir */
RtlInitUnicodeString( &nameW, winebuilddirW );
valueW.MaximumLength = 0;
if (RtlQueryEnvironmentVariable_U( NULL, &nameW, &valueW ) != STATUS_BUFFER_TOO_SMALL)
{
RtlInitUnicodeString( &nameW, winedatadirW );
prefix = dataprefixW;
if (RtlQueryEnvironmentVariable_U( NULL, &nameW, &valueW ) != STATUS_BUFFER_TOO_SMALL)
return status;
}
valueW.MaximumLength = valueW.Length + sizeof(buildprefixW) + strlenW(name) * sizeof(WCHAR);
if (!(valueW.Buffer = RtlAllocateHeap( GetProcessHeap(), 0, valueW.MaximumLength )))
return STATUS_NO_MEMORY;
if (!RtlQueryEnvironmentVariable_U( NULL, &nameW, &valueW ))
{
strcatW( valueW.Buffer, prefix );
strcatW( valueW.Buffer, name );
valueW.Length = strlenW(valueW.Buffer) * sizeof(WCHAR);
InitializeObjectAttributes( &attr, &valueW, 0, 0, NULL );
status = NtOpenFile( file, GENERIC_READ, &attr, &io, FILE_SHARE_READ, FILE_SYNCHRONOUS_IO_ALERT );
if (!status) TRACE( "found %s\n", debugstr_w( valueW.Buffer ));
}
RtlFreeUnicodeString( &valueW );
return status;
}
#if !defined(__APPLE__) && !defined(__ANDROID__) /* these platforms always use UTF-8 */
/* charset to codepage map, sorted by name */
@ -427,6 +565,35 @@ NTSTATUS WINAPI NtQueryInstallUILanguage( LANGID *lang )
}
/**************************************************************************
* NtGetNlsSectionPtr (NTDLL.@)
*/
NTSTATUS WINAPI NtGetNlsSectionPtr( ULONG type, ULONG id, void *unknown, void **ptr, SIZE_T *size )
{
FILE_END_OF_FILE_INFORMATION info;
IO_STATUS_BLOCK io;
HANDLE file;
NTSTATUS status;
if ((status = open_nls_data_file( type, id, &file ))) return status;
if ((status = NtQueryInformationFile( file, &io, &info, sizeof(info), FileEndOfFileInformation )))
goto done;
/* FIXME: return a heap block instead of a file mapping for now */
if (!(*ptr = RtlAllocateHeap( GetProcessHeap(), 0, info.EndOfFile.QuadPart )))
{
status = STATUS_NO_MEMORY;
goto done;
}
status = NtReadFile( file, 0, NULL, NULL, &io, *ptr, info.EndOfFile.QuadPart, NULL, NULL );
if (!status && io.Information != info.EndOfFile.QuadPart) status = STATUS_INVALID_FILE_FOR_SECTION;
if (!status) *size = io.Information;
else RtlFreeHeap( GetProcessHeap(), 0, *ptr );
done:
NtClose( file );
return status;
}
/******************************************************************
* RtlLocaleNameToLcid (NTDLL.@)
*/

View File

@ -220,6 +220,7 @@
@ stdcall -norelay NtGetContextThread(long ptr)
@ stdcall NtGetCurrentProcessorNumber()
# @ stub NtGetDevicePowerState
@ stdcall NtGetNlsSectionPtr(long long long ptr ptr)
@ stub NtGetPlugPlayEvent
@ stdcall NtGetTickCount()
@ stdcall NtGetWriteWatch(long long ptr long ptr ptr ptr)
@ -1182,6 +1183,7 @@
@ stdcall -private -norelay ZwGetContextThread(long ptr) NtGetContextThread
@ stdcall -private ZwGetCurrentProcessorNumber() NtGetCurrentProcessorNumber
# @ stub ZwGetDevicePowerState
@ stdcall -private ZwGetNlsSectionPtr(long long long ptr ptr) NtGetNlsSectionPtr
@ stub ZwGetPlugPlayEvent
@ stdcall -private ZwGetTickCount() NtGetTickCount
@ stdcall -private ZwGetWriteWatch(long long ptr long ptr ptr ptr) NtGetWriteWatch

View File

@ -2407,6 +2407,7 @@ NTSYSAPI NTSTATUS WINAPI NtFreeVirtualMemory(HANDLE,PVOID*,SIZE_T*,ULONG);
NTSYSAPI NTSTATUS WINAPI NtFsControlFile(HANDLE,HANDLE,PIO_APC_ROUTINE,PVOID,PIO_STATUS_BLOCK,ULONG,PVOID,ULONG,PVOID,ULONG);
NTSYSAPI NTSTATUS WINAPI NtGetContextThread(HANDLE,CONTEXT*);
NTSYSAPI ULONG WINAPI NtGetCurrentProcessorNumber(void);
NTSYSAPI NTSTATUS WINAPI NtGetNlsSectionPtr(ULONG,ULONG,void*,void**,SIZE_T*);
NTSYSAPI NTSTATUS WINAPI NtGetPlugPlayEvent(ULONG,ULONG,PVOID,ULONG);
NTSYSAPI ULONG WINAPI NtGetTickCount(VOID);
NTSYSAPI NTSTATUS WINAPI NtGetWriteWatch(HANDLE,ULONG,PVOID,SIZE_T,PVOID*,ULONG_PTR*,ULONG*);