ReactOS 0.4.17-dev-1190-g4c812f4
locale.c
Go to the documentation of this file.
1/*
2 * PROJECT: ReactOS runtime library
3 * LICENSE: MIT (https://spdx.org/licenses/MIT)
4 * PURPOSE: Rtl locale functions
5 * COPYRIGHT: Copyright 2025 Timo Kreuzer <timo.kreuzer@reactos.org>
6 */
7
8#include <rtl.h>
9
10#define NDEBUG
11#include <debug.h>
12
13// See https://winprotocoldoc.z19.web.core.windows.net/MS-LCID/%5bMS-LCID%5d.pdf
14// For special LCIDs see https://learn.microsoft.com/en-us/windows/win32/intl/locale-custom-constants
15// and https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-lcid/926e694f-1797-4418-a922-343d1c5e91a6
16// and https://learn.microsoft.com/en-us/windows/win32/intl/locale-identifiers
17
18#define MAX_PRIMARY_LANGUAGE 0x3FF
19#define MAX_BASIC_LCID 0x5FFF
20
21#define LCID_ALT_NAME 0x00100000 // Alternative name, OR'ed with LCID
22
25
26typedef struct _LOCALE_ENTRY
27{
28 const CHAR Locale[16];
29 LCID Lcid : 24;
32
33// This table is sorted alphabetically to allow binary search
35{
36 { "", 0x0007F }, // LOCALE_INVARIANT
37 { "af", 0x00036 },
38 { "af-ZA", 0x00436 },
39 { "am", 0x0005E },
40 { "am-ET", 0x0045E },
41 { "ar", 0x00001 },
42 // { "ar-145", 0x04801 }, // reserved
43 { "ar-AE", 0x03801 },
44 { "ar-BH", 0x03C01 },
45 { "ar-DZ", 0x01401 },
46 { "ar-EG", 0x00C01 },
47 { "ar-IQ", 0x00801 },
48 { "ar-JO", 0x02C01 },
49 { "ar-KW", 0x03401 },
50 { "ar-LB", 0x03001 },
51 { "ar-LY", 0x01001 },
52 { "ar-MA", 0x01801 },
53 { "ar-OM", 0x02001 },
54 // { "ar-Ploc-SA", 0x04401 }, // reserved
55 { "ar-QA", 0x04001 },
56 { "ar-SA", 0x00401 },
57 { "ar-SY", 0x02801 },
58 { "ar-TN", 0x01C01 },
59 { "ar-YE", 0x02401 },
60 { "arn", 0x0007A },
61 { "arn-CL", 0x0047A },
62 { "as", 0x0004D },
63 { "as-IN", 0x0044D },
64 { "az", 0x0002C },
65 { "az-Cyrl", 0x0742C },
66 { "az-Cyrl-AZ", 0x0082C }, // Doc: reserved
67 { "az-Latn", 0x0782C },
68 { "az-Latn-AZ", 0x0042C },
69 { "ba", 0x0006D },
70 { "ba-RU", 0x0046D },
71 { "be", 0x00023 },
72 { "be-BY", 0x00423 },
73 { "bg", 0x00002 },
74 { "bg-BG", 0x00402 },
75 { "bin", 0x00066 }, // Doc: reserved
76 { "bin-NG", 0x00466 }, // Doc: reserved
77 { "bn", 0x00045 },
78 { "bn-BD", 0x00845 },
79 { "bn-IN", 0x00445 },
80 { "bo", 0x00051 },
81 // { "bo-BT", 0x00851 }, // reserved
82 { "bo-CN", 0x00451 },
83 { "br", 0x0007E },
84 { "br-FR", 0x0047E },
85 { "bs", 0x0781A },
86 { "bs-Cyrl", 0x0641A },
87 { "bs-Cyrl-BA", 0x0201A },
88 { "bs-Latn", 0x0681A },
89 { "bs-Latn-BA", 0x0141A },
90 { "ca", 0x00003 },
91 { "ca-ES", 0x00403 },
92 { "ca-ES-valencia", 0x00803 },
93 { "chr", 0x0005C },
94 { "chr-Cher", 0x07C5C },
95 { "chr-Cher-US", 0x0045C },
96 { "co", 0x00083 },
97 { "co-FR", 0x00483 },
98 { "cs", 0x00005 },
99 { "cs-CZ", 0x00405 },
100 { "cy", 0x00052 },
101 { "cy-GB", 0x00452 },
102 { "da", 0x00006 },
103 { "da-DK", 0x00406 },
104 { "de", 0x00007 },
105 { "de-AT", 0x00C07 },
106 { "de-CH", 0x00807 },
107 { "de-DE", 0x00407 },
108 { "de-DE_phoneb", 0x10407 },
109 { "de-LI", 0x01407 },
110 { "de-LU", 0x01007 },
111 { "dsb", 0x07C2E },
112 { "dsb-DE", 0x0082E },
113 { "dv", 0x00065 },
114 { "dv-MV", 0x00465 },
115 { "dz-BT", 0x00C51 },
116 { "el", 0x00008 },
117 { "el-GR", 0x00408 },
118 { "en", 0x00009 },
119 { "en-029", 0x02409 }, // Doc: reserved
120 { "en-AE", 0x04C09 },
121 { "en-AU", 0x00C09 },
122 // { "en-BH", 0x05009 }, // reserved
123 { "en-BZ", 0x02809 },
124 { "en-CA", 0x01009 },
125 // { "en-EG", 0x05409 }, // reserved
126 { "en-GB", 0x00809 },
127 { "en-HK", 0x03C09 },
128 { "en-ID", 0x03809 }, // reserved
129 { "en-IE", 0x01809 },
130 { "en-IN", 0x04009 },
131 { "en-JM", 0x02009 },
132 // { "en-JO", 0x05809 }, // reserved
133 // { "en-KW", 0x05C09 }, // reserved
134 { "en-MY", 0x04409 },
135 { "en-NZ", 0x01409 },
136 { "en-PH", 0x03409 },
137 { "en-SG", 0x04809 },
138 // { "en-TR", 0x6009 }, // reserved
139 { "en-TT", 0x02C09 },
140 { "en-US", 0x00409 },
141 // { "en-YE", 0x6409 }, // reserved
142 { "en-ZA", 0x01C09 },
143 { "en-ZW", 0x03009 },
144 { "es", 0x0000A },
145 { "es-419", 0x0580A }, // Doc: reserved
146 { "es-AR", 0x02C0A },
147 { "es-BO", 0x0400A },
148 { "es-CL", 0x0340A },
149 { "es-CO", 0x0240A },
150 { "es-CR", 0x0140A },
151 { "es-CU", 0x05C0A },
152 { "es-DO", 0x01C0A },
153 { "es-EC", 0x0300A },
154 { "es-ES", 0x00C0A },
155 { "es-ES_tradnl", 0x0040A },
156 { "es-GT", 0x0100A },
157 { "es-HN", 0x0480A },
158 { "es-MX", 0x0080A },
159 { "es-NI", 0x04C0A },
160 { "es-PA", 0x0180A },
161 { "es-PE", 0x0280A },
162 { "es-PR", 0x0500A },
163 { "es-PY", 0x03C0A },
164 { "es-SV", 0x0440A },
165 { "es-US", 0x0540A },
166 { "es-UY", 0x0380A },
167 { "es-VE", 0x0200A },
168 { "et", 0x00025 },
169 { "et-EE", 0x00425 },
170 { "eu", 0x0002D },
171 { "eu-ES", 0x0042D },
172 { "fa", 0x00029 },
173 { "fa-IR", 0x00429 },
174 { "ff", 0x00067 },
175 { "ff-Latn", 0x07C67 },
176 { "ff-Latn-NG", 0x00467 },
177 { "ff-Latn-SN", 0x00867 },
178 { "ff-NG", 0x00467 | LCID_ALT_NAME },
179 { "fi", 0x0000B },
180 { "fi-FI", 0x0040B },
181 { "fil", 0x00064 },
182 { "fil-PH", 0x00464 },
183 { "fo", 0x00038 },
184 { "fo-FO", 0x00438 },
185 { "fr", 0x0000C },
186 // { "fr-015", 0x0E40C }, // reserved
187 { "fr-029", 0x01C0C },
188 { "fr-BE", 0x0080C },
189 { "fr-CA", 0x00C0C },
190 { "fr-CD", 0x0240C },
191 { "fr-CH", 0x0100C },
192 { "fr-CI", 0x0300C },
193 { "fr-CM", 0x02C0C },
194 { "fr-FR", 0x0040C },
195 { "fr-HT", 0x03C0C },
196 { "fr-LU", 0x0140C },
197 { "fr-MA", 0x0380C },
198 { "fr-MC", 0x0180C },
199 { "fr-ML", 0x0340C },
200 { "fr-RE", 0x0200C },
201 { "fr-SN", 0x0280C },
202 { "fy", 0x00062 },
203 { "fy-NL", 0x00462 },
204 { "ga", 0x0003C },
205 { "ga-IE", 0x0083C },
206 { "gd", 0x00091 },
207 { "gd-GB", 0x00491 },
208 { "gl", 0x00056 },
209 { "gl-ES", 0x00456 },
210 { "gn", 0x00074 },
211 { "gn-PY", 0x00474 },
212 { "gsw", 0x00084 },
213 { "gsw-FR", 0x00484 },
214 { "gu", 0x00047 },
215 { "gu-IN", 0x00447 },
216 { "ha", 0x00068 },
217 { "ha-Latn", 0x07C68 },
218 { "ha-Latn-NG", 0x00468 },
219 { "haw", 0x00075 },
220 { "haw-US", 0x00475 },
221 { "he", 0x0000D },
222 { "he-IL", 0x0040D },
223 { "hi", 0x00039 },
224 { "hi-IN", 0x00439 },
225 { "hr", 0x0001A },
226 { "hr-BA", 0x0101A },
227 { "hr-HR", 0x0041A },
228 { "hsb", 0x0002E },
229 { "hsb-DE", 0x0042E },
230 { "hu", 0x0000E },
231 { "hu-HU", 0x0040E },
232 { "hu-HU_technl", 0x1040E },
233 { "hy", 0x0002B },
234 { "hy-AM", 0x0042B },
235 { "ibb", 0x00069 }, // Doc: reserved
236 { "ibb-NG", 0x00469 }, // Doc: reserved
237 { "id", 0x00021 },
238 { "id-ID", 0x00421 },
239 { "ig", 0x00070 },
240 { "ig-NG", 0x00470 },
241 { "ii", 0x00078 },
242 { "ii-CN", 0x00478 },
243 { "is", 0x0000F },
244 { "is-IS", 0x0040F },
245 { "it", 0x00010 },
246 { "it-CH", 0x00810 },
247 { "it-IT", 0x00410 },
248 { "iu", 0x0005D },
249 { "iu-Cans", 0x0785D },
250 { "iu-Cans-CA", 0x0045D },
251 { "iu-Latn", 0x07C5D },
252 { "iu-Latn-CA", 0x0085D },
253 { "ja", 0x00011 },
254 { "ja-JP", 0x00411 },
255 { "ja-JP_radstr", 0x040411 },
256 // { "ja-Ploc-JP", 0x00811 }, // reserved
257 { "ka", 0x00037 },
258 { "ka-GE", 0x00437 },
259 { "ka-GE_modern", 0x10437 },
260 // { "khb-Talu-CN", 0x00490 }, // reserved
261 { "kk", 0x0003F },
262 { "kk-Cyrl", 0x0003F | LCID_ALT_NAME }, // Doc: 0x0783F, reserved
263 { "kk-KZ", 0x0043F },
264 // { "kk-Latn", 0x07C3F }, // reserved
265 // { "kk-Latn-KZ", 0x0083F }, // reserved
266 { "kl", 0x0006F },
267 { "kl-GL", 0x0046F },
268 { "km", 0x00053 },
269 { "km-KH", 0x00453 },
270 { "kn", 0x0004B },
271 { "kn-IN", 0x0044B },
272 { "ko", 0x00012 },
273 { "ko-KR", 0x00412 },
274 { "kok", 0x00057 },
275 { "kok-IN", 0x00457 },
276 { "kr", 0x00071 }, // Doc: reserved
277 { "kr-Latn-NG", 0x00471 },
278 { "ks", 0x00060 },
279 { "ks-Arab", 0x00460 }, // Neutral locale
280 { "ks-Deva-IN", 0x00860 },
281 { "ku", 0x00092 },
282 { "ku-Arab", 0x07C92 },
283 { "ku-Arab-IQ", 0x00492 },
284 { "ky", 0x00040 },
285 { "ky-KG", 0x00440 },
286 { "la", 0x00076 }, // reserved
287 { "la-001", 0x00476 }, // Doc: la-VA
288 { "lb", 0x0006E },
289 { "lb-LU", 0x0046E },
290 { "lo", 0x00054 },
291 { "lo-LA", 0x00454 },
292 { "lt", 0x00027 },
293 { "lt-LT", 0x00427 },
294 { "lv", 0x00026 },
295 { "lv-LV", 0x00426 },
296 { "mi", 0x00081 },
297 { "mi-NZ", 0x00481 },
298 { "mk", 0x0002F },
299 { "mk-MK", 0x0042F },
300 { "ml", 0x0004C },
301 { "ml-IN", 0x0044C },
302 { "mn", 0x00050 },
303 { "mn-Cyrl", 0x07850 },
304 { "mn-MN", 0x00450 },
305 { "mn-Mong", 0x07C50 },
306 { "mn-Mong-CN", 0x00850 }, // Doc: reserved
307 { "mn-Mong-MN", 0x00C50 },
308 { "mni", 0x00058 }, // Doc: reserved
309 { "mni-IN", 0x00458 }, // Doc: reserved
310 { "moh", 0x0007C },
311 { "moh-CA", 0x0047C },
312 { "mr", 0x0004E },
313 { "mr-IN", 0x0044E },
314 { "ms", 0x0003E },
315 { "ms-BN", 0x0083E },
316 { "ms-MY", 0x0043E },
317 { "mt", 0x0003A },
318 { "mt-MT", 0x0043A },
319 { "my", 0x00055 },
320 { "my-MM", 0x00455 },
321 { "nb", 0x07C14 },
322 { "nb-NO", 0x00414 },
323 { "ne", 0x00061 },
324 { "ne-IN", 0x00861 },
325 { "ne-NP", 0x00461 },
326 { "nl", 0x00013 },
327 { "nl-BE", 0x00813 },
328 { "nl-NL", 0x00413 },
329 { "nn", 0x07814 },
330 { "nn-NO", 0x00814 },
331 { "no", 0x00014 },
332 { "nso", 0x0006C },
333 { "nso-ZA", 0x0046C },
334 { "oc", 0x00082 },
335 { "oc-FR", 0x00482 },
336 { "om", 0x00072 },
337 { "om-ET", 0x00472 },
338 { "or", 0x00048 },
339 { "or-IN", 0x00448 },
340 { "pa", 0x00046 },
341 { "pa-Arab", 0x07C46 },
342 { "pa-Arab-PK", 0x00846 },
343 { "pa-IN", 0x00446 },
344 { "pap", 0x00079 }, // Doc: reserved
345 { "pap-029", 0x00479 }, // Doc: reserved
346 { "pl", 0x00015 },
347 { "pl-PL", 0x00415 },
348 // { "plt-MG", 0x0048D }, // reserved
349 { "prs", 0x0008C },
350 { "prs-AF", 0x0048C },
351 { "ps", 0x00063 },
352 { "ps-AF", 0x00463 },
353 { "pt", 0x00016 },
354 { "pt-BR", 0x00416 },
355 { "pt-PT", 0x00816 },
356 { "qps-ploc", 0x00501 },
357 { "qps-ploca", 0x005FE },
358 { "qps-plocm", 0x009FF },
359 { "quc", 0x00086 }, // Doc: 0x00093, reserved
360 // { "quc-CO", 0x00493 }, // reserved
361 { "quc-Latn-GT", 0x00486 }, // Doc: qut-GT, reserved
362 { "qut", 0x00086 | LCID_ALT_NAME },
363 { "qut-GT", 0x00486 | LCID_ALT_NAME }, // reserved
364 { "quz", 0x0006B },
365 { "quz-BO", 0x0046B },
366 { "quz-EC", 0x0086B },
367 { "quz-PE", 0x00C6b },
368 { "rm", 0x00017 },
369 { "rm-CH", 0x00417 },
370 { "ro", 0x00018 },
371 { "ro-MD", 0x00818 },
372 { "ro-RO", 0x00418 },
373 { "ru", 0x00019 },
374 { "ru-MD", 0x00819 },
375 { "ru-RU", 0x00419 },
376 { "rw", 0x00087 },
377 { "rw-RW", 0x00487 },
378 { "sa", 0x0004F },
379 { "sa-IN", 0x0044F },
380 { "sah", 0x00085 },
381 { "sah-RU", 0x00485 },
382 { "sd", 0x00059 },
383 { "sd-Arab", 0x07C59 },
384 { "sd-Arab-PK", 0x00859 },
385 { "sd-Deva-IN", 0x00459 }, // Doc: reserved
386 { "se", 0x0003B },
387 { "se-FI", 0x00C3B },
388 { "se-NO", 0x0043B },
389 { "se-SE", 0x0083B },
390 { "si", 0x0005B },
391 { "si-LK", 0x0045B },
392 { "sk", 0x0001B },
393 { "sk-SK", 0x0041B },
394 { "sl", 0x00024 },
395 { "sl-SI", 0x00424 },
396 { "sma", 0x0783B },
397 { "sma-NO", 0x0183B },
398 { "sma-SE", 0x01C3B },
399 { "smj", 0x07C3B },
400 { "smj-NO", 0x0103B },
401 { "smj-SE", 0x0143B },
402 { "smn", 0x0703B },
403 { "smn-FI", 0x0243B },
404 { "sms", 0x0743B },
405 { "sms-FI", 0x0203B },
406 { "so", 0x00077 }, // Doc: reserved
407 { "so-SO", 0x00477 },
408 { "sq", 0x0001C },
409 { "sq-AL", 0x0041C },
410 { "sr", 0x07C1A },
411 { "sr-Cyrl", 0x06C1A },
412 { "sr-Cyrl-BA", 0x01C1A },
413 { "sr-Cyrl-CS", 0x00C1A },
414 { "sr-Cyrl-ME", 0x0301A },
415 { "sr-Cyrl-RS", 0x0281A },
416 { "sr-Latn", 0x0701A },
417 { "sr-Latn-BA", 0x0181A },
418 { "sr-Latn-CS", 0x0081A },
419 { "sr-Latn-ME", 0x02C1A },
420 { "sr-Latn-RS", 0x0241A },
421 { "st", 0x00030 },
422 { "st-ZA", 0x00430 },
423 { "sv", 0x0001D },
424 { "sv-FI", 0x0081D },
425 { "sv-SE", 0x0041D },
426 { "sw", 0x00041 },
427 { "sw-KE", 0x00441 },
428 { "syr", 0x0005A },
429 { "syr-SY", 0x0045A },
430 { "ta", 0x00049 },
431 { "ta-IN", 0x00449 },
432 { "ta-LK", 0x00849 },
433 // { "tdd-Tale-CN", 0x0048F }, // reserved
434 { "te", 0x0004A },
435 { "te-IN", 0x0044A },
436 { "tg", 0x00028 },
437 { "tg-Cyrl", 0x07C28 },
438 { "tg-Cyrl-TJ", 0x00428 },
439 { "th", 0x0001E },
440 { "th-TH", 0x0041E },
441 { "ti", 0x00073 },
442 { "ti-ER", 0x00873 },
443 { "ti-ET", 0x00473 },
444 { "tk", 0x00042 },
445 { "tk-TM", 0x00442 },
446 // { "tmz-MA", 0x00C5F }, // reserved
447 { "tn", 0x00032 },
448 { "tn-BW", 0x00832 },
449 { "tn-ZA", 0x00432 },
450 { "tr", 0x0001F },
451 { "tr-TR", 0x0041F },
452 { "ts", 0x00031 },
453 { "ts-ZA", 0x00431 },
454 { "tt", 0x00044 },
455 { "tt-RU", 0x00444 },
456 { "tzm", 0x0005F },
457 { "tzm-Arab-MA", 0x0045F },
458 { "tzm-Latn", 0x07C5F },
459 { "tzm-Latn-DZ", 0x0085F },
460 { "tzm-Tfng", 0x0785F },
461 { "tzm-Tfng-MA", 0x0105F },
462 { "ug", 0x00080 },
463 { "ug-CN", 0x00480 },
464 { "uk", 0x00022 },
465 { "uk-UA", 0x00422 },
466 { "ur", 0x00020 },
467 { "ur-IN", 0x00820 },
468 { "ur-PK", 0x00420 },
469 { "uz", 0x00043 },
470 { "uz-Cyrl", 0x07843 },
471 { "uz-Cyrl-UZ", 0x00843 }, // Doc: reserved
472 { "uz-Latn", 0x07C43 },
473 { "uz-Latn-UZ", 0x00443 },
474 { "ve", 0x00033 },
475 { "ve-ZA", 0x00433 },
476 { "vi", 0x0002A },
477 { "vi-VN", 0x0042A },
478 { "wo", 0x00088 },
479 { "wo-SN", 0x00488 },
480 { "xh", 0x00034 },
481 { "xh-ZA", 0x00434 },
482 { "yi", 0x0003D }, // Doc: reserved
483 { "yi-001", 0x0043D },
484 { "yo", 0x0006A },
485 { "yo-NG", 0x0046A },
486 { "zh", 0x07804 },
487 { "zh-CN", 0x00804 },
488 { "zh-CN_stroke", 0x20804 },
489 { "zh-Hans", 0x00004 },
490 { "zh-Hant", 0x07C04 },
491 { "zh-HK", 0x00C04 },
492 { "zh-HK_radstr", 0x40C04 },
493 { "zh-MO", 0x01404 },
494 { "zh-MO_radstr", 0x41404 },
495 { "zh-SG", 0x01004 },
496 { "zh-SG_stroke", 0x21004 },
497 { "zh-TW", 0x00404 },
498 { "zh-TW_pronun", 0x30404 },
499 { "zh-TW_radstr", 0x40404 },
500 // { "zh-yue-HK", 0x0048E }, // reserved
501 { "zu", 0x00035 },
502 { "zu-ZA", 0x00435 },
503};
504
505// This table will be sorted by LCID at runtime
507
514NTAPI
516{
519
520 for (USHORT i = 0; i < ARRAYSIZE(RtlpLocaleTable); i++)
521 {
523 USHORT j = i;
524
525 while ((j > 0) && (RtlpLocaleTable[RtlpLocaleIndexTable[j - 1]].Lcid > Lcid))
526 {
528 j--;
529 }
530
532 }
533
534 return STATUS_SUCCESS;
535}
536
538static
539ULONG
541 _In_ LCID Lcid)
542{
543 USHORT TableIndex;
544 LONG Low = 0;
546 LONG Middle;
547 LCID CurrentLcid;
548
549 while (Low <= High)
550 {
551 Middle = (Low + High) / 2;
552
553 /* Use the indirection table to get the real table entry */
554 TableIndex = RtlpLocaleIndexTable[Middle];
555 ASSERT(TableIndex < ARRAYSIZE(RtlpLocaleTable));
556
557 /* Compare the LCID (including the alternative name flag!) */
558 CurrentLcid = RtlpLocaleTable[TableIndex].Lcid;
559 if (CurrentLcid < Lcid)
560 {
561 Low = Middle + 1;
562 }
563 else if (CurrentLcid > Lcid)
564 {
565 High = Middle - 1;
566 }
567 else /* CurrentLcid == Lcid */
568 {
569 return RtlpLocaleIndexTable[Middle];
570 }
571 }
572
573 return MAXULONG;
574}
575
576#define LOWERCASE_CHAR(Char) \
577 (((Char) >= 'A' && (Char) <= 'Z') ? ((Char) + ('a' - 'A')) : (Char))
578
580static
581INT
583 _In_ PCSTR AsciiLocaleName,
584 _In_ PCUNICODE_STRING UnicodeLocaleName)
585{
586 ULONG i;
587
588 /* Do a case-insensitive comparison. */
589 for (i = 0; i < UnicodeLocaleName->Length / sizeof(WCHAR); i++)
590 {
591 /* Make the 2 chars lower case for comparison */
592 CHAR Char1 = LOWERCASE_CHAR(AsciiLocaleName[i]);
593 WCHAR Char2 = LOWERCASE_CHAR(UnicodeLocaleName->Buffer[i]);
594
595 /* Keep comparing, while they are equal */
596 if (Char1 == Char2)
597 {
598 continue;
599 }
600
601 /* Check if the ASCII string ends first */
602 if (AsciiLocaleName[i] == '\0')
603 {
604 /* The 1st string is shorter than the 2nd, i.e. smaller */
605 return -1;
606 }
607
608 /* Return the difference between the two characters */
609 return (INT)Char1 - (INT)Char2;
610 }
611
612 /* The strings match up to the lenth of the unicode string.
613 If the ASCII string ends here, they are equal. */
614 if (AsciiLocaleName[i] == '\0')
615 {
616 return 0;
617 }
618
619 /* The 1st string is longer than the 2nd, i.e. larger */
620 return 1;
621}
622
624static
625ULONG
628{
629 LONG Low = 0;
631 LONG Middle;
632 PCSTR CurrentLocaleName;
633 INT CompareResult;
634
635 while (Low <= High)
636 {
637 Middle = (Low + High) / 2;
638
639 CurrentLocaleName = RtlpLocaleTable[Middle].Locale;
640 CompareResult = CompareLocaleNames(CurrentLocaleName, LocaleName);
641 if (CompareResult < 0)
642 {
643 Low = Middle + 1;
644 }
645 else if (CompareResult > 0)
646 {
647 High = Middle - 1;
648 }
649 else /* CompareResult == 0 */
650 {
651 return Middle;
652 }
653 }
654
655 return MAXULONG;
656}
657
659static
663 _In_ PCSTR AsciiString)
664{
665 SIZE_T AsciiLength = strlen(AsciiString);
666
667 /* Make sure we can copy the full string, including the terminating 0 */
668 if (UnicodeString->MaximumLength < (AsciiLength + 1) * sizeof(WCHAR))
669 {
670 return FALSE;
671 }
672
673 /* Copy the string manually */
674 for (SIZE_T i = 0; i < AsciiLength; i++)
675 {
676 UnicodeString->Buffer[i] = (WCHAR)AsciiString[i];
677 }
678
679 /* Add the terminating 0 and update the Length */
680 UnicodeString->Buffer[AsciiLength] = UNICODE_NULL;
681 UnicodeString->Length = (USHORT)(AsciiLength * sizeof(WCHAR));
682
683 return TRUE;
684}
685
686static
689 _In_ LCID Lcid)
690{
691 /* Check if the LCID is within the neutral locale range */
692 if (((Lcid <= MAX_PRIMARY_LANGUAGE) && (Lcid != LOCALE_INVARIANT)) ||
693 (Lcid == 0x0460) /* ks-Arab */ ||
694 ((Lcid & 0xFFFF) > MAX_BASIC_LCID))
695 {
696 return TRUE;
697 }
698
699 return FALSE;
700}
701
703NTAPI
705 _In_ LCID Lcid,
709{
710 ULONG LocaleIndex;
711
712 /* Check for invalid flags */
713 if (Flags & ~0x2)
714 {
715 DPRINT1("RtlLcidToLocaleName: Invalid flags: 0x%lx\n", Flags);
717 }
718
719 /* Check if the LocaleName buffer is valid */
720 if ((LocaleName == NULL) || (LocaleName->Buffer == NULL))
721 {
722 DPRINT1("RtlLcidToLocaleName: Invalid buffer\n");
724 }
725
726 /* Validate LCID */
728 {
729 DPRINT1("RtlLcidToLocaleName: Invalid LCID: 0x%lx\n", Lcid);
731 }
732
733 /* Check if neutral locales were requested */
734 if ((Flags & RTL_LOCALE_ALLOW_NEUTRAL_NAMES) == 0)
735 {
736 /* Check if this is a neutral locale */
738 {
739 DPRINT("RtlLcidToLocaleName: Neutral LCID: 0x%lx\n", Lcid);
741 }
742 }
743
744 /* Handle special LCIDs */
745 switch (Lcid)
746 {
749 break;
750
754 break;
755
757 return STATUS_UNSUCCESSFUL;
758 }
759
760 /* Try to find the locale by LCID */
761 LocaleIndex = FindIndexByLcid(Lcid);
762 if (LocaleIndex == MAXULONG)
763 {
764 DPRINT("RtlLcidToLocaleName: LCID 0x%lx not found\n", Lcid);
766 }
767
768 /* Copy the locale name to the buffer */
769 if (!CopyAsciizToUnicodeString(LocaleName, RtlpLocaleTable[LocaleIndex].Locale))
770 {
771 DPRINT("RtlLcidToLocaleName: Buffer too small\n");
773 }
774
775 return STATUS_SUCCESS;
776}
777
779static
785{
786 ULONG LocaleIndex;
787 LCID FoundLcid;
788
789 /* Check if LocaleName points to a valid unicode string */
790 if ((LocaleName == NULL) || (LocaleName->Buffer == NULL))
791 {
792 DPRINT1("RtlpLocaleNameToLcidInternal: Invalid buffer\n");
794 }
795
796 /* Check if the Lcid pointer is valid */
797 if (Lcid == NULL)
798 {
799 DPRINT1("RtlpLocaleNameToLcidInternal: Lcid is NULL\n");
801 }
802
803 /* Check for invalid flags */
804 if (Flags & ~0x3)
805 {
806 DPRINT1("RtlpLocaleNameToLcidInternal: Invalid flags: 0x%lx\n", Flags);
808 }
809
810 /* Try to find the locale */
811 LocaleIndex = FindIndexByLocaleName(LocaleName);
812 if (LocaleIndex == MAXULONG)
813 {
814 DPRINT("RtlpLocaleNameToLcidInternal: Locale name not found\n");
816 }
817
818 /* Extract the LCID without the flags */
819 FoundLcid = RtlpLocaleTable[LocaleIndex].Lcid & NLS_VALID_LOCALE_MASK;
820
821 /* Check if neutral locales were requested */
822 if ((Flags & RTL_LOCALE_ALLOW_NEUTRAL_NAMES) == 0)
823 {
824 /* Check if this is a neutral locale */
825 if (IsNeutralLocale(FoundLcid))
826 {
827 DPRINT("RtlpLocaleNameToLcidInternal: Neutral LCID: 0x%lx\n", FoundLcid);
829 }
830 }
831
832 /* Copy the LCID to the output buffer */
833 *Lcid = FoundLcid;
834
835 return STATUS_SUCCESS;
836}
837
838
840NTAPI
845{
846 UNICODE_STRING LocaleNameString;
847
848 /* Convert the string to a UNICODE_STRING */
849 RtlInitUnicodeString(&LocaleNameString, LocaleName);
850
851 /* Forward to internal function */
852 return RtlpLocaleNameToLcidInternal(&LocaleNameString, Lcid, Flags);
853}
854
855_Success_(return != FALSE)
857NTAPI
858RtlLCIDToCultureName(
859 _In_ LCID Lcid,
861{
863
864 /* Forward to RtlLcidToLocaleName, include neutral names */
865 Status = RtlLcidToLocaleName(Lcid, String, RTL_LOCALE_ALLOW_NEUTRAL_NAMES, FALSE);
866 if (!NT_SUCCESS(Status))
867 {
868 DPRINT1("RtlLcidToLocaleName failed with status 0x%lx\n", Status);
869 return FALSE;
870 }
871
872 return TRUE;
873}
874
875_Success_(return != FALSE)
877NTAPI
878RtlCultureNameToLCID(
881{
883
884 if ((String == NULL) ||
885 (String->Buffer == NULL) ||
886 (String->Buffer[0] == UNICODE_NULL))
887 {
888 return FALSE;
889 }
890
891 /* Forward to internal function, include neutral names */
892 Status = RtlpLocaleNameToLcidInternal(String, Lcid, RTL_LOCALE_ALLOW_NEUTRAL_NAMES);
893 if (!NT_SUCCESS(Status))
894 {
895 DPRINT1("RtlpLocaleNameToLcidInternal failed with status 0x%lx\n", Status);
896 return FALSE;
897 }
898
899 return TRUE;
900}
901
903NTAPI
907{
909 return TRUE;
910}
911
913NTAPI
915 _In_ LCID LcidValue,
917 _In_ ULONG Padding,
918 _Out_writes_(Size) PWSTR pResultBuf,
920{
923}
static _In_ LPCWSTR LocaleName
unsigned char BOOLEAN
Definition: actypes.h:127
LONG NTSTATUS
Definition: precomp.h:26
#define DPRINT1
Definition: precomp.h:8
#define UNIMPLEMENTED
Definition: ntoskrnl.c:15
#define ARRAYSIZE(a)
Definition: cat.c:25
#define STATUS_NOT_IMPLEMENTED
Definition: d3dkmdt.h:42
_In_ D3DDDI_VIDEO_PRESENT_TARGET_ID _In_ ULONG _In_ ULONG Flags
Definition: dispmprt.h:245
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:33
_ACRTIMP size_t __cdecl strlen(const char *)
Definition: string.c:1597
Status
Definition: gdiplustypes.h:24
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint GLint GLint j
Definition: glfuncs.h:250
#define ASSERT(a)
Definition: mode.c:44
static const SYSTEMTIME INT
Definition: locale.c:57
_Out_ PLCID Lcid
Definition: rtlfuncs.h:5258
_In_ PSID _In_ BOOLEAN AllocateDestinationString
Definition: rtlfuncs.h:1381
_In_opt_ ULONG Base
Definition: rtlfuncs.h:2486
#define _Inout_
Definition: no_sal2.h:162
#define _Success_(c)
Definition: no_sal2.h:84
#define _Must_inspect_result_
Definition: no_sal2.h:62
#define _Out_writes_(s)
Definition: no_sal2.h:176
#define _Out_
Definition: no_sal2.h:160
#define _In_
Definition: no_sal2.h:158
NTSYSAPI VOID NTAPI RtlInitUnicodeString(PUNICODE_STRING DestinationString, PCWSTR SourceString)
#define _ARRAYSIZE(A)
Definition: ntbasedef.h:713
* PLCID
Definition: ntbasedef.h:521
#define LOCALE_USER_DEFAULT
#define LOCALE_INVARIANT
#define LOCALE_CUSTOM_DEFAULT
#define LOCALE_SYSTEM_DEFAULT
#define UNICODE_NULL
#define LOCALE_CUSTOM_UI_DEFAULT
#define NLS_VALID_LOCALE_MASK
NTSTATUS NTAPI NtQueryDefaultLocale(IN BOOLEAN UserProfile, OUT PLCID DefaultLocaleId)
Definition: locale.c:392
#define STATUS_INVALID_PARAMETER_2
Definition: ntstatus.h:570
#define STATUS_INVALID_PARAMETER_1
Definition: ntstatus.h:569
#define STATUS_INVALID_PARAMETER_3
Definition: ntstatus.h:571
short WCHAR
Definition: pedump.c:58
long LONG
Definition: pedump.c:60
unsigned short USHORT
Definition: pedump.c:61
char CHAR
Definition: pedump.c:57
DWORD LCID
Definition: nls.h:13
NTSTATUS NTAPI RtlConvertLCIDToString(_In_ LCID LcidValue, _In_ ULONG Base, _In_ ULONG Padding, _Out_writes_(Size) PWSTR pResultBuf, _In_ ULONG Size)
Definition: locale.c:914
static USHORT RtlpLocaleIndexTable[_ARRAYSIZE(RtlpLocaleTable)]
Definition: locale.c:506
static _Must_inspect_result_ INT CompareLocaleNames(_In_ PCSTR AsciiLocaleName, _In_ PCUNICODE_STRING UnicodeLocaleName)
Definition: locale.c:582
LCID RtlpUserDefaultLcid
Definition: locale.c:23
static const LOCALE_ENTRY RtlpLocaleTable[]
Definition: locale.c:34
struct _LOCALE_ENTRY LOCALE_ENTRY
NTSTATUS NTAPI RtlpInitializeLocaleTable(VOID)
Initializes the locale index table, that maps the LCIDs to their indexes in the alphabetical table,...
Definition: locale.c:515
#define MAX_PRIMARY_LANGUAGE
Definition: locale.c:18
static _Must_inspect_result_ NTSTATUS RtlpLocaleNameToLcidInternal(_In_ PCUNICODE_STRING LocaleName, _Out_ PLCID Lcid, _In_ ULONG Flags)
Definition: locale.c:781
#define LCID_ALT_NAME
Definition: locale.c:21
LCID RtlpSystemDefaultLcid
Definition: locale.c:24
static _Must_inspect_result_ ULONG FindIndexByLcid(_In_ LCID Lcid)
Definition: locale.c:540
static BOOLEAN IsNeutralLocale(_In_ LCID Lcid)
Definition: locale.c:688
#define LOWERCASE_CHAR(Char)
Definition: locale.c:576
static _Must_inspect_result_ BOOLEAN CopyAsciizToUnicodeString(_Inout_ PUNICODE_STRING UnicodeString, _In_ PCSTR AsciiString)
Definition: locale.c:661
#define MAX_BASIC_LCID
Definition: locale.c:19
static _Must_inspect_result_ ULONG FindIndexByLocaleName(_In_ PCUNICODE_STRING LocaleName)
Definition: locale.c:626
#define STATUS_SUCCESS
Definition: shellext.h:65
#define STATUS_BUFFER_TOO_SMALL
Definition: shellext.h:69
#define DPRINT
Definition: sndvol32.h:73
@ High
Definition: strmini.h:378
@ Low
Definition: strmini.h:380
Definition: locale.c:27
const CHAR Locale[16]
Definition: locale.c:28
LCID Lcid
Definition: locale.c:29
ULONG Flags
Definition: locale.c:30
USHORT MaximumLength
Definition: env_spec_w32.h:370
uint16_t * PWSTR
Definition: typedefs.h:56
#define MAXULONG
Definition: typedefs.h:251
const uint16_t * PCWSTR
Definition: typedefs.h:57
const uint16_t * LPCWSTR
Definition: typedefs.h:57
#define NTAPI
Definition: typedefs.h:36
ULONG_PTR SIZE_T
Definition: typedefs.h:80
int32_t INT
Definition: typedefs.h:58
const char * PCSTR
Definition: typedefs.h:52
uint32_t ULONG
Definition: typedefs.h:59
#define STATUS_UNSUCCESSFUL
Definition: udferr_usr.h:132
_Must_inspect_result_ _In_ WDFDEVICE _In_ PWDF_DEVICE_PROPERTY_DATA _In_ DEVPROPTYPE _In_ ULONG Size
Definition: wdfdevice.h:4539
_Must_inspect_result_ _In_ WDFDEVICE _In_ WDFSTRING String
Definition: wdfdevice.h:2439
WDF_EXTERN_C_START typedef _Must_inspect_result_ _In_opt_ PCUNICODE_STRING UnicodeString
Definition: wdfstring.h:64
NTSYSAPI NTSTATUS WINAPI RtlLocaleNameToLcid(const WCHAR *, LCID *, ULONG)
NTSYSAPI BOOLEAN WINAPI RtlIsValidLocaleName(const WCHAR *, ULONG)
NTSYSAPI NTSTATUS WINAPI RtlLcidToLocaleName(LCID, UNICODE_STRING *, ULONG, BOOLEAN)