2 * National Language Support library
4 * Copyright 1995 Martin von Loewis
5 * Copyright 1998 David Lee Lambert
6 * Copyright 2000 Julio César Gázquez
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 #include "wine/port.h"
37 #include "wine/unicode.h"
42 #include "wine/debug.h"
44 WINE_DEFAULT_DEBUG_CHANNEL(nls
);
47 static const unsigned char LCM_Unicode_LUT
[] = {
81 7 , 29, /* " - 34 */ /* " */
100 12 , 106, /* 5 - 53 */
101 12 , 125, /* 6 - 54 */
102 12 , 144, /* 7 - 55 */
103 12 , 162, /* 8 - 56 */
104 12 , 180, /* 9 - 57 */
114 14 , 10, /* C - 67 */
115 14 , 26, /* D - 68 */
116 14 , 33, /* E - 69 */
117 14 , 35, /* F - 70 */
118 14 , 37, /* G - 71 */
119 14 , 44, /* H - 72 */
120 14 , 50, /* I - 73 */
121 14 , 53, /* J - 74 */
122 14 , 54, /* K - 75 */
123 14 , 72, /* L - 76 */
124 14 , 81, /* M - 77 */
125 14 , 112, /* N - 78 */
126 14 , 124, /* O - 79 */
127 14 , 126, /* P - 80 */
128 14 , 137, /* Q - 81 */
129 14 , 138, /* R - 82 */
130 14 , 145, /* S - 83 */
131 14 , 153, /* T - 84 */
132 14 , 159, /* U - 85 */
133 14 , 162, /* V - 86 */
134 14 , 164, /* W - 87 */
135 14 , 166, /* X - 88 */
136 14 , 167, /* Y - 89 */
137 14 , 169, /* Z - 90 */
146 14 , 10, /* c - 99 */
147 14 , 26, /* d - 100 */
148 14 , 33, /* e - 101 */
149 14 , 35, /* f - 102 */
150 14 , 37, /* g - 103 */
151 14 , 44, /* h - 104 */
152 14 , 50, /* i - 105 */
153 14 , 53, /* j - 106 */
154 14 , 54, /* k - 107 */
155 14 , 72, /* l - 108 */
156 14 , 81, /* m - 109 */
157 14 , 112, /* n - 110 */
158 14 , 124, /* o - 111 */
159 14 , 126, /* p - 112 */
160 14 , 137, /* q - 113 */
161 14 , 138, /* r - 114 */
162 14 , 145, /* s - 115 */
163 14 , 153, /* t - 116 */
164 14 , 159, /* u - 117 */
165 14 , 162, /* v - 118 */
166 14 , 164, /* w - 119 */
167 14 , 166, /* x - 120 */
168 14 , 167, /* y - 121 */
169 14 , 169, /* z - 122 */
170 7 , 74, /* { - 123 */
171 7 , 76, /* | - 124 */
172 7 , 78, /* } - 125 */
173 7 , 80, /* ~ - 126 */
174 6 , 29, /* \x7f - 127 */
175 6 , 30, /* € - 128 */
176 6 , 31, /* � - 129 */
177 7 , 123, /* ‚ - 130 */
178 14 , 35, /* ƒ - 131 */
179 7 , 127, /* „ - 132 */
180 10 , 21, /* … - 133 */
181 10 , 15, /* † - 134 */
182 10 , 16, /* ‡ - 135 */
183 7 , 67, /* ˆ - 136 */
184 10 , 22, /* ‰ - 137 */
185 14 , 145, /* Š - 138 */
186 7 , 136, /* ‹ - 139 */
187 14 + 16 , 124, /* Œ - 140 */
188 6 , 43, /* � - 141 */
189 6 , 44, /* Ž - 142 */
190 6 , 45, /* � - 143 */
191 6 , 46, /* � - 144 */
192 7 , 121, /* ‘ - 145 */
193 7 , 122, /* ’ - 146 */
194 7 , 125, /* “ - 147 */
195 7 , 126, /* ” - 148 */
196 10 , 17, /* • - 149 */
197 6 , 137, /* – - 150 */
198 6 , 139, /* — - 151 */
199 7 , 93, /* ˜ - 152 */
200 14 , 156, /* ™ - 153 */
201 14 , 145, /* š - 154 */
202 7 , 137, /* › - 155 */
203 14 + 16 , 124, /* œ - 156 */
204 6 , 59, /* � - 157 */
205 6 , 60, /* ž - 158 */
206 14 , 167, /* Ÿ - 159 */
208 7 , 81, /* ¡ - 161 */
209 10 , 2, /* ¢ - 162 */
210 10 , 3, /* £ - 163 */
211 10 , 4, /* ¤ - 164 */
212 10 , 5, /* ¥ - 165 */
213 7 , 82, /* ¦ - 166 */
214 10 , 6, /* § - 167 */
215 7 , 83, /* ¨ - 168 */
216 10 , 7, /* © - 169 */
217 14 , 2, /* ª - 170 */
218 8 , 24, /* « - 171 */
219 10 , 8, /* ¬ - 172 */
220 6 , 131, /* - 173 */
221 10 , 9, /* ® - 174 */
222 7 , 84, /* ¯ - 175 */
223 10 , 10, /* ° - 176 */
224 8 , 23, /* ± - 177 */
225 12 , 51, /* ² - 178 */
226 12 , 70, /* ³ - 179 */
227 7 , 85, /* ´ - 180 */
228 10 , 11, /* µ - 181 */
229 10 , 12, /* ¶ - 182 */
230 10 , 13, /* · - 183 */
231 7 , 86, /* ¸ - 184 */
232 12 , 33, /* ¹ - 185 */
233 14 , 124, /* º - 186 */
234 8 , 26, /* » - 187 */
235 12 , 21, /* ¼ - 188 */
236 12 , 25, /* ½ - 189 */
237 12 , 29, /* ¾ - 190 */
238 7 , 87, /* ¿ - 191 */
239 14 , 2, /* À - 192 */
240 14 , 2, /* Á - 193 */
241 14 , 2, /* Â - 194 */
242 14 , 2, /* Ã - 195 */
243 14 , 2, /* Ä - 196 */
244 14 , 2, /* Å - 197 */
245 14 + 16 , 2, /* Æ - 198 */
246 14 , 10, /* Ç - 199 */
247 14 , 33, /* È - 200 */
248 14 , 33, /* É - 201 */
249 14 , 33, /* Ê - 202 */
250 14 , 33, /* Ë - 203 */
251 14 , 50, /* Ì - 204 */
252 14 , 50, /* Í - 205 */
253 14 , 50, /* Î - 206 */
254 14 , 50, /* Ï - 207 */
255 14 , 26, /* Ð - 208 */
256 14 , 112, /* Ñ - 209 */
257 14 , 124, /* Ò - 210 */
258 14 , 124, /* Ó - 211 */
259 14 , 124, /* Ô - 212 */
260 14 , 124, /* Õ - 213 */
261 14 , 124, /* Ö - 214 */
262 8 , 28, /* × - 215 */
263 14 , 124, /* Ø - 216 */
264 14 , 159, /* Ù - 217 */
265 14 , 159, /* Ú - 218 */
266 14 , 159, /* Û - 219 */
267 14 , 159, /* Ü - 220 */
268 14 , 167, /* Ý - 221 */
269 14 + 32 , 153, /* Þ - 222 */
270 14 + 48 , 145, /* ß - 223 */
271 14 , 2, /* à - 224 */
272 14 , 2, /* á - 225 */
273 14 , 2, /* â - 226 */
274 14 , 2, /* ã - 227 */
275 14 , 2, /* ä - 228 */
276 14 , 2, /* å - 229 */
277 14 + 16 , 2, /* æ - 230 */
278 14 , 10, /* ç - 231 */
279 14 , 33, /* è - 232 */
280 14 , 33, /* é - 233 */
281 14 , 33, /* ê - 234 */
282 14 , 33, /* ë - 235 */
283 14 , 50, /* ì - 236 */
284 14 , 50, /* í - 237 */
285 14 , 50, /* î - 238 */
286 14 , 50, /* ï - 239 */
287 14 , 26, /* ð - 240 */
288 14 , 112, /* ñ - 241 */
289 14 , 124, /* ò - 242 */
290 14 , 124, /* ó - 243 */
291 14 , 124, /* ô - 244 */
292 14 , 124, /* õ - 245 */
293 14 , 124, /* ö - 246 */
294 8 , 29, /* ÷ - 247 */
295 14 , 124, /* ø - 248 */
296 14 , 159, /* ù - 249 */
297 14 , 159, /* ú - 250 */
298 14 , 159, /* û - 251 */
299 14 , 159, /* ü - 252 */
300 14 , 167, /* ý - 253 */
301 14 + 32 , 153, /* þ - 254 */
302 14 , 167 /* ÿ - 255 */ };
304 static const unsigned char LCM_Unicode_LUT_2
[] = { 33, 44, 145 };
306 #define LCM_Diacritic_Start 131
308 static const unsigned char LCM_Diacritic_LUT
[] = {
436 /******************************************************************************
437 * OLE2NLS_isPunctuation [INTERNAL]
439 static int OLE2NLS_isPunctuation(unsigned char c
)
441 /* "punctuation character" in this context is a character which is
442 considered "less important" during word sort comparison.
443 See LCMapString implementation for the precise definition
444 of "less important". */
446 return (LCM_Unicode_LUT
[-2+2*c
]==6);
449 /******************************************************************************
450 * OLE2NLS_isNonSpacing [INTERNAL]
452 static int OLE2NLS_isNonSpacing(unsigned char c
)
454 /* This function is used by LCMapStringA. Characters
455 for which it returns true are ignored when mapping a
456 string with NORM_IGNORENONSPACE */
457 return ((c
==136) || (c
==170) || (c
==186));
460 /******************************************************************************
461 * OLE2NLS_isSymbol [INTERNAL]
462 * FIXME: handle current locale
464 static int OLE2NLS_isSymbol(unsigned char c
)
466 /* This function is used by LCMapStringA. Characters
467 for which it returns true are ignored when mapping a
468 string with NORM_IGNORESYMBOLS */
469 return ( (c
!=0) && !(isalpha(c
) || isdigit(c
)) );
472 /******************************************************************************
473 * identity [Internal]
475 static int identity(int c
)
480 /*************************************************************************
481 * LCMapStringA [KERNEL32.@]
483 * Convert a string, or generate a sort key from it.
486 * Success: The length of the string written to dststr.
490 * -If mapflags includes LCMAP_SORTKEY, the function will generate a
491 * sort key for srcstr. Otherwise, srcstr is converted according to
493 * -If scrlen is -1, the function will compute the length of strsrc
494 * (which must be NUL terminated) itself.
495 * -If dstlen is 0, The return value is the buffer length that is needed.
496 * -NORM_IGNOREWIDTH means to compare ASCII and wide characters
497 * as if they are equal.
498 * In the only code page implemented so far, there may not be
499 * wide characters in strings passed to this function,
500 * so there is nothing to be done for this flag.
502 INT WINAPI
LCMapStringA(
503 LCID lcid
, /* [in] Locale Id */
504 DWORD mapflags
, /* [in] Flags */
505 LPCSTR srcstr
, /* [in] Source buffer */
506 INT srclen
, /* [in] Length of srcstr */
507 LPSTR dststr
, /* [out] Destination buffer */
508 INT dstlen
) /* [in] Length of dststr */
512 TRACE("(0x%04lx,0x%08lx,%s,%d,%p,%d)\n",
513 lcid
,mapflags
,debugstr_an(srcstr
,srclen
),srclen
,dststr
,dstlen
);
515 if ( ((dstlen
!=0) && (dststr
==NULL
)) || (srcstr
==NULL
) )
517 ERR("(src=%s,dest=%s): Invalid NULL string\n",
518 debugstr_an(srcstr
,srclen
), dststr
);
519 SetLastError(ERROR_INVALID_PARAMETER
);
523 srclen
= strlen(srcstr
) + 1 ; /* (include final '\0') */
525 #define LCMAPSTRINGA_SUPPORTED_FLAGS (LCMAP_UPPERCASE | \
529 NORM_IGNORENONSPACE | \
533 /* FIXME: as long as we don't support Katakana nor Hiragana
534 * characters, we can support NORM_IGNOREKANATYPE
536 if (mapflags
& ~LCMAPSTRINGA_SUPPORTED_FLAGS
)
538 FIXME("(0x%04lx,0x%08lx,%p,%d,%p,%d): "
539 "unimplemented flags: 0x%08lx\n",
546 mapflags
& ~LCMAPSTRINGA_SUPPORTED_FLAGS
550 if ( !(mapflags
& LCMAP_SORTKEY
) )
553 int (*f
)(int) = identity
;
554 int flag_ignorenonspace
= mapflags
& NORM_IGNORENONSPACE
;
555 int flag_ignoresymbols
= mapflags
& NORM_IGNORESYMBOLS
;
557 if (flag_ignorenonspace
|| flag_ignoresymbols
)
559 /* For some values of mapflags, the length of the resulting
560 string is not known at this point. Windows does map the string
561 and does not SetLastError ERROR_INSUFFICIENT_BUFFER in
565 /* Compute required length */
566 for (i
=j
=0; i
< srclen
; i
++)
568 if ( !(flag_ignorenonspace
&& OLE2NLS_isNonSpacing(srcstr
[i
]))
569 && !(flag_ignoresymbols
&& OLE2NLS_isSymbol(srcstr
[i
])) )
581 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
585 if (mapflags
& LCMAP_UPPERCASE
)
587 else if (mapflags
& LCMAP_LOWERCASE
)
589 /* FIXME: NORM_IGNORENONSPACE requires another conversion */
590 for (i
=j
=0; (i
<srclen
) && (j
<dstlen
) ; i
++)
592 if ( !(flag_ignorenonspace
&& OLE2NLS_isNonSpacing(srcstr
[i
]))
593 && !(flag_ignoresymbols
&& OLE2NLS_isSymbol(srcstr
[i
])) )
595 dststr
[j
] = (CHAR
) f(srcstr
[i
]);
602 /* FIXME: This function completely ignores the "lcid" parameter. */
603 /* else ... (mapflags & LCMAP_SORTKEY) */
608 int delayed_punctuation_len
=0;
609 char *case_component
;
610 char *diacritic_component
;
611 char *delayed_punctuation_component
;
613 int flag_stringsort
= mapflags
& SORT_STRINGSORT
;
615 /* compute how much room we will need */
616 for (i
=0;i
<srclen
;i
++)
619 unsigned char source_char
= srcstr
[i
];
620 if (source_char
!='\0')
622 if (flag_stringsort
|| !OLE2NLS_isPunctuation(source_char
))
625 if ( LCM_Unicode_LUT
[-2+2*source_char
] & ~15 )
626 unicode_len
++; /* double letter */
630 delayed_punctuation_len
++;
634 if (isupper(source_char
))
635 case_len
=unicode_len
;
637 ofs
= source_char
- LCM_Diacritic_Start
;
638 if ((ofs
>=0) && (LCM_Diacritic_LUT
[ofs
]!=2))
639 diacritic_len
=unicode_len
;
642 if (mapflags
& NORM_IGNORECASE
)
644 if (mapflags
& NORM_IGNORENONSPACE
)
647 room
= 2 * unicode_len
/* "unicode" component */
648 + diacritic_len
/* "diacritic" component */
649 + case_len
/* "case" component */
650 + 4 * delayed_punctuation_len
/* punctuation in word sort mode */
651 + 4 /* four '\1' separators */
652 + 1 ; /* terminal '\0' */
655 else if (dstlen
<room
)
657 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
661 /*FIXME the Pointercheck should not be nessesary */
662 if (IsBadWritePtr (dststr
,room
))
663 { ERR("bad destination buffer (dststr) : %p,%d\n",dststr
,dstlen
);
664 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
668 /* locate each component, write separators */
669 diacritic_component
= dststr
+ 2*unicode_len
;
670 *diacritic_component
++ = '\1';
671 case_component
= diacritic_component
+ diacritic_len
;
672 *case_component
++ = '\1';
673 delayed_punctuation_component
= case_component
+ case_len
;
674 *delayed_punctuation_component
++ = '\1';
675 *delayed_punctuation_component
++ = '\1';
677 /* read source string char by char, write
678 corresponding weight in each component. */
679 for (i
=0,count
=0;i
<srclen
;i
++)
681 unsigned char source_char
=srcstr
[i
];
682 if (source_char
!='\0')
685 type
= LCM_Unicode_LUT
[-2+2*source_char
];
686 longcode
= type
>> 4;
688 if (!flag_stringsort
&& OLE2NLS_isPunctuation(source_char
))
690 WORD encrypted_location
= (1<<15) + 7 + 4*count
;
691 *delayed_punctuation_component
++ = (unsigned char) (encrypted_location
>>8);
692 *delayed_punctuation_component
++ = (unsigned char) (encrypted_location
&255);
693 /* big-endian is used here because it lets string comparison be
694 compatible with numerical comparison */
696 *delayed_punctuation_component
++ = type
;
697 *delayed_punctuation_component
++ = LCM_Unicode_LUT
[-1+2*source_char
];
698 /* assumption : a punctuation character is never a
699 double or accented letter */
703 dststr
[2*count
] = type
;
704 dststr
[2*count
+1] = LCM_Unicode_LUT
[-1+2*source_char
];
708 case_component
[count
] = ( isupper(source_char
) ? 18 : 2 ) ;
709 if (count
<diacritic_len
)
710 diacritic_component
[count
] = 2; /* assumption: a double letter
714 dststr
[2*count
] = type
;
715 dststr
[2*count
+1] = *(LCM_Unicode_LUT_2
- 1 + longcode
);
716 /* 16 in the first column of LCM_Unicode_LUT --> longcode = 1
717 32 in the first column of LCM_Unicode_LUT --> longcode = 2
718 48 in the first column of LCM_Unicode_LUT --> longcode = 3 */
722 case_component
[count
] = ( isupper(source_char
) ? 18 : 2 ) ;
723 if (count
<diacritic_len
)
725 int ofs
= source_char
- LCM_Diacritic_Start
;
726 diacritic_component
[count
] = (ofs
>=0 ? LCM_Diacritic_LUT
[ofs
] : 2);
732 dststr
[room
-1] = '\0';
737 /*************************************************************************
738 * LCMapStringW [KERNEL32.@]
742 INT WINAPI
LCMapStringW(
743 LCID lcid
,DWORD mapflags
,LPCWSTR srcstr
,INT srclen
,LPWSTR dststr
,
748 TRACE("(0x%04lx,0x%08lx,%p,%d,%p,%d)\n",
749 lcid
, mapflags
, srcstr
, srclen
, dststr
, dstlen
);
751 if ( ((dstlen
!=0) && (dststr
==NULL
)) || (srcstr
==NULL
) )
753 ERR("(src=%p,dst=%p): Invalid NULL string\n", srcstr
, dststr
);
754 SetLastError(ERROR_INVALID_PARAMETER
);
758 srclen
= strlenW(srcstr
)+1;
760 /* FIXME: Both this function and it's companion LCMapStringA()
761 * completely ignore the "lcid" parameter. In place of the "lcid"
762 * parameter the application must set the "LC_COLLATE" or "LC_ALL"
763 * environment variable prior to invoking this function. */
764 if (mapflags
& LCMAP_SORTKEY
)
766 /* Possible values of LC_COLLATE. */
767 char *lc_collate_default
= 0; /* value prior to this function */
768 char *lc_collate_env
= 0; /* value retrieved from the environment */
770 /* General purpose index into strings of any type. */
773 /* Lengths of various strings where the length is measured in
774 * wide characters for wide character strings and in bytes for
775 * native strings. The lengths include the NULL terminator. */
776 size_t returned_len
= 0;
777 size_t src_native_len
= 0;
778 size_t dst_native_len
= 0;
779 size_t dststr_libc_len
= 0;
781 /* Native (character set determined by locale) versions of the
782 * strings source and destination strings. */
783 LPSTR src_native
= 0;
784 LPSTR dst_native
= 0;
786 /* Version of the source and destination strings using the
787 * "wchar_t" Unicode data type needed by various libc functions. */
788 wchar_t *srcstr_libc
= 0;
789 wchar_t *dststr_libc
= 0;
791 if(!(srcstr_libc
= (wchar_t *)HeapAlloc(GetProcessHeap(), 0,
792 srclen
* sizeof(wchar_t))))
794 ERR("Unable to allocate %d bytes for srcstr_libc\n",
795 srclen
* sizeof(wchar_t));
796 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
800 /* Convert source string to a libc Unicode string. */
801 for(str_idx
= 0; str_idx
< srclen
; str_idx
++)
803 srcstr_libc
[str_idx
] = srcstr
[str_idx
];
806 /* src_native should contain at most 3 bytes for each
807 * multibyte characters in the original srcstr string. */
808 src_native_len
= 3 * srclen
;
809 if(!(src_native
= (LPSTR
)HeapAlloc(GetProcessHeap(), 0,
812 ERR("Unable to allocate %d bytes for src_native\n", src_native_len
);
813 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
814 if(srcstr_libc
) HeapFree(GetProcessHeap(), 0, srcstr_libc
);
818 /* FIXME: Prior to to setting the LC_COLLATE locale category the
819 * current value is backed up so it can be restored after the
820 * last LC_COLLATE sensitive function returns.
822 * Even though the locale is adjusted for a minimum amount of
823 * time a race condition exists where other threads may be
824 * affected if they invoke LC_COLLATE sensitive functions. One
825 * possible solution is to wrap all LC_COLLATE sensitive Wine
826 * functions, like LCMapStringW(), in a mutex.
828 * Another enhancement to the following would be to set the
829 * LC_COLLATE locale category as a function of the "lcid"
830 * parameter instead of the "LC_COLLATE" environment variable. */
831 if(!(lc_collate_default
= setlocale(LC_COLLATE
, NULL
)))
833 ERR("Unable to query the LC_COLLATE catagory\n");
834 SetLastError(ERROR_INVALID_PARAMETER
);
835 if(srcstr_libc
) HeapFree(GetProcessHeap(), 0, srcstr_libc
);
836 if(src_native
) HeapFree(GetProcessHeap(), 0, src_native
);
840 if(!(lc_collate_env
= setlocale(LC_COLLATE
, "")))
842 ERR("Unable to inherit the LC_COLLATE locale category from the "
843 "environment. The \"LC_COLLATE\" environment variable is "
844 "\"%s\".\n", getenv("LC_COLLATE") ?
845 getenv("LC_COLLATE") : "<unset>");
846 SetLastError(ERROR_INVALID_PARAMETER
);
847 if(srcstr_libc
) HeapFree(GetProcessHeap(), 0, srcstr_libc
);
848 if(src_native
) HeapFree(GetProcessHeap(), 0, src_native
);
852 TRACE("lc_collate_default = %s\n", lc_collate_default
);
853 TRACE("lc_collate_env = %s\n", lc_collate_env
);
855 /* Convert the libc Unicode string to a native multibyte character
857 returned_len
= wcstombs(src_native
, srcstr_libc
, src_native_len
) + 1;
858 if(returned_len
== 0)
860 ERR("wcstombs failed. The string specified (%s) may contain an invalid character.\n",
862 SetLastError(ERROR_INVALID_PARAMETER
);
863 if(srcstr_libc
) HeapFree(GetProcessHeap(), 0, srcstr_libc
);
864 if(src_native
) HeapFree(GetProcessHeap(), 0, src_native
);
865 setlocale(LC_COLLATE
, lc_collate_default
);
868 else if(returned_len
> src_native_len
)
870 src_native
[src_native_len
- 1] = 0;
871 ERR("wcstombs returned a string (%s) that was longer (%d bytes) "
872 "than expected (%d bytes).\n", src_native
, returned_len
,
875 /* Since this is an internal error I'm not sure what the correct
877 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
879 if(srcstr_libc
) HeapFree(GetProcessHeap(), 0, srcstr_libc
);
880 if(src_native
) HeapFree(GetProcessHeap(), 0, src_native
);
881 setlocale(LC_COLLATE
, lc_collate_default
);
884 src_native_len
= returned_len
;
886 TRACE("src_native = %s src_native_len = %d\n",
887 src_native
, src_native_len
);
889 /* dst_native seems to contain at most 4 bytes for each byte in
890 * the original src_native string. Change if need be since this
891 * isn't documented by the strxfrm() man page. */
892 dst_native_len
= 4 * src_native_len
;
893 if(!(dst_native
= (LPSTR
)HeapAlloc(GetProcessHeap(), 0, dst_native_len
)))
895 ERR("Unable to allocate %d bytes for dst_native\n", dst_native_len
);
896 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
897 if(srcstr_libc
) HeapFree(GetProcessHeap(), 0, srcstr_libc
);
898 if(src_native
) HeapFree(GetProcessHeap(), 0, src_native
);
899 setlocale(LC_COLLATE
, lc_collate_default
);
903 /* The actual translation is done by the following call to
904 * strxfrm(). The surrounding code could have been simplified
905 * by calling wcsxfrm() instead except that wcsxfrm() is not
906 * available on older Linux systems (RedHat 4.1 with
909 * Also, it is possible that the translation could be done by
910 * various tables as it is done in LCMapStringA(). However, I'm
911 * not sure what those tables are. */
912 returned_len
= strxfrm(dst_native
, src_native
, dst_native_len
) + 1;
914 if(returned_len
> dst_native_len
)
916 dst_native
[dst_native_len
- 1] = 0;
917 ERR("strxfrm returned a string (%s) that was longer (%d bytes) "
918 "than expected (%d bytes).\n", dst_native
, returned_len
,
921 /* Since this is an internal error I'm not sure what the correct
923 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
925 if(srcstr_libc
) HeapFree(GetProcessHeap(), 0, srcstr_libc
);
926 if(src_native
) HeapFree(GetProcessHeap(), 0, src_native
);
927 if(dst_native
) HeapFree(GetProcessHeap(), 0, dst_native
);
928 setlocale(LC_COLLATE
, lc_collate_default
);
931 dst_native_len
= returned_len
;
933 TRACE("dst_native = %s dst_native_len = %d\n",
934 dst_native
, dst_native_len
);
936 dststr_libc_len
= dst_native_len
;
937 if(!(dststr_libc
= (wchar_t *)HeapAlloc(GetProcessHeap(), 0,
938 dststr_libc_len
* sizeof(wchar_t))))
940 ERR("Unable to allocate %d bytes for dststr_libc\n",
941 dststr_libc_len
* sizeof(wchar_t));
942 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
943 if(srcstr_libc
) HeapFree(GetProcessHeap(), 0, srcstr_libc
);
944 if(src_native
) HeapFree(GetProcessHeap(), 0, src_native
);
945 if(dst_native
) HeapFree(GetProcessHeap(), 0, dst_native
);
946 setlocale(LC_COLLATE
, lc_collate_default
);
950 /* Convert the native multibyte string to a libc Unicode string. */
951 returned_len
= mbstowcs(dststr_libc
, dst_native
, dst_native_len
) + 1;
953 /* Restore LC_COLLATE now that the last LC_COLLATE sensitive
954 * function has returned. */
955 setlocale(LC_COLLATE
, lc_collate_default
);
957 if(returned_len
== 0)
959 ERR("mbstowcs failed. The native version of the translated string "
960 "(%s) may contain an invalid character.\n", dst_native
);
961 SetLastError(ERROR_INVALID_PARAMETER
);
962 if(srcstr_libc
) HeapFree(GetProcessHeap(), 0, srcstr_libc
);
963 if(src_native
) HeapFree(GetProcessHeap(), 0, src_native
);
964 if(dst_native
) HeapFree(GetProcessHeap(), 0, dst_native
);
965 if(dststr_libc
) HeapFree(GetProcessHeap(), 0, dststr_libc
);
970 if(returned_len
> dstlen
)
972 ERR("mbstowcs returned a string that was longer (%d chars) "
973 "than the buffer provided (%d chars).\n", returned_len
,
975 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
976 if(srcstr_libc
) HeapFree(GetProcessHeap(), 0, srcstr_libc
);
977 if(src_native
) HeapFree(GetProcessHeap(), 0, src_native
);
978 if(dst_native
) HeapFree(GetProcessHeap(), 0, dst_native
);
979 if(dststr_libc
) HeapFree(GetProcessHeap(), 0, dststr_libc
);
982 dstlen
= returned_len
;
984 /* Convert a libc Unicode string to the destination string. */
985 for(str_idx
= 0; str_idx
< dstlen
; str_idx
++)
987 dststr
[str_idx
] = dststr_libc
[str_idx
];
989 TRACE("1st 4 int sized chunks of dststr = %x %x %x %x\n",
990 *(((int *)dststr
) + 0),
991 *(((int *)dststr
) + 1),
992 *(((int *)dststr
) + 2),
993 *(((int *)dststr
) + 3));
997 dstlen
= returned_len
;
999 TRACE("dstlen (return) = %d\n", dstlen
);
1000 if(srcstr_libc
) HeapFree(GetProcessHeap(), 0, srcstr_libc
);
1001 if(src_native
) HeapFree(GetProcessHeap(), 0, src_native
);
1002 if(dst_native
) HeapFree(GetProcessHeap(), 0, dst_native
);
1003 if(dststr_libc
) HeapFree(GetProcessHeap(), 0, dststr_libc
);
1008 int (*f
)(int)=identity
;
1014 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
1018 if (mapflags
& LCMAP_UPPERCASE
)
1020 else if (mapflags
& LCMAP_LOWERCASE
)
1022 for (i
=0; i
< srclen
; i
++)
1023 dststr
[i
] = (WCHAR
) f(srcstr
[i
]);
1029 /***********************************************************************
1030 * OLE2NLS_EstimateMappingLength
1032 * Estimates the number of characters required to hold the string
1033 * computed by LCMapStringA.
1035 * The size is always over-estimated, with a fixed limit on the
1036 * amount of estimation error.
1038 * Note that len == -1 is not permitted.
1040 static inline int OLE2NLS_EstimateMappingLength(LCID lcid
, DWORD dwMapFlags
,
1041 LPCSTR str
, DWORD len
)
1043 /* Estimate only for small strings to keep the estimation error from
1044 * becoming too large. */
1045 if (len
< 128) return len
* 8 + 5;
1046 else return LCMapStringA(lcid
, dwMapFlags
, str
, len
, NULL
, 0);
1049 /******************************************************************************
1050 * CompareStringA [KERNEL32.@]
1051 * Compares two strings using locale
1055 * success: CSTR_LESS_THAN, CSTR_EQUAL, CSTR_GREATER_THAN
1060 * Defaults to a word sort, but uses a string sort if
1061 * SORT_STRINGSORT is set.
1062 * Calls SetLastError for ERROR_INVALID_FLAGS, ERROR_INVALID_PARAMETER.
1066 * This implementation ignores the locale
1070 * Quite inefficient.
1072 int WINAPI
CompareStringA(
1073 LCID lcid
, /* [in] locale ID */
1074 DWORD fdwStyle
, /* [in] comparison-style options */
1075 LPCSTR s1
, /* [in] first string */
1076 int l1
, /* [in] length of first string */
1077 LPCSTR s2
, /* [in] second string */
1078 int l2
) /* [in] length of second string */
1080 int mapstring_flags
;
1084 TRACE("%s and %s\n",
1085 debugstr_an (s1
,l1
), debugstr_an (s2
,l2
));
1087 if ( (s1
==NULL
) || (s2
==NULL
) )
1089 ERR("(s1=%s,s2=%s): Invalid NULL string\n",
1090 debugstr_an(s1
,l1
), debugstr_an(s2
,l2
));
1091 SetLastError(ERROR_INVALID_PARAMETER
);
1095 if(fdwStyle
& NORM_IGNORESYMBOLS
)
1096 FIXME("IGNORESYMBOLS not supported\n");
1098 if (l1
== -1) l1
= strlen(s1
);
1099 if (l2
== -1) l2
= strlen(s2
);
1101 mapstring_flags
= LCMAP_SORTKEY
| fdwStyle
;
1102 len1
= OLE2NLS_EstimateMappingLength(lcid
, mapstring_flags
, s1
, l1
);
1103 len2
= OLE2NLS_EstimateMappingLength(lcid
, mapstring_flags
, s2
, l2
);
1105 if ((len1
==0)||(len2
==0))
1106 return 0; /* something wrong happened */
1108 sk1
= (LPSTR
)HeapAlloc(GetProcessHeap(), 0, len1
+ len2
);
1110 if ( (!LCMapStringA(lcid
,mapstring_flags
,s1
,l1
,sk1
,len1
))
1111 || (!LCMapStringA(lcid
,mapstring_flags
,s2
,l2
,sk2
,len2
)) )
1113 ERR("Bug in LCmapStringA.\n");
1118 /* strcmp doesn't necessarily return -1, 0, or 1 */
1119 result
= strcmp(sk1
,sk2
);
1121 HeapFree(GetProcessHeap(),0,sk1
);
1128 /* must be greater, if we reach this point */
1132 /******************************************************************************
1133 * CompareStringW [KERNEL32.@]
1134 * This implementation ignores the locale
1135 * FIXME : Does only string sort. Should
1136 * be reimplemented the same way as CompareStringA.
1138 int WINAPI
CompareStringW(LCID lcid
, DWORD fdwStyle
,
1139 LPCWSTR s1
, int l1
, LPCWSTR s2
, int l2
)
1142 if(fdwStyle
& NORM_IGNORENONSPACE
)
1143 FIXME("IGNORENONSPACE not supported\n");
1144 if(fdwStyle
& NORM_IGNORESYMBOLS
)
1145 FIXME("IGNORESYMBOLS not supported\n");
1147 if(s1
==NULL
|| s2
==NULL
)
1149 SetLastError(ERROR_INVALID_PARAMETER
);
1152 /* Is strcmp defaulting to string sort or to word sort?? */
1153 /* FIXME: Handle NORM_STRINGSORT */
1154 l1
= (l1
==-1)?strlenW(s1
):l1
;
1155 l2
= (l2
==-1)?strlenW(s2
):l2
;
1156 len
= l1
<l2
? l1
:l2
;
1157 ret
= (fdwStyle
& NORM_IGNORECASE
) ? strncmpiW(s1
,s2
,len
) : strncmpW(s1
,s2
,len
);
1158 /* not equal, return 1 or 3 */
1160 /* need to translate result */
1161 return ((int)ret
< 0) ? 1 : 3;
1163 /* same len, return 2 */
1164 if(l1
==l2
) return 2;
1165 /* the longer one is lexically greater */
1166 return (l1
<l2
)? 1 : 3;
1169 /***********************************************************************
1170 * lstrcmp (KERNEL32.@)
1171 * lstrcmpA (KERNEL32.@)
1173 INT WINAPI
lstrcmpA( LPCSTR str1
, LPCSTR str2
)
1175 return CompareStringA(LOCALE_SYSTEM_DEFAULT
,0,str1
,-1,str2
,-1) - 2 ;
1179 /***********************************************************************
1180 * lstrcmpW (KERNEL32.@)
1181 * FIXME : should call CompareStringW, when it is implemented.
1182 * This implementation is not "word sort", as it should.
1184 INT WINAPI
lstrcmpW( LPCWSTR str1
, LPCWSTR str2
)
1186 TRACE("%s and %s\n",
1187 debugstr_w (str1
), debugstr_w (str2
));
1188 if (!str1
|| !str2
) {
1189 SetLastError(ERROR_INVALID_PARAMETER
);
1192 while (*str1
&& (*str1
== *str2
)) { str1
++; str2
++; }
1193 return (INT
)(*str1
- *str2
);
1197 /***********************************************************************
1198 * lstrcmpi (KERNEL32.@)
1199 * lstrcmpiA (KERNEL32.@)
1201 INT WINAPI
lstrcmpiA( LPCSTR str1
, LPCSTR str2
)
1202 { TRACE("strcmpi %s and %s\n",
1203 debugstr_a (str1
), debugstr_a (str2
));
1204 return CompareStringA(LOCALE_SYSTEM_DEFAULT
,NORM_IGNORECASE
,str1
,-1,str2
,-1)-2;
1208 /***********************************************************************
1209 * lstrcmpiW (KERNEL32.@)
1211 INT WINAPI
lstrcmpiW( LPCWSTR str1
, LPCWSTR str2
)
1213 if (!str1
|| !str2
) {
1214 SetLastError(ERROR_INVALID_PARAMETER
);
1217 return strcmpiW( str1
, str2
);