Fix the case of product and company names.
[wine] / libs / unicode / sortkey.c
1 /*
2  * Unicode sort key generation
3  *
4  * Copyright 2003 Dmitry Timoshkov
5  *
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.
10  *
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.
15  *
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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20 #include "wine/unicode.h"
21
22 extern int get_decomposition(WCHAR src, WCHAR *dst, unsigned int dstlen);
23
24 /*
25  * flags - normalization NORM_* flags
26  *
27  * FIXME: 'variable' flag not handled
28  */
29 int wine_get_sortkey(int flags, const WCHAR *src, int srclen, char *dst, int dstlen)
30 {
31     extern const unsigned int collation_table[];
32     WCHAR dummy[4]; /* no decomposition is larger than 4 chars */
33     int key_len[4];
34     char *key_ptr[4];
35     const WCHAR *src_save = src;
36     int srclen_save = srclen;
37
38     key_len[0] = key_len[1] = key_len[2] = key_len[3] = 0;
39     for (; srclen; srclen--, src++)
40     {
41         int decomposed_len = get_decomposition(*src, dummy, 4);
42         if (decomposed_len)
43         {
44             int i;
45             for (i = 0; i < decomposed_len; i++)
46             {
47                 WCHAR wch = dummy[i];
48                 unsigned int ce;
49
50                 /* tests show that win2k just ignores NORM_IGNORENONSPACE,
51                  * and skips white space and punctuation characters for
52                  * NORM_IGNORESYMBOLS.
53                  */
54                 if ((flags & NORM_IGNORESYMBOLS) && (get_char_typeW(wch) & (C1_PUNCT | C1_SPACE)))
55                     continue;
56
57                 if (flags & NORM_IGNORECASE) wch = tolowerW(wch);
58
59                 ce = collation_table[collation_table[wch >> 8] + (wch & 0xff)];
60                 if (ce != (unsigned int)-1)
61                 {
62                     if (ce >> 16) key_len[0] += 2;
63                     if ((ce >> 8) & 0xff) key_len[1]++;
64                     if ((ce >> 4) & 0x0f) key_len[2]++;
65                     /*if (ce & 1)
66                     {
67                         if (wch >> 8) key_len[3]++;
68                         key_len[3]++;
69                     }*/
70                 }
71                 /*else
72                 {
73                     key_len[0] += 2;
74                     if (wch >> 8) key_len[0]++;
75                     if (wch & 0xff) key_len[0]++;
76                 }*/
77             }
78         }
79     }
80
81     if (!dstlen) /* compute length */
82         /* 4 * '\1' + 1 * '\0' + key length */
83         return key_len[0] + key_len[1] + key_len[2] + key_len[3] + 4 + 1;
84
85     if (dstlen < key_len[0] + key_len[1] + key_len[2] + key_len[3] + 4 + 1)
86         return 0; /* overflow */
87
88     src = src_save;
89     srclen = srclen_save;
90
91     key_ptr[0] = dst;
92     key_ptr[1] = key_ptr[0] + key_len[0] + 1;
93     key_ptr[2] = key_ptr[1] + key_len[1] + 1;
94     key_ptr[3] = key_ptr[2] + key_len[2] + 1;
95
96     for (; srclen; srclen--, src++)
97     {
98         int decomposed_len = get_decomposition(*src, dummy, 4);
99         if (decomposed_len)
100         {
101             int i;
102             for (i = 0; i < decomposed_len; i++)
103             {
104                 WCHAR wch = dummy[i];
105                 unsigned int ce;
106
107                 /* tests show that win2k just ignores NORM_IGNORENONSPACE,
108                  * and skips white space and punctuation characters for
109                  * NORM_IGNORESYMBOLS.
110                  */
111                 if ((flags & NORM_IGNORESYMBOLS) && (get_char_typeW(wch) & (C1_PUNCT | C1_SPACE)))
112                     continue;
113
114                 if (flags & NORM_IGNORECASE) wch = tolowerW(wch);
115
116                 ce = collation_table[collation_table[wch >> 8] + (wch & 0xff)];
117                 if (ce != (unsigned int)-1)
118                 {
119                     WCHAR key;
120                     if ((key = ce >> 16))
121                     {
122                         *key_ptr[0]++ = key >> 8;
123                         *key_ptr[0]++ = key & 0xff;
124                     }
125                     /* make key 1 start from 2 */
126                     if ((key = (ce >> 8) & 0xff)) *key_ptr[1]++ = key + 1;
127                     /* make key 2 start from 2 */
128                     if ((key = (ce >> 4) & 0x0f)) *key_ptr[2]++ = key + 1;
129                     /* key 3 is always a character code */
130                     /*if (ce & 1)
131                     {
132                         if (wch >> 8) *key_ptr[3]++ = wch >> 8;
133                         if (wch & 0xff) *key_ptr[3]++ = wch & 0xff;
134                     }*/
135                 }
136                 /*else
137                 {
138                     *key_ptr[0]++ = 0xff;
139                     *key_ptr[0]++ = 0xfe;
140                     if (wch >> 8) *key_ptr[0]++ = wch >> 8;
141                     if (wch & 0xff) *key_ptr[0]++ = wch & 0xff;
142                 }*/
143             }
144         }
145     }
146
147     *key_ptr[0] = '\1';
148     *key_ptr[1] = '\1';
149     *key_ptr[2] = '\1';
150     *key_ptr[3]++ = '\1';
151     *key_ptr[3] = 0;
152
153     return key_ptr[3] - dst;
154 }