[ROSAPPS] Add NLS to TXT file converter
authorDmitry Chapyshev <dmitry@reactos.org>
Thu, 15 Sep 2016 21:13:26 +0000 (21:13 +0000)
committerDmitry Chapyshev <dmitry@reactos.org>
Thu, 15 Sep 2016 21:13:26 +0000 (21:13 +0000)
svn path=/trunk/; revision=72693

rosapps/applications/devutils/CMakeLists.txt
rosapps/applications/devutils/nls2txt/CMakeLists.txt [new file with mode: 0644]
rosapps/applications/devutils/nls2txt/bestfit.c [new file with mode: 0644]
rosapps/applications/devutils/nls2txt/main.c [new file with mode: 0644]
rosapps/applications/devutils/nls2txt/nls.c [new file with mode: 0644]
rosapps/applications/devutils/nls2txt/nls2txt.rc [new file with mode: 0644]
rosapps/applications/devutils/nls2txt/precomp.h [new file with mode: 0644]

index f3ff7ec..f87900e 100644 (file)
@@ -3,6 +3,7 @@ add_subdirectory(createspec)
 add_subdirectory(gdb2)
 add_subdirectory(gdihv)
 add_subdirectory(genguid)
+add_subdirectory(nls2txt)
 add_subdirectory(shimdbg)
 add_subdirectory(symdump)
 add_subdirectory(syscalldump)
diff --git a/rosapps/applications/devutils/nls2txt/CMakeLists.txt b/rosapps/applications/devutils/nls2txt/CMakeLists.txt
new file mode 100644 (file)
index 0000000..ae6be88
--- /dev/null
@@ -0,0 +1,12 @@
+
+list(APPEND SOURCE
+    main.c
+    nls.c
+    bestfit.c
+    precomp.h)
+
+add_executable(nls2txt ${SOURCE} nls2txt.rc)
+add_pch(nls2txt precomp.h SOURCE)
+set_module_type(nls2txt win32cui UNICODE)
+add_importlibs(nls2txt user32 gdi32 comdlg32 comctl32 getuname msvcrt kernel32)
+add_cd_file(TARGET nls2txt DESTINATION reactos/system32 FOR all)
diff --git a/rosapps/applications/devutils/nls2txt/bestfit.c b/rosapps/applications/devutils/nls2txt/bestfit.c
new file mode 100644 (file)
index 0000000..24cd2cf
--- /dev/null
@@ -0,0 +1,282 @@
+/*
+ * PROJECT:     ReactOS NLS to TXT Converter
+ * LICENSE:     GNU General Public License Version 2.0 or any later version
+ * FILE:        devutils/nls2txt/bestfit.c
+ * COPYRIGHT:   Copyright 2016 Dmitry Chapyshev <dmitry@reactos.org>
+ */
+
+#include "precomp.h"
+
+static HANDLE
+BestFit_CreateFile(const WCHAR *pszFile)
+{
+    DWORD dwBytesWritten;
+    HANDLE hFile;
+
+    hFile = CreateFileW(pszFile,
+                        GENERIC_WRITE,
+                        FILE_SHARE_READ | FILE_SHARE_WRITE,
+                        NULL,
+                        CREATE_ALWAYS,
+                        FILE_ATTRIBUTE_NORMAL,
+                        NULL);
+    if (hFile != INVALID_HANDLE_VALUE)
+    {
+        /* Write UTF-8 BOM */
+        WriteFile(hFile, "\xEF\xBB\xBF", 3, &dwBytesWritten, NULL);
+    }
+
+    return hFile;
+}
+
+static VOID
+BestFit_CloseFile(HANDLE hFile)
+{
+    CloseHandle(hFile);
+}
+
+static CHAR*
+UTF8fromUNICODE(const WCHAR *pszInput, PSIZE_T Size)
+{
+    ULONG Length;
+    CHAR *pszOutput;
+
+    if (!pszInput || !Size) return NULL;
+
+    Length = WideCharToMultiByte(CP_UTF8, 0, pszInput, -1, NULL, 0, NULL, NULL);
+
+    *Size = Length * sizeof(CHAR);
+
+    pszOutput = (CHAR *) malloc(*Size);
+    if (pszOutput)
+    {
+        WideCharToMultiByte(CP_UTF8, 0, pszInput, -1, pszOutput, Length, NULL, NULL);
+    }
+
+    return pszOutput;
+}
+
+static VOID
+BestFit_Write(HANDLE hFile, const WCHAR *pszFormat, ...)
+{
+    LARGE_INTEGER FileSize;
+    LARGE_INTEGER MoveTo;
+    LARGE_INTEGER NewPos;
+    DWORD dwBytesWritten;
+
+    if (hFile == INVALID_HANDLE_VALUE)
+        return;
+
+    MoveTo.QuadPart = 0;
+    if (!SetFilePointerEx(hFile, MoveTo, &NewPos, FILE_END))
+        return;
+
+    if (!GetFileSizeEx(hFile, &FileSize))
+        return;
+
+    if (LockFile(hFile, (DWORD_PTR)NewPos.QuadPart, 0, (DWORD_PTR)FileSize.QuadPart, 0))
+    {
+        WCHAR *pszString;
+        CHAR *pszUtf8;
+        va_list Args;
+        SIZE_T Size;
+
+        va_start(Args, pszFormat);
+
+        Size = (_vscwprintf(pszFormat, Args) + 1) * sizeof(WCHAR);
+        pszString = (WCHAR*) malloc(Size);
+
+        if (!pszString)
+        {
+            UnlockFile(hFile, (DWORD_PTR)NewPos.QuadPart, 0, (DWORD_PTR)FileSize.QuadPart, 0);
+            va_end(Args);
+            return;
+        }
+
+        StringCbVPrintfW(pszString, Size, pszFormat, Args);
+        va_end(Args);
+
+        pszUtf8 = UTF8fromUNICODE(pszString, &Size);
+        if (pszUtf8)
+        {
+            WriteFile(hFile, pszUtf8, Size - sizeof(CHAR), &dwBytesWritten, NULL);
+            free(pszUtf8);
+        }
+
+        free(pszString);
+
+        UnlockFile(hFile, (DWORD_PTR)NewPos.QuadPart, 0, (DWORD_PTR)FileSize.QuadPart, 0);
+    }
+}
+
+BOOL
+BestFit_FromNLS(const WCHAR *pszNLSFile, const WCHAR *pszBestFitFile)
+{
+    CPTABLEINFO CodePageTable;
+    PUSHORT CodePage;
+    HANDLE hFile;
+    USHORT CodePageChar;
+    ULONG UnicodeChar;
+
+    CodePage = NLS_ReadFile(pszNLSFile, &CodePageTable);
+    if (CodePage == NULL)
+        return FALSE;
+
+    hFile = BestFit_CreateFile(pszBestFitFile);
+    if (hFile == INVALID_HANDLE_VALUE)
+    {
+        free(CodePage);
+        return FALSE;
+    }
+
+    /* The only field is the decimal windows code page number for this code page. */
+    BestFit_Write(hFile, L"CODEPAGE %u\r\n\r\n", CodePageTable.CodePage);
+
+    BestFit_Write(hFile,
+                  L"CPINFO %u 0x%02X 0x%04X\r\n\r\n",
+                  /* "1" for a single byte code page, "2" for a double byte code page */
+                  CodePageTable.MaximumCharacterSize,
+                  /* Replacement characters for unassigned Unicode code points when
+                     written to this code page */
+                  CodePageTable.DefaultChar,
+                  /* Replacement characters for illegal or unassigned code page values
+                     when converting to Unicode. */
+                  CodePageTable.UniDefaultChar);
+
+    /* This field contains the number of following records of code page to Unicode mappings. */
+    BestFit_Write(hFile, L"MBTABLE %u\r\n\r\n", NLS_RecordsCountForMBTable(&CodePageTable));
+
+    for (CodePageChar = 0; CodePageChar <= 0xFF; CodePageChar++)
+    {
+        if (!NLS_IsDefaultCharForMB(&CodePageTable, CodePageChar))
+        {
+            WCHAR szCharName[MAX_STR_LEN] = { 0 };
+
+            GetUName(CodePageTable.MultiByteTable[CodePageChar], szCharName);
+
+            BestFit_Write(hFile,
+                          L"0x%02X 0x%04X ;%s\r\n",
+                          CodePageChar,
+                          CodePageTable.MultiByteTable[CodePageChar],
+                          szCharName);
+        }
+    }
+
+    BestFit_Write(hFile, L"\r\n");
+
+    if (NLS_IsGlyphTablePresent(&CodePageTable))
+    {
+        PUSHORT GlyphTable = CodePageTable.MultiByteTable + 256 + 1;
+
+        BestFit_Write(hFile, L"GLYPHTABLE %u\r\n\r\n", NLS_RecordsCountForGlyphTable(&CodePageTable));
+
+        for (CodePageChar = 0; CodePageChar <= 0xFF; CodePageChar++)
+        {
+            WCHAR szCharName[MAX_STR_LEN] = { 0 };
+
+            GetUName(GlyphTable[CodePageChar], szCharName);
+
+            BestFit_Write(hFile,
+                          L"0x%02X 0x%04X ;%s\r\n",
+                          CodePageChar,
+                          GlyphTable[CodePageChar],
+                          szCharName);
+        }
+
+        BestFit_Write(hFile, L"\r\n");
+    }
+
+    if (NLS_IsDBCSCodePage(&CodePageTable))
+    {
+        PUSHORT LeadByteRanges = (PUSHORT)&CodePageTable.LeadByte[0];
+        USHORT Index;
+        USHORT LeadByte;
+
+        BestFit_Write(hFile,
+                      L"DBCSRANGE %u ;%u DBCS Lead Byte Ranges\r\n\r\n",
+                      CodePageTable.DBCSRanges[0],
+                      CodePageTable.DBCSRanges[0]);
+
+        for (Index = 0; Index < MAXIMUM_LEADBYTES / 2; Index++)
+        {
+            if (!LeadByteRanges[Index])
+                continue;
+
+            BestFit_Write(hFile,
+                          L"0x%X 0x%X ;Lead Byte Range %u\r\n\r\n",
+                          LOBYTE(LeadByteRanges[Index]),
+                          HIBYTE(LeadByteRanges[Index]),
+                          Index + 1);
+
+            for (LeadByte = LOBYTE(LeadByteRanges[Index]);
+                 LeadByte <= HIBYTE(LeadByteRanges[Index]);
+                 LeadByte++)
+            {
+                PUSHORT LeadByteInfo = CodePageTable.DBCSOffsets;
+
+                BestFit_Write(hFile,
+                              L"DBCSTABLE %u ;Range = %u, LeadByte = 0x%02X\r\n\r\n",
+                              NLS_RecordsCountForDBCSTable(&CodePageTable, LeadByte),
+                              Index + 1,
+                              LeadByte);
+
+                for (CodePageChar = 0; CodePageChar <= 0xFF; CodePageChar++)
+                {
+                    USHORT Info = LeadByteInfo[LeadByte];
+
+                    if (Info && LeadByteInfo[Info + CodePageChar] != CodePageTable.UniDefaultChar)
+                    {
+                        BestFit_Write(hFile,
+                                      L"0x%02X 0x%04X\r\n",
+                                      CodePageChar,
+                                      LeadByteInfo[Info + CodePageChar]);
+                    }
+                }
+
+                BestFit_Write(hFile, L"\r\n");
+            }
+        }
+    }
+
+    /* This field contains the number of records of Unicode to byte mappings. */
+    BestFit_Write(hFile, L"WCTABLE %u\r\n\r\n", NLS_RecordsCountForUnicodeTable(&CodePageTable));
+
+    for (UnicodeChar = 0; UnicodeChar <= 0xFFFF; UnicodeChar++)
+    {
+        if (!NLS_IsDefaultCharForUnicode(&CodePageTable, UnicodeChar))
+        {
+            WCHAR szCharName[MAX_STR_LEN] = { 0 };
+
+            GetUName(UnicodeChar, szCharName);
+
+            if (NLS_IsDBCSCodePage(&CodePageTable))
+            {
+                PUSHORT MultiByteTable = (PUSHORT)CodePageTable.WideCharTable;
+
+                BestFit_Write(hFile,
+                              L"0x%04X 0x%04X ;%s\r\n",
+                              UnicodeChar,
+                              MultiByteTable[UnicodeChar],
+                              szCharName);
+            }
+            else
+            {
+                PUCHAR SingleByteTable = (PUCHAR)CodePageTable.WideCharTable;
+
+                BestFit_Write(hFile,
+                              L"0x%04X 0x%02X ;%s\r\n",
+                              UnicodeChar,
+                              SingleByteTable[UnicodeChar],
+                              szCharName);
+            }
+        }
+    }
+
+    /* This tag marks the end of the code page data. Anything after this marker is ignored. */
+    BestFit_Write(hFile, L"\r\nENDCODEPAGE\r\n");
+
+    BestFit_CloseFile(hFile);
+    free(CodePage);
+
+    return TRUE;
+}
diff --git a/rosapps/applications/devutils/nls2txt/main.c b/rosapps/applications/devutils/nls2txt/main.c
new file mode 100644 (file)
index 0000000..f9c1799
--- /dev/null
@@ -0,0 +1,19 @@
+/*
+ * PROJECT:     ReactOS NLS to TXT Converter
+ * LICENSE:     GNU General Public License Version 2.0 or any later version
+ * FILE:        devutils/nls2txt/main.c
+ * COPYRIGHT:   Copyright 2016 Dmitry Chapyshev <dmitry@reactos.org>
+ */
+
+#include "precomp.h"
+
+INT wmain(INT argc, WCHAR* argv[])
+{
+    if (argc != 3)
+        return 1;
+
+    if (!BestFit_FromNLS(argv[1], argv[2]))
+        return 1;
+
+    return 0;
+}
diff --git a/rosapps/applications/devutils/nls2txt/nls.c b/rosapps/applications/devutils/nls2txt/nls.c
new file mode 100644 (file)
index 0000000..55eda81
--- /dev/null
@@ -0,0 +1,203 @@
+/*
+ * PROJECT:     ReactOS NLS to TXT Converter
+ * LICENSE:     GNU General Public License Version 2.0 or any later version
+ * FILE:        devutils/nlsedit/nls.c
+ * COPYRIGHT:   Copyright 2016 Dmitry Chapyshev <dmitry@reactos.org>
+ */
+
+#include "precomp.h"
+
+static VOID
+NLS_InitCodePageTable(PUSHORT TableBase, PCPTABLEINFO CodePageTable)
+{
+    PNLS_FILE_HEADER NlsFileHeader;
+
+    NlsFileHeader = (PNLS_FILE_HEADER)TableBase;
+
+    /* Copy header fields first */
+    CodePageTable->CodePage = NlsFileHeader->CodePage;
+    CodePageTable->MaximumCharacterSize = NlsFileHeader->MaximumCharacterSize;
+    CodePageTable->DefaultChar = NlsFileHeader->DefaultChar;
+    CodePageTable->UniDefaultChar = NlsFileHeader->UniDefaultChar;
+    CodePageTable->TransDefaultChar = NlsFileHeader->TransDefaultChar;
+    CodePageTable->TransUniDefaultChar = NlsFileHeader->TransUniDefaultChar;
+
+    CopyMemory(&CodePageTable->LeadByte, &NlsFileHeader->LeadByte, MAXIMUM_LEADBYTES);
+
+    /* Offset to wide char table is after the header */
+    CodePageTable->WideCharTable = TableBase + NlsFileHeader->HeaderSize + 1 +
+                                   TableBase[NlsFileHeader->HeaderSize];
+
+    /* Then multibyte table (256 wchars) follows */
+    CodePageTable->MultiByteTable = TableBase + NlsFileHeader->HeaderSize + 1;
+
+    /* Check the presence of glyph table (256 wchars) */
+    if (!CodePageTable->MultiByteTable[256])
+    {
+        CodePageTable->DBCSRanges = CodePageTable->MultiByteTable + 256 + 1;
+    }
+    else
+    {
+        CodePageTable->DBCSRanges = CodePageTable->MultiByteTable + 256 + 1 + 256;
+    }
+
+    /* Is this double-byte code page? */
+    if (*CodePageTable->DBCSRanges)
+    {
+        CodePageTable->DBCSCodePage = 1;
+        CodePageTable->DBCSOffsets = CodePageTable->DBCSRanges + 1;
+    }
+    else
+    {
+        CodePageTable->DBCSCodePage = 0;
+        CodePageTable->DBCSOffsets = NULL;
+    }
+}
+
+PUSHORT
+NLS_ReadFile(const WCHAR *pszFile, PCPTABLEINFO CodePageTable)
+{
+    HANDLE hFile;
+
+    hFile = CreateFile(pszFile, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
+    if (hFile != INVALID_HANDLE_VALUE)
+    {
+        PUSHORT pData = NULL;
+        DWORD dwRead;
+        DWORD dwFileSize;
+
+        dwFileSize = GetFileSize(hFile, NULL);
+        pData = malloc(dwFileSize);
+        if (pData != NULL)
+        {
+            if (ReadFile(hFile, pData, dwFileSize, &dwRead, NULL) != FALSE)
+            {
+                NLS_InitCodePageTable(pData, CodePageTable);
+                CloseHandle(hFile);
+
+                return pData;
+            }
+
+            free(pData);
+        }
+
+        CloseHandle(hFile);
+    }
+
+    return NULL;
+}
+
+BOOL
+NLS_IsDBCSCodePage(PCPTABLEINFO CodePageTable)
+{
+    return (BOOL)CodePageTable->DBCSCodePage;
+}
+
+BOOL
+NLS_IsGlyphTablePresent(PCPTABLEINFO CodePageTable)
+{
+    return (CodePageTable->MultiByteTable[256]) ? TRUE : FALSE;
+}
+
+BOOL
+NLS_IsDefaultCharForMB(PCPTABLEINFO CodePageTable, UCHAR Char)
+{
+    if (CodePageTable->MultiByteTable[Char] != CodePageTable->UniDefaultChar)
+        return FALSE;
+
+    return TRUE;
+}
+
+BOOL
+NLS_IsDefaultCharForUnicode(PCPTABLEINFO CodePageTable, USHORT Char)
+{
+    USHORT CodePageChar;
+
+    if (NLS_IsDBCSCodePage(CodePageTable))
+    {
+        PUSHORT MultiByteTable = (PUSHORT)CodePageTable->WideCharTable;
+        CodePageChar = MultiByteTable[Char];
+    }
+    else
+    {
+        PUCHAR SingleByteTable = (PUCHAR)CodePageTable->WideCharTable;
+        CodePageChar = SingleByteTable[Char];
+    }
+
+    if (CodePageChar != CodePageTable->DefaultChar)
+        return FALSE;
+
+    return TRUE;
+}
+
+USHORT
+NLS_RecordsCountForMBTable(PCPTABLEINFO CodePageTable)
+{
+    USHORT CodePageChar;
+    USHORT Count = 0;
+
+    for (CodePageChar = 0; CodePageChar <= 0xFF; CodePageChar++)
+    {
+        if (!NLS_IsDefaultCharForMB(CodePageTable, CodePageChar))
+            Count++;
+    }
+
+    return Count;
+}
+
+USHORT
+NLS_RecordsCountForUnicodeTable(PCPTABLEINFO CodePageTable)
+{
+    ULONG UnicodeChar;
+    USHORT Count = 0;
+
+    for (UnicodeChar = 0; UnicodeChar <= 0xFFFF; UnicodeChar++)
+    {
+        if (!NLS_IsDefaultCharForUnicode(CodePageTable, UnicodeChar))
+            Count++;
+    }
+
+    return Count;
+}
+
+USHORT
+NLS_RecordsCountForGlyphTable(PCPTABLEINFO CodePageTable)
+{
+    USHORT Count = 0;
+
+    if (NLS_IsGlyphTablePresent(CodePageTable))
+    {
+        PUSHORT GlyphTable = CodePageTable->MultiByteTable + 256 + 1;
+        USHORT CodePageChar;
+
+        for (CodePageChar = 0; CodePageChar <= 0xFF; CodePageChar++)
+        {
+            USHORT Char = GlyphTable[CodePageChar];
+
+            if (Char != CodePageTable->UniDefaultChar)
+                Count++;
+        }
+    }
+
+    return Count;
+}
+
+USHORT
+NLS_RecordsCountForDBCSTable(PCPTABLEINFO CodePageTable, UCHAR LeadByte)
+{
+    PUSHORT LeadByteInfo = CodePageTable->DBCSOffsets;
+    USHORT CodePageChar;
+    USHORT Count = 0;
+
+    for (CodePageChar = 0; CodePageChar <= 0xFF; CodePageChar++)
+    {
+        USHORT Info = LeadByteInfo[LeadByte];
+
+        if (Info && LeadByteInfo[Info + CodePageChar] != CodePageTable->UniDefaultChar)
+        {
+            Count++;
+        }
+    }
+
+    return Count;
+}
diff --git a/rosapps/applications/devutils/nls2txt/nls2txt.rc b/rosapps/applications/devutils/nls2txt/nls2txt.rc
new file mode 100644 (file)
index 0000000..7c6a1b9
--- /dev/null
@@ -0,0 +1,18 @@
+/*
+ * PROJECT:     ReactOS NLS to TXT Converter
+ * LICENSE:     GNU General Public License Version 2.0 or any later version
+ * FILE:        devutils/nls2txt/nls2txt.rc
+ * COPYRIGHT:   Copyright 2016 Dmitry Chapyshev <dmitry@reactos.org>
+ */
+
+#include <windows.h>
+#include <commctrl.h>
+
+LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
+
+#define REACTOS_STR_FILE_DESCRIPTION    "ReactOS NLS to TXT Converter"
+#define REACTOS_STR_INTERNAL_NAME       "nls2txt"
+#define REACTOS_STR_ORIGINAL_FILENAME   "nls2txt.exe"
+#include <reactos/version.rc>
+
+#include <reactos/manifest_exe.rc>
diff --git a/rosapps/applications/devutils/nls2txt/precomp.h b/rosapps/applications/devutils/nls2txt/precomp.h
new file mode 100644 (file)
index 0000000..9fc0064
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * PROJECT:     ReactOS NLS to TXT Converter
+ * LICENSE:     GNU General Public License Version 2.0 or any later version
+ * FILE:        devutils/nls2txt/precomp.h
+ * COPYRIGHT:   Copyright 2016 Dmitry Chapyshev <dmitry@reactos.org>
+ */
+
+#ifndef __PRECOMP_H
+#define __PRECOMP_H
+
+#include <windows.h>
+#include <windowsx.h>
+#include <commctrl.h>
+#include <strsafe.h>
+
+#define MAX_STR_LEN   256
+
+#define MAXIMUM_LEADBYTES   12
+
+typedef struct _NLS_FILE_HEADER
+{
+    USHORT HeaderSize;
+    USHORT CodePage;
+    USHORT MaximumCharacterSize;
+    USHORT DefaultChar;
+    USHORT UniDefaultChar;
+    USHORT TransDefaultChar;
+    USHORT TransUniDefaultChar;
+    UCHAR LeadByte[MAXIMUM_LEADBYTES];
+} NLS_FILE_HEADER, *PNLS_FILE_HEADER;
+
+typedef struct _CPTABLEINFO
+{
+    USHORT CodePage;
+    USHORT MaximumCharacterSize;       /* 1 = SBCS, 2 = DBCS */
+    USHORT DefaultChar;                /* Default MultiByte Character for the CP->Unicode conversion */
+    USHORT UniDefaultChar;             /* Default Unicode Character for the CP->Unicode conversion */
+    USHORT TransDefaultChar;           /* Default MultiByte Character for the Unicode->CP conversion */
+    USHORT TransUniDefaultChar;        /* Default Unicode Character for the Unicode->CP conversion */
+    USHORT DBCSCodePage;
+    UCHAR LeadByte[MAXIMUM_LEADBYTES];
+    PUSHORT MultiByteTable;             /* Table for CP->Unicode conversion */
+    PVOID WideCharTable;                /* Table for Unicode->CP conversion */
+    PUSHORT DBCSRanges;
+    PUSHORT DBCSOffsets;
+} CPTABLEINFO, *PCPTABLEINFO;
+
+int WINAPI
+GetUName(IN WORD wCharCode, OUT LPWSTR lpBuf);
+
+/* nls.c */
+PUSHORT
+NLS_ReadFile(const WCHAR *pszFile, PCPTABLEINFO CodePageTable);
+
+BOOL
+NLS_IsDBCSCodePage(PCPTABLEINFO CodePageTable);
+
+BOOL
+NLS_IsGlyphTablePresent(PCPTABLEINFO CodePageTable);
+
+BOOL
+NLS_IsDefaultCharForMB(PCPTABLEINFO CodePageTable, UCHAR Char);
+
+BOOL
+NLS_IsDefaultCharForUnicode(PCPTABLEINFO CodePageTable, USHORT Char);
+
+USHORT
+NLS_RecordsCountForMBTable(PCPTABLEINFO CodePageTable);
+
+USHORT
+NLS_RecordsCountForUnicodeTable(PCPTABLEINFO CodePageTable);
+
+USHORT
+NLS_RecordsCountForGlyphTable(PCPTABLEINFO CodePageTable);
+
+USHORT
+NLS_RecordsCountForDBCSTable(PCPTABLEINFO CodePageTable, UCHAR LeadByte);
+
+/* bestfit.c */
+BOOL
+BestFit_FromNLS(const WCHAR *pszNLSFile, const WCHAR *pszBestFitFile);
+
+#endif