4 * Copyright 2004, 2019 Alexandre Julliard
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #define NONAMELESSUNION
28 #define WIN32_NO_STATUS
32 #include "ntdll_misc.h"
33 #include "wine/debug.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(nls
);
37 /* NLS codepage file format:
40 * WORD offset to cp2uni table in words
42 * WORD MaximumCharacterSize
45 * WORD TransDefaultChar
46 * WORD TransUniDefaultChar
49 * WORD offset to uni2cp table in words
50 * WORD[256] cp2uni table
51 * WORD glyph table size
52 * WORD[glyph_table_size] glyph table
53 * WORD number of lead byte ranges
54 * WORD[256] lead byte offsets in words
55 * WORD[leadbytes][256] cp2uni table for lead bytes
58 * BYTE[65536] / WORD[65536] uni2cp table
63 NLS_SECTION_SORTKEYS
= 9,
64 NLS_SECTION_CASEMAP
= 10,
65 NLS_SECTION_CODEPAGE
= 11,
66 NLS_SECTION_NORMALIZE
= 12
69 UINT NlsAnsiCodePage
= 0;
70 BYTE NlsMbCodePageTag
= 0;
71 BYTE NlsMbOemCodePageTag
= 0;
73 /* NLS normalization file */
76 WCHAR name
[13]; /* 00 file name */
77 USHORT checksum
[3]; /* 1a checksum? */
78 USHORT version
[4]; /* 20 Unicode version */
79 USHORT form
; /* 28 normalization form */
80 USHORT len_factor
; /* 2a factor for length estimates */
81 USHORT unknown1
; /* 2c */
82 USHORT decomp_size
; /* 2e decomposition hash size */
83 USHORT comp_size
; /* 30 composition hash size */
84 USHORT unknown2
; /* 32 */
85 USHORT classes
; /* 34 combining classes table offset */
86 USHORT props_level1
; /* 36 char properties table level 1 offset */
87 USHORT props_level2
; /* 38 char properties table level 2 offset */
88 USHORT decomp_hash
; /* 3a decomposition hash table offset */
89 USHORT decomp_map
; /* 3c decomposition character map table offset */
90 USHORT decomp_seq
; /* 3e decomposition character sequences offset */
91 USHORT comp_hash
; /* 40 composition hash table offset */
92 USHORT comp_seq
; /* 42 composition character sequences offset */
93 /* BYTE[] combining class values */
94 /* BYTE[0x2200] char properties index level 1 */
95 /* BYTE[] char properties index level 2 */
96 /* WORD[] decomposition hash table */
97 /* WORD[] decomposition character map */
98 /* WORD[] decomposition character sequences */
99 /* WORD[] composition hash table */
100 /* WORD[] composition character sequences */
103 LCID user_lcid
= 0, system_lcid
= 0;
105 static NLSTABLEINFO nls_info
;
106 static HMODULE kernel32_handle
;
107 static CPTABLEINFO unix_table
;
108 static struct norm_table
*norm_tables
[16];
111 static NTSTATUS
load_string( ULONG id
, LANGID lang
, WCHAR
*buffer
, ULONG len
)
113 const IMAGE_RESOURCE_DATA_ENTRY
*data
;
114 LDR_RESOURCE_INFO info
;
119 info
.Type
= 6; /* RT_STRING */
120 info
.Name
= (id
>> 4) + 1;
121 info
.Language
= lang
;
122 if ((status
= LdrFindResource_U( kernel32_handle
, &info
, 3, &data
))) return status
;
123 p
= (WCHAR
*)((char *)kernel32_handle
+ data
->OffsetToData
);
124 for (i
= 0; i
< (id
& 0x0f); i
++) p
+= *p
+ 1;
125 if (*p
>= len
) return STATUS_BUFFER_TOO_SMALL
;
126 memcpy( buffer
, p
+ 1, *p
* sizeof(WCHAR
) );
128 return STATUS_SUCCESS
;
132 static DWORD
mbtowc_size( const CPTABLEINFO
*info
, LPCSTR str
, UINT len
)
136 if (!info
->DBCSCodePage
) return len
;
138 for (res
= 0; len
; len
--, str
++, res
++)
140 if (info
->DBCSOffsets
[(unsigned char)*str
] && len
> 1)
150 static DWORD
wctomb_size( const CPTABLEINFO
*info
, LPCWSTR str
, UINT len
)
152 if (info
->DBCSCodePage
)
154 WCHAR
*uni2cp
= info
->WideCharTable
;
157 for (res
= 0; len
; len
--, str
++, res
++)
158 if (uni2cp
[*str
] & 0xff00) res
++;
165 static WCHAR
casemap( USHORT
*table
, WCHAR ch
)
167 return ch
+ table
[table
[table
[ch
>> 8] + ((ch
>> 4) & 0x0f)] + (ch
& 0x0f)];
171 static WCHAR
casemap_ascii( WCHAR ch
)
173 if (ch
>= 'a' && ch
<= 'z') ch
-= 'a' - 'A';
178 static int get_utf16( const WCHAR
*src
, unsigned int srclen
, unsigned int *ch
)
180 if (IS_HIGH_SURROGATE( src
[0] ))
182 if (srclen
<= 1) return 0;
183 if (!IS_LOW_SURROGATE( src
[1] )) return 0;
184 *ch
= 0x10000 + ((src
[0] & 0x3ff) << 10) + (src
[1] & 0x3ff);
187 if (IS_LOW_SURROGATE( src
[0] )) return 0;
192 static void put_utf16( WCHAR
*dst
, unsigned int ch
)
197 dst
[0] = 0xd800 | (ch
>> 10);
198 dst
[1] = 0xdc00 | (ch
& 0x3ff);
204 static NTSTATUS
load_norm_table( ULONG form
, const struct norm_table
**info
)
207 USHORT
*data
, *tables
;
211 if (!form
) return STATUS_INVALID_PARAMETER
;
212 if (form
>= ARRAY_SIZE(norm_tables
)) return STATUS_OBJECT_NAME_NOT_FOUND
;
214 if (!norm_tables
[form
])
216 if ((status
= NtGetNlsSectionPtr( NLS_SECTION_NORMALIZE
, form
, NULL
, (void **)&data
, &size
)))
221 if (size
<= 0x44) goto invalid
;
222 if (data
[0x14] != form
) goto invalid
;
223 tables
= data
+ 0x1a;
224 for (i
= 0; i
< 8; i
++)
226 if (tables
[i
] > size
/ sizeof(USHORT
)) goto invalid
;
227 if (i
&& tables
[i
] < tables
[i
-1]) goto invalid
;
230 if (InterlockedCompareExchangePointer( (void **)&norm_tables
[form
], data
, NULL
))
231 RtlFreeHeap( GetProcessHeap(), 0, data
);
233 *info
= norm_tables
[form
];
234 return STATUS_SUCCESS
;
237 RtlFreeHeap( GetProcessHeap(), 0, data
);
238 return STATUS_INVALID_PARAMETER
;
242 static BYTE
rol( BYTE val
, BYTE count
)
244 return (val
<< count
) | (val
>> (8 - count
));
248 static BYTE
get_char_props( const struct norm_table
*info
, unsigned int ch
)
250 const BYTE
*level1
= (const BYTE
*)((const USHORT
*)info
+ info
->props_level1
);
251 const BYTE
*level2
= (const BYTE
*)((const USHORT
*)info
+ info
->props_level2
);
252 BYTE off
= level1
[ch
/ 128];
254 if (!off
|| off
>= 0xfb) return rol( off
, 5 );
255 return level2
[(off
- 1) * 128 + ch
% 128];
259 #define HANGUL_SBASE 0xac00
260 #define HANGUL_LBASE 0x1100
261 #define HANGUL_VBASE 0x1161
262 #define HANGUL_TBASE 0x11a7
263 #define HANGUL_LCOUNT 19
264 #define HANGUL_VCOUNT 21
265 #define HANGUL_TCOUNT 28
266 #define HANGUL_NCOUNT (HANGUL_VCOUNT * HANGUL_TCOUNT)
267 #define HANGUL_SCOUNT (HANGUL_LCOUNT * HANGUL_NCOUNT)
269 static const WCHAR
*get_decomposition( const struct norm_table
*info
, unsigned int ch
,
270 BYTE props
, WCHAR
*buffer
, unsigned int *ret_len
)
272 const struct pair
{ WCHAR src
; USHORT dst
; } *pairs
;
273 const USHORT
*hash_table
= (const USHORT
*)info
+ info
->decomp_hash
;
275 unsigned int i
, pos
, end
, len
, hash
;
277 /* default to no decomposition */
278 put_utf16( buffer
, ch
);
279 *ret_len
= 1 + (ch
>= 0x10000);
280 if (!props
|| props
== 0x7f) return buffer
;
282 if (props
== 0xff) /* Hangul or invalid char */
284 if (ch
>= HANGUL_SBASE
&& ch
< HANGUL_SBASE
+ HANGUL_SCOUNT
)
286 unsigned short sindex
= ch
- HANGUL_SBASE
;
287 unsigned short tindex
= sindex
% HANGUL_TCOUNT
;
288 buffer
[0] = HANGUL_LBASE
+ sindex
/ HANGUL_NCOUNT
;
289 buffer
[1] = HANGUL_VBASE
+ (sindex
% HANGUL_NCOUNT
) / HANGUL_TCOUNT
;
290 if (tindex
) buffer
[2] = HANGUL_TBASE
+ tindex
;
291 *ret_len
= 2 + !!tindex
;
294 /* ignore other chars in Hangul range */
295 if (ch
>= HANGUL_LBASE
&& ch
< HANGUL_LBASE
+ 0x100) return buffer
;
296 if (ch
>= HANGUL_SBASE
&& ch
< HANGUL_SBASE
+ 0x2c00) return buffer
;
300 hash
= ch
% info
->decomp_size
;
301 pos
= hash_table
[hash
];
304 if (props
!= 0xbf) return buffer
;
305 ret
= (const USHORT
*)info
+ info
->decomp_seq
+ (pos
& 0x1fff);
310 pairs
= (const struct pair
*)((const USHORT
*)info
+ info
->decomp_map
);
312 /* find the end of the hash bucket */
313 for (i
= hash
+ 1; i
< info
->decomp_size
; i
++) if (!(hash_table
[i
] >> 13)) break;
314 if (i
< info
->decomp_size
) end
= hash_table
[i
];
315 else for (end
= pos
; pairs
[end
].src
; end
++) ;
317 for ( ; pos
< end
; pos
++)
319 if (pairs
[pos
].src
!= (WCHAR
)ch
) continue;
320 ret
= (const USHORT
*)info
+ info
->decomp_seq
+ (pairs
[pos
].dst
& 0x1fff);
321 len
= pairs
[pos
].dst
>> 13;
324 if (pos
>= end
) return buffer
;
327 if (len
== 7) while (ret
[len
]) len
++;
328 if (!ret
[0]) len
= 0; /* ignored char */
334 static BYTE
get_combining_class( const struct norm_table
*info
, unsigned int c
)
336 const BYTE
*classes
= (const BYTE
*)((const USHORT
*)info
+ info
->classes
);
337 BYTE
class = get_char_props( info
, c
) & 0x3f;
339 if (class == 0x3f) return 0;
340 return classes
[class];
344 static BOOL
is_starter( const struct norm_table
*info
, unsigned int c
)
346 return !get_combining_class( info
, c
);
350 static BOOL
reorderable_pair( const struct norm_table
*info
, unsigned int c1
, unsigned int c2
)
354 /* reorderable if ccc1 > ccc2 > 0 */
355 ccc1
= get_combining_class( info
, c1
);
356 if (ccc1
< 2) return FALSE
;
357 ccc2
= get_combining_class( info
, c2
);
358 return ccc2
&& (ccc1
> ccc2
);
361 static void canonical_order_substring( const struct norm_table
*info
, WCHAR
*str
, unsigned int len
)
363 unsigned int i
, ch1
, ch2
, len1
, len2
;
369 for (i
= 0; i
< len
- 1; i
+= len1
)
371 if (!(len1
= get_utf16( str
+ i
, len
- i
, &ch1
))) break;
372 if (i
+ len1
>= len
) break;
373 if (!(len2
= get_utf16( str
+ i
+ len1
, len
- i
- len1
, &ch2
))) break;
374 if (reorderable_pair( info
, ch1
, ch2
))
377 memcpy( tmp
, str
+ i
, len1
* sizeof(WCHAR
) );
378 memcpy( str
+ i
, str
+ i
+ len1
, len2
* sizeof(WCHAR
) );
379 memcpy( str
+ i
+ len2
, tmp
, len1
* sizeof(WCHAR
) );
388 /****************************************************************************
389 * canonical_order_string
391 * Reorder the string into canonical order - D108/D109.
393 * Starters (chars with combining class == 0) don't move, so look for continuous
394 * substrings of non-starters and only reorder those.
396 static void canonical_order_string( const struct norm_table
*info
, WCHAR
*str
, unsigned int len
)
398 unsigned int ch
, i
, r
, next
= 0;
400 for (i
= 0; i
< len
; i
+= r
)
402 if (!(r
= get_utf16( str
+ i
, len
- i
, &ch
))) return;
403 if (i
&& is_starter( info
, ch
))
405 if (i
> next
+ 1) /* at least two successive non-starters */
406 canonical_order_substring( info
, str
+ next
, i
- next
);
410 if (i
> next
+ 1) canonical_order_substring( info
, str
+ next
, i
- next
);
414 static NTSTATUS
decompose_string( const struct norm_table
*info
, const WCHAR
*src
, int src_len
,
415 WCHAR
*dst
, int *dst_len
)
418 int src_pos
, dst_pos
;
419 unsigned int ch
, len
, decomp_len
;
423 for (src_pos
= dst_pos
= 0; src_pos
< src_len
; src_pos
+= len
)
425 if (!(len
= get_utf16( src
+ src_pos
, src_len
- src_pos
, &ch
)))
427 *dst_len
= src_pos
+ IS_HIGH_SURROGATE( src
[src_pos
] );
428 return STATUS_NO_UNICODE_TRANSLATION
;
430 props
= get_char_props( info
, ch
);
431 if (!(decomp
= get_decomposition( info
, ch
, props
, buffer
, &decomp_len
)))
433 /* allow final null */
434 if (!ch
&& src_pos
== src_len
- 1 && dst_pos
< *dst_len
)
440 return STATUS_NO_UNICODE_TRANSLATION
;
442 if (dst_pos
+ decomp_len
> *dst_len
)
444 *dst_len
+= (src_len
- src_pos
) * info
->len_factor
;
445 return STATUS_BUFFER_TOO_SMALL
;
447 memcpy( dst
+ dst_pos
, decomp
, decomp_len
* sizeof(WCHAR
) );
448 dst_pos
+= decomp_len
;
451 canonical_order_string( info
, dst
, dst_pos
);
453 return STATUS_SUCCESS
;
457 static unsigned int compose_hangul( unsigned int ch1
, unsigned int ch2
)
459 if (ch1
>= HANGUL_LBASE
&& ch1
< HANGUL_LBASE
+ HANGUL_LCOUNT
)
461 int lindex
= ch1
- HANGUL_LBASE
;
462 int vindex
= ch2
- HANGUL_VBASE
;
463 if (vindex
>= 0 && vindex
< HANGUL_VCOUNT
)
464 return HANGUL_SBASE
+ (lindex
* HANGUL_VCOUNT
+ vindex
) * HANGUL_TCOUNT
;
466 if (ch1
>= HANGUL_SBASE
&& ch1
< HANGUL_SBASE
+ HANGUL_SCOUNT
)
468 int sindex
= ch1
- HANGUL_SBASE
;
469 if (!(sindex
% HANGUL_TCOUNT
))
471 int tindex
= ch2
- HANGUL_TBASE
;
472 if (tindex
> 0 && tindex
< HANGUL_TCOUNT
) return ch1
+ tindex
;
479 static unsigned int compose_chars( const struct norm_table
*info
, unsigned int ch1
, unsigned int ch2
)
481 const USHORT
*table
= (const USHORT
*)info
+ info
->comp_hash
;
482 const WCHAR
*chars
= (const USHORT
*)info
+ info
->comp_seq
;
483 unsigned int hash
, start
, end
, i
, len
, ch
[3];
485 hash
= (ch1
+ 95 * ch2
) % info
->comp_size
;
487 end
= table
[hash
+ 1];
490 for (i
= 0; i
< 3; i
++, start
+= len
) len
= get_utf16( chars
+ start
, end
- start
, ch
+ i
);
491 if (ch
[0] == ch1
&& ch
[1] == ch2
) return ch
[2];
496 static unsigned int compose_string( const struct norm_table
*info
, WCHAR
*str
, unsigned int srclen
)
498 unsigned int i
, ch
, comp
, len
, start_ch
= 0, last_starter
= srclen
;
499 BYTE
class, prev_class
= 0;
501 for (i
= 0; i
< srclen
; i
+= len
)
503 if (!(len
= get_utf16( str
+ i
, srclen
- i
, &ch
))) return 0;
504 class = get_combining_class( info
, ch
);
505 if (last_starter
== srclen
|| (prev_class
&& prev_class
>= class) ||
506 (!(comp
= compose_hangul( start_ch
, ch
)) &&
507 !(comp
= compose_chars( info
, start_ch
, ch
))))
518 int comp_len
= 1 + (comp
>= 0x10000);
519 int start_len
= 1 + (start_ch
>= 0x10000);
521 if (comp_len
!= start_len
)
522 memmove( str
+ last_starter
+ comp_len
, str
+ last_starter
+ start_len
,
523 (i
- (last_starter
+ start_len
)) * sizeof(WCHAR
) );
524 memmove( str
+ i
+ comp_len
- start_len
, str
+ i
+ len
, (srclen
- i
- len
) * sizeof(WCHAR
) );
525 srclen
+= comp_len
- start_len
- len
;
530 put_utf16( str
+ i
, comp
);
537 static NTSTATUS
open_nls_data_file( ULONG type
, ULONG id
, HANDLE
*file
)
539 static const WCHAR pathfmtW
[] = {'\\','?','?','\\','%','s','%','s',0};
540 static const WCHAR keyfmtW
[] =
541 {'\\','R','e','g','i','s','t','r','y','\\','M','a','c','h','i','n','e','\\','S','y','s','t','e','m','\\',
542 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
543 'C','o','n','t','r','o','l','\\','N','l','s','\\','%','s',0};
544 static const WCHAR sortdirW
[] = {'C',':','\\','w','i','n','d','o','w','s','\\',
545 'g','l','o','b','a','l','i','z','a','t','i','o','n','\\',
546 's','o','r','t','i','n','g','\\',0};
547 static const WCHAR cpW
[] = {'C','o','d','e','p','a','g','e',0};
548 static const WCHAR normW
[] = {'N','o','r','m','a','l','i','z','a','t','i','o','n',0};
549 static const WCHAR langW
[] = {'L','a','n','g','u','a','g','e',0};
550 static const WCHAR cpfmtW
[] = {'%','u',0};
551 static const WCHAR normfmtW
[] = {'%','x',0};
552 static const WCHAR langfmtW
[] = {'%','0','4','x',0};
553 static const WCHAR winedatadirW
[] = {'W','I','N','E','D','A','T','A','D','I','R',0};
554 static const WCHAR winebuilddirW
[] = {'W','I','N','E','B','U','I','L','D','D','I','R',0};
555 static const WCHAR dataprefixW
[] = {'\\','n','l','s','\\',0};
556 static const WCHAR cpdefaultW
[] = {'c','_','%','0','3','d','.','n','l','s',0};
557 static const WCHAR intlW
[] = {'l','_','i','n','t','l','.','n','l','s',0};
558 static const WCHAR normnfcW
[] = {'n','o','r','m','n','f','c','.','n','l','s',0};
559 static const WCHAR normnfdW
[] = {'n','o','r','m','n','f','d','.','n','l','s',0};
560 static const WCHAR normnfkcW
[] = {'n','o','r','m','n','f','k','c','.','n','l','s',0};
561 static const WCHAR normnfkdW
[] = {'n','o','r','m','n','f','k','d','.','n','l','s',0};
562 static const WCHAR normidnaW
[] = {'n','o','r','m','i','d','n','a','.','n','l','s',0};
563 static const WCHAR sortkeysW
[] = {'s','o','r','t','d','e','f','a','u','l','t','.','n','l','s',0};
567 NTSTATUS status
= STATUS_OBJECT_NAME_NOT_FOUND
;
569 OBJECT_ATTRIBUTES attr
;
570 UNICODE_STRING nameW
, valueW
;
571 WCHAR buffer
[MAX_PATH
], value
[10];
572 const WCHAR
*name
= NULL
, *dir
= system_dir
;
573 KEY_VALUE_PARTIAL_INFORMATION
*info
;
575 /* get filename from registry */
579 case NLS_SECTION_SORTKEYS
:
580 if (id
) return STATUS_INVALID_PARAMETER_1
;
583 case NLS_SECTION_CASEMAP
:
584 if (id
) return STATUS_UNSUCCESSFUL
;
585 swprintf( buffer
, ARRAY_SIZE(buffer
), keyfmtW
, langW
);
586 swprintf( value
, ARRAY_SIZE(value
), langfmtW
, LANGIDFROMLCID(system_lcid
) );
588 case NLS_SECTION_CODEPAGE
:
589 swprintf( buffer
, ARRAY_SIZE(buffer
), keyfmtW
, cpW
);
590 swprintf( value
, ARRAY_SIZE(value
), cpfmtW
, id
);
592 case NLS_SECTION_NORMALIZE
:
593 swprintf( buffer
, ARRAY_SIZE(buffer
), keyfmtW
, normW
);
594 swprintf( value
, ARRAY_SIZE(value
), normfmtW
, id
);
597 return STATUS_INVALID_PARAMETER_1
;
602 RtlInitUnicodeString( &nameW
, buffer
);
603 RtlInitUnicodeString( &valueW
, value
);
604 InitializeObjectAttributes( &attr
, &nameW
, 0, 0, NULL
);
605 if (!(status
= NtOpenKey( &handle
, KEY_READ
, &attr
)))
607 info
= (KEY_VALUE_PARTIAL_INFORMATION
*)buffer
;
608 size
= sizeof(buffer
) - sizeof(WCHAR
);
609 if (!(status
= NtQueryValueKey( handle
, &valueW
, KeyValuePartialInformation
, info
, size
, &size
)))
611 ((WCHAR
*)info
->Data
)[info
->DataLength
/ sizeof(WCHAR
)] = 0;
612 name
= (WCHAR
*)info
->Data
;
618 if (!name
|| !*name
) /* otherwise some hardcoded defaults */
622 case NLS_SECTION_SORTKEYS
:
626 case NLS_SECTION_CASEMAP
:
629 case NLS_SECTION_CODEPAGE
:
630 swprintf( buffer
, ARRAY_SIZE(buffer
), cpdefaultW
, id
);
633 case NLS_SECTION_NORMALIZE
:
636 case NormalizationC
: name
= normnfcW
; break;
637 case NormalizationD
: name
= normnfdW
; break;
638 case NormalizationKC
: name
= normnfkcW
; break;
639 case NormalizationKD
: name
= normnfkdW
; break;
640 case 13: name
= normidnaW
; break;
644 if (!name
) return status
;
647 /* try to open file in system dir */
649 valueW
.MaximumLength
= (wcslen(name
) + wcslen(dir
) + 5) * sizeof(WCHAR
);
650 if (!(valueW
.Buffer
= RtlAllocateHeap( GetProcessHeap(), 0, valueW
.MaximumLength
)))
651 return STATUS_NO_MEMORY
;
652 valueW
.Length
= swprintf( valueW
.Buffer
, valueW
.MaximumLength
/sizeof(WCHAR
),
653 pathfmtW
, dir
, name
) * sizeof(WCHAR
);
654 InitializeObjectAttributes( &attr
, &valueW
, 0, 0, NULL
);
655 status
= NtOpenFile( file
, GENERIC_READ
, &attr
, &io
, FILE_SHARE_READ
, FILE_SYNCHRONOUS_IO_ALERT
);
656 if (!status
) TRACE( "found %s\n", debugstr_w( valueW
.Buffer
));
657 RtlFreeUnicodeString( &valueW
);
658 if (status
!= STATUS_OBJECT_NAME_NOT_FOUND
&& status
!= STATUS_OBJECT_PATH_NOT_FOUND
) return status
;
660 /* not found, try in build or data dir */
662 RtlInitUnicodeString( &nameW
, winebuilddirW
);
663 valueW
.MaximumLength
= 0;
664 if (RtlQueryEnvironmentVariable_U( NULL
, &nameW
, &valueW
) != STATUS_BUFFER_TOO_SMALL
)
666 RtlInitUnicodeString( &nameW
, winedatadirW
);
667 if (RtlQueryEnvironmentVariable_U( NULL
, &nameW
, &valueW
) != STATUS_BUFFER_TOO_SMALL
)
670 valueW
.MaximumLength
= valueW
.Length
+ sizeof(dataprefixW
) + wcslen(name
) * sizeof(WCHAR
);
671 if (!(valueW
.Buffer
= RtlAllocateHeap( GetProcessHeap(), 0, valueW
.MaximumLength
)))
672 return STATUS_NO_MEMORY
;
673 if (!RtlQueryEnvironmentVariable_U( NULL
, &nameW
, &valueW
))
675 wcscat( valueW
.Buffer
, dataprefixW
);
676 wcscat( valueW
.Buffer
, name
);
677 valueW
.Length
= wcslen(valueW
.Buffer
) * sizeof(WCHAR
);
678 InitializeObjectAttributes( &attr
, &valueW
, 0, 0, NULL
);
679 status
= NtOpenFile( file
, GENERIC_READ
, &attr
, &io
, FILE_SHARE_READ
, FILE_SYNCHRONOUS_IO_ALERT
);
680 if (!status
) TRACE( "found %s\n", debugstr_w( valueW
.Buffer
));
682 RtlFreeUnicodeString( &valueW
);
687 void init_unix_codepage(void)
689 USHORT
*data
= unix_funcs
->get_unix_codepage_data();
690 if (data
) RtlInitCodePageTable( data
, &unix_table
);
694 static LCID
locale_to_lcid( WCHAR
*win_name
)
699 if (!RtlLocaleNameToLcid( win_name
, &lcid
, 0 )) return lcid
;
701 /* try neutral name */
702 if ((p
= wcsrchr( win_name
, '-' )))
705 if (!RtlLocaleNameToLcid( win_name
, &lcid
, 2 ))
707 if (SUBLANGID(lcid
) == SUBLANG_NEUTRAL
)
708 lcid
= MAKELANGID( PRIMARYLANGID(lcid
), SUBLANG_DEFAULT
);
716 /******************************************************************
719 void init_locale( HMODULE module
)
721 WCHAR system_locale
[LOCALE_NAME_MAX_LENGTH
];
722 WCHAR user_locale
[LOCALE_NAME_MAX_LENGTH
];
724 kernel32_handle
= module
;
726 unix_funcs
->get_locales( system_locale
, user_locale
);
727 system_lcid
= locale_to_lcid( system_locale
);
728 user_lcid
= locale_to_lcid( user_locale
);
729 if (!system_lcid
) system_lcid
= MAKELCID( MAKELANGID(LANG_ENGLISH
,SUBLANG_DEFAULT
), SORT_DEFAULT
);
730 if (!user_lcid
) user_lcid
= system_lcid
;
732 NtSetDefaultUILanguage( LANGIDFROMLCID(user_lcid
) );
733 NtSetDefaultLocale( TRUE
, user_lcid
);
734 NtSetDefaultLocale( FALSE
, system_lcid
);
735 TRACE( "system=%04x user=%04x\n", system_lcid
, user_lcid
);
739 /******************************************************************
742 DWORD
ntdll_umbstowcs( const char *src
, DWORD srclen
, WCHAR
*dst
, DWORD dstlen
)
746 if (unix_table
.CodePage
)
747 RtlCustomCPToUnicodeN( &unix_table
, dst
, dstlen
* sizeof(WCHAR
), &reslen
, src
, srclen
);
749 RtlUTF8ToUnicodeN( dst
, dstlen
* sizeof(WCHAR
), &reslen
, src
, srclen
);
750 return reslen
/ sizeof(WCHAR
);
754 /******************************************************************
757 int ntdll_wcstoumbs( const WCHAR
*src
, DWORD srclen
, char *dst
, DWORD dstlen
, BOOL strict
)
761 if (!unix_table
.CodePage
)
762 RtlUnicodeToUTF8N( dst
, dstlen
, &reslen
, src
, srclen
* sizeof(WCHAR
) );
764 RtlUnicodeToCustomCPN( &unix_table
, dst
, dstlen
, &reslen
, src
, srclen
* sizeof(WCHAR
) );
765 else /* do it by hand to make sure every character roundtrips correctly */
767 if (unix_table
.DBCSOffsets
)
769 const unsigned short *uni2cp
= unix_table
.WideCharTable
;
770 for (i
= dstlen
; srclen
&& i
; i
--, srclen
--, src
++)
772 unsigned short ch
= uni2cp
[*src
];
775 if (unix_table
.DBCSOffsets
[unix_table
.DBCSOffsets
[ch
>> 8] + (ch
& 0xff)] != *src
)
777 if (i
== 1) break; /* do not output a partial char */
783 if (unix_table
.MultiByteTable
[ch
] != *src
) return -1;
791 const unsigned char *uni2cp
= unix_table
.WideCharTable
;
792 reslen
= min( srclen
, dstlen
);
793 for (i
= 0; i
< reslen
; i
++)
795 unsigned char ch
= uni2cp
[src
[i
]];
796 if (unix_table
.MultiByteTable
[ch
] != src
[i
]) return -1;
805 /******************************************************************
806 * __wine_get_unix_codepage (NTDLL.@)
808 UINT CDECL
__wine_get_unix_codepage(void)
810 if (!unix_table
.CodePage
) return CP_UTF8
;
811 return unix_table
.CodePage
;
815 static NTSTATUS
get_dummy_preferred_ui_language( DWORD flags
, LANGID lang
, ULONG
*count
,
816 WCHAR
*buffer
, ULONG
*size
)
818 WCHAR name
[LOCALE_NAME_MAX_LENGTH
+ 2];
822 FIXME("(0x%x %p %p %p) returning a dummy value (current locale)\n", flags
, count
, buffer
, size
);
824 status
= load_string( (flags
& MUI_LANGUAGE_ID
) ? LOCALE_ILANGUAGE
: LOCALE_SNAME
,
825 lang
, name
, ARRAY_SIZE(name
) );
826 if (status
) return status
;
828 len
= wcslen( name
) + 2;
835 return STATUS_BUFFER_TOO_SMALL
;
837 memcpy( buffer
, name
, len
* sizeof(WCHAR
) );
841 TRACE("returned variable content: %d, \"%s\", %d\n", *count
, debugstr_w(buffer
), *size
);
842 return STATUS_SUCCESS
;
846 /**************************************************************************
847 * RtlGetProcessPreferredUILanguages (NTDLL.@)
849 NTSTATUS WINAPI
RtlGetProcessPreferredUILanguages( DWORD flags
, ULONG
*count
, WCHAR
*buffer
, ULONG
*size
)
853 FIXME( "%08x, %p, %p %p\n", flags
, count
, buffer
, size
);
855 NtQueryDefaultUILanguage( &ui_language
);
856 return get_dummy_preferred_ui_language( flags
, ui_language
, count
, buffer
, size
);
860 /**************************************************************************
861 * RtlGetSystemPreferredUILanguages (NTDLL.@)
863 NTSTATUS WINAPI
RtlGetSystemPreferredUILanguages( DWORD flags
, ULONG unknown
, ULONG
*count
,
864 WCHAR
*buffer
, ULONG
*size
)
868 if (flags
& ~(MUI_LANGUAGE_NAME
| MUI_LANGUAGE_ID
| MUI_MACHINE_LANGUAGE_SETTINGS
)) return STATUS_INVALID_PARAMETER
;
869 if ((flags
& MUI_LANGUAGE_NAME
) && (flags
& MUI_LANGUAGE_ID
)) return STATUS_INVALID_PARAMETER
;
870 if (*size
&& !buffer
) return STATUS_INVALID_PARAMETER
;
872 NtQueryInstallUILanguage( &ui_language
);
873 return get_dummy_preferred_ui_language( flags
, ui_language
, count
, buffer
, size
);
877 /**************************************************************************
878 * RtlGetThreadPreferredUILanguages (NTDLL.@)
880 NTSTATUS WINAPI
RtlGetThreadPreferredUILanguages( DWORD flags
, ULONG
*count
, WCHAR
*buffer
, ULONG
*size
)
884 FIXME( "%08x, %p, %p %p\n", flags
, count
, buffer
, size
);
886 NtQueryDefaultUILanguage( &ui_language
);
887 return get_dummy_preferred_ui_language( flags
, ui_language
, count
, buffer
, size
);
891 /**************************************************************************
892 * RtlGetUserPreferredUILanguages (NTDLL.@)
894 NTSTATUS WINAPI
RtlGetUserPreferredUILanguages( DWORD flags
, ULONG unknown
, ULONG
*count
,
895 WCHAR
*buffer
, ULONG
*size
)
899 if (flags
& ~(MUI_LANGUAGE_NAME
| MUI_LANGUAGE_ID
)) return STATUS_INVALID_PARAMETER
;
900 if ((flags
& MUI_LANGUAGE_NAME
) && (flags
& MUI_LANGUAGE_ID
)) return STATUS_INVALID_PARAMETER
;
901 if (*size
&& !buffer
) return STATUS_INVALID_PARAMETER
;
903 NtQueryDefaultUILanguage( &ui_language
);
904 return get_dummy_preferred_ui_language( flags
, ui_language
, count
, buffer
, size
);
908 /**************************************************************************
909 * RtlSetProcessPreferredUILanguages (NTDLL.@)
911 NTSTATUS WINAPI
RtlSetProcessPreferredUILanguages( DWORD flags
, PCZZWSTR buffer
, ULONG
*count
)
913 FIXME( "%u, %p, %p\n", flags
, buffer
, count
);
914 return STATUS_SUCCESS
;
918 /**************************************************************************
919 * RtlSetThreadPreferredUILanguages (NTDLL.@)
921 NTSTATUS WINAPI
RtlSetThreadPreferredUILanguages( DWORD flags
, PCZZWSTR buffer
, ULONG
*count
)
923 FIXME( "%u, %p, %p\n", flags
, buffer
, count
);
924 return STATUS_SUCCESS
;
928 /**************************************************************************
929 * NtGetNlsSectionPtr (NTDLL.@)
931 NTSTATUS WINAPI
NtGetNlsSectionPtr( ULONG type
, ULONG id
, void *unknown
, void **ptr
, SIZE_T
*size
)
933 FILE_END_OF_FILE_INFORMATION info
;
938 if ((status
= open_nls_data_file( type
, id
, &file
))) return status
;
940 if ((status
= NtQueryInformationFile( file
, &io
, &info
, sizeof(info
), FileEndOfFileInformation
)))
942 /* FIXME: return a heap block instead of a file mapping for now */
943 if (!(*ptr
= RtlAllocateHeap( GetProcessHeap(), 0, info
.EndOfFile
.QuadPart
)))
945 status
= STATUS_NO_MEMORY
;
948 status
= NtReadFile( file
, 0, NULL
, NULL
, &io
, *ptr
, info
.EndOfFile
.QuadPart
, NULL
, NULL
);
949 if (!status
&& io
.Information
!= info
.EndOfFile
.QuadPart
) status
= STATUS_INVALID_FILE_FOR_SECTION
;
950 if (!status
) *size
= io
.Information
;
951 else RtlFreeHeap( GetProcessHeap(), 0, *ptr
);
958 /******************************************************************
959 * RtlInitCodePageTable (NTDLL.@)
961 void WINAPI
RtlInitCodePageTable( USHORT
*ptr
, CPTABLEINFO
*info
)
963 USHORT hdr_size
= ptr
[0];
965 info
->CodePage
= ptr
[1];
966 info
->MaximumCharacterSize
= ptr
[2];
967 info
->DefaultChar
= ptr
[3];
968 info
->UniDefaultChar
= ptr
[4];
969 info
->TransDefaultChar
= ptr
[5];
970 info
->TransUniDefaultChar
= ptr
[6];
971 memcpy( info
->LeadByte
, ptr
+ 7, sizeof(info
->LeadByte
) );
974 info
->WideCharTable
= ptr
+ ptr
[0] + 1;
975 info
->MultiByteTable
= ++ptr
;
977 if (*ptr
++) ptr
+= 256; /* glyph table */
978 info
->DBCSRanges
= ptr
;
979 if (*ptr
) /* dbcs ranges */
981 info
->DBCSCodePage
= 1;
982 info
->DBCSOffsets
= ptr
+ 1;
986 info
->DBCSCodePage
= 0;
987 info
->DBCSOffsets
= NULL
;
992 /**************************************************************************
993 * RtlInitNlsTables (NTDLL.@)
995 void WINAPI
RtlInitNlsTables( USHORT
*ansi
, USHORT
*oem
, USHORT
*casetable
, NLSTABLEINFO
*info
)
997 RtlInitCodePageTable( ansi
, &info
->AnsiTableInfo
);
998 RtlInitCodePageTable( oem
, &info
->OemTableInfo
);
999 info
->UpperCaseTable
= casetable
+ 2;
1000 info
->LowerCaseTable
= casetable
+ casetable
[1] + 2;
1004 /**************************************************************************
1005 * RtlResetRtlTranslations (NTDLL.@)
1007 void WINAPI
RtlResetRtlTranslations( const NLSTABLEINFO
*info
)
1009 NlsAnsiCodePage
= info
->AnsiTableInfo
.CodePage
;
1010 NlsMbCodePageTag
= info
->AnsiTableInfo
.DBCSCodePage
;
1011 NlsMbOemCodePageTag
= info
->OemTableInfo
.DBCSCodePage
;
1016 /**************************************************************************
1017 * RtlAnsiCharToUnicodeChar (NTDLL.@)
1019 WCHAR WINAPI
RtlAnsiCharToUnicodeChar( char **ansi
)
1021 if (nls_info
.AnsiTableInfo
.DBCSOffsets
)
1023 USHORT off
= nls_info
.AnsiTableInfo
.DBCSOffsets
[(unsigned char)**ansi
];
1027 return nls_info
.AnsiTableInfo
.DBCSOffsets
[off
+ (unsigned char)*(*ansi
)++];
1030 return nls_info
.AnsiTableInfo
.MultiByteTable
[(unsigned char)*(*ansi
)++];
1034 /******************************************************************************
1035 * RtlCompareUnicodeStrings (NTDLL.@)
1037 LONG WINAPI
RtlCompareUnicodeStrings( const WCHAR
*s1
, SIZE_T len1
, const WCHAR
*s2
, SIZE_T len2
,
1038 BOOLEAN case_insensitive
)
1041 SIZE_T len
= min( len1
, len2
);
1043 if (case_insensitive
)
1045 if (nls_info
.UpperCaseTable
)
1047 while (!ret
&& len
--) ret
= casemap( nls_info
.UpperCaseTable
, *s1
++ ) -
1048 casemap( nls_info
.UpperCaseTable
, *s2
++ );
1050 else /* locale not setup yet */
1052 while (!ret
&& len
--) ret
= casemap_ascii( *s1
++ ) - casemap_ascii( *s2
++ );
1057 while (!ret
&& len
--) ret
= *s1
++ - *s2
++;
1059 if (!ret
) ret
= len1
- len2
;
1064 /**************************************************************************
1065 * RtlPrefixUnicodeString (NTDLL.@)
1067 BOOLEAN WINAPI
RtlPrefixUnicodeString( const UNICODE_STRING
*s1
, const UNICODE_STRING
*s2
,
1068 BOOLEAN ignore_case
)
1072 if (s1
->Length
> s2
->Length
) return FALSE
;
1075 for (i
= 0; i
< s1
->Length
/ sizeof(WCHAR
); i
++)
1076 if (casemap( nls_info
.UpperCaseTable
, s1
->Buffer
[i
] ) !=
1077 casemap( nls_info
.UpperCaseTable
, s2
->Buffer
[i
] )) return FALSE
;
1081 for (i
= 0; i
< s1
->Length
/ sizeof(WCHAR
); i
++)
1082 if (s1
->Buffer
[i
] != s2
->Buffer
[i
]) return FALSE
;
1089 /******************************************************************************
1090 * RtlHashUnicodeString (NTDLL.@)
1092 NTSTATUS WINAPI
RtlHashUnicodeString( const UNICODE_STRING
*string
, BOOLEAN case_insensitive
,
1093 ULONG alg
, ULONG
*hash
)
1097 if (!string
|| !hash
) return STATUS_INVALID_PARAMETER
;
1101 case HASH_STRING_ALGORITHM_DEFAULT
:
1102 case HASH_STRING_ALGORITHM_X65599
:
1105 return STATUS_INVALID_PARAMETER
;
1109 if (!case_insensitive
)
1110 for (i
= 0; i
< string
->Length
/ sizeof(WCHAR
); i
++)
1111 *hash
= *hash
* 65599 + string
->Buffer
[i
];
1112 else if (nls_info
.UpperCaseTable
)
1113 for (i
= 0; i
< string
->Length
/ sizeof(WCHAR
); i
++)
1114 *hash
= *hash
* 65599 + casemap( nls_info
.UpperCaseTable
, string
->Buffer
[i
] );
1115 else /* locale not setup yet */
1116 for (i
= 0; i
< string
->Length
/ sizeof(WCHAR
); i
++)
1117 *hash
= *hash
* 65599 + casemap_ascii( string
->Buffer
[i
] );
1118 return STATUS_SUCCESS
;
1122 /**************************************************************************
1123 * RtlCustomCPToUnicodeN (NTDLL.@)
1125 NTSTATUS WINAPI
RtlCustomCPToUnicodeN( CPTABLEINFO
*info
, WCHAR
*dst
, DWORD dstlen
, DWORD
*reslen
,
1126 const char *src
, DWORD srclen
)
1130 dstlen
/= sizeof(WCHAR
);
1131 if (info
->DBCSOffsets
)
1133 for (i
= dstlen
; srclen
&& i
; i
--, srclen
--, src
++, dst
++)
1135 USHORT off
= info
->DBCSOffsets
[(unsigned char)*src
];
1136 if (off
&& srclen
> 1)
1140 *dst
= info
->DBCSOffsets
[off
+ (unsigned char)*src
];
1142 else *dst
= info
->MultiByteTable
[(unsigned char)*src
];
1148 ret
= min( srclen
, dstlen
);
1149 for (i
= 0; i
< ret
; i
++) dst
[i
] = info
->MultiByteTable
[(unsigned char)src
[i
]];
1151 if (reslen
) *reslen
= ret
* sizeof(WCHAR
);
1152 return STATUS_SUCCESS
;
1156 /**************************************************************************
1157 * RtlUnicodeToCustomCPN (NTDLL.@)
1159 NTSTATUS WINAPI
RtlUnicodeToCustomCPN( CPTABLEINFO
*info
, char *dst
, DWORD dstlen
, DWORD
*reslen
,
1160 const WCHAR
*src
, DWORD srclen
)
1164 srclen
/= sizeof(WCHAR
);
1165 if (info
->DBCSCodePage
)
1167 WCHAR
*uni2cp
= info
->WideCharTable
;
1169 for (i
= dstlen
; srclen
&& i
; i
--, srclen
--, src
++)
1171 if (uni2cp
[*src
] & 0xff00)
1173 if (i
== 1) break; /* do not output a partial char */
1175 *dst
++ = uni2cp
[*src
] >> 8;
1177 *dst
++ = (char)uni2cp
[*src
];
1183 char *uni2cp
= info
->WideCharTable
;
1184 ret
= min( srclen
, dstlen
);
1185 for (i
= 0; i
< ret
; i
++) dst
[i
] = uni2cp
[src
[i
]];
1187 if (reslen
) *reslen
= ret
;
1188 return STATUS_SUCCESS
;
1192 /**************************************************************************
1193 * RtlMultiByteToUnicodeN (NTDLL.@)
1195 NTSTATUS WINAPI
RtlMultiByteToUnicodeN( WCHAR
*dst
, DWORD dstlen
, DWORD
*reslen
,
1196 const char *src
, DWORD srclen
)
1198 if (nls_info
.AnsiTableInfo
.WideCharTable
)
1199 return RtlCustomCPToUnicodeN( &nls_info
.AnsiTableInfo
, dst
, dstlen
, reslen
, src
, srclen
);
1201 /* locale not setup yet */
1202 dstlen
= min( srclen
, dstlen
/ sizeof(WCHAR
) );
1203 if (reslen
) *reslen
= dstlen
* sizeof(WCHAR
);
1204 while (dstlen
--) *dst
++ = *src
++ & 0x7f;
1205 return STATUS_SUCCESS
;
1209 /**************************************************************************
1210 * RtlMultiByteToUnicodeSize (NTDLL.@)
1212 NTSTATUS WINAPI
RtlMultiByteToUnicodeSize( DWORD
*size
, const char *str
, DWORD len
)
1214 *size
= mbtowc_size( &nls_info
.AnsiTableInfo
, str
, len
) * sizeof(WCHAR
);
1215 return STATUS_SUCCESS
;
1219 /**************************************************************************
1220 * RtlOemToUnicodeN (NTDLL.@)
1222 NTSTATUS WINAPI
RtlOemToUnicodeN( WCHAR
*dst
, DWORD dstlen
, DWORD
*reslen
,
1223 const char *src
, DWORD srclen
)
1225 return RtlCustomCPToUnicodeN( &nls_info
.OemTableInfo
, dst
, dstlen
, reslen
, src
, srclen
);
1229 /**************************************************************************
1230 * RtlOemStringToUnicodeSize (NTDLL.@)
1231 * RtlxOemStringToUnicodeSize (NTDLL.@)
1233 DWORD WINAPI
RtlOemStringToUnicodeSize( const STRING
*str
)
1235 return (mbtowc_size( &nls_info
.OemTableInfo
, str
->Buffer
, str
->Length
) + 1) * sizeof(WCHAR
);
1239 /**************************************************************************
1240 * RtlUnicodeStringToOemSize (NTDLL.@)
1241 * RtlxUnicodeStringToOemSize (NTDLL.@)
1243 DWORD WINAPI
RtlUnicodeStringToOemSize( const UNICODE_STRING
*str
)
1245 return wctomb_size( &nls_info
.OemTableInfo
, str
->Buffer
, str
->Length
/ sizeof(WCHAR
) ) + 1;
1249 /**************************************************************************
1250 * RtlUnicodeToMultiByteN (NTDLL.@)
1252 NTSTATUS WINAPI
RtlUnicodeToMultiByteN( char *dst
, DWORD dstlen
, DWORD
*reslen
,
1253 const WCHAR
*src
, DWORD srclen
)
1255 if (nls_info
.AnsiTableInfo
.WideCharTable
)
1256 return RtlUnicodeToCustomCPN( &nls_info
.AnsiTableInfo
, dst
, dstlen
, reslen
, src
, srclen
);
1258 /* locale not setup yet */
1259 dstlen
= min( srclen
/ sizeof(WCHAR
), dstlen
);
1260 if (reslen
) *reslen
= dstlen
;
1264 if (ch
> 0x7f) ch
= '?';
1267 return STATUS_SUCCESS
;
1271 /**************************************************************************
1272 * RtlUnicodeToMultiByteSize (NTDLL.@)
1274 NTSTATUS WINAPI
RtlUnicodeToMultiByteSize( DWORD
*size
, const WCHAR
*str
, DWORD len
)
1276 *size
= wctomb_size( &nls_info
.AnsiTableInfo
, str
, len
/ sizeof(WCHAR
) );
1277 return STATUS_SUCCESS
;
1281 /**************************************************************************
1282 * RtlUnicodeToOemN (NTDLL.@)
1284 NTSTATUS WINAPI
RtlUnicodeToOemN( char *dst
, DWORD dstlen
, DWORD
*reslen
,
1285 const WCHAR
*src
, DWORD srclen
)
1287 return RtlUnicodeToCustomCPN( &nls_info
.OemTableInfo
, dst
, dstlen
, reslen
, src
, srclen
);
1291 /**************************************************************************
1292 * RtlDowncaseUnicodeChar (NTDLL.@)
1294 WCHAR WINAPI
RtlDowncaseUnicodeChar( WCHAR wch
)
1296 if (nls_info
.LowerCaseTable
) return casemap( nls_info
.LowerCaseTable
, wch
);
1297 if (wch
>= 'A' && wch
<= 'Z') wch
+= 'a' - 'A';
1302 /**************************************************************************
1303 * RtlDowncaseUnicodeString (NTDLL.@)
1305 NTSTATUS WINAPI
RtlDowncaseUnicodeString( UNICODE_STRING
*dest
, const UNICODE_STRING
*src
,
1308 DWORD i
, len
= src
->Length
;
1312 dest
->MaximumLength
= len
;
1313 if (!(dest
->Buffer
= RtlAllocateHeap( GetProcessHeap(), 0, len
))) return STATUS_NO_MEMORY
;
1315 else if (len
> dest
->MaximumLength
) return STATUS_BUFFER_OVERFLOW
;
1317 for (i
= 0; i
< len
/ sizeof(WCHAR
); i
++)
1318 dest
->Buffer
[i
] = casemap( nls_info
.LowerCaseTable
, src
->Buffer
[i
] );
1320 return STATUS_SUCCESS
;
1324 /**************************************************************************
1325 * RtlUpcaseUnicodeChar (NTDLL.@)
1327 WCHAR WINAPI
RtlUpcaseUnicodeChar( WCHAR wch
)
1329 return casemap( nls_info
.UpperCaseTable
, wch
);
1333 /**************************************************************************
1334 * RtlUpcaseUnicodeString (NTDLL.@)
1336 NTSTATUS WINAPI
RtlUpcaseUnicodeString( UNICODE_STRING
*dest
, const UNICODE_STRING
*src
,
1339 DWORD i
, len
= src
->Length
;
1343 dest
->MaximumLength
= len
;
1344 if (!(dest
->Buffer
= RtlAllocateHeap( GetProcessHeap(), 0, len
))) return STATUS_NO_MEMORY
;
1346 else if (len
> dest
->MaximumLength
) return STATUS_BUFFER_OVERFLOW
;
1348 for (i
= 0; i
< len
/ sizeof(WCHAR
); i
++)
1349 dest
->Buffer
[i
] = casemap( nls_info
.UpperCaseTable
, src
->Buffer
[i
] );
1351 return STATUS_SUCCESS
;
1355 /**************************************************************************
1356 * RtlUpcaseUnicodeToCustomCPN (NTDLL.@)
1358 NTSTATUS WINAPI
RtlUpcaseUnicodeToCustomCPN( CPTABLEINFO
*info
, char *dst
, DWORD dstlen
, DWORD
*reslen
,
1359 const WCHAR
*src
, DWORD srclen
)
1363 srclen
/= sizeof(WCHAR
);
1364 if (info
->DBCSCodePage
)
1366 WCHAR
*uni2cp
= info
->WideCharTable
;
1368 for (i
= dstlen
; srclen
&& i
; i
--, srclen
--, src
++)
1370 WCHAR ch
= casemap( nls_info
.UpperCaseTable
, *src
);
1371 if (uni2cp
[ch
] & 0xff00)
1373 if (i
== 1) break; /* do not output a partial char */
1375 *dst
++ = uni2cp
[ch
] >> 8;
1377 *dst
++ = (char)uni2cp
[ch
];
1383 char *uni2cp
= info
->WideCharTable
;
1384 ret
= min( srclen
, dstlen
);
1385 for (i
= 0; i
< ret
; i
++) dst
[i
] = uni2cp
[casemap( nls_info
.UpperCaseTable
, src
[i
] )];
1387 if (reslen
) *reslen
= ret
;
1388 return STATUS_SUCCESS
;
1392 /**************************************************************************
1393 * RtlUpcaseUnicodeToMultiByteN (NTDLL.@)
1395 NTSTATUS WINAPI
RtlUpcaseUnicodeToMultiByteN( char *dst
, DWORD dstlen
, DWORD
*reslen
,
1396 const WCHAR
*src
, DWORD srclen
)
1398 return RtlUpcaseUnicodeToCustomCPN( &nls_info
.AnsiTableInfo
, dst
, dstlen
, reslen
, src
, srclen
);
1402 /**************************************************************************
1403 * RtlUpcaseUnicodeToOemN (NTDLL.@)
1405 NTSTATUS WINAPI
RtlUpcaseUnicodeToOemN( char *dst
, DWORD dstlen
, DWORD
*reslen
,
1406 const WCHAR
*src
, DWORD srclen
)
1408 if (nls_info
.OemTableInfo
.WideCharTable
)
1409 return RtlUpcaseUnicodeToCustomCPN( &nls_info
.OemTableInfo
, dst
, dstlen
, reslen
, src
, srclen
);
1411 /* locale not setup yet */
1412 dstlen
= min( srclen
/ sizeof(WCHAR
), dstlen
);
1413 if (reslen
) *reslen
= dstlen
;
1417 if (ch
> 0x7f) ch
= '?';
1418 else ch
= casemap_ascii( ch
);
1421 return STATUS_SUCCESS
;
1425 /*********************************************************************
1426 * towlower (NTDLL.@)
1428 WCHAR __cdecl
towlower( WCHAR ch
)
1430 if (ch
>= 0x100) return ch
;
1431 return casemap( nls_info
.LowerCaseTable
, ch
);
1435 /*********************************************************************
1436 * towupper (NTDLL.@)
1438 WCHAR __cdecl
towupper( WCHAR ch
)
1440 if (nls_info
.UpperCaseTable
) return casemap( nls_info
.UpperCaseTable
, ch
);
1441 return casemap_ascii( ch
);
1445 /******************************************************************
1446 * RtlLocaleNameToLcid (NTDLL.@)
1448 NTSTATUS WINAPI
RtlLocaleNameToLcid( const WCHAR
*name
, LCID
*lcid
, ULONG flags
)
1450 /* locale name format is: lang[-script][-country][_modifier] */
1452 static const WCHAR sepW
[] = {'-','_',0};
1454 const IMAGE_RESOURCE_DIRECTORY
*resdir
;
1455 const IMAGE_RESOURCE_DIRECTORY_ENTRY
*et
;
1456 LDR_RESOURCE_INFO info
;
1457 WCHAR buf
[LOCALE_NAME_MAX_LENGTH
];
1458 WCHAR lang
[LOCALE_NAME_MAX_LENGTH
]; /* language ("en") (note: buffer contains the other strings too) */
1459 WCHAR
*country
= NULL
; /* country ("US") */
1460 WCHAR
*script
= NULL
; /* script ("Latn") */
1464 if (!name
) return STATUS_INVALID_PARAMETER_1
;
1468 *lcid
= LANG_INVARIANT
;
1471 if (wcslen( name
) >= LOCALE_NAME_MAX_LENGTH
) return STATUS_INVALID_PARAMETER_1
;
1472 wcscpy( lang
, name
);
1474 if ((p
= wcspbrk( lang
, sepW
)) && *p
== '-')
1478 if ((p
= wcspbrk( p
, sepW
)) && *p
== '-')
1483 p
= wcspbrk( p
, sepW
);
1485 if (p
) *p
= 0; /* FIXME: modifier is ignored */
1486 /* second value can be script or country, check length to resolve the ambiguity */
1487 if (!script
&& wcslen( country
) == 4)
1494 info
.Type
= 6; /* RT_STRING */
1495 info
.Name
= (LOCALE_SNAME
>> 4) + 1;
1496 if (LdrFindResourceDirectory_U( kernel32_handle
, &info
, 2, &resdir
))
1497 return STATUS_INVALID_PARAMETER_1
;
1499 et
= (const IMAGE_RESOURCE_DIRECTORY_ENTRY
*)(resdir
+ 1);
1500 for (i
= 0; i
< resdir
->NumberOfNamedEntries
+ resdir
->NumberOfIdEntries
; i
++)
1502 LANGID id
= et
[i
].u
.Id
;
1504 if (PRIMARYLANGID(id
) == LANG_NEUTRAL
) continue;
1506 if (!load_string( LOCALE_SNAME
, id
, buf
, ARRAY_SIZE(buf
) ) && !wcsicmp( name
, buf
))
1508 *lcid
= MAKELCID( id
, SORT_DEFAULT
); /* FIXME: handle sort order */
1512 if (load_string( LOCALE_SISO639LANGNAME
, id
, buf
, ARRAY_SIZE(buf
) ) || wcsicmp( lang
, buf
))
1517 unsigned int len
= wcslen( script
);
1518 if (load_string( LOCALE_SSCRIPTS
, id
, buf
, ARRAY_SIZE(buf
) )) continue;
1522 if (!wcsnicmp( p
, script
, len
) && (!p
[len
] || p
[len
] == ';')) break;
1523 if (!(p
= wcschr( p
, ';'))) break;
1526 if (!p
|| !*p
) continue;
1529 if (!country
&& (flags
& 2))
1531 if (!script
) id
= MAKELANGID( PRIMARYLANGID(id
), LANG_NEUTRAL
);
1534 case MAKELANGID( LANG_CHINESE
, SUBLANG_NEUTRAL
):
1535 case MAKELANGID( LANG_CHINESE
, SUBLANG_CHINESE_SINGAPORE
):
1536 *lcid
= MAKELCID( 0x7804, SORT_DEFAULT
);
1538 case MAKELANGID( LANG_CHINESE
, SUBLANG_CHINESE_TRADITIONAL
):
1539 case MAKELANGID( LANG_CHINESE
, SUBLANG_CHINESE_MACAU
):
1540 case MAKELANGID( LANG_CHINESE
, SUBLANG_CHINESE_HONGKONG
):
1541 *lcid
= MAKELCID( 0x7c04, SORT_DEFAULT
);
1544 *lcid
= MAKELANGID( PRIMARYLANGID(id
), SUBLANG_NEUTRAL
);
1550 return STATUS_INVALID_PARAMETER_1
;
1553 TRACE( "%s -> %04x\n", debugstr_w(name
), *lcid
);
1554 return STATUS_SUCCESS
;
1558 /* helper for the various utf8 mbstowcs functions */
1559 static unsigned int decode_utf8_char( unsigned char ch
, const char **str
, const char *strend
)
1561 /* number of following bytes in sequence based on first byte value (for bytes above 0x7f) */
1562 static const char utf8_length
[128] =
1564 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x80-0x8f */
1565 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x90-0x9f */
1566 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xa0-0xaf */
1567 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xb0-0xbf */
1568 0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 0xc0-0xcf */
1569 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 0xd0-0xdf */
1570 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, /* 0xe0-0xef */
1571 3,3,3,3,3,0,0,0,0,0,0,0,0,0,0,0 /* 0xf0-0xff */
1574 /* first byte mask depending on UTF-8 sequence length */
1575 static const unsigned char utf8_mask
[4] = { 0x7f, 0x1f, 0x0f, 0x07 };
1577 unsigned int len
= utf8_length
[ch
- 0x80];
1578 unsigned int res
= ch
& utf8_mask
[len
];
1579 const char *end
= *str
+ len
;
1589 if ((ch
= end
[-3] ^ 0x80) >= 0x40) break;
1590 res
= (res
<< 6) | ch
;
1592 if (res
< 0x10) break;
1594 if ((ch
= end
[-2] ^ 0x80) >= 0x40) break;
1595 res
= (res
<< 6) | ch
;
1596 if (res
>= 0x110000 >> 6) break;
1598 if (res
< 0x20) break;
1599 if (res
>= 0xd800 >> 6 && res
<= 0xdfff >> 6) break;
1601 if ((ch
= end
[-1] ^ 0x80) >= 0x40) break;
1602 res
= (res
<< 6) | ch
;
1604 if (res
< 0x80) break;
1611 /**************************************************************************
1612 * RtlUTF8ToUnicodeN (NTDLL.@)
1614 NTSTATUS WINAPI
RtlUTF8ToUnicodeN( WCHAR
*dst
, DWORD dstlen
, DWORD
*reslen
, const char *src
, DWORD srclen
)
1616 unsigned int res
, len
;
1617 NTSTATUS status
= STATUS_SUCCESS
;
1618 const char *srcend
= src
+ srclen
;
1621 if (!src
) return STATUS_INVALID_PARAMETER_4
;
1622 if (!reslen
) return STATUS_INVALID_PARAMETER
;
1624 dstlen
/= sizeof(WCHAR
);
1625 dstend
= dst
+ dstlen
;
1628 for (len
= 0; src
< srcend
; len
++)
1630 unsigned char ch
= *src
++;
1631 if (ch
< 0x80) continue;
1632 if ((res
= decode_utf8_char( ch
, &src
, srcend
)) > 0x10ffff)
1633 status
= STATUS_SOME_NOT_MAPPED
;
1635 if (res
> 0xffff) len
++;
1637 *reslen
= len
* sizeof(WCHAR
);
1641 while ((dst
< dstend
) && (src
< srcend
))
1643 unsigned char ch
= *src
++;
1644 if (ch
< 0x80) /* special fast case for 7-bit ASCII */
1649 if ((res
= decode_utf8_char( ch
, &src
, srcend
)) <= 0xffff)
1653 else if (res
<= 0x10ffff) /* we need surrogates */
1656 *dst
++ = 0xd800 | (res
>> 10);
1657 if (dst
== dstend
) break;
1658 *dst
++ = 0xdc00 | (res
& 0x3ff);
1663 status
= STATUS_SOME_NOT_MAPPED
;
1666 if (src
< srcend
) status
= STATUS_BUFFER_TOO_SMALL
; /* overflow */
1667 *reslen
= (dstlen
- (dstend
- dst
)) * sizeof(WCHAR
);
1672 /**************************************************************************
1673 * RtlUnicodeToUTF8N (NTDLL.@)
1675 NTSTATUS WINAPI
RtlUnicodeToUTF8N( char *dst
, DWORD dstlen
, DWORD
*reslen
, const WCHAR
*src
, DWORD srclen
)
1678 unsigned int val
, len
;
1679 NTSTATUS status
= STATUS_SUCCESS
;
1681 if (!src
) return STATUS_INVALID_PARAMETER_4
;
1682 if (!reslen
) return STATUS_INVALID_PARAMETER
;
1683 if (dst
&& (srclen
& 1)) return STATUS_INVALID_PARAMETER_5
;
1685 srclen
/= sizeof(WCHAR
);
1689 for (len
= 0; srclen
; srclen
--, src
++)
1691 if (*src
< 0x80) len
++; /* 0x00-0x7f: 1 byte */
1692 else if (*src
< 0x800) len
+= 2; /* 0x80-0x7ff: 2 bytes */
1695 if (!get_utf16( src
, srclen
, &val
))
1698 status
= STATUS_SOME_NOT_MAPPED
;
1700 if (val
< 0x10000) len
+= 3; /* 0x800-0xffff: 3 bytes */
1701 else /* 0x10000-0x10ffff: 4 bytes */
1713 for (end
= dst
+ dstlen
; srclen
; srclen
--, src
++)
1717 if (ch
< 0x80) /* 0x00-0x7f: 1 byte */
1719 if (dst
> end
- 1) break;
1723 if (ch
< 0x800) /* 0x80-0x7ff: 2 bytes */
1725 if (dst
> end
- 2) break;
1726 dst
[1] = 0x80 | (ch
& 0x3f);
1732 if (!get_utf16( src
, srclen
, &val
))
1735 status
= STATUS_SOME_NOT_MAPPED
;
1737 if (val
< 0x10000) /* 0x800-0xffff: 3 bytes */
1739 if (dst
> end
- 3) break;
1740 dst
[2] = 0x80 | (val
& 0x3f);
1742 dst
[1] = 0x80 | (val
& 0x3f);
1744 dst
[0] = 0xe0 | val
;
1747 else /* 0x10000-0x10ffff: 4 bytes */
1749 if (dst
> end
- 4) break;
1750 dst
[3] = 0x80 | (val
& 0x3f);
1752 dst
[2] = 0x80 | (val
& 0x3f);
1754 dst
[1] = 0x80 | (val
& 0x3f);
1756 dst
[0] = 0xf0 | val
;
1762 if (srclen
) status
= STATUS_BUFFER_TOO_SMALL
;
1763 *reslen
= dstlen
- (end
- dst
);
1768 /******************************************************************************
1769 * RtlIsNormalizedString (NTDLL.@)
1771 NTSTATUS WINAPI
RtlIsNormalizedString( ULONG form
, const WCHAR
*str
, INT len
, BOOLEAN
*res
)
1773 const struct norm_table
*info
;
1775 BYTE props
, class, last_class
= 0;
1777 int i
, r
, result
= 1;
1779 if ((status
= load_norm_table( form
, &info
))) return status
;
1781 if (len
== -1) len
= wcslen( str
);
1783 for (i
= 0; i
< len
&& result
; i
+= r
)
1785 if (!(r
= get_utf16( str
+ i
, len
- i
, &ch
))) return STATUS_NO_UNICODE_TRANSLATION
;
1786 if (info
->comp_size
)
1788 if ((ch
>= HANGUL_VBASE
&& ch
< HANGUL_VBASE
+ HANGUL_VCOUNT
) ||
1789 (ch
>= HANGUL_TBASE
&& ch
< HANGUL_TBASE
+ HANGUL_TCOUNT
))
1791 result
= -1; /* QC=Maybe */
1795 else if (ch
>= HANGUL_SBASE
&& ch
< HANGUL_SBASE
+ HANGUL_SCOUNT
)
1797 result
= 0; /* QC=No */
1800 props
= get_char_props( info
, ch
);
1801 class = props
& 0x3f;
1805 if (props
== 0xbf) result
= 0; /* QC=No */
1806 else if (props
== 0xff)
1808 /* ignore other chars in Hangul range */
1809 if (ch
>= HANGUL_LBASE
&& ch
< HANGUL_LBASE
+ 0x100) continue;
1810 if (ch
>= HANGUL_SBASE
&& ch
< HANGUL_SBASE
+ 0x2c00) continue;
1811 /* allow final null */
1812 if (!ch
&& i
== len
- 1) continue;
1813 return STATUS_NO_UNICODE_TRANSLATION
;
1816 else if (props
& 0x80)
1818 if ((props
& 0xc0) == 0xc0) result
= -1; /* QC=Maybe */
1819 if (class && class < last_class
) result
= 0; /* QC=No */
1822 else last_class
= 0;
1827 int dstlen
= len
* 4;
1829 WCHAR
*buffer
= RtlAllocateHeap( GetProcessHeap(), 0, dstlen
* sizeof(WCHAR
) );
1830 if (!buffer
) return STATUS_NO_MEMORY
;
1831 status
= RtlNormalizeString( form
, str
, len
, buffer
, &dstlen
);
1832 result
= !status
&& (dstlen
== len
) && !wcsncmp( buffer
, str
, len
);
1833 RtlFreeHeap( GetProcessHeap(), 0, buffer
);
1836 return STATUS_SUCCESS
;
1840 /******************************************************************************
1841 * RtlNormalizeString (NTDLL.@)
1843 NTSTATUS WINAPI
RtlNormalizeString( ULONG form
, const WCHAR
*src
, INT src_len
, WCHAR
*dst
, INT
*dst_len
)
1847 const struct norm_table
*info
;
1848 NTSTATUS status
= STATUS_SUCCESS
;
1850 TRACE( "%x %s %d %p %d\n", form
, debugstr_wn(src
, src_len
), src_len
, dst
, *dst_len
);
1852 if ((status
= load_norm_table( form
, &info
))) return status
;
1854 if (src_len
== -1) src_len
= wcslen(src
) + 1;
1858 *dst_len
= src_len
* info
->len_factor
;
1859 if (*dst_len
> 64) *dst_len
= max( 64, src_len
+ src_len
/ 8 );
1860 return STATUS_SUCCESS
;
1865 return STATUS_SUCCESS
;
1868 if (!info
->comp_size
) return decompose_string( info
, src
, src_len
, dst
, dst_len
);
1870 buf_len
= src_len
* 4;
1873 buf
= RtlAllocateHeap( GetProcessHeap(), 0, buf_len
* sizeof(WCHAR
) );
1874 if (!buf
) return STATUS_NO_MEMORY
;
1875 status
= decompose_string( info
, src
, src_len
, buf
, &buf_len
);
1876 if (status
!= STATUS_BUFFER_TOO_SMALL
) break;
1877 RtlFreeHeap( GetProcessHeap(), 0, buf
);
1881 buf_len
= compose_string( info
, buf
, buf_len
);
1882 if (*dst_len
>= buf_len
) memcpy( dst
, buf
, buf_len
* sizeof(WCHAR
) );
1883 else status
= STATUS_BUFFER_TOO_SMALL
;
1885 RtlFreeHeap( GetProcessHeap(), 0, buf
);
1891 /* Punycode parameters */
1892 enum { BASE
= 36, TMIN
= 1, TMAX
= 26, SKEW
= 38, DAMP
= 700 };
1894 static BOOL
check_invalid_chars( const struct norm_table
*info
, DWORD flags
,
1895 const unsigned int *buffer
, int len
)
1899 for (i
= 0; i
< len
; i
++)
1903 case 0x200c: /* zero-width non-joiner */
1904 case 0x200d: /* zero-width joiner */
1905 if (!i
|| get_combining_class( info
, buffer
[i
- 1] ) != 9) return TRUE
;
1907 case 0x2260: /* not equal to */
1908 case 0x226e: /* not less than */
1909 case 0x226f: /* not greater than */
1910 if (flags
& IDN_USE_STD3_ASCII_RULES
) return TRUE
;
1913 switch (get_char_props( info
, buffer
[i
] ))
1918 if (buffer
[i
] >= HANGUL_SBASE
&& buffer
[i
] < HANGUL_SBASE
+ 0x2c00) break;
1921 if (!(flags
& IDN_ALLOW_UNASSIGNED
)) return TRUE
;
1926 if ((flags
& IDN_USE_STD3_ASCII_RULES
) && len
&& (buffer
[0] == '-' || buffer
[len
- 1] == '-'))
1933 /******************************************************************************
1934 * RtlIdnToAscii (NTDLL.@)
1936 NTSTATUS WINAPI
RtlIdnToAscii( DWORD flags
, const WCHAR
*src
, INT srclen
, WCHAR
*dst
, INT
*dstlen
)
1938 static const WCHAR prefixW
[] = {'x','n','-','-'};
1939 const struct norm_table
*info
;
1941 WCHAR normstr
[256], res
[256];
1942 unsigned int ch
, buffer
[64];
1943 int i
, len
, start
, end
, out_label
, out
= 0, normlen
= ARRAY_SIZE(normstr
);
1945 TRACE( "%x %s %p %d\n", flags
, debugstr_wn(src
, srclen
), dst
, *dstlen
);
1947 if ((status
= load_norm_table( 13, &info
))) return status
;
1949 if ((status
= RtlIdnToNameprepUnicode( flags
, src
, srclen
, normstr
, &normlen
))) return status
;
1951 /* implementation of Punycode based on RFC 3492 */
1953 for (start
= 0; start
< normlen
; start
= end
+ 1)
1955 int n
= 0x80, bias
= 72, delta
= 0, b
= 0, h
, buflen
= 0;
1958 for (i
= start
; i
< normlen
; i
+= len
)
1960 if (!(len
= get_utf16( normstr
+ i
, normlen
- i
, &ch
))) break;
1961 if (!ch
|| ch
== '.') break;
1963 buffer
[buflen
++] = ch
;
1967 if (b
== end
- start
)
1969 if (end
< normlen
) b
++;
1970 if (out
+ b
> ARRAY_SIZE(res
)) return STATUS_INVALID_IDN_NORMALIZATION
;
1971 memcpy( res
+ out
, normstr
+ start
, b
* sizeof(WCHAR
) );
1976 if (buflen
>= 4 && buffer
[2] == '-' && buffer
[3] == '-') return STATUS_INVALID_IDN_NORMALIZATION
;
1977 if (check_invalid_chars( info
, flags
, buffer
, buflen
)) return STATUS_INVALID_IDN_NORMALIZATION
;
1979 if (out
+ 5 + b
> ARRAY_SIZE(res
)) return STATUS_INVALID_IDN_NORMALIZATION
;
1980 memcpy( res
+ out
, prefixW
, sizeof(prefixW
) );
1981 out
+= ARRAY_SIZE(prefixW
);
1984 for (i
= start
; i
< end
; i
++) if (normstr
[i
] < 0x80) res
[out
++] = normstr
[i
];
1988 for (h
= b
; h
< buflen
; delta
++, n
++)
1990 int m
= 0x10ffff, q
, k
;
1992 for (i
= 0; i
< buflen
; i
++) if (buffer
[i
] >= n
&& m
> buffer
[i
]) m
= buffer
[i
];
1993 delta
+= (m
- n
) * (h
+ 1);
1996 for (i
= 0; i
< buflen
; i
++)
2000 for (q
= delta
, k
= BASE
; ; k
+= BASE
)
2002 int t
= k
<= bias
? TMIN
: k
>= bias
+ TMAX
? TMAX
: k
- bias
;
2003 int disp
= q
< t
? q
: t
+ (q
- t
) % (BASE
- t
);
2004 if (out
+ 1 > ARRAY_SIZE(res
)) return STATUS_INVALID_IDN_NORMALIZATION
;
2005 res
[out
++] = disp
<= 25 ? 'a' + disp
: '0' + disp
- 26;
2007 q
= (q
- t
) / (BASE
- t
);
2009 delta
/= (h
== b
? DAMP
: 2);
2010 delta
+= delta
/ (h
+ 1);
2011 for (k
= 0; delta
> ((BASE
- TMIN
) * TMAX
) / 2; k
+= BASE
) delta
/= BASE
- TMIN
;
2012 bias
= k
+ ((BASE
- TMIN
+ 1) * delta
) / (delta
+ SKEW
);
2016 else if (buffer
[i
] < n
) delta
++;
2020 if (out
- out_label
> 63) return STATUS_INVALID_IDN_NORMALIZATION
;
2024 if (out
+ 1 > ARRAY_SIZE(res
)) return STATUS_INVALID_IDN_NORMALIZATION
;
2025 res
[out
++] = normstr
[end
];
2031 if (out
<= *dstlen
) memcpy( dst
, res
, out
* sizeof(WCHAR
) );
2032 else status
= STATUS_BUFFER_TOO_SMALL
;
2039 /******************************************************************************
2040 * RtlIdnToNameprepUnicode (NTDLL.@)
2042 NTSTATUS WINAPI
RtlIdnToNameprepUnicode( DWORD flags
, const WCHAR
*src
, INT srclen
,
2043 WCHAR
*dst
, INT
*dstlen
)
2045 const struct norm_table
*info
;
2049 int i
, start
, len
, buflen
= ARRAY_SIZE(buf
);
2051 if (flags
& ~(IDN_ALLOW_UNASSIGNED
| IDN_USE_STD3_ASCII_RULES
)) return STATUS_INVALID_PARAMETER
;
2052 if (!src
|| srclen
< -1) return STATUS_INVALID_PARAMETER
;
2054 TRACE( "%x %s %p %d\n", flags
, debugstr_wn(src
, srclen
), dst
, *dstlen
);
2056 if ((status
= load_norm_table( 13, &info
))) return status
;
2058 if (srclen
== -1) srclen
= wcslen(src
) + 1;
2060 for (i
= 0; i
< srclen
; i
++) if (src
[i
] < 0x20 || src
[i
] >= 0x7f) break;
2062 if (i
== srclen
|| (i
== srclen
- 1 && !src
[i
])) /* ascii only */
2064 if (srclen
> buflen
) return STATUS_INVALID_IDN_NORMALIZATION
;
2065 memcpy( buf
, src
, srclen
* sizeof(WCHAR
) );
2068 else if ((status
= RtlNormalizeString( 13, src
, srclen
, buf
, &buflen
)))
2070 if (status
== STATUS_NO_UNICODE_TRANSLATION
) status
= STATUS_INVALID_IDN_NORMALIZATION
;
2074 for (i
= start
= 0; i
< buflen
; i
+= len
)
2076 if (!(len
= get_utf16( buf
+ i
, buflen
- i
, &ch
))) break;
2080 if (start
== i
) return STATUS_INVALID_IDN_NORMALIZATION
;
2081 /* maximal label length is 63 characters */
2082 if (i
- start
> 63) return STATUS_INVALID_IDN_NORMALIZATION
;
2083 if ((flags
& IDN_USE_STD3_ASCII_RULES
) && (buf
[start
] == '-' || buf
[i
-1] == '-'))
2084 return STATUS_INVALID_IDN_NORMALIZATION
;
2088 if (flags
& IDN_USE_STD3_ASCII_RULES
)
2090 if ((ch
>= 'a' && ch
<= 'z') || (ch
>= 'A' && ch
<= 'Z') ||
2091 (ch
>= '0' && ch
<= '9') || ch
== '-') continue;
2092 return STATUS_INVALID_IDN_NORMALIZATION
;
2094 if (!(flags
& IDN_ALLOW_UNASSIGNED
))
2096 if (get_char_props( info
, ch
) == 0x7f) return STATUS_INVALID_IDN_NORMALIZATION
;
2099 if (!i
|| i
- start
> 63) return STATUS_INVALID_IDN_NORMALIZATION
;
2100 if ((flags
& IDN_USE_STD3_ASCII_RULES
) && (buf
[start
] == '-' || buf
[i
-1] == '-'))
2101 return STATUS_INVALID_IDN_NORMALIZATION
;
2105 if (buflen
<= *dstlen
) memcpy( dst
, buf
, buflen
* sizeof(WCHAR
) );
2106 else status
= STATUS_BUFFER_TOO_SMALL
;
2113 /******************************************************************************
2114 * RtlIdnToUnicode (NTDLL.@)
2116 NTSTATUS WINAPI
RtlIdnToUnicode( DWORD flags
, const WCHAR
*src
, INT srclen
, WCHAR
*dst
, INT
*dstlen
)
2118 const struct norm_table
*info
;
2119 int i
, buflen
, start
, end
, out_label
, out
= 0;
2124 if (!src
|| srclen
< -1) return STATUS_INVALID_PARAMETER
;
2125 if (srclen
== -1) srclen
= wcslen( src
) + 1;
2127 TRACE( "%x %s %p %d\n", flags
, debugstr_wn(src
, srclen
), dst
, *dstlen
);
2129 if ((status
= load_norm_table( 13, &info
))) return status
;
2131 for (start
= 0; start
< srclen
; )
2133 int n
= 0x80, bias
= 72, pos
= 0, old_pos
, w
, k
, t
, delim
= 0, digit
, delta
;
2136 for (i
= start
; i
< srclen
; i
++)
2139 if (ch
> 0x7f || (i
!= srclen
- 1 && !ch
)) return STATUS_INVALID_IDN_NORMALIZATION
;
2140 if (!ch
|| ch
== '.') break;
2141 if (ch
== '-') delim
= i
;
2143 if (!(flags
& IDN_USE_STD3_ASCII_RULES
)) continue;
2144 if ((ch
>= 'a' && ch
<= 'z') || (ch
>= 'A' && ch
<= 'Z') ||
2145 (ch
>= '0' && ch
<= '9') || ch
== '-')
2147 return STATUS_INVALID_IDN_NORMALIZATION
;
2151 /* last label may be empty */
2152 if (start
== end
&& ch
) return STATUS_INVALID_IDN_NORMALIZATION
;
2154 if (end
- start
< 4 ||
2155 (src
[start
] != 'x' && src
[start
] != 'X') ||
2156 (src
[start
+ 1] != 'n' && src
[start
+ 1] != 'N') ||
2157 src
[start
+ 2] != '-' || src
[start
+ 3] != '-')
2159 if (end
- start
> 63) return STATUS_INVALID_IDN_NORMALIZATION
;
2161 if ((flags
& IDN_USE_STD3_ASCII_RULES
) && (src
[start
] == '-' || src
[end
- 1] == '-'))
2162 return STATUS_INVALID_IDN_NORMALIZATION
;
2164 if (end
< srclen
) end
++;
2167 if (out
+ end
- start
<= *dstlen
)
2168 memcpy( dst
+ out
, src
+ start
, (end
- start
) * sizeof(WCHAR
));
2169 else return STATUS_BUFFER_TOO_SMALL
;
2176 if (delim
== start
+ 3) delim
++;
2178 for (i
= start
+ 4; i
< delim
&& buflen
< ARRAY_SIZE(buffer
); i
++) buffer
[buflen
++] = src
[i
];
2184 for (k
= BASE
; ; k
+= BASE
)
2186 if (i
>= end
) return STATUS_INVALID_IDN_NORMALIZATION
;
2188 if (ch
>= 'a' && ch
<= 'z') digit
= ch
- 'a';
2189 else if (ch
>= 'A' && ch
<= 'Z') digit
= ch
- 'A';
2190 else if (ch
>= '0' && ch
<= '9') digit
= ch
- '0' + 26;
2191 else return STATUS_INVALID_IDN_NORMALIZATION
;
2193 t
= k
<= bias
? TMIN
: k
>= bias
+ TMAX
? TMAX
: k
- bias
;
2194 if (digit
< t
) break;
2198 delta
= (pos
- old_pos
) / (!old_pos
? DAMP
: 2);
2199 delta
+= delta
/ (buflen
+ 1);
2200 for (k
= 0; delta
> ((BASE
- TMIN
) * TMAX
) / 2; k
+= BASE
) delta
/= BASE
- TMIN
;
2201 bias
= k
+ ((BASE
- TMIN
+ 1) * delta
) / (delta
+ SKEW
);
2202 n
+= pos
/ (buflen
+ 1);
2205 if (buflen
>= ARRAY_SIZE(buffer
) - 1) return STATUS_INVALID_IDN_NORMALIZATION
;
2206 memmove( buffer
+ pos
+ 1, buffer
+ pos
, (buflen
- pos
) * sizeof(*buffer
) );
2211 if (check_invalid_chars( info
, flags
, buffer
, buflen
)) return STATUS_INVALID_IDN_NORMALIZATION
;
2213 for (i
= 0; i
< buflen
; i
++)
2215 int len
= 1 + (buffer
[i
] >= 0x10000);
2218 if (out
+ len
<= *dstlen
) put_utf16( dst
+ out
, buffer
[i
] );
2219 else return STATUS_BUFFER_TOO_SMALL
;
2224 if (out
- out_label
> 63) return STATUS_INVALID_IDN_NORMALIZATION
;
2230 if (out
+ 1 <= *dstlen
) dst
[out
] = src
[end
];
2231 else return STATUS_BUFFER_TOO_SMALL
;
2238 return STATUS_SUCCESS
;