1 /*
2  * PROJECT:     ReactOS NLS to TXT Converter
3  * LICENSE:     GNU General Public License Version 2.0 or any later version
4  * FILE:        devutils/nlsedit/nls.c
5  * COPYRIGHT:   Copyright 2016 Dmitry Chapyshev <dmitry@reactos.org>
6  */
7 
8 #include "precomp.h"
9 
10 static VOID
NLS_InitCodePageTable(PUSHORT TableBase,PCPTABLEINFO CodePageTable)11 NLS_InitCodePageTable(PUSHORT TableBase, PCPTABLEINFO CodePageTable)
12 {
13     PNLS_FILE_HEADER NlsFileHeader;
14 
15     NlsFileHeader = (PNLS_FILE_HEADER)TableBase;
16 
17     /* Copy header fields first */
18     CodePageTable->CodePage = NlsFileHeader->CodePage;
19     CodePageTable->MaximumCharacterSize = NlsFileHeader->MaximumCharacterSize;
20     CodePageTable->DefaultChar = NlsFileHeader->DefaultChar;
21     CodePageTable->UniDefaultChar = NlsFileHeader->UniDefaultChar;
22     CodePageTable->TransDefaultChar = NlsFileHeader->TransDefaultChar;
23     CodePageTable->TransUniDefaultChar = NlsFileHeader->TransUniDefaultChar;
24 
25     CopyMemory(&CodePageTable->LeadByte, &NlsFileHeader->LeadByte, MAXIMUM_LEADBYTES);
26 
27     /* Offset to wide char table is after the header */
28     CodePageTable->WideCharTable = TableBase + NlsFileHeader->HeaderSize + 1 +
29                                    TableBase[NlsFileHeader->HeaderSize];
30 
31     /* Then multibyte table (256 wchars) follows */
32     CodePageTable->MultiByteTable = TableBase + NlsFileHeader->HeaderSize + 1;
33 
34     /* Check the presence of glyph table (256 wchars) */
35     if (!CodePageTable->MultiByteTable[256])
36     {
37         CodePageTable->DBCSRanges = CodePageTable->MultiByteTable + 256 + 1;
38     }
39     else
40     {
41         CodePageTable->DBCSRanges = CodePageTable->MultiByteTable + 256 + 1 + 256;
42     }
43 
44     /* Is this double-byte code page? */
45     if (*CodePageTable->DBCSRanges)
46     {
47         CodePageTable->DBCSCodePage = 1;
48         CodePageTable->DBCSOffsets = CodePageTable->DBCSRanges + 1;
49     }
50     else
51     {
52         CodePageTable->DBCSCodePage = 0;
53         CodePageTable->DBCSOffsets = NULL;
54     }
55 }
56 
57 PUSHORT
NLS_ReadFile(const WCHAR * pszFile,PCPTABLEINFO CodePageTable)58 NLS_ReadFile(const WCHAR *pszFile, PCPTABLEINFO CodePageTable)
59 {
60     HANDLE hFile;
61 
62     hFile = CreateFile(pszFile, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
63     if (hFile != INVALID_HANDLE_VALUE)
64     {
65         PUSHORT pData;
66         DWORD dwRead;
67         DWORD dwFileSize;
68 
69         dwFileSize = GetFileSize(hFile, NULL);
70         pData = malloc(dwFileSize);
71         if (pData != NULL)
72         {
73             if (ReadFile(hFile, pData, dwFileSize, &dwRead, NULL) != FALSE)
74             {
75                 NLS_InitCodePageTable(pData, CodePageTable);
76                 CloseHandle(hFile);
77 
78                 return pData;
79             }
80 
81             free(pData);
82         }
83 
84         CloseHandle(hFile);
85     }
86 
87     return NULL;
88 }
89 
90 BOOL
NLS_IsDBCSCodePage(PCPTABLEINFO CodePageTable)91 NLS_IsDBCSCodePage(PCPTABLEINFO CodePageTable)
92 {
93     return (BOOL)CodePageTable->DBCSCodePage;
94 }
95 
96 BOOL
NLS_IsGlyphTablePresent(PCPTABLEINFO CodePageTable)97 NLS_IsGlyphTablePresent(PCPTABLEINFO CodePageTable)
98 {
99     return (CodePageTable->MultiByteTable[256]) ? TRUE : FALSE;
100 }
101 
102 BOOL
NLS_IsDefaultCharForMB(PCPTABLEINFO CodePageTable,UCHAR Char)103 NLS_IsDefaultCharForMB(PCPTABLEINFO CodePageTable, UCHAR Char)
104 {
105     if (CodePageTable->MultiByteTable[Char] != CodePageTable->UniDefaultChar)
106         return FALSE;
107 
108     return TRUE;
109 }
110 
111 BOOL
NLS_IsDefaultCharForUnicode(PCPTABLEINFO CodePageTable,USHORT Char)112 NLS_IsDefaultCharForUnicode(PCPTABLEINFO CodePageTable, USHORT Char)
113 {
114     USHORT CodePageChar;
115 
116     if (NLS_IsDBCSCodePage(CodePageTable))
117     {
118         PUSHORT MultiByteTable = (PUSHORT)CodePageTable->WideCharTable;
119         CodePageChar = MultiByteTable[Char];
120     }
121     else
122     {
123         PUCHAR SingleByteTable = (PUCHAR)CodePageTable->WideCharTable;
124         CodePageChar = SingleByteTable[Char];
125     }
126 
127     if (CodePageChar != CodePageTable->DefaultChar)
128         return FALSE;
129 
130     return TRUE;
131 }
132 
133 USHORT
NLS_RecordsCountForMBTable(PCPTABLEINFO CodePageTable)134 NLS_RecordsCountForMBTable(PCPTABLEINFO CodePageTable)
135 {
136     USHORT CodePageChar;
137     USHORT Count = 0;
138 
139     for (CodePageChar = 0; CodePageChar <= 0xFF; CodePageChar++)
140     {
141         if (!NLS_IsDefaultCharForMB(CodePageTable, CodePageChar))
142             Count++;
143     }
144 
145     return Count;
146 }
147 
148 USHORT
NLS_RecordsCountForUnicodeTable(PCPTABLEINFO CodePageTable)149 NLS_RecordsCountForUnicodeTable(PCPTABLEINFO CodePageTable)
150 {
151     ULONG UnicodeChar;
152     USHORT Count = 0;
153 
154     for (UnicodeChar = 0; UnicodeChar <= 0xFFFF; UnicodeChar++)
155     {
156         if (!NLS_IsDefaultCharForUnicode(CodePageTable, UnicodeChar))
157             Count++;
158     }
159 
160     return Count;
161 }
162 
163 USHORT
NLS_RecordsCountForGlyphTable(PCPTABLEINFO CodePageTable)164 NLS_RecordsCountForGlyphTable(PCPTABLEINFO CodePageTable)
165 {
166     USHORT Count = 0;
167 
168     if (NLS_IsGlyphTablePresent(CodePageTable))
169     {
170         PUSHORT GlyphTable = CodePageTable->MultiByteTable + 256 + 1;
171         USHORT CodePageChar;
172 
173         for (CodePageChar = 0; CodePageChar <= 0xFF; CodePageChar++)
174         {
175             USHORT Char = GlyphTable[CodePageChar];
176 
177             if (Char != CodePageTable->UniDefaultChar)
178                 Count++;
179         }
180     }
181 
182     return Count;
183 }
184 
185 USHORT
NLS_RecordsCountForDBCSTable(PCPTABLEINFO CodePageTable,UCHAR LeadByte)186 NLS_RecordsCountForDBCSTable(PCPTABLEINFO CodePageTable, UCHAR LeadByte)
187 {
188     PUSHORT LeadByteInfo = CodePageTable->DBCSOffsets;
189     USHORT CodePageChar;
190     USHORT Count = 0;
191 
192     for (CodePageChar = 0; CodePageChar <= 0xFF; CodePageChar++)
193     {
194         USHORT Info = LeadByteInfo[LeadByte];
195 
196         if (Info && LeadByteInfo[Info + CodePageChar] != CodePageTable->UniDefaultChar)
197         {
198             Count++;
199         }
200     }
201 
202     return Count;
203 }
204