XSLTUnicodeSort.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330
  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 Computer, 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. #include "config.h"
  29. #include "XSLTUnicodeSort.h"
  30. #if ENABLE(XSLT)
  31. #include <libxslt/templates.h>
  32. #include <libxslt/xsltutils.h>
  33. #include <wtf/text/WTFString.h>
  34. #include <wtf/unicode/Collator.h>
  35. #if PLATFORM(MAC)
  36. #include "SoftLinking.h"
  37. #endif
  38. #if PLATFORM(MAC)
  39. SOFT_LINK_LIBRARY(libxslt)
  40. SOFT_LINK(libxslt, xsltComputeSortResult, xmlXPathObjectPtr*, (xsltTransformContextPtr ctxt, xmlNodePtr sort), (ctxt, sort))
  41. SOFT_LINK(libxslt, xsltEvalAttrValueTemplate, xmlChar*, (xsltTransformContextPtr ctxt, xmlNodePtr node, const xmlChar *name, const xmlChar *ns), (ctxt, node, name, ns))
  42. static void xsltTransformErrorTrampoline(xsltTransformContextPtr, xsltStylesheetPtr, xmlNodePtr, const char* message, ...) WTF_ATTRIBUTE_PRINTF(4, 5);
  43. void xsltTransformErrorTrampoline(xsltTransformContextPtr context, xsltStylesheetPtr style, xmlNodePtr node, const char* message, ...)
  44. {
  45. va_list args;
  46. va_start(args, message);
  47. #if OS(PS3)
  48. char messageWithArgs[1024];
  49. vsnprintf(messageWithArgs, sizeof(messageWithArgs) - 1, message, args);
  50. #else
  51. char* messageWithArgs;
  52. vasprintf(&messageWithArgs, message, args);
  53. #endif
  54. va_end(args);
  55. static void (*xsltTransformErrorPointer)(xsltTransformContextPtr, xsltStylesheetPtr, xmlNodePtr, const char*, ...) WTF_ATTRIBUTE_PRINTF(4, 5)
  56. = reinterpret_cast<void (*)(xsltTransformContextPtr, xsltStylesheetPtr, xmlNodePtr, const char*, ...)>(dlsym(libxsltLibrary(), "xsltTransformError"));
  57. xsltTransformErrorPointer(context, style, node, "%s", messageWithArgs);
  58. #if !OS(PS3)
  59. free(messageWithArgs);
  60. #endif
  61. }
  62. #define xsltTransformError xsltTransformErrorTrampoline
  63. #endif
  64. namespace WebCore {
  65. // Based on default implementation from libxslt 1.1.22 and xsltICUSort.c example.
  66. void xsltUnicodeSortFunction(xsltTransformContextPtr ctxt, xmlNodePtr *sorts, int nbsorts)
  67. {
  68. #ifdef XSLT_REFACTORED
  69. xsltStyleItemSortPtr comp;
  70. #else
  71. xsltStylePreCompPtr comp;
  72. #endif
  73. xmlXPathObjectPtr *resultsTab[XSLT_MAX_SORT];
  74. xmlXPathObjectPtr *results = NULL, *res;
  75. xmlNodeSetPtr list = NULL;
  76. int descending, number, desc, numb;
  77. int len = 0;
  78. int i, j, incr;
  79. int tst;
  80. int depth;
  81. xmlNodePtr node;
  82. xmlXPathObjectPtr tmp;
  83. int tempstype[XSLT_MAX_SORT], temporder[XSLT_MAX_SORT];
  84. if ((ctxt == NULL) || (sorts == NULL) || (nbsorts <= 0) ||
  85. (nbsorts >= XSLT_MAX_SORT))
  86. return;
  87. if (sorts[0] == NULL)
  88. return;
  89. comp = static_cast<xsltStylePreComp*>(sorts[0]->psvi);
  90. if (comp == NULL)
  91. return;
  92. list = ctxt->nodeList;
  93. if ((list == NULL) || (list->nodeNr <= 1))
  94. return; /* nothing to do */
  95. for (j = 0; j < nbsorts; j++) {
  96. comp = static_cast<xsltStylePreComp*>(sorts[j]->psvi);
  97. tempstype[j] = 0;
  98. if ((comp->stype == NULL) && (comp->has_stype != 0)) {
  99. comp->stype =
  100. xsltEvalAttrValueTemplate(ctxt, sorts[j],
  101. (const xmlChar *) "data-type",
  102. XSLT_NAMESPACE);
  103. if (comp->stype != NULL) {
  104. tempstype[j] = 1;
  105. if (xmlStrEqual(comp->stype, (const xmlChar *) "text"))
  106. comp->number = 0;
  107. else if (xmlStrEqual(comp->stype, (const xmlChar *) "number"))
  108. comp->number = 1;
  109. else {
  110. xsltTransformError(ctxt, NULL, sorts[j],
  111. "xsltDoSortFunction: no support for data-type = %s\n",
  112. comp->stype);
  113. comp->number = 0; /* use default */
  114. }
  115. }
  116. }
  117. temporder[j] = 0;
  118. if ((comp->order == NULL) && (comp->has_order != 0)) {
  119. comp->order = xsltEvalAttrValueTemplate(ctxt, sorts[j],
  120. (const xmlChar *) "order",
  121. XSLT_NAMESPACE);
  122. if (comp->order != NULL) {
  123. temporder[j] = 1;
  124. if (xmlStrEqual(comp->order, (const xmlChar *) "ascending"))
  125. comp->descending = 0;
  126. else if (xmlStrEqual(comp->order,
  127. (const xmlChar *) "descending"))
  128. comp->descending = 1;
  129. else {
  130. xsltTransformError(ctxt, NULL, sorts[j],
  131. "xsltDoSortFunction: invalid value %s for order\n",
  132. comp->order);
  133. comp->descending = 0; /* use default */
  134. }
  135. }
  136. }
  137. }
  138. len = list->nodeNr;
  139. resultsTab[0] = xsltComputeSortResult(ctxt, sorts[0]);
  140. for (i = 1;i < XSLT_MAX_SORT;i++)
  141. resultsTab[i] = NULL;
  142. results = resultsTab[0];
  143. comp = static_cast<xsltStylePreComp*>(sorts[0]->psvi);
  144. descending = comp->descending;
  145. number = comp->number;
  146. if (results == NULL)
  147. return;
  148. // We are passing a language identifier to a function that expects a locale identifier.
  149. // The implementation of Collator should be lenient, and accept both "en-US" and "en_US", for example.
  150. // This lets an author to really specify sorting rules, e.g. "de_DE@collation=phonebook", which isn't
  151. // possible with language alone.
  152. Collator collator(comp->has_lang ? (const char*)comp->lang : "en");
  153. collator.setOrderLowerFirst(comp->lower_first);
  154. /* Shell's sort of node-set */
  155. for (incr = len / 2; incr > 0; incr /= 2) {
  156. for (i = incr; i < len; i++) {
  157. j = i - incr;
  158. if (results[i] == NULL)
  159. continue;
  160. while (j >= 0) {
  161. if (results[j] == NULL)
  162. tst = 1;
  163. else {
  164. if (number) {
  165. /* We make NaN smaller than number in accordance
  166. with XSLT spec */
  167. if (xmlXPathIsNaN(results[j]->floatval)) {
  168. if (xmlXPathIsNaN(results[j + incr]->floatval))
  169. tst = 0;
  170. else
  171. tst = -1;
  172. } else if (xmlXPathIsNaN(results[j + incr]->floatval))
  173. tst = 1;
  174. else if (results[j]->floatval ==
  175. results[j + incr]->floatval)
  176. tst = 0;
  177. else if (results[j]->floatval >
  178. results[j + incr]->floatval)
  179. tst = 1;
  180. else tst = -1;
  181. } else {
  182. String str1 = String::fromUTF8((const char*)results[j]->stringval);
  183. String str2 = String::fromUTF8((const char*)results[j + incr]->stringval);
  184. tst = collator.collate(str1.characters(), str1.length(), str2.characters(), str2.length());
  185. }
  186. if (descending)
  187. tst = -tst;
  188. }
  189. if (tst == 0) {
  190. /*
  191. * Okay we need to use multi level sorts
  192. */
  193. depth = 1;
  194. while (depth < nbsorts) {
  195. if (sorts[depth] == NULL)
  196. break;
  197. comp = static_cast<xsltStylePreComp*>(sorts[depth]->psvi);
  198. if (comp == NULL)
  199. break;
  200. desc = comp->descending;
  201. numb = comp->number;
  202. /*
  203. * Compute the result of the next level for the
  204. * full set, this might be optimized ... or not
  205. */
  206. if (resultsTab[depth] == NULL)
  207. resultsTab[depth] = xsltComputeSortResult(ctxt,
  208. sorts[depth]);
  209. res = resultsTab[depth];
  210. if (res == NULL)
  211. break;
  212. if (res[j] == NULL) {
  213. if (res[j+incr] != NULL)
  214. tst = 1;
  215. } else {
  216. if (numb) {
  217. /* We make NaN smaller than number in
  218. accordance with XSLT spec */
  219. if (xmlXPathIsNaN(res[j]->floatval)) {
  220. if (xmlXPathIsNaN(res[j +
  221. incr]->floatval))
  222. tst = 0;
  223. else
  224. tst = -1;
  225. } else if (xmlXPathIsNaN(res[j + incr]->
  226. floatval))
  227. tst = 1;
  228. else if (res[j]->floatval == res[j + incr]->
  229. floatval)
  230. tst = 0;
  231. else if (res[j]->floatval >
  232. res[j + incr]->floatval)
  233. tst = 1;
  234. else tst = -1;
  235. } else {
  236. String str1 = String::fromUTF8((const char*)res[j]->stringval);
  237. String str2 = String::fromUTF8((const char*)res[j + incr]->stringval);
  238. tst = collator.collate(str1.characters(), str1.length(), str2.characters(), str2.length());
  239. }
  240. if (desc)
  241. tst = -tst;
  242. }
  243. /*
  244. * if we still can't differenciate at this level
  245. * try one level deeper.
  246. */
  247. if (tst != 0)
  248. break;
  249. depth++;
  250. }
  251. }
  252. if (tst == 0) {
  253. tst = results[j]->index > results[j + incr]->index;
  254. }
  255. if (tst > 0) {
  256. tmp = results[j];
  257. results[j] = results[j + incr];
  258. results[j + incr] = tmp;
  259. node = list->nodeTab[j];
  260. list->nodeTab[j] = list->nodeTab[j + incr];
  261. list->nodeTab[j + incr] = node;
  262. depth = 1;
  263. while (depth < nbsorts) {
  264. if (sorts[depth] == NULL)
  265. break;
  266. if (resultsTab[depth] == NULL)
  267. break;
  268. res = resultsTab[depth];
  269. tmp = res[j];
  270. res[j] = res[j + incr];
  271. res[j + incr] = tmp;
  272. depth++;
  273. }
  274. j -= incr;
  275. } else
  276. break;
  277. }
  278. }
  279. }
  280. for (j = 0; j < nbsorts; j++) {
  281. comp = static_cast<xsltStylePreComp*>(sorts[j]->psvi);
  282. if (tempstype[j] == 1) {
  283. /* The data-type needs to be recomputed each time */
  284. xmlFree((void *)(comp->stype));
  285. comp->stype = NULL;
  286. }
  287. if (temporder[j] == 1) {
  288. /* The order needs to be recomputed each time */
  289. xmlFree((void *)(comp->order));
  290. comp->order = NULL;
  291. }
  292. if (resultsTab[j] != NULL) {
  293. for (i = 0;i < len;i++)
  294. xmlXPathFreeObject(resultsTab[j][i]);
  295. xmlFree(resultsTab[j]);
  296. }
  297. }
  298. }
  299. }
  300. #endif