Alexandre Julliard : ntdll: Implement NtGetNlsSectionPtr().
Alexandre Julliard
julliard at winehq.org
Tue Nov 26 16:21:24 CST 2019
Module: wine
Branch: master
Commit: f5c4a89cf28c6e7d9a2f27968bc35e8cbc724e79
URL: https://source.winehq.org/git/wine.git/?a=commit;h=f5c4a89cf28c6e7d9a2f27968bc35e8cbc724e79
Author: Alexandre Julliard <julliard at winehq.org>
Date: Tue Nov 26 17:25:42 2019 +0100
ntdll: Implement NtGetNlsSectionPtr().
Signed-off-by: Alexandre Julliard <julliard at winehq.org>
---
dlls/ntdll/locale.c | 167 ++++++++++++++++++++++++++++++++++++++++++++++++++
dlls/ntdll/ntdll.spec | 2 +
include/winternl.h | 1 +
3 files changed, 170 insertions(+)
diff --git a/dlls/ntdll/locale.c b/dlls/ntdll/locale.c
index 94a945c17c..1c80bf80bb 100644
--- a/dlls/ntdll/locale.c
+++ b/dlls/ntdll/locale.c
@@ -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.@)
*/
diff --git a/dlls/ntdll/ntdll.spec b/dlls/ntdll/ntdll.spec
index fa2c7a32cd..3e1aa2fe49 100644
--- a/dlls/ntdll/ntdll.spec
+++ b/dlls/ntdll/ntdll.spec
@@ -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
diff --git a/include/winternl.h b/include/winternl.h
index d5c8d76ccf..635c230ded 100644
--- a/include/winternl.h
+++ b/include/winternl.h
@@ -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*);
More information about the wine-cvs
mailing list