ExceptionCode enumeration should use modern exception names
[WebKit-https.git] / Source / WebCore / xml / XSLTUnicodeSort.cpp
1 /*
2  * Copyright (C) 2007, 2008, 2009 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
8  * 1.  Redistributions of source code must retain the above copyright
9  *     notice, this list of conditions and the following disclaimer.
10  * 2.  Redistributions in binary form must reproduce the above copyright
11  *     notice, this list of conditions and the following disclaimer in the
12  *     documentation and/or other materials provided with the distribution.
13  * 3.  Neither the name of Apple Inc. ("Apple") nor the names of
14  *     its contributors may be used to endorse or promote products derived
15  *     from this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
18  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
21  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28
29 #include "config.h"
30 #include "XSLTUnicodeSort.h"
31
32 #if ENABLE(XSLT)
33
34 #include <libxslt/templates.h>
35 #include <libxslt/xsltutils.h>
36 #include <wtf/StringExtras.h>
37 #include <wtf/Vector.h>
38 #include <wtf/unicode/Collator.h>
39
40 #if OS(DARWIN) && !PLATFORM(GTK)
41 #include <wtf/SoftLinking.h>
42 #endif
43
44 #if OS(DARWIN) && !PLATFORM(GTK)
45
46 SOFT_LINK_LIBRARY(libxslt)
47 SOFT_LINK(libxslt, xsltComputeSortResult, xmlXPathObjectPtr*, (xsltTransformContextPtr ctxt, xmlNodePtr sort), (ctxt, sort))
48 SOFT_LINK(libxslt, xsltEvalAttrValueTemplate, xmlChar*, (xsltTransformContextPtr ctxt, xmlNodePtr node, const xmlChar *name, const xmlChar *ns), (ctxt, node, name, ns))
49
50 static void xsltTransformErrorTrampoline(xsltTransformContextPtr, xsltStylesheetPtr, xmlNodePtr, const char* message, ...) WTF_ATTRIBUTE_PRINTF(4, 5);
51
52 void xsltTransformErrorTrampoline(xsltTransformContextPtr context, xsltStylesheetPtr style, xmlNodePtr node, const char* message, ...)
53 {
54     va_list args;
55     va_start(args, message);
56
57     va_list preflightArgs;
58     va_copy(preflightArgs, args);
59     size_t stringLength = vsnprintf(nullptr, 0, message, preflightArgs);
60     va_end(preflightArgs);
61
62     Vector<char, 1024> buffer(stringLength + 1);
63     vsnprintf(buffer.data(), stringLength + 1, message, args);
64     va_end(args);
65
66     static void (*xsltTransformErrorPointer)(xsltTransformContextPtr, xsltStylesheetPtr, xmlNodePtr, const char*, ...) WTF_ATTRIBUTE_PRINTF(4, 5)
67         = reinterpret_cast<void (*)(xsltTransformContextPtr, xsltStylesheetPtr, xmlNodePtr, const char*, ...)>(dlsym(libxsltLibrary(), "xsltTransformError"));
68     xsltTransformErrorPointer(context, style, node, "%s", buffer.data());
69 }
70
71 #define xsltTransformError xsltTransformErrorTrampoline
72
73 #endif
74
75 namespace WebCore {
76
77 // Based on default implementation from libxslt 1.1.22 and xsltICUSort.c example.
78 void xsltUnicodeSortFunction(xsltTransformContextPtr ctxt, xmlNodePtr *sorts, int nbsorts)
79 {
80 #ifdef XSLT_REFACTORED
81     xsltStyleItemSortPtr comp;
82 #else
83     xsltStylePreCompPtr comp;
84 #endif
85     xmlXPathObjectPtr *resultsTab[XSLT_MAX_SORT];
86     xmlXPathObjectPtr *results = NULL, *res;
87     xmlNodeSetPtr list = NULL;
88     int descending, number, desc, numb;
89     int len = 0;
90     int i, j, incr;
91     int tst;
92     int depth;
93     xmlNodePtr node;
94     xmlXPathObjectPtr tmp;    
95     int tempstype[XSLT_MAX_SORT], temporder[XSLT_MAX_SORT];
96
97     if ((ctxt == NULL) || (sorts == NULL) || (nbsorts <= 0) ||
98         (nbsorts >= XSLT_MAX_SORT))
99         return;
100     if (sorts[0] == NULL)
101         return;
102     comp = static_cast<xsltStylePreComp*>(sorts[0]->psvi);
103     if (comp == NULL)
104         return;
105
106     list = ctxt->nodeList;
107     if ((list == NULL) || (list->nodeNr <= 1))
108         return; /* nothing to do */
109
110     for (j = 0; j < nbsorts; j++) {
111         comp = static_cast<xsltStylePreComp*>(sorts[j]->psvi);
112         tempstype[j] = 0;
113         if ((comp->stype == NULL) && (comp->has_stype != 0)) {
114             comp->stype =
115                 xsltEvalAttrValueTemplate(ctxt, sorts[j],
116                                           (const xmlChar *) "data-type",
117                                           XSLT_NAMESPACE);
118             if (comp->stype != NULL) {
119                 tempstype[j] = 1;
120                 if (xmlStrEqual(comp->stype, (const xmlChar *) "text"))
121                     comp->number = 0;
122                 else if (xmlStrEqual(comp->stype, (const xmlChar *) "number"))
123                     comp->number = 1;
124                 else {
125                     xsltTransformError(ctxt, NULL, sorts[j],
126                           "xsltDoSortFunction: no support for data-type = %s\n",
127                                      comp->stype);
128                     comp->number = 0; /* use default */
129                 }
130             }
131         }
132         temporder[j] = 0;
133         if ((comp->order == NULL) && (comp->has_order != 0)) {
134             comp->order = xsltEvalAttrValueTemplate(ctxt, sorts[j],
135                                                     (const xmlChar *) "order",
136                                                     XSLT_NAMESPACE);
137             if (comp->order != NULL) {
138                 temporder[j] = 1;
139                 if (xmlStrEqual(comp->order, (const xmlChar *) "ascending"))
140                     comp->descending = 0;
141                 else if (xmlStrEqual(comp->order,
142                                      (const xmlChar *) "descending"))
143                     comp->descending = 1;
144                 else {
145                     xsltTransformError(ctxt, NULL, sorts[j],
146                              "xsltDoSortFunction: invalid value %s for order\n",
147                                      comp->order);
148                     comp->descending = 0; /* use default */
149                 }
150             }
151         }
152     }
153
154     len = list->nodeNr;
155
156     resultsTab[0] = xsltComputeSortResult(ctxt, sorts[0]);
157     for (i = 1;i < XSLT_MAX_SORT;i++)
158         resultsTab[i] = NULL;
159
160     results = resultsTab[0];
161
162     comp = static_cast<xsltStylePreComp*>(sorts[0]->psvi);
163     descending = comp->descending;
164     number = comp->number;
165     if (results == NULL)
166         return;
167
168     // We are passing a language identifier to a function that expects a locale identifier.
169     // The implementation of Collator should be lenient, and accept both "en-US" and "en_US", for example.
170     // This lets an author specify sorting rules, e.g. "de_DE@collation=phonebook", which isn't
171     // possible with language alone.
172     Collator collator(comp->has_lang ? reinterpret_cast<const char*>(comp->lang) : "en", comp->lower_first);
173
174     /* Shell's sort of node-set */
175     for (incr = len / 2; incr > 0; incr /= 2) {
176         for (i = incr; i < len; i++) {
177             j = i - incr;
178             if (results[i] == NULL)
179                 continue;
180             
181             while (j >= 0) {
182                 if (results[j] == NULL)
183                     tst = 1;
184                 else {
185                     if (number) {
186                         /* We make NaN smaller than number in accordance
187                            with XSLT spec */
188                         if (xmlXPathIsNaN(results[j]->floatval)) {
189                             if (xmlXPathIsNaN(results[j + incr]->floatval))
190                                 tst = 0;
191                             else
192                                 tst = -1;
193                         } else if (xmlXPathIsNaN(results[j + incr]->floatval))
194                             tst = 1;
195                         else if (results[j]->floatval ==
196                                 results[j + incr]->floatval)
197                             tst = 0;
198                         else if (results[j]->floatval > 
199                                 results[j + incr]->floatval)
200                             tst = 1;
201                         else tst = -1;
202                     } else
203                         tst = collator.collateUTF8(reinterpret_cast<const char*>(results[j]->stringval), reinterpret_cast<const char*>(results[j + incr]->stringval));
204                     if (descending)
205                         tst = -tst;
206                 }
207                 if (tst == 0) {
208                     /*
209                      * Okay we need to use multi level sorts
210                      */
211                     depth = 1;
212                     while (depth < nbsorts) {
213                         if (sorts[depth] == NULL)
214                             break;
215                         comp = static_cast<xsltStylePreComp*>(sorts[depth]->psvi);
216                         if (comp == NULL)
217                             break;
218                         desc = comp->descending;
219                         numb = comp->number;
220
221                         /*
222                          * Compute the result of the next level for the
223                          * full set, this might be optimized ... or not
224                          */
225                         if (resultsTab[depth] == NULL) 
226                             resultsTab[depth] = xsltComputeSortResult(ctxt,
227                                                         sorts[depth]);
228                         res = resultsTab[depth];
229                         if (res == NULL) 
230                             break;
231                         if (res[j] == NULL) {
232                             if (res[j+incr] != NULL)
233                                 tst = 1;
234                         } else {
235                             if (numb) {
236                                 /* We make NaN smaller than number in
237                                    accordance with XSLT spec */
238                                 if (xmlXPathIsNaN(res[j]->floatval)) {
239                                     if (xmlXPathIsNaN(res[j +
240                                                     incr]->floatval))
241                                         tst = 0;
242                                     else
243                                         tst = -1;
244                                 } else if (xmlXPathIsNaN(res[j + incr]->
245                                                 floatval))
246                                     tst = 1;
247                                 else if (res[j]->floatval == res[j + incr]->
248                                                 floatval)
249                                     tst = 0;
250                                 else if (res[j]->floatval > 
251                                         res[j + incr]->floatval)
252                                     tst = 1;
253                                 else tst = -1;
254                             } else
255                                 tst = collator.collateUTF8(reinterpret_cast<const char*>(res[j]->stringval), reinterpret_cast<const char*>(res[j + incr]->stringval));
256                             if (desc)
257                                 tst = -tst;
258                         }
259
260                         /*
261                          * if we still can't differenciate at this level
262                          * try one level deeper.
263                          */
264                         if (tst != 0)
265                             break;
266                         depth++;
267                     }
268                 }
269                 if (tst == 0) {
270                     tst = results[j]->index > results[j + incr]->index;
271                 }
272                 if (tst > 0) {
273                     tmp = results[j];
274                     results[j] = results[j + incr];
275                     results[j + incr] = tmp;
276                     node = list->nodeTab[j];
277                     list->nodeTab[j] = list->nodeTab[j + incr];
278                     list->nodeTab[j + incr] = node;
279                     depth = 1;
280                     while (depth < nbsorts) {
281                         if (sorts[depth] == NULL)
282                             break;
283                         if (resultsTab[depth] == NULL)
284                             break;
285                         res = resultsTab[depth];
286                         tmp = res[j];
287                         res[j] = res[j + incr];
288                         res[j + incr] = tmp;
289                         depth++;
290                     }
291                     j -= incr;
292                 } else
293                     break;
294             }
295         }
296     }
297
298     for (j = 0; j < nbsorts; j++) {
299         comp = static_cast<xsltStylePreComp*>(sorts[j]->psvi);
300         if (tempstype[j] == 1) {
301             /* The data-type needs to be recomputed each time */
302             xmlFree((void *)(comp->stype));
303             comp->stype = NULL;
304         }
305         if (temporder[j] == 1) {
306             /* The order needs to be recomputed each time */
307             xmlFree((void *)(comp->order));
308             comp->order = NULL;
309         }
310         if (resultsTab[j] != NULL) {
311             for (i = 0;i < len;i++)
312                 xmlXPathFreeObject(resultsTab[j][i]);
313             xmlFree(resultsTab[j]);
314         }
315     }
316 }
317
318 }
319
320 #endif