1 /*
2 * PROJECT: FreeLoader
3 * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
4 * PURPOSE: "Poor-man" boot-time National Language Support (NLS) functions.
5 * COPYRIGHT: Copyright 2022 Hermès Bélusca-Maïto
6 *
7 * NOTE: This code is used at boot-time when no NLS tables are loaded.
8 * Adapted from lib/rtl/nls.c
9 */
10
11 /* INCLUDES ******************************************************************/
12
13 #include <rtl.h>
14
15 /* GLOBALS *******************************************************************/
16
17 BOOLEAN NlsMbCodePageTag = FALSE;
18
19 BOOLEAN NlsMbOemCodePageTag = FALSE;
20 PUSHORT NlsOemToUnicodeTable = NULL;
21 PCHAR NlsUnicodeToOemTable = NULL;
22 PUSHORT NlsUnicodeToMbOemTable = NULL;
23 PUSHORT NlsOemLeadByteInfo = NULL;
24
25 USHORT NlsOemDefaultChar = '\0';
26 USHORT NlsUnicodeDefaultChar = 0;
27
28 /* FUNCTIONS *****************************************************************/
29
30 WCHAR
31 NTAPI
RtlpDowncaseUnicodeChar(_In_ WCHAR Source)32 RtlpDowncaseUnicodeChar(
33 _In_ WCHAR Source)
34 {
35 USHORT Offset = 0;
36
37 if (Source < L'A')
38 return Source;
39
40 if (Source <= L'Z')
41 return Source + (L'a' - L'A');
42
43 #if 0
44 if (Source < 0x80)
45 return Source;
46 #endif
47
48 return Source + (SHORT)Offset;
49 }
50
51 WCHAR
52 NTAPI
RtlDowncaseUnicodeChar(_In_ WCHAR Source)53 RtlDowncaseUnicodeChar(
54 _In_ WCHAR Source)
55 {
56 return RtlpDowncaseUnicodeChar(Source);
57 }
58
59 _Use_decl_annotations_
60 NTSTATUS
61 NTAPI
RtlMultiByteToUnicodeN(_Out_ PWCH UnicodeString,_In_ ULONG UnicodeSize,_Out_opt_ PULONG ResultSize,_In_ PCCH MbString,_In_ ULONG MbSize)62 RtlMultiByteToUnicodeN(
63 _Out_ PWCH UnicodeString,
64 _In_ ULONG UnicodeSize,
65 _Out_opt_ PULONG ResultSize,
66 _In_ PCCH MbString,
67 _In_ ULONG MbSize)
68 {
69 ULONG Size = 0;
70 ULONG i;
71
72 /* single-byte code page */
73 if (MbSize > (UnicodeSize / sizeof(WCHAR)))
74 Size = UnicodeSize / sizeof(WCHAR);
75 else
76 Size = MbSize;
77
78 if (ResultSize)
79 *ResultSize = Size * sizeof(WCHAR);
80
81 for (i = 0; i < Size; i++)
82 {
83 /* Trivially zero-extend */
84 UnicodeString[i] = (WCHAR)MbString[i];
85 }
86
87 return STATUS_SUCCESS;
88 }
89
90 _Use_decl_annotations_
91 NTSTATUS
92 NTAPI
RtlMultiByteToUnicodeSize(_Out_ PULONG UnicodeSize,_In_ PCCH MbString,_In_ ULONG MbSize)93 RtlMultiByteToUnicodeSize(
94 _Out_ PULONG UnicodeSize,
95 _In_ PCCH MbString,
96 _In_ ULONG MbSize)
97 {
98 /* single-byte code page */
99 *UnicodeSize = MbSize * sizeof(WCHAR);
100
101 return STATUS_SUCCESS;
102 }
103
104 _Use_decl_annotations_
105 NTSTATUS
106 NTAPI
RtlUnicodeToMultiByteN(_Out_ PCHAR MbString,_In_ ULONG MbSize,_Out_opt_ PULONG ResultSize,_In_ PCWCH UnicodeString,_In_ ULONG UnicodeSize)107 RtlUnicodeToMultiByteN(
108 _Out_ PCHAR MbString,
109 _In_ ULONG MbSize,
110 _Out_opt_ PULONG ResultSize,
111 _In_ PCWCH UnicodeString,
112 _In_ ULONG UnicodeSize)
113 {
114 ULONG Size = 0;
115 ULONG i;
116
117 /* single-byte code page */
118 Size = (UnicodeSize > (MbSize * sizeof(WCHAR)))
119 ? MbSize : (UnicodeSize / sizeof(WCHAR));
120
121 if (ResultSize)
122 *ResultSize = Size;
123
124 for (i = 0; i < Size; i++)
125 {
126 /* Check for characters that cannot be trivially demoted to ANSI */
127 if (*((PCHAR)UnicodeString + 1) == 0)
128 {
129 *MbString++ = (CHAR)*UnicodeString++;
130 }
131 else
132 {
133 /* Invalid character, use default */
134 *MbString++ = NlsOemDefaultChar;
135 UnicodeString++;
136 }
137 }
138
139 return STATUS_SUCCESS;
140 }
141
142 _Use_decl_annotations_
143 NTSTATUS
144 NTAPI
RtlUnicodeToMultiByteSize(_Out_ PULONG MbSize,_In_ PCWCH UnicodeString,_In_ ULONG UnicodeSize)145 RtlUnicodeToMultiByteSize(
146 _Out_ PULONG MbSize,
147 _In_ PCWCH UnicodeString,
148 _In_ ULONG UnicodeSize)
149 {
150 ULONG UnicodeLength = UnicodeSize / sizeof(WCHAR);
151
152 /* single-byte code page */
153 *MbSize = UnicodeLength;
154
155 return STATUS_SUCCESS;
156 }
157
158 WCHAR
159 NTAPI
RtlpUpcaseUnicodeChar(_In_ WCHAR Source)160 RtlpUpcaseUnicodeChar(
161 _In_ WCHAR Source)
162 {
163 USHORT Offset = 0;
164
165 if (Source < 'a')
166 return Source;
167
168 if (Source <= 'z')
169 return (Source - ('a' - 'A'));
170
171 return Source + (SHORT)Offset;
172 }
173
174 WCHAR
175 NTAPI
RtlUpcaseUnicodeChar(_In_ WCHAR Source)176 RtlUpcaseUnicodeChar(
177 _In_ WCHAR Source)
178 {
179 return RtlpUpcaseUnicodeChar(Source);
180 }
181
182 _Use_decl_annotations_
183 NTSTATUS
184 NTAPI
RtlUpcaseUnicodeToMultiByteN(_Out_ PCHAR MbString,_In_ ULONG MbSize,_Out_opt_ PULONG ResultSize,_In_ PCWCH UnicodeString,_In_ ULONG UnicodeSize)185 RtlUpcaseUnicodeToMultiByteN(
186 _Out_ PCHAR MbString,
187 _In_ ULONG MbSize,
188 _Out_opt_ PULONG ResultSize,
189 _In_ PCWCH UnicodeString,
190 _In_ ULONG UnicodeSize)
191 {
192 WCHAR UpcaseChar;
193 ULONG Size = 0;
194 ULONG i;
195
196 /* single-byte code page */
197 if (UnicodeSize > (MbSize * sizeof(WCHAR)))
198 Size = MbSize;
199 else
200 Size = UnicodeSize / sizeof(WCHAR);
201
202 if (ResultSize)
203 *ResultSize = Size;
204
205 for (i = 0; i < Size; i++)
206 {
207 UpcaseChar = RtlpUpcaseUnicodeChar(*UnicodeString);
208
209 /* Check for characters that cannot be trivially demoted to ANSI */
210 if (*((PCHAR)&UpcaseChar + 1) == 0)
211 {
212 *MbString = (CHAR)UpcaseChar;
213 }
214 else
215 {
216 /* Invalid character, use default */
217 *MbString = NlsOemDefaultChar;
218 }
219
220 MbString++;
221 UnicodeString++;
222 }
223
224 return STATUS_SUCCESS;
225 }
226
227 CHAR
228 NTAPI
RtlUpperChar(_In_ CHAR Source)229 RtlUpperChar(
230 _In_ CHAR Source)
231 {
232 /* Check for simple ANSI case */
233 if (Source <= 'z')
234 {
235 /* Check for simple downcase a-z case */
236 if (Source >= 'a')
237 {
238 /* Just XOR with the difference */
239 return Source ^ ('a' - 'A');
240 }
241 else
242 {
243 /* Otherwise return the same char, it's already upcase */
244 return Source;
245 }
246 }
247 else
248 {
249 /* single-byte code page */
250 return (CHAR)RtlpUpcaseUnicodeChar((WCHAR)Source);
251 }
252 }
253
254
255 /**
256 * Stubbed OEM helpers that should not be used in the OS boot loader,
257 * but are necessary for linking with the rest of the RTL unicode.c.
258 **/
259
260 _Use_decl_annotations_
261 NTSTATUS
262 NTAPI
RtlUnicodeToOemN(_Out_ PCHAR OemString,_In_ ULONG OemSize,_Out_opt_ PULONG ResultSize,_In_ PCWCH UnicodeString,_In_ ULONG UnicodeSize)263 RtlUnicodeToOemN(
264 _Out_ PCHAR OemString,
265 _In_ ULONG OemSize,
266 _Out_opt_ PULONG ResultSize,
267 _In_ PCWCH UnicodeString,
268 _In_ ULONG UnicodeSize)
269 {
270 if (OemSize)
271 *OemString = ANSI_NULL;
272
273 if (ResultSize)
274 *ResultSize = 0;
275
276 return STATUS_NOT_IMPLEMENTED;
277 }
278
279 _Use_decl_annotations_
280 NTSTATUS
281 NTAPI
RtlOemToUnicodeN(_Out_ PWCHAR UnicodeString,_In_ ULONG UnicodeSize,_Out_opt_ PULONG ResultSize,_In_ PCCH OemString,_In_ ULONG OemSize)282 RtlOemToUnicodeN(
283 _Out_ PWCHAR UnicodeString,
284 _In_ ULONG UnicodeSize,
285 _Out_opt_ PULONG ResultSize,
286 _In_ PCCH OemString,
287 _In_ ULONG OemSize)
288 {
289 if (UnicodeString)
290 *UnicodeString = UNICODE_NULL;
291
292 if (ResultSize)
293 *ResultSize = 0;
294
295 return STATUS_NOT_IMPLEMENTED;
296 }
297
298 _Use_decl_annotations_
299 NTSTATUS
300 NTAPI
RtlUpcaseUnicodeToOemN(_Out_ PCHAR OemString,_In_ ULONG OemSize,_Out_opt_ PULONG ResultSize,_In_ PCWCH UnicodeString,_In_ ULONG UnicodeSize)301 RtlUpcaseUnicodeToOemN(
302 _Out_ PCHAR OemString,
303 _In_ ULONG OemSize,
304 _Out_opt_ PULONG ResultSize,
305 _In_ PCWCH UnicodeString,
306 _In_ ULONG UnicodeSize)
307 {
308 if (OemSize)
309 *OemString = ANSI_NULL;
310
311 if (ResultSize)
312 *ResultSize = 0;
313
314 return STATUS_NOT_IMPLEMENTED;
315 }
316
317 /* EOF */
318