4 * Copyright 1995 Martin von Loewis
5 * Copyright 1998 David Lee Lambert
6 * Copyright 2000 Julio César Gázquez
7 * Copyright 2003 Jon Griffiths
8 * Copyright 2005 Dmitry Timoshkov
9 * Copyright 2002, 2019 Alexandre Julliard
11 * This library is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public
13 * License as published by the Free Software Foundation; either
14 * version 2.1 of the License, or (at your option) any later version.
16 * This library is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Lesser General Public License for more details.
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with this library; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
30 #define WIN32_NO_STATUS
31 #define WINNORMALIZEAPI
38 #include "kernelbase.h"
39 #include "wine/debug.h"
41 WINE_DEFAULT_DEBUG_CHANNEL(nls
);
43 #define CALINFO_MAX_YEAR 2029
45 extern const unsigned int collation_table
[] DECLSPEC_HIDDEN
;
47 static HANDLE kernel32_handle
;
49 static const struct registry_value
55 { LOCALE_ICALENDARTYPE
, L
"iCalendarType" },
56 { LOCALE_ICURRDIGITS
, L
"iCurrDigits" },
57 { LOCALE_ICURRENCY
, L
"iCurrency" },
58 { LOCALE_IDIGITS
, L
"iDigits" },
59 { LOCALE_IFIRSTDAYOFWEEK
, L
"iFirstDayOfWeek" },
60 { LOCALE_IFIRSTWEEKOFYEAR
, L
"iFirstWeekOfYear" },
61 { LOCALE_ILZERO
, L
"iLZero" },
62 { LOCALE_IMEASURE
, L
"iMeasure" },
63 { LOCALE_INEGCURR
, L
"iNegCurr" },
64 { LOCALE_INEGNUMBER
, L
"iNegNumber" },
65 { LOCALE_IPAPERSIZE
, L
"iPaperSize" },
66 { LOCALE_ITIME
, L
"iTime" },
67 { LOCALE_S1159
, L
"s1159" },
68 { LOCALE_S2359
, L
"s2359" },
69 { LOCALE_SCURRENCY
, L
"sCurrency" },
70 { LOCALE_SDATE
, L
"sDate" },
71 { LOCALE_SDECIMAL
, L
"sDecimal" },
72 { LOCALE_SGROUPING
, L
"sGrouping" },
73 { LOCALE_SLIST
, L
"sList" },
74 { LOCALE_SLONGDATE
, L
"sLongDate" },
75 { LOCALE_SMONDECIMALSEP
, L
"sMonDecimalSep" },
76 { LOCALE_SMONGROUPING
, L
"sMonGrouping" },
77 { LOCALE_SMONTHOUSANDSEP
, L
"sMonThousandSep" },
78 { LOCALE_SNEGATIVESIGN
, L
"sNegativeSign" },
79 { LOCALE_SPOSITIVESIGN
, L
"sPositiveSign" },
80 { LOCALE_SSHORTDATE
, L
"sShortDate" },
81 { LOCALE_STHOUSAND
, L
"sThousand" },
82 { LOCALE_STIME
, L
"sTime" },
83 { LOCALE_STIMEFORMAT
, L
"sTimeFormat" },
84 { LOCALE_SYEARMONTH
, L
"sYearMonth" },
85 /* The following are not listed under MSDN as supported,
86 * but seem to be used and also stored in the registry.
88 { LOCALE_SNAME
, L
"LocaleName" },
89 { LOCALE_ICOUNTRY
, L
"iCountry" },
90 { LOCALE_IDATE
, L
"iDate" },
91 { LOCALE_ILDATE
, L
"iLDate" },
92 { LOCALE_ITLZERO
, L
"iTLZero" },
93 { LOCALE_SCOUNTRY
, L
"sCountry" },
94 { LOCALE_SABBREVLANGNAME
, L
"sLanguage" },
95 { LOCALE_IDIGITSUBSTITUTION
, L
"Numshape" },
96 { LOCALE_SNATIVEDIGITS
, L
"sNativeDigits" },
97 { LOCALE_ITIMEMARKPOSN
, L
"iTimePrefix" },
100 static WCHAR
*registry_cache
[ARRAY_SIZE(registry_values
)];
102 static const struct { UINT cp
; const WCHAR
*name
; } codepage_names
[] =
104 { 37, L
"IBM EBCDIC US Canada" },
105 { 424, L
"IBM EBCDIC Hebrew" },
106 { 437, L
"OEM United States" },
107 { 500, L
"IBM EBCDIC International" },
108 { 708, L
"Arabic ASMO" },
109 { 720, L
"Arabic (Transparent ASMO)" },
110 { 737, L
"OEM Greek 437G" },
111 { 775, L
"OEM Baltic" },
112 { 850, L
"OEM Multilingual Latin 1" },
113 { 852, L
"OEM Slovak Latin 2" },
114 { 855, L
"OEM Cyrillic" },
115 { 856, L
"Hebrew PC" },
116 { 857, L
"OEM Turkish" },
117 { 860, L
"OEM Portuguese" },
118 { 861, L
"OEM Icelandic" },
119 { 862, L
"OEM Hebrew" },
120 { 863, L
"OEM Canadian French" },
121 { 864, L
"OEM Arabic" },
122 { 865, L
"OEM Nordic" },
123 { 866, L
"OEM Russian" },
124 { 869, L
"OEM Greek" },
125 { 874, L
"ANSI/OEM Thai" },
126 { 875, L
"IBM EBCDIC Greek" },
127 { 878, L
"Russian KOI8" },
128 { 932, L
"ANSI/OEM Japanese Shift-JIS" },
129 { 936, L
"ANSI/OEM Simplified Chinese GBK" },
130 { 949, L
"ANSI/OEM Korean Unified Hangul" },
131 { 950, L
"ANSI/OEM Traditional Chinese Big5" },
132 { 1006, L
"IBM Arabic" },
133 { 1026, L
"IBM EBCDIC Latin 5 Turkish" },
134 { 1250, L
"ANSI Eastern Europe" },
135 { 1251, L
"ANSI Cyrillic" },
136 { 1252, L
"ANSI Latin 1" },
137 { 1253, L
"ANSI Greek" },
138 { 1254, L
"ANSI Turkish" },
139 { 1255, L
"ANSI Hebrew" },
140 { 1256, L
"ANSI Arabic" },
141 { 1257, L
"ANSI Baltic" },
142 { 1258, L
"ANSI/OEM Viet Nam" },
143 { 1361, L
"Korean Johab" },
144 { 10000, L
"Mac Roman" },
145 { 10001, L
"Mac Japanese" },
146 { 10002, L
"Mac Traditional Chinese" },
147 { 10003, L
"Mac Korean" },
148 { 10004, L
"Mac Arabic" },
149 { 10005, L
"Mac Hebrew" },
150 { 10006, L
"Mac Greek" },
151 { 10007, L
"Mac Cyrillic" },
152 { 10008, L
"Mac Simplified Chinese" },
153 { 10010, L
"Mac Romanian" },
154 { 10017, L
"Mac Ukrainian" },
155 { 10021, L
"Mac Thai" },
156 { 10029, L
"Mac Latin 2" },
157 { 10079, L
"Mac Icelandic" },
158 { 10081, L
"Mac Turkish" },
159 { 10082, L
"Mac Croatian" },
160 { 20127, L
"US-ASCII (7bit)" },
161 { 20866, L
"Russian KOI8" },
162 { 20932, L
"EUC-JP" },
163 { 20949, L
"Korean Wansung" },
164 { 21866, L
"Ukrainian KOI8" },
165 { 28591, L
"ISO 8859-1 Latin 1" },
166 { 28592, L
"ISO 8859-2 Latin 2 (East European)" },
167 { 28593, L
"ISO 8859-3 Latin 3 (South European)" },
168 { 28594, L
"ISO 8859-4 Latin 4 (Baltic old)" },
169 { 28595, L
"ISO 8859-5 Cyrillic" },
170 { 28596, L
"ISO 8859-6 Arabic" },
171 { 28597, L
"ISO 8859-7 Greek" },
172 { 28598, L
"ISO 8859-8 Hebrew" },
173 { 28599, L
"ISO 8859-9 Latin 5 (Turkish)" },
174 { 28600, L
"ISO 8859-10 Latin 6 (Nordic)" },
175 { 28601, L
"ISO 8859-11 Latin (Thai)" },
176 { 28603, L
"ISO 8859-13 Latin 7 (Baltic)" },
177 { 28604, L
"ISO 8859-14 Latin 8 (Celtic)" },
178 { 28605, L
"ISO 8859-15 Latin 9 (Euro)" },
179 { 28606, L
"ISO 8859-16 Latin 10 (Balkan)" },
180 { 65000, L
"Unicode (UTF-7)" },
181 { 65001, L
"Unicode (UTF-8)" }
184 /* Unicode expanded ligatures */
185 static const WCHAR ligatures
[][5] =
187 { 0x00c6, 'A','E',0 },
188 { 0x00de, 'T','H',0 },
189 { 0x00df, 's','s',0 },
190 { 0x00e6, 'a','e',0 },
191 { 0x00fe, 't','h',0 },
192 { 0x0132, 'I','J',0 },
193 { 0x0133, 'i','j',0 },
194 { 0x0152, 'O','E',0 },
195 { 0x0153, 'o','e',0 },
196 { 0x01c4, 'D',0x017d,0 },
197 { 0x01c5, 'D',0x017e,0 },
198 { 0x01c6, 'd',0x017e,0 },
199 { 0x01c7, 'L','J',0 },
200 { 0x01c8, 'L','j',0 },
201 { 0x01c9, 'l','j',0 },
202 { 0x01ca, 'N','J',0 },
203 { 0x01cb, 'N','j',0 },
204 { 0x01cc, 'n','j',0 },
205 { 0x01e2, 0x0100,0x0112,0 },
206 { 0x01e3, 0x0101,0x0113,0 },
207 { 0x01f1, 'D','Z',0 },
208 { 0x01f2, 'D','z',0 },
209 { 0x01f3, 'd','z',0 },
210 { 0x01fc, 0x00c1,0x00c9,0 },
211 { 0x01fd, 0x00e1,0x00e9,0 },
212 { 0x05f0, 0x05d5,0x05d5,0 },
213 { 0x05f1, 0x05d5,0x05d9,0 },
214 { 0x05f2, 0x05d9,0x05d9,0 },
215 { 0xfb00, 'f','f',0 },
216 { 0xfb01, 'f','i',0 },
217 { 0xfb02, 'f','l',0 },
218 { 0xfb03, 'f','f','i',0 },
219 { 0xfb04, 'f','f','l',0 },
220 { 0xfb05, 0x017f,'t',0 },
221 { 0xfb06, 's','t',0 },
224 enum locationkind
{ LOCATION_NATION
= 0, LOCATION_REGION
, LOCATION_BOTH
};
233 enum locationkind kind
;
236 static const struct geoinfo geoinfodata
[] =
238 { 2, L
"AG", L
"ATG", 10039880, 28 }, /* Antigua and Barbuda */
239 { 3, L
"AF", L
"AFG", 47614, 4 }, /* Afghanistan */
240 { 4, L
"DZ", L
"DZA", 42487, 12 }, /* Algeria */
241 { 5, L
"AZ", L
"AZE", 47611, 31 }, /* Azerbaijan */
242 { 6, L
"AL", L
"ALB", 47610, 8 }, /* Albania */
243 { 7, L
"AM", L
"ARM", 47611, 51 }, /* Armenia */
244 { 8, L
"AD", L
"AND", 47610, 20 }, /* Andorra */
245 { 9, L
"AO", L
"AGO", 42484, 24 }, /* Angola */
246 { 10, L
"AS", L
"ASM", 26286, 16 }, /* American Samoa */
247 { 11, L
"AR", L
"ARG", 31396, 32 }, /* Argentina */
248 { 12, L
"AU", L
"AUS", 10210825, 36 }, /* Australia */
249 { 14, L
"AT", L
"AUT", 10210824, 40 }, /* Austria */
250 { 17, L
"BH", L
"BHR", 47611, 48 }, /* Bahrain */
251 { 18, L
"BB", L
"BRB", 10039880, 52 }, /* Barbados */
252 { 19, L
"BW", L
"BWA", 10039883, 72 }, /* Botswana */
253 { 20, L
"BM", L
"BMU", 23581, 60 }, /* Bermuda */
254 { 21, L
"BE", L
"BEL", 10210824, 56 }, /* Belgium */
255 { 22, L
"BS", L
"BHS", 10039880, 44 }, /* Bahamas, The */
256 { 23, L
"BD", L
"BGD", 47614, 50 }, /* Bangladesh */
257 { 24, L
"BZ", L
"BLZ", 27082, 84 }, /* Belize */
258 { 25, L
"BA", L
"BIH", 47610, 70 }, /* Bosnia and Herzegovina */
259 { 26, L
"BO", L
"BOL", 31396, 68 }, /* Bolivia */
260 { 27, L
"MM", L
"MMR", 47599, 104 }, /* Myanmar */
261 { 28, L
"BJ", L
"BEN", 42483, 204 }, /* Benin */
262 { 29, L
"BY", L
"BLR", 47609, 112 }, /* Belarus */
263 { 30, L
"SB", L
"SLB", 20900, 90 }, /* Solomon Islands */
264 { 32, L
"BR", L
"BRA", 31396, 76 }, /* Brazil */
265 { 34, L
"BT", L
"BTN", 47614, 64 }, /* Bhutan */
266 { 35, L
"BG", L
"BGR", 47609, 100 }, /* Bulgaria */
267 { 37, L
"BN", L
"BRN", 47599, 96 }, /* Brunei */
268 { 38, L
"BI", L
"BDI", 47603, 108 }, /* Burundi */
269 { 39, L
"CA", L
"CAN", 23581, 124 }, /* Canada */
270 { 40, L
"KH", L
"KHM", 47599, 116 }, /* Cambodia */
271 { 41, L
"TD", L
"TCD", 42484, 148 }, /* Chad */
272 { 42, L
"LK", L
"LKA", 47614, 144 }, /* Sri Lanka */
273 { 43, L
"CG", L
"COG", 42484, 178 }, /* Congo */
274 { 44, L
"CD", L
"COD", 42484, 180 }, /* Congo (DRC) */
275 { 45, L
"CN", L
"CHN", 47600, 156 }, /* China */
276 { 46, L
"CL", L
"CHL", 31396, 152 }, /* Chile */
277 { 49, L
"CM", L
"CMR", 42484, 120 }, /* Cameroon */
278 { 50, L
"KM", L
"COM", 47603, 174 }, /* Comoros */
279 { 51, L
"CO", L
"COL", 31396, 170 }, /* Colombia */
280 { 54, L
"CR", L
"CRI", 27082, 188 }, /* Costa Rica */
281 { 55, L
"CF", L
"CAF", 42484, 140 }, /* Central African Republic */
282 { 56, L
"CU", L
"CUB", 10039880, 192 }, /* Cuba */
283 { 57, L
"CV", L
"CPV", 42483, 132 }, /* Cape Verde */
284 { 59, L
"CY", L
"CYP", 47611, 196 }, /* Cyprus */
285 { 61, L
"DK", L
"DNK", 10039882, 208 }, /* Denmark */
286 { 62, L
"DJ", L
"DJI", 47603, 262 }, /* Djibouti */
287 { 63, L
"DM", L
"DMA", 10039880, 212 }, /* Dominica */
288 { 65, L
"DO", L
"DOM", 10039880, 214 }, /* Dominican Republic */
289 { 66, L
"EC", L
"ECU", 31396, 218 }, /* Ecuador */
290 { 67, L
"EG", L
"EGY", 42487, 818 }, /* Egypt */
291 { 68, L
"IE", L
"IRL", 10039882, 372 }, /* Ireland */
292 { 69, L
"GQ", L
"GNQ", 42484, 226 }, /* Equatorial Guinea */
293 { 70, L
"EE", L
"EST", 10039882, 233 }, /* Estonia */
294 { 71, L
"ER", L
"ERI", 47603, 232 }, /* Eritrea */
295 { 72, L
"SV", L
"SLV", 27082, 222 }, /* El Salvador */
296 { 73, L
"ET", L
"ETH", 47603, 231 }, /* Ethiopia */
297 { 75, L
"CZ", L
"CZE", 47609, 203 }, /* Czech Republic */
298 { 77, L
"FI", L
"FIN", 10039882, 246 }, /* Finland */
299 { 78, L
"FJ", L
"FJI", 20900, 242 }, /* Fiji Islands */
300 { 80, L
"FM", L
"FSM", 21206, 583 }, /* Micronesia */
301 { 81, L
"FO", L
"FRO", 10039882, 234 }, /* Faroe Islands */
302 { 84, L
"FR", L
"FRA", 10210824, 250 }, /* France */
303 { 86, L
"GM", L
"GMB", 42483, 270 }, /* Gambia, The */
304 { 87, L
"GA", L
"GAB", 42484, 266 }, /* Gabon */
305 { 88, L
"GE", L
"GEO", 47611, 268 }, /* Georgia */
306 { 89, L
"GH", L
"GHA", 42483, 288 }, /* Ghana */
307 { 90, L
"GI", L
"GIB", 47610, 292 }, /* Gibraltar */
308 { 91, L
"GD", L
"GRD", 10039880, 308 }, /* Grenada */
309 { 93, L
"GL", L
"GRL", 23581, 304 }, /* Greenland */
310 { 94, L
"DE", L
"DEU", 10210824, 276 }, /* Germany */
311 { 98, L
"GR", L
"GRC", 47610, 300 }, /* Greece */
312 { 99, L
"GT", L
"GTM", 27082, 320 }, /* Guatemala */
313 { 100, L
"GN", L
"GIN", 42483, 324 }, /* Guinea */
314 { 101, L
"GY", L
"GUY", 31396, 328 }, /* Guyana */
315 { 103, L
"HT", L
"HTI", 10039880, 332 }, /* Haiti */
316 { 104, L
"HK", L
"HKG", 47600, 344 }, /* Hong Kong S.A.R. */
317 { 106, L
"HN", L
"HND", 27082, 340 }, /* Honduras */
318 { 108, L
"HR", L
"HRV", 47610, 191 }, /* Croatia */
319 { 109, L
"HU", L
"HUN", 47609, 348 }, /* Hungary */
320 { 110, L
"IS", L
"ISL", 10039882, 352 }, /* Iceland */
321 { 111, L
"ID", L
"IDN", 47599, 360 }, /* Indonesia */
322 { 113, L
"IN", L
"IND", 47614, 356 }, /* India */
323 { 114, L
"IO", L
"IOT", 39070, 86 }, /* British Indian Ocean Territory */
324 { 116, L
"IR", L
"IRN", 47614, 364 }, /* Iran */
325 { 117, L
"IL", L
"ISR", 47611, 376 }, /* Israel */
326 { 118, L
"IT", L
"ITA", 47610, 380 }, /* Italy */
327 { 119, L
"CI", L
"CIV", 42483, 384 }, /* Côte d'Ivoire */
328 { 121, L
"IQ", L
"IRQ", 47611, 368 }, /* Iraq */
329 { 122, L
"JP", L
"JPN", 47600, 392 }, /* Japan */
330 { 124, L
"JM", L
"JAM", 10039880, 388 }, /* Jamaica */
331 { 125, L
"SJ", L
"SJM", 10039882, 744 }, /* Jan Mayen */
332 { 126, L
"JO", L
"JOR", 47611, 400 }, /* Jordan */
333 { 127, L
"XX", L
"XX", 161832256 }, /* Johnston Atoll */
334 { 129, L
"KE", L
"KEN", 47603, 404 }, /* Kenya */
335 { 130, L
"KG", L
"KGZ", 47590, 417 }, /* Kyrgyzstan */
336 { 131, L
"KP", L
"PRK", 47600, 408 }, /* North Korea */
337 { 133, L
"KI", L
"KIR", 21206, 296 }, /* Kiribati */
338 { 134, L
"KR", L
"KOR", 47600, 410 }, /* Korea */
339 { 136, L
"KW", L
"KWT", 47611, 414 }, /* Kuwait */
340 { 137, L
"KZ", L
"KAZ", 47590, 398 }, /* Kazakhstan */
341 { 138, L
"LA", L
"LAO", 47599, 418 }, /* Laos */
342 { 139, L
"LB", L
"LBN", 47611, 422 }, /* Lebanon */
343 { 140, L
"LV", L
"LVA", 10039882, 428 }, /* Latvia */
344 { 141, L
"LT", L
"LTU", 10039882, 440 }, /* Lithuania */
345 { 142, L
"LR", L
"LBR", 42483, 430 }, /* Liberia */
346 { 143, L
"SK", L
"SVK", 47609, 703 }, /* Slovakia */
347 { 145, L
"LI", L
"LIE", 10210824, 438 }, /* Liechtenstein */
348 { 146, L
"LS", L
"LSO", 10039883, 426 }, /* Lesotho */
349 { 147, L
"LU", L
"LUX", 10210824, 442 }, /* Luxembourg */
350 { 148, L
"LY", L
"LBY", 42487, 434 }, /* Libya */
351 { 149, L
"MG", L
"MDG", 47603, 450 }, /* Madagascar */
352 { 151, L
"MO", L
"MAC", 47600, 446 }, /* Macao S.A.R. */
353 { 152, L
"MD", L
"MDA", 47609, 498 }, /* Moldova */
354 { 154, L
"MN", L
"MNG", 47600, 496 }, /* Mongolia */
355 { 156, L
"MW", L
"MWI", 47603, 454 }, /* Malawi */
356 { 157, L
"ML", L
"MLI", 42483, 466 }, /* Mali */
357 { 158, L
"MC", L
"MCO", 10210824, 492 }, /* Monaco */
358 { 159, L
"MA", L
"MAR", 42487, 504 }, /* Morocco */
359 { 160, L
"MU", L
"MUS", 47603, 480 }, /* Mauritius */
360 { 162, L
"MR", L
"MRT", 42483, 478 }, /* Mauritania */
361 { 163, L
"MT", L
"MLT", 47610, 470 }, /* Malta */
362 { 164, L
"OM", L
"OMN", 47611, 512 }, /* Oman */
363 { 165, L
"MV", L
"MDV", 47614, 462 }, /* Maldives */
364 { 166, L
"MX", L
"MEX", 27082, 484 }, /* Mexico */
365 { 167, L
"MY", L
"MYS", 47599, 458 }, /* Malaysia */
366 { 168, L
"MZ", L
"MOZ", 47603, 508 }, /* Mozambique */
367 { 173, L
"NE", L
"NER", 42483, 562 }, /* Niger */
368 { 174, L
"VU", L
"VUT", 20900, 548 }, /* Vanuatu */
369 { 175, L
"NG", L
"NGA", 42483, 566 }, /* Nigeria */
370 { 176, L
"NL", L
"NLD", 10210824, 528 }, /* Netherlands */
371 { 177, L
"NO", L
"NOR", 10039882, 578 }, /* Norway */
372 { 178, L
"NP", L
"NPL", 47614, 524 }, /* Nepal */
373 { 180, L
"NR", L
"NRU", 21206, 520 }, /* Nauru */
374 { 181, L
"SR", L
"SUR", 31396, 740 }, /* Suriname */
375 { 182, L
"NI", L
"NIC", 27082, 558 }, /* Nicaragua */
376 { 183, L
"NZ", L
"NZL", 10210825, 554 }, /* New Zealand */
377 { 184, L
"PS", L
"PSE", 47611, 275 }, /* Palestinian Authority */
378 { 185, L
"PY", L
"PRY", 31396, 600 }, /* Paraguay */
379 { 187, L
"PE", L
"PER", 31396, 604 }, /* Peru */
380 { 190, L
"PK", L
"PAK", 47614, 586 }, /* Pakistan */
381 { 191, L
"PL", L
"POL", 47609, 616 }, /* Poland */
382 { 192, L
"PA", L
"PAN", 27082, 591 }, /* Panama */
383 { 193, L
"PT", L
"PRT", 47610, 620 }, /* Portugal */
384 { 194, L
"PG", L
"PNG", 20900, 598 }, /* Papua New Guinea */
385 { 195, L
"PW", L
"PLW", 21206, 585 }, /* Palau */
386 { 196, L
"GW", L
"GNB", 42483, 624 }, /* Guinea-Bissau */
387 { 197, L
"QA", L
"QAT", 47611, 634 }, /* Qatar */
388 { 198, L
"RE", L
"REU", 47603, 638 }, /* Reunion */
389 { 199, L
"MH", L
"MHL", 21206, 584 }, /* Marshall Islands */
390 { 200, L
"RO", L
"ROU", 47609, 642 }, /* Romania */
391 { 201, L
"PH", L
"PHL", 47599, 608 }, /* Philippines */
392 { 202, L
"PR", L
"PRI", 10039880, 630 }, /* Puerto Rico */
393 { 203, L
"RU", L
"RUS", 47609, 643 }, /* Russia */
394 { 204, L
"RW", L
"RWA", 47603, 646 }, /* Rwanda */
395 { 205, L
"SA", L
"SAU", 47611, 682 }, /* Saudi Arabia */
396 { 206, L
"PM", L
"SPM", 23581, 666 }, /* St. Pierre and Miquelon */
397 { 207, L
"KN", L
"KNA", 10039880, 659 }, /* St. Kitts and Nevis */
398 { 208, L
"SC", L
"SYC", 47603, 690 }, /* Seychelles */
399 { 209, L
"ZA", L
"ZAF", 10039883, 710 }, /* South Africa */
400 { 210, L
"SN", L
"SEN", 42483, 686 }, /* Senegal */
401 { 212, L
"SI", L
"SVN", 47610, 705 }, /* Slovenia */
402 { 213, L
"SL", L
"SLE", 42483, 694 }, /* Sierra Leone */
403 { 214, L
"SM", L
"SMR", 47610, 674 }, /* San Marino */
404 { 215, L
"SG", L
"SGP", 47599, 702 }, /* Singapore */
405 { 216, L
"SO", L
"SOM", 47603, 706 }, /* Somalia */
406 { 217, L
"ES", L
"ESP", 47610, 724 }, /* Spain */
407 { 218, L
"LC", L
"LCA", 10039880, 662 }, /* St. Lucia */
408 { 219, L
"SD", L
"SDN", 42487, 736 }, /* Sudan */
409 { 220, L
"SJ", L
"SJM", 10039882, 744 }, /* Svalbard */
410 { 221, L
"SE", L
"SWE", 10039882, 752 }, /* Sweden */
411 { 222, L
"SY", L
"SYR", 47611, 760 }, /* Syria */
412 { 223, L
"CH", L
"CHE", 10210824, 756 }, /* Switzerland */
413 { 224, L
"AE", L
"ARE", 47611, 784 }, /* United Arab Emirates */
414 { 225, L
"TT", L
"TTO", 10039880, 780 }, /* Trinidad and Tobago */
415 { 227, L
"TH", L
"THA", 47599, 764 }, /* Thailand */
416 { 228, L
"TJ", L
"TJK", 47590, 762 }, /* Tajikistan */
417 { 231, L
"TO", L
"TON", 26286, 776 }, /* Tonga */
418 { 232, L
"TG", L
"TGO", 42483, 768 }, /* Togo */
419 { 233, L
"ST", L
"STP", 42484, 678 }, /* São Tomé and Príncipe */
420 { 234, L
"TN", L
"TUN", 42487, 788 }, /* Tunisia */
421 { 235, L
"TR", L
"TUR", 47611, 792 }, /* Turkey */
422 { 236, L
"TV", L
"TUV", 26286, 798 }, /* Tuvalu */
423 { 237, L
"TW", L
"TWN", 47600, 158 }, /* Taiwan */
424 { 238, L
"TM", L
"TKM", 47590, 795 }, /* Turkmenistan */
425 { 239, L
"TZ", L
"TZA", 47603, 834 }, /* Tanzania */
426 { 240, L
"UG", L
"UGA", 47603, 800 }, /* Uganda */
427 { 241, L
"UA", L
"UKR", 47609, 804 }, /* Ukraine */
428 { 242, L
"GB", L
"GBR", 10039882, 826 }, /* United Kingdom */
429 { 244, L
"US", L
"USA", 23581, 840 }, /* United States */
430 { 245, L
"BF", L
"BFA", 42483, 854 }, /* Burkina Faso */
431 { 246, L
"UY", L
"URY", 31396, 858 }, /* Uruguay */
432 { 247, L
"UZ", L
"UZB", 47590, 860 }, /* Uzbekistan */
433 { 248, L
"VC", L
"VCT", 10039880, 670 }, /* St. Vincent and the Grenadines */
434 { 249, L
"VE", L
"VEN", 31396, 862 }, /* Bolivarian Republic of Venezuela */
435 { 251, L
"VN", L
"VNM", 47599, 704 }, /* Vietnam */
436 { 252, L
"VI", L
"VIR", 10039880, 850 }, /* Virgin Islands */
437 { 253, L
"VA", L
"VAT", 47610, 336 }, /* Vatican City */
438 { 254, L
"NA", L
"NAM", 10039883, 516 }, /* Namibia */
439 { 257, L
"EH", L
"ESH", 42487, 732 }, /* Western Sahara (disputed) */
440 { 258, L
"XX", L
"XX", 161832256 }, /* Wake Island */
441 { 259, L
"WS", L
"WSM", 26286, 882 }, /* Samoa */
442 { 260, L
"SZ", L
"SWZ", 10039883, 748 }, /* Swaziland */
443 { 261, L
"YE", L
"YEM", 47611, 887 }, /* Yemen */
444 { 263, L
"ZM", L
"ZMB", 47603, 894 }, /* Zambia */
445 { 264, L
"ZW", L
"ZWE", 47603, 716 }, /* Zimbabwe */
446 { 269, L
"CS", L
"SCG", 47610, 891 }, /* Serbia and Montenegro (Former) */
447 { 270, L
"ME", L
"MNE", 47610, 499 }, /* Montenegro */
448 { 271, L
"RS", L
"SRB", 47610, 688 }, /* Serbia */
449 { 273, L
"CW", L
"CUW", 10039880, 531 }, /* Curaçao */
450 { 276, L
"SS", L
"SSD", 42487, 728 }, /* South Sudan */
451 { 300, L
"AI", L
"AIA", 10039880, 660 }, /* Anguilla */
452 { 301, L
"AQ", L
"ATA", 39070, 10 }, /* Antarctica */
453 { 302, L
"AW", L
"ABW", 10039880, 533 }, /* Aruba */
454 { 303, L
"XX", L
"XX", 343 }, /* Ascension Island */
455 { 304, L
"XX", L
"XX", 10210825 }, /* Ashmore and Cartier Islands */
456 { 305, L
"XX", L
"XX", 161832256 }, /* Baker Island */
457 { 306, L
"BV", L
"BVT", 39070, 74 }, /* Bouvet Island */
458 { 307, L
"KY", L
"CYM", 10039880, 136 }, /* Cayman Islands */
459 { 308, L
"XX", L
"XX", 10210824, 830, LOCATION_BOTH
}, /* Channel Islands */
460 { 309, L
"CX", L
"CXR", 12, 162 }, /* Christmas Island */
461 { 310, L
"XX", L
"XX", 27114 }, /* Clipperton Island */
462 { 311, L
"CC", L
"CCK", 10210825, 166 }, /* Cocos (Keeling) Islands */
463 { 312, L
"CK", L
"COK", 26286, 184 }, /* Cook Islands */
464 { 313, L
"XX", L
"XX", 10210825 }, /* Coral Sea Islands */
465 { 314, L
"XX", L
"XX", 114 }, /* Diego Garcia */
466 { 315, L
"FK", L
"FLK", 31396, 238 }, /* Falkland Islands (Islas Malvinas) */
467 { 317, L
"GF", L
"GUF", 31396, 254 }, /* French Guiana */
468 { 318, L
"PF", L
"PYF", 26286, 258 }, /* French Polynesia */
469 { 319, L
"TF", L
"ATF", 39070, 260 }, /* French Southern and Antarctic Lands */
470 { 321, L
"GP", L
"GLP", 10039880, 312 }, /* Guadeloupe */
471 { 322, L
"GU", L
"GUM", 21206, 316 }, /* Guam */
472 { 323, L
"XX", L
"XX", 39070 }, /* Guantanamo Bay */
473 { 324, L
"GG", L
"GGY", 308, 831 }, /* Guernsey */
474 { 325, L
"HM", L
"HMD", 39070, 334 }, /* Heard Island and McDonald Islands */
475 { 326, L
"XX", L
"XX", 161832256 }, /* Howland Island */
476 { 327, L
"XX", L
"XX", 161832256 }, /* Jarvis Island */
477 { 328, L
"JE", L
"JEY", 308, 832 }, /* Jersey */
478 { 329, L
"XX", L
"XX", 161832256 }, /* Kingman Reef */
479 { 330, L
"MQ", L
"MTQ", 10039880, 474 }, /* Martinique */
480 { 331, L
"YT", L
"MYT", 47603, 175 }, /* Mayotte */
481 { 332, L
"MS", L
"MSR", 10039880, 500 }, /* Montserrat */
482 { 333, L
"AN", L
"ANT", 10039880, 530, LOCATION_BOTH
}, /* Netherlands Antilles (Former) */
483 { 334, L
"NC", L
"NCL", 20900, 540 }, /* New Caledonia */
484 { 335, L
"NU", L
"NIU", 26286, 570 }, /* Niue */
485 { 336, L
"NF", L
"NFK", 10210825, 574 }, /* Norfolk Island */
486 { 337, L
"MP", L
"MNP", 21206, 580 }, /* Northern Mariana Islands */
487 { 338, L
"XX", L
"XX", 161832256 }, /* Palmyra Atoll */
488 { 339, L
"PN", L
"PCN", 26286, 612 }, /* Pitcairn Islands */
489 { 340, L
"XX", L
"XX", 337 }, /* Rota Island */
490 { 341, L
"XX", L
"XX", 337 }, /* Saipan */
491 { 342, L
"GS", L
"SGS", 39070, 239 }, /* South Georgia and the South Sandwich Islands */
492 { 343, L
"SH", L
"SHN", 42483, 654 }, /* St. Helena */
493 { 346, L
"XX", L
"XX", 337 }, /* Tinian Island */
494 { 347, L
"TK", L
"TKL", 26286, 772 }, /* Tokelau */
495 { 348, L
"XX", L
"XX", 343 }, /* Tristan da Cunha */
496 { 349, L
"TC", L
"TCA", 10039880, 796 }, /* Turks and Caicos Islands */
497 { 351, L
"VG", L
"VGB", 10039880, 92 }, /* Virgin Islands, British */
498 { 352, L
"WF", L
"WLF", 26286, 876 }, /* Wallis and Futuna */
499 { 742, L
"XX", L
"XX", 39070, 2, LOCATION_REGION
}, /* Africa */
500 { 2129, L
"XX", L
"XX", 39070, 142, LOCATION_REGION
}, /* Asia */
501 { 10541, L
"XX", L
"XX", 39070, 150, LOCATION_REGION
}, /* Europe */
502 { 15126, L
"IM", L
"IMN", 10039882, 833 }, /* Man, Isle of */
503 { 19618, L
"MK", L
"MKD", 47610, 807 }, /* Macedonia, Former Yugoslav Republic of */
504 { 20900, L
"XX", L
"XX", 27114, 54, LOCATION_REGION
}, /* Melanesia */
505 { 21206, L
"XX", L
"XX", 27114, 57, LOCATION_REGION
}, /* Micronesia */
506 { 21242, L
"XX", L
"XX", 161832256 }, /* Midway Islands */
507 { 23581, L
"XX", L
"XX", 10026358, 21, LOCATION_REGION
}, /* Northern America */
508 { 26286, L
"XX", L
"XX", 27114, 61, LOCATION_REGION
}, /* Polynesia */
509 { 27082, L
"XX", L
"XX", 161832257, 13, LOCATION_REGION
}, /* Central America */
510 { 27114, L
"XX", L
"XX", 39070, 9, LOCATION_REGION
}, /* Oceania */
511 { 30967, L
"SX", L
"SXM", 10039880, 534 }, /* Sint Maarten (Dutch part) */
512 { 31396, L
"XX", L
"XX", 161832257, 5, LOCATION_REGION
}, /* South America */
513 { 31706, L
"MF", L
"MAF", 10039880, 663 }, /* Saint Martin (French part) */
514 { 39070, L
"XX", L
"XX", 39070, 1, LOCATION_REGION
}, /* World */
515 { 42483, L
"XX", L
"XX", 742, 11, LOCATION_REGION
}, /* Western Africa */
516 { 42484, L
"XX", L
"XX", 742, 17, LOCATION_REGION
}, /* Middle Africa */
517 { 42487, L
"XX", L
"XX", 742, 15, LOCATION_REGION
}, /* Northern Africa */
518 { 47590, L
"XX", L
"XX", 2129, 143, LOCATION_REGION
}, /* Central Asia */
519 { 47599, L
"XX", L
"XX", 2129, 35, LOCATION_REGION
}, /* South-Eastern Asia */
520 { 47600, L
"XX", L
"XX", 2129, 30, LOCATION_REGION
}, /* Eastern Asia */
521 { 47603, L
"XX", L
"XX", 742, 14, LOCATION_REGION
}, /* Eastern Africa */
522 { 47609, L
"XX", L
"XX", 10541, 151, LOCATION_REGION
}, /* Eastern Europe */
523 { 47610, L
"XX", L
"XX", 10541, 39, LOCATION_REGION
}, /* Southern Europe */
524 { 47611, L
"XX", L
"XX", 2129, 145, LOCATION_REGION
}, /* Middle East */
525 { 47614, L
"XX", L
"XX", 2129, 34, LOCATION_REGION
}, /* Southern Asia */
526 { 7299303, L
"TL", L
"TLS", 47599, 626 }, /* Democratic Republic of Timor-Leste */
527 { 9914689, L
"XK", L
"XKS", 47610, 906 }, /* Kosovo */
528 { 10026358, L
"XX", L
"XX", 39070, 19, LOCATION_REGION
}, /* Americas */
529 { 10028789, L
"AX", L
"ALA", 10039882, 248 }, /* Åland Islands */
530 { 10039880, L
"XX", L
"XX", 161832257, 29, LOCATION_REGION
}, /* Caribbean */
531 { 10039882, L
"XX", L
"XX", 10541, 154, LOCATION_REGION
}, /* Northern Europe */
532 { 10039883, L
"XX", L
"XX", 742, 18, LOCATION_REGION
}, /* Southern Africa */
533 { 10210824, L
"XX", L
"XX", 10541, 155, LOCATION_REGION
}, /* Western Europe */
534 { 10210825, L
"XX", L
"XX", 27114, 53, LOCATION_REGION
}, /* Australia and New Zealand */
535 { 161832015, L
"BL", L
"BLM", 10039880, 652 }, /* Saint Barthélemy */
536 { 161832256, L
"UM", L
"UMI", 27114, 581 }, /* U.S. Minor Outlying Islands */
537 { 161832257, L
"XX", L
"XX", 10026358, 419, LOCATION_REGION
}, /* Latin America and the Caribbean */
538 { 161832258, L
"BG", L
"BES", 10039880, 535 }, /* Bonaire, Sint Eustatius and Saba */
541 /* NLS normalization file */
544 WCHAR name
[13]; /* 00 file name */
545 USHORT checksum
[3]; /* 1a checksum? */
546 USHORT version
[4]; /* 20 Unicode version */
547 USHORT form
; /* 28 normalization form */
548 USHORT len_factor
; /* 2a factor for length estimates */
549 USHORT unknown1
; /* 2c */
550 USHORT decomp_size
; /* 2e decomposition hash size */
551 USHORT comp_size
; /* 30 composition hash size */
552 USHORT unknown2
; /* 32 */
553 USHORT classes
; /* 34 combining classes table offset */
554 USHORT props_level1
; /* 36 char properties table level 1 offset */
555 USHORT props_level2
; /* 38 char properties table level 2 offset */
556 USHORT decomp_hash
; /* 3a decomposition hash table offset */
557 USHORT decomp_map
; /* 3c decomposition character map table offset */
558 USHORT decomp_seq
; /* 3e decomposition character sequences offset */
559 USHORT comp_hash
; /* 40 composition hash table offset */
560 USHORT comp_seq
; /* 42 composition character sequences offset */
561 /* BYTE[] combining class values */
562 /* BYTE[0x2200] char properties index level 1 */
563 /* BYTE[] char properties index level 2 */
564 /* WORD[] decomposition hash table */
565 /* WORD[] decomposition character map */
566 /* WORD[] decomposition character sequences */
567 /* WORD[] composition hash table */
568 /* WORD[] composition character sequences */
571 static NLSTABLEINFO nls_info
;
572 static UINT unix_cp
= CP_UTF8
;
573 static UINT mac_cp
= 10000;
574 static LCID system_lcid
;
575 static LCID user_lcid
;
576 static HKEY intl_key
;
579 static const NLS_LOCALE_LCID_INDEX
*lcids_index
;
580 static const NLS_LOCALE_LCNAME_INDEX
*lcnames_index
;
581 static const NLS_LOCALE_HEADER
*locale_table
;
582 static const WCHAR
*locale_strings
;
583 static const NLS_LOCALE_DATA
*system_locale
;
584 static const NLS_LOCALE_DATA
*user_locale
;
586 static CPTABLEINFO codepages
[128];
587 static unsigned int nb_codepages
;
589 static struct norm_table
*norm_info
;
593 GUID id
; /* sort GUID */
594 DWORD flags
; /* flags */
595 DWORD compr
; /* offset to compression table */
596 DWORD except
; /* exception table offset in sortkey table */
597 DWORD ling_except
; /* exception table offset for linguistic casing */
598 DWORD casemap
; /* linguistic casemap table offset */
601 #define FLAG_HAS_3_BYTE_WEIGHTS 0x01
602 #define FLAG_REVERSEDIACRITICS 0x10
603 #define FLAG_DOUBLECOMPRESSION 0x20
604 #define FLAG_INVERSECASING 0x40
606 static const struct sortguid
*current_locale_sort
;
608 static const GUID default_sort_guid
= { 0x00000001, 0x57ee, 0x1e5c, { 0x00, 0xb4, 0xd0, 0x00, 0x0b, 0xb1, 0xe1, 0x1e }};
612 DWORD
*keys
; /* sortkey table, indexed by char */
613 USHORT
*casemap
; /* casemap table, in l_intl.nls format */
614 WORD
*ctypes
; /* CT_CTYPE1,2,3 values */
615 BYTE
*ctype_idx
; /* index to map char to ctypes array entry */
616 DWORD version
; /* NLS version */
617 DWORD guid_count
; /* number of sort GUIDs */
618 struct sortguid
*guids
; /* table of sort GUIDs */
621 static CRITICAL_SECTION locale_section
;
622 static CRITICAL_SECTION_DEBUG critsect_debug
=
624 0, 0, &locale_section
,
625 { &critsect_debug
.ProcessLocksList
, &critsect_debug
.ProcessLocksList
},
626 0, 0, { (DWORD_PTR
)(__FILE__
": locale_section") }
628 static CRITICAL_SECTION locale_section
= { &critsect_debug
, -1, 0, 0, 0, 0 };
631 static void load_locale_nls(void)
647 RtlGetLocaleFileMappingAddress( (void **)&header
, &lcid
, &dummy
);
648 locale_table
= (const NLS_LOCALE_HEADER
*)((char *)header
+ header
->locales
);
649 lcids_index
= (const NLS_LOCALE_LCID_INDEX
*)((char *)locale_table
+ locale_table
->lcids_offset
);
650 lcnames_index
= (const NLS_LOCALE_LCNAME_INDEX
*)((char *)locale_table
+ locale_table
->lcnames_offset
);
651 locale_strings
= (const WCHAR
*)((char *)locale_table
+ locale_table
->strings_offset
);
655 static void init_sortkeys( DWORD
*ptr
)
660 sort
.keys
= (DWORD
*)((char *)ptr
+ ptr
[0]);
661 sort
.casemap
= (USHORT
*)((char *)ptr
+ ptr
[1]);
663 ctype
= (WORD
*)((char *)ptr
+ ptr
[2]);
664 sort
.ctypes
= ctype
+ 2;
665 sort
.ctype_idx
= (BYTE
*)ctype
+ ctype
[1] + 2;
667 table
= (DWORD
*)((char *)ptr
+ ptr
[3]);
668 sort
.version
= table
[0];
669 sort
.guid_count
= table
[1];
670 sort
.guids
= (struct sortguid
*)(table
+ 2);
674 static const struct sortguid
*find_sortguid( const GUID
*guid
)
676 int pos
, ret
, min
= 0, max
= sort
.guid_count
- 1;
680 pos
= (min
+ max
) / 2;
681 ret
= memcmp( guid
, &sort
.guids
[pos
].id
, sizeof(*guid
) );
682 if (!ret
) return &sort
.guids
[pos
];
683 if (ret
> 0) min
= pos
+ 1;
686 ERR( "no sort found for %s\n", debugstr_guid( guid
));
691 static const struct sortguid
*get_language_sort( const WCHAR
*locale
)
693 WCHAR
*p
, *end
, buffer
[LOCALE_NAME_MAX_LENGTH
], guidstr
[39];
694 const struct sortguid
*ret
;
700 if (locale
== LOCALE_NAME_USER_DEFAULT
)
702 if (current_locale_sort
) return current_locale_sort
;
703 GetUserDefaultLocaleName( buffer
, ARRAY_SIZE( buffer
));
705 else lstrcpynW( buffer
, locale
, LOCALE_NAME_MAX_LENGTH
);
707 if (buffer
[0] && !RegOpenKeyExW( nls_key
, L
"Sorting\\Ids", 0, KEY_READ
, &key
))
711 size
= sizeof(guidstr
);
712 if (!RegQueryValueExW( key
, buffer
, NULL
, &type
, (BYTE
*)guidstr
, &size
) && type
== REG_SZ
)
714 RtlInitUnicodeString( &str
, guidstr
);
715 if (!RtlGUIDFromString( &str
, &guid
))
717 ret
= find_sortguid( &guid
);
722 for (p
= end
= buffer
; *p
; p
++) if (*p
== '-' || *p
== '_') end
= p
;
723 if (end
== buffer
) break;
727 ret
= find_sortguid( &default_sort_guid
);
734 static const NLS_LOCALE_DATA
*get_locale_data( UINT idx
)
736 ULONG offset
= locale_table
->locales_offset
+ idx
* locale_table
->locale_size
;
737 return (const NLS_LOCALE_DATA
*)((const char *)locale_table
+ offset
);
741 static int compare_locale_names( const WCHAR
*n1
, const WCHAR
*n2
)
747 if (ch1
>= 'a' && ch1
<= 'z') ch1
-= 'a' - 'A';
748 else if (ch1
== '_') ch1
= '-';
749 if (ch2
>= 'a' && ch2
<= 'z') ch2
-= 'a' - 'A';
750 else if (ch2
== '_') ch2
= '-';
751 if (!ch1
|| ch1
!= ch2
) return ch1
- ch2
;
756 static const NLS_LOCALE_LCNAME_INDEX
*find_lcname_entry( const WCHAR
*name
)
758 int min
= 0, max
= locale_table
->nb_lcnames
- 1;
762 int res
, pos
= (min
+ max
) / 2;
763 const WCHAR
*str
= locale_strings
+ lcnames_index
[pos
].name
;
764 res
= compare_locale_names( name
, str
+ 1 );
765 if (res
< 0) max
= pos
- 1;
766 else if (res
> 0) min
= pos
+ 1;
767 else return &lcnames_index
[pos
];
773 static const NLS_LOCALE_LCID_INDEX
*find_lcid_entry( LCID lcid
)
775 int min
= 0, max
= locale_table
->nb_lcids
- 1;
779 int pos
= (min
+ max
) / 2;
780 if (lcid
< lcids_index
[pos
].id
) max
= pos
- 1;
781 else if (lcid
> lcids_index
[pos
].id
) min
= pos
+ 1;
782 else return &lcids_index
[pos
];
788 static const NLS_LOCALE_DATA
*get_locale_by_name( const WCHAR
*name
, LCID
*lcid
)
790 const NLS_LOCALE_LCNAME_INDEX
*entry
;
792 if (name
== LOCALE_NAME_USER_DEFAULT
)
797 if (!(entry
= find_lcname_entry( name
))) return NULL
;
799 return get_locale_data( entry
->idx
);
803 static const NLS_LOCALE_DATA
*get_locale_by_id( LCID
*lcid
, DWORD flags
)
805 const NLS_LOCALE_LCID_INDEX
*entry
;
806 const NLS_LOCALE_DATA
*locale
;
810 case LOCALE_SYSTEM_DEFAULT
:
812 return system_locale
;
814 case LOCALE_USER_DEFAULT
:
815 case LOCALE_CUSTOM_DEFAULT
:
819 if (!(entry
= find_lcid_entry( *lcid
))) return NULL
;
820 locale
= get_locale_data( entry
->idx
);
821 if (!(flags
& LOCALE_ALLOW_NEUTRAL_NAMES
) && !locale
->inotneutral
)
822 locale
= get_locale_by_name( locale_strings
+ locale
->ssortlocale
+ 1, lcid
);
828 static int locale_return_data( const WCHAR
*data
, int datalen
, LCTYPE type
, WCHAR
*buffer
, int len
)
830 if (type
& LOCALE_RETURN_NUMBER
)
832 SetLastError( ERROR_INVALID_FLAGS
);
836 if (!len
) return datalen
;
839 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
842 memcpy( buffer
, data
, datalen
* sizeof(WCHAR
) );
847 static int locale_return_string( DWORD pos
, LCTYPE type
, WCHAR
*buffer
, int len
)
849 return locale_return_data( locale_strings
+ pos
+ 1, locale_strings
[pos
] + 1, type
, buffer
, len
);
853 static int locale_return_number( UINT val
, LCTYPE type
, WCHAR
*buffer
, int len
)
858 if (!(type
& LOCALE_RETURN_NUMBER
))
860 switch (LOWORD(type
))
862 case LOCALE_ILANGUAGE
:
863 case LOCALE_IDEFAULTLANGUAGE
:
864 ret
= swprintf( tmp
, ARRAY_SIZE(tmp
), L
"%04x", val
) + 1;
866 case LOCALE_IDEFAULTEBCDICCODEPAGE
:
867 ret
= swprintf( tmp
, ARRAY_SIZE(tmp
), L
"%03u", val
) + 1;
870 ret
= swprintf( tmp
, ARRAY_SIZE(tmp
), L
"%u", val
) + 1;
874 else ret
= sizeof(UINT
) / sizeof(WCHAR
);
876 if (!len
) return ret
;
879 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
883 if (type
& LOCALE_RETURN_NUMBER
) memcpy( buffer
, &val
, sizeof(val
) );
884 else wcscpy( buffer
, tmp
);
890 static int locale_return_strarray( DWORD pos
, WORD idx
, LCTYPE type
, WCHAR
*buffer
, int len
)
892 const DWORD
*array
= (const DWORD
*)(locale_strings
+ pos
+ 1);
893 WORD count
= locale_strings
[pos
];
895 return locale_return_string( idx
< count
? array
[idx
] : 0, type
, buffer
, len
);
899 /* get locale information from the locale.nls file */
900 static int get_locale_info( const NLS_LOCALE_DATA
*locale
, LCID lcid
, LCTYPE type
,
901 WCHAR
*buffer
, int len
)
905 if (locale
!= user_locale
) type
|= LOCALE_NOUSEROVERRIDE
;
907 switch (LOWORD(type
))
909 case LOCALE_ILANGUAGE
:
910 /* return default language for neutral locales */
911 val
= locale
->inotneutral
? locale
->ilanguage
: locale
->idefaultlanguage
;
912 return locale_return_number( val
, type
, buffer
, len
);
914 case LOCALE_SLOCALIZEDDISPLAYNAME
:
915 /* FIXME: localization */
916 return locale_return_string( locale
->sengdisplayname
, type
, buffer
, len
);
918 case LOCALE_SABBREVLANGNAME
:
919 return locale_return_string( locale
->sabbrevlangname
, type
, buffer
, len
);
921 case LOCALE_SNATIVELANGNAME
:
922 return locale_return_string( locale
->snativelangname
, type
, buffer
, len
);
924 case LOCALE_ICOUNTRY
:
927 case LOCALE_SLOCALIZEDCOUNTRYNAME
:
928 /* FIXME: localization */
929 return locale_return_string( locale
->sengcountry
, type
, buffer
, len
);
931 case LOCALE_SABBREVCTRYNAME
:
932 return locale_return_string( locale
->sabbrevctryname
, type
, buffer
, len
);
934 case LOCALE_SNATIVECTRYNAME
:
935 return locale_return_string( locale
->snativectryname
, type
, buffer
, len
);
937 case LOCALE_IDEFAULTLANGUAGE
:
938 return locale_return_number( locale
->idefaultlanguage
, type
, buffer
, len
);
940 case LOCALE_IDEFAULTCOUNTRY
:
943 case LOCALE_IDEFAULTCODEPAGE
:
944 val
= locale
->idefaultcodepage
== CP_UTF8
? CP_OEMCP
: locale
->idefaultcodepage
;
945 return locale_return_number( val
, type
, buffer
, len
);
950 case LOCALE_IMEASURE
:
953 case LOCALE_SDECIMAL
:
956 case LOCALE_STHOUSAND
:
959 case LOCALE_SGROUPING
:
968 case LOCALE_SNATIVEDIGITS
:
971 case LOCALE_SCURRENCY
:
974 case LOCALE_SINTLSYMBOL
:
977 case LOCALE_SMONDECIMALSEP
:
980 case LOCALE_SMONTHOUSANDSEP
:
983 case LOCALE_SMONGROUPING
:
986 case LOCALE_ICURRDIGITS
:
987 case LOCALE_IINTLCURRDIGITS
:
990 case LOCALE_ICURRENCY
:
993 case LOCALE_INEGCURR
:
1002 case LOCALE_SSHORTDATE
:
1005 case LOCALE_SLONGDATE
:
1017 case LOCALE_ICENTURY
:
1020 case LOCALE_ITLZERO
:
1023 case LOCALE_IDAYLZERO
:
1026 case LOCALE_IMONLZERO
:
1035 case LOCALE_SDAYNAME1
:
1036 case LOCALE_SDAYNAME2
:
1037 case LOCALE_SDAYNAME3
:
1038 case LOCALE_SDAYNAME4
:
1039 case LOCALE_SDAYNAME5
:
1040 case LOCALE_SDAYNAME6
:
1041 case LOCALE_SDAYNAME7
:
1042 return locale_return_strarray( locale
->sdayname
,
1043 LOWORD(type
- LOCALE_SDAYNAME1
+ 1) % 7, type
, buffer
, len
);
1045 case LOCALE_SABBREVDAYNAME1
:
1046 case LOCALE_SABBREVDAYNAME2
:
1047 case LOCALE_SABBREVDAYNAME3
:
1048 case LOCALE_SABBREVDAYNAME4
:
1049 case LOCALE_SABBREVDAYNAME5
:
1050 case LOCALE_SABBREVDAYNAME6
:
1051 case LOCALE_SABBREVDAYNAME7
:
1052 return locale_return_strarray( locale
->sabbrevdayname
,
1053 LOWORD(type
- LOCALE_SABBREVDAYNAME1
+ 1) % 7, type
, buffer
, len
);
1055 case LOCALE_SMONTHNAME1
:
1056 case LOCALE_SMONTHNAME2
:
1057 case LOCALE_SMONTHNAME3
:
1058 case LOCALE_SMONTHNAME4
:
1059 case LOCALE_SMONTHNAME5
:
1060 case LOCALE_SMONTHNAME6
:
1061 case LOCALE_SMONTHNAME7
:
1062 case LOCALE_SMONTHNAME8
:
1063 case LOCALE_SMONTHNAME9
:
1064 case LOCALE_SMONTHNAME10
:
1065 case LOCALE_SMONTHNAME11
:
1066 case LOCALE_SMONTHNAME12
:
1067 return locale_return_strarray( ((type
& LOCALE_RETURN_GENITIVE_NAMES
) && locale
->sgenitivemonth
) ?
1068 locale
->sgenitivemonth
: locale
->smonthname
,
1069 type
- LOCALE_SMONTHNAME1
, type
, buffer
, len
);
1071 case LOCALE_SABBREVMONTHNAME1
:
1072 case LOCALE_SABBREVMONTHNAME2
:
1073 case LOCALE_SABBREVMONTHNAME3
:
1074 case LOCALE_SABBREVMONTHNAME4
:
1075 case LOCALE_SABBREVMONTHNAME5
:
1076 case LOCALE_SABBREVMONTHNAME6
:
1077 case LOCALE_SABBREVMONTHNAME7
:
1078 case LOCALE_SABBREVMONTHNAME8
:
1079 case LOCALE_SABBREVMONTHNAME9
:
1080 case LOCALE_SABBREVMONTHNAME10
:
1081 case LOCALE_SABBREVMONTHNAME11
:
1082 case LOCALE_SABBREVMONTHNAME12
:
1083 return locale_return_strarray( ((type
& LOCALE_RETURN_GENITIVE_NAMES
) && locale
->sabbrevgenitivemonth
) ?
1084 locale
->sabbrevgenitivemonth
: locale
->sabbrevmonthname
,
1085 type
- LOCALE_SABBREVMONTHNAME1
, type
, buffer
, len
);
1087 case LOCALE_SPOSITIVESIGN
:
1090 case LOCALE_SNEGATIVESIGN
:
1093 case LOCALE_IPOSSIGNPOSN
:
1096 case LOCALE_INEGSIGNPOSN
:
1099 case LOCALE_IPOSSYMPRECEDES
:
1102 case LOCALE_IPOSSEPBYSPACE
:
1105 case LOCALE_INEGSYMPRECEDES
:
1108 case LOCALE_INEGSEPBYSPACE
:
1111 case LOCALE_FONTSIGNATURE
:
1114 case LOCALE_SISO639LANGNAME
:
1115 return locale_return_string( locale
->siso639langname
, type
, buffer
, len
);
1117 case LOCALE_SISO3166CTRYNAME
:
1118 return locale_return_string( locale
->siso3166ctryname
, type
, buffer
, len
);
1124 if (SORTIDFROMLCID(lcid
)) /* custom sort locale */
1126 const NLS_LOCALE_LCID_INDEX
*entry
= find_lcid_entry( lcid
& ~0x80000000 );
1127 if (entry
) return locale_return_string( entry
->name
, type
, buffer
, len
);
1129 return locale_return_string( locale
->sname
, type
, buffer
, len
);
1131 case LOCALE_SDURATION
:
1134 case LOCALE_SKEYBOARDSTOINSTALL
:
1137 case LOCALE_SSHORTESTDAYNAME1
:
1138 case LOCALE_SSHORTESTDAYNAME2
:
1139 case LOCALE_SSHORTESTDAYNAME3
:
1140 case LOCALE_SSHORTESTDAYNAME4
:
1141 case LOCALE_SSHORTESTDAYNAME5
:
1142 case LOCALE_SSHORTESTDAYNAME6
:
1143 case LOCALE_SSHORTESTDAYNAME7
:
1144 return locale_return_strarray( locale
->sshortestdayname
,
1145 LOWORD(type
- LOCALE_SSHORTESTDAYNAME1
+ 1) % 7, type
, buffer
, len
);
1147 case LOCALE_SISO639LANGNAME2
:
1148 return locale_return_string( locale
->siso639langname2
, type
, buffer
, len
);
1150 case LOCALE_SISO3166CTRYNAME2
:
1151 return locale_return_string( locale
->siso3166ctryname2
, type
, buffer
, len
);
1156 case LOCALE_SPOSINFINITY
:
1159 case LOCALE_SNEGINFINITY
:
1162 case LOCALE_SSCRIPTS
:
1165 case LOCALE_SPARENT
:
1166 return locale_return_string( locale
->sparent
, type
, buffer
, len
);
1168 case LOCALE_SCONSOLEFALLBACKNAME
:
1171 case LOCALE_SLOCALIZEDLANGUAGENAME
:
1172 /* FIXME: localization */
1173 return locale_return_string( locale
->senglanguage
, type
, buffer
, len
);
1175 case LOCALE_IREADINGLAYOUT
:
1178 case LOCALE_INEUTRAL
:
1181 case LOCALE_SENGLISHDISPLAYNAME
:
1182 return locale_return_string( locale
->sengdisplayname
, type
, buffer
, len
);
1184 case LOCALE_SNATIVEDISPLAYNAME
:
1185 return locale_return_string( locale
->snativedisplayname
, type
, buffer
, len
);
1187 case LOCALE_INEGATIVEPERCENT
:
1190 case LOCALE_IPOSITIVEPERCENT
:
1193 case LOCALE_SPERCENT
:
1196 case LOCALE_SPERMILLE
:
1199 case LOCALE_SMONTHDAY
:
1202 case LOCALE_SSHORTTIME
:
1205 case LOCALE_SOPENTYPELANGUAGETAG
:
1208 case LOCALE_SSORTLOCALE
:
1211 case LOCALE_SRELATIVELONGDATE
:
1214 case 0x007d: /* undocumented */
1217 case LOCALE_SSHORTESTAM
:
1220 case LOCALE_SSHORTESTPM
:
1223 case LOCALE_SENGLANGUAGE
:
1224 return locale_return_string( locale
->senglanguage
, type
, buffer
, len
);
1226 case LOCALE_SENGCOUNTRY
:
1227 return locale_return_string( locale
->sengcountry
, type
, buffer
, len
);
1229 case LOCALE_STIMEFORMAT
:
1232 case LOCALE_IDEFAULTANSICODEPAGE
:
1233 val
= locale
->idefaultansicodepage
== CP_UTF8
? CP_ACP
: locale
->idefaultansicodepage
;
1234 return locale_return_number( val
, type
, buffer
, len
);
1236 case LOCALE_ITIMEMARKPOSN
:
1239 case LOCALE_SYEARMONTH
:
1242 case LOCALE_SENGCURRNAME
:
1245 case LOCALE_SNATIVECURRNAME
:
1248 case LOCALE_ICALENDARTYPE
:
1251 case LOCALE_IPAPERSIZE
:
1254 case LOCALE_IOPTIONALCALENDAR
:
1257 case LOCALE_IFIRSTDAYOFWEEK
:
1260 case LOCALE_IFIRSTWEEKOFYEAR
:
1263 case LOCALE_SMONTHNAME13
:
1264 return locale_return_strarray( ((type
& LOCALE_RETURN_GENITIVE_NAMES
) && locale
->sgenitivemonth
) ?
1265 locale
->sgenitivemonth
: locale
->smonthname
,
1266 12, type
, buffer
, len
);
1268 case LOCALE_SABBREVMONTHNAME13
:
1269 return locale_return_strarray( ((type
& LOCALE_RETURN_GENITIVE_NAMES
) && locale
->sabbrevgenitivemonth
) ?
1270 locale
->sabbrevgenitivemonth
: locale
->sabbrevmonthname
,
1271 12, type
, buffer
, len
);
1273 case LOCALE_INEGNUMBER
:
1276 case LOCALE_IDEFAULTMACCODEPAGE
:
1277 val
= locale
->idefaultmaccodepage
== CP_UTF8
? CP_MACCP
: locale
->idefaultmaccodepage
;
1278 return locale_return_number( val
, type
, buffer
, len
);
1280 case LOCALE_IDEFAULTEBCDICCODEPAGE
:
1281 return locale_return_number( locale
->idefaultebcdiccodepage
, type
, buffer
, len
);
1283 case LOCALE_SSORTNAME
:
1286 case LOCALE_IDIGITSUBSTITUTION
:
1289 SetLastError( ERROR_INVALID_FLAGS
);
1294 /***********************************************************************
1297 void init_locale(void)
1299 UINT ansi_cp
= 0, oem_cp
= 0;
1300 USHORT
*ansi_ptr
, *oem_ptr
;
1302 WCHAR bufferW
[LOCALE_NAME_MAX_LENGTH
];
1303 DYNAMIC_TIME_ZONE_INFORMATION timezone
;
1304 GEOID geoid
= GEOID_NOT_AVAILABLE
;
1305 DWORD count
, dispos
, i
;
1310 NtQueryDefaultLocale( FALSE
, &system_lcid
);
1311 NtQueryDefaultLocale( FALSE
, &user_lcid
);
1312 system_locale
= get_locale_by_id( &system_lcid
, 0 );
1313 user_locale
= get_locale_by_id( &user_lcid
, 0 );
1315 if (GetEnvironmentVariableW( L
"WINEUNIXCP", bufferW
, ARRAY_SIZE(bufferW
) ))
1316 unix_cp
= wcstoul( bufferW
, NULL
, 10 );
1318 kernel32_handle
= GetModuleHandleW( L
"kernel32.dll" );
1320 GetLocaleInfoW( LOCALE_SYSTEM_DEFAULT
, LOCALE_IDEFAULTANSICODEPAGE
| LOCALE_RETURN_NUMBER
,
1321 (WCHAR
*)&ansi_cp
, sizeof(ansi_cp
)/sizeof(WCHAR
) );
1322 GetLocaleInfoW( LOCALE_SYSTEM_DEFAULT
, LOCALE_IDEFAULTMACCODEPAGE
| LOCALE_RETURN_NUMBER
,
1323 (WCHAR
*)&mac_cp
, sizeof(mac_cp
)/sizeof(WCHAR
) );
1324 GetLocaleInfoW( LOCALE_SYSTEM_DEFAULT
, LOCALE_IDEFAULTCODEPAGE
| LOCALE_RETURN_NUMBER
,
1325 (WCHAR
*)&oem_cp
, sizeof(oem_cp
)/sizeof(WCHAR
) );
1327 NtGetNlsSectionPtr( 9, 0, NULL
, &sort_ptr
, &size
);
1328 NtGetNlsSectionPtr( 12, NormalizationC
, NULL
, (void **)&norm_info
, &size
);
1329 init_sortkeys( sort_ptr
);
1331 if (!ansi_cp
|| NtGetNlsSectionPtr( 11, ansi_cp
, NULL
, (void **)&ansi_ptr
, &size
))
1332 NtGetNlsSectionPtr( 11, 1252, NULL
, (void **)&ansi_ptr
, &size
);
1333 if (!oem_cp
|| NtGetNlsSectionPtr( 11, oem_cp
, 0, (void **)&oem_ptr
, &size
))
1334 NtGetNlsSectionPtr( 11, 437, NULL
, (void **)&oem_ptr
, &size
);
1335 NtCurrentTeb()->Peb
->AnsiCodePageData
= ansi_ptr
;
1336 NtCurrentTeb()->Peb
->OemCodePageData
= oem_ptr
;
1337 NtCurrentTeb()->Peb
->UnicodeCaseTableData
= sort
.casemap
;
1338 RtlInitNlsTables( ansi_ptr
, oem_ptr
, sort
.casemap
, &nls_info
);
1339 RtlResetRtlTranslations( &nls_info
);
1341 RegCreateKeyExW( HKEY_LOCAL_MACHINE
, L
"System\\CurrentControlSet\\Control\\Nls",
1342 0, NULL
, REG_OPTION_NON_VOLATILE
, KEY_ALL_ACCESS
, NULL
, &nls_key
, NULL
);
1343 RegCreateKeyExW( HKEY_LOCAL_MACHINE
, L
"Software\\Microsoft\\Windows NT\\CurrentVersion\\Time Zones",
1344 0, NULL
, REG_OPTION_NON_VOLATILE
, KEY_ALL_ACCESS
, NULL
, &tz_key
, NULL
);
1345 RegCreateKeyExW( HKEY_CURRENT_USER
, L
"Control Panel\\International",
1346 0, NULL
, REG_OPTION_NON_VOLATILE
, KEY_ALL_ACCESS
, NULL
, &intl_key
, NULL
);
1348 current_locale_sort
= get_language_sort( LOCALE_NAME_USER_DEFAULT
);
1350 if (GetDynamicTimeZoneInformation( &timezone
) != TIME_ZONE_ID_INVALID
&&
1351 !RegCreateKeyExW( HKEY_LOCAL_MACHINE
, L
"System\\CurrentControlSet\\Control\\TimeZoneInformation",
1352 0, NULL
, REG_OPTION_NON_VOLATILE
, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
))
1354 RegSetValueExW( hkey
, L
"StandardName", 0, REG_SZ
, (BYTE
*)timezone
.StandardName
,
1355 (lstrlenW(timezone
.StandardName
) + 1) * sizeof(WCHAR
) );
1356 RegSetValueExW( hkey
, L
"TimeZoneKeyName", 0, REG_SZ
, (BYTE
*)timezone
.TimeZoneKeyName
,
1357 (lstrlenW(timezone
.TimeZoneKeyName
) + 1) * sizeof(WCHAR
) );
1358 RegCloseKey( hkey
);
1361 if (!RegCreateKeyExW( intl_key
, L
"Geo", 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &hkey
, &dispos
))
1363 if (dispos
== REG_CREATED_NEW_KEY
)
1365 GetLocaleInfoW( LOCALE_USER_DEFAULT
, LOCALE_IGEOID
| LOCALE_RETURN_NUMBER
,
1366 (WCHAR
*)&geoid
, sizeof(geoid
) / sizeof(WCHAR
) );
1367 SetUserGeoID( geoid
);
1369 RegCloseKey( hkey
);
1372 /* Update registry contents if the user locale has changed.
1373 * This simulates the action of the Windows control panel. */
1375 count
= sizeof(bufferW
);
1376 if (!RegQueryValueExW( intl_key
, L
"Locale", NULL
, NULL
, (BYTE
*)bufferW
, &count
))
1378 if (wcstoul( bufferW
, NULL
, 16 ) == user_lcid
) return; /* already set correctly */
1379 TRACE( "updating registry, locale changed %s -> %08lx\n", debugstr_w(bufferW
), user_lcid
);
1381 else TRACE( "updating registry, locale changed none -> %08lx\n", user_lcid
);
1382 swprintf( bufferW
, ARRAY_SIZE(bufferW
), L
"%08x", user_lcid
);
1383 RegSetValueExW( intl_key
, L
"Locale", 0, REG_SZ
,
1384 (BYTE
*)bufferW
, (lstrlenW(bufferW
) + 1) * sizeof(WCHAR
) );
1386 for (i
= 0; i
< ARRAY_SIZE(registry_values
); i
++)
1388 GetLocaleInfoW( LOCALE_USER_DEFAULT
, registry_values
[i
].lctype
| LOCALE_NOUSEROVERRIDE
,
1389 bufferW
, ARRAY_SIZE( bufferW
));
1390 RegSetValueExW( intl_key
, registry_values
[i
].name
, 0, REG_SZ
,
1391 (BYTE
*)bufferW
, (lstrlenW(bufferW
) + 1) * sizeof(WCHAR
) );
1394 if (geoid
== GEOID_NOT_AVAILABLE
)
1396 GetLocaleInfoW( LOCALE_USER_DEFAULT
, LOCALE_IGEOID
| LOCALE_RETURN_NUMBER
,
1397 (WCHAR
*)&geoid
, sizeof(geoid
) / sizeof(WCHAR
) );
1398 SetUserGeoID( geoid
);
1401 if (!RegCreateKeyExW( nls_key
, L
"Codepage",
1402 0, NULL
, REG_OPTION_NON_VOLATILE
, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
))
1404 count
= swprintf( bufferW
, ARRAY_SIZE(bufferW
), L
"%03d", ansi_cp
);
1405 RegSetValueExW( hkey
, L
"ACP", 0, REG_SZ
, (BYTE
*)bufferW
, (count
+ 1) * sizeof(WCHAR
) );
1406 count
= swprintf( bufferW
, ARRAY_SIZE(bufferW
), L
"%03d", oem_cp
);
1407 RegSetValueExW( hkey
, L
"OEMCP", 0, REG_SZ
, (BYTE
*)bufferW
, (count
+ 1) * sizeof(WCHAR
) );
1408 count
= swprintf( bufferW
, ARRAY_SIZE(bufferW
), L
"%03d", mac_cp
);
1409 RegSetValueExW( hkey
, L
"MACCP", 0, REG_SZ
, (BYTE
*)bufferW
, (count
+ 1) * sizeof(WCHAR
) );
1410 RegCloseKey( hkey
);
1415 static inline USHORT
get_table_entry( const USHORT
*table
, WCHAR ch
)
1417 return table
[table
[table
[ch
>> 8] + ((ch
>> 4) & 0x0f)] + (ch
& 0xf)];
1421 static inline WCHAR
casemap( const USHORT
*table
, WCHAR ch
)
1423 return ch
+ table
[table
[table
[ch
>> 8] + ((ch
>> 4) & 0x0f)] + (ch
& 0x0f)];
1427 static inline WORD
get_char_type( DWORD type
, WCHAR ch
)
1429 const BYTE
*ptr
= sort
.ctype_idx
+ ((const WORD
*)sort
.ctype_idx
)[ch
>> 8];
1430 ptr
= sort
.ctype_idx
+ ((const WORD
*)ptr
)[(ch
>> 4) & 0x0f] + (ch
& 0x0f);
1431 return sort
.ctypes
[*ptr
* 3 + type
/ 2];
1435 static BYTE
rol( BYTE val
, BYTE count
)
1437 return (val
<< count
) | (val
>> (8 - count
));
1441 static BYTE
get_char_props( const struct norm_table
*info
, unsigned int ch
)
1443 const BYTE
*level1
= (const BYTE
*)((const USHORT
*)info
+ info
->props_level1
);
1444 const BYTE
*level2
= (const BYTE
*)((const USHORT
*)info
+ info
->props_level2
);
1445 BYTE off
= level1
[ch
/ 128];
1447 if (!off
|| off
>= 0xfb) return rol( off
, 5 );
1448 return level2
[(off
- 1) * 128 + ch
% 128];
1452 static const WCHAR
*get_decomposition( WCHAR ch
, unsigned int *ret_len
)
1454 const struct pair
{ WCHAR src
; USHORT dst
; } *pairs
;
1455 const USHORT
*hash_table
= (const USHORT
*)norm_info
+ norm_info
->decomp_hash
;
1457 unsigned int i
, pos
, end
, len
, hash
;
1460 hash
= ch
% norm_info
->decomp_size
;
1461 pos
= hash_table
[hash
];
1464 if (get_char_props( norm_info
, ch
) != 0xbf) return NULL
;
1465 ret
= (const USHORT
*)norm_info
+ norm_info
->decomp_seq
+ (pos
& 0x1fff);
1470 pairs
= (const struct pair
*)((const USHORT
*)norm_info
+ norm_info
->decomp_map
);
1472 /* find the end of the hash bucket */
1473 for (i
= hash
+ 1; i
< norm_info
->decomp_size
; i
++) if (!(hash_table
[i
] >> 13)) break;
1474 if (i
< norm_info
->decomp_size
) end
= hash_table
[i
];
1475 else for (end
= pos
; pairs
[end
].src
; end
++) ;
1477 for ( ; pos
< end
; pos
++)
1479 if (pairs
[pos
].src
!= (WCHAR
)ch
) continue;
1480 ret
= (const USHORT
*)norm_info
+ norm_info
->decomp_seq
+ (pairs
[pos
].dst
& 0x1fff);
1481 len
= pairs
[pos
].dst
>> 13;
1484 if (pos
>= end
) return NULL
;
1487 if (len
== 7) while (ret
[len
]) len
++;
1488 if (!ret
[0]) len
= 0; /* ignored char */
1494 static WCHAR
compose_chars( WCHAR ch1
, WCHAR ch2
)
1496 const USHORT
*table
= (const USHORT
*)norm_info
+ norm_info
->comp_hash
;
1497 const WCHAR
*chars
= (const USHORT
*)norm_info
+ norm_info
->comp_seq
;
1498 unsigned int hash
, start
, end
, i
;
1501 hash
= (ch1
+ 95 * ch2
) % norm_info
->comp_size
;
1502 start
= table
[hash
];
1503 end
= table
[hash
+ 1];
1506 for (i
= 0; i
< 3; i
++, start
++)
1508 ch
[i
] = chars
[start
];
1509 if (IS_HIGH_SURROGATE( ch
[i
] )) start
++;
1511 if (ch
[0] == ch1
&& ch
[1] == ch2
) return ch
[2];
1517 static UINT
get_lcid_codepage( LCID lcid
, ULONG flags
)
1519 UINT ret
= GetACP();
1521 if (!(flags
& LOCALE_USE_CP_ACP
) && lcid
!= GetSystemDefaultLCID())
1522 GetLocaleInfoW( lcid
, LOCALE_IDEFAULTANSICODEPAGE
| LOCALE_RETURN_NUMBER
,
1523 (WCHAR
*)&ret
, sizeof(ret
)/sizeof(WCHAR
) );
1528 static int get_value_base_by_lctype( LCTYPE lctype
)
1530 return lctype
== LOCALE_ILANGUAGE
|| lctype
== LOCALE_IDEFAULTLANGUAGE
? 16 : 10;
1534 static const struct registry_value
*get_locale_registry_value( DWORD lctype
)
1538 for (i
= 0; i
< ARRAY_SIZE( registry_values
); i
++)
1539 if (registry_values
[i
].lctype
== lctype
) return ®istry_values
[i
];
1544 static INT
get_registry_locale_info( const struct registry_value
*registry_value
, LPWSTR buffer
, INT len
)
1546 DWORD size
, index
= registry_value
- registry_values
;
1549 RtlEnterCriticalSection( &locale_section
);
1551 if (!registry_cache
[index
])
1553 size
= len
* sizeof(WCHAR
);
1554 ret
= RegQueryValueExW( intl_key
, registry_value
->name
, NULL
, NULL
, (BYTE
*)buffer
, &size
);
1557 if (buffer
&& (registry_cache
[index
] = HeapAlloc( GetProcessHeap(), 0, size
+ sizeof(WCHAR
) )))
1559 memcpy( registry_cache
[index
], buffer
, size
);
1560 registry_cache
[index
][size
/ sizeof(WCHAR
)] = 0;
1562 RtlLeaveCriticalSection( &locale_section
);
1563 return size
/ sizeof(WCHAR
);
1567 RtlLeaveCriticalSection( &locale_section
);
1568 if (ret
== ERROR_FILE_NOT_FOUND
) return -1;
1569 if (ret
== ERROR_MORE_DATA
) SetLastError( ERROR_INSUFFICIENT_BUFFER
);
1570 else SetLastError( ret
);
1575 ret
= lstrlenW( registry_cache
[index
] ) + 1;
1580 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
1583 else lstrcpyW( buffer
, registry_cache
[index
] );
1585 RtlLeaveCriticalSection( &locale_section
);
1590 static const CPTABLEINFO
*get_codepage_table( UINT codepage
)
1599 return &nls_info
.AnsiTableInfo
;
1601 return &nls_info
.OemTableInfo
;
1606 if (NtCurrentTeb()->CurrentLocale
== GetUserDefaultLCID()) return &nls_info
.AnsiTableInfo
;
1607 codepage
= get_lcid_codepage( NtCurrentTeb()->CurrentLocale
, 0 );
1608 if (!codepage
) return &nls_info
.AnsiTableInfo
;
1611 if (codepage
== nls_info
.AnsiTableInfo
.CodePage
) return &nls_info
.AnsiTableInfo
;
1612 if (codepage
== nls_info
.OemTableInfo
.CodePage
) return &nls_info
.OemTableInfo
;
1616 RtlEnterCriticalSection( &locale_section
);
1618 for (i
= 0; i
< nb_codepages
; i
++) if (codepages
[i
].CodePage
== codepage
) goto done
;
1620 if (i
== ARRAY_SIZE( codepages
))
1622 RtlLeaveCriticalSection( &locale_section
);
1623 ERR( "too many codepages\n" );
1626 if (NtGetNlsSectionPtr( 11, codepage
, NULL
, (void **)&ptr
, &size
))
1628 RtlLeaveCriticalSection( &locale_section
);
1629 SetLastError( ERROR_INVALID_PARAMETER
);
1632 RtlInitCodePageTable( ptr
, &codepages
[i
] );
1635 RtlLeaveCriticalSection( &locale_section
);
1636 return &codepages
[i
];
1640 static const WCHAR
*get_ligature( WCHAR wc
)
1642 int low
= 0, high
= ARRAY_SIZE( ligatures
) -1;
1645 int pos
= (low
+ high
) / 2;
1646 if (ligatures
[pos
][0] < wc
) low
= pos
+ 1;
1647 else if (ligatures
[pos
][0] > wc
) high
= pos
- 1;
1648 else return ligatures
[pos
] + 1;
1654 static NTSTATUS
expand_ligatures( const WCHAR
*src
, int srclen
, WCHAR
*dst
, int *dstlen
)
1656 int i
, len
, pos
= 0;
1657 NTSTATUS ret
= STATUS_SUCCESS
;
1658 const WCHAR
*expand
;
1660 for (i
= 0; i
< srclen
; i
++)
1662 if (!(expand
= get_ligature( src
[i
] )))
1667 else len
= lstrlenW( expand
);
1669 if (*dstlen
&& ret
== STATUS_SUCCESS
)
1671 if (pos
+ len
<= *dstlen
) memcpy( dst
+ pos
, expand
, len
* sizeof(WCHAR
) );
1672 else ret
= STATUS_BUFFER_TOO_SMALL
;
1681 static NTSTATUS
fold_digits( const WCHAR
*src
, int srclen
, WCHAR
*dst
, int *dstlen
)
1683 extern const WCHAR wine_digitmap
[] DECLSPEC_HIDDEN
;
1684 int i
, len
= *dstlen
;
1687 if (!len
) return STATUS_SUCCESS
;
1688 if (srclen
> len
) return STATUS_BUFFER_TOO_SMALL
;
1689 for (i
= 0; i
< srclen
; i
++)
1691 WCHAR digit
= get_table_entry( wine_digitmap
, src
[i
] );
1692 dst
[i
] = digit
? digit
: src
[i
];
1694 return STATUS_SUCCESS
;
1698 static NTSTATUS
fold_string( DWORD flags
, const WCHAR
*src
, int srclen
, WCHAR
*dst
, int *dstlen
)
1705 case MAP_PRECOMPOSED
:
1706 return RtlNormalizeString( NormalizationC
, src
, srclen
, dst
, dstlen
);
1708 case MAP_PRECOMPOSED
| MAP_FOLDCZONE
:
1709 return RtlNormalizeString( NormalizationKC
, src
, srclen
, dst
, dstlen
);
1711 return RtlNormalizeString( NormalizationD
, src
, srclen
, dst
, dstlen
);
1712 case MAP_COMPOSITE
| MAP_FOLDCZONE
:
1713 return RtlNormalizeString( NormalizationKD
, src
, srclen
, dst
, dstlen
);
1714 case MAP_FOLDDIGITS
:
1715 return fold_digits( src
, srclen
, dst
, dstlen
);
1716 case MAP_EXPAND_LIGATURES
:
1717 case MAP_EXPAND_LIGATURES
| MAP_FOLDCZONE
:
1718 return expand_ligatures( src
, srclen
, dst
, dstlen
);
1719 case MAP_FOLDDIGITS
| MAP_PRECOMPOSED
:
1720 if (!(tmp
= RtlAllocateHeap( GetProcessHeap(), 0, srclen
* sizeof(WCHAR
) )))
1721 return STATUS_NO_MEMORY
;
1722 fold_digits( src
, srclen
, tmp
, &srclen
);
1723 ret
= RtlNormalizeString( NormalizationC
, tmp
, srclen
, dst
, dstlen
);
1725 case MAP_FOLDDIGITS
| MAP_FOLDCZONE
:
1726 case MAP_FOLDDIGITS
| MAP_PRECOMPOSED
| MAP_FOLDCZONE
:
1727 if (!(tmp
= RtlAllocateHeap( GetProcessHeap(), 0, srclen
* sizeof(WCHAR
) )))
1728 return STATUS_NO_MEMORY
;
1729 fold_digits( src
, srclen
, tmp
, &srclen
);
1730 ret
= RtlNormalizeString( NormalizationKC
, tmp
, srclen
, dst
, dstlen
);
1732 case MAP_FOLDDIGITS
| MAP_COMPOSITE
:
1733 if (!(tmp
= RtlAllocateHeap( GetProcessHeap(), 0, srclen
* sizeof(WCHAR
) )))
1734 return STATUS_NO_MEMORY
;
1735 fold_digits( src
, srclen
, tmp
, &srclen
);
1736 ret
= RtlNormalizeString( NormalizationD
, tmp
, srclen
, dst
, dstlen
);
1738 case MAP_FOLDDIGITS
| MAP_COMPOSITE
| MAP_FOLDCZONE
:
1739 if (!(tmp
= RtlAllocateHeap( GetProcessHeap(), 0, srclen
* sizeof(WCHAR
) )))
1740 return STATUS_NO_MEMORY
;
1741 fold_digits( src
, srclen
, tmp
, &srclen
);
1742 ret
= RtlNormalizeString( NormalizationKD
, tmp
, srclen
, dst
, dstlen
);
1744 case MAP_EXPAND_LIGATURES
| MAP_FOLDDIGITS
:
1745 case MAP_EXPAND_LIGATURES
| MAP_FOLDDIGITS
| MAP_FOLDCZONE
:
1746 if (!(tmp
= RtlAllocateHeap( GetProcessHeap(), 0, srclen
* sizeof(WCHAR
) )))
1747 return STATUS_NO_MEMORY
;
1748 fold_digits( src
, srclen
, tmp
, &srclen
);
1749 ret
= expand_ligatures( tmp
, srclen
, dst
, dstlen
);
1752 return STATUS_INVALID_PARAMETER_1
;
1754 RtlFreeHeap( GetProcessHeap(), 0, tmp
);
1759 static int mbstowcs_cpsymbol( DWORD flags
, const char *src
, int srclen
, WCHAR
*dst
, int dstlen
)
1765 SetLastError( ERROR_INVALID_FLAGS
);
1768 if (!dstlen
) return srclen
;
1769 len
= min( srclen
, dstlen
);
1770 for (i
= 0; i
< len
; i
++)
1772 unsigned char c
= src
[i
];
1773 dst
[i
] = (c
< 0x20) ? c
: c
+ 0xf000;
1777 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
1784 static int mbstowcs_utf7( DWORD flags
, const char *src
, int srclen
, WCHAR
*dst
, int dstlen
)
1786 static const signed char base64_decoding_table
[] =
1788 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x00-0x0F */
1789 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x10-0x1F */
1790 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, /* 0x20-0x2F */
1791 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, /* 0x30-0x3F */
1792 -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, /* 0x40-0x4F */
1793 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, /* 0x50-0x5F */
1794 -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, /* 0x60-0x6F */
1795 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1 /* 0x70-0x7F */
1798 const char *source_end
= src
+ srclen
;
1799 int offset
= 0, pos
= 0;
1800 DWORD byte_pair
= 0;
1804 SetLastError( ERROR_INVALID_FLAGS
);
1807 #define OUTPUT(ch) \
1811 if (pos >= dstlen) goto overflow; \
1817 while (src
< source_end
)
1822 if (src
>= source_end
) break;
1825 /* just a plus sign escaped as +- */
1833 signed char sextet
= *src
;
1836 /* skip over the dash and end base64 decoding
1837 * the current, unfinished byte pair is discarded */
1844 /* the next character of src is < 0 and therefore not part of a base64 sequence
1845 * the current, unfinished byte pair is NOT discarded in this case
1846 * this is probably a bug in Windows */
1849 sextet
= base64_decoding_table
[sextet
];
1852 /* -1 means that the next character of src is not part of a base64 sequence
1853 * in other words, all sextets in this base64 sequence have been processed
1854 * the current, unfinished byte pair is discarded */
1859 byte_pair
= (byte_pair
<< 6) | sextet
;
1863 /* this byte pair is done */
1864 OUTPUT( byte_pair
>> (offset
- 16) );
1869 while (src
< source_end
);
1873 OUTPUT( (unsigned char)*src
);
1880 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
1886 static int mbstowcs_utf8( DWORD flags
, const char *src
, int srclen
, WCHAR
*dst
, int dstlen
)
1891 if (flags
& ~(MB_PRECOMPOSED
| MB_COMPOSITE
| MB_USEGLYPHCHARS
| MB_ERR_INVALID_CHARS
))
1893 SetLastError( ERROR_INVALID_FLAGS
);
1896 if (!dstlen
) dst
= NULL
;
1897 status
= RtlUTF8ToUnicodeN( dst
, dstlen
* sizeof(WCHAR
), &reslen
, src
, srclen
);
1898 if (status
== STATUS_SOME_NOT_MAPPED
)
1900 if (flags
& MB_ERR_INVALID_CHARS
)
1902 SetLastError( ERROR_NO_UNICODE_TRANSLATION
);
1906 else if (!set_ntstatus( status
)) reslen
= 0;
1908 return reslen
/ sizeof(WCHAR
);
1912 static inline int is_private_use_area_char( WCHAR code
)
1914 return (code
>= 0xe000 && code
<= 0xf8ff);
1918 static int check_invalid_chars( const CPTABLEINFO
*info
, const unsigned char *src
, int srclen
)
1920 if (info
->DBCSOffsets
)
1922 for ( ; srclen
; src
++, srclen
-- )
1924 USHORT off
= info
->DBCSOffsets
[*src
];
1927 if (srclen
== 1) break; /* partial char, error */
1928 if (info
->DBCSOffsets
[off
+ src
[1]] == info
->UniDefaultChar
&&
1929 ((src
[0] << 8) | src
[1]) != info
->TransUniDefaultChar
) break;
1934 if (info
->MultiByteTable
[*src
] == info
->UniDefaultChar
&& *src
!= info
->TransUniDefaultChar
)
1936 if (is_private_use_area_char( info
->MultiByteTable
[*src
] )) break;
1941 for ( ; srclen
; src
++, srclen
-- )
1943 if (info
->MultiByteTable
[*src
] == info
->UniDefaultChar
&& *src
!= info
->TransUniDefaultChar
)
1945 if (is_private_use_area_char( info
->MultiByteTable
[*src
] )) break;
1953 static int mbstowcs_decompose( const CPTABLEINFO
*info
, const unsigned char *src
, int srclen
,
1954 WCHAR
*dst
, int dstlen
)
1959 const WCHAR
*decomp
;
1960 unsigned int decomp_len
;
1962 if (info
->DBCSOffsets
)
1964 if (!dstlen
) /* compute length */
1966 for (len
= 0; srclen
; srclen
--, src
++, len
+= decomp_len
)
1968 if ((off
= info
->DBCSOffsets
[*src
]))
1970 if (srclen
> 1 && src
[1])
1974 ch
= info
->DBCSOffsets
[off
+ *src
];
1976 else ch
= info
->UniDefaultChar
;
1978 else ch
= info
->MultiByteTable
[*src
];
1979 get_decomposition( ch
, &decomp_len
);
1984 for (len
= dstlen
; srclen
&& len
; srclen
--, src
++, dst
+= decomp_len
, len
-= decomp_len
)
1986 if ((off
= info
->DBCSOffsets
[*src
]))
1988 if (srclen
> 1 && src
[1])
1992 ch
= info
->DBCSOffsets
[off
+ *src
];
1994 else ch
= info
->UniDefaultChar
;
1996 else ch
= info
->MultiByteTable
[*src
];
1998 if ((decomp
= get_decomposition( ch
, &decomp_len
)))
2000 if (len
< decomp_len
) break;
2001 memcpy( dst
, decomp
, decomp_len
* sizeof(WCHAR
) );
2008 if (!dstlen
) /* compute length */
2010 for (len
= 0; srclen
; srclen
--, src
++, len
+= decomp_len
)
2011 get_decomposition( info
->MultiByteTable
[*src
], &decomp_len
);
2015 for (len
= dstlen
; srclen
&& len
; srclen
--, src
++, dst
+= decomp_len
, len
-= decomp_len
)
2017 ch
= info
->MultiByteTable
[*src
];
2018 if ((decomp
= get_decomposition( ch
, &decomp_len
)))
2020 if (len
< decomp_len
) break;
2021 memcpy( dst
, decomp
, decomp_len
* sizeof(WCHAR
) );
2029 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
2032 return dstlen
- len
;
2036 static int mbstowcs_sbcs( const CPTABLEINFO
*info
, const unsigned char *src
, int srclen
,
2037 WCHAR
*dst
, int dstlen
)
2039 const USHORT
*table
= info
->MultiByteTable
;
2042 if (!dstlen
) return srclen
;
2044 if (dstlen
< srclen
) /* buffer too small: fill it up to dstlen and return error */
2047 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
2051 while (srclen
>= 16)
2053 dst
[0] = table
[src
[0]];
2054 dst
[1] = table
[src
[1]];
2055 dst
[2] = table
[src
[2]];
2056 dst
[3] = table
[src
[3]];
2057 dst
[4] = table
[src
[4]];
2058 dst
[5] = table
[src
[5]];
2059 dst
[6] = table
[src
[6]];
2060 dst
[7] = table
[src
[7]];
2061 dst
[8] = table
[src
[8]];
2062 dst
[9] = table
[src
[9]];
2063 dst
[10] = table
[src
[10]];
2064 dst
[11] = table
[src
[11]];
2065 dst
[12] = table
[src
[12]];
2066 dst
[13] = table
[src
[13]];
2067 dst
[14] = table
[src
[14]];
2068 dst
[15] = table
[src
[15]];
2074 /* now handle the remaining characters */
2079 case 15: dst
[-15] = table
[src
[-15]];
2080 case 14: dst
[-14] = table
[src
[-14]];
2081 case 13: dst
[-13] = table
[src
[-13]];
2082 case 12: dst
[-12] = table
[src
[-12]];
2083 case 11: dst
[-11] = table
[src
[-11]];
2084 case 10: dst
[-10] = table
[src
[-10]];
2085 case 9: dst
[-9] = table
[src
[-9]];
2086 case 8: dst
[-8] = table
[src
[-8]];
2087 case 7: dst
[-7] = table
[src
[-7]];
2088 case 6: dst
[-6] = table
[src
[-6]];
2089 case 5: dst
[-5] = table
[src
[-5]];
2090 case 4: dst
[-4] = table
[src
[-4]];
2091 case 3: dst
[-3] = table
[src
[-3]];
2092 case 2: dst
[-2] = table
[src
[-2]];
2093 case 1: dst
[-1] = table
[src
[-1]];
2100 static int mbstowcs_dbcs( const CPTABLEINFO
*info
, const unsigned char *src
, int srclen
,
2101 WCHAR
*dst
, int dstlen
)
2108 for (i
= 0; srclen
; i
++, src
++, srclen
--)
2109 if (info
->DBCSOffsets
[*src
] && srclen
> 1 && src
[1]) { src
++; srclen
--; }
2113 for (i
= dstlen
; srclen
&& i
; i
--, srclen
--, src
++, dst
++)
2115 if ((off
= info
->DBCSOffsets
[*src
]))
2117 if (srclen
> 1 && src
[1])
2121 *dst
= info
->DBCSOffsets
[off
+ *src
];
2123 else *dst
= info
->UniDefaultChar
;
2125 else *dst
= info
->MultiByteTable
[*src
];
2129 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
2136 static int mbstowcs_codepage( UINT codepage
, DWORD flags
, const char *src
, int srclen
,
2137 WCHAR
*dst
, int dstlen
)
2139 CPTABLEINFO local_info
;
2140 const CPTABLEINFO
*info
= get_codepage_table( codepage
);
2141 const unsigned char *str
= (const unsigned char *)src
;
2145 SetLastError( ERROR_INVALID_PARAMETER
);
2148 if (flags
& ~(MB_PRECOMPOSED
| MB_COMPOSITE
| MB_USEGLYPHCHARS
| MB_ERR_INVALID_CHARS
))
2150 SetLastError( ERROR_INVALID_FLAGS
);
2154 if ((flags
& MB_USEGLYPHCHARS
) && info
->MultiByteTable
[256] == 256)
2157 local_info
.MultiByteTable
+= 257;
2160 if ((flags
& MB_ERR_INVALID_CHARS
) && check_invalid_chars( info
, str
, srclen
))
2162 SetLastError( ERROR_NO_UNICODE_TRANSLATION
);
2166 if (flags
& MB_COMPOSITE
) return mbstowcs_decompose( info
, str
, srclen
, dst
, dstlen
);
2168 if (info
->DBCSOffsets
)
2169 return mbstowcs_dbcs( info
, str
, srclen
, dst
, dstlen
);
2171 return mbstowcs_sbcs( info
, str
, srclen
, dst
, dstlen
);
2175 static int wcstombs_cpsymbol( DWORD flags
, const WCHAR
*src
, int srclen
, char *dst
, int dstlen
,
2176 const char *defchar
, BOOL
*used
)
2182 SetLastError( ERROR_INVALID_FLAGS
);
2185 if (defchar
|| used
)
2187 SetLastError( ERROR_INVALID_PARAMETER
);
2190 if (!dstlen
) return srclen
;
2191 len
= min( srclen
, dstlen
);
2192 for (i
= 0; i
< len
; i
++)
2194 if (src
[i
] < 0x20) dst
[i
] = src
[i
];
2195 else if (src
[i
] >= 0xf020 && src
[i
] < 0xf100) dst
[i
] = src
[i
] - 0xf000;
2198 SetLastError( ERROR_NO_UNICODE_TRANSLATION
);
2204 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
2211 static int wcstombs_utf7( DWORD flags
, const WCHAR
*src
, int srclen
, char *dst
, int dstlen
,
2212 const char *defchar
, BOOL
*used
)
2214 static const char directly_encodable
[] =
2216 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, /* 0x00 - 0x0f */
2217 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x10 - 0x1f */
2218 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, /* 0x20 - 0x2f */
2219 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, /* 0x30 - 0x3f */
2220 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x40 - 0x4f */
2221 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, /* 0x50 - 0x5f */
2222 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x60 - 0x6f */
2223 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 /* 0x70 - 0x7a */
2225 #define ENCODABLE(ch) ((ch) <= 0x7a && directly_encodable[(ch)])
2227 static const char base64_encoding_table
[] =
2228 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
2230 const WCHAR
*source_end
= src
+ srclen
;
2233 if (defchar
|| used
)
2235 SetLastError( ERROR_INVALID_PARAMETER
);
2240 SetLastError( ERROR_INVALID_FLAGS
);
2244 #define OUTPUT(ch) \
2248 if (pos >= dstlen) goto overflow; \
2254 while (src
< source_end
)
2262 else if (ENCODABLE(*src
))
2269 unsigned int offset
= 0, byte_pair
= 0;
2272 while (src
< source_end
&& !ENCODABLE(*src
))
2274 byte_pair
= (byte_pair
<< 16) | *src
;
2279 OUTPUT( base64_encoding_table
[(byte_pair
>> offset
) & 0x3f] );
2285 /* Windows won't create a padded base64 character if there's no room for the - sign
2286 * as well ; this is probably a bug in Windows */
2287 if (dstlen
> 0 && pos
+ 1 >= dstlen
) goto overflow
;
2288 byte_pair
<<= (6 - offset
);
2289 OUTPUT( base64_encoding_table
[byte_pair
& 0x3f] );
2291 /* Windows always explicitly terminates the base64 sequence
2292 even though RFC 2152 (page 3, rule 2) does not require this */
2299 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
2306 static int wcstombs_utf8( DWORD flags
, const WCHAR
*src
, int srclen
, char *dst
, int dstlen
,
2307 const char *defchar
, BOOL
*used
)
2312 if (defchar
|| used
)
2314 SetLastError( ERROR_INVALID_PARAMETER
);
2317 if (flags
& ~(WC_DISCARDNS
| WC_SEPCHARS
| WC_DEFAULTCHAR
| WC_ERR_INVALID_CHARS
|
2318 WC_COMPOSITECHECK
| WC_NO_BEST_FIT_CHARS
))
2320 SetLastError( ERROR_INVALID_FLAGS
);
2323 if (!dstlen
) dst
= NULL
;
2324 status
= RtlUnicodeToUTF8N( dst
, dstlen
, &reslen
, src
, srclen
* sizeof(WCHAR
) );
2325 if (status
== STATUS_SOME_NOT_MAPPED
)
2327 if (flags
& WC_ERR_INVALID_CHARS
)
2329 SetLastError( ERROR_NO_UNICODE_TRANSLATION
);
2333 else if (!set_ntstatus( status
)) reslen
= 0;
2338 static int wcstombs_sbcs( const CPTABLEINFO
*info
, const WCHAR
*src
, unsigned int srclen
,
2339 char *dst
, unsigned int dstlen
)
2341 const char *table
= info
->WideCharTable
;
2344 if (!dstlen
) return srclen
;
2346 if (dstlen
< srclen
)
2348 /* buffer too small: fill it up to dstlen and return error */
2350 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
2354 while (srclen
>= 16)
2356 dst
[0] = table
[src
[0]];
2357 dst
[1] = table
[src
[1]];
2358 dst
[2] = table
[src
[2]];
2359 dst
[3] = table
[src
[3]];
2360 dst
[4] = table
[src
[4]];
2361 dst
[5] = table
[src
[5]];
2362 dst
[6] = table
[src
[6]];
2363 dst
[7] = table
[src
[7]];
2364 dst
[8] = table
[src
[8]];
2365 dst
[9] = table
[src
[9]];
2366 dst
[10] = table
[src
[10]];
2367 dst
[11] = table
[src
[11]];
2368 dst
[12] = table
[src
[12]];
2369 dst
[13] = table
[src
[13]];
2370 dst
[14] = table
[src
[14]];
2371 dst
[15] = table
[src
[15]];
2377 /* now handle remaining characters */
2382 case 15: dst
[-15] = table
[src
[-15]];
2383 case 14: dst
[-14] = table
[src
[-14]];
2384 case 13: dst
[-13] = table
[src
[-13]];
2385 case 12: dst
[-12] = table
[src
[-12]];
2386 case 11: dst
[-11] = table
[src
[-11]];
2387 case 10: dst
[-10] = table
[src
[-10]];
2388 case 9: dst
[-9] = table
[src
[-9]];
2389 case 8: dst
[-8] = table
[src
[-8]];
2390 case 7: dst
[-7] = table
[src
[-7]];
2391 case 6: dst
[-6] = table
[src
[-6]];
2392 case 5: dst
[-5] = table
[src
[-5]];
2393 case 4: dst
[-4] = table
[src
[-4]];
2394 case 3: dst
[-3] = table
[src
[-3]];
2395 case 2: dst
[-2] = table
[src
[-2]];
2396 case 1: dst
[-1] = table
[src
[-1]];
2403 static int wcstombs_dbcs( const CPTABLEINFO
*info
, const WCHAR
*src
, unsigned int srclen
,
2404 char *dst
, unsigned int dstlen
)
2406 const USHORT
*table
= info
->WideCharTable
;
2411 for (i
= 0; srclen
; src
++, srclen
--, i
++) if (table
[*src
] & 0xff00) i
++;
2415 for (i
= dstlen
; srclen
&& i
; i
--, srclen
--, src
++)
2417 if (table
[*src
] & 0xff00)
2419 if (i
== 1) break; /* do not output a partial char */
2421 *dst
++ = table
[*src
] >> 8;
2423 *dst
++ = (char)table
[*src
];
2427 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
2434 static inline int is_valid_sbcs_mapping( const CPTABLEINFO
*info
, DWORD flags
, unsigned int wch
)
2436 const unsigned char *table
= info
->WideCharTable
;
2438 if (wch
>= 0x10000) return 0;
2439 if ((flags
& WC_NO_BEST_FIT_CHARS
) || table
[wch
] == info
->DefaultChar
)
2440 return (info
->MultiByteTable
[table
[wch
]] == wch
);
2445 static inline int is_valid_dbcs_mapping( const CPTABLEINFO
*info
, DWORD flags
, unsigned int wch
)
2447 const unsigned short *table
= info
->WideCharTable
;
2450 if (wch
>= 0x10000) return 0;
2452 if ((flags
& WC_NO_BEST_FIT_CHARS
) || ch
== info
->DefaultChar
)
2454 if (ch
>> 8) return info
->DBCSOffsets
[info
->DBCSOffsets
[ch
>> 8] + (ch
& 0xff)] == wch
;
2455 return info
->MultiByteTable
[ch
] == wch
;
2461 static int wcstombs_sbcs_slow( const CPTABLEINFO
*info
, DWORD flags
, const WCHAR
*src
, unsigned int srclen
,
2462 char *dst
, unsigned int dstlen
, const char *defchar
, BOOL
*used
)
2464 const char *table
= info
->WideCharTable
;
2465 const char def
= defchar
? *defchar
: (char)info
->DefaultChar
;
2469 unsigned int composed
;
2471 if (!used
) used
= &tmp
; /* avoid checking on every char */
2476 for (i
= 0; srclen
; i
++, src
++, srclen
--)
2479 if ((flags
& WC_COMPOSITECHECK
) && (srclen
> 1) && (composed
= compose_chars( src
[0], src
[1] )))
2481 /* now check if we can use the composed char */
2482 if (is_valid_sbcs_mapping( info
, flags
, composed
))
2484 /* we have a good mapping, use it */
2489 /* no mapping for the composed char, check the other flags */
2490 if (flags
& WC_DEFAULTCHAR
) /* use the default char instead */
2493 src
++; /* skip the non-spacing char */
2497 if (flags
& WC_DISCARDNS
) /* skip the second char of the composition */
2502 /* WC_SEPCHARS is the default */
2504 if (!*used
) *used
= !is_valid_sbcs_mapping( info
, flags
, wch
);
2509 for (i
= dstlen
; srclen
&& i
; dst
++, i
--, src
++, srclen
--)
2512 if ((flags
& WC_COMPOSITECHECK
) && (srclen
> 1) && (composed
= compose_chars( src
[0], src
[1] )))
2514 /* now check if we can use the composed char */
2515 if (is_valid_sbcs_mapping( info
, flags
, composed
))
2517 /* we have a good mapping, use it */
2518 *dst
= table
[composed
];
2523 /* no mapping for the composed char, check the other flags */
2524 if (flags
& WC_DEFAULTCHAR
) /* use the default char instead */
2528 src
++; /* skip the non-spacing char */
2532 if (flags
& WC_DISCARDNS
) /* skip the second char of the composition */
2537 /* WC_SEPCHARS is the default */
2541 if (!is_valid_sbcs_mapping( info
, flags
, wch
))
2549 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
2556 static int wcstombs_dbcs_slow( const CPTABLEINFO
*info
, DWORD flags
, const WCHAR
*src
, unsigned int srclen
,
2557 char *dst
, unsigned int dstlen
, const char *defchar
, BOOL
*used
)
2559 const USHORT
*table
= info
->WideCharTable
;
2560 WCHAR wch
, defchar_value
;
2561 unsigned int composed
;
2566 if (!defchar
[1]) defchar_value
= (unsigned char)defchar
[0];
2567 else defchar_value
= ((unsigned char)defchar
[0] << 8) | (unsigned char)defchar
[1];
2569 if (!used
) used
= &tmp
; /* avoid checking on every char */
2574 if (!defchar
&& !used
&& !(flags
& WC_COMPOSITECHECK
))
2576 for (i
= 0; srclen
; srclen
--, src
++, i
++) if (table
[*src
] & 0xff00) i
++;
2579 for (i
= 0; srclen
; srclen
--, src
++, i
++)
2582 if ((flags
& WC_COMPOSITECHECK
) && (srclen
> 1) && (composed
= compose_chars( src
[0], src
[1] )))
2584 /* now check if we can use the composed char */
2585 if (is_valid_dbcs_mapping( info
, flags
, composed
))
2587 /* we have a good mapping for the composed char, use it */
2588 res
= table
[composed
];
2589 if (res
& 0xff00) i
++;
2594 /* no mapping for the composed char, check the other flags */
2595 if (flags
& WC_DEFAULTCHAR
) /* use the default char instead */
2597 if (defchar_value
& 0xff00) i
++;
2599 src
++; /* skip the non-spacing char */
2603 if (flags
& WC_DISCARDNS
) /* skip the second char of the composition */
2608 /* WC_SEPCHARS is the default */
2612 if (!is_valid_dbcs_mapping( info
, flags
, wch
))
2614 res
= defchar_value
;
2617 if (res
& 0xff00) i
++;
2623 for (i
= dstlen
; srclen
&& i
; i
--, srclen
--, src
++)
2626 if ((flags
& WC_COMPOSITECHECK
) && (srclen
> 1) && (composed
= compose_chars( src
[0], src
[1] )))
2628 /* now check if we can use the composed char */
2629 if (is_valid_dbcs_mapping( info
, flags
, composed
))
2631 /* we have a good mapping for the composed char, use it */
2632 res
= table
[composed
];
2637 /* no mapping for the composed char, check the other flags */
2638 if (flags
& WC_DEFAULTCHAR
) /* use the default char instead */
2640 res
= defchar_value
;
2642 src
++; /* skip the non-spacing char */
2646 if (flags
& WC_DISCARDNS
) /* skip the second char of the composition */
2651 /* WC_SEPCHARS is the default */
2655 if (!is_valid_dbcs_mapping( info
, flags
, wch
))
2657 res
= defchar_value
;
2664 if (i
== 1) break; /* do not output a partial char */
2672 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
2679 static int wcstombs_codepage( UINT codepage
, DWORD flags
, const WCHAR
*src
, int srclen
,
2680 char *dst
, int dstlen
, const char *defchar
, BOOL
*used
)
2682 const CPTABLEINFO
*info
= get_codepage_table( codepage
);
2686 SetLastError( ERROR_INVALID_PARAMETER
);
2689 if (flags
& ~(WC_DISCARDNS
| WC_SEPCHARS
| WC_DEFAULTCHAR
| WC_ERR_INVALID_CHARS
|
2690 WC_COMPOSITECHECK
| WC_NO_BEST_FIT_CHARS
))
2692 SetLastError( ERROR_INVALID_FLAGS
);
2695 if (flags
|| defchar
|| used
)
2697 if (!defchar
) defchar
= (const char *)&info
->DefaultChar
;
2698 if (info
->DBCSOffsets
)
2699 return wcstombs_dbcs_slow( info
, flags
, src
, srclen
, dst
, dstlen
, defchar
, used
);
2701 return wcstombs_sbcs_slow( info
, flags
, src
, srclen
, dst
, dstlen
, defchar
, used
);
2703 if (info
->DBCSOffsets
)
2704 return wcstombs_dbcs( info
, src
, srclen
, dst
, dstlen
);
2706 return wcstombs_sbcs( info
, src
, srclen
, dst
, dstlen
);
2710 static int get_sortkey( DWORD flags
, const WCHAR
*src
, int srclen
, char *dst
, int dstlen
)
2712 WCHAR dummy
[4]; /* no decomposition is larger than 4 chars */
2715 const WCHAR
*src_save
= src
;
2716 int srclen_save
= srclen
;
2718 key_len
[0] = key_len
[1] = key_len
[2] = key_len
[3] = 0;
2719 for (; srclen
; srclen
--, src
++)
2721 unsigned int i
, decomposed_len
= 1;/*wine_decompose(*src, dummy, 4);*/
2725 for (i
= 0; i
< decomposed_len
; i
++)
2727 WCHAR wch
= dummy
[i
];
2730 if ((flags
& NORM_IGNORESYMBOLS
) &&
2731 (get_char_type( CT_CTYPE1
, wch
) & (C1_PUNCT
| C1_SPACE
)))
2734 if (flags
& NORM_IGNORECASE
) wch
= casemap( nls_info
.LowerCaseTable
, wch
);
2736 ce
= collation_table
[collation_table
[collation_table
[wch
>> 8] + ((wch
>> 4) & 0x0f)] + (wch
& 0xf)];
2737 if (ce
!= (unsigned int)-1)
2739 if (ce
>> 16) key_len
[0] += 2;
2740 if ((ce
>> 8) & 0xff) key_len
[1]++;
2741 if ((ce
>> 4) & 0x0f) key_len
[2]++;
2744 if (wch
>> 8) key_len
[3]++;
2751 if (wch
>> 8) key_len
[0]++;
2752 if (wch
& 0xff) key_len
[0]++;
2758 if (!dstlen
) /* compute length */
2759 /* 4 * '\1' + key length */
2760 return key_len
[0] + key_len
[1] + key_len
[2] + key_len
[3] + 4;
2762 if (dstlen
< key_len
[0] + key_len
[1] + key_len
[2] + key_len
[3] + 4 + 1)
2763 return 0; /* overflow */
2766 srclen
= srclen_save
;
2769 key_ptr
[1] = key_ptr
[0] + key_len
[0] + 1;
2770 key_ptr
[2] = key_ptr
[1] + key_len
[1] + 1;
2771 key_ptr
[3] = key_ptr
[2] + key_len
[2] + 1;
2773 for (; srclen
; srclen
--, src
++)
2775 unsigned int i
, decomposed_len
= 1;/*wine_decompose(*src, dummy, 4);*/
2779 for (i
= 0; i
< decomposed_len
; i
++)
2781 WCHAR wch
= dummy
[i
];
2784 if ((flags
& NORM_IGNORESYMBOLS
) &&
2785 (get_char_type( CT_CTYPE1
, wch
) & (C1_PUNCT
| C1_SPACE
)))
2788 if (flags
& NORM_IGNORECASE
) wch
= casemap( nls_info
.LowerCaseTable
, wch
);
2790 ce
= collation_table
[collation_table
[collation_table
[wch
>> 8] + ((wch
>> 4) & 0x0f)] + (wch
& 0xf)];
2791 if (ce
!= (unsigned int)-1)
2794 if ((key
= ce
>> 16))
2796 *key_ptr
[0]++ = key
>> 8;
2797 *key_ptr
[0]++ = key
& 0xff;
2799 /* make key 1 start from 2 */
2800 if ((key
= (ce
>> 8) & 0xff)) *key_ptr
[1]++ = key
+ 1;
2801 /* make key 2 start from 2 */
2802 if ((key
= (ce
>> 4) & 0x0f)) *key_ptr
[2]++ = key
+ 1;
2803 /* key 3 is always a character code */
2806 if (wch
>> 8) *key_ptr
[3]++ = wch
>> 8;
2807 if (wch
& 0xff) *key_ptr
[3]++ = wch
& 0xff;
2812 *key_ptr
[0]++ = 0xff;
2813 *key_ptr
[0]++ = 0xfe;
2814 if (wch
>> 8) *key_ptr
[0]++ = wch
>> 8;
2815 if (wch
& 0xff) *key_ptr
[0]++ = wch
& 0xff;
2826 return key_ptr
[3] - dst
;
2830 /* compose a full-width katakana. return consumed source characters. */
2831 static int compose_katakana( const WCHAR
*src
, int srclen
, WCHAR
*dst
)
2833 static const BYTE katakana_map
[] =
2835 /* */ 0x02, 0x0c, 0x0d, 0x01, 0xfb, 0xf2, 0xa1, /* U+FF61- */
2836 0xa3, 0xa5, 0xa7, 0xa9, 0xe3, 0xe5, 0xe7, 0xc3, /* U+FF68- */
2837 0xfc, 0xa2, 0xa4, 0xa6, 0xa8, 0xaa, 0xab, 0xad, /* U+FF70- */
2838 0xaf, 0xb1, 0xb3, 0xb5, 0xb7, 0xb9, 0xbb, 0xbd, /* U+FF78- */
2839 0xbf, 0xc1, 0xc4, 0xc6, 0xc8, 0xca, 0xcb, 0xcc, /* U+FF80- */
2840 0xcd, 0xce, 0xcf, 0xd2, 0xd5, 0xd8, 0xdb, 0xde, /* U+FF88- */
2841 0xdf, 0xe0, 0xe1, 0xe2, 0xe4, 0xe6, 0xe8, 0xe9, /* U+FF90- */
2842 0xea, 0xeb, 0xec, 0xed, 0xef, 0xf3, 0x99, 0x9a, /* U+FF98- */
2847 if (!dst
) dst
= &dummy
;
2861 shift
= *src
- 0xff61;
2862 if (shift
< 0 || shift
>= ARRAY_SIZE( katakana_map
)) return 0;
2863 *dst
= katakana_map
[shift
] | 0x3000;
2867 if (srclen
<= 1) return 1;
2871 case 0xff9e: /* datakuten (voiced sound) */
2872 if ((*src
>= 0xff76 && *src
<= 0xff84) || (*src
>= 0xff8a && *src
<= 0xff8e) || *src
== 0x30fd)
2874 else if (*src
== 0xff73)
2875 *dst
= 0x30f4; /* KATAKANA LETTER VU */
2876 else if (*src
== 0xff9c)
2877 *dst
= 0x30f7; /* KATAKANA LETTER VA */
2878 else if (*src
== 0x30f0)
2879 *dst
= 0x30f8; /* KATAKANA LETTER VI */
2880 else if (*src
== 0x30f1)
2881 *dst
= 0x30f9; /* KATAKANA LETTER VE */
2882 else if (*src
== 0xff66)
2883 *dst
= 0x30fa; /* KATAKANA LETTER VO */
2887 case 0xff9f: /* handakuten (semi-voiced sound) */
2888 if (*src
>= 0xff8a && *src
<= 0xff8e)
2899 /* map one or two half-width characters to one full-width character */
2900 static int map_to_fullwidth( const WCHAR
*src
, int srclen
, WCHAR
*dst
)
2904 if (*src
<= '~' && *src
> ' ' && *src
!= '\\')
2905 *dst
= *src
- 0x20 + 0xff00;
2906 else if (*src
== ' ')
2908 else if (*src
<= 0x00af && *src
>= 0x00a2)
2910 static const BYTE misc_symbols_table
[] =
2912 0xe0, 0xe1, 0x00, 0xe5, 0xe4, 0x00, 0x00, /* U+00A2- */
2913 0x00, 0x00, 0x00, 0xe2, 0x00, 0x00, 0xe3 /* U+00A9- */
2915 if (misc_symbols_table
[*src
- 0x00a2])
2916 *dst
= misc_symbols_table
[*src
- 0x00a2] | 0xff00;
2920 else if (*src
== 0x20a9) /* WON SIGN */
2922 else if ((n
= compose_katakana(src
, srclen
, dst
)) > 0)
2924 else if (*src
>= 0xffa0 && *src
<= 0xffdc)
2926 static const BYTE hangul_mapping_table
[] =
2928 0x64, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* U+FFA0- */
2929 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* U+FFA8- */
2930 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* U+FFB0- */
2931 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x00, /* U+FFB8- */
2932 0x00, 0x00, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, /* U+FFC0- */
2933 0x00, 0x00, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, /* U+FFC8- */
2934 0x00, 0x00, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 0x60, /* U+FFD0- */
2935 0x00, 0x00, 0x61, 0x62, 0x63 /* U+FFD8- */
2938 if (hangul_mapping_table
[*src
- 0xffa0])
2939 *dst
= hangul_mapping_table
[*src
- 0xffa0] | 0x3100;
2949 /* decompose a full-width katakana character into one or two half-width characters. */
2950 static int decompose_katakana( WCHAR c
, WCHAR
*dst
, int dstlen
)
2952 static const BYTE katakana_map
[] =
2954 /* */ 0x9e, 0x9f, 0x9e, 0x9f, 0x00, 0x00, 0x00, /* U+3099- */
2955 0x00, 0x67, 0x71, 0x68, 0x72, 0x69, 0x73, 0x6a, /* U+30a1- */
2956 0x74, 0x6b, 0x75, 0x76, 0x01, 0x77, 0x01, 0x78, /* U+30a8- */
2957 0x01, 0x79, 0x01, 0x7a, 0x01, 0x7b, 0x01, 0x7c, /* U+30b0- */
2958 0x01, 0x7d, 0x01, 0x7e, 0x01, 0x7f, 0x01, 0x80, /* U+30b8- */
2959 0x01, 0x81, 0x01, 0x6f, 0x82, 0x01, 0x83, 0x01, /* U+30c0- */
2960 0x84, 0x01, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, /* U+30c8- */
2961 0x01, 0x02, 0x8b, 0x01, 0x02, 0x8c, 0x01, 0x02, /* U+30d0- */
2962 0x8d, 0x01, 0x02, 0x8e, 0x01, 0x02, 0x8f, 0x90, /* U+30d8- */
2963 0x91, 0x92, 0x93, 0x6c, 0x94, 0x6d, 0x95, 0x6e, /* U+30e0- */
2964 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x00, 0x9c, /* U+30e8- */
2965 0x00, 0x00, 0x66, 0x9d, 0x4e, 0x00, 0x00, 0x08, /* U+30f0- */
2966 0x58, 0x58, 0x08, 0x65, 0x70, 0x00, 0x51 /* U+30f8- */
2968 int len
= 0, shift
= c
- 0x3099;
2971 if (shift
< 0 || shift
>= ARRAY_SIZE( katakana_map
)) return 0;
2973 k
= katakana_map
[shift
];
2976 if (dstlen
> 0) *dst
= c
;
2981 if (dstlen
> 0) *dst
= k
| 0xff00;
2988 dst
[0] = (k
> 0x50) ? (c
- (k
& 0xf)) : (katakana_map
[shift
- k
] | 0xff00);
2989 dst
[1] = (k
== 2) ? 0xff9f : 0xff9e;
2996 /* map single full-width character to single or double half-width characters. */
2997 static int map_to_halfwidth( WCHAR c
, WCHAR
*dst
, int dstlen
)
2999 int n
= decompose_katakana( c
, dst
, dstlen
);
3000 if (n
> 0) return n
;
3004 else if (c
== 0x3001)
3006 else if (c
== 0x3002)
3008 else if (c
== 0x300c || c
== 0x300d)
3009 *dst
= (c
- 0x300c) + 0xff62;
3010 else if (c
>= 0x3131 && c
<= 0x3163)
3012 *dst
= c
- 0x3131 + 0xffa1;
3013 if (*dst
>= 0xffbf) *dst
+= 3;
3014 if (*dst
>= 0xffc8) *dst
+= 2;
3015 if (*dst
>= 0xffd0) *dst
+= 2;
3016 if (*dst
>= 0xffd8) *dst
+= 2;
3018 else if (c
== 0x3164)
3020 else if (c
== 0x2019)
3022 else if (c
== 0x201d)
3024 else if (c
> 0xff00 && c
< 0xff5f && c
!= 0xff3c)
3025 *dst
= c
- 0xff00 + 0x20;
3026 else if (c
>= 0xffe0 && c
<= 0xffe6)
3028 static const WCHAR misc_symbol_map
[] = { 0x00a2, 0x00a3, 0x00ac, 0x00af, 0x00a6, 0x00a5, 0x20a9 };
3029 *dst
= misc_symbol_map
[c
- 0xffe0];
3038 /* 32-bit collation element table format:
3039 * unicode weight - high 16 bit, diacritic weight - high 8 bit of low 16 bit,
3040 * case weight - high 4 bit of low 8 bit.
3043 enum weight
{ UNICODE_WEIGHT
, DIACRITIC_WEIGHT
, CASE_WEIGHT
};
3045 static unsigned int get_weight( WCHAR ch
, enum weight type
)
3049 ret
= collation_table
[collation_table
[collation_table
[ch
>> 8] + ((ch
>> 4) & 0x0f)] + (ch
& 0xf)];
3050 if (ret
== ~0u) return ch
;
3054 case UNICODE_WEIGHT
: return ret
>> 16;
3055 case DIACRITIC_WEIGHT
: return (ret
>> 8) & 0xff;
3056 case CASE_WEIGHT
: return (ret
>> 4) & 0x0f;
3062 static void inc_str_pos( const WCHAR
**str
, int *len
, unsigned int *dpos
, unsigned int *dlen
)
3074 static int compare_weights(int flags
, const WCHAR
*str1
, int len1
,
3075 const WCHAR
*str2
, int len2
, enum weight type
)
3077 unsigned int ce1
, ce2
, dpos1
= 0, dpos2
= 0, dlen1
= 0, dlen2
= 0;
3078 const WCHAR
*dstr1
= NULL
, *dstr2
= NULL
;
3080 while (len1
> 0 && len2
> 0)
3082 if (!dlen1
&& !(dstr1
= get_decomposition( *str1
, &dlen1
))) dstr1
= str1
;
3083 if (!dlen2
&& !(dstr2
= get_decomposition( *str2
, &dlen2
))) dstr2
= str2
;
3085 if (flags
& NORM_IGNORESYMBOLS
)
3088 /* FIXME: not tested */
3089 if (get_char_type( CT_CTYPE1
, dstr1
[dpos1
] ) & (C1_PUNCT
| C1_SPACE
))
3091 inc_str_pos( &str1
, &len1
, &dpos1
, &dlen1
);
3094 if (get_char_type( CT_CTYPE1
, dstr2
[dpos2
] ) & (C1_PUNCT
| C1_SPACE
))
3096 inc_str_pos( &str2
, &len2
, &dpos2
, &dlen2
);
3102 /* hyphen and apostrophe are treated differently depending on
3103 * whether SORT_STRINGSORT specified or not
3105 if (type
== UNICODE_WEIGHT
&& !(flags
& SORT_STRINGSORT
))
3107 if (dstr1
[dpos1
] == '-' || dstr1
[dpos1
] == '\'')
3109 if (dstr2
[dpos2
] != '-' && dstr2
[dpos2
] != '\'')
3111 inc_str_pos( &str1
, &len1
, &dpos1
, &dlen1
);
3115 else if (dstr2
[dpos2
] == '-' || dstr2
[dpos2
] == '\'')
3117 inc_str_pos( &str2
, &len2
, &dpos2
, &dlen2
);
3122 ce1
= get_weight( dstr1
[dpos1
], type
);
3125 inc_str_pos( &str1
, &len1
, &dpos1
, &dlen1
);
3128 ce2
= get_weight( dstr2
[dpos2
], type
);
3131 inc_str_pos( &str2
, &len2
, &dpos2
, &dlen2
);
3135 if (ce1
- ce2
) return ce1
- ce2
;
3137 inc_str_pos( &str1
, &len1
, &dpos1
, &dlen1
);
3138 inc_str_pos( &str2
, &len2
, &dpos2
, &dlen2
);
3142 if (!dlen1
&& !(dstr1
= get_decomposition( *str1
, &dlen1
))) dstr1
= str1
;
3143 ce1
= get_weight( dstr1
[dpos1
], type
);
3145 inc_str_pos( &str1
, &len1
, &dpos1
, &dlen1
);
3149 if (!dlen2
&& !(dstr2
= get_decomposition( *str2
, &dlen2
))) dstr2
= str2
;
3150 ce2
= get_weight( dstr2
[dpos2
], type
);
3152 inc_str_pos( &str2
, &len2
, &dpos2
, &dlen2
);
3158 static const struct geoinfo
*get_geoinfo_ptr( GEOID geoid
)
3160 int min
= 0, max
= ARRAY_SIZE( geoinfodata
)-1;
3164 int n
= (min
+ max
)/2;
3165 const struct geoinfo
*ptr
= &geoinfodata
[n
];
3166 if (geoid
== ptr
->id
) /* we don't need empty entries */
3167 return *ptr
->iso2W
? ptr
: NULL
;
3168 if (ptr
->id
> geoid
) max
= n
-1;
3175 static int compare_tzdate( const TIME_FIELDS
*tf
, const SYSTEMTIME
*compare
)
3177 static const int month_lengths
[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
3178 int first
, last
, limit
, dayinsecs
;
3180 if (tf
->Month
< compare
->wMonth
) return -1; /* We are in a month before the date limit. */
3181 if (tf
->Month
> compare
->wMonth
) return 1; /* We are in a month after the date limit. */
3183 /* if year is 0 then date is in day-of-week format, otherwise
3184 * it's absolute date.
3186 if (!compare
->wYear
)
3188 /* wDay is interpreted as number of the week in the month
3189 * 5 means: the last week in the month */
3190 /* calculate the day of the first DayOfWeek in the month */
3191 first
= (6 + compare
->wDayOfWeek
- tf
->Weekday
+ tf
->Day
) % 7 + 1;
3192 /* check needed for the 5th weekday of the month */
3193 last
= month_lengths
[tf
->Month
- 1] +
3194 (tf
->Month
== 2 && (!(tf
->Year
% 4) && (tf
->Year
% 100 || !(tf
->Year
% 400))));
3195 limit
= first
+ 7 * (compare
->wDay
- 1);
3196 if (limit
> last
) limit
-= 7;
3198 else limit
= compare
->wDay
;
3200 limit
= ((limit
* 24 + compare
->wHour
) * 60 + compare
->wMinute
) * 60;
3201 dayinsecs
= ((tf
->Day
* 24 + tf
->Hour
) * 60 + tf
->Minute
) * 60 + tf
->Second
;
3202 return dayinsecs
- limit
;
3206 static DWORD
get_timezone_id( const TIME_ZONE_INFORMATION
*info
, LARGE_INTEGER time
, BOOL is_local
)
3209 BOOL before_standard_date
, after_daylight_date
;
3213 if (!info
->DaylightDate
.wMonth
) return TIME_ZONE_ID_UNKNOWN
;
3215 /* if year is 0 then date is in day-of-week format, otherwise it's absolute date */
3216 if (info
->StandardDate
.wMonth
== 0 ||
3217 (info
->StandardDate
.wYear
== 0 &&
3218 (info
->StandardDate
.wDay
< 1 || info
->StandardDate
.wDay
> 5 ||
3219 info
->DaylightDate
.wDay
< 1 || info
->DaylightDate
.wDay
> 5)))
3221 SetLastError( ERROR_INVALID_PARAMETER
);
3222 return TIME_ZONE_ID_INVALID
;
3225 if (!is_local
) time
.QuadPart
-= info
->Bias
* (LONGLONG
)600000000;
3226 RtlTimeToTimeFields( &time
, &tf
);
3230 t2
.QuadPart
= time
.QuadPart
- info
->DaylightBias
* (LONGLONG
)600000000;
3231 RtlTimeToTimeFields( &t2
, &tf
);
3233 if (tf
.Year
== year
)
3234 before_standard_date
= compare_tzdate( &tf
, &info
->StandardDate
) < 0;
3236 before_standard_date
= tf
.Year
< year
;
3240 t2
.QuadPart
= time
.QuadPart
- info
->StandardBias
* (LONGLONG
)600000000;
3241 RtlTimeToTimeFields( &t2
, &tf
);
3243 if (tf
.Year
== year
)
3244 after_daylight_date
= compare_tzdate( &tf
, &info
->DaylightDate
) >= 0;
3246 after_daylight_date
= tf
.Year
> year
;
3248 if (info
->DaylightDate
.wMonth
< info
->StandardDate
.wMonth
) /* Northern hemisphere */
3250 if (before_standard_date
&& after_daylight_date
) return TIME_ZONE_ID_DAYLIGHT
;
3252 else /* Down south */
3254 if (before_standard_date
|| after_daylight_date
) return TIME_ZONE_ID_DAYLIGHT
;
3256 return TIME_ZONE_ID_STANDARD
;
3260 /* Note: the Internal_ functions are not documented. The number of parameters
3261 * should be correct, but their exact meaning may not.
3264 /******************************************************************************
3265 * Internal_EnumCalendarInfo (kernelbase.@)
3267 BOOL WINAPI DECLSPEC_HOTPATCH
Internal_EnumCalendarInfo( CALINFO_ENUMPROCW proc
, LCID lcid
, CALID id
,
3268 CALTYPE type
, BOOL unicode
, BOOL ex
,
3269 BOOL exex
, LPARAM lparam
)
3272 CALID calendars
[2] = { id
};
3277 SetLastError( ERROR_INVALID_PARAMETER
);
3281 if (id
== ENUM_ALL_CALENDARS
)
3283 if (!GetLocaleInfoW( lcid
, LOCALE_ICALENDARTYPE
| LOCALE_RETURN_NUMBER
,
3284 (WCHAR
*)&calendars
[0], sizeof(calendars
[0]) / sizeof(WCHAR
) )) return FALSE
;
3285 if (!GetLocaleInfoW( lcid
, LOCALE_IOPTIONALCALENDAR
| LOCALE_RETURN_NUMBER
,
3286 (WCHAR
*)&calendars
[1], sizeof(calendars
[1]) / sizeof(WCHAR
) )) calendars
[1] = 0;
3289 for (i
= 0; i
< ARRAY_SIZE(calendars
) && calendars
[i
]; i
++)
3292 if (type
& CAL_RETURN_NUMBER
)
3293 ret
= GetCalendarInfoW( lcid
, id
, type
, NULL
, 0, (LPDWORD
)buffer
);
3295 ret
= GetCalendarInfoW( lcid
, id
, type
, buffer
, ARRAY_SIZE(buffer
), NULL
);
3299 ret
= GetCalendarInfoW( lcid
, id
, type
, bufW
, ARRAY_SIZE(bufW
), NULL
);
3300 if (ret
) WideCharToMultiByte( CP_ACP
, 0, bufW
, -1, (char *)buffer
, sizeof(buffer
), NULL
, NULL
);
3305 if (exex
) ret
= ((CALINFO_ENUMPROCEXEX
)proc
)( buffer
, id
, NULL
, lparam
);
3306 else if (ex
) ret
= ((CALINFO_ENUMPROCEXW
)proc
)( buffer
, id
);
3307 else ret
= proc( buffer
);
3315 /**************************************************************************
3316 * Internal_EnumDateFormats (kernelbase.@)
3318 BOOL WINAPI DECLSPEC_HOTPATCH
Internal_EnumDateFormats( DATEFMT_ENUMPROCW proc
, LCID lcid
, DWORD flags
,
3319 BOOL unicode
, BOOL ex
, BOOL exex
, LPARAM lparam
)
3328 SetLastError( ERROR_INVALID_PARAMETER
);
3331 if (!GetLocaleInfoW( lcid
, LOCALE_ICALENDARTYPE
|LOCALE_RETURN_NUMBER
,
3332 (LPWSTR
)&cal_id
, sizeof(cal_id
)/sizeof(WCHAR
) ))
3335 switch (flags
& ~LOCALE_USE_CP_ACP
)
3338 case DATE_SHORTDATE
:
3339 lctype
= LOCALE_SSHORTDATE
;
3342 lctype
= LOCALE_SLONGDATE
;
3344 case DATE_YEARMONTH
:
3345 lctype
= LOCALE_SYEARMONTH
;
3348 FIXME( "unknown date format 0x%08lx\n", flags
);
3349 SetLastError( ERROR_INVALID_PARAMETER
);
3353 lctype
|= flags
& LOCALE_USE_CP_ACP
;
3355 ret
= GetLocaleInfoW( lcid
, lctype
, buffer
, ARRAY_SIZE(buffer
) );
3357 ret
= GetLocaleInfoA( lcid
, lctype
, (char *)buffer
, sizeof(buffer
) );
3361 if (exex
) ((DATEFMT_ENUMPROCEXEX
)proc
)( buffer
, cal_id
, lparam
);
3362 else if (ex
) ((DATEFMT_ENUMPROCEXW
)proc
)( buffer
, cal_id
);
3363 else proc( buffer
);
3369 /******************************************************************************
3370 * Internal_EnumLanguageGroupLocales (kernelbase.@)
3372 BOOL WINAPI DECLSPEC_HOTPATCH
Internal_EnumLanguageGroupLocales( LANGGROUPLOCALE_ENUMPROCW proc
, LGRPID id
,
3373 DWORD flags
, LONG_PTR param
, BOOL unicode
)
3375 WCHAR name
[10], value
[10];
3376 DWORD name_len
, value_len
, type
, index
= 0, alt
= 0;
3380 if (!proc
|| id
< LGRPID_WESTERN_EUROPE
|| id
> LGRPID_ARMENIAN
)
3382 SetLastError( ERROR_INVALID_PARAMETER
);
3386 if (RegOpenKeyExW( nls_key
, L
"Locale", 0, KEY_READ
, &key
)) return FALSE
;
3387 if (RegOpenKeyExW( key
, L
"Alternate Sorts", 0, KEY_READ
, &altkey
)) altkey
= 0;
3391 name_len
= ARRAY_SIZE(name
);
3392 value_len
= sizeof(value
);
3393 if (RegEnumValueW( alt
? altkey
: key
, index
++, name
, &name_len
, NULL
,
3394 &type
, (BYTE
*)value
, &value_len
))
3400 if (type
!= REG_SZ
) continue;
3401 if (id
!= wcstoul( value
, NULL
, 16 )) continue;
3402 lcid
= wcstoul( name
, NULL
, 16 );
3406 WideCharToMultiByte( CP_ACP
, 0, name
, -1, nameA
, sizeof(nameA
), NULL
, NULL
);
3407 if (!((LANGGROUPLOCALE_ENUMPROCA
)proc
)( id
, lcid
, nameA
, param
)) break;
3409 else if (!proc( id
, lcid
, name
, param
)) break;
3411 RegCloseKey( altkey
);
3417 /***********************************************************************
3418 * Internal_EnumSystemCodePages (kernelbase.@)
3420 BOOL WINAPI DECLSPEC_HOTPATCH
Internal_EnumSystemCodePages( CODEPAGE_ENUMPROCW proc
, DWORD flags
,
3424 DWORD name_len
, type
, index
= 0;
3427 if (RegOpenKeyExW( nls_key
, L
"Codepage", 0, KEY_READ
, &key
)) return FALSE
;
3431 name_len
= ARRAY_SIZE(name
);
3432 if (RegEnumValueW( key
, index
++, name
, &name_len
, NULL
, &type
, NULL
, NULL
)) break;
3433 if (type
!= REG_SZ
) continue;
3434 if (!wcstoul( name
, NULL
, 10 )) continue;
3438 WideCharToMultiByte( CP_ACP
, 0, name
, -1, nameA
, sizeof(nameA
), NULL
, NULL
);
3439 if (!((CODEPAGE_ENUMPROCA
)proc
)( nameA
)) break;
3441 else if (!proc( name
)) break;
3448 /******************************************************************************
3449 * Internal_EnumSystemLanguageGroups (kernelbase.@)
3451 BOOL WINAPI DECLSPEC_HOTPATCH
Internal_EnumSystemLanguageGroups( LANGUAGEGROUP_ENUMPROCW proc
,
3452 DWORD flags
, LONG_PTR param
, BOOL unicode
)
3454 WCHAR name
[10], value
[10], descr
[80];
3455 DWORD name_len
, value_len
, type
, index
= 0;
3461 SetLastError( ERROR_INVALID_PARAMETER
);
3468 flags
= LGRPID_INSTALLED
;
3470 case LGRPID_INSTALLED
:
3471 case LGRPID_SUPPORTED
:
3474 SetLastError( ERROR_INVALID_FLAGS
);
3478 if (RegOpenKeyExW( nls_key
, L
"Language Groups", 0, KEY_READ
, &key
)) return FALSE
;
3482 name_len
= ARRAY_SIZE(name
);
3483 value_len
= sizeof(value
);
3484 if (RegEnumValueW( key
, index
++, name
, &name_len
, NULL
, &type
, (BYTE
*)value
, &value_len
)) break;
3485 if (type
!= REG_SZ
) continue;
3487 id
= wcstoul( name
, NULL
, 16 );
3489 if (!(flags
& LGRPID_SUPPORTED
) && !wcstoul( value
, NULL
, 10 )) continue;
3490 if (!LoadStringW( kernel32_handle
, 0x2000 + id
, descr
, ARRAY_SIZE(descr
) )) descr
[0] = 0;
3491 TRACE( "%p: %lu %s %s %lx %Ix\n", proc
, id
, debugstr_w(name
), debugstr_w(descr
), flags
, param
);
3494 char nameA
[10], descrA
[80];
3495 WideCharToMultiByte( CP_ACP
, 0, name
, -1, nameA
, sizeof(nameA
), NULL
, NULL
);
3496 WideCharToMultiByte( CP_ACP
, 0, descr
, -1, descrA
, sizeof(descrA
), NULL
, NULL
);
3497 if (!((LANGUAGEGROUP_ENUMPROCA
)proc
)( id
, nameA
, descrA
, flags
, param
)) break;
3499 else if (!proc( id
, name
, descr
, flags
, param
)) break;
3506 /**************************************************************************
3507 * Internal_EnumTimeFormats (kernelbase.@)
3509 BOOL WINAPI DECLSPEC_HOTPATCH
Internal_EnumTimeFormats( TIMEFMT_ENUMPROCW proc
, LCID lcid
, DWORD flags
,
3510 BOOL unicode
, BOOL ex
, LPARAM lparam
)
3518 SetLastError( ERROR_INVALID_PARAMETER
);
3521 switch (flags
& ~LOCALE_USE_CP_ACP
)
3524 lctype
= LOCALE_STIMEFORMAT
;
3526 case TIME_NOSECONDS
:
3527 lctype
= LOCALE_SSHORTTIME
;
3530 FIXME( "Unknown time format %lx\n", flags
);
3531 SetLastError( ERROR_INVALID_PARAMETER
);
3535 lctype
|= flags
& LOCALE_USE_CP_ACP
;
3537 ret
= GetLocaleInfoW( lcid
, lctype
, buffer
, ARRAY_SIZE(buffer
) );
3539 ret
= GetLocaleInfoA( lcid
, lctype
, (char *)buffer
, sizeof(buffer
) );
3543 if (ex
) ((TIMEFMT_ENUMPROCEX
)proc
)( buffer
, lparam
);
3544 else proc( buffer
);
3550 /******************************************************************************
3551 * Internal_EnumUILanguages (kernelbase.@)
3553 BOOL WINAPI DECLSPEC_HOTPATCH
Internal_EnumUILanguages( UILANGUAGE_ENUMPROCW proc
, DWORD flags
,
3554 LONG_PTR param
, BOOL unicode
)
3556 WCHAR nameW
[LOCALE_NAME_MAX_LENGTH
];
3557 char nameA
[LOCALE_NAME_MAX_LENGTH
];
3562 SetLastError( ERROR_INVALID_PARAMETER
);
3565 if (flags
& ~(MUI_LANGUAGE_ID
| MUI_LANGUAGE_NAME
))
3567 SetLastError( ERROR_INVALID_FLAGS
);
3571 for (i
= 0; i
< locale_table
->nb_lcnames
; i
++)
3573 if (!lcnames_index
[i
].name
) continue; /* skip invariant locale */
3574 if (lcnames_index
[i
].id
& 0x80000000) continue; /* skip aliases */
3575 if (!get_locale_data( lcnames_index
[i
].idx
)->inotneutral
) continue; /* skip neutral locales */
3576 if (!SORTIDFROMLCID( lcnames_index
[i
].id
) != !(flags
& LCID_ALTERNATE_SORTS
))
3577 continue; /* skip alternate sorts */
3578 if (flags
& MUI_LANGUAGE_NAME
)
3580 const WCHAR
*str
= locale_strings
+ lcnames_index
[i
].name
;
3584 memcpy( nameW
, str
+ 1, (*str
+ 1) * sizeof(WCHAR
) );
3585 if (!proc( nameW
, param
)) break;
3589 WideCharToMultiByte( CP_ACP
, 0, str
+ 1, -1, nameA
, sizeof(nameA
), NULL
, NULL
);
3590 if (!((UILANGUAGE_ENUMPROCA
)proc
)( nameA
, param
)) break;
3595 if (lcnames_index
[i
].id
== LOCALE_CUSTOM_UNSPECIFIED
) continue; /* skip locales with no lcid */
3598 swprintf( nameW
, ARRAY_SIZE(nameW
), L
"%04lx", lcnames_index
[i
].id
);
3599 if (!proc( nameW
, param
)) break;
3603 sprintf( nameA
, "%04x", lcnames_index
[i
].id
);
3604 if (!((UILANGUAGE_ENUMPROCA
)proc
)( nameA
, param
)) break;
3612 /******************************************************************************
3613 * CompareStringEx (kernelbase.@)
3615 INT WINAPI
CompareStringEx( const WCHAR
*locale
, DWORD flags
, const WCHAR
*str1
, int len1
,
3616 const WCHAR
*str2
, int len2
, NLSVERSIONINFO
*version
,
3617 void *reserved
, LPARAM handle
)
3619 DWORD supported_flags
= NORM_IGNORECASE
| NORM_IGNORENONSPACE
| NORM_IGNORESYMBOLS
| SORT_STRINGSORT
|
3620 NORM_IGNOREKANATYPE
| NORM_IGNOREWIDTH
| LOCALE_USE_CP_ACP
;
3621 DWORD semistub_flags
= NORM_LINGUISTIC_CASING
| LINGUISTIC_IGNORECASE
| LINGUISTIC_IGNOREDIACRITIC
|
3622 SORT_DIGITSASNUMBERS
| 0x10000000;
3623 /* 0x10000000 is related to diacritics in Arabic, Japanese, and Hebrew */
3627 if (version
) FIXME( "unexpected version parameter\n" );
3628 if (reserved
) FIXME( "unexpected reserved value\n" );
3629 if (handle
) FIXME( "unexpected handle\n" );
3633 SetLastError( ERROR_INVALID_PARAMETER
);
3637 if (flags
& ~(supported_flags
| semistub_flags
))
3639 SetLastError( ERROR_INVALID_FLAGS
);
3643 if (flags
& semistub_flags
)
3645 if (!once
++) FIXME( "semi-stub behavior for flag(s) 0x%lx\n", flags
& semistub_flags
);
3648 if (len1
< 0) len1
= lstrlenW(str1
);
3649 if (len2
< 0) len2
= lstrlenW(str2
);
3651 ret
= compare_weights( flags
, str1
, len1
, str2
, len2
, UNICODE_WEIGHT
);
3654 if (!(flags
& NORM_IGNORENONSPACE
))
3655 ret
= compare_weights( flags
, str1
, len1
, str2
, len2
, DIACRITIC_WEIGHT
);
3656 if (!ret
&& !(flags
& NORM_IGNORECASE
))
3657 ret
= compare_weights( flags
, str1
, len1
, str2
, len2
, CASE_WEIGHT
);
3659 if (!ret
) return CSTR_EQUAL
;
3660 return (ret
< 0) ? CSTR_LESS_THAN
: CSTR_GREATER_THAN
;
3664 /******************************************************************************
3665 * CompareStringA (kernelbase.@)
3667 INT WINAPI DECLSPEC_HOTPATCH
CompareStringA( LCID lcid
, DWORD flags
, const char *str1
, int len1
,
3668 const char *str2
, int len2
)
3670 WCHAR
*buf1W
= NtCurrentTeb()->StaticUnicodeBuffer
;
3671 WCHAR
*buf2W
= buf1W
+ 130;
3672 LPWSTR str1W
, str2W
;
3673 INT len1W
= 0, len2W
= 0, ret
;
3674 UINT locale_cp
= CP_ACP
;
3678 SetLastError( ERROR_INVALID_PARAMETER
);
3682 if (flags
& SORT_DIGITSASNUMBERS
)
3684 SetLastError( ERROR_INVALID_FLAGS
);
3688 if (len1
< 0) len1
= strlen(str1
);
3689 if (len2
< 0) len2
= strlen(str2
);
3691 locale_cp
= get_lcid_codepage( lcid
, flags
);
3694 if (len1
<= 130) len1W
= MultiByteToWideChar( locale_cp
, 0, str1
, len1
, buf1W
, 130 );
3695 if (len1W
) str1W
= buf1W
;
3698 len1W
= MultiByteToWideChar( locale_cp
, 0, str1
, len1
, NULL
, 0 );
3699 str1W
= HeapAlloc( GetProcessHeap(), 0, len1W
* sizeof(WCHAR
) );
3702 SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
3705 MultiByteToWideChar( locale_cp
, 0, str1
, len1
, str1W
, len1W
);
3716 if (len2
<= 130) len2W
= MultiByteToWideChar( locale_cp
, 0, str2
, len2
, buf2W
, 130 );
3717 if (len2W
) str2W
= buf2W
;
3720 len2W
= MultiByteToWideChar( locale_cp
, 0, str2
, len2
, NULL
, 0 );
3721 str2W
= HeapAlloc( GetProcessHeap(), 0, len2W
* sizeof(WCHAR
) );
3724 if (str1W
!= buf1W
) HeapFree( GetProcessHeap(), 0, str1W
);
3725 SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
3728 MultiByteToWideChar( locale_cp
, 0, str2
, len2
, str2W
, len2W
);
3737 ret
= CompareStringW( lcid
, flags
, str1W
, len1W
, str2W
, len2W
);
3739 if (str1W
!= buf1W
) HeapFree( GetProcessHeap(), 0, str1W
);
3740 if (str2W
!= buf2W
) HeapFree( GetProcessHeap(), 0, str2W
);
3745 /******************************************************************************
3746 * CompareStringW (kernelbase.@)
3748 INT WINAPI DECLSPEC_HOTPATCH
CompareStringW( LCID lcid
, DWORD flags
, const WCHAR
*str1
, int len1
,
3749 const WCHAR
*str2
, int len2
)
3751 return CompareStringEx( NULL
, flags
, str1
, len1
, str2
, len2
, NULL
, NULL
, 0 );
3755 /******************************************************************************
3756 * CompareStringOrdinal (kernelbase.@)
3758 INT WINAPI DECLSPEC_HOTPATCH
CompareStringOrdinal( const WCHAR
*str1
, INT len1
,
3759 const WCHAR
*str2
, INT len2
, BOOL ignore_case
)
3765 SetLastError( ERROR_INVALID_PARAMETER
);
3768 if (len1
< 0) len1
= lstrlenW( str1
);
3769 if (len2
< 0) len2
= lstrlenW( str2
);
3771 ret
= RtlCompareUnicodeStrings( str1
, len1
, str2
, len2
, ignore_case
);
3772 if (ret
< 0) return CSTR_LESS_THAN
;
3773 if (ret
> 0) return CSTR_GREATER_THAN
;
3778 /******************************************************************************
3779 * ConvertDefaultLocale (kernelbase.@)
3781 LCID WINAPI DECLSPEC_HOTPATCH
ConvertDefaultLocale( LCID lcid
)
3783 get_locale_by_id( &lcid
, 0 );
3788 /******************************************************************************
3789 * EnumCalendarInfoW (kernelbase.@)
3791 BOOL WINAPI DECLSPEC_HOTPATCH
EnumCalendarInfoW( CALINFO_ENUMPROCW proc
, LCID lcid
,
3792 CALID id
, CALTYPE type
)
3794 return Internal_EnumCalendarInfo( proc
, lcid
, id
, type
, TRUE
, FALSE
, FALSE
, 0 );
3798 /******************************************************************************
3799 * EnumCalendarInfoExW (kernelbase.@)
3801 BOOL WINAPI DECLSPEC_HOTPATCH
EnumCalendarInfoExW( CALINFO_ENUMPROCEXW proc
, LCID lcid
,
3802 CALID id
, CALTYPE type
)
3804 return Internal_EnumCalendarInfo( (CALINFO_ENUMPROCW
)proc
, lcid
, id
, type
, TRUE
, TRUE
, FALSE
, 0 );
3807 /******************************************************************************
3808 * EnumCalendarInfoExEx (kernelbase.@)
3810 BOOL WINAPI DECLSPEC_HOTPATCH
EnumCalendarInfoExEx( CALINFO_ENUMPROCEXEX proc
, LPCWSTR locale
, CALID id
,
3811 LPCWSTR reserved
, CALTYPE type
, LPARAM lparam
)
3813 LCID lcid
= LocaleNameToLCID( locale
, 0 );
3814 return Internal_EnumCalendarInfo( (CALINFO_ENUMPROCW
)proc
, lcid
, id
, type
, TRUE
, TRUE
, TRUE
, lparam
);
3818 /**************************************************************************
3819 * EnumDateFormatsW (kernelbase.@)
3821 BOOL WINAPI DECLSPEC_HOTPATCH
EnumDateFormatsW( DATEFMT_ENUMPROCW proc
, LCID lcid
, DWORD flags
)
3823 return Internal_EnumDateFormats( proc
, lcid
, flags
, TRUE
, FALSE
, FALSE
, 0 );
3827 /**************************************************************************
3828 * EnumDateFormatsExW (kernelbase.@)
3830 BOOL WINAPI DECLSPEC_HOTPATCH
EnumDateFormatsExW( DATEFMT_ENUMPROCEXW proc
, LCID lcid
, DWORD flags
)
3832 return Internal_EnumDateFormats( (DATEFMT_ENUMPROCW
)proc
, lcid
, flags
, TRUE
, TRUE
, FALSE
, 0 );
3836 /**************************************************************************
3837 * EnumDateFormatsExEx (kernelbase.@)
3839 BOOL WINAPI DECLSPEC_HOTPATCH
EnumDateFormatsExEx( DATEFMT_ENUMPROCEXEX proc
, const WCHAR
*locale
,
3840 DWORD flags
, LPARAM lparam
)
3842 LCID lcid
= LocaleNameToLCID( locale
, 0 );
3843 return Internal_EnumDateFormats( (DATEFMT_ENUMPROCW
)proc
, lcid
, flags
, TRUE
, TRUE
, TRUE
, lparam
);
3848 /******************************************************************************
3849 * EnumDynamicTimeZoneInformation (kernelbase.@)
3851 DWORD WINAPI DECLSPEC_HOTPATCH
EnumDynamicTimeZoneInformation( DWORD index
,
3852 DYNAMIC_TIME_ZONE_INFORMATION
*info
)
3854 DYNAMIC_TIME_ZONE_INFORMATION tz
;
3858 if (!info
) return ERROR_INVALID_PARAMETER
;
3860 size
= ARRAY_SIZE(tz
.TimeZoneKeyName
);
3861 ret
= RegEnumKeyExW( tz_key
, index
, tz
.TimeZoneKeyName
, &size
, NULL
, NULL
, NULL
, NULL
);
3862 if (ret
) return ret
;
3864 tz
.DynamicDaylightTimeDisabled
= TRUE
;
3865 if (!GetTimeZoneInformationForYear( 0, &tz
, (TIME_ZONE_INFORMATION
*)info
)) return GetLastError();
3867 lstrcpyW( info
->TimeZoneKeyName
, tz
.TimeZoneKeyName
);
3868 info
->DynamicDaylightTimeDisabled
= FALSE
;
3873 /******************************************************************************
3874 * EnumLanguageGroupLocalesW (kernelbase.@)
3876 BOOL WINAPI DECLSPEC_HOTPATCH
EnumLanguageGroupLocalesW( LANGGROUPLOCALE_ENUMPROCW proc
, LGRPID id
,
3877 DWORD flags
, LONG_PTR param
)
3879 return Internal_EnumLanguageGroupLocales( proc
, id
, flags
, param
, TRUE
);
3883 /******************************************************************************
3884 * EnumUILanguagesW (kernelbase.@)
3886 BOOL WINAPI DECLSPEC_HOTPATCH
EnumUILanguagesW( UILANGUAGE_ENUMPROCW proc
, DWORD flags
, LONG_PTR param
)
3888 return Internal_EnumUILanguages( proc
, flags
, param
, TRUE
);
3892 /***********************************************************************
3893 * EnumSystemCodePagesW (kernelbase.@)
3895 BOOL WINAPI DECLSPEC_HOTPATCH
EnumSystemCodePagesW( CODEPAGE_ENUMPROCW proc
, DWORD flags
)
3897 return Internal_EnumSystemCodePages( proc
, flags
, TRUE
);
3901 /******************************************************************************
3902 * EnumSystemGeoID (kernelbase.@)
3904 BOOL WINAPI DECLSPEC_HOTPATCH
EnumSystemGeoID( GEOCLASS
class, GEOID parent
, GEO_ENUMPROC proc
)
3908 TRACE( "(%ld, %ld, %p)\n", class, parent
, proc
);
3912 SetLastError( ERROR_INVALID_PARAMETER
);
3915 if (class != GEOCLASS_NATION
&& class != GEOCLASS_REGION
&& class != GEOCLASS_ALL
)
3917 SetLastError( ERROR_INVALID_FLAGS
);
3921 for (i
= 0; i
< ARRAY_SIZE(geoinfodata
); i
++)
3923 const struct geoinfo
*ptr
= &geoinfodata
[i
];
3925 if (class == GEOCLASS_NATION
&& (ptr
->kind
!= LOCATION_NATION
)) continue;
3926 /* LOCATION_BOTH counts as region */
3927 if (class == GEOCLASS_REGION
&& (ptr
->kind
== LOCATION_NATION
)) continue;
3928 if (parent
&& ptr
->parent
!= parent
) continue;
3929 if (!proc( ptr
->id
)) break;
3935 /******************************************************************************
3936 * EnumSystemLanguageGroupsW (kernelbase.@)
3938 BOOL WINAPI DECLSPEC_HOTPATCH
EnumSystemLanguageGroupsW( LANGUAGEGROUP_ENUMPROCW proc
,
3939 DWORD flags
, LONG_PTR param
)
3941 return Internal_EnumSystemLanguageGroups( proc
, flags
, param
, TRUE
);
3945 /******************************************************************************
3946 * EnumSystemLocalesA (kernelbase.@)
3948 BOOL WINAPI DECLSPEC_HOTPATCH
EnumSystemLocalesA( LOCALE_ENUMPROCA proc
, DWORD flags
)
3953 for (i
= 0; i
< locale_table
->nb_lcnames
; i
++)
3955 if (!lcnames_index
[i
].name
) continue; /* skip invariant locale */
3956 if (lcnames_index
[i
].id
== LOCALE_CUSTOM_UNSPECIFIED
) continue; /* skip locales with no lcid */
3957 if (lcnames_index
[i
].id
& 0x80000000) continue; /* skip aliases */
3958 if (!get_locale_data( lcnames_index
[i
].idx
)->inotneutral
) continue; /* skip neutral locales */
3959 if (!SORTIDFROMLCID( lcnames_index
[i
].id
) != !(flags
& LCID_ALTERNATE_SORTS
))
3960 continue; /* skip alternate sorts */
3961 sprintf( name
, "%08x", lcnames_index
[i
].id
);
3962 if (!proc( name
)) break;
3968 /******************************************************************************
3969 * EnumSystemLocalesW (kernelbase.@)
3971 BOOL WINAPI DECLSPEC_HOTPATCH
EnumSystemLocalesW( LOCALE_ENUMPROCW proc
, DWORD flags
)
3976 for (i
= 0; i
< locale_table
->nb_lcnames
; i
++)
3978 if (!lcnames_index
[i
].name
) continue; /* skip invariant locale */
3979 if (lcnames_index
[i
].id
== LOCALE_CUSTOM_UNSPECIFIED
) continue; /* skip locales with no lcid */
3980 if (lcnames_index
[i
].id
& 0x80000000) continue; /* skip aliases */
3981 if (!get_locale_data( lcnames_index
[i
].idx
)->inotneutral
) continue; /* skip neutral locales */
3982 if (!SORTIDFROMLCID( lcnames_index
[i
].id
) != !(flags
& LCID_ALTERNATE_SORTS
))
3983 continue; /* skip alternate sorts */
3984 swprintf( name
, ARRAY_SIZE(name
), L
"%08lx", lcnames_index
[i
].id
);
3985 if (!proc( name
)) break;
3991 /******************************************************************************
3992 * EnumSystemLocalesEx (kernelbase.@)
3994 BOOL WINAPI DECLSPEC_HOTPATCH
EnumSystemLocalesEx( LOCALE_ENUMPROCEX proc
, DWORD wanted_flags
,
3995 LPARAM param
, void *reserved
)
3997 WCHAR buffer
[LOCALE_NAME_MAX_LENGTH
];
4002 SetLastError( ERROR_INVALID_PARAMETER
);
4006 for (i
= 0; i
< locale_table
->nb_lcnames
; i
++)
4008 const NLS_LOCALE_DATA
*locale
= get_locale_data( lcnames_index
[i
].idx
);
4009 const WCHAR
*str
= locale_strings
+ lcnames_index
[i
].name
;
4011 if (lcnames_index
[i
].id
& 0x80000000) continue; /* skip aliases */
4012 memcpy( buffer
, str
+ 1, (*str
+ 1) * sizeof(WCHAR
) );
4013 if (SORTIDFROMLCID( lcnames_index
[i
].id
) || wcschr( str
+ 1, '_' ))
4014 flags
= LOCALE_ALTERNATE_SORTS
;
4016 flags
= LOCALE_WINDOWS
| (locale
->inotneutral
? LOCALE_SPECIFICDATA
: LOCALE_NEUTRALDATA
);
4017 if (wanted_flags
&& !(flags
& wanted_flags
)) continue;
4018 if (!proc( buffer
, flags
, param
)) break;
4024 /**************************************************************************
4025 * EnumTimeFormatsW (kernelbase.@)
4027 BOOL WINAPI DECLSPEC_HOTPATCH
EnumTimeFormatsW( TIMEFMT_ENUMPROCW proc
, LCID lcid
, DWORD flags
)
4029 return Internal_EnumTimeFormats( proc
, lcid
, flags
, TRUE
, FALSE
, 0 );
4033 /**************************************************************************
4034 * EnumTimeFormatsEx (kernelbase.@)
4036 BOOL WINAPI DECLSPEC_HOTPATCH
EnumTimeFormatsEx( TIMEFMT_ENUMPROCEX proc
, const WCHAR
*locale
,
4037 DWORD flags
, LPARAM lparam
)
4039 LCID lcid
= LocaleNameToLCID( locale
, 0 );
4040 return Internal_EnumTimeFormats( (TIMEFMT_ENUMPROCW
)proc
, lcid
, flags
, TRUE
, TRUE
, lparam
);
4044 /**************************************************************************
4045 * FindNLSString (kernelbase.@)
4047 INT WINAPI DECLSPEC_HOTPATCH
FindNLSString( LCID lcid
, DWORD flags
, const WCHAR
*src
,
4048 int srclen
, const WCHAR
*value
, int valuelen
, int *found
)
4050 WCHAR locale
[LOCALE_NAME_MAX_LENGTH
];
4052 LCIDToLocaleName( lcid
, locale
, ARRAY_SIZE(locale
), 0 );
4053 return FindNLSStringEx( locale
, flags
, src
, srclen
, value
, valuelen
, found
, NULL
, NULL
, 0 );
4057 /**************************************************************************
4058 * FindNLSStringEx (kernelbase.@)
4060 INT WINAPI DECLSPEC_HOTPATCH
FindNLSStringEx( const WCHAR
*locale
, DWORD flags
, const WCHAR
*src
,
4061 int srclen
, const WCHAR
*value
, int valuelen
, int *found
,
4062 NLSVERSIONINFO
*version
, void *reserved
, LPARAM handle
)
4064 /* FIXME: this function should normalize strings before calling CompareStringEx() */
4066 int offset
, inc
, count
;
4068 TRACE( "%s %lx %s %d %s %d %p %p %p %Id\n", wine_dbgstr_w(locale
), flags
,
4069 wine_dbgstr_w(src
), srclen
, wine_dbgstr_w(value
), valuelen
, found
,
4070 version
, reserved
, handle
);
4072 if (version
|| reserved
|| handle
|| !IsValidLocaleName(locale
) ||
4073 !src
|| !srclen
|| srclen
< -1 || !value
|| !valuelen
|| valuelen
< -1)
4075 SetLastError( ERROR_INVALID_PARAMETER
);
4078 if (srclen
== -1) srclen
= lstrlenW(src
);
4079 if (valuelen
== -1) valuelen
= lstrlenW(value
);
4082 if (srclen
< 0) return -1;
4084 mask
= flags
& ~(FIND_FROMSTART
| FIND_FROMEND
| FIND_STARTSWITH
| FIND_ENDSWITH
);
4085 count
= flags
& (FIND_FROMSTART
| FIND_FROMEND
) ? srclen
+ 1 : 1;
4086 offset
= flags
& (FIND_FROMSTART
| FIND_STARTSWITH
) ? 0 : srclen
;
4087 inc
= flags
& (FIND_FROMSTART
| FIND_STARTSWITH
) ? 1 : -1;
4090 if (CompareStringEx( locale
, mask
, src
+ offset
, valuelen
,
4091 value
, valuelen
, NULL
, NULL
, 0 ) == CSTR_EQUAL
)
4093 if (found
) *found
= valuelen
;
4102 /******************************************************************************
4103 * FindStringOrdinal (kernelbase.@)
4105 INT WINAPI DECLSPEC_HOTPATCH
FindStringOrdinal( DWORD flag
, const WCHAR
*src
, INT src_size
,
4106 const WCHAR
*val
, INT val_size
, BOOL ignore_case
)
4108 INT offset
, inc
, count
;
4110 TRACE( "%#lx %s %d %s %d %d\n", flag
, wine_dbgstr_w(src
), src_size
,
4111 wine_dbgstr_w(val
), val_size
, ignore_case
);
4115 SetLastError( ERROR_INVALID_PARAMETER
);
4119 if (flag
!= FIND_FROMSTART
&& flag
!= FIND_FROMEND
&& flag
!= FIND_STARTSWITH
&& flag
!= FIND_ENDSWITH
)
4121 SetLastError( ERROR_INVALID_FLAGS
);
4125 if (src_size
== -1) src_size
= lstrlenW( src
);
4126 if (val_size
== -1) val_size
= lstrlenW( val
);
4128 SetLastError( ERROR_SUCCESS
);
4129 src_size
-= val_size
;
4130 if (src_size
< 0) return -1;
4132 count
= flag
& (FIND_FROMSTART
| FIND_FROMEND
) ? src_size
+ 1 : 1;
4133 offset
= flag
& (FIND_FROMSTART
| FIND_STARTSWITH
) ? 0 : src_size
;
4134 inc
= flag
& (FIND_FROMSTART
| FIND_STARTSWITH
) ? 1 : -1;
4137 if (CompareStringOrdinal( src
+ offset
, val_size
, val
, val_size
, ignore_case
) == CSTR_EQUAL
)
4145 /******************************************************************************
4146 * FoldStringW (kernelbase.@)
4148 INT WINAPI DECLSPEC_HOTPATCH
FoldStringW( DWORD flags
, LPCWSTR src
, INT srclen
, LPWSTR dst
, INT dstlen
)
4154 if (!src
|| !srclen
|| dstlen
< 0 || (dstlen
&& !dst
) || src
== dst
)
4156 SetLastError( ERROR_INVALID_PARAMETER
);
4159 if (srclen
== -1) srclen
= lstrlenW(src
) + 1;
4161 if (!dstlen
&& (flags
& (MAP_PRECOMPOSED
| MAP_FOLDCZONE
| MAP_COMPOSITE
)))
4164 if (!(buf
= RtlAllocateHeap( GetProcessHeap(), 0, len
* sizeof(WCHAR
) )))
4166 SetLastError( ERROR_OUTOFMEMORY
);
4173 status
= fold_string( flags
, src
, srclen
, buf
, &len
);
4174 if (buf
!= dst
) RtlFreeHeap( GetProcessHeap(), 0, buf
);
4175 if (status
!= STATUS_BUFFER_TOO_SMALL
) break;
4176 if (!(buf
= RtlAllocateHeap( GetProcessHeap(), 0, len
* sizeof(WCHAR
) )))
4178 SetLastError( ERROR_OUTOFMEMORY
);
4182 if (status
== STATUS_INVALID_PARAMETER_1
)
4184 SetLastError( ERROR_INVALID_FLAGS
);
4187 if (!set_ntstatus( status
)) return 0;
4189 if (dstlen
&& dstlen
< len
) SetLastError( ERROR_INSUFFICIENT_BUFFER
);
4194 static const WCHAR
*get_message( DWORD flags
, const void *src
, UINT id
, UINT lang
,
4195 BOOL ansi
, WCHAR
**buffer
)
4199 if (!(flags
& FORMAT_MESSAGE_FROM_STRING
))
4201 const MESSAGE_RESOURCE_ENTRY
*entry
;
4202 NTSTATUS status
= STATUS_INVALID_PARAMETER
;
4204 if (flags
& FORMAT_MESSAGE_FROM_HMODULE
)
4206 HMODULE module
= (HMODULE
)src
;
4207 if (!module
) module
= GetModuleHandleW( 0 );
4208 status
= RtlFindMessage( module
, RT_MESSAGETABLE
, lang
, id
, &entry
);
4210 if (status
&& (flags
& FORMAT_MESSAGE_FROM_SYSTEM
))
4212 /* Fold win32 hresult to its embedded error code. */
4213 if (HRESULT_SEVERITY(id
) == SEVERITY_ERROR
&& HRESULT_FACILITY(id
) == FACILITY_WIN32
)
4214 id
= HRESULT_CODE( id
);
4215 status
= RtlFindMessage( kernel32_handle
, RT_MESSAGETABLE
, lang
, id
, &entry
);
4217 if (!set_ntstatus( status
)) return NULL
;
4220 ansi
= !(entry
->Flags
& MESSAGE_RESOURCE_UNICODE
);
4223 if (!ansi
) return src
;
4224 len
= MultiByteToWideChar( CP_ACP
, 0, src
, -1, NULL
, 0 );
4225 if (!(*buffer
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
) ))) return NULL
;
4226 MultiByteToWideChar( CP_ACP
, 0, src
, -1, *buffer
, len
);
4231 /***********************************************************************
4232 * FormatMessageA (kernelbase.@)
4234 DWORD WINAPI DECLSPEC_HOTPATCH
FormatMessageA( DWORD flags
, const void *source
, DWORD msgid
, DWORD langid
,
4235 char *buffer
, DWORD size
, va_list *args
)
4238 ULONG len
, retsize
= 0;
4239 ULONG width
= (flags
& FORMAT_MESSAGE_MAX_WIDTH_MASK
);
4241 WCHAR
*result
, *message
= NULL
;
4244 TRACE( "(0x%lx,%p,%#lx,0x%lx,%p,%lu,%p)\n", flags
, source
, msgid
, langid
, buffer
, size
, args
);
4246 if (flags
& FORMAT_MESSAGE_ALLOCATE_BUFFER
)
4250 SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
4253 *(char **)buffer
= NULL
;
4257 SetLastError( ERROR_INVALID_PARAMETER
);
4261 if (width
== 0xff) width
= ~0u;
4263 if (!(src
= get_message( flags
, source
, msgid
, langid
, TRUE
, &message
))) return 0;
4265 if (!(result
= HeapAlloc( GetProcessHeap(), 0, 65536 )))
4266 status
= STATUS_NO_MEMORY
;
4268 status
= RtlFormatMessage( src
, width
, !!(flags
& FORMAT_MESSAGE_IGNORE_INSERTS
),
4269 TRUE
, !!(flags
& FORMAT_MESSAGE_ARGUMENT_ARRAY
), args
,
4270 result
, 65536, &retsize
);
4272 HeapFree( GetProcessHeap(), 0, message
);
4274 if (status
== STATUS_BUFFER_OVERFLOW
)
4276 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
4279 if (!set_ntstatus( status
)) goto done
;
4281 len
= WideCharToMultiByte( CP_ACP
, 0, result
, retsize
/ sizeof(WCHAR
), NULL
, 0, NULL
, NULL
);
4284 SetLastError( ERROR_NO_WORK_DONE
);
4288 if (flags
& FORMAT_MESSAGE_ALLOCATE_BUFFER
)
4290 char *buf
= LocalAlloc( LMEM_ZEROINIT
, max( size
, len
));
4293 SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
4296 *(char **)buffer
= buf
;
4297 WideCharToMultiByte( CP_ACP
, 0, result
, retsize
/ sizeof(WCHAR
), buf
, max( size
, len
), NULL
, NULL
);
4299 else if (len
> size
)
4301 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
4304 else WideCharToMultiByte( CP_ACP
, 0, result
, retsize
/ sizeof(WCHAR
), buffer
, size
, NULL
, NULL
);
4309 HeapFree( GetProcessHeap(), 0, result
);
4314 /***********************************************************************
4315 * FormatMessageW (kernelbase.@)
4317 DWORD WINAPI DECLSPEC_HOTPATCH
FormatMessageW( DWORD flags
, const void *source
, DWORD msgid
, DWORD langid
,
4318 WCHAR
*buffer
, DWORD size
, va_list *args
)
4321 ULONG width
= (flags
& FORMAT_MESSAGE_MAX_WIDTH_MASK
);
4323 WCHAR
*message
= NULL
;
4326 TRACE( "(0x%lx,%p,%#lx,0x%lx,%p,%lu,%p)\n", flags
, source
, msgid
, langid
, buffer
, size
, args
);
4330 SetLastError( ERROR_INVALID_PARAMETER
);
4334 if (width
== 0xff) width
= ~0u;
4336 if (flags
& FORMAT_MESSAGE_ALLOCATE_BUFFER
) *(LPWSTR
*)buffer
= NULL
;
4338 if (!(src
= get_message( flags
, source
, msgid
, langid
, FALSE
, &message
))) return 0;
4340 if (flags
& FORMAT_MESSAGE_ALLOCATE_BUFFER
)
4343 ULONG alloc
= max( size
* sizeof(WCHAR
), 65536 );
4347 if (!(result
= HeapAlloc( GetProcessHeap(), 0, alloc
)))
4349 status
= STATUS_NO_MEMORY
;
4352 status
= RtlFormatMessage( src
, width
, !!(flags
& FORMAT_MESSAGE_IGNORE_INSERTS
),
4353 FALSE
, !!(flags
& FORMAT_MESSAGE_ARGUMENT_ARRAY
), args
,
4354 result
, alloc
, &retsize
);
4357 if (retsize
<= sizeof(WCHAR
)) HeapFree( GetProcessHeap(), 0, result
);
4358 else *(WCHAR
**)buffer
= HeapReAlloc( GetProcessHeap(), HEAP_REALLOC_IN_PLACE_ONLY
,
4359 result
, max( retsize
, size
* sizeof(WCHAR
) ));
4362 HeapFree( GetProcessHeap(), 0, result
);
4363 if (status
!= STATUS_BUFFER_OVERFLOW
) break;
4367 else status
= RtlFormatMessage( src
, width
, !!(flags
& FORMAT_MESSAGE_IGNORE_INSERTS
),
4368 FALSE
, !!(flags
& FORMAT_MESSAGE_ARGUMENT_ARRAY
), args
,
4369 buffer
, size
* sizeof(WCHAR
), &retsize
);
4371 HeapFree( GetProcessHeap(), 0, message
);
4373 if (status
== STATUS_BUFFER_OVERFLOW
)
4375 if (size
) buffer
[size
- 1] = 0;
4376 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
4379 if (!set_ntstatus( status
)) return 0;
4380 if (retsize
<= sizeof(WCHAR
)) SetLastError( ERROR_NO_WORK_DONE
);
4381 return retsize
/ sizeof(WCHAR
) - 1;
4385 /******************************************************************************
4386 * GetACP (kernelbase.@)
4388 UINT WINAPI
GetACP(void)
4390 return nls_info
.AnsiTableInfo
.CodePage
;
4394 /***********************************************************************
4395 * GetCPInfo (kernelbase.@)
4397 BOOL WINAPI DECLSPEC_HOTPATCH
GetCPInfo( UINT codepage
, CPINFO
*cpinfo
)
4399 const CPTABLEINFO
*table
;
4403 SetLastError( ERROR_INVALID_PARAMETER
);
4410 cpinfo
->DefaultChar
[0] = 0x3f;
4411 cpinfo
->DefaultChar
[1] = 0;
4412 memset( cpinfo
->LeadByte
, 0, sizeof(cpinfo
->LeadByte
) );
4413 cpinfo
->MaxCharSize
= (codepage
== CP_UTF7
) ? 5 : 4;
4416 if (!(table
= get_codepage_table( codepage
))) return FALSE
;
4417 cpinfo
->MaxCharSize
= table
->MaximumCharacterSize
;
4418 memcpy( cpinfo
->DefaultChar
, &table
->DefaultChar
, sizeof(cpinfo
->DefaultChar
) );
4419 memcpy( cpinfo
->LeadByte
, table
->LeadByte
, sizeof(cpinfo
->LeadByte
) );
4426 /***********************************************************************
4427 * GetCPInfoExW (kernelbase.@)
4429 BOOL WINAPI
GetCPInfoExW( UINT codepage
, DWORD flags
, CPINFOEXW
*cpinfo
)
4431 const CPTABLEINFO
*table
;
4436 SetLastError( ERROR_INVALID_PARAMETER
);
4442 cpinfo
->DefaultChar
[0] = 0x3f;
4443 cpinfo
->DefaultChar
[1] = 0;
4444 cpinfo
->LeadByte
[0] = cpinfo
->LeadByte
[1] = 0;
4445 cpinfo
->MaxCharSize
= 5;
4446 cpinfo
->CodePage
= CP_UTF7
;
4447 cpinfo
->UnicodeDefaultChar
= 0x3f;
4450 cpinfo
->DefaultChar
[0] = 0x3f;
4451 cpinfo
->DefaultChar
[1] = 0;
4452 cpinfo
->LeadByte
[0] = cpinfo
->LeadByte
[1] = 0;
4453 cpinfo
->MaxCharSize
= 4;
4454 cpinfo
->CodePage
= CP_UTF8
;
4455 cpinfo
->UnicodeDefaultChar
= 0x3f;
4458 if (!(table
= get_codepage_table( codepage
))) return FALSE
;
4459 cpinfo
->MaxCharSize
= table
->MaximumCharacterSize
;
4460 memcpy( cpinfo
->DefaultChar
, &table
->DefaultChar
, sizeof(cpinfo
->DefaultChar
) );
4461 memcpy( cpinfo
->LeadByte
, table
->LeadByte
, sizeof(cpinfo
->LeadByte
) );
4462 cpinfo
->CodePage
= table
->CodePage
;
4463 cpinfo
->UnicodeDefaultChar
= table
->UniDefaultChar
;
4468 max
= ARRAY_SIZE(codepage_names
) - 1;
4469 cpinfo
->CodePageName
[0] = 0;
4472 pos
= (min
+ max
) / 2;
4473 if (codepage_names
[pos
].cp
< cpinfo
->CodePage
) min
= pos
+ 1;
4474 else if (codepage_names
[pos
].cp
> cpinfo
->CodePage
) max
= pos
- 1;
4477 wcscpy( cpinfo
->CodePageName
, codepage_names
[pos
].name
);
4485 /***********************************************************************
4486 * GetCalendarInfoW (kernelbase.@)
4488 INT WINAPI DECLSPEC_HOTPATCH
GetCalendarInfoW( LCID lcid
, CALID calendar
, CALTYPE type
,
4489 WCHAR
*data
, INT count
, DWORD
*value
)
4491 static const LCTYPE lctype_map
[] =
4494 0, /* CAL_ICALINTVALUE */
4495 0, /* CAL_SCALNAME */
4496 0, /* CAL_IYEAROFFSETRANGE */
4497 0, /* CAL_SERASTRING */
4507 LOCALE_SABBREVDAYNAME1
,
4508 LOCALE_SABBREVDAYNAME2
,
4509 LOCALE_SABBREVDAYNAME3
,
4510 LOCALE_SABBREVDAYNAME4
,
4511 LOCALE_SABBREVDAYNAME5
,
4512 LOCALE_SABBREVDAYNAME6
,
4513 LOCALE_SABBREVDAYNAME7
,
4523 LOCALE_SMONTHNAME10
,
4524 LOCALE_SMONTHNAME11
,
4525 LOCALE_SMONTHNAME12
,
4526 LOCALE_SMONTHNAME13
,
4527 LOCALE_SABBREVMONTHNAME1
,
4528 LOCALE_SABBREVMONTHNAME2
,
4529 LOCALE_SABBREVMONTHNAME3
,
4530 LOCALE_SABBREVMONTHNAME4
,
4531 LOCALE_SABBREVMONTHNAME5
,
4532 LOCALE_SABBREVMONTHNAME6
,
4533 LOCALE_SABBREVMONTHNAME7
,
4534 LOCALE_SABBREVMONTHNAME8
,
4535 LOCALE_SABBREVMONTHNAME9
,
4536 LOCALE_SABBREVMONTHNAME10
,
4537 LOCALE_SABBREVMONTHNAME11
,
4538 LOCALE_SABBREVMONTHNAME12
,
4539 LOCALE_SABBREVMONTHNAME13
,
4541 0, /* CAL_ITWODIGITYEARMAX */
4542 LOCALE_SSHORTESTDAYNAME1
,
4543 LOCALE_SSHORTESTDAYNAME2
,
4544 LOCALE_SSHORTESTDAYNAME3
,
4545 LOCALE_SSHORTESTDAYNAME4
,
4546 LOCALE_SSHORTESTDAYNAME5
,
4547 LOCALE_SSHORTESTDAYNAME6
,
4548 LOCALE_SSHORTESTDAYNAME7
,
4550 0, /* CAL_SABBREVERASTRING */
4553 CALTYPE calinfo
= type
& 0xffff;
4555 if (type
& CAL_NOUSEROVERRIDE
) FIXME("flag CAL_NOUSEROVERRIDE used, not fully implemented\n");
4556 if (type
& CAL_USE_CP_ACP
) FIXME("flag CAL_USE_CP_ACP used, not fully implemented\n");
4558 if ((type
& CAL_RETURN_NUMBER
) && !value
)
4560 SetLastError( ERROR_INVALID_PARAMETER
);
4564 if (type
& CAL_RETURN_GENITIVE_NAMES
) flags
|= LOCALE_RETURN_GENITIVE_NAMES
;
4568 case CAL_ICALINTVALUE
:
4569 if (type
& CAL_RETURN_NUMBER
)
4570 return GetLocaleInfoW( lcid
, LOCALE_RETURN_NUMBER
| LOCALE_ICALENDARTYPE
,
4571 (WCHAR
*)value
, sizeof(*value
) / sizeof(WCHAR
) );
4572 return GetLocaleInfoW( lcid
, LOCALE_ICALENDARTYPE
, data
, count
);
4575 FIXME( "Unimplemented caltype %ld\n", calinfo
);
4576 if (data
) *data
= 0;
4579 case CAL_IYEAROFFSETRANGE
:
4580 case CAL_SERASTRING
:
4581 case CAL_SABBREVERASTRING
:
4582 FIXME( "Unimplemented caltype %ld\n", calinfo
);
4585 case CAL_SSHORTDATE
:
4594 case CAL_SABBREVDAYNAME1
:
4595 case CAL_SABBREVDAYNAME2
:
4596 case CAL_SABBREVDAYNAME3
:
4597 case CAL_SABBREVDAYNAME4
:
4598 case CAL_SABBREVDAYNAME5
:
4599 case CAL_SABBREVDAYNAME6
:
4600 case CAL_SABBREVDAYNAME7
:
4601 case CAL_SMONTHNAME1
:
4602 case CAL_SMONTHNAME2
:
4603 case CAL_SMONTHNAME3
:
4604 case CAL_SMONTHNAME4
:
4605 case CAL_SMONTHNAME5
:
4606 case CAL_SMONTHNAME6
:
4607 case CAL_SMONTHNAME7
:
4608 case CAL_SMONTHNAME8
:
4609 case CAL_SMONTHNAME9
:
4610 case CAL_SMONTHNAME10
:
4611 case CAL_SMONTHNAME11
:
4612 case CAL_SMONTHNAME12
:
4613 case CAL_SMONTHNAME13
:
4614 case CAL_SABBREVMONTHNAME1
:
4615 case CAL_SABBREVMONTHNAME2
:
4616 case CAL_SABBREVMONTHNAME3
:
4617 case CAL_SABBREVMONTHNAME4
:
4618 case CAL_SABBREVMONTHNAME5
:
4619 case CAL_SABBREVMONTHNAME6
:
4620 case CAL_SABBREVMONTHNAME7
:
4621 case CAL_SABBREVMONTHNAME8
:
4622 case CAL_SABBREVMONTHNAME9
:
4623 case CAL_SABBREVMONTHNAME10
:
4624 case CAL_SABBREVMONTHNAME11
:
4625 case CAL_SABBREVMONTHNAME12
:
4626 case CAL_SABBREVMONTHNAME13
:
4628 case CAL_SYEARMONTH
:
4629 case CAL_SSHORTESTDAYNAME1
:
4630 case CAL_SSHORTESTDAYNAME2
:
4631 case CAL_SSHORTESTDAYNAME3
:
4632 case CAL_SSHORTESTDAYNAME4
:
4633 case CAL_SSHORTESTDAYNAME5
:
4634 case CAL_SSHORTESTDAYNAME6
:
4635 case CAL_SSHORTESTDAYNAME7
:
4636 return GetLocaleInfoW( lcid
, lctype_map
[calinfo
] | flags
, data
, count
);
4638 case CAL_ITWODIGITYEARMAX
:
4639 if (type
& CAL_RETURN_NUMBER
)
4641 *value
= CALINFO_MAX_YEAR
;
4642 return sizeof(DWORD
) / sizeof(WCHAR
);
4647 int ret
= swprintf( buffer
, ARRAY_SIZE(buffer
), L
"%u", CALINFO_MAX_YEAR
) + 1;
4648 if (!data
) return ret
;
4651 lstrcpyW( data
, buffer
);
4654 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
4659 FIXME( "Unknown caltype %ld\n", calinfo
);
4660 SetLastError( ERROR_INVALID_FLAGS
);
4667 /***********************************************************************
4668 * GetCalendarInfoEx (kernelbase.@)
4670 INT WINAPI DECLSPEC_HOTPATCH
GetCalendarInfoEx( const WCHAR
*locale
, CALID calendar
, const WCHAR
*reserved
,
4671 CALTYPE type
, WCHAR
*data
, INT count
, DWORD
*value
)
4673 LCID lcid
= LocaleNameToLCID( locale
, 0 );
4674 return GetCalendarInfoW( lcid
, calendar
, type
, data
, count
, value
);
4677 static CRITICAL_SECTION tzname_section
;
4678 static CRITICAL_SECTION_DEBUG tzname_section_debug
=
4680 0, 0, &tzname_section
,
4681 { &tzname_section_debug
.ProcessLocksList
, &tzname_section_debug
.ProcessLocksList
},
4682 0, 0, { (DWORD_PTR
)(__FILE__
": tzname_section") }
4684 static CRITICAL_SECTION tzname_section
= { &tzname_section_debug
, -1, 0, 0, 0, 0 };
4687 WCHAR key_name
[128];
4688 WCHAR standard_name
[32];
4689 WCHAR daylight_name
[32];
4692 /***********************************************************************
4693 * GetDynamicTimeZoneInformation (kernelbase.@)
4695 DWORD WINAPI DECLSPEC_HOTPATCH
GetDynamicTimeZoneInformation( DYNAMIC_TIME_ZONE_INFORMATION
*info
)
4700 if (!set_ntstatus( RtlQueryDynamicTimeZoneInformation( (RTL_DYNAMIC_TIME_ZONE_INFORMATION
*)info
)))
4701 return TIME_ZONE_ID_INVALID
;
4703 RtlEnterCriticalSection( &tzname_section
);
4704 if (cached_tzname
.lcid
== GetThreadLocale() &&
4705 !wcscmp( info
->TimeZoneKeyName
, cached_tzname
.key_name
))
4707 wcscpy( info
->StandardName
, cached_tzname
.standard_name
);
4708 wcscpy( info
->DaylightName
, cached_tzname
.daylight_name
);
4709 RtlLeaveCriticalSection( &tzname_section
);
4713 RtlLeaveCriticalSection( &tzname_section
);
4714 if (!RegOpenKeyExW( tz_key
, info
->TimeZoneKeyName
, 0, KEY_ALL_ACCESS
, &key
))
4716 RegLoadMUIStringW( key
, L
"MUI_Std", info
->StandardName
,
4717 sizeof(info
->StandardName
), NULL
, 0, system_dir
);
4718 RegLoadMUIStringW( key
, L
"MUI_Dlt", info
->DaylightName
,
4719 sizeof(info
->DaylightName
), NULL
, 0, system_dir
);
4722 else return TIME_ZONE_ID_INVALID
;
4724 RtlEnterCriticalSection( &tzname_section
);
4725 cached_tzname
.lcid
= GetThreadLocale();
4726 wcscpy( cached_tzname
.key_name
, info
->TimeZoneKeyName
);
4727 wcscpy( cached_tzname
.standard_name
, info
->StandardName
);
4728 wcscpy( cached_tzname
.daylight_name
, info
->DaylightName
);
4729 RtlLeaveCriticalSection( &tzname_section
);
4732 NtQuerySystemTime( &now
);
4733 return get_timezone_id( (TIME_ZONE_INFORMATION
*)info
, now
, FALSE
);
4737 /******************************************************************************
4738 * GetDynamicTimeZoneInformationEffectiveYears (kernelbase.@)
4740 DWORD WINAPI DECLSPEC_HOTPATCH
GetDynamicTimeZoneInformationEffectiveYears( const DYNAMIC_TIME_ZONE_INFORMATION
*info
,
4741 DWORD
*first
, DWORD
*last
)
4743 HKEY key
, dst_key
= 0;
4744 DWORD type
, count
, ret
= ERROR_FILE_NOT_FOUND
;
4746 if (RegOpenKeyExW( tz_key
, info
->TimeZoneKeyName
, 0, KEY_ALL_ACCESS
, &key
)) return ret
;
4748 if (RegOpenKeyExW( key
, L
"Dynamic DST", 0, KEY_ALL_ACCESS
, &dst_key
)) goto done
;
4749 count
= sizeof(DWORD
);
4750 if (RegQueryValueExW( dst_key
, L
"FirstEntry", NULL
, &type
, (BYTE
*)first
, &count
)) goto done
;
4751 if (type
!= REG_DWORD
) goto done
;
4752 count
= sizeof(DWORD
);
4753 if (RegQueryValueExW( dst_key
, L
"LastEntry", NULL
, &type
, (BYTE
*)last
, &count
)) goto done
;
4754 if (type
!= REG_DWORD
) goto done
;
4758 RegCloseKey( dst_key
);
4764 /******************************************************************************
4765 * GetFileMUIInfo (kernelbase.@)
4767 BOOL WINAPI
/* DECLSPEC_HOTPATCH */ GetFileMUIInfo( DWORD flags
, const WCHAR
*path
,
4768 FILEMUIINFO
*info
, DWORD
*size
)
4770 FIXME( "stub: %lu, %s, %p, %p\n", flags
, debugstr_w(path
), info
, size
);
4771 SetLastError( ERROR_CALL_NOT_IMPLEMENTED
);
4776 /******************************************************************************
4777 * GetFileMUIPath (kernelbase.@)
4779 BOOL WINAPI
/* DECLSPEC_HOTPATCH */ GetFileMUIPath( DWORD flags
, const WCHAR
*filepath
,
4780 WCHAR
*language
, ULONG
*languagelen
,
4781 WCHAR
*muipath
, ULONG
*muipathlen
,
4782 ULONGLONG
*enumerator
)
4784 FIXME( "stub: 0x%lx, %s, %s, %p, %p, %p, %p\n", flags
, debugstr_w(filepath
),
4785 debugstr_w(language
), languagelen
, muipath
, muipathlen
, enumerator
);
4786 SetLastError( ERROR_CALL_NOT_IMPLEMENTED
);
4791 /******************************************************************************
4792 * GetGeoInfoW (kernelbase.@)
4794 INT WINAPI DECLSPEC_HOTPATCH
GetGeoInfoW( GEOID id
, GEOTYPE type
, WCHAR
*data
, int count
, LANGID lang
)
4796 const struct geoinfo
*ptr
= get_geoinfo_ptr( id
);
4798 const WCHAR
*str
= bufferW
;
4801 TRACE( "%ld %ld %p %d %d\n", id
, type
, data
, count
, lang
);
4805 SetLastError( ERROR_INVALID_PARAMETER
);
4811 if (ptr
->kind
!= LOCATION_NATION
) return 0;
4814 swprintf( bufferW
, ARRAY_SIZE(bufferW
), L
"%u", ptr
->id
);
4816 case GEO_ISO_UN_NUMBER
:
4817 swprintf( bufferW
, ARRAY_SIZE(bufferW
), L
"%03u", ptr
->uncode
);
4820 swprintf( bufferW
, ARRAY_SIZE(bufferW
), L
"%u", ptr
->parent
);
4830 case GEO_FRIENDLYNAME
:
4831 case GEO_OFFICIALNAME
:
4833 case GEO_OFFICIALLANGUAGES
:
4836 case GEO_DIALINGCODE
:
4837 case GEO_CURRENCYCODE
:
4838 case GEO_CURRENCYSYMBOL
:
4840 FIXME( "type %ld is not supported\n", type
);
4841 SetLastError( ERROR_CALL_NOT_IMPLEMENTED
);
4844 WARN( "unrecognized type %ld\n", type
);
4845 SetLastError( ERROR_INVALID_FLAGS
);
4849 len
= lstrlenW(str
) + 1;
4850 if (!data
|| !count
) return len
;
4852 memcpy( data
, str
, min(len
, count
) * sizeof(WCHAR
) );
4853 if (count
< len
) SetLastError( ERROR_INSUFFICIENT_BUFFER
);
4854 return count
< len
? 0 : len
;
4858 /******************************************************************************
4859 * GetLocaleInfoA (kernelbase.@)
4861 INT WINAPI DECLSPEC_HOTPATCH
GetLocaleInfoA( LCID lcid
, LCTYPE lctype
, char *buffer
, INT len
)
4866 TRACE( "lcid=0x%lx lctype=0x%lx %p %d\n", lcid
, lctype
, buffer
, len
);
4868 if (len
< 0 || (len
&& !buffer
))
4870 SetLastError( ERROR_INVALID_PARAMETER
);
4873 if (LOWORD(lctype
) == LOCALE_SSHORTTIME
|| (lctype
& LOCALE_RETURN_GENITIVE_NAMES
))
4875 SetLastError( ERROR_INVALID_FLAGS
);
4879 if (LOWORD(lctype
) == LOCALE_FONTSIGNATURE
|| (lctype
& LOCALE_RETURN_NUMBER
))
4880 return GetLocaleInfoW( lcid
, lctype
, (WCHAR
*)buffer
, len
/ sizeof(WCHAR
) ) * sizeof(WCHAR
);
4882 if (!(lenW
= GetLocaleInfoW( lcid
, lctype
, NULL
, 0 ))) return 0;
4884 if (!(bufferW
= RtlAllocateHeap( GetProcessHeap(), 0, lenW
* sizeof(WCHAR
) )))
4886 SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
4889 ret
= GetLocaleInfoW( lcid
, lctype
, bufferW
, lenW
);
4890 if (ret
) ret
= WideCharToMultiByte( get_lcid_codepage( lcid
, lctype
), 0,
4891 bufferW
, ret
, buffer
, len
, NULL
, NULL
);
4892 RtlFreeHeap( GetProcessHeap(), 0, bufferW
);
4897 /******************************************************************************
4898 * GetLocaleInfoW (kernelbase.@)
4900 INT WINAPI DECLSPEC_HOTPATCH
GetLocaleInfoW( LCID lcid
, LCTYPE lctype
, WCHAR
*buffer
, INT len
)
4902 const NLS_LOCALE_DATA
*locale
;
4906 UINT lcflags
= lctype
;
4910 if (len
< 0 || (len
&& !buffer
))
4912 SetLastError( ERROR_INVALID_PARAMETER
);
4915 if (!(locale
= get_locale_by_id( &lcid
, 0 )))
4917 SetLastError( ERROR_INVALID_PARAMETER
);
4920 ret
= get_locale_info( locale
, lcid
, lctype
, buffer
, len
);
4921 if (ret
!= -1) return ret
;
4923 if (!len
) buffer
= NULL
;
4925 lcid
= ConvertDefaultLocale( lcid
);
4926 lctype
= LOWORD(lctype
);
4928 TRACE( "(lcid=0x%lx,lctype=0x%lx,%p,%d)\n", lcid
, lctype
, buffer
, len
);
4930 /* first check for overrides in the registry */
4932 if (!(lcflags
& LOCALE_NOUSEROVERRIDE
) && lcid
== ConvertDefaultLocale( LOCALE_USER_DEFAULT
))
4934 const struct registry_value
*value
= get_locale_registry_value( lctype
);
4938 if (lcflags
& LOCALE_RETURN_NUMBER
)
4941 ret
= get_registry_locale_info( value
, tmp
, ARRAY_SIZE( tmp
));
4945 UINT number
= wcstol( tmp
, &end
, get_value_base_by_lctype( lctype
) );
4946 if (*end
) /* invalid number */
4948 SetLastError( ERROR_INVALID_FLAGS
);
4951 ret
= sizeof(UINT
) / sizeof(WCHAR
);
4952 if (!len
) return ret
;
4955 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
4958 memcpy( buffer
, &number
, sizeof(number
) );
4961 else ret
= get_registry_locale_info( value
, buffer
, len
);
4963 if (ret
!= -1) return ret
;
4967 /* now load it from kernel resources */
4969 if (!(hrsrc
= FindResourceExW( kernel32_handle
, (LPWSTR
)RT_STRING
,
4970 ULongToPtr((lctype
>> 4) + 1), lcid
)))
4972 SetLastError( ERROR_INVALID_FLAGS
); /* no such lctype */
4975 if (!(hmem
= LoadResource( kernel32_handle
, hrsrc
))) return 0;
4977 p
= LockResource( hmem
);
4978 for (i
= 0; i
< (lctype
& 0x0f); i
++) p
+= *p
+ 1;
4980 if (lcflags
& LOCALE_RETURN_NUMBER
) ret
= sizeof(UINT
) / sizeof(WCHAR
);
4982 ret
= (lctype
== LOCALE_FONTSIGNATURE
) ? *p
: *p
+ 1;
4984 if (!len
) return ret
;
4988 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
4992 if (lcflags
& LOCALE_RETURN_NUMBER
)
4995 WCHAR
*end
, *tmp
= HeapAlloc( GetProcessHeap(), 0, (*p
+ 1) * sizeof(WCHAR
) );
4997 memcpy( tmp
, p
+ 1, *p
* sizeof(WCHAR
) );
4999 number
= wcstol( tmp
, &end
, get_value_base_by_lctype( lctype
) );
5001 memcpy( buffer
, &number
, sizeof(number
) );
5002 else /* invalid number */
5004 SetLastError( ERROR_INVALID_FLAGS
);
5007 HeapFree( GetProcessHeap(), 0, tmp
);
5009 TRACE( "(lcid=0x%lx,lctype=0x%lx,%p,%d) returning number %d\n",
5010 lcid
, lctype
, buffer
, len
, number
);
5014 memcpy( buffer
, p
+ 1, ret
* sizeof(WCHAR
) );
5015 if (lctype
!= LOCALE_FONTSIGNATURE
) buffer
[ret
-1] = 0;
5017 TRACE( "(lcid=0x%lx,lctype=0x%lx,%p,%d) returning %d %s\n",
5018 lcid
, lctype
, buffer
, len
, ret
, debugstr_w(buffer
) );
5024 /******************************************************************************
5025 * GetLocaleInfoEx (kernelbase.@)
5027 INT WINAPI DECLSPEC_HOTPATCH
GetLocaleInfoEx( const WCHAR
*name
, LCTYPE info
, WCHAR
*buffer
, INT len
)
5031 const NLS_LOCALE_DATA
*locale
= get_locale_by_name( name
, &lcid
);
5035 SetLastError( ERROR_INVALID_PARAMETER
);
5038 ret
= get_locale_info( locale
, lcid
, info
, buffer
, len
);
5039 if (ret
!= -1) return ret
;
5041 TRACE( "%s 0x%lx\n", debugstr_w(name
), info
);
5043 lcid
= LocaleNameToLCID( name
, 0 );
5044 if (!lcid
) return 0;
5045 return GetLocaleInfoW( lcid
, info
, buffer
, len
);
5049 /******************************************************************************
5050 * GetNLSVersion (kernelbase.@)
5052 BOOL WINAPI DECLSPEC_HOTPATCH
GetNLSVersion( NLS_FUNCTION func
, LCID lcid
, NLSVERSIONINFO
*info
)
5054 WCHAR locale
[LOCALE_NAME_MAX_LENGTH
];
5056 if (info
->dwNLSVersionInfoSize
< offsetof( NLSVERSIONINFO
, dwEffectiveId
))
5058 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
5061 if (!LCIDToLocaleName( lcid
, locale
, LOCALE_NAME_MAX_LENGTH
, LOCALE_ALLOW_NEUTRAL_NAMES
))
5063 SetLastError( ERROR_INVALID_PARAMETER
);
5066 return GetNLSVersionEx( func
, locale
, (NLSVERSIONINFOEX
*)info
);
5070 /******************************************************************************
5071 * GetNLSVersionEx (kernelbase.@)
5073 BOOL WINAPI DECLSPEC_HOTPATCH
GetNLSVersionEx( NLS_FUNCTION func
, const WCHAR
*locale
,
5074 NLSVERSIONINFOEX
*info
)
5078 if (func
!= COMPARE_STRING
)
5080 SetLastError( ERROR_INVALID_FLAGS
);
5083 if (info
->dwNLSVersionInfoSize
< sizeof(*info
) &&
5084 (info
->dwNLSVersionInfoSize
!= offsetof( NLSVERSIONINFO
, dwEffectiveId
)))
5086 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
5090 if (!(lcid
= LocaleNameToLCID( locale
, 0 ))) return FALSE
;
5092 info
->dwNLSVersion
= info
->dwDefinedVersion
= sort
.version
;
5093 if (info
->dwNLSVersionInfoSize
>= sizeof(*info
))
5095 const struct sortguid
*sortid
= get_language_sort( locale
);
5096 info
->dwEffectiveId
= lcid
;
5097 info
->guidCustomVersion
= sortid
? sortid
->id
: default_sort_guid
;
5103 /******************************************************************************
5104 * GetOEMCP (kernelbase.@)
5106 UINT WINAPI
GetOEMCP(void)
5108 return nls_info
.OemTableInfo
.CodePage
;
5112 /***********************************************************************
5113 * GetProcessPreferredUILanguages (kernelbase.@)
5115 BOOL WINAPI DECLSPEC_HOTPATCH
GetProcessPreferredUILanguages( DWORD flags
, ULONG
*count
,
5116 WCHAR
*buffer
, ULONG
*size
)
5118 return set_ntstatus( RtlGetProcessPreferredUILanguages( flags
, count
, buffer
, size
));
5122 /***********************************************************************
5123 * GetStringTypeA (kernelbase.@)
5125 BOOL WINAPI DECLSPEC_HOTPATCH
GetStringTypeA( LCID locale
, DWORD type
, const char *src
, int count
,
5133 if (count
== -1) count
= strlen(src
) + 1;
5135 cp
= get_lcid_codepage( locale
, 0 );
5136 countW
= MultiByteToWideChar(cp
, 0, src
, count
, NULL
, 0);
5137 if((srcW
= HeapAlloc(GetProcessHeap(), 0, countW
* sizeof(WCHAR
))))
5139 MultiByteToWideChar(cp
, 0, src
, count
, srcW
, countW
);
5141 * NOTE: the target buffer has 1 word for each CHARACTER in the source
5142 * string, with multibyte characters there maybe be more bytes in count
5143 * than character space in the buffer!
5145 ret
= GetStringTypeW(type
, srcW
, countW
, chartype
);
5146 HeapFree(GetProcessHeap(), 0, srcW
);
5152 /***********************************************************************
5153 * GetStringTypeW (kernelbase.@)
5155 BOOL WINAPI DECLSPEC_HOTPATCH
GetStringTypeW( DWORD type
, const WCHAR
*src
, INT count
, WORD
*chartype
)
5159 SetLastError( ERROR_INVALID_PARAMETER
);
5162 if (type
!= CT_CTYPE1
&& type
!= CT_CTYPE2
&& type
!= CT_CTYPE3
)
5164 SetLastError( ERROR_INVALID_PARAMETER
);
5168 if (count
== -1) count
= lstrlenW(src
) + 1;
5170 while (count
--) *chartype
++ = get_char_type( type
, *src
++ );
5176 /***********************************************************************
5177 * GetStringTypeExW (kernelbase.@)
5179 BOOL WINAPI DECLSPEC_HOTPATCH
GetStringTypeExW( LCID locale
, DWORD type
, const WCHAR
*src
, int count
,
5182 /* locale is ignored for Unicode */
5183 return GetStringTypeW( type
, src
, count
, chartype
);
5187 /***********************************************************************
5188 * GetSystemDefaultLCID (kernelbase.@)
5190 LCID WINAPI DECLSPEC_HOTPATCH
GetSystemDefaultLCID(void)
5196 /***********************************************************************
5197 * GetSystemDefaultLangID (kernelbase.@)
5199 LANGID WINAPI DECLSPEC_HOTPATCH
GetSystemDefaultLangID(void)
5201 return LANGIDFROMLCID( GetSystemDefaultLCID() );
5205 /***********************************************************************
5206 * GetSystemDefaultLocaleName (kernelbase.@)
5208 INT WINAPI DECLSPEC_HOTPATCH
GetSystemDefaultLocaleName( LPWSTR name
, INT count
)
5210 return get_locale_info( system_locale
, system_lcid
, LOCALE_SNAME
, name
, count
);
5214 /***********************************************************************
5215 * GetSystemDefaultUILanguage (kernelbase.@)
5217 LANGID WINAPI DECLSPEC_HOTPATCH
GetSystemDefaultUILanguage(void)
5220 NtQueryInstallUILanguage( &lang
);
5225 /***********************************************************************
5226 * GetSystemPreferredUILanguages (kernelbase.@)
5228 BOOL WINAPI DECLSPEC_HOTPATCH
GetSystemPreferredUILanguages( DWORD flags
, ULONG
*count
,
5229 WCHAR
*buffer
, ULONG
*size
)
5231 return set_ntstatus( RtlGetSystemPreferredUILanguages( flags
, 0, count
, buffer
, size
));
5235 /***********************************************************************
5236 * GetThreadPreferredUILanguages (kernelbase.@)
5238 BOOL WINAPI DECLSPEC_HOTPATCH
GetThreadPreferredUILanguages( DWORD flags
, ULONG
*count
,
5239 WCHAR
*buffer
, ULONG
*size
)
5241 return set_ntstatus( RtlGetThreadPreferredUILanguages( flags
, count
, buffer
, size
));
5245 /***********************************************************************
5246 * GetTimeZoneInformation (kernelbase.@)
5248 DWORD WINAPI DECLSPEC_HOTPATCH
GetTimeZoneInformation( TIME_ZONE_INFORMATION
*info
)
5250 DYNAMIC_TIME_ZONE_INFORMATION tzinfo
;
5251 DWORD ret
= GetDynamicTimeZoneInformation( &tzinfo
);
5253 memcpy( info
, &tzinfo
, sizeof(*info
) );
5258 /***********************************************************************
5259 * GetTimeZoneInformationForYear (kernelbase.@)
5261 BOOL WINAPI DECLSPEC_HOTPATCH
GetTimeZoneInformationForYear( USHORT year
,
5262 DYNAMIC_TIME_ZONE_INFORMATION
*dynamic
,
5263 TIME_ZONE_INFORMATION
*info
)
5265 DYNAMIC_TIME_ZONE_INFORMATION local_info
;
5266 HKEY key
= 0, dst_key
;
5274 SYSTEMTIME std_date
;
5275 SYSTEMTIME dlt_date
;
5278 TRACE( "(%u,%p)\n", year
, info
);
5282 if (GetDynamicTimeZoneInformation( &local_info
) == TIME_ZONE_ID_INVALID
) return FALSE
;
5283 dynamic
= &local_info
;
5286 if ((ret
= RegOpenKeyExW( tz_key
, dynamic
->TimeZoneKeyName
, 0, KEY_ALL_ACCESS
, &key
))) goto done
;
5287 if (RegLoadMUIStringW( key
, L
"MUI_Std", info
->StandardName
,
5288 sizeof(info
->StandardName
), NULL
, 0, system_dir
))
5290 count
= sizeof(info
->StandardName
);
5291 if ((ret
= RegQueryValueExW( key
, L
"Std", NULL
, NULL
, (BYTE
*)info
->StandardName
, &count
)))
5294 if (RegLoadMUIStringW( key
, L
"MUI_Dlt", info
->DaylightName
,
5295 sizeof(info
->DaylightName
), NULL
, 0, system_dir
))
5297 count
= sizeof(info
->DaylightName
);
5298 if ((ret
= RegQueryValueExW( key
, L
"Dlt", NULL
, NULL
, (BYTE
*)info
->DaylightName
, &count
)))
5302 ret
= ERROR_FILE_NOT_FOUND
;
5303 if (!dynamic
->DynamicDaylightTimeDisabled
&&
5304 !RegOpenKeyExW( key
, L
"Dynamic DST", 0, KEY_ALL_ACCESS
, &dst_key
))
5307 swprintf( yearW
, ARRAY_SIZE(yearW
), L
"%u", year
);
5308 count
= sizeof(data
);
5309 ret
= RegQueryValueExW( dst_key
, yearW
, NULL
, NULL
, (BYTE
*)&data
, &count
);
5310 RegCloseKey( dst_key
);
5314 count
= sizeof(data
);
5315 ret
= RegQueryValueExW( key
, L
"TZI", NULL
, NULL
, (BYTE
*)&data
, &count
);
5320 info
->Bias
= data
.bias
;
5321 info
->StandardBias
= data
.std_bias
;
5322 info
->DaylightBias
= data
.dlt_bias
;
5323 info
->StandardDate
= data
.std_date
;
5324 info
->DaylightDate
= data
.dlt_date
;
5329 if (ret
) SetLastError( ret
);
5334 /***********************************************************************
5335 * GetUserDefaultLCID (kernelbase.@)
5337 LCID WINAPI DECLSPEC_HOTPATCH
GetUserDefaultLCID(void)
5343 /***********************************************************************
5344 * GetUserDefaultLangID (kernelbase.@)
5346 LANGID WINAPI DECLSPEC_HOTPATCH
GetUserDefaultLangID(void)
5348 return LANGIDFROMLCID( GetUserDefaultLCID() );
5352 /***********************************************************************
5353 * GetUserDefaultLocaleName (kernelbase.@)
5355 INT WINAPI DECLSPEC_HOTPATCH
GetUserDefaultLocaleName( LPWSTR name
, INT len
)
5357 return get_locale_info( user_locale
, user_lcid
, LOCALE_SNAME
, name
, len
);
5361 /***********************************************************************
5362 * GetUserDefaultUILanguage (kernelbase.@)
5364 LANGID WINAPI DECLSPEC_HOTPATCH
GetUserDefaultUILanguage(void)
5367 NtQueryDefaultUILanguage( &lang
);
5372 /******************************************************************************
5373 * GetUserGeoID (kernelbase.@)
5375 GEOID WINAPI DECLSPEC_HOTPATCH
GetUserGeoID( GEOCLASS geoclass
)
5384 case GEOCLASS_NATION
:
5387 case GEOCLASS_REGION
:
5391 WARN("Unknown geoclass %ld\n", geoclass
);
5392 return GEOID_NOT_AVAILABLE
;
5394 if (!RegOpenKeyExW( intl_key
, L
"Geo", 0, KEY_ALL_ACCESS
, &hkey
))
5396 DWORD count
= sizeof(bufferW
);
5397 if (!RegQueryValueExW( hkey
, name
, NULL
, NULL
, (BYTE
*)bufferW
, &count
))
5398 ret
= wcstol( bufferW
, NULL
, 10 );
5399 RegCloseKey( hkey
);
5405 /******************************************************************************
5406 * GetUserPreferredUILanguages (kernelbase.@)
5408 BOOL WINAPI DECLSPEC_HOTPATCH
GetUserPreferredUILanguages( DWORD flags
, ULONG
*count
,
5409 WCHAR
*buffer
, ULONG
*size
)
5411 return set_ntstatus( RtlGetUserPreferredUILanguages( flags
, 0, count
, buffer
, size
));
5415 /******************************************************************************
5416 * IdnToAscii (kernelbase.@)
5418 INT WINAPI DECLSPEC_HOTPATCH
IdnToAscii( DWORD flags
, const WCHAR
*src
, INT srclen
,
5419 WCHAR
*dst
, INT dstlen
)
5421 NTSTATUS status
= RtlIdnToAscii( flags
, src
, srclen
, dst
, &dstlen
);
5422 if (!set_ntstatus( status
)) return 0;
5427 /******************************************************************************
5428 * IdnToNameprepUnicode (kernelbase.@)
5430 INT WINAPI DECLSPEC_HOTPATCH
IdnToNameprepUnicode( DWORD flags
, const WCHAR
*src
, INT srclen
,
5431 WCHAR
*dst
, INT dstlen
)
5433 NTSTATUS status
= RtlIdnToNameprepUnicode( flags
, src
, srclen
, dst
, &dstlen
);
5434 if (!set_ntstatus( status
)) return 0;
5439 /******************************************************************************
5440 * IdnToUnicode (kernelbase.@)
5442 INT WINAPI DECLSPEC_HOTPATCH
IdnToUnicode( DWORD flags
, const WCHAR
*src
, INT srclen
,
5443 WCHAR
*dst
, INT dstlen
)
5445 NTSTATUS status
= RtlIdnToUnicode( flags
, src
, srclen
, dst
, &dstlen
);
5446 if (!set_ntstatus( status
)) return 0;
5451 /******************************************************************************
5452 * IsCharAlphaA (kernelbase.@)
5454 BOOL WINAPI DECLSPEC_HOTPATCH
IsCharAlphaA( CHAR c
)
5456 WCHAR wc
= nls_info
.AnsiTableInfo
.MultiByteTable
[(unsigned char)c
];
5457 return !!(get_char_type( CT_CTYPE1
, wc
) & C1_ALPHA
);
5461 /******************************************************************************
5462 * IsCharAlphaW (kernelbase.@)
5464 BOOL WINAPI DECLSPEC_HOTPATCH
IsCharAlphaW( WCHAR wc
)
5466 return !!(get_char_type( CT_CTYPE1
, wc
) & C1_ALPHA
);
5470 /******************************************************************************
5471 * IsCharAlphaNumericA (kernelbase.@)
5473 BOOL WINAPI DECLSPEC_HOTPATCH
IsCharAlphaNumericA( CHAR c
)
5475 WCHAR wc
= nls_info
.AnsiTableInfo
.MultiByteTable
[(unsigned char)c
];
5476 return !!(get_char_type( CT_CTYPE1
, wc
) & (C1_ALPHA
| C1_DIGIT
));
5480 /******************************************************************************
5481 * IsCharAlphaNumericW (kernelbase.@)
5483 BOOL WINAPI DECLSPEC_HOTPATCH
IsCharAlphaNumericW( WCHAR wc
)
5485 return !!(get_char_type( CT_CTYPE1
, wc
) & (C1_ALPHA
| C1_DIGIT
));
5489 /******************************************************************************
5490 * IsCharBlankW (kernelbase.@)
5492 BOOL WINAPI DECLSPEC_HOTPATCH
IsCharBlankW( WCHAR wc
)
5494 return !!(get_char_type( CT_CTYPE1
, wc
) & C1_BLANK
);
5498 /******************************************************************************
5499 * IsCharCntrlW (kernelbase.@)
5501 BOOL WINAPI DECLSPEC_HOTPATCH
IsCharCntrlW( WCHAR wc
)
5503 return !!(get_char_type( CT_CTYPE1
, wc
) & C1_CNTRL
);
5507 /******************************************************************************
5508 * IsCharDigitW (kernelbase.@)
5510 BOOL WINAPI DECLSPEC_HOTPATCH
IsCharDigitW( WCHAR wc
)
5512 return !!(get_char_type( CT_CTYPE1
, wc
) & C1_DIGIT
);
5516 /******************************************************************************
5517 * IsCharLowerA (kernelbase.@)
5519 BOOL WINAPI DECLSPEC_HOTPATCH
IsCharLowerA( CHAR c
)
5521 WCHAR wc
= nls_info
.AnsiTableInfo
.MultiByteTable
[(unsigned char)c
];
5522 return !!(get_char_type( CT_CTYPE1
, wc
) & C1_LOWER
);
5526 /******************************************************************************
5527 * IsCharLowerW (kernelbase.@)
5529 BOOL WINAPI DECLSPEC_HOTPATCH
IsCharLowerW( WCHAR wc
)
5531 return !!(get_char_type( CT_CTYPE1
, wc
) & C1_LOWER
);
5535 /******************************************************************************
5536 * IsCharPunctW (kernelbase.@)
5538 BOOL WINAPI DECLSPEC_HOTPATCH
IsCharPunctW( WCHAR wc
)
5540 return !!(get_char_type( CT_CTYPE1
, wc
) & C1_PUNCT
);
5544 /******************************************************************************
5545 * IsCharSpaceA (kernelbase.@)
5547 BOOL WINAPI DECLSPEC_HOTPATCH
IsCharSpaceA( CHAR c
)
5549 WCHAR wc
= nls_info
.AnsiTableInfo
.MultiByteTable
[(unsigned char)c
];
5550 return !!(get_char_type( CT_CTYPE1
, wc
) & C1_SPACE
);
5554 /******************************************************************************
5555 * IsCharSpaceW (kernelbase.@)
5557 BOOL WINAPI DECLSPEC_HOTPATCH
IsCharSpaceW( WCHAR wc
)
5559 return !!(get_char_type( CT_CTYPE1
, wc
) & C1_SPACE
);
5563 /******************************************************************************
5564 * IsCharUpperA (kernelbase.@)
5566 BOOL WINAPI DECLSPEC_HOTPATCH
IsCharUpperA( CHAR c
)
5568 WCHAR wc
= nls_info
.AnsiTableInfo
.MultiByteTable
[(unsigned char)c
];
5569 return !!(get_char_type( CT_CTYPE1
, wc
) & C1_UPPER
);
5573 /******************************************************************************
5574 * IsCharUpperW (kernelbase.@)
5576 BOOL WINAPI DECLSPEC_HOTPATCH
IsCharUpperW( WCHAR wc
)
5578 return !!(get_char_type( CT_CTYPE1
, wc
) & C1_UPPER
);
5582 /******************************************************************************
5583 * IsCharXDigitW (kernelbase.@)
5585 BOOL WINAPI DECLSPEC_HOTPATCH
IsCharXDigitW( WCHAR wc
)
5587 return !!(get_char_type( CT_CTYPE1
, wc
) & C1_XDIGIT
);
5591 /******************************************************************************
5592 * IsDBCSLeadByte (kernelbase.@)
5594 BOOL WINAPI DECLSPEC_HOTPATCH
IsDBCSLeadByte( BYTE testchar
)
5596 return nls_info
.AnsiTableInfo
.DBCSCodePage
&& nls_info
.AnsiTableInfo
.DBCSOffsets
[testchar
];
5600 /******************************************************************************
5601 * IsDBCSLeadByteEx (kernelbase.@)
5603 BOOL WINAPI DECLSPEC_HOTPATCH
IsDBCSLeadByteEx( UINT codepage
, BYTE testchar
)
5605 const CPTABLEINFO
*table
= get_codepage_table( codepage
);
5606 return table
&& table
->DBCSCodePage
&& table
->DBCSOffsets
[testchar
];
5610 /******************************************************************************
5611 * IsNormalizedString (kernelbase.@)
5613 BOOL WINAPI DECLSPEC_HOTPATCH
IsNormalizedString( NORM_FORM form
, const WCHAR
*str
, INT len
)
5616 if (!set_ntstatus( RtlIsNormalizedString( form
, str
, len
, &res
))) res
= FALSE
;
5621 /******************************************************************************
5622 * IsValidCodePage (kernelbase.@)
5624 BOOL WINAPI DECLSPEC_HOTPATCH
IsValidCodePage( UINT codepage
)
5637 return get_codepage_table( codepage
) != NULL
;
5642 /******************************************************************************
5643 * IsValidLanguageGroup (kernelbase.@)
5645 BOOL WINAPI DECLSPEC_HOTPATCH
IsValidLanguageGroup( LGRPID id
, DWORD flags
)
5647 WCHAR name
[10], value
[10];
5648 DWORD type
, value_len
= sizeof(value
);
5652 if (RegOpenKeyExW( nls_key
, L
"Language Groups", 0, KEY_READ
, &key
)) return FALSE
;
5654 swprintf( name
, ARRAY_SIZE(name
), L
"%x", id
);
5655 if (!RegQueryValueExW( key
, name
, NULL
, &type
, (BYTE
*)value
, &value_len
) && type
== REG_SZ
)
5656 ret
= (flags
& LGRPID_SUPPORTED
) || wcstoul( value
, NULL
, 10 );
5663 /******************************************************************************
5664 * IsValidLocale (kernelbase.@)
5666 BOOL WINAPI DECLSPEC_HOTPATCH
IsValidLocale( LCID lcid
, DWORD flags
)
5668 return !!get_locale_by_id( &lcid
, LOCALE_ALLOW_NEUTRAL_NAMES
);
5672 /******************************************************************************
5673 * IsValidLocaleName (kernelbase.@)
5675 BOOL WINAPI DECLSPEC_HOTPATCH
IsValidLocaleName( const WCHAR
*locale
)
5677 if (locale
== LOCALE_NAME_USER_DEFAULT
) return FALSE
;
5678 return !!find_lcname_entry( locale
);
5682 /******************************************************************************
5683 * IsValidNLSVersion (kernelbase.@)
5685 DWORD WINAPI DECLSPEC_HOTPATCH
IsValidNLSVersion( NLS_FUNCTION func
, const WCHAR
*locale
,
5686 NLSVERSIONINFOEX
*info
)
5688 static const GUID GUID_NULL
;
5689 NLSVERSIONINFOEX infoex
;
5692 if (func
!= COMPARE_STRING
)
5694 SetLastError( ERROR_INVALID_PARAMETER
);
5697 if (info
->dwNLSVersionInfoSize
< sizeof(*info
) &&
5698 (info
->dwNLSVersionInfoSize
!= offsetof( NLSVERSIONINFO
, dwEffectiveId
)))
5700 SetLastError( ERROR_INVALID_PARAMETER
);
5703 infoex
.dwNLSVersionInfoSize
= sizeof(infoex
);
5704 if (!GetNLSVersionEx( func
, locale
, &infoex
)) return FALSE
;
5706 ret
= (infoex
.dwNLSVersion
& ~0xff) == (info
->dwNLSVersion
& ~0xff);
5707 if (ret
&& !IsEqualGUID( &info
->guidCustomVersion
, &GUID_NULL
))
5708 ret
= find_sortguid( &info
->guidCustomVersion
) != NULL
;
5710 if (!ret
) SetLastError( ERROR_SUCCESS
);
5715 /***********************************************************************
5716 * LCIDToLocaleName (kernelbase.@)
5718 INT WINAPI DECLSPEC_HOTPATCH
LCIDToLocaleName( LCID lcid
, WCHAR
*name
, INT count
, DWORD flags
)
5720 const NLS_LOCALE_DATA
*locale
= get_locale_by_id( &lcid
, flags
);
5724 SetLastError( ERROR_INVALID_PARAMETER
);
5727 return get_locale_info( locale
, lcid
, LOCALE_SNAME
, name
, count
);
5731 /***********************************************************************
5732 * LCMapStringEx (kernelbase.@)
5734 INT WINAPI DECLSPEC_HOTPATCH
LCMapStringEx( const WCHAR
*locale
, DWORD flags
, const WCHAR
*src
, int srclen
,
5735 WCHAR
*dst
, int dstlen
, NLSVERSIONINFO
*version
,
5736 void *reserved
, LPARAM handle
)
5738 const struct sortguid
*sortid
= NULL
;
5742 if (version
) FIXME( "unsupported version structure %p\n", version
);
5743 if (reserved
) FIXME( "unsupported reserved pointer %p\n", reserved
);
5747 if (!once
++) FIXME( "unsupported lparam %Ix\n", handle
);
5750 if (!src
|| !srclen
|| dstlen
< 0)
5752 SetLastError( ERROR_INVALID_PARAMETER
);
5756 /* mutually exclusive flags */
5757 if ((flags
& (LCMAP_LOWERCASE
| LCMAP_UPPERCASE
)) == (LCMAP_LOWERCASE
| LCMAP_UPPERCASE
) ||
5758 (flags
& (LCMAP_HIRAGANA
| LCMAP_KATAKANA
)) == (LCMAP_HIRAGANA
| LCMAP_KATAKANA
) ||
5759 (flags
& (LCMAP_HALFWIDTH
| LCMAP_FULLWIDTH
)) == (LCMAP_HALFWIDTH
| LCMAP_FULLWIDTH
) ||
5760 (flags
& (LCMAP_TRADITIONAL_CHINESE
| LCMAP_SIMPLIFIED_CHINESE
)) == (LCMAP_TRADITIONAL_CHINESE
| LCMAP_SIMPLIFIED_CHINESE
) ||
5763 SetLastError( ERROR_INVALID_FLAGS
);
5767 if (!dstlen
) dst
= NULL
;
5769 if (flags
& LCMAP_LINGUISTIC_CASING
&& !(sortid
= get_language_sort( locale
)))
5771 FIXME( "unknown locale %s\n", debugstr_w(locale
) );
5772 SetLastError( ERROR_INVALID_PARAMETER
);
5776 if (flags
& LCMAP_SORTKEY
)
5782 SetLastError( ERROR_INVALID_FLAGS
);
5785 if (srclen
< 0) srclen
= lstrlenW(src
);
5787 TRACE( "(%s,0x%08lx,%s,%d,%p,%d)\n",
5788 debugstr_w(locale
), flags
, debugstr_wn(src
, srclen
), srclen
, dst
, dstlen
);
5790 if ((ret
= get_sortkey( flags
, src
, srclen
, (char *)dst
, dstlen
))) ret
++;
5791 else SetLastError( ERROR_INSUFFICIENT_BUFFER
);
5795 /* SORT_STRINGSORT must be used exclusively with LCMAP_SORTKEY */
5796 if (flags
& SORT_STRINGSORT
)
5798 SetLastError( ERROR_INVALID_FLAGS
);
5801 if (((flags
& (NORM_IGNORENONSPACE
| NORM_IGNORESYMBOLS
)) &&
5802 (flags
& ~(NORM_IGNORENONSPACE
| NORM_IGNORESYMBOLS
))) ||
5803 ((flags
& (LCMAP_HIRAGANA
| LCMAP_KATAKANA
| LCMAP_HALFWIDTH
| LCMAP_FULLWIDTH
)) &&
5804 (flags
& (LCMAP_SIMPLIFIED_CHINESE
| LCMAP_TRADITIONAL_CHINESE
))))
5806 SetLastError( ERROR_INVALID_FLAGS
);
5810 if (srclen
< 0) srclen
= lstrlenW(src
) + 1;
5812 TRACE( "(%s,0x%08lx,%s,%d,%p,%d)\n",
5813 debugstr_w(locale
), flags
, debugstr_wn(src
, srclen
), srclen
, dst
, dstlen
);
5815 if (!dst
) /* return required string length */
5817 if (flags
& NORM_IGNORESYMBOLS
)
5819 for (len
= 0; srclen
; src
++, srclen
--)
5820 if (!(get_char_type( CT_CTYPE1
, *src
) & (C1_PUNCT
| C1_SPACE
))) len
++;
5822 else if (flags
& LCMAP_FULLWIDTH
)
5824 for (len
= 0; srclen
; src
++, srclen
--, len
++)
5826 if (compose_katakana( src
, srclen
, NULL
) == 2)
5833 else if (flags
& LCMAP_HALFWIDTH
)
5835 for (len
= 0; srclen
; src
++, srclen
--, len
++)
5838 /* map Hiragana to Katakana before decomposition if needed */
5839 if ((flags
& LCMAP_KATAKANA
) &&
5840 ((wch
>= 0x3041 && wch
<= 0x3096) || wch
== 0x309D || wch
== 0x309E))
5843 if (decompose_katakana( wch
, NULL
, 0 ) == 2) len
++;
5850 if (src
== dst
&& (flags
& ~(LCMAP_LOWERCASE
| LCMAP_UPPERCASE
)))
5852 SetLastError( ERROR_INVALID_FLAGS
);
5856 if (flags
& (NORM_IGNORENONSPACE
| NORM_IGNORESYMBOLS
))
5858 for (len
= dstlen
, dst_ptr
= dst
; srclen
&& len
; src
++, srclen
--)
5860 if ((flags
& NORM_IGNORESYMBOLS
) && (get_char_type( CT_CTYPE1
, *src
) & (C1_PUNCT
| C1_SPACE
)))
5868 if (flags
& (LCMAP_FULLWIDTH
| LCMAP_HALFWIDTH
| LCMAP_HIRAGANA
| LCMAP_KATAKANA
))
5870 for (len
= dstlen
, dst_ptr
= dst
; len
&& srclen
; src
++, srclen
--, len
--, dst_ptr
++)
5873 if (flags
& LCMAP_FULLWIDTH
)
5875 /* map half-width character to full-width one,
5876 e.g. U+FF71 -> U+30A2, U+FF8C U+FF9F -> U+30D7. */
5877 if (map_to_fullwidth( src
, srclen
, &wch
) == 2)
5885 if (flags
& LCMAP_KATAKANA
)
5887 /* map hiragana to katakana, e.g. U+3041 -> U+30A1.
5888 we can't use C3_HIRAGANA as some characters can't map to katakana */
5889 if ((wch
>= 0x3041 && wch
<= 0x3096) || wch
== 0x309D || wch
== 0x309E) wch
+= 0x60;
5891 else if (flags
& LCMAP_HIRAGANA
)
5893 /* map katakana to hiragana, e.g. U+30A1 -> U+3041.
5894 we can't use C3_KATAKANA as some characters can't map to hiragana */
5895 if ((wch
>= 0x30A1 && wch
<= 0x30F6) || wch
== 0x30FD || wch
== 0x30FE) wch
-= 0x60;
5898 if (flags
& LCMAP_HALFWIDTH
)
5900 /* map full-width character to half-width one,
5901 e.g. U+30A2 -> U+FF71, U+30D7 -> U+FF8C U+FF9F. */
5902 if (map_to_halfwidth(wch
, dst_ptr
, len
) == 2)
5909 else *dst_ptr
= wch
;
5911 if (!(flags
& (LCMAP_UPPERCASE
| LCMAP_LOWERCASE
)) || srclen
) goto done
;
5913 srclen
= dst_ptr
- dst
;
5917 if (flags
& (LCMAP_UPPERCASE
| LCMAP_LOWERCASE
))
5919 const USHORT
*table
= sort
.casemap
+ (flags
& LCMAP_LINGUISTIC_CASING
? sortid
->casemap
: 0);
5920 table
= table
+ 2 + (flags
& LCMAP_LOWERCASE
? table
[1] : 0);
5921 for (len
= dstlen
, dst_ptr
= dst
; srclen
&& len
; src
++, srclen
--, len
--)
5922 *dst_ptr
++ = casemap( table
, *src
);
5926 len
= min( srclen
, dstlen
);
5927 memcpy( dst
, src
, len
* sizeof(WCHAR
) );
5928 dst_ptr
= dst
+ len
;
5935 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
5939 return dst_ptr
- dst
;
5943 /***********************************************************************
5944 * LCMapStringA (kernelbase.@)
5946 INT WINAPI DECLSPEC_HOTPATCH
LCMapStringA( LCID lcid
, DWORD flags
, const char *src
, int srclen
,
5947 char *dst
, int dstlen
)
5949 WCHAR
*bufW
= NtCurrentTeb()->StaticUnicodeBuffer
;
5951 INT ret
= 0, srclenW
, dstlenW
;
5952 UINT locale_cp
= CP_ACP
;
5954 if (!src
|| !srclen
|| dstlen
< 0)
5956 SetLastError( ERROR_INVALID_PARAMETER
);
5960 locale_cp
= get_lcid_codepage( lcid
, flags
);
5962 srclenW
= MultiByteToWideChar( locale_cp
, 0, src
, srclen
, bufW
, 260 );
5963 if (srclenW
) srcW
= bufW
;
5966 srclenW
= MultiByteToWideChar( locale_cp
, 0, src
, srclen
, NULL
, 0 );
5967 srcW
= HeapAlloc( GetProcessHeap(), 0, srclenW
* sizeof(WCHAR
) );
5970 SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
5973 MultiByteToWideChar( locale_cp
, 0, src
, srclen
, srcW
, srclenW
);
5976 if (flags
& LCMAP_SORTKEY
)
5980 SetLastError( ERROR_INVALID_FLAGS
);
5983 ret
= LCMapStringEx( NULL
, flags
, srcW
, srclenW
, (WCHAR
*)dst
, dstlen
, NULL
, NULL
, 0 );
5987 if (flags
& SORT_STRINGSORT
)
5989 SetLastError( ERROR_INVALID_FLAGS
);
5993 dstlenW
= LCMapStringEx( NULL
, flags
, srcW
, srclenW
, NULL
, 0, NULL
, NULL
, 0 );
5994 if (!dstlenW
) goto done
;
5996 dstW
= HeapAlloc( GetProcessHeap(), 0, dstlenW
* sizeof(WCHAR
) );
5999 SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
6002 LCMapStringEx( NULL
, flags
, srcW
, srclenW
, dstW
, dstlenW
, NULL
, NULL
, 0 );
6003 ret
= WideCharToMultiByte( locale_cp
, 0, dstW
, dstlenW
, dst
, dstlen
, NULL
, NULL
);
6004 HeapFree( GetProcessHeap(), 0, dstW
);
6007 if (srcW
!= bufW
) HeapFree( GetProcessHeap(), 0, srcW
);
6012 /***********************************************************************
6013 * LCMapStringW (kernelbase.@)
6015 INT WINAPI DECLSPEC_HOTPATCH
LCMapStringW( LCID lcid
, DWORD flags
, const WCHAR
*src
, int srclen
,
6016 WCHAR
*dst
, int dstlen
)
6018 return LCMapStringEx( NULL
, flags
, src
, srclen
, dst
, dstlen
, NULL
, NULL
, 0 );
6022 /***********************************************************************
6023 * LocaleNameToLCID (kernelbase.@)
6025 LCID WINAPI DECLSPEC_HOTPATCH
LocaleNameToLCID( const WCHAR
*name
, DWORD flags
)
6028 const NLS_LOCALE_DATA
*locale
= get_locale_by_name( name
, &lcid
);
6032 SetLastError( ERROR_INVALID_PARAMETER
);
6035 if (!(flags
& LOCALE_ALLOW_NEUTRAL_NAMES
) && !locale
->inotneutral
)
6036 lcid
= locale
->idefaultlanguage
;
6041 /******************************************************************************
6042 * MultiByteToWideChar (kernelbase.@)
6044 INT WINAPI DECLSPEC_HOTPATCH
MultiByteToWideChar( UINT codepage
, DWORD flags
, const char *src
, INT srclen
,
6045 WCHAR
*dst
, INT dstlen
)
6049 if (!src
|| !srclen
|| (!dst
&& dstlen
) || dstlen
< 0)
6051 SetLastError( ERROR_INVALID_PARAMETER
);
6054 if (srclen
< 0) srclen
= strlen(src
) + 1;
6059 ret
= mbstowcs_cpsymbol( flags
, src
, srclen
, dst
, dstlen
);
6062 ret
= mbstowcs_utf7( flags
, src
, srclen
, dst
, dstlen
);
6065 ret
= mbstowcs_utf8( flags
, src
, srclen
, dst
, dstlen
);
6068 if (unix_cp
== CP_UTF8
)
6070 ret
= mbstowcs_utf8( flags
, src
, srclen
, dst
, dstlen
);
6076 ret
= mbstowcs_codepage( codepage
, flags
, src
, srclen
, dst
, dstlen
);
6079 TRACE( "cp %d %s -> %s, ret = %d\n", codepage
, debugstr_an(src
, srclen
), debugstr_wn(dst
, ret
), ret
);
6084 /******************************************************************************
6085 * NormalizeString (kernelbase.@)
6087 INT WINAPI DECLSPEC_HOTPATCH
NormalizeString(NORM_FORM form
, const WCHAR
*src
, INT src_len
,
6088 WCHAR
*dst
, INT dst_len
)
6090 NTSTATUS status
= RtlNormalizeString( form
, src
, src_len
, dst
, &dst_len
);
6094 case STATUS_OBJECT_NAME_NOT_FOUND
:
6095 status
= STATUS_INVALID_PARAMETER
;
6097 case STATUS_BUFFER_TOO_SMALL
:
6098 case STATUS_NO_UNICODE_TRANSLATION
:
6102 SetLastError( RtlNtStatusToDosError( status
));
6107 /******************************************************************************
6108 * ResolveLocaleName (kernelbase.@)
6110 INT WINAPI DECLSPEC_HOTPATCH
ResolveLocaleName( LPCWSTR name
, LPWSTR buffer
, INT len
)
6112 FIXME( "stub: %s, %p, %d\n", wine_dbgstr_w(name
), buffer
, len
);
6114 SetLastError( ERROR_CALL_NOT_IMPLEMENTED
);
6119 /******************************************************************************
6120 * SetLocaleInfoW (kernelbase.@)
6122 BOOL WINAPI DECLSPEC_HOTPATCH
SetLocaleInfoW( LCID lcid
, LCTYPE lctype
, const WCHAR
*data
)
6124 const struct registry_value
*value
;
6128 lctype
= LOWORD(lctype
);
6129 value
= get_locale_registry_value( lctype
);
6131 if (!data
|| !value
)
6133 SetLastError( ERROR_INVALID_PARAMETER
);
6137 if (lctype
== LOCALE_IDATE
|| lctype
== LOCALE_ILDATE
)
6139 SetLastError( ERROR_INVALID_FLAGS
);
6143 TRACE( "setting %lx (%s) to %s\n", lctype
, debugstr_w(value
->name
), debugstr_w(data
) );
6145 /* FIXME: should check that data to set is sane */
6147 status
= RegSetValueExW( intl_key
, value
->name
, 0, REG_SZ
, (BYTE
*)data
, (lstrlenW(data
)+1)*sizeof(WCHAR
) );
6148 index
= value
- registry_values
;
6150 RtlEnterCriticalSection( &locale_section
);
6151 HeapFree( GetProcessHeap(), 0, registry_cache
[index
] );
6152 registry_cache
[index
] = NULL
;
6153 RtlLeaveCriticalSection( &locale_section
);
6155 if (lctype
== LOCALE_SSHORTDATE
|| lctype
== LOCALE_SLONGDATE
)
6157 /* Set I-value from S value */
6158 WCHAR
*pD
, *pM
, *pY
, buf
[2];
6160 pD
= wcschr( data
, 'd' );
6161 pM
= wcschr( data
, 'M' );
6162 pY
= wcschr( data
, 'y' );
6164 if (pD
<= pM
) buf
[0] = '1'; /* D-M-Y */
6165 else if (pY
<= pM
) buf
[0] = '2'; /* Y-M-D */
6166 else buf
[0] = '0'; /* M-D-Y */
6169 lctype
= (lctype
== LOCALE_SSHORTDATE
) ? LOCALE_IDATE
: LOCALE_ILDATE
;
6170 value
= get_locale_registry_value( lctype
);
6171 index
= value
- registry_values
;
6173 RegSetValueExW( intl_key
, value
->name
, 0, REG_SZ
, (BYTE
*)buf
, sizeof(buf
) );
6175 RtlEnterCriticalSection( &locale_section
);
6176 HeapFree( GetProcessHeap(), 0, registry_cache
[index
] );
6177 registry_cache
[index
] = NULL
;
6178 RtlLeaveCriticalSection( &locale_section
);
6180 return set_ntstatus( status
);
6184 /***********************************************************************
6185 * SetCalendarInfoW (kernelbase.@)
6187 INT WINAPI
/* DECLSPEC_HOTPATCH */ SetCalendarInfoW( LCID lcid
, CALID calendar
, CALTYPE type
, const WCHAR
*data
)
6189 FIXME( "(%08lx,%08lx,%08lx,%s): stub\n", lcid
, calendar
, type
, debugstr_w(data
) );
6194 /***********************************************************************
6195 * SetProcessPreferredUILanguages (kernelbase.@)
6197 BOOL WINAPI DECLSPEC_HOTPATCH
SetProcessPreferredUILanguages( DWORD flags
, PCZZWSTR buffer
, ULONG
*count
)
6199 return set_ntstatus( RtlSetProcessPreferredUILanguages( flags
, buffer
, count
));
6203 /***********************************************************************
6204 * SetThreadPreferredUILanguages (kernelbase.@)
6206 BOOL WINAPI DECLSPEC_HOTPATCH
SetThreadPreferredUILanguages( DWORD flags
, PCZZWSTR buffer
, ULONG
*count
)
6208 return set_ntstatus( RtlSetThreadPreferredUILanguages( flags
, buffer
, count
));
6212 /***********************************************************************
6213 * SetTimeZoneInformation (kernelbase.@)
6215 BOOL WINAPI DECLSPEC_HOTPATCH
SetTimeZoneInformation( const TIME_ZONE_INFORMATION
*info
)
6217 return set_ntstatus( RtlSetTimeZoneInformation( (const RTL_TIME_ZONE_INFORMATION
*)info
));
6221 /******************************************************************************
6222 * SetUserGeoID (kernelbase.@)
6224 BOOL WINAPI DECLSPEC_HOTPATCH
SetUserGeoID( GEOID id
)
6226 const struct geoinfo
*geoinfo
= get_geoinfo_ptr( id
);
6232 SetLastError( ERROR_INVALID_PARAMETER
);
6235 if (!RegCreateKeyExW( intl_key
, L
"Geo", 0, NULL
, 0, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
))
6237 const WCHAR
*name
= geoinfo
->kind
== LOCATION_NATION
? L
"Nation" : L
"Region";
6238 swprintf( bufferW
, ARRAY_SIZE(bufferW
), L
"%u", geoinfo
->id
);
6239 RegSetValueExW( hkey
, name
, 0, REG_SZ
, (BYTE
*)bufferW
, (lstrlenW(bufferW
) + 1) * sizeof(WCHAR
) );
6241 if (geoinfo
->kind
== LOCATION_NATION
|| geoinfo
->kind
== LOCATION_BOTH
)
6242 lstrcpyW( bufferW
, geoinfo
->iso2W
);
6244 swprintf( bufferW
, ARRAY_SIZE(bufferW
), L
"%03u", geoinfo
->uncode
);
6245 RegSetValueExW( hkey
, L
"Name", 0, REG_SZ
, (BYTE
*)bufferW
, (lstrlenW(bufferW
) + 1) * sizeof(WCHAR
) );
6246 RegCloseKey( hkey
);
6252 /***********************************************************************
6253 * SystemTimeToTzSpecificLocalTime (kernelbase.@)
6255 BOOL WINAPI DECLSPEC_HOTPATCH
SystemTimeToTzSpecificLocalTime( const TIME_ZONE_INFORMATION
*info
,
6256 const SYSTEMTIME
*system
,
6259 TIME_ZONE_INFORMATION tzinfo
;
6264 RtlQueryTimeZoneInformation( (RTL_TIME_ZONE_INFORMATION
*)&tzinfo
);
6268 if (!SystemTimeToFileTime( system
, (FILETIME
*)&ft
)) return FALSE
;
6269 switch (get_timezone_id( info
, ft
, FALSE
))
6271 case TIME_ZONE_ID_UNKNOWN
:
6272 ft
.QuadPart
-= info
->Bias
* (LONGLONG
)600000000;
6274 case TIME_ZONE_ID_STANDARD
:
6275 ft
.QuadPart
-= (info
->Bias
+ info
->StandardBias
) * (LONGLONG
)600000000;
6277 case TIME_ZONE_ID_DAYLIGHT
:
6278 ft
.QuadPart
-= (info
->Bias
+ info
->DaylightBias
) * (LONGLONG
)600000000;
6283 return FileTimeToSystemTime( (FILETIME
*)&ft
, local
);
6287 /***********************************************************************
6288 * TzSpecificLocalTimeToSystemTime (kernelbase.@)
6290 BOOL WINAPI DECLSPEC_HOTPATCH
TzSpecificLocalTimeToSystemTime( const TIME_ZONE_INFORMATION
*info
,
6291 const SYSTEMTIME
*local
,
6292 SYSTEMTIME
*system
)
6294 TIME_ZONE_INFORMATION tzinfo
;
6299 RtlQueryTimeZoneInformation( (RTL_TIME_ZONE_INFORMATION
*)&tzinfo
);
6303 if (!SystemTimeToFileTime( local
, (FILETIME
*)&ft
)) return FALSE
;
6304 switch (get_timezone_id( info
, ft
, TRUE
))
6306 case TIME_ZONE_ID_UNKNOWN
:
6307 ft
.QuadPart
+= info
->Bias
* (LONGLONG
)600000000;
6309 case TIME_ZONE_ID_STANDARD
:
6310 ft
.QuadPart
+= (info
->Bias
+ info
->StandardBias
) * (LONGLONG
)600000000;
6312 case TIME_ZONE_ID_DAYLIGHT
:
6313 ft
.QuadPart
+= (info
->Bias
+ info
->DaylightBias
) * (LONGLONG
)600000000;
6318 return FileTimeToSystemTime( (FILETIME
*)&ft
, system
);
6322 /***********************************************************************
6323 * VerLanguageNameA (kernelbase.@)
6325 DWORD WINAPI DECLSPEC_HOTPATCH
VerLanguageNameA( DWORD lang
, LPSTR buffer
, DWORD size
)
6327 return GetLocaleInfoA( MAKELCID( lang
, SORT_DEFAULT
), LOCALE_SENGLANGUAGE
, buffer
, size
);
6331 /***********************************************************************
6332 * VerLanguageNameW (kernelbase.@)
6334 DWORD WINAPI DECLSPEC_HOTPATCH
VerLanguageNameW( DWORD lang
, LPWSTR buffer
, DWORD size
)
6336 return GetLocaleInfoW( MAKELCID( lang
, SORT_DEFAULT
), LOCALE_SENGLANGUAGE
, buffer
, size
);
6340 /***********************************************************************
6341 * WideCharToMultiByte (kernelbase.@)
6343 INT WINAPI DECLSPEC_HOTPATCH
WideCharToMultiByte( UINT codepage
, DWORD flags
, LPCWSTR src
, INT srclen
,
6344 LPSTR dst
, INT dstlen
, LPCSTR defchar
, BOOL
*used
)
6348 if (!src
|| !srclen
|| (!dst
&& dstlen
) || dstlen
< 0)
6350 SetLastError( ERROR_INVALID_PARAMETER
);
6354 if (srclen
< 0) srclen
= lstrlenW(src
) + 1;
6359 ret
= wcstombs_cpsymbol( flags
, src
, srclen
, dst
, dstlen
, defchar
, used
);
6362 ret
= wcstombs_utf7( flags
, src
, srclen
, dst
, dstlen
, defchar
, used
);
6365 ret
= wcstombs_utf8( flags
, src
, srclen
, dst
, dstlen
, defchar
, used
);
6368 if (unix_cp
== CP_UTF8
)
6370 if (used
) *used
= FALSE
;
6371 ret
= wcstombs_utf8( flags
, src
, srclen
, dst
, dstlen
, NULL
, NULL
);
6377 ret
= wcstombs_codepage( codepage
, flags
, src
, srclen
, dst
, dstlen
, defchar
, used
);
6380 TRACE( "cp %d %s -> %s, ret = %d\n", codepage
, debugstr_wn(src
, srclen
), debugstr_an(dst
, ret
), ret
);
6385 /***********************************************************************
6386 * GetUserDefaultGeoName (kernelbase.@)
6388 INT WINAPI
GetUserDefaultGeoName(LPWSTR geo_name
, int count
)
6390 const struct geoinfo
*geoinfo
;
6396 TRACE( "geo_name %p, count %d.\n", geo_name
, count
);
6398 if (count
&& !geo_name
)
6400 SetLastError( ERROR_INVALID_PARAMETER
);
6403 if (!(status
= RegOpenKeyExW( intl_key
, L
"Geo", 0, KEY_ALL_ACCESS
, &key
)))
6405 size
= sizeof(buffer
);
6406 status
= RegQueryValueExW( key
, L
"Name", NULL
, NULL
, (BYTE
*)buffer
, &size
);
6411 if ((geoinfo
= get_geoinfo_ptr( GetUserGeoID( GEOCLASS_NATION
))) && geoinfo
->id
!= 39070)
6412 lstrcpyW( buffer
, geoinfo
->iso2W
);
6414 lstrcpyW( buffer
, L
"001" );
6416 size
= lstrlenW( buffer
) + 1;
6421 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
6424 lstrcpyW( geo_name
, buffer
);
6429 /***********************************************************************
6430 * SetUserDefaultGeoName (kernelbase.@)
6432 BOOL WINAPI
SetUserGeoName(PWSTR geo_name
)
6438 TRACE( "geo_name %s.\n", debugstr_w( geo_name
));
6442 SetLastError( ERROR_INVALID_PARAMETER
);
6446 if (lstrlenW( geo_name
) == 3)
6448 uncode
= wcstol( geo_name
, &endptr
, 10 );
6449 if (!uncode
|| endptr
!= geo_name
+ 3)
6451 SetLastError( ERROR_INVALID_PARAMETER
);
6454 for (i
= 0; i
< ARRAY_SIZE(geoinfodata
); ++i
)
6455 if (geoinfodata
[i
].uncode
== uncode
)
6460 if (!lstrcmpiW( geo_name
, L
"XX" ))
6461 return SetUserGeoID( 39070 );
6462 for (i
= 0; i
< ARRAY_SIZE(geoinfodata
); ++i
)
6463 if (!lstrcmpiW( geo_name
, geoinfodata
[i
].iso2W
))
6466 if (i
== ARRAY_SIZE(geoinfodata
))
6468 SetLastError( ERROR_INVALID_PARAMETER
);
6471 return SetUserGeoID( geoinfodata
[i
].id
);