Line  | Count  | Source (jump to first uncovered line)  | 
1  |  | /*  | 
2  |  |  * xpath.c: XML Path Language implementation  | 
3  |  |  *          XPath is a language for addressing parts of an XML document,  | 
4  |  |  *          designed to be used by both XSLT and XPointer  | 
5  |  |  *  | 
6  |  |  * Reference: W3C Recommendation 16 November 1999  | 
7  |  |  *     http://www.w3.org/TR/1999/REC-xpath-19991116  | 
8  |  |  * Public reference:  | 
9  |  |  *     http://www.w3.org/TR/xpath  | 
10  |  |  *  | 
11  |  |  * See Copyright for the status of this software  | 
12  |  |  *  | 
13  |  |  * Author: daniel@veillard.com  | 
14  |  |  *  | 
15  |  |  */  | 
16  |  |  | 
17  |  | /* To avoid EBCDIC trouble when parsing on zOS */  | 
18  |  | #if defined(__MVS__)  | 
19  |  | #pragma convert("ISO8859-1") | 
20  |  | #endif  | 
21  |  |  | 
22  |  | #define IN_LIBXML  | 
23  |  | #include "libxml.h"  | 
24  |  |  | 
25  |  | #include <limits.h>  | 
26  |  | #include <string.h>  | 
27  |  | #include <stddef.h>  | 
28  |  | #include <math.h>  | 
29  |  | #include <float.h>  | 
30  |  | #include <ctype.h>  | 
31  |  |  | 
32  |  | #include <libxml/xmlmemory.h>  | 
33  |  | #include <libxml/tree.h>  | 
34  |  | #include <libxml/valid.h>  | 
35  |  | #include <libxml/xpath.h>  | 
36  |  | #include <libxml/xpathInternals.h>  | 
37  |  | #include <libxml/parserInternals.h>  | 
38  |  | #include <libxml/hash.h>  | 
39  |  | #ifdef LIBXML_XPTR_LOCS_ENABLED  | 
40  |  | #include <libxml/xpointer.h>  | 
41  |  | #endif  | 
42  |  | #ifdef LIBXML_DEBUG_ENABLED  | 
43  |  | #include <libxml/debugXML.h>  | 
44  |  | #endif  | 
45  |  | #include <libxml/xmlerror.h>  | 
46  |  | #include <libxml/threads.h>  | 
47  |  | #include <libxml/globals.h>  | 
48  |  | #ifdef LIBXML_PATTERN_ENABLED  | 
49  |  | #include <libxml/pattern.h>  | 
50  |  | #endif  | 
51  |  |  | 
52  |  | #include "private/buf.h"  | 
53  |  | #include "private/error.h"  | 
54  |  | #include "private/xpath.h"  | 
55  |  |  | 
56  |  | #ifdef LIBXML_PATTERN_ENABLED  | 
57  |  | #define XPATH_STREAMING  | 
58  |  | #endif  | 
59  |  |  | 
60  |  | #define TODO                \  | 
61  | 1.56k  |     xmlGenericError(xmlGenericErrorContext,       \  | 
62  | 1.56k  |       "Unimplemented block at %s:%d\n",       \  | 
63  | 1.56k  |             __FILE__, __LINE__);  | 
64  |  |  | 
65  |  | /**  | 
66  |  |  * WITH_TIM_SORT:  | 
67  |  |  *  | 
68  |  |  * Use the Timsort algorithm provided in timsort.h to sort  | 
69  |  |  * nodeset as this is a great improvement over the old Shell sort  | 
70  |  |  * used in xmlXPathNodeSetSort()  | 
71  |  |  */  | 
72  |  | #define WITH_TIM_SORT  | 
73  |  |  | 
74  |  | /*  | 
75  |  | * XP_OPTIMIZED_NON_ELEM_COMPARISON:  | 
76  |  | * If defined, this will use xmlXPathCmpNodesExt() instead of  | 
77  |  | * xmlXPathCmpNodes(). The new function is optimized comparison of  | 
78  |  | * non-element nodes; actually it will speed up comparison only if  | 
79  |  | * xmlXPathOrderDocElems() was called in order to index the elements of  | 
80  |  | * a tree in document order; Libxslt does such an indexing, thus it will  | 
81  |  | * benefit from this optimization.  | 
82  |  | */  | 
83  |  | #define XP_OPTIMIZED_NON_ELEM_COMPARISON  | 
84  |  |  | 
85  |  | /*  | 
86  |  | * XP_OPTIMIZED_FILTER_FIRST:  | 
87  |  | * If defined, this will optimize expressions like "key('foo', 'val')[b][1]" | 
88  |  | * in a way, that it stop evaluation at the first node.  | 
89  |  | */  | 
90  |  | #define XP_OPTIMIZED_FILTER_FIRST  | 
91  |  |  | 
92  |  | /*  | 
93  |  | * XP_DEBUG_OBJ_USAGE:  | 
94  |  | * Internal flag to enable tracking of how much XPath objects have been  | 
95  |  | * created.  | 
96  |  | */  | 
97  |  | /* #define XP_DEBUG_OBJ_USAGE */  | 
98  |  |  | 
99  |  | /*  | 
100  |  |  * XPATH_MAX_STEPS:  | 
101  |  |  * when compiling an XPath expression we arbitrary limit the maximum  | 
102  |  |  * number of step operation in the compiled expression. 1000000 is  | 
103  |  |  * an insanely large value which should never be reached under normal  | 
104  |  |  * circumstances  | 
105  |  |  */  | 
106  | 776k  | #define XPATH_MAX_STEPS 1000000  | 
107  |  |  | 
108  |  | /*  | 
109  |  |  * XPATH_MAX_STACK_DEPTH:  | 
110  |  |  * when evaluating an XPath expression we arbitrary limit the maximum  | 
111  |  |  * number of object allowed to be pushed on the stack. 1000000 is  | 
112  |  |  * an insanely large value which should never be reached under normal  | 
113  |  |  * circumstances  | 
114  |  |  */  | 
115  | 4.08k  | #define XPATH_MAX_STACK_DEPTH 1000000  | 
116  |  |  | 
117  |  | /*  | 
118  |  |  * XPATH_MAX_NODESET_LENGTH:  | 
119  |  |  * when evaluating an XPath expression nodesets are created and we  | 
120  |  |  * arbitrary limit the maximum length of those node set. 10000000 is  | 
121  |  |  * an insanely large value which should never be reached under normal  | 
122  |  |  * circumstances, one would first need to construct an in memory tree  | 
123  |  |  * with more than 10 millions nodes.  | 
124  |  |  */  | 
125  | 4.44M  | #define XPATH_MAX_NODESET_LENGTH 10000000  | 
126  |  |  | 
127  |  | /*  | 
128  |  |  * XPATH_MAX_RECRUSION_DEPTH:  | 
129  |  |  * Maximum amount of nested functions calls when parsing or evaluating  | 
130  |  |  * expressions  | 
131  |  |  */  | 
132  |  | #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION  | 
133  | 114M  | #define XPATH_MAX_RECURSION_DEPTH 500  | 
134  |  | #elif defined(_WIN32)  | 
135  |  | /* Windows typically limits stack size to 1MB. */  | 
136  |  | #define XPATH_MAX_RECURSION_DEPTH 1000  | 
137  |  | #else  | 
138  |  | #define XPATH_MAX_RECURSION_DEPTH 5000  | 
139  |  | #endif  | 
140  |  |  | 
141  |  | /*  | 
142  |  |  * TODO:  | 
143  |  |  * There are a few spots where some tests are done which depend upon ascii  | 
144  |  |  * data.  These should be enhanced for full UTF8 support (see particularly  | 
145  |  |  * any use of the macros IS_ASCII_CHARACTER and IS_ASCII_DIGIT)  | 
146  |  |  */  | 
147  |  |  | 
148  |  | #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON  | 
149  |  | /**  | 
150  |  |  * xmlXPathCmpNodesExt:  | 
151  |  |  * @node1:  the first node  | 
152  |  |  * @node2:  the second node  | 
153  |  |  *  | 
154  |  |  * Compare two nodes w.r.t document order.  | 
155  |  |  * This one is optimized for handling of non-element nodes.  | 
156  |  |  *  | 
157  |  |  * Returns -2 in case of error 1 if first point < second point, 0 if  | 
158  |  |  *         it's the same node, -1 otherwise  | 
159  |  |  */  | 
160  |  | static int  | 
161  | 26.8M  | xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) { | 
162  | 26.8M  |     int depth1, depth2;  | 
163  | 26.8M  |     int misc = 0, precedence1 = 0, precedence2 = 0;  | 
164  | 26.8M  |     xmlNodePtr miscNode1 = NULL, miscNode2 = NULL;  | 
165  | 26.8M  |     xmlNodePtr cur, root;  | 
166  | 26.8M  |     ptrdiff_t l1, l2;  | 
167  |  |  | 
168  | 26.8M  |     if ((node1 == NULL) || (node2 == NULL))  | 
169  | 0  |   return(-2);  | 
170  |  |  | 
171  | 26.8M  |     if (node1 == node2)  | 
172  | 0  |   return(0);  | 
173  |  |  | 
174  |  |     /*  | 
175  |  |      * a couple of optimizations which will avoid computations in most cases  | 
176  |  |      */  | 
177  | 26.8M  |     switch (node1->type) { | 
178  | 14.1M  |   case XML_ELEMENT_NODE:  | 
179  | 14.1M  |       if (node2->type == XML_ELEMENT_NODE) { | 
180  | 10.2M  |     if ((0 > (ptrdiff_t) node1->content) &&  | 
181  | 10.2M  |         (0 > (ptrdiff_t) node2->content) &&  | 
182  | 10.2M  |         (node1->doc == node2->doc))  | 
183  | 8.37M  |     { | 
184  | 8.37M  |         l1 = -((ptrdiff_t) node1->content);  | 
185  | 8.37M  |         l2 = -((ptrdiff_t) node2->content);  | 
186  | 8.37M  |         if (l1 < l2)  | 
187  | 7.64M  |       return(1);  | 
188  | 722k  |         if (l1 > l2)  | 
189  | 722k  |       return(-1);  | 
190  | 722k  |     } else  | 
191  | 1.84M  |         goto turtle_comparison;  | 
192  | 10.2M  |       }  | 
193  | 3.97M  |       break;  | 
194  | 3.97M  |   case XML_ATTRIBUTE_NODE:  | 
195  | 1.45M  |       precedence1 = 1; /* element is owner */  | 
196  | 1.45M  |       miscNode1 = node1;  | 
197  | 1.45M  |       node1 = node1->parent;  | 
198  | 1.45M  |       misc = 1;  | 
199  | 1.45M  |       break;  | 
200  | 8.58M  |   case XML_TEXT_NODE:  | 
201  | 8.98M  |   case XML_CDATA_SECTION_NODE:  | 
202  | 9.56M  |   case XML_COMMENT_NODE:  | 
203  | 10.2M  |   case XML_PI_NODE: { | 
204  | 10.2M  |       miscNode1 = node1;  | 
205  |  |       /*  | 
206  |  |       * Find nearest element node.  | 
207  |  |       */  | 
208  | 10.2M  |       if (node1->prev != NULL) { | 
209  | 8.60M  |     do { | 
210  | 8.60M  |         node1 = node1->prev;  | 
211  | 8.60M  |         if (node1->type == XML_ELEMENT_NODE) { | 
212  | 5.84M  |       precedence1 = 3; /* element in prev-sibl axis */  | 
213  | 5.84M  |       break;  | 
214  | 5.84M  |         }  | 
215  | 2.76M  |         if (node1->prev == NULL) { | 
216  | 0  |       precedence1 = 2; /* element is parent */  | 
217  |  |       /*  | 
218  |  |       * URGENT TODO: Are there any cases, where the  | 
219  |  |       * parent of such a node is not an element node?  | 
220  |  |       */  | 
221  | 0  |       node1 = node1->parent;  | 
222  | 0  |       break;  | 
223  | 0  |         }  | 
224  | 2.76M  |     } while (1);  | 
225  | 5.84M  |       } else { | 
226  | 4.37M  |     precedence1 = 2; /* element is parent */  | 
227  | 4.37M  |     node1 = node1->parent;  | 
228  | 4.37M  |       }  | 
229  | 10.2M  |       if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE) ||  | 
230  | 10.2M  |     (0 <= (ptrdiff_t) node1->content)) { | 
231  |  |     /*  | 
232  |  |     * Fallback for whatever case.  | 
233  |  |     */  | 
234  | 847k  |     node1 = miscNode1;  | 
235  | 847k  |     precedence1 = 0;  | 
236  | 847k  |       } else  | 
237  | 9.37M  |     misc = 1;  | 
238  | 10.2M  |   }  | 
239  | 0  |       break;  | 
240  | 554k  |   case XML_NAMESPACE_DECL:  | 
241  |  |       /*  | 
242  |  |       * TODO: why do we return 1 for namespace nodes?  | 
243  |  |       */  | 
244  | 554k  |       return(1);  | 
245  | 376k  |   default:  | 
246  | 376k  |       break;  | 
247  | 26.8M  |     }  | 
248  | 16.0M  |     switch (node2->type) { | 
249  | 4.75M  |   case XML_ELEMENT_NODE:  | 
250  | 4.75M  |       break;  | 
251  | 1.33M  |   case XML_ATTRIBUTE_NODE:  | 
252  | 1.33M  |       precedence2 = 1; /* element is owner */  | 
253  | 1.33M  |       miscNode2 = node2;  | 
254  | 1.33M  |       node2 = node2->parent;  | 
255  | 1.33M  |       misc = 1;  | 
256  | 1.33M  |       break;  | 
257  | 7.76M  |   case XML_TEXT_NODE:  | 
258  | 8.11M  |   case XML_CDATA_SECTION_NODE:  | 
259  | 8.68M  |   case XML_COMMENT_NODE:  | 
260  | 9.29M  |   case XML_PI_NODE: { | 
261  | 9.29M  |       miscNode2 = node2;  | 
262  | 9.29M  |       if (node2->prev != NULL) { | 
263  | 8.21M  |     do { | 
264  | 8.21M  |         node2 = node2->prev;  | 
265  | 8.21M  |         if (node2->type == XML_ELEMENT_NODE) { | 
266  | 5.26M  |       precedence2 = 3; /* element in prev-sibl axis */  | 
267  | 5.26M  |       break;  | 
268  | 5.26M  |         }  | 
269  | 2.95M  |         if (node2->prev == NULL) { | 
270  | 0  |       precedence2 = 2; /* element is parent */  | 
271  | 0  |       node2 = node2->parent;  | 
272  | 0  |       break;  | 
273  | 0  |         }  | 
274  | 2.95M  |     } while (1);  | 
275  | 5.26M  |       } else { | 
276  | 4.03M  |     precedence2 = 2; /* element is parent */  | 
277  | 4.03M  |     node2 = node2->parent;  | 
278  | 4.03M  |       }  | 
279  | 9.29M  |       if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE) ||  | 
280  | 9.29M  |     (0 <= (ptrdiff_t) node2->content))  | 
281  | 890k  |       { | 
282  | 890k  |     node2 = miscNode2;  | 
283  | 890k  |     precedence2 = 0;  | 
284  | 890k  |       } else  | 
285  | 8.40M  |     misc = 1;  | 
286  | 9.29M  |   }  | 
287  | 0  |       break;  | 
288  | 51.8k  |   case XML_NAMESPACE_DECL:  | 
289  | 51.8k  |       return(1);  | 
290  | 592k  |   default:  | 
291  | 592k  |       break;  | 
292  | 16.0M  |     }  | 
293  | 15.9M  |     if (misc) { | 
294  | 14.3M  |   if (node1 == node2) { | 
295  | 6.03M  |       if (precedence1 == precedence2) { | 
296  |  |     /*  | 
297  |  |     * The ugly case; but normally there aren't many  | 
298  |  |     * adjacent non-element nodes around.  | 
299  |  |     */  | 
300  | 1.53M  |     cur = miscNode2->prev;  | 
301  | 1.63M  |     while (cur != NULL) { | 
302  | 1.63M  |         if (cur == miscNode1)  | 
303  | 1.40M  |       return(1);  | 
304  | 223k  |         if (cur->type == XML_ELEMENT_NODE)  | 
305  | 121k  |       return(-1);  | 
306  | 102k  |         cur = cur->prev;  | 
307  | 102k  |     }  | 
308  | 7.48k  |     return (-1);  | 
309  | 4.49M  |       } else { | 
310  |  |     /*  | 
311  |  |     * Evaluate based on higher precedence wrt to the element.  | 
312  |  |     * TODO: This assumes attributes are sorted before content.  | 
313  |  |     *   Is this 100% correct?  | 
314  |  |     */  | 
315  | 4.49M  |     if (precedence1 < precedence2)  | 
316  | 3.86M  |         return(1);  | 
317  | 630k  |     else  | 
318  | 630k  |         return(-1);  | 
319  | 4.49M  |       }  | 
320  | 6.03M  |   }  | 
321  |  |   /*  | 
322  |  |   * Special case: One of the helper-elements is contained by the other.  | 
323  |  |   * <foo>  | 
324  |  |   *   <node2>  | 
325  |  |   *     <node1>Text-1(precedence1 == 2)</node1>  | 
326  |  |   *   </node2>  | 
327  |  |   *   Text-6(precedence2 == 3)  | 
328  |  |   * </foo>  | 
329  |  |   */  | 
330  | 8.33M  |   if ((precedence2 == 3) && (precedence1 > 1)) { | 
331  | 1.36M  |       cur = node1->parent;  | 
332  | 3.64M  |       while (cur) { | 
333  | 2.74M  |     if (cur == node2)  | 
334  | 457k  |         return(1);  | 
335  | 2.28M  |     cur = cur->parent;  | 
336  | 2.28M  |       }  | 
337  | 1.36M  |   }  | 
338  | 7.87M  |   if ((precedence1 == 3) && (precedence2 > 1)) { | 
339  | 922k  |       cur = node2->parent;  | 
340  | 2.81M  |       while (cur) { | 
341  | 2.08M  |     if (cur == node1)  | 
342  | 197k  |         return(-1);  | 
343  | 1.89M  |     cur = cur->parent;  | 
344  | 1.89M  |       }  | 
345  | 922k  |   }  | 
346  | 7.87M  |     }  | 
347  |  |  | 
348  |  |     /*  | 
349  |  |      * Speedup using document order if available.  | 
350  |  |      */  | 
351  | 9.29M  |     if ((node1->type == XML_ELEMENT_NODE) &&  | 
352  | 9.29M  |   (node2->type == XML_ELEMENT_NODE) &&  | 
353  | 9.29M  |   (0 > (ptrdiff_t) node1->content) &&  | 
354  | 9.29M  |   (0 > (ptrdiff_t) node2->content) &&  | 
355  | 9.29M  |   (node1->doc == node2->doc)) { | 
356  |  |  | 
357  | 7.09M  |   l1 = -((ptrdiff_t) node1->content);  | 
358  | 7.09M  |   l2 = -((ptrdiff_t) node2->content);  | 
359  | 7.09M  |   if (l1 < l2)  | 
360  | 4.90M  |       return(1);  | 
361  | 2.18M  |   if (l1 > l2)  | 
362  | 2.18M  |       return(-1);  | 
363  | 2.18M  |     }  | 
364  |  |  | 
365  | 4.05M  | turtle_comparison:  | 
366  |  |  | 
367  | 4.05M  |     if (node1 == node2->prev)  | 
368  | 2.02M  |   return(1);  | 
369  | 2.02M  |     if (node1 == node2->next)  | 
370  | 40.1k  |   return(-1);  | 
371  |  |     /*  | 
372  |  |      * compute depth to root  | 
373  |  |      */  | 
374  | 3.32M  |     for (depth2 = 0, cur = node2; cur->parent != NULL; cur = cur->parent) { | 
375  | 1.95M  |   if (cur->parent == node1)  | 
376  | 607k  |       return(1);  | 
377  | 1.34M  |   depth2++;  | 
378  | 1.34M  |     }  | 
379  | 1.37M  |     root = cur;  | 
380  | 3.72M  |     for (depth1 = 0, cur = node1; cur->parent != NULL; cur = cur->parent) { | 
381  | 2.94M  |   if (cur->parent == node2)  | 
382  | 593k  |       return(-1);  | 
383  | 2.35M  |   depth1++;  | 
384  | 2.35M  |     }  | 
385  |  |     /*  | 
386  |  |      * Distinct document (or distinct entities :-( ) case.  | 
387  |  |      */  | 
388  | 782k  |     if (root != cur) { | 
389  | 40.1k  |   return(-2);  | 
390  | 40.1k  |     }  | 
391  |  |     /*  | 
392  |  |      * get the nearest common ancestor.  | 
393  |  |      */  | 
394  | 1.17M  |     while (depth1 > depth2) { | 
395  | 428k  |   depth1--;  | 
396  | 428k  |   node1 = node1->parent;  | 
397  | 428k  |     }  | 
398  | 867k  |     while (depth2 > depth1) { | 
399  | 124k  |   depth2--;  | 
400  | 124k  |   node2 = node2->parent;  | 
401  | 124k  |     }  | 
402  | 1.02M  |     while (node1->parent != node2->parent) { | 
403  | 286k  |   node1 = node1->parent;  | 
404  | 286k  |   node2 = node2->parent;  | 
405  |  |   /* should not happen but just in case ... */  | 
406  | 286k  |   if ((node1 == NULL) || (node2 == NULL))  | 
407  | 0  |       return(-2);  | 
408  | 286k  |     }  | 
409  |  |     /*  | 
410  |  |      * Find who's first.  | 
411  |  |      */  | 
412  | 742k  |     if (node1 == node2->prev)  | 
413  | 553k  |   return(1);  | 
414  | 189k  |     if (node1 == node2->next)  | 
415  | 141k  |   return(-1);  | 
416  |  |     /*  | 
417  |  |      * Speedup using document order if available.  | 
418  |  |      */  | 
419  | 47.8k  |     if ((node1->type == XML_ELEMENT_NODE) &&  | 
420  | 47.8k  |   (node2->type == XML_ELEMENT_NODE) &&  | 
421  | 47.8k  |   (0 > (ptrdiff_t) node1->content) &&  | 
422  | 47.8k  |   (0 > (ptrdiff_t) node2->content) &&  | 
423  | 47.8k  |   (node1->doc == node2->doc)) { | 
424  |  | 
  | 
425  | 0  |   l1 = -((ptrdiff_t) node1->content);  | 
426  | 0  |   l2 = -((ptrdiff_t) node2->content);  | 
427  | 0  |   if (l1 < l2)  | 
428  | 0  |       return(1);  | 
429  | 0  |   if (l1 > l2)  | 
430  | 0  |       return(-1);  | 
431  | 0  |     }  | 
432  |  |  | 
433  | 1.18M  |     for (cur = node1->next;cur != NULL;cur = cur->next)  | 
434  | 1.15M  |   if (cur == node2)  | 
435  | 21.3k  |       return(1);  | 
436  | 26.4k  |     return(-1); /* assume there is no sibling list corruption */  | 
437  | 47.8k  | }  | 
438  |  | #endif /* XP_OPTIMIZED_NON_ELEM_COMPARISON */  | 
439  |  |  | 
440  |  | /*  | 
441  |  |  * Wrapper for the Timsort algorithm from timsort.h  | 
442  |  |  */  | 
443  |  | #ifdef WITH_TIM_SORT  | 
444  |  | #define SORT_NAME libxml_domnode  | 
445  | 19.3M  | #define SORT_TYPE xmlNodePtr  | 
446  |  | /**  | 
447  |  |  * wrap_cmp:  | 
448  |  |  * @x: a node  | 
449  |  |  * @y: another node  | 
450  |  |  *  | 
451  |  |  * Comparison function for the Timsort implementation  | 
452  |  |  *  | 
453  |  |  * Returns -2 in case of error -1 if first point < second point, 0 if  | 
454  |  |  *         it's the same node, +1 otherwise  | 
455  |  |  */  | 
456  |  | static  | 
457  |  | int wrap_cmp( xmlNodePtr x, xmlNodePtr y );  | 
458  |  | #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON  | 
459  |  |     static int wrap_cmp( xmlNodePtr x, xmlNodePtr y )  | 
460  | 26.6M  |     { | 
461  | 26.6M  |         int res = xmlXPathCmpNodesExt(x, y);  | 
462  | 26.6M  |         return res == -2 ? res : -res;  | 
463  | 26.6M  |     }  | 
464  |  | #else  | 
465  |  |     static int wrap_cmp( xmlNodePtr x, xmlNodePtr y )  | 
466  |  |     { | 
467  |  |         int res = xmlXPathCmpNodes(x, y);  | 
468  |  |         return res == -2 ? res : -res;  | 
469  |  |     }  | 
470  |  | #endif  | 
471  | 26.6M  | #define SORT_CMP(x, y)  (wrap_cmp(x, y))  | 
472  |  | #include "timsort.h"  | 
473  |  | #endif /* WITH_TIM_SORT */  | 
474  |  |  | 
475  |  | #if defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)  | 
476  |  |  | 
477  |  | /************************************************************************  | 
478  |  |  *                  *  | 
479  |  |  *      Floating point stuff        *  | 
480  |  |  *                  *  | 
481  |  |  ************************************************************************/  | 
482  |  |  | 
483  |  | double xmlXPathNAN = 0.0;  | 
484  |  | double xmlXPathPINF = 0.0;  | 
485  |  | double xmlXPathNINF = 0.0;  | 
486  |  |  | 
487  |  | /**  | 
488  |  |  * xmlXPathInit:  | 
489  |  |  *  | 
490  |  |  * DEPRECATED: Alias for xmlInitParser.  | 
491  |  |  */  | 
492  |  | void  | 
493  | 0  | xmlXPathInit(void) { | 
494  | 0  |     xmlInitParser();  | 
495  | 0  | }  | 
496  |  |  | 
497  |  | /**  | 
498  |  |  * xmlInitXPathInternal:  | 
499  |  |  *  | 
500  |  |  * Initialize the XPath environment  | 
501  |  |  */  | 
502  |  | ATTRIBUTE_NO_SANITIZE("float-divide-by-zero") | 
503  |  | void  | 
504  | 3.70k  | xmlInitXPathInternal(void) { | 
505  | 3.70k  | #if defined(NAN) && defined(INFINITY)  | 
506  | 3.70k  |     xmlXPathNAN = NAN;  | 
507  | 3.70k  |     xmlXPathPINF = INFINITY;  | 
508  | 3.70k  |     xmlXPathNINF = -INFINITY;  | 
509  |  | #else  | 
510  |  |     /* MSVC doesn't allow division by zero in constant expressions. */  | 
511  |  |     double zero = 0.0;  | 
512  |  |     xmlXPathNAN = 0.0 / zero;  | 
513  |  |     xmlXPathPINF = 1.0 / zero;  | 
514  |  |     xmlXPathNINF = -xmlXPathPINF;  | 
515  |  | #endif  | 
516  | 3.70k  | }  | 
517  |  |  | 
518  |  | /**  | 
519  |  |  * xmlXPathIsNaN:  | 
520  |  |  * @val:  a double value  | 
521  |  |  *  | 
522  |  |  * Returns 1 if the value is a NaN, 0 otherwise  | 
523  |  |  */  | 
524  |  | int  | 
525  | 12.5M  | xmlXPathIsNaN(double val) { | 
526  | 12.5M  | #ifdef isnan  | 
527  | 12.5M  |     return isnan(val);  | 
528  |  | #else  | 
529  |  |     return !(val == val);  | 
530  |  | #endif  | 
531  | 12.5M  | }  | 
532  |  |  | 
533  |  | /**  | 
534  |  |  * xmlXPathIsInf:  | 
535  |  |  * @val:  a double value  | 
536  |  |  *  | 
537  |  |  * Returns 1 if the value is +Infinite, -1 if -Infinite, 0 otherwise  | 
538  |  |  */  | 
539  |  | int  | 
540  | 6.22M  | xmlXPathIsInf(double val) { | 
541  | 6.22M  | #ifdef isinf  | 
542  | 6.22M  |     return isinf(val) ? (val > 0 ? 1 : -1) : 0;  | 
543  |  | #else  | 
544  |  |     if (val >= xmlXPathPINF)  | 
545  |  |         return 1;  | 
546  |  |     if (val <= -xmlXPathPINF)  | 
547  |  |         return -1;  | 
548  |  |     return 0;  | 
549  |  | #endif  | 
550  | 6.22M  | }  | 
551  |  |  | 
552  |  | #endif /* SCHEMAS or XPATH */  | 
553  |  |  | 
554  |  | #ifdef LIBXML_XPATH_ENABLED  | 
555  |  |  | 
556  |  | /*  | 
557  |  |  * TODO: when compatibility allows remove all "fake node libxslt" strings  | 
558  |  |  *       the test should just be name[0] = ' '  | 
559  |  |  */  | 
560  |  | #ifdef DEBUG_XPATH_EXPRESSION  | 
561  |  | #define DEBUG_STEP  | 
562  |  | #define DEBUG_EXPR  | 
563  |  | #define DEBUG_EVAL_COUNTS  | 
564  |  | #endif  | 
565  |  |  | 
566  |  | static xmlNs xmlXPathXMLNamespaceStruct = { | 
567  |  |     NULL,  | 
568  |  |     XML_NAMESPACE_DECL,  | 
569  |  |     XML_XML_NAMESPACE,  | 
570  |  |     BAD_CAST "xml",  | 
571  |  |     NULL,  | 
572  |  |     NULL  | 
573  |  | };  | 
574  |  | static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct;  | 
575  |  | #ifndef LIBXML_THREAD_ENABLED  | 
576  |  | /*  | 
577  |  |  * Optimizer is disabled only when threaded apps are detected while  | 
578  |  |  * the library ain't compiled for thread safety.  | 
579  |  |  */  | 
580  |  | static int xmlXPathDisableOptimizer = 0;  | 
581  |  | #endif  | 
582  |  |  | 
583  |  | /************************************************************************  | 
584  |  |  *                  *  | 
585  |  |  *      Error handling routines       *  | 
586  |  |  *                  *  | 
587  |  |  ************************************************************************/  | 
588  |  |  | 
589  |  | /**  | 
590  |  |  * XP_ERRORNULL:  | 
591  |  |  * @X:  the error code  | 
592  |  |  *  | 
593  |  |  * Macro to raise an XPath error and return NULL.  | 
594  |  |  */  | 
595  |  | #define XP_ERRORNULL(X)             \  | 
596  | 202k  |     { xmlXPathErr(ctxt, X); return(NULL); } | 
597  |  |  | 
598  |  | /*  | 
599  |  |  * The array xmlXPathErrorMessages corresponds to the enum xmlXPathError  | 
600  |  |  */  | 
601  |  | static const char* const xmlXPathErrorMessages[] = { | 
602  |  |     "Ok\n",  | 
603  |  |     "Number encoding\n",  | 
604  |  |     "Unfinished literal\n",  | 
605  |  |     "Start of literal\n",  | 
606  |  |     "Expected $ for variable reference\n",  | 
607  |  |     "Undefined variable\n",  | 
608  |  |     "Invalid predicate\n",  | 
609  |  |     "Invalid expression\n",  | 
610  |  |     "Missing closing curly brace\n",  | 
611  |  |     "Unregistered function\n",  | 
612  |  |     "Invalid operand\n",  | 
613  |  |     "Invalid type\n",  | 
614  |  |     "Invalid number of arguments\n",  | 
615  |  |     "Invalid context size\n",  | 
616  |  |     "Invalid context position\n",  | 
617  |  |     "Memory allocation error\n",  | 
618  |  |     "Syntax error\n",  | 
619  |  |     "Resource error\n",  | 
620  |  |     "Sub resource error\n",  | 
621  |  |     "Undefined namespace prefix\n",  | 
622  |  |     "Encoding error\n",  | 
623  |  |     "Char out of XML range\n",  | 
624  |  |     "Invalid or incomplete context\n",  | 
625  |  |     "Stack usage error\n",  | 
626  |  |     "Forbidden variable\n",  | 
627  |  |     "Operation limit exceeded\n",  | 
628  |  |     "Recursion limit exceeded\n",  | 
629  |  |     "?? Unknown error ??\n" /* Must be last in the list! */  | 
630  |  | };  | 
631  | 15.9M  | #define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) /  \  | 
632  | 15.9M  |        sizeof(xmlXPathErrorMessages[0])) - 1)  | 
633  |  | /**  | 
634  |  |  * xmlXPathErrMemory:  | 
635  |  |  * @ctxt:  an XPath context  | 
636  |  |  * @extra:  extra information  | 
637  |  |  *  | 
638  |  |  * Handle a redefinition of attribute error  | 
639  |  |  */  | 
640  |  | static void  | 
641  |  | xmlXPathErrMemory(xmlXPathContextPtr ctxt, const char *extra)  | 
642  | 0  | { | 
643  | 0  |     if (ctxt != NULL) { | 
644  | 0  |         xmlResetError(&ctxt->lastError);  | 
645  | 0  |         if (extra) { | 
646  | 0  |             xmlChar buf[200];  | 
647  |  | 
  | 
648  | 0  |             xmlStrPrintf(buf, 200,  | 
649  | 0  |                          "Memory allocation failed : %s\n",  | 
650  | 0  |                          extra);  | 
651  | 0  |             ctxt->lastError.message = (char *) xmlStrdup(buf);  | 
652  | 0  |         } else { | 
653  | 0  |             ctxt->lastError.message = (char *)  | 
654  | 0  |          xmlStrdup(BAD_CAST "Memory allocation failed\n");  | 
655  | 0  |         }  | 
656  | 0  |         ctxt->lastError.domain = XML_FROM_XPATH;  | 
657  | 0  |         ctxt->lastError.code = XML_ERR_NO_MEMORY;  | 
658  | 0  |   if (ctxt->error != NULL)  | 
659  | 0  |       ctxt->error(ctxt->userData, &ctxt->lastError);  | 
660  | 0  |     } else { | 
661  | 0  |         if (extra)  | 
662  | 0  |             __xmlRaiseError(NULL, NULL, NULL,  | 
663  | 0  |                             NULL, NULL, XML_FROM_XPATH,  | 
664  | 0  |                             XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,  | 
665  | 0  |                             extra, NULL, NULL, 0, 0,  | 
666  | 0  |                             "Memory allocation failed : %s\n", extra);  | 
667  | 0  |         else  | 
668  | 0  |             __xmlRaiseError(NULL, NULL, NULL,  | 
669  | 0  |                             NULL, NULL, XML_FROM_XPATH,  | 
670  | 0  |                             XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,  | 
671  | 0  |                             NULL, NULL, NULL, 0, 0,  | 
672  | 0  |                             "Memory allocation failed\n");  | 
673  | 0  |     }  | 
674  | 0  | }  | 
675  |  |  | 
676  |  | /**  | 
677  |  |  * xmlXPathPErrMemory:  | 
678  |  |  * @ctxt:  an XPath parser context  | 
679  |  |  * @extra:  extra information  | 
680  |  |  *  | 
681  |  |  * Handle a redefinition of attribute error  | 
682  |  |  */  | 
683  |  | static void  | 
684  |  | xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt, const char *extra)  | 
685  | 0  | { | 
686  | 0  |     if (ctxt == NULL)  | 
687  | 0  |   xmlXPathErrMemory(NULL, extra);  | 
688  | 0  |     else { | 
689  | 0  |   ctxt->error = XPATH_MEMORY_ERROR;  | 
690  | 0  |   xmlXPathErrMemory(ctxt->context, extra);  | 
691  | 0  |     }  | 
692  | 0  | }  | 
693  |  |  | 
694  |  | /**  | 
695  |  |  * xmlXPathErr:  | 
696  |  |  * @ctxt:  a XPath parser context  | 
697  |  |  * @error:  the error code  | 
698  |  |  *  | 
699  |  |  * Handle an XPath error  | 
700  |  |  */  | 
701  |  | void  | 
702  |  | xmlXPathErr(xmlXPathParserContextPtr ctxt, int error)  | 
703  | 15.9M  | { | 
704  | 15.9M  |     if ((error < 0) || (error > MAXERRNO))  | 
705  | 0  |   error = MAXERRNO;  | 
706  | 15.9M  |     if (ctxt == NULL) { | 
707  | 0  |   __xmlRaiseError(NULL, NULL, NULL,  | 
708  | 0  |       NULL, NULL, XML_FROM_XPATH,  | 
709  | 0  |       error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,  | 
710  | 0  |       XML_ERR_ERROR, NULL, 0,  | 
711  | 0  |       NULL, NULL, NULL, 0, 0,  | 
712  | 0  |       "%s", xmlXPathErrorMessages[error]);  | 
713  | 0  |   return;  | 
714  | 0  |     }  | 
715  | 15.9M  |     ctxt->error = error;  | 
716  | 15.9M  |     if (ctxt->context == NULL) { | 
717  | 0  |   __xmlRaiseError(NULL, NULL, NULL,  | 
718  | 0  |       NULL, NULL, XML_FROM_XPATH,  | 
719  | 0  |       error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,  | 
720  | 0  |       XML_ERR_ERROR, NULL, 0,  | 
721  | 0  |       (const char *) ctxt->base, NULL, NULL,  | 
722  | 0  |       ctxt->cur - ctxt->base, 0,  | 
723  | 0  |       "%s", xmlXPathErrorMessages[error]);  | 
724  | 0  |   return;  | 
725  | 0  |     }  | 
726  |  |  | 
727  |  |     /* cleanup current last error */  | 
728  | 15.9M  |     xmlResetError(&ctxt->context->lastError);  | 
729  |  |  | 
730  | 15.9M  |     ctxt->context->lastError.domain = XML_FROM_XPATH;  | 
731  | 15.9M  |     ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK -  | 
732  | 15.9M  |                            XPATH_EXPRESSION_OK;  | 
733  | 15.9M  |     ctxt->context->lastError.level = XML_ERR_ERROR;  | 
734  | 15.9M  |     ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base);  | 
735  | 15.9M  |     ctxt->context->lastError.int1 = ctxt->cur - ctxt->base;  | 
736  | 15.9M  |     ctxt->context->lastError.node = ctxt->context->debugNode;  | 
737  | 15.9M  |     if (ctxt->context->error != NULL) { | 
738  | 0  |   ctxt->context->error(ctxt->context->userData,  | 
739  | 0  |                        &ctxt->context->lastError);  | 
740  | 15.9M  |     } else { | 
741  | 15.9M  |   __xmlRaiseError(NULL, NULL, NULL,  | 
742  | 15.9M  |       NULL, ctxt->context->debugNode, XML_FROM_XPATH,  | 
743  | 15.9M  |       error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,  | 
744  | 15.9M  |       XML_ERR_ERROR, NULL, 0,  | 
745  | 15.9M  |       (const char *) ctxt->base, NULL, NULL,  | 
746  | 15.9M  |       ctxt->cur - ctxt->base, 0,  | 
747  | 15.9M  |       "%s", xmlXPathErrorMessages[error]);  | 
748  | 15.9M  |     }  | 
749  |  |  | 
750  | 15.9M  | }  | 
751  |  |  | 
752  |  | /**  | 
753  |  |  * xmlXPatherror:  | 
754  |  |  * @ctxt:  the XPath Parser context  | 
755  |  |  * @file:  the file name  | 
756  |  |  * @line:  the line number  | 
757  |  |  * @no:  the error number  | 
758  |  |  *  | 
759  |  |  * Formats an error message.  | 
760  |  |  */  | 
761  |  | void  | 
762  |  | xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,  | 
763  | 341k  |               int line ATTRIBUTE_UNUSED, int no) { | 
764  | 341k  |     xmlXPathErr(ctxt, no);  | 
765  | 341k  | }  | 
766  |  |  | 
767  |  | /**  | 
768  |  |  * xmlXPathCheckOpLimit:  | 
769  |  |  * @ctxt:  the XPath Parser context  | 
770  |  |  * @opCount:  the number of operations to be added  | 
771  |  |  *  | 
772  |  |  * Adds opCount to the running total of operations and returns -1 if the  | 
773  |  |  * operation limit is exceeded. Returns 0 otherwise.  | 
774  |  |  */  | 
775  |  | static int  | 
776  | 424M  | xmlXPathCheckOpLimit(xmlXPathParserContextPtr ctxt, unsigned long opCount) { | 
777  | 424M  |     xmlXPathContextPtr xpctxt = ctxt->context;  | 
778  |  |  | 
779  | 424M  |     if ((opCount > xpctxt->opLimit) ||  | 
780  | 424M  |         (xpctxt->opCount > xpctxt->opLimit - opCount)) { | 
781  | 2.13k  |         xpctxt->opCount = xpctxt->opLimit;  | 
782  | 2.13k  |         xmlXPathErr(ctxt, XPATH_OP_LIMIT_EXCEEDED);  | 
783  | 2.13k  |         return(-1);  | 
784  | 2.13k  |     }  | 
785  |  |  | 
786  | 424M  |     xpctxt->opCount += opCount;  | 
787  | 424M  |     return(0);  | 
788  | 424M  | }  | 
789  |  |  | 
790  |  | #define OP_LIMIT_EXCEEDED(ctxt, n) \  | 
791  | 417M  |     ((ctxt->context->opLimit != 0) && (xmlXPathCheckOpLimit(ctxt, n) < 0))  | 
792  |  |  | 
793  |  | /************************************************************************  | 
794  |  |  *                  *  | 
795  |  |  *      Utilities         *  | 
796  |  |  *                  *  | 
797  |  |  ************************************************************************/  | 
798  |  |  | 
799  |  | /**  | 
800  |  |  * xsltPointerList:  | 
801  |  |  *  | 
802  |  |  * Pointer-list for various purposes.  | 
803  |  |  */  | 
804  |  | typedef struct _xmlPointerList xmlPointerList;  | 
805  |  | typedef xmlPointerList *xmlPointerListPtr;  | 
806  |  | struct _xmlPointerList { | 
807  |  |     void **items;  | 
808  |  |     int number;  | 
809  |  |     int size;  | 
810  |  | };  | 
811  |  | /*  | 
812  |  | * TODO: Since such a list-handling is used in xmlschemas.c and libxslt  | 
813  |  | * and here, we should make the functions public.  | 
814  |  | */  | 
815  |  | static int  | 
816  |  | xmlPointerListAddSize(xmlPointerListPtr list,  | 
817  |  |            void *item,  | 
818  |  |            int initialSize)  | 
819  | 80.0M  | { | 
820  | 80.0M  |     if (list->items == NULL) { | 
821  | 378k  |   if (initialSize <= 0)  | 
822  | 0  |       initialSize = 1;  | 
823  | 378k  |   list->items = (void **) xmlMalloc(initialSize * sizeof(void *));  | 
824  | 378k  |   if (list->items == NULL) { | 
825  | 0  |       xmlXPathErrMemory(NULL,  | 
826  | 0  |     "xmlPointerListCreate: allocating item\n");  | 
827  | 0  |       return(-1);  | 
828  | 0  |   }  | 
829  | 378k  |   list->number = 0;  | 
830  | 378k  |   list->size = initialSize;  | 
831  | 79.6M  |     } else if (list->size <= list->number) { | 
832  | 181k  |         if (list->size > 50000000) { | 
833  | 0  |       xmlXPathErrMemory(NULL,  | 
834  | 0  |     "xmlPointerListAddSize: re-allocating item\n");  | 
835  | 0  |             return(-1);  | 
836  | 0  |         }  | 
837  | 181k  |   list->size *= 2;  | 
838  | 181k  |   list->items = (void **) xmlRealloc(list->items,  | 
839  | 181k  |       list->size * sizeof(void *));  | 
840  | 181k  |   if (list->items == NULL) { | 
841  | 0  |       xmlXPathErrMemory(NULL,  | 
842  | 0  |     "xmlPointerListAddSize: re-allocating item\n");  | 
843  | 0  |       list->size = 0;  | 
844  | 0  |       return(-1);  | 
845  | 0  |   }  | 
846  | 181k  |     }  | 
847  | 80.0M  |     list->items[list->number++] = item;  | 
848  | 80.0M  |     return(0);  | 
849  | 80.0M  | }  | 
850  |  |  | 
851  |  | /**  | 
852  |  |  * xsltPointerListCreate:  | 
853  |  |  *  | 
854  |  |  * Creates an xsltPointerList structure.  | 
855  |  |  *  | 
856  |  |  * Returns a xsltPointerList structure or NULL in case of an error.  | 
857  |  |  */  | 
858  |  | static xmlPointerListPtr  | 
859  |  | xmlPointerListCreate(int initialSize)  | 
860  | 378k  | { | 
861  | 378k  |     xmlPointerListPtr ret;  | 
862  |  |  | 
863  | 378k  |     ret = xmlMalloc(sizeof(xmlPointerList));  | 
864  | 378k  |     if (ret == NULL) { | 
865  | 0  |   xmlXPathErrMemory(NULL,  | 
866  | 0  |       "xmlPointerListCreate: allocating item\n");  | 
867  | 0  |   return (NULL);  | 
868  | 0  |     }  | 
869  | 378k  |     memset(ret, 0, sizeof(xmlPointerList));  | 
870  | 378k  |     if (initialSize > 0) { | 
871  | 378k  |   xmlPointerListAddSize(ret, NULL, initialSize);  | 
872  | 378k  |   ret->number = 0;  | 
873  | 378k  |     }  | 
874  | 378k  |     return (ret);  | 
875  | 378k  | }  | 
876  |  |  | 
877  |  | /**  | 
878  |  |  * xsltPointerListFree:  | 
879  |  |  *  | 
880  |  |  * Frees the xsltPointerList structure. This does not free  | 
881  |  |  * the content of the list.  | 
882  |  |  */  | 
883  |  | static void  | 
884  |  | xmlPointerListFree(xmlPointerListPtr list)  | 
885  | 376k  | { | 
886  | 376k  |     if (list == NULL)  | 
887  | 0  |   return;  | 
888  | 376k  |     if (list->items != NULL)  | 
889  | 376k  |   xmlFree(list->items);  | 
890  | 376k  |     xmlFree(list);  | 
891  | 376k  | }  | 
892  |  |  | 
893  |  | /************************************************************************  | 
894  |  |  *                  *  | 
895  |  |  *      Parser Types          *  | 
896  |  |  *                  *  | 
897  |  |  ************************************************************************/  | 
898  |  |  | 
899  |  | /*  | 
900  |  |  * Types are private:  | 
901  |  |  */  | 
902  |  |  | 
903  |  | typedef enum { | 
904  |  |     XPATH_OP_END=0,  | 
905  |  |     XPATH_OP_AND,  | 
906  |  |     XPATH_OP_OR,  | 
907  |  |     XPATH_OP_EQUAL,  | 
908  |  |     XPATH_OP_CMP,  | 
909  |  |     XPATH_OP_PLUS,  | 
910  |  |     XPATH_OP_MULT,  | 
911  |  |     XPATH_OP_UNION,  | 
912  |  |     XPATH_OP_ROOT,  | 
913  |  |     XPATH_OP_NODE,  | 
914  |  |     XPATH_OP_COLLECT,  | 
915  |  |     XPATH_OP_VALUE, /* 11 */  | 
916  |  |     XPATH_OP_VARIABLE,  | 
917  |  |     XPATH_OP_FUNCTION,  | 
918  |  |     XPATH_OP_ARG,  | 
919  |  |     XPATH_OP_PREDICATE,  | 
920  |  |     XPATH_OP_FILTER, /* 16 */  | 
921  |  |     XPATH_OP_SORT /* 17 */  | 
922  |  | #ifdef LIBXML_XPTR_LOCS_ENABLED  | 
923  |  |     ,XPATH_OP_RANGETO  | 
924  |  | #endif  | 
925  |  | } xmlXPathOp;  | 
926  |  |  | 
927  |  | typedef enum { | 
928  |  |     AXIS_ANCESTOR = 1,  | 
929  |  |     AXIS_ANCESTOR_OR_SELF,  | 
930  |  |     AXIS_ATTRIBUTE,  | 
931  |  |     AXIS_CHILD,  | 
932  |  |     AXIS_DESCENDANT,  | 
933  |  |     AXIS_DESCENDANT_OR_SELF,  | 
934  |  |     AXIS_FOLLOWING,  | 
935  |  |     AXIS_FOLLOWING_SIBLING,  | 
936  |  |     AXIS_NAMESPACE,  | 
937  |  |     AXIS_PARENT,  | 
938  |  |     AXIS_PRECEDING,  | 
939  |  |     AXIS_PRECEDING_SIBLING,  | 
940  |  |     AXIS_SELF  | 
941  |  | } xmlXPathAxisVal;  | 
942  |  |  | 
943  |  | typedef enum { | 
944  |  |     NODE_TEST_NONE = 0,  | 
945  |  |     NODE_TEST_TYPE = 1,  | 
946  |  |     NODE_TEST_PI = 2,  | 
947  |  |     NODE_TEST_ALL = 3,  | 
948  |  |     NODE_TEST_NS = 4,  | 
949  |  |     NODE_TEST_NAME = 5  | 
950  |  | } xmlXPathTestVal;  | 
951  |  |  | 
952  |  | typedef enum { | 
953  |  |     NODE_TYPE_NODE = 0,  | 
954  |  |     NODE_TYPE_COMMENT = XML_COMMENT_NODE,  | 
955  |  |     NODE_TYPE_TEXT = XML_TEXT_NODE,  | 
956  |  |     NODE_TYPE_PI = XML_PI_NODE  | 
957  |  | } xmlXPathTypeVal;  | 
958  |  |  | 
959  |  | typedef struct _xmlXPathStepOp xmlXPathStepOp;  | 
960  |  | typedef xmlXPathStepOp *xmlXPathStepOpPtr;  | 
961  |  | struct _xmlXPathStepOp { | 
962  |  |     xmlXPathOp op;    /* The identifier of the operation */  | 
963  |  |     int ch1;      /* First child */  | 
964  |  |     int ch2;      /* Second child */  | 
965  |  |     int value;  | 
966  |  |     int value2;  | 
967  |  |     int value3;  | 
968  |  |     void *value4;  | 
969  |  |     void *value5;  | 
970  |  |     xmlXPathFunction cache;  | 
971  |  |     void *cacheURI;  | 
972  |  | };  | 
973  |  |  | 
974  |  | struct _xmlXPathCompExpr { | 
975  |  |     int nbStep;     /* Number of steps in this expression */  | 
976  |  |     int maxStep;    /* Maximum number of steps allocated */  | 
977  |  |     xmlXPathStepOp *steps;  /* ops for computation of this expression */  | 
978  |  |     int last;     /* index of last step in expression */  | 
979  |  |     xmlChar *expr;    /* the expression being computed */  | 
980  |  |     xmlDictPtr dict;    /* the dictionary to use if any */  | 
981  |  | #ifdef DEBUG_EVAL_COUNTS  | 
982  |  |     int nb;  | 
983  |  |     xmlChar *string;  | 
984  |  | #endif  | 
985  |  | #ifdef XPATH_STREAMING  | 
986  |  |     xmlPatternPtr stream;  | 
987  |  | #endif  | 
988  |  | };  | 
989  |  |  | 
990  |  | /************************************************************************  | 
991  |  |  *                  *  | 
992  |  |  *      Forward declarations        *  | 
993  |  |  *                  *  | 
994  |  |  ************************************************************************/  | 
995  |  | static void  | 
996  |  | xmlXPathFreeValueTree(xmlNodeSetPtr obj);  | 
997  |  | static void  | 
998  |  | xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj);  | 
999  |  | static int  | 
1000  |  | xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,  | 
1001  |  |                         xmlXPathStepOpPtr op, xmlNodePtr *first);  | 
1002  |  | static int  | 
1003  |  | xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,  | 
1004  |  |           xmlXPathStepOpPtr op,  | 
1005  |  |           int isPredicate);  | 
1006  |  | static void  | 
1007  |  | xmlXPathFreeObjectEntry(void *obj, const xmlChar *name);  | 
1008  |  |  | 
1009  |  | /************************************************************************  | 
1010  |  |  *                  *  | 
1011  |  |  *      Parser Type functions       *  | 
1012  |  |  *                  *  | 
1013  |  |  ************************************************************************/  | 
1014  |  |  | 
1015  |  | /**  | 
1016  |  |  * xmlXPathNewCompExpr:  | 
1017  |  |  *  | 
1018  |  |  * Create a new Xpath component  | 
1019  |  |  *  | 
1020  |  |  * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error  | 
1021  |  |  */  | 
1022  |  | static xmlXPathCompExprPtr  | 
1023  | 1.41M  | xmlXPathNewCompExpr(void) { | 
1024  | 1.41M  |     xmlXPathCompExprPtr cur;  | 
1025  |  |  | 
1026  | 1.41M  |     cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));  | 
1027  | 1.41M  |     if (cur == NULL) { | 
1028  | 0  |         xmlXPathErrMemory(NULL, "allocating component\n");  | 
1029  | 0  |   return(NULL);  | 
1030  | 0  |     }  | 
1031  | 1.41M  |     memset(cur, 0, sizeof(xmlXPathCompExpr));  | 
1032  | 1.41M  |     cur->maxStep = 10;  | 
1033  | 1.41M  |     cur->nbStep = 0;  | 
1034  | 1.41M  |     cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *  | 
1035  | 1.41M  |                                      sizeof(xmlXPathStepOp));  | 
1036  | 1.41M  |     if (cur->steps == NULL) { | 
1037  | 0  |         xmlXPathErrMemory(NULL, "allocating steps\n");  | 
1038  | 0  |   xmlFree(cur);  | 
1039  | 0  |   return(NULL);  | 
1040  | 0  |     }  | 
1041  | 1.41M  |     memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));  | 
1042  | 1.41M  |     cur->last = -1;  | 
1043  |  | #ifdef DEBUG_EVAL_COUNTS  | 
1044  |  |     cur->nb = 0;  | 
1045  |  | #endif  | 
1046  | 1.41M  |     return(cur);  | 
1047  | 1.41M  | }  | 
1048  |  |  | 
1049  |  | /**  | 
1050  |  |  * xmlXPathFreeCompExpr:  | 
1051  |  |  * @comp:  an XPATH comp  | 
1052  |  |  *  | 
1053  |  |  * Free up the memory allocated by @comp  | 
1054  |  |  */  | 
1055  |  | void  | 
1056  |  | xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)  | 
1057  | 1.41M  | { | 
1058  | 1.41M  |     xmlXPathStepOpPtr op;  | 
1059  | 1.41M  |     int i;  | 
1060  |  |  | 
1061  | 1.41M  |     if (comp == NULL)  | 
1062  | 0  |         return;  | 
1063  | 1.41M  |     if (comp->dict == NULL) { | 
1064  | 45.6M  |   for (i = 0; i < comp->nbStep; i++) { | 
1065  | 44.2M  |       op = &comp->steps[i];  | 
1066  | 44.2M  |       if (op->value4 != NULL) { | 
1067  | 2.50M  |     if (op->op == XPATH_OP_VALUE)  | 
1068  | 1.52M  |         xmlXPathFreeObject(op->value4);  | 
1069  | 976k  |     else  | 
1070  | 976k  |         xmlFree(op->value4);  | 
1071  | 2.50M  |       }  | 
1072  | 44.2M  |       if (op->value5 != NULL)  | 
1073  | 4.21M  |     xmlFree(op->value5);  | 
1074  | 44.2M  |   }  | 
1075  | 1.41M  |     } else { | 
1076  | 0  |   for (i = 0; i < comp->nbStep; i++) { | 
1077  | 0  |       op = &comp->steps[i];  | 
1078  | 0  |       if (op->value4 != NULL) { | 
1079  | 0  |     if (op->op == XPATH_OP_VALUE)  | 
1080  | 0  |         xmlXPathFreeObject(op->value4);  | 
1081  | 0  |       }  | 
1082  | 0  |   }  | 
1083  | 0  |         xmlDictFree(comp->dict);  | 
1084  | 0  |     }  | 
1085  | 1.41M  |     if (comp->steps != NULL) { | 
1086  | 1.41M  |         xmlFree(comp->steps);  | 
1087  | 1.41M  |     }  | 
1088  |  | #ifdef DEBUG_EVAL_COUNTS  | 
1089  |  |     if (comp->string != NULL) { | 
1090  |  |         xmlFree(comp->string);  | 
1091  |  |     }  | 
1092  |  | #endif  | 
1093  | 1.41M  | #ifdef XPATH_STREAMING  | 
1094  | 1.41M  |     if (comp->stream != NULL) { | 
1095  | 95.2k  |         xmlFreePatternList(comp->stream);  | 
1096  | 95.2k  |     }  | 
1097  | 1.41M  | #endif  | 
1098  | 1.41M  |     if (comp->expr != NULL) { | 
1099  | 351k  |         xmlFree(comp->expr);  | 
1100  | 351k  |     }  | 
1101  |  |  | 
1102  | 1.41M  |     xmlFree(comp);  | 
1103  | 1.41M  | }  | 
1104  |  |  | 
1105  |  | /**  | 
1106  |  |  * xmlXPathCompExprAdd:  | 
1107  |  |  * @comp:  the compiled expression  | 
1108  |  |  * @ch1: first child index  | 
1109  |  |  * @ch2: second child index  | 
1110  |  |  * @op:  an op  | 
1111  |  |  * @value:  the first int value  | 
1112  |  |  * @value2:  the second int value  | 
1113  |  |  * @value3:  the third int value  | 
1114  |  |  * @value4:  the first string value  | 
1115  |  |  * @value5:  the second string value  | 
1116  |  |  *  | 
1117  |  |  * Add a step to an XPath Compiled Expression  | 
1118  |  |  *  | 
1119  |  |  * Returns -1 in case of failure, the index otherwise  | 
1120  |  |  */  | 
1121  |  | static int  | 
1122  |  | xmlXPathCompExprAdd(xmlXPathParserContextPtr ctxt, int ch1, int ch2,  | 
1123  |  |    xmlXPathOp op, int value,  | 
1124  | 44.2M  |    int value2, int value3, void *value4, void *value5) { | 
1125  | 44.2M  |     xmlXPathCompExprPtr comp = ctxt->comp;  | 
1126  | 44.2M  |     if (comp->nbStep >= comp->maxStep) { | 
1127  | 776k  |   xmlXPathStepOp *real;  | 
1128  |  |  | 
1129  | 776k  |         if (comp->maxStep >= XPATH_MAX_STEPS) { | 
1130  | 0  |       xmlXPathPErrMemory(ctxt, "adding step\n");  | 
1131  | 0  |       return(-1);  | 
1132  | 0  |         }  | 
1133  | 776k  |   comp->maxStep *= 2;  | 
1134  | 776k  |   real = (xmlXPathStepOp *) xmlRealloc(comp->steps,  | 
1135  | 776k  |                           comp->maxStep * sizeof(xmlXPathStepOp));  | 
1136  | 776k  |   if (real == NULL) { | 
1137  | 0  |       comp->maxStep /= 2;  | 
1138  | 0  |       xmlXPathPErrMemory(ctxt, "adding step\n");  | 
1139  | 0  |       return(-1);  | 
1140  | 0  |   }  | 
1141  | 776k  |   comp->steps = real;  | 
1142  | 776k  |     }  | 
1143  | 44.2M  |     comp->last = comp->nbStep;  | 
1144  | 44.2M  |     comp->steps[comp->nbStep].ch1 = ch1;  | 
1145  | 44.2M  |     comp->steps[comp->nbStep].ch2 = ch2;  | 
1146  | 44.2M  |     comp->steps[comp->nbStep].op = op;  | 
1147  | 44.2M  |     comp->steps[comp->nbStep].value = value;  | 
1148  | 44.2M  |     comp->steps[comp->nbStep].value2 = value2;  | 
1149  | 44.2M  |     comp->steps[comp->nbStep].value3 = value3;  | 
1150  | 44.2M  |     if ((comp->dict != NULL) &&  | 
1151  | 44.2M  |         ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) ||  | 
1152  | 0  |    (op == XPATH_OP_COLLECT))) { | 
1153  | 0  |         if (value4 != NULL) { | 
1154  | 0  |       comp->steps[comp->nbStep].value4 = (xmlChar *)  | 
1155  | 0  |           (void *)xmlDictLookup(comp->dict, value4, -1);  | 
1156  | 0  |       xmlFree(value4);  | 
1157  | 0  |   } else  | 
1158  | 0  |       comp->steps[comp->nbStep].value4 = NULL;  | 
1159  | 0  |         if (value5 != NULL) { | 
1160  | 0  |       comp->steps[comp->nbStep].value5 = (xmlChar *)  | 
1161  | 0  |           (void *)xmlDictLookup(comp->dict, value5, -1);  | 
1162  | 0  |       xmlFree(value5);  | 
1163  | 0  |   } else  | 
1164  | 0  |       comp->steps[comp->nbStep].value5 = NULL;  | 
1165  | 44.2M  |     } else { | 
1166  | 44.2M  |   comp->steps[comp->nbStep].value4 = value4;  | 
1167  | 44.2M  |   comp->steps[comp->nbStep].value5 = value5;  | 
1168  | 44.2M  |     }  | 
1169  | 44.2M  |     comp->steps[comp->nbStep].cache = NULL;  | 
1170  | 44.2M  |     return(comp->nbStep++);  | 
1171  | 44.2M  | }  | 
1172  |  |  | 
1173  |  | /**  | 
1174  |  |  * xmlXPathCompSwap:  | 
1175  |  |  * @comp:  the compiled expression  | 
1176  |  |  * @op: operation index  | 
1177  |  |  *  | 
1178  |  |  * Swaps 2 operations in the compiled expression  | 
1179  |  |  */  | 
1180  |  | static void  | 
1181  | 68.8k  | xmlXPathCompSwap(xmlXPathStepOpPtr op) { | 
1182  | 68.8k  |     int tmp;  | 
1183  |  |  | 
1184  |  | #ifndef LIBXML_THREAD_ENABLED  | 
1185  |  |     /*  | 
1186  |  |      * Since this manipulates possibly shared variables, this is  | 
1187  |  |      * disabled if one detects that the library is used in a multithreaded  | 
1188  |  |      * application  | 
1189  |  |      */  | 
1190  |  |     if (xmlXPathDisableOptimizer)  | 
1191  |  |   return;  | 
1192  |  | #endif  | 
1193  |  |  | 
1194  | 68.8k  |     tmp = op->ch1;  | 
1195  | 68.8k  |     op->ch1 = op->ch2;  | 
1196  | 68.8k  |     op->ch2 = tmp;  | 
1197  | 68.8k  | }  | 
1198  |  |  | 
1199  |  | #define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \  | 
1200  | 7.14M  |     xmlXPathCompExprAdd(ctxt, (op1), (op2),     \  | 
1201  | 7.14M  |                   (op), (val), (val2), (val3), (val4), (val5))  | 
1202  |  | #define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5)     \  | 
1203  | 4.46M  |     xmlXPathCompExprAdd(ctxt, ctxt->comp->last, -1,   \  | 
1204  | 4.46M  |                   (op), (val), (val2), (val3), (val4), (val5))  | 
1205  |  |  | 
1206  | 16.1M  | #define PUSH_LEAVE_EXPR(op, val, val2)          \  | 
1207  | 16.1M  | xmlXPathCompExprAdd(ctxt, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)  | 
1208  |  |  | 
1209  | 1.33M  | #define PUSH_UNARY_EXPR(op, ch, val, val2)        \  | 
1210  | 1.33M  | xmlXPathCompExprAdd(ctxt, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)  | 
1211  |  |  | 
1212  | 15.2M  | #define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2)     \  | 
1213  | 15.2M  | xmlXPathCompExprAdd(ctxt, (ch1), (ch2), (op),     \  | 
1214  | 15.2M  |       (val), (val2), 0 ,NULL ,NULL)  | 
1215  |  |  | 
1216  |  | /************************************************************************  | 
1217  |  |  *                  *  | 
1218  |  |  *    XPath object cache structures       *  | 
1219  |  |  *                  *  | 
1220  |  |  ************************************************************************/  | 
1221  |  |  | 
1222  |  | /* #define XP_DEFAULT_CACHE_ON */  | 
1223  |  |  | 
1224  | 11.8M  | #define XP_HAS_CACHE(c) ((c != NULL) && ((c)->cache != NULL))  | 
1225  |  |  | 
1226  |  | typedef struct _xmlXPathContextCache xmlXPathContextCache;  | 
1227  |  | typedef xmlXPathContextCache *xmlXPathContextCachePtr;  | 
1228  |  | struct _xmlXPathContextCache { | 
1229  |  |     xmlPointerListPtr nodesetObjs;  /* contains xmlXPathObjectPtr */  | 
1230  |  |     xmlPointerListPtr stringObjs;   /* contains xmlXPathObjectPtr */  | 
1231  |  |     xmlPointerListPtr booleanObjs;  /* contains xmlXPathObjectPtr */  | 
1232  |  |     xmlPointerListPtr numberObjs;   /* contains xmlXPathObjectPtr */  | 
1233  |  |     xmlPointerListPtr miscObjs;     /* contains xmlXPathObjectPtr */  | 
1234  |  |     int maxNodeset;  | 
1235  |  |     int maxString;  | 
1236  |  |     int maxBoolean;  | 
1237  |  |     int maxNumber;  | 
1238  |  |     int maxMisc;  | 
1239  |  | #ifdef XP_DEBUG_OBJ_USAGE  | 
1240  |  |     int dbgCachedAll;  | 
1241  |  |     int dbgCachedNodeset;  | 
1242  |  |     int dbgCachedString;  | 
1243  |  |     int dbgCachedBool;  | 
1244  |  |     int dbgCachedNumber;  | 
1245  |  |     int dbgCachedPoint;  | 
1246  |  |     int dbgCachedRange;  | 
1247  |  |     int dbgCachedLocset;  | 
1248  |  |     int dbgCachedUsers;  | 
1249  |  |     int dbgCachedXSLTTree;  | 
1250  |  |     int dbgCachedUndefined;  | 
1251  |  |  | 
1252  |  |  | 
1253  |  |     int dbgReusedAll;  | 
1254  |  |     int dbgReusedNodeset;  | 
1255  |  |     int dbgReusedString;  | 
1256  |  |     int dbgReusedBool;  | 
1257  |  |     int dbgReusedNumber;  | 
1258  |  |     int dbgReusedPoint;  | 
1259  |  |     int dbgReusedRange;  | 
1260  |  |     int dbgReusedLocset;  | 
1261  |  |     int dbgReusedUsers;  | 
1262  |  |     int dbgReusedXSLTTree;  | 
1263  |  |     int dbgReusedUndefined;  | 
1264  |  |  | 
1265  |  | #endif  | 
1266  |  | };  | 
1267  |  |  | 
1268  |  | /************************************************************************  | 
1269  |  |  *                  *  | 
1270  |  |  *    Debugging related functions       *  | 
1271  |  |  *                  *  | 
1272  |  |  ************************************************************************/  | 
1273  |  |  | 
1274  |  | #define STRANGE             \  | 
1275  | 43  |     xmlGenericError(xmlGenericErrorContext,       \  | 
1276  | 43  |       "Internal error at %s:%d\n",        \  | 
1277  | 43  |             __FILE__, __LINE__);  | 
1278  |  |  | 
1279  |  | #ifdef LIBXML_DEBUG_ENABLED  | 
1280  |  | static void  | 
1281  | 0  | xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) { | 
1282  | 0  |     int i;  | 
1283  | 0  |     char shift[100];  | 
1284  |  | 
  | 
1285  | 0  |     for (i = 0;((i < depth) && (i < 25));i++)  | 
1286  | 0  |         shift[2 * i] = shift[2 * i + 1] = ' ';  | 
1287  | 0  |     shift[2 * i] = shift[2 * i + 1] = 0;  | 
1288  | 0  |     if (cur == NULL) { | 
1289  | 0  |   fprintf(output, "%s", shift);  | 
1290  | 0  |   fprintf(output, "Node is NULL !\n");  | 
1291  | 0  |   return;  | 
1292  |  | 
  | 
1293  | 0  |     }  | 
1294  |  |  | 
1295  | 0  |     if ((cur->type == XML_DOCUMENT_NODE) ||  | 
1296  | 0  |        (cur->type == XML_HTML_DOCUMENT_NODE)) { | 
1297  | 0  |   fprintf(output, "%s", shift);  | 
1298  | 0  |   fprintf(output, " /\n");  | 
1299  | 0  |     } else if (cur->type == XML_ATTRIBUTE_NODE)  | 
1300  | 0  |   xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);  | 
1301  | 0  |     else  | 
1302  | 0  |   xmlDebugDumpOneNode(output, cur, depth);  | 
1303  | 0  | }  | 
1304  |  | static void  | 
1305  | 0  | xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) { | 
1306  | 0  |     xmlNodePtr tmp;  | 
1307  | 0  |     int i;  | 
1308  | 0  |     char shift[100];  | 
1309  |  | 
  | 
1310  | 0  |     for (i = 0;((i < depth) && (i < 25));i++)  | 
1311  | 0  |         shift[2 * i] = shift[2 * i + 1] = ' ';  | 
1312  | 0  |     shift[2 * i] = shift[2 * i + 1] = 0;  | 
1313  | 0  |     if (cur == NULL) { | 
1314  | 0  |   fprintf(output, "%s", shift);  | 
1315  | 0  |   fprintf(output, "Node is NULL !\n");  | 
1316  | 0  |   return;  | 
1317  |  | 
  | 
1318  | 0  |     }  | 
1319  |  |  | 
1320  | 0  |     while (cur != NULL) { | 
1321  | 0  |   tmp = cur;  | 
1322  | 0  |   cur = cur->next;  | 
1323  | 0  |   xmlDebugDumpOneNode(output, tmp, depth);  | 
1324  | 0  |     }  | 
1325  | 0  | }  | 
1326  |  |  | 
1327  |  | static void  | 
1328  | 0  | xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) { | 
1329  | 0  |     int i;  | 
1330  | 0  |     char shift[100];  | 
1331  |  | 
  | 
1332  | 0  |     for (i = 0;((i < depth) && (i < 25));i++)  | 
1333  | 0  |         shift[2 * i] = shift[2 * i + 1] = ' ';  | 
1334  | 0  |     shift[2 * i] = shift[2 * i + 1] = 0;  | 
1335  |  | 
  | 
1336  | 0  |     if (cur == NULL) { | 
1337  | 0  |   fprintf(output, "%s", shift);  | 
1338  | 0  |   fprintf(output, "NodeSet is NULL !\n");  | 
1339  | 0  |   return;  | 
1340  |  | 
  | 
1341  | 0  |     }  | 
1342  |  |  | 
1343  | 0  |     if (cur != NULL) { | 
1344  | 0  |   fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);  | 
1345  | 0  |   for (i = 0;i < cur->nodeNr;i++) { | 
1346  | 0  |       fprintf(output, "%s", shift);  | 
1347  | 0  |       fprintf(output, "%d", i + 1);  | 
1348  | 0  |       xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);  | 
1349  | 0  |   }  | 
1350  | 0  |     }  | 
1351  | 0  | }  | 
1352  |  |  | 
1353  |  | static void  | 
1354  | 0  | xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) { | 
1355  | 0  |     int i;  | 
1356  | 0  |     char shift[100];  | 
1357  |  | 
  | 
1358  | 0  |     for (i = 0;((i < depth) && (i < 25));i++)  | 
1359  | 0  |         shift[2 * i] = shift[2 * i + 1] = ' ';  | 
1360  | 0  |     shift[2 * i] = shift[2 * i + 1] = 0;  | 
1361  |  | 
  | 
1362  | 0  |     if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) { | 
1363  | 0  |   fprintf(output, "%s", shift);  | 
1364  | 0  |   fprintf(output, "Value Tree is NULL !\n");  | 
1365  | 0  |   return;  | 
1366  |  | 
  | 
1367  | 0  |     }  | 
1368  |  |  | 
1369  | 0  |     fprintf(output, "%s", shift);  | 
1370  | 0  |     fprintf(output, "%d", i + 1);  | 
1371  | 0  |     xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);  | 
1372  | 0  | }  | 
1373  |  | #if defined(LIBXML_XPTR_LOCS_ENABLED)  | 
1374  |  | static void  | 
1375  |  | xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) { | 
1376  |  |     int i;  | 
1377  |  |     char shift[100];  | 
1378  |  |  | 
1379  |  |     for (i = 0;((i < depth) && (i < 25));i++)  | 
1380  |  |         shift[2 * i] = shift[2 * i + 1] = ' ';  | 
1381  |  |     shift[2 * i] = shift[2 * i + 1] = 0;  | 
1382  |  |  | 
1383  |  |     if (cur == NULL) { | 
1384  |  |   fprintf(output, "%s", shift);  | 
1385  |  |   fprintf(output, "LocationSet is NULL !\n");  | 
1386  |  |   return;  | 
1387  |  |  | 
1388  |  |     }  | 
1389  |  |  | 
1390  |  |     for (i = 0;i < cur->locNr;i++) { | 
1391  |  |   fprintf(output, "%s", shift);  | 
1392  |  |         fprintf(output, "%d : ", i + 1);  | 
1393  |  |   xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);  | 
1394  |  |     }  | 
1395  |  | }  | 
1396  |  | #endif /* LIBXML_XPTR_LOCS_ENABLED */  | 
1397  |  |  | 
1398  |  | /**  | 
1399  |  |  * xmlXPathDebugDumpObject:  | 
1400  |  |  * @output:  the FILE * to dump the output  | 
1401  |  |  * @cur:  the object to inspect  | 
1402  |  |  * @depth:  indentation level  | 
1403  |  |  *  | 
1404  |  |  * Dump the content of the object for debugging purposes  | 
1405  |  |  */  | 
1406  |  | void  | 
1407  | 0  | xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) { | 
1408  | 0  |     int i;  | 
1409  | 0  |     char shift[100];  | 
1410  |  | 
  | 
1411  | 0  |     if (output == NULL) return;  | 
1412  |  |  | 
1413  | 0  |     for (i = 0;((i < depth) && (i < 25));i++)  | 
1414  | 0  |         shift[2 * i] = shift[2 * i + 1] = ' ';  | 
1415  | 0  |     shift[2 * i] = shift[2 * i + 1] = 0;  | 
1416  |  |  | 
1417  |  | 
  | 
1418  | 0  |     fprintf(output, "%s", shift);  | 
1419  |  | 
  | 
1420  | 0  |     if (cur == NULL) { | 
1421  | 0  |         fprintf(output, "Object is empty (NULL)\n");  | 
1422  | 0  |   return;  | 
1423  | 0  |     }  | 
1424  | 0  |     switch(cur->type) { | 
1425  | 0  |         case XPATH_UNDEFINED:  | 
1426  | 0  |       fprintf(output, "Object is uninitialized\n");  | 
1427  | 0  |       break;  | 
1428  | 0  |         case XPATH_NODESET:  | 
1429  | 0  |       fprintf(output, "Object is a Node Set :\n");  | 
1430  | 0  |       xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);  | 
1431  | 0  |       break;  | 
1432  | 0  |   case XPATH_XSLT_TREE:  | 
1433  | 0  |       fprintf(output, "Object is an XSLT value tree :\n");  | 
1434  | 0  |       xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);  | 
1435  | 0  |       break;  | 
1436  | 0  |         case XPATH_BOOLEAN:  | 
1437  | 0  |       fprintf(output, "Object is a Boolean : ");  | 
1438  | 0  |       if (cur->boolval) fprintf(output, "true\n");  | 
1439  | 0  |       else fprintf(output, "false\n");  | 
1440  | 0  |       break;  | 
1441  | 0  |         case XPATH_NUMBER:  | 
1442  | 0  |       switch (xmlXPathIsInf(cur->floatval)) { | 
1443  | 0  |       case 1:  | 
1444  | 0  |     fprintf(output, "Object is a number : Infinity\n");  | 
1445  | 0  |     break;  | 
1446  | 0  |       case -1:  | 
1447  | 0  |     fprintf(output, "Object is a number : -Infinity\n");  | 
1448  | 0  |     break;  | 
1449  | 0  |       default:  | 
1450  | 0  |     if (xmlXPathIsNaN(cur->floatval)) { | 
1451  | 0  |         fprintf(output, "Object is a number : NaN\n");  | 
1452  | 0  |     } else if (cur->floatval == 0) { | 
1453  |  |                     /* Omit sign for negative zero. */  | 
1454  | 0  |         fprintf(output, "Object is a number : 0\n");  | 
1455  | 0  |     } else { | 
1456  | 0  |         fprintf(output, "Object is a number : %0g\n", cur->floatval);  | 
1457  | 0  |     }  | 
1458  | 0  |       }  | 
1459  | 0  |       break;  | 
1460  | 0  |         case XPATH_STRING:  | 
1461  | 0  |       fprintf(output, "Object is a string : ");  | 
1462  | 0  |       xmlDebugDumpString(output, cur->stringval);  | 
1463  | 0  |       fprintf(output, "\n");  | 
1464  | 0  |       break;  | 
1465  |  | #ifdef LIBXML_XPTR_LOCS_ENABLED  | 
1466  |  |   case XPATH_POINT:  | 
1467  |  |       fprintf(output, "Object is a point : index %d in node", cur->index);  | 
1468  |  |       xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);  | 
1469  |  |       fprintf(output, "\n");  | 
1470  |  |       break;  | 
1471  |  |   case XPATH_RANGE:  | 
1472  |  |       if ((cur->user2 == NULL) ||  | 
1473  |  |     ((cur->user2 == cur->user) && (cur->index == cur->index2))) { | 
1474  |  |     fprintf(output, "Object is a collapsed range :\n");  | 
1475  |  |     fprintf(output, "%s", shift);  | 
1476  |  |     if (cur->index >= 0)  | 
1477  |  |         fprintf(output, "index %d in ", cur->index);  | 
1478  |  |     fprintf(output, "node\n");  | 
1479  |  |     xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,  | 
1480  |  |                     depth + 1);  | 
1481  |  |       } else  { | 
1482  |  |     fprintf(output, "Object is a range :\n");  | 
1483  |  |     fprintf(output, "%s", shift);  | 
1484  |  |     fprintf(output, "From ");  | 
1485  |  |     if (cur->index >= 0)  | 
1486  |  |         fprintf(output, "index %d in ", cur->index);  | 
1487  |  |     fprintf(output, "node\n");  | 
1488  |  |     xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,  | 
1489  |  |                     depth + 1);  | 
1490  |  |     fprintf(output, "%s", shift);  | 
1491  |  |     fprintf(output, "To ");  | 
1492  |  |     if (cur->index2 >= 0)  | 
1493  |  |         fprintf(output, "index %d in ", cur->index2);  | 
1494  |  |     fprintf(output, "node\n");  | 
1495  |  |     xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,  | 
1496  |  |                     depth + 1);  | 
1497  |  |     fprintf(output, "\n");  | 
1498  |  |       }  | 
1499  |  |       break;  | 
1500  |  |   case XPATH_LOCATIONSET:  | 
1501  |  |       fprintf(output, "Object is a Location Set:\n");  | 
1502  |  |       xmlXPathDebugDumpLocationSet(output,  | 
1503  |  |         (xmlLocationSetPtr) cur->user, depth);  | 
1504  |  |       break;  | 
1505  |  | #endif /* LIBXML_XPTR_LOCS_ENABLED */  | 
1506  | 0  |   case XPATH_USERS:  | 
1507  | 0  |       fprintf(output, "Object is user defined\n");  | 
1508  | 0  |       break;  | 
1509  | 0  |     }  | 
1510  | 0  | }  | 
1511  |  |  | 
1512  |  | static void  | 
1513  |  | xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,  | 
1514  | 0  |                        xmlXPathStepOpPtr op, int depth) { | 
1515  | 0  |     int i;  | 
1516  | 0  |     char shift[100];  | 
1517  |  | 
  | 
1518  | 0  |     for (i = 0;((i < depth) && (i < 25));i++)  | 
1519  | 0  |         shift[2 * i] = shift[2 * i + 1] = ' ';  | 
1520  | 0  |     shift[2 * i] = shift[2 * i + 1] = 0;  | 
1521  |  | 
  | 
1522  | 0  |     fprintf(output, "%s", shift);  | 
1523  | 0  |     if (op == NULL) { | 
1524  | 0  |   fprintf(output, "Step is NULL\n");  | 
1525  | 0  |   return;  | 
1526  | 0  |     }  | 
1527  | 0  |     switch (op->op) { | 
1528  | 0  |         case XPATH_OP_END:  | 
1529  | 0  |       fprintf(output, "END"); break;  | 
1530  | 0  |         case XPATH_OP_AND:  | 
1531  | 0  |       fprintf(output, "AND"); break;  | 
1532  | 0  |         case XPATH_OP_OR:  | 
1533  | 0  |       fprintf(output, "OR"); break;  | 
1534  | 0  |         case XPATH_OP_EQUAL:  | 
1535  | 0  |        if (op->value)  | 
1536  | 0  |      fprintf(output, "EQUAL =");  | 
1537  | 0  |        else  | 
1538  | 0  |      fprintf(output, "EQUAL !=");  | 
1539  | 0  |        break;  | 
1540  | 0  |         case XPATH_OP_CMP:  | 
1541  | 0  |        if (op->value)  | 
1542  | 0  |      fprintf(output, "CMP <");  | 
1543  | 0  |        else  | 
1544  | 0  |      fprintf(output, "CMP >");  | 
1545  | 0  |        if (!op->value2)  | 
1546  | 0  |      fprintf(output, "=");  | 
1547  | 0  |        break;  | 
1548  | 0  |         case XPATH_OP_PLUS:  | 
1549  | 0  |        if (op->value == 0)  | 
1550  | 0  |      fprintf(output, "PLUS -");  | 
1551  | 0  |        else if (op->value == 1)  | 
1552  | 0  |      fprintf(output, "PLUS +");  | 
1553  | 0  |        else if (op->value == 2)  | 
1554  | 0  |      fprintf(output, "PLUS unary -");  | 
1555  | 0  |        else if (op->value == 3)  | 
1556  | 0  |      fprintf(output, "PLUS unary - -");  | 
1557  | 0  |        break;  | 
1558  | 0  |         case XPATH_OP_MULT:  | 
1559  | 0  |        if (op->value == 0)  | 
1560  | 0  |      fprintf(output, "MULT *");  | 
1561  | 0  |        else if (op->value == 1)  | 
1562  | 0  |      fprintf(output, "MULT div");  | 
1563  | 0  |        else  | 
1564  | 0  |      fprintf(output, "MULT mod");  | 
1565  | 0  |        break;  | 
1566  | 0  |         case XPATH_OP_UNION:  | 
1567  | 0  |        fprintf(output, "UNION"); break;  | 
1568  | 0  |         case XPATH_OP_ROOT:  | 
1569  | 0  |        fprintf(output, "ROOT"); break;  | 
1570  | 0  |         case XPATH_OP_NODE:  | 
1571  | 0  |        fprintf(output, "NODE"); break;  | 
1572  | 0  |         case XPATH_OP_SORT:  | 
1573  | 0  |        fprintf(output, "SORT"); break;  | 
1574  | 0  |         case XPATH_OP_COLLECT: { | 
1575  | 0  |       xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;  | 
1576  | 0  |       xmlXPathTestVal test = (xmlXPathTestVal)op->value2;  | 
1577  | 0  |       xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;  | 
1578  | 0  |       const xmlChar *prefix = op->value4;  | 
1579  | 0  |       const xmlChar *name = op->value5;  | 
1580  |  | 
  | 
1581  | 0  |       fprintf(output, "COLLECT ");  | 
1582  | 0  |       switch (axis) { | 
1583  | 0  |     case AXIS_ANCESTOR:  | 
1584  | 0  |         fprintf(output, " 'ancestors' "); break;  | 
1585  | 0  |     case AXIS_ANCESTOR_OR_SELF:  | 
1586  | 0  |         fprintf(output, " 'ancestors-or-self' "); break;  | 
1587  | 0  |     case AXIS_ATTRIBUTE:  | 
1588  | 0  |         fprintf(output, " 'attributes' "); break;  | 
1589  | 0  |     case AXIS_CHILD:  | 
1590  | 0  |         fprintf(output, " 'child' "); break;  | 
1591  | 0  |     case AXIS_DESCENDANT:  | 
1592  | 0  |         fprintf(output, " 'descendant' "); break;  | 
1593  | 0  |     case AXIS_DESCENDANT_OR_SELF:  | 
1594  | 0  |         fprintf(output, " 'descendant-or-self' "); break;  | 
1595  | 0  |     case AXIS_FOLLOWING:  | 
1596  | 0  |         fprintf(output, " 'following' "); break;  | 
1597  | 0  |     case AXIS_FOLLOWING_SIBLING:  | 
1598  | 0  |         fprintf(output, " 'following-siblings' "); break;  | 
1599  | 0  |     case AXIS_NAMESPACE:  | 
1600  | 0  |         fprintf(output, " 'namespace' "); break;  | 
1601  | 0  |     case AXIS_PARENT:  | 
1602  | 0  |         fprintf(output, " 'parent' "); break;  | 
1603  | 0  |     case AXIS_PRECEDING:  | 
1604  | 0  |         fprintf(output, " 'preceding' "); break;  | 
1605  | 0  |     case AXIS_PRECEDING_SIBLING:  | 
1606  | 0  |         fprintf(output, " 'preceding-sibling' "); break;  | 
1607  | 0  |     case AXIS_SELF:  | 
1608  | 0  |         fprintf(output, " 'self' "); break;  | 
1609  | 0  |       }  | 
1610  | 0  |       switch (test) { | 
1611  | 0  |                 case NODE_TEST_NONE:  | 
1612  | 0  |         fprintf(output, "'none' "); break;  | 
1613  | 0  |                 case NODE_TEST_TYPE:  | 
1614  | 0  |         fprintf(output, "'type' "); break;  | 
1615  | 0  |                 case NODE_TEST_PI:  | 
1616  | 0  |         fprintf(output, "'PI' "); break;  | 
1617  | 0  |                 case NODE_TEST_ALL:  | 
1618  | 0  |         fprintf(output, "'all' "); break;  | 
1619  | 0  |                 case NODE_TEST_NS:  | 
1620  | 0  |         fprintf(output, "'namespace' "); break;  | 
1621  | 0  |                 case NODE_TEST_NAME:  | 
1622  | 0  |         fprintf(output, "'name' "); break;  | 
1623  | 0  |       }  | 
1624  | 0  |       switch (type) { | 
1625  | 0  |                 case NODE_TYPE_NODE:  | 
1626  | 0  |         fprintf(output, "'node' "); break;  | 
1627  | 0  |                 case NODE_TYPE_COMMENT:  | 
1628  | 0  |         fprintf(output, "'comment' "); break;  | 
1629  | 0  |                 case NODE_TYPE_TEXT:  | 
1630  | 0  |         fprintf(output, "'text' "); break;  | 
1631  | 0  |                 case NODE_TYPE_PI:  | 
1632  | 0  |         fprintf(output, "'PI' "); break;  | 
1633  | 0  |       }  | 
1634  | 0  |       if (prefix != NULL)  | 
1635  | 0  |     fprintf(output, "%s:", prefix);  | 
1636  | 0  |       if (name != NULL)  | 
1637  | 0  |     fprintf(output, "%s", (const char *) name);  | 
1638  | 0  |       break;  | 
1639  |  | 
  | 
1640  | 0  |         }  | 
1641  | 0  |   case XPATH_OP_VALUE: { | 
1642  | 0  |       xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;  | 
1643  |  | 
  | 
1644  | 0  |       fprintf(output, "ELEM ");  | 
1645  | 0  |       xmlXPathDebugDumpObject(output, object, 0);  | 
1646  | 0  |       goto finish;  | 
1647  | 0  |   }  | 
1648  | 0  |   case XPATH_OP_VARIABLE: { | 
1649  | 0  |       const xmlChar *prefix = op->value5;  | 
1650  | 0  |       const xmlChar *name = op->value4;  | 
1651  |  | 
  | 
1652  | 0  |       if (prefix != NULL)  | 
1653  | 0  |     fprintf(output, "VARIABLE %s:%s", prefix, name);  | 
1654  | 0  |       else  | 
1655  | 0  |     fprintf(output, "VARIABLE %s", name);  | 
1656  | 0  |       break;  | 
1657  | 0  |   }  | 
1658  | 0  |   case XPATH_OP_FUNCTION: { | 
1659  | 0  |       int nbargs = op->value;  | 
1660  | 0  |       const xmlChar *prefix = op->value5;  | 
1661  | 0  |       const xmlChar *name = op->value4;  | 
1662  |  | 
  | 
1663  | 0  |       if (prefix != NULL)  | 
1664  | 0  |     fprintf(output, "FUNCTION %s:%s(%d args)",  | 
1665  | 0  |       prefix, name, nbargs);  | 
1666  | 0  |       else  | 
1667  | 0  |     fprintf(output, "FUNCTION %s(%d args)", name, nbargs);  | 
1668  | 0  |       break;  | 
1669  | 0  |   }  | 
1670  | 0  |         case XPATH_OP_ARG: fprintf(output, "ARG"); break;  | 
1671  | 0  |         case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;  | 
1672  | 0  |         case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;  | 
1673  |  | #ifdef LIBXML_XPTR_LOCS_ENABLED  | 
1674  |  |         case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;  | 
1675  |  | #endif  | 
1676  | 0  |   default:  | 
1677  | 0  |         fprintf(output, "UNKNOWN %d\n", op->op); return;  | 
1678  | 0  |     }  | 
1679  | 0  |     fprintf(output, "\n");  | 
1680  | 0  | finish:  | 
1681  | 0  |     if (op->ch1 >= 0)  | 
1682  | 0  |   xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);  | 
1683  | 0  |     if (op->ch2 >= 0)  | 
1684  | 0  |   xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);  | 
1685  | 0  | }  | 
1686  |  |  | 
1687  |  | /**  | 
1688  |  |  * xmlXPathDebugDumpCompExpr:  | 
1689  |  |  * @output:  the FILE * for the output  | 
1690  |  |  * @comp:  the precompiled XPath expression  | 
1691  |  |  * @depth:  the indentation level.  | 
1692  |  |  *  | 
1693  |  |  * Dumps the tree of the compiled XPath expression.  | 
1694  |  |  */  | 
1695  |  | void  | 
1696  |  | xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,  | 
1697  | 0  |                     int depth) { | 
1698  | 0  |     int i;  | 
1699  | 0  |     char shift[100];  | 
1700  |  | 
  | 
1701  | 0  |     if ((output == NULL) || (comp == NULL)) return;  | 
1702  |  |  | 
1703  | 0  |     for (i = 0;((i < depth) && (i < 25));i++)  | 
1704  | 0  |         shift[2 * i] = shift[2 * i + 1] = ' ';  | 
1705  | 0  |     shift[2 * i] = shift[2 * i + 1] = 0;  | 
1706  |  | 
  | 
1707  | 0  |     fprintf(output, "%s", shift);  | 
1708  |  | 
  | 
1709  | 0  | #ifdef XPATH_STREAMING  | 
1710  | 0  |     if (comp->stream) { | 
1711  | 0  |         fprintf(output, "Streaming Expression\n");  | 
1712  | 0  |     } else  | 
1713  | 0  | #endif  | 
1714  | 0  |     { | 
1715  | 0  |         fprintf(output, "Compiled Expression : %d elements\n",  | 
1716  | 0  |                 comp->nbStep);  | 
1717  | 0  |         i = comp->last;  | 
1718  | 0  |         xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);  | 
1719  | 0  |     }  | 
1720  | 0  | }  | 
1721  |  |  | 
1722  |  | #ifdef XP_DEBUG_OBJ_USAGE  | 
1723  |  |  | 
1724  |  | /*  | 
1725  |  | * XPath object usage related debugging variables.  | 
1726  |  | */  | 
1727  |  | static int xmlXPathDebugObjCounterUndefined = 0;  | 
1728  |  | static int xmlXPathDebugObjCounterNodeset = 0;  | 
1729  |  | static int xmlXPathDebugObjCounterBool = 0;  | 
1730  |  | static int xmlXPathDebugObjCounterNumber = 0;  | 
1731  |  | static int xmlXPathDebugObjCounterString = 0;  | 
1732  |  | static int xmlXPathDebugObjCounterPoint = 0;  | 
1733  |  | static int xmlXPathDebugObjCounterRange = 0;  | 
1734  |  | static int xmlXPathDebugObjCounterLocset = 0;  | 
1735  |  | static int xmlXPathDebugObjCounterUsers = 0;  | 
1736  |  | static int xmlXPathDebugObjCounterXSLTTree = 0;  | 
1737  |  | static int xmlXPathDebugObjCounterAll = 0;  | 
1738  |  |  | 
1739  |  | static int xmlXPathDebugObjTotalUndefined = 0;  | 
1740  |  | static int xmlXPathDebugObjTotalNodeset = 0;  | 
1741  |  | static int xmlXPathDebugObjTotalBool = 0;  | 
1742  |  | static int xmlXPathDebugObjTotalNumber = 0;  | 
1743  |  | static int xmlXPathDebugObjTotalString = 0;  | 
1744  |  | static int xmlXPathDebugObjTotalPoint = 0;  | 
1745  |  | static int xmlXPathDebugObjTotalRange = 0;  | 
1746  |  | static int xmlXPathDebugObjTotalLocset = 0;  | 
1747  |  | static int xmlXPathDebugObjTotalUsers = 0;  | 
1748  |  | static int xmlXPathDebugObjTotalXSLTTree = 0;  | 
1749  |  | static int xmlXPathDebugObjTotalAll = 0;  | 
1750  |  |  | 
1751  |  | static int xmlXPathDebugObjMaxUndefined = 0;  | 
1752  |  | static int xmlXPathDebugObjMaxNodeset = 0;  | 
1753  |  | static int xmlXPathDebugObjMaxBool = 0;  | 
1754  |  | static int xmlXPathDebugObjMaxNumber = 0;  | 
1755  |  | static int xmlXPathDebugObjMaxString = 0;  | 
1756  |  | static int xmlXPathDebugObjMaxPoint = 0;  | 
1757  |  | static int xmlXPathDebugObjMaxRange = 0;  | 
1758  |  | static int xmlXPathDebugObjMaxLocset = 0;  | 
1759  |  | static int xmlXPathDebugObjMaxUsers = 0;  | 
1760  |  | static int xmlXPathDebugObjMaxXSLTTree = 0;  | 
1761  |  | static int xmlXPathDebugObjMaxAll = 0;  | 
1762  |  |  | 
1763  |  | static void  | 
1764  |  | xmlXPathDebugObjUsageReset(xmlXPathContextPtr ctxt)  | 
1765  |  | { | 
1766  |  |     if (ctxt != NULL) { | 
1767  |  |   if (ctxt->cache != NULL) { | 
1768  |  |       xmlXPathContextCachePtr cache =  | 
1769  |  |     (xmlXPathContextCachePtr) ctxt->cache;  | 
1770  |  |  | 
1771  |  |       cache->dbgCachedAll = 0;  | 
1772  |  |       cache->dbgCachedNodeset = 0;  | 
1773  |  |       cache->dbgCachedString = 0;  | 
1774  |  |       cache->dbgCachedBool = 0;  | 
1775  |  |       cache->dbgCachedNumber = 0;  | 
1776  |  |       cache->dbgCachedPoint = 0;  | 
1777  |  |       cache->dbgCachedRange = 0;  | 
1778  |  |       cache->dbgCachedLocset = 0;  | 
1779  |  |       cache->dbgCachedUsers = 0;  | 
1780  |  |       cache->dbgCachedXSLTTree = 0;  | 
1781  |  |       cache->dbgCachedUndefined = 0;  | 
1782  |  |  | 
1783  |  |       cache->dbgReusedAll = 0;  | 
1784  |  |       cache->dbgReusedNodeset = 0;  | 
1785  |  |       cache->dbgReusedString = 0;  | 
1786  |  |       cache->dbgReusedBool = 0;  | 
1787  |  |       cache->dbgReusedNumber = 0;  | 
1788  |  |       cache->dbgReusedPoint = 0;  | 
1789  |  |       cache->dbgReusedRange = 0;  | 
1790  |  |       cache->dbgReusedLocset = 0;  | 
1791  |  |       cache->dbgReusedUsers = 0;  | 
1792  |  |       cache->dbgReusedXSLTTree = 0;  | 
1793  |  |       cache->dbgReusedUndefined = 0;  | 
1794  |  |   }  | 
1795  |  |     }  | 
1796  |  |  | 
1797  |  |     xmlXPathDebugObjCounterUndefined = 0;  | 
1798  |  |     xmlXPathDebugObjCounterNodeset = 0;  | 
1799  |  |     xmlXPathDebugObjCounterBool = 0;  | 
1800  |  |     xmlXPathDebugObjCounterNumber = 0;  | 
1801  |  |     xmlXPathDebugObjCounterString = 0;  | 
1802  |  |     xmlXPathDebugObjCounterPoint = 0;  | 
1803  |  |     xmlXPathDebugObjCounterRange = 0;  | 
1804  |  |     xmlXPathDebugObjCounterLocset = 0;  | 
1805  |  |     xmlXPathDebugObjCounterUsers = 0;  | 
1806  |  |     xmlXPathDebugObjCounterXSLTTree = 0;  | 
1807  |  |     xmlXPathDebugObjCounterAll = 0;  | 
1808  |  |  | 
1809  |  |     xmlXPathDebugObjTotalUndefined = 0;  | 
1810  |  |     xmlXPathDebugObjTotalNodeset = 0;  | 
1811  |  |     xmlXPathDebugObjTotalBool = 0;  | 
1812  |  |     xmlXPathDebugObjTotalNumber = 0;  | 
1813  |  |     xmlXPathDebugObjTotalString = 0;  | 
1814  |  |     xmlXPathDebugObjTotalPoint = 0;  | 
1815  |  |     xmlXPathDebugObjTotalRange = 0;  | 
1816  |  |     xmlXPathDebugObjTotalLocset = 0;  | 
1817  |  |     xmlXPathDebugObjTotalUsers = 0;  | 
1818  |  |     xmlXPathDebugObjTotalXSLTTree = 0;  | 
1819  |  |     xmlXPathDebugObjTotalAll = 0;  | 
1820  |  |  | 
1821  |  |     xmlXPathDebugObjMaxUndefined = 0;  | 
1822  |  |     xmlXPathDebugObjMaxNodeset = 0;  | 
1823  |  |     xmlXPathDebugObjMaxBool = 0;  | 
1824  |  |     xmlXPathDebugObjMaxNumber = 0;  | 
1825  |  |     xmlXPathDebugObjMaxString = 0;  | 
1826  |  |     xmlXPathDebugObjMaxPoint = 0;  | 
1827  |  |     xmlXPathDebugObjMaxRange = 0;  | 
1828  |  |     xmlXPathDebugObjMaxLocset = 0;  | 
1829  |  |     xmlXPathDebugObjMaxUsers = 0;  | 
1830  |  |     xmlXPathDebugObjMaxXSLTTree = 0;  | 
1831  |  |     xmlXPathDebugObjMaxAll = 0;  | 
1832  |  |  | 
1833  |  | }  | 
1834  |  |  | 
1835  |  | static void  | 
1836  |  | xmlXPathDebugObjUsageRequested(xmlXPathContextPtr ctxt,  | 
1837  |  |             xmlXPathObjectType objType)  | 
1838  |  | { | 
1839  |  |     int isCached = 0;  | 
1840  |  |  | 
1841  |  |     if (ctxt != NULL) { | 
1842  |  |   if (ctxt->cache != NULL) { | 
1843  |  |       xmlXPathContextCachePtr cache =  | 
1844  |  |     (xmlXPathContextCachePtr) ctxt->cache;  | 
1845  |  |  | 
1846  |  |       isCached = 1;  | 
1847  |  |  | 
1848  |  |       cache->dbgReusedAll++;  | 
1849  |  |       switch (objType) { | 
1850  |  |     case XPATH_UNDEFINED:  | 
1851  |  |         cache->dbgReusedUndefined++;  | 
1852  |  |         break;  | 
1853  |  |     case XPATH_NODESET:  | 
1854  |  |         cache->dbgReusedNodeset++;  | 
1855  |  |         break;  | 
1856  |  |     case XPATH_BOOLEAN:  | 
1857  |  |         cache->dbgReusedBool++;  | 
1858  |  |         break;  | 
1859  |  |     case XPATH_NUMBER:  | 
1860  |  |         cache->dbgReusedNumber++;  | 
1861  |  |         break;  | 
1862  |  |     case XPATH_STRING:  | 
1863  |  |         cache->dbgReusedString++;  | 
1864  |  |         break;  | 
1865  |  | #ifdef LIBXML_XPTR_LOCS_ENABLED  | 
1866  |  |     case XPATH_POINT:  | 
1867  |  |         cache->dbgReusedPoint++;  | 
1868  |  |         break;  | 
1869  |  |     case XPATH_RANGE:  | 
1870  |  |         cache->dbgReusedRange++;  | 
1871  |  |         break;  | 
1872  |  |     case XPATH_LOCATIONSET:  | 
1873  |  |         cache->dbgReusedLocset++;  | 
1874  |  |         break;  | 
1875  |  | #endif /* LIBXML_XPTR_LOCS_ENABLED */  | 
1876  |  |     case XPATH_USERS:  | 
1877  |  |         cache->dbgReusedUsers++;  | 
1878  |  |         break;  | 
1879  |  |     case XPATH_XSLT_TREE:  | 
1880  |  |         cache->dbgReusedXSLTTree++;  | 
1881  |  |         break;  | 
1882  |  |     default:  | 
1883  |  |         break;  | 
1884  |  |       }  | 
1885  |  |   }  | 
1886  |  |     }  | 
1887  |  |  | 
1888  |  |     switch (objType) { | 
1889  |  |   case XPATH_UNDEFINED:  | 
1890  |  |       if (! isCached)  | 
1891  |  |     xmlXPathDebugObjTotalUndefined++;  | 
1892  |  |       xmlXPathDebugObjCounterUndefined++;  | 
1893  |  |       if (xmlXPathDebugObjCounterUndefined >  | 
1894  |  |     xmlXPathDebugObjMaxUndefined)  | 
1895  |  |     xmlXPathDebugObjMaxUndefined =  | 
1896  |  |         xmlXPathDebugObjCounterUndefined;  | 
1897  |  |       break;  | 
1898  |  |   case XPATH_NODESET:  | 
1899  |  |       if (! isCached)  | 
1900  |  |     xmlXPathDebugObjTotalNodeset++;  | 
1901  |  |       xmlXPathDebugObjCounterNodeset++;  | 
1902  |  |       if (xmlXPathDebugObjCounterNodeset >  | 
1903  |  |     xmlXPathDebugObjMaxNodeset)  | 
1904  |  |     xmlXPathDebugObjMaxNodeset =  | 
1905  |  |         xmlXPathDebugObjCounterNodeset;  | 
1906  |  |       break;  | 
1907  |  |   case XPATH_BOOLEAN:  | 
1908  |  |       if (! isCached)  | 
1909  |  |     xmlXPathDebugObjTotalBool++;  | 
1910  |  |       xmlXPathDebugObjCounterBool++;  | 
1911  |  |       if (xmlXPathDebugObjCounterBool >  | 
1912  |  |     xmlXPathDebugObjMaxBool)  | 
1913  |  |     xmlXPathDebugObjMaxBool =  | 
1914  |  |         xmlXPathDebugObjCounterBool;  | 
1915  |  |       break;  | 
1916  |  |   case XPATH_NUMBER:  | 
1917  |  |       if (! isCached)  | 
1918  |  |     xmlXPathDebugObjTotalNumber++;  | 
1919  |  |       xmlXPathDebugObjCounterNumber++;  | 
1920  |  |       if (xmlXPathDebugObjCounterNumber >  | 
1921  |  |     xmlXPathDebugObjMaxNumber)  | 
1922  |  |     xmlXPathDebugObjMaxNumber =  | 
1923  |  |         xmlXPathDebugObjCounterNumber;  | 
1924  |  |       break;  | 
1925  |  |   case XPATH_STRING:  | 
1926  |  |       if (! isCached)  | 
1927  |  |     xmlXPathDebugObjTotalString++;  | 
1928  |  |       xmlXPathDebugObjCounterString++;  | 
1929  |  |       if (xmlXPathDebugObjCounterString >  | 
1930  |  |     xmlXPathDebugObjMaxString)  | 
1931  |  |     xmlXPathDebugObjMaxString =  | 
1932  |  |         xmlXPathDebugObjCounterString;  | 
1933  |  |       break;  | 
1934  |  | #ifdef LIBXML_XPTR_LOCS_ENABLED  | 
1935  |  |   case XPATH_POINT:  | 
1936  |  |       if (! isCached)  | 
1937  |  |     xmlXPathDebugObjTotalPoint++;  | 
1938  |  |       xmlXPathDebugObjCounterPoint++;  | 
1939  |  |       if (xmlXPathDebugObjCounterPoint >  | 
1940  |  |     xmlXPathDebugObjMaxPoint)  | 
1941  |  |     xmlXPathDebugObjMaxPoint =  | 
1942  |  |         xmlXPathDebugObjCounterPoint;  | 
1943  |  |       break;  | 
1944  |  |   case XPATH_RANGE:  | 
1945  |  |       if (! isCached)  | 
1946  |  |     xmlXPathDebugObjTotalRange++;  | 
1947  |  |       xmlXPathDebugObjCounterRange++;  | 
1948  |  |       if (xmlXPathDebugObjCounterRange >  | 
1949  |  |     xmlXPathDebugObjMaxRange)  | 
1950  |  |     xmlXPathDebugObjMaxRange =  | 
1951  |  |         xmlXPathDebugObjCounterRange;  | 
1952  |  |       break;  | 
1953  |  |   case XPATH_LOCATIONSET:  | 
1954  |  |       if (! isCached)  | 
1955  |  |     xmlXPathDebugObjTotalLocset++;  | 
1956  |  |       xmlXPathDebugObjCounterLocset++;  | 
1957  |  |       if (xmlXPathDebugObjCounterLocset >  | 
1958  |  |     xmlXPathDebugObjMaxLocset)  | 
1959  |  |     xmlXPathDebugObjMaxLocset =  | 
1960  |  |         xmlXPathDebugObjCounterLocset;  | 
1961  |  |       break;  | 
1962  |  | #endif /* LIBXML_XPTR_LOCS_ENABLED */  | 
1963  |  |   case XPATH_USERS:  | 
1964  |  |       if (! isCached)  | 
1965  |  |     xmlXPathDebugObjTotalUsers++;  | 
1966  |  |       xmlXPathDebugObjCounterUsers++;  | 
1967  |  |       if (xmlXPathDebugObjCounterUsers >  | 
1968  |  |     xmlXPathDebugObjMaxUsers)  | 
1969  |  |     xmlXPathDebugObjMaxUsers =  | 
1970  |  |         xmlXPathDebugObjCounterUsers;  | 
1971  |  |       break;  | 
1972  |  |   case XPATH_XSLT_TREE:  | 
1973  |  |       if (! isCached)  | 
1974  |  |     xmlXPathDebugObjTotalXSLTTree++;  | 
1975  |  |       xmlXPathDebugObjCounterXSLTTree++;  | 
1976  |  |       if (xmlXPathDebugObjCounterXSLTTree >  | 
1977  |  |     xmlXPathDebugObjMaxXSLTTree)  | 
1978  |  |     xmlXPathDebugObjMaxXSLTTree =  | 
1979  |  |         xmlXPathDebugObjCounterXSLTTree;  | 
1980  |  |       break;  | 
1981  |  |   default:  | 
1982  |  |       break;  | 
1983  |  |     }  | 
1984  |  |     if (! isCached)  | 
1985  |  |   xmlXPathDebugObjTotalAll++;  | 
1986  |  |     xmlXPathDebugObjCounterAll++;  | 
1987  |  |     if (xmlXPathDebugObjCounterAll >  | 
1988  |  |   xmlXPathDebugObjMaxAll)  | 
1989  |  |   xmlXPathDebugObjMaxAll =  | 
1990  |  |       xmlXPathDebugObjCounterAll;  | 
1991  |  | }  | 
1992  |  |  | 
1993  |  | static void  | 
1994  |  | xmlXPathDebugObjUsageReleased(xmlXPathContextPtr ctxt,  | 
1995  |  |             xmlXPathObjectType objType)  | 
1996  |  | { | 
1997  |  |     int isCached = 0;  | 
1998  |  |  | 
1999  |  |     if (ctxt != NULL) { | 
2000  |  |   if (ctxt->cache != NULL) { | 
2001  |  |       xmlXPathContextCachePtr cache =  | 
2002  |  |     (xmlXPathContextCachePtr) ctxt->cache;  | 
2003  |  |  | 
2004  |  |       isCached = 1;  | 
2005  |  |  | 
2006  |  |       cache->dbgCachedAll++;  | 
2007  |  |       switch (objType) { | 
2008  |  |     case XPATH_UNDEFINED:  | 
2009  |  |         cache->dbgCachedUndefined++;  | 
2010  |  |         break;  | 
2011  |  |     case XPATH_NODESET:  | 
2012  |  |         cache->dbgCachedNodeset++;  | 
2013  |  |         break;  | 
2014  |  |     case XPATH_BOOLEAN:  | 
2015  |  |         cache->dbgCachedBool++;  | 
2016  |  |         break;  | 
2017  |  |     case XPATH_NUMBER:  | 
2018  |  |         cache->dbgCachedNumber++;  | 
2019  |  |         break;  | 
2020  |  |     case XPATH_STRING:  | 
2021  |  |         cache->dbgCachedString++;  | 
2022  |  |         break;  | 
2023  |  | #ifdef LIBXML_XPTR_LOCS_ENABLED  | 
2024  |  |     case XPATH_POINT:  | 
2025  |  |         cache->dbgCachedPoint++;  | 
2026  |  |         break;  | 
2027  |  |     case XPATH_RANGE:  | 
2028  |  |         cache->dbgCachedRange++;  | 
2029  |  |         break;  | 
2030  |  |     case XPATH_LOCATIONSET:  | 
2031  |  |         cache->dbgCachedLocset++;  | 
2032  |  |         break;  | 
2033  |  | #endif /* LIBXML_XPTR_LOCS_ENABLED */  | 
2034  |  |     case XPATH_USERS:  | 
2035  |  |         cache->dbgCachedUsers++;  | 
2036  |  |         break;  | 
2037  |  |     case XPATH_XSLT_TREE:  | 
2038  |  |         cache->dbgCachedXSLTTree++;  | 
2039  |  |         break;  | 
2040  |  |     default:  | 
2041  |  |         break;  | 
2042  |  |       }  | 
2043  |  |  | 
2044  |  |   }  | 
2045  |  |     }  | 
2046  |  |     switch (objType) { | 
2047  |  |   case XPATH_UNDEFINED:  | 
2048  |  |       xmlXPathDebugObjCounterUndefined--;  | 
2049  |  |       break;  | 
2050  |  |   case XPATH_NODESET:  | 
2051  |  |       xmlXPathDebugObjCounterNodeset--;  | 
2052  |  |       break;  | 
2053  |  |   case XPATH_BOOLEAN:  | 
2054  |  |       xmlXPathDebugObjCounterBool--;  | 
2055  |  |       break;  | 
2056  |  |   case XPATH_NUMBER:  | 
2057  |  |       xmlXPathDebugObjCounterNumber--;  | 
2058  |  |       break;  | 
2059  |  |   case XPATH_STRING:  | 
2060  |  |       xmlXPathDebugObjCounterString--;  | 
2061  |  |       break;  | 
2062  |  | #ifdef LIBXML_XPTR_LOCS_ENABLED  | 
2063  |  |   case XPATH_POINT:  | 
2064  |  |       xmlXPathDebugObjCounterPoint--;  | 
2065  |  |       break;  | 
2066  |  |   case XPATH_RANGE:  | 
2067  |  |       xmlXPathDebugObjCounterRange--;  | 
2068  |  |       break;  | 
2069  |  |   case XPATH_LOCATIONSET:  | 
2070  |  |       xmlXPathDebugObjCounterLocset--;  | 
2071  |  |       break;  | 
2072  |  | #endif /* LIBXML_XPTR_LOCS_ENABLED */  | 
2073  |  |   case XPATH_USERS:  | 
2074  |  |       xmlXPathDebugObjCounterUsers--;  | 
2075  |  |       break;  | 
2076  |  |   case XPATH_XSLT_TREE:  | 
2077  |  |       xmlXPathDebugObjCounterXSLTTree--;  | 
2078  |  |       break;  | 
2079  |  |   default:  | 
2080  |  |       break;  | 
2081  |  |     }  | 
2082  |  |     xmlXPathDebugObjCounterAll--;  | 
2083  |  | }  | 
2084  |  |  | 
2085  |  | static void  | 
2086  |  | xmlXPathDebugObjUsageDisplay(xmlXPathContextPtr ctxt)  | 
2087  |  | { | 
2088  |  |     int reqAll, reqNodeset, reqString, reqBool, reqNumber,  | 
2089  |  |   reqXSLTTree, reqUndefined;  | 
2090  |  |     int caAll = 0, caNodeset = 0, caString = 0, caBool = 0,  | 
2091  |  |   caNumber = 0, caXSLTTree = 0, caUndefined = 0;  | 
2092  |  |     int reAll = 0, reNodeset = 0, reString = 0, reBool = 0,  | 
2093  |  |   reNumber = 0, reXSLTTree = 0, reUndefined = 0;  | 
2094  |  |     int leftObjs = xmlXPathDebugObjCounterAll;  | 
2095  |  |  | 
2096  |  |     reqAll = xmlXPathDebugObjTotalAll;  | 
2097  |  |     reqNodeset = xmlXPathDebugObjTotalNodeset;  | 
2098  |  |     reqString = xmlXPathDebugObjTotalString;  | 
2099  |  |     reqBool = xmlXPathDebugObjTotalBool;  | 
2100  |  |     reqNumber = xmlXPathDebugObjTotalNumber;  | 
2101  |  |     reqXSLTTree = xmlXPathDebugObjTotalXSLTTree;  | 
2102  |  |     reqUndefined = xmlXPathDebugObjTotalUndefined;  | 
2103  |  |  | 
2104  |  |     printf("# XPath object usage:\n"); | 
2105  |  |  | 
2106  |  |     if (ctxt != NULL) { | 
2107  |  |   if (ctxt->cache != NULL) { | 
2108  |  |       xmlXPathContextCachePtr cache =  | 
2109  |  |     (xmlXPathContextCachePtr) ctxt->cache;  | 
2110  |  |  | 
2111  |  |       reAll = cache->dbgReusedAll;  | 
2112  |  |       reqAll += reAll;  | 
2113  |  |       reNodeset = cache->dbgReusedNodeset;  | 
2114  |  |       reqNodeset += reNodeset;  | 
2115  |  |       reString = cache->dbgReusedString;  | 
2116  |  |       reqString += reString;  | 
2117  |  |       reBool = cache->dbgReusedBool;  | 
2118  |  |       reqBool += reBool;  | 
2119  |  |       reNumber = cache->dbgReusedNumber;  | 
2120  |  |       reqNumber += reNumber;  | 
2121  |  |       reXSLTTree = cache->dbgReusedXSLTTree;  | 
2122  |  |       reqXSLTTree += reXSLTTree;  | 
2123  |  |       reUndefined = cache->dbgReusedUndefined;  | 
2124  |  |       reqUndefined += reUndefined;  | 
2125  |  |  | 
2126  |  |       caAll = cache->dbgCachedAll;  | 
2127  |  |       caBool = cache->dbgCachedBool;  | 
2128  |  |       caNodeset = cache->dbgCachedNodeset;  | 
2129  |  |       caString = cache->dbgCachedString;  | 
2130  |  |       caNumber = cache->dbgCachedNumber;  | 
2131  |  |       caXSLTTree = cache->dbgCachedXSLTTree;  | 
2132  |  |       caUndefined = cache->dbgCachedUndefined;  | 
2133  |  |  | 
2134  |  |       if (cache->nodesetObjs)  | 
2135  |  |     leftObjs -= cache->nodesetObjs->number;  | 
2136  |  |       if (cache->stringObjs)  | 
2137  |  |     leftObjs -= cache->stringObjs->number;  | 
2138  |  |       if (cache->booleanObjs)  | 
2139  |  |     leftObjs -= cache->booleanObjs->number;  | 
2140  |  |       if (cache->numberObjs)  | 
2141  |  |     leftObjs -= cache->numberObjs->number;  | 
2142  |  |       if (cache->miscObjs)  | 
2143  |  |     leftObjs -= cache->miscObjs->number;  | 
2144  |  |   }  | 
2145  |  |     }  | 
2146  |  |  | 
2147  |  |     printf("# all\n"); | 
2148  |  |     printf("#   total  : %d\n", reqAll); | 
2149  |  |     printf("#   left  : %d\n", leftObjs); | 
2150  |  |     printf("#   created: %d\n", xmlXPathDebugObjTotalAll); | 
2151  |  |     printf("#   reused : %d\n", reAll); | 
2152  |  |     printf("#   max    : %d\n", xmlXPathDebugObjMaxAll); | 
2153  |  |  | 
2154  |  |     printf("# node-sets\n"); | 
2155  |  |     printf("#   total  : %d\n", reqNodeset); | 
2156  |  |     printf("#   created: %d\n", xmlXPathDebugObjTotalNodeset); | 
2157  |  |     printf("#   reused : %d\n", reNodeset); | 
2158  |  |     printf("#   max    : %d\n", xmlXPathDebugObjMaxNodeset); | 
2159  |  |  | 
2160  |  |     printf("# strings\n"); | 
2161  |  |     printf("#   total  : %d\n", reqString); | 
2162  |  |     printf("#   created: %d\n", xmlXPathDebugObjTotalString); | 
2163  |  |     printf("#   reused : %d\n", reString); | 
2164  |  |     printf("#   max    : %d\n", xmlXPathDebugObjMaxString); | 
2165  |  |  | 
2166  |  |     printf("# booleans\n"); | 
2167  |  |     printf("#   total  : %d\n", reqBool); | 
2168  |  |     printf("#   created: %d\n", xmlXPathDebugObjTotalBool); | 
2169  |  |     printf("#   reused : %d\n", reBool); | 
2170  |  |     printf("#   max    : %d\n", xmlXPathDebugObjMaxBool); | 
2171  |  |  | 
2172  |  |     printf("# numbers\n"); | 
2173  |  |     printf("#   total  : %d\n", reqNumber); | 
2174  |  |     printf("#   created: %d\n", xmlXPathDebugObjTotalNumber); | 
2175  |  |     printf("#   reused : %d\n", reNumber); | 
2176  |  |     printf("#   max    : %d\n", xmlXPathDebugObjMaxNumber); | 
2177  |  |  | 
2178  |  |     printf("# XSLT result tree fragments\n"); | 
2179  |  |     printf("#   total  : %d\n", reqXSLTTree); | 
2180  |  |     printf("#   created: %d\n", xmlXPathDebugObjTotalXSLTTree); | 
2181  |  |     printf("#   reused : %d\n", reXSLTTree); | 
2182  |  |     printf("#   max    : %d\n", xmlXPathDebugObjMaxXSLTTree); | 
2183  |  |  | 
2184  |  |     printf("# undefined\n"); | 
2185  |  |     printf("#   total  : %d\n", reqUndefined); | 
2186  |  |     printf("#   created: %d\n", xmlXPathDebugObjTotalUndefined); | 
2187  |  |     printf("#   reused : %d\n", reUndefined); | 
2188  |  |     printf("#   max    : %d\n", xmlXPathDebugObjMaxUndefined); | 
2189  |  |  | 
2190  |  | }  | 
2191  |  |  | 
2192  |  | #endif /* XP_DEBUG_OBJ_USAGE */  | 
2193  |  |  | 
2194  |  | #endif /* LIBXML_DEBUG_ENABLED */  | 
2195  |  |  | 
2196  |  | /************************************************************************  | 
2197  |  |  *                  *  | 
2198  |  |  *      XPath object caching        *  | 
2199  |  |  *                  *  | 
2200  |  |  ************************************************************************/  | 
2201  |  |  | 
2202  |  | /**  | 
2203  |  |  * xmlXPathNewCache:  | 
2204  |  |  *  | 
2205  |  |  * Create a new object cache  | 
2206  |  |  *  | 
2207  |  |  * Returns the xmlXPathCache just allocated.  | 
2208  |  |  */  | 
2209  |  | static xmlXPathContextCachePtr  | 
2210  |  | xmlXPathNewCache(void)  | 
2211  | 193k  | { | 
2212  | 193k  |     xmlXPathContextCachePtr ret;  | 
2213  |  |  | 
2214  | 193k  |     ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache));  | 
2215  | 193k  |     if (ret == NULL) { | 
2216  | 0  |         xmlXPathErrMemory(NULL, "creating object cache\n");  | 
2217  | 0  |   return(NULL);  | 
2218  | 0  |     }  | 
2219  | 193k  |     memset(ret, 0 , sizeof(xmlXPathContextCache));  | 
2220  | 193k  |     ret->maxNodeset = 100;  | 
2221  | 193k  |     ret->maxString = 100;  | 
2222  | 193k  |     ret->maxBoolean = 100;  | 
2223  | 193k  |     ret->maxNumber = 100;  | 
2224  | 193k  |     ret->maxMisc = 100;  | 
2225  | 193k  |     return(ret);  | 
2226  | 193k  | }  | 
2227  |  |  | 
2228  |  | static void  | 
2229  |  | xmlXPathCacheFreeObjectList(xmlPointerListPtr list)  | 
2230  | 376k  | { | 
2231  | 376k  |     int i;  | 
2232  | 376k  |     xmlXPathObjectPtr obj;  | 
2233  |  |  | 
2234  | 376k  |     if (list == NULL)  | 
2235  | 0  |   return;  | 
2236  |  |  | 
2237  | 4.91M  |     for (i = 0; i < list->number; i++) { | 
2238  | 4.53M  |   obj = list->items[i];  | 
2239  |  |   /*  | 
2240  |  |   * Note that it is already assured that we don't need to  | 
2241  |  |   * look out for namespace nodes in the node-set.  | 
2242  |  |   */  | 
2243  | 4.53M  |   if (obj->nodesetval != NULL) { | 
2244  | 3.67M  |       if (obj->nodesetval->nodeTab != NULL)  | 
2245  | 2.90M  |     xmlFree(obj->nodesetval->nodeTab);  | 
2246  | 3.67M  |       xmlFree(obj->nodesetval);  | 
2247  | 3.67M  |   }  | 
2248  | 4.53M  |   xmlFree(obj);  | 
2249  |  | #ifdef XP_DEBUG_OBJ_USAGE  | 
2250  |  |   xmlXPathDebugObjCounterAll--;  | 
2251  |  | #endif  | 
2252  | 4.53M  |     }  | 
2253  | 376k  |     xmlPointerListFree(list);  | 
2254  | 376k  | }  | 
2255  |  |  | 
2256  |  | static void  | 
2257  |  | xmlXPathFreeCache(xmlXPathContextCachePtr cache)  | 
2258  | 186k  | { | 
2259  | 186k  |     if (cache == NULL)  | 
2260  | 0  |   return;  | 
2261  | 186k  |     if (cache->nodesetObjs)  | 
2262  | 116k  |   xmlXPathCacheFreeObjectList(cache->nodesetObjs);  | 
2263  | 186k  |     if (cache->stringObjs)  | 
2264  | 76.1k  |   xmlXPathCacheFreeObjectList(cache->stringObjs);  | 
2265  | 186k  |     if (cache->booleanObjs)  | 
2266  | 52.3k  |   xmlXPathCacheFreeObjectList(cache->booleanObjs);  | 
2267  | 186k  |     if (cache->numberObjs)  | 
2268  | 67.3k  |   xmlXPathCacheFreeObjectList(cache->numberObjs);  | 
2269  | 186k  |     if (cache->miscObjs)  | 
2270  | 63.8k  |   xmlXPathCacheFreeObjectList(cache->miscObjs);  | 
2271  | 186k  |     xmlFree(cache);  | 
2272  | 186k  | }  | 
2273  |  |  | 
2274  |  | /**  | 
2275  |  |  * xmlXPathContextSetCache:  | 
2276  |  |  *  | 
2277  |  |  * @ctxt:  the XPath context  | 
2278  |  |  * @active: enables/disables (creates/frees) the cache  | 
2279  |  |  * @value: a value with semantics dependent on @options  | 
2280  |  |  * @options: options (currently only the value 0 is used)  | 
2281  |  |  *  | 
2282  |  |  * Creates/frees an object cache on the XPath context.  | 
2283  |  |  * If activates XPath objects (xmlXPathObject) will be cached internally  | 
2284  |  |  * to be reused.  | 
2285  |  |  * @options:  | 
2286  |  |  *   0: This will set the XPath object caching:  | 
2287  |  |  *      @value:  | 
2288  |  |  *        This will set the maximum number of XPath objects  | 
2289  |  |  *        to be cached per slot  | 
2290  |  |  *        There are 5 slots for: node-set, string, number, boolean, and  | 
2291  |  |  *        misc objects. Use <0 for the default number (100).  | 
2292  |  |  *   Other values for @options have currently no effect.  | 
2293  |  |  *  | 
2294  |  |  * Returns 0 if the setting succeeded, and -1 on API or internal errors.  | 
2295  |  |  */  | 
2296  |  | int  | 
2297  |  | xmlXPathContextSetCache(xmlXPathContextPtr ctxt,  | 
2298  |  |       int active,  | 
2299  |  |       int value,  | 
2300  |  |       int options)  | 
2301  | 379k  | { | 
2302  | 379k  |     if (ctxt == NULL)  | 
2303  | 0  |   return(-1);  | 
2304  | 379k  |     if (active) { | 
2305  | 193k  |   xmlXPathContextCachePtr cache;  | 
2306  |  |  | 
2307  | 193k  |   if (ctxt->cache == NULL) { | 
2308  | 193k  |       ctxt->cache = xmlXPathNewCache();  | 
2309  | 193k  |       if (ctxt->cache == NULL)  | 
2310  | 0  |     return(-1);  | 
2311  | 193k  |   }  | 
2312  | 193k  |   cache = (xmlXPathContextCachePtr) ctxt->cache;  | 
2313  | 193k  |   if (options == 0) { | 
2314  | 193k  |       if (value < 0)  | 
2315  | 193k  |     value = 100;  | 
2316  | 193k  |       cache->maxNodeset = value;  | 
2317  | 193k  |       cache->maxString = value;  | 
2318  | 193k  |       cache->maxNumber = value;  | 
2319  | 193k  |       cache->maxBoolean = value;  | 
2320  | 193k  |       cache->maxMisc = value;  | 
2321  | 193k  |   }  | 
2322  | 193k  |     } else if (ctxt->cache != NULL) { | 
2323  | 186k  |   xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);  | 
2324  | 186k  |   ctxt->cache = NULL;  | 
2325  | 186k  |     }  | 
2326  | 379k  |     return(0);  | 
2327  | 379k  | }  | 
2328  |  |  | 
2329  |  | /**  | 
2330  |  |  * xmlXPathCacheWrapNodeSet:  | 
2331  |  |  * @ctxt: the XPath context  | 
2332  |  |  * @val:  the NodePtr value  | 
2333  |  |  *  | 
2334  |  |  * This is the cached version of xmlXPathWrapNodeSet().  | 
2335  |  |  * Wrap the Nodeset @val in a new xmlXPathObjectPtr  | 
2336  |  |  *  | 
2337  |  |  * Returns the created or reused object.  | 
2338  |  |  */  | 
2339  |  | static xmlXPathObjectPtr  | 
2340  |  | xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt, xmlNodeSetPtr val)  | 
2341  | 25.7M  | { | 
2342  | 25.7M  |     if ((ctxt != NULL) && (ctxt->cache != NULL)) { | 
2343  | 25.7M  |   xmlXPathContextCachePtr cache =  | 
2344  | 25.7M  |       (xmlXPathContextCachePtr) ctxt->cache;  | 
2345  |  |  | 
2346  | 25.7M  |   if ((cache->miscObjs != NULL) &&  | 
2347  | 25.7M  |       (cache->miscObjs->number != 0))  | 
2348  | 20.0M  |   { | 
2349  | 20.0M  |       xmlXPathObjectPtr ret;  | 
2350  |  |  | 
2351  | 20.0M  |       ret = (xmlXPathObjectPtr)  | 
2352  | 20.0M  |     cache->miscObjs->items[--cache->miscObjs->number];  | 
2353  | 20.0M  |       ret->type = XPATH_NODESET;  | 
2354  | 20.0M  |       ret->nodesetval = val;  | 
2355  |  | #ifdef XP_DEBUG_OBJ_USAGE  | 
2356  |  |       xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);  | 
2357  |  | #endif  | 
2358  | 20.0M  |       return(ret);  | 
2359  | 20.0M  |   }  | 
2360  | 25.7M  |     }  | 
2361  |  |  | 
2362  | 5.69M  |     return(xmlXPathWrapNodeSet(val));  | 
2363  |  |  | 
2364  | 25.7M  | }  | 
2365  |  |  | 
2366  |  | /**  | 
2367  |  |  * xmlXPathCacheWrapString:  | 
2368  |  |  * @ctxt: the XPath context  | 
2369  |  |  * @val:  the xmlChar * value  | 
2370  |  |  *  | 
2371  |  |  * This is the cached version of xmlXPathWrapString().  | 
2372  |  |  * Wraps the @val string into an XPath object.  | 
2373  |  |  *  | 
2374  |  |  * Returns the created or reused object.  | 
2375  |  |  */  | 
2376  |  | static xmlXPathObjectPtr  | 
2377  |  | xmlXPathCacheWrapString(xmlXPathContextPtr ctxt, xmlChar *val)  | 
2378  | 1.33M  | { | 
2379  | 1.33M  |     if ((ctxt != NULL) && (ctxt->cache != NULL)) { | 
2380  | 1.33M  |   xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;  | 
2381  |  |  | 
2382  | 1.33M  |   if ((cache->stringObjs != NULL) &&  | 
2383  | 1.33M  |       (cache->stringObjs->number != 0))  | 
2384  | 217k  |   { | 
2385  |  |  | 
2386  | 217k  |       xmlXPathObjectPtr ret;  | 
2387  |  |  | 
2388  | 217k  |       ret = (xmlXPathObjectPtr)  | 
2389  | 217k  |     cache->stringObjs->items[--cache->stringObjs->number];  | 
2390  | 217k  |       ret->type = XPATH_STRING;  | 
2391  | 217k  |       ret->stringval = val;  | 
2392  |  | #ifdef XP_DEBUG_OBJ_USAGE  | 
2393  |  |       xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);  | 
2394  |  | #endif  | 
2395  | 217k  |       return(ret);  | 
2396  | 1.11M  |   } else if ((cache->miscObjs != NULL) &&  | 
2397  | 1.11M  |       (cache->miscObjs->number != 0))  | 
2398  | 855k  |   { | 
2399  | 855k  |       xmlXPathObjectPtr ret;  | 
2400  |  |       /*  | 
2401  |  |       * Fallback to misc-cache.  | 
2402  |  |       */  | 
2403  | 855k  |       ret = (xmlXPathObjectPtr)  | 
2404  | 855k  |     cache->miscObjs->items[--cache->miscObjs->number];  | 
2405  |  |  | 
2406  | 855k  |       ret->type = XPATH_STRING;  | 
2407  | 855k  |       ret->stringval = val;  | 
2408  |  | #ifdef XP_DEBUG_OBJ_USAGE  | 
2409  |  |       xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);  | 
2410  |  | #endif  | 
2411  | 855k  |       return(ret);  | 
2412  | 855k  |   }  | 
2413  | 1.33M  |     }  | 
2414  | 259k  |     return(xmlXPathWrapString(val));  | 
2415  | 1.33M  | }  | 
2416  |  |  | 
2417  |  | /**  | 
2418  |  |  * xmlXPathCacheNewNodeSet:  | 
2419  |  |  * @ctxt: the XPath context  | 
2420  |  |  * @val:  the NodePtr value  | 
2421  |  |  *  | 
2422  |  |  * This is the cached version of xmlXPathNewNodeSet().  | 
2423  |  |  * Acquire an xmlXPathObjectPtr of type NodeSet and initialize  | 
2424  |  |  * it with the single Node @val  | 
2425  |  |  *  | 
2426  |  |  * Returns the created or reused object.  | 
2427  |  |  */  | 
2428  |  | static xmlXPathObjectPtr  | 
2429  |  | xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt, xmlNodePtr val)  | 
2430  | 21.1M  | { | 
2431  | 21.1M  |     if ((ctxt != NULL) && (ctxt->cache)) { | 
2432  | 21.1M  |   xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;  | 
2433  |  |  | 
2434  | 21.1M  |   if ((cache->nodesetObjs != NULL) &&  | 
2435  | 21.1M  |       (cache->nodesetObjs->number != 0))  | 
2436  | 20.8M  |   { | 
2437  | 20.8M  |       xmlXPathObjectPtr ret;  | 
2438  |  |       /*  | 
2439  |  |       * Use the nodeset-cache.  | 
2440  |  |       */  | 
2441  | 20.8M  |       ret = (xmlXPathObjectPtr)  | 
2442  | 20.8M  |     cache->nodesetObjs->items[--cache->nodesetObjs->number];  | 
2443  | 20.8M  |       ret->type = XPATH_NODESET;  | 
2444  | 20.8M  |       ret->boolval = 0;  | 
2445  | 20.8M  |       if (val) { | 
2446  | 20.4M  |     if ((ret->nodesetval->nodeMax == 0) ||  | 
2447  | 20.4M  |         (val->type == XML_NAMESPACE_DECL))  | 
2448  | 2.54M  |     { | 
2449  |  |                     /* TODO: Check memory error. */  | 
2450  | 2.54M  |         xmlXPathNodeSetAddUnique(ret->nodesetval, val);  | 
2451  | 17.8M  |     } else { | 
2452  | 17.8M  |         ret->nodesetval->nodeTab[0] = val;  | 
2453  | 17.8M  |         ret->nodesetval->nodeNr = 1;  | 
2454  | 17.8M  |     }  | 
2455  | 20.4M  |       }  | 
2456  |  | #ifdef XP_DEBUG_OBJ_USAGE  | 
2457  |  |       xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);  | 
2458  |  | #endif  | 
2459  | 20.8M  |       return(ret);  | 
2460  | 20.8M  |   } else if ((cache->miscObjs != NULL) &&  | 
2461  | 371k  |       (cache->miscObjs->number != 0))  | 
2462  | 18.3k  |   { | 
2463  | 18.3k  |       xmlXPathObjectPtr ret;  | 
2464  |  |       /*  | 
2465  |  |       * Fallback to misc-cache.  | 
2466  |  |       */  | 
2467  |  |  | 
2468  | 18.3k  |       ret = (xmlXPathObjectPtr)  | 
2469  | 18.3k  |     cache->miscObjs->items[--cache->miscObjs->number];  | 
2470  |  |  | 
2471  | 18.3k  |       ret->type = XPATH_NODESET;  | 
2472  | 18.3k  |       ret->boolval = 0;  | 
2473  | 18.3k  |       ret->nodesetval = xmlXPathNodeSetCreate(val);  | 
2474  | 18.3k  |       if (ret->nodesetval == NULL) { | 
2475  | 0  |     ctxt->lastError.domain = XML_FROM_XPATH;  | 
2476  | 0  |     ctxt->lastError.code = XML_ERR_NO_MEMORY;  | 
2477  | 0  |     return(NULL);  | 
2478  | 0  |       }  | 
2479  |  | #ifdef XP_DEBUG_OBJ_USAGE  | 
2480  |  |       xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);  | 
2481  |  | #endif  | 
2482  | 18.3k  |       return(ret);  | 
2483  | 18.3k  |   }  | 
2484  | 21.1M  |     }  | 
2485  | 355k  |     return(xmlXPathNewNodeSet(val));  | 
2486  | 21.1M  | }  | 
2487  |  |  | 
2488  |  | /**  | 
2489  |  |  * xmlXPathCacheNewCString:  | 
2490  |  |  * @ctxt: the XPath context  | 
2491  |  |  * @val:  the char * value  | 
2492  |  |  *  | 
2493  |  |  * This is the cached version of xmlXPathNewCString().  | 
2494  |  |  * Acquire an xmlXPathObjectPtr of type string and of value @val  | 
2495  |  |  *  | 
2496  |  |  * Returns the created or reused object.  | 
2497  |  |  */  | 
2498  |  | static xmlXPathObjectPtr  | 
2499  |  | xmlXPathCacheNewCString(xmlXPathContextPtr ctxt, const char *val)  | 
2500  | 61.8k  | { | 
2501  | 61.8k  |     if ((ctxt != NULL) && (ctxt->cache)) { | 
2502  | 61.8k  |   xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;  | 
2503  |  |  | 
2504  | 61.8k  |   if ((cache->stringObjs != NULL) &&  | 
2505  | 61.8k  |       (cache->stringObjs->number != 0))  | 
2506  | 57.3k  |   { | 
2507  | 57.3k  |       xmlXPathObjectPtr ret;  | 
2508  |  |  | 
2509  | 57.3k  |       ret = (xmlXPathObjectPtr)  | 
2510  | 57.3k  |     cache->stringObjs->items[--cache->stringObjs->number];  | 
2511  |  |  | 
2512  | 57.3k  |       ret->type = XPATH_STRING;  | 
2513  | 57.3k  |       ret->stringval = xmlStrdup(BAD_CAST val);  | 
2514  |  | #ifdef XP_DEBUG_OBJ_USAGE  | 
2515  |  |       xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);  | 
2516  |  | #endif  | 
2517  | 57.3k  |       return(ret);  | 
2518  | 57.3k  |   } else if ((cache->miscObjs != NULL) &&  | 
2519  | 4.56k  |       (cache->miscObjs->number != 0))  | 
2520  | 1.60k  |   { | 
2521  | 1.60k  |       xmlXPathObjectPtr ret;  | 
2522  |  |  | 
2523  | 1.60k  |       ret = (xmlXPathObjectPtr)  | 
2524  | 1.60k  |     cache->miscObjs->items[--cache->miscObjs->number];  | 
2525  |  |  | 
2526  | 1.60k  |       ret->type = XPATH_STRING;  | 
2527  | 1.60k  |       ret->stringval = xmlStrdup(BAD_CAST val);  | 
2528  |  | #ifdef XP_DEBUG_OBJ_USAGE  | 
2529  |  |       xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);  | 
2530  |  | #endif  | 
2531  | 1.60k  |       return(ret);  | 
2532  | 1.60k  |   }  | 
2533  | 61.8k  |     }  | 
2534  | 2.96k  |     return(xmlXPathNewCString(val));  | 
2535  | 61.8k  | }  | 
2536  |  |  | 
2537  |  | /**  | 
2538  |  |  * xmlXPathCacheNewString:  | 
2539  |  |  * @ctxt: the XPath context  | 
2540  |  |  * @val:  the xmlChar * value  | 
2541  |  |  *  | 
2542  |  |  * This is the cached version of xmlXPathNewString().  | 
2543  |  |  * Acquire an xmlXPathObjectPtr of type string and of value @val  | 
2544  |  |  *  | 
2545  |  |  * Returns the created or reused object.  | 
2546  |  |  */  | 
2547  |  | static xmlXPathObjectPtr  | 
2548  |  | xmlXPathCacheNewString(xmlXPathContextPtr ctxt, const xmlChar *val)  | 
2549  | 7.46M  | { | 
2550  | 7.46M  |     if ((ctxt != NULL) && (ctxt->cache)) { | 
2551  | 7.46M  |   xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;  | 
2552  |  |  | 
2553  | 7.46M  |   if ((cache->stringObjs != NULL) &&  | 
2554  | 7.46M  |       (cache->stringObjs->number != 0))  | 
2555  | 4.74M  |   { | 
2556  | 4.74M  |       xmlXPathObjectPtr ret;  | 
2557  |  |  | 
2558  | 4.74M  |       ret = (xmlXPathObjectPtr)  | 
2559  | 4.74M  |     cache->stringObjs->items[--cache->stringObjs->number];  | 
2560  | 4.74M  |       ret->type = XPATH_STRING;  | 
2561  | 4.74M  |       if (val != NULL)  | 
2562  | 4.74M  |     ret->stringval = xmlStrdup(val);  | 
2563  | 1.74k  |       else  | 
2564  | 1.74k  |     ret->stringval = xmlStrdup((const xmlChar *)"");  | 
2565  |  | #ifdef XP_DEBUG_OBJ_USAGE  | 
2566  |  |       xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);  | 
2567  |  | #endif  | 
2568  | 4.74M  |       return(ret);  | 
2569  | 4.74M  |   } else if ((cache->miscObjs != NULL) &&  | 
2570  | 2.72M  |       (cache->miscObjs->number != 0))  | 
2571  | 1.58M  |   { | 
2572  | 1.58M  |       xmlXPathObjectPtr ret;  | 
2573  |  |  | 
2574  | 1.58M  |       ret = (xmlXPathObjectPtr)  | 
2575  | 1.58M  |     cache->miscObjs->items[--cache->miscObjs->number];  | 
2576  |  |  | 
2577  | 1.58M  |       ret->type = XPATH_STRING;  | 
2578  | 1.58M  |       if (val != NULL)  | 
2579  | 1.58M  |     ret->stringval = xmlStrdup(val);  | 
2580  | 88  |       else  | 
2581  | 88  |     ret->stringval = xmlStrdup((const xmlChar *)"");  | 
2582  |  | #ifdef XP_DEBUG_OBJ_USAGE  | 
2583  |  |       xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);  | 
2584  |  | #endif  | 
2585  | 1.58M  |       return(ret);  | 
2586  | 1.58M  |   }  | 
2587  | 7.46M  |     }  | 
2588  | 1.13M  |     return(xmlXPathNewString(val));  | 
2589  | 7.46M  | }  | 
2590  |  |  | 
2591  |  | /**  | 
2592  |  |  * xmlXPathCacheNewBoolean:  | 
2593  |  |  * @ctxt: the XPath context  | 
2594  |  |  * @val:  the boolean value  | 
2595  |  |  *  | 
2596  |  |  * This is the cached version of xmlXPathNewBoolean().  | 
2597  |  |  * Acquires an xmlXPathObjectPtr of type boolean and of value @val  | 
2598  |  |  *  | 
2599  |  |  * Returns the created or reused object.  | 
2600  |  |  */  | 
2601  |  | static xmlXPathObjectPtr  | 
2602  |  | xmlXPathCacheNewBoolean(xmlXPathContextPtr ctxt, int val)  | 
2603  | 10.4M  | { | 
2604  | 10.4M  |     if ((ctxt != NULL) && (ctxt->cache)) { | 
2605  | 10.4M  |   xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;  | 
2606  |  |  | 
2607  | 10.4M  |   if ((cache->booleanObjs != NULL) &&  | 
2608  | 10.4M  |       (cache->booleanObjs->number != 0))  | 
2609  | 10.0M  |   { | 
2610  | 10.0M  |       xmlXPathObjectPtr ret;  | 
2611  |  |  | 
2612  | 10.0M  |       ret = (xmlXPathObjectPtr)  | 
2613  | 10.0M  |     cache->booleanObjs->items[--cache->booleanObjs->number];  | 
2614  | 10.0M  |       ret->type = XPATH_BOOLEAN;  | 
2615  | 10.0M  |       ret->boolval = (val != 0);  | 
2616  |  | #ifdef XP_DEBUG_OBJ_USAGE  | 
2617  |  |       xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);  | 
2618  |  | #endif  | 
2619  | 10.0M  |       return(ret);  | 
2620  | 10.0M  |   } else if ((cache->miscObjs != NULL) &&  | 
2621  | 384k  |       (cache->miscObjs->number != 0))  | 
2622  | 206k  |   { | 
2623  | 206k  |       xmlXPathObjectPtr ret;  | 
2624  |  |  | 
2625  | 206k  |       ret = (xmlXPathObjectPtr)  | 
2626  | 206k  |     cache->miscObjs->items[--cache->miscObjs->number];  | 
2627  |  |  | 
2628  | 206k  |       ret->type = XPATH_BOOLEAN;  | 
2629  | 206k  |       ret->boolval = (val != 0);  | 
2630  |  | #ifdef XP_DEBUG_OBJ_USAGE  | 
2631  |  |       xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);  | 
2632  |  | #endif  | 
2633  | 206k  |       return(ret);  | 
2634  | 206k  |   }  | 
2635  | 10.4M  |     }  | 
2636  | 177k  |     return(xmlXPathNewBoolean(val));  | 
2637  | 10.4M  | }  | 
2638  |  |  | 
2639  |  | /**  | 
2640  |  |  * xmlXPathCacheNewFloat:  | 
2641  |  |  * @ctxt: the XPath context  | 
2642  |  |  * @val:  the double value  | 
2643  |  |  *  | 
2644  |  |  * This is the cached version of xmlXPathNewFloat().  | 
2645  |  |  * Acquires an xmlXPathObjectPtr of type double and of value @val  | 
2646  |  |  *  | 
2647  |  |  * Returns the created or reused object.  | 
2648  |  |  */  | 
2649  |  | static xmlXPathObjectPtr  | 
2650  |  | xmlXPathCacheNewFloat(xmlXPathContextPtr ctxt, double val)  | 
2651  | 17.6M  | { | 
2652  | 17.6M  |      if ((ctxt != NULL) && (ctxt->cache)) { | 
2653  | 17.6M  |   xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;  | 
2654  |  |  | 
2655  | 17.6M  |   if ((cache->numberObjs != NULL) &&  | 
2656  | 17.6M  |       (cache->numberObjs->number != 0))  | 
2657  | 15.6M  |   { | 
2658  | 15.6M  |       xmlXPathObjectPtr ret;  | 
2659  |  |  | 
2660  | 15.6M  |       ret = (xmlXPathObjectPtr)  | 
2661  | 15.6M  |     cache->numberObjs->items[--cache->numberObjs->number];  | 
2662  | 15.6M  |       ret->type = XPATH_NUMBER;  | 
2663  | 15.6M  |       ret->floatval = val;  | 
2664  |  | #ifdef XP_DEBUG_OBJ_USAGE  | 
2665  |  |       xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);  | 
2666  |  | #endif  | 
2667  | 15.6M  |       return(ret);  | 
2668  | 15.6M  |   } else if ((cache->miscObjs != NULL) &&  | 
2669  | 1.98M  |       (cache->miscObjs->number != 0))  | 
2670  | 787k  |   { | 
2671  | 787k  |       xmlXPathObjectPtr ret;  | 
2672  |  |  | 
2673  | 787k  |       ret = (xmlXPathObjectPtr)  | 
2674  | 787k  |     cache->miscObjs->items[--cache->miscObjs->number];  | 
2675  |  |  | 
2676  | 787k  |       ret->type = XPATH_NUMBER;  | 
2677  | 787k  |       ret->floatval = val;  | 
2678  |  | #ifdef XP_DEBUG_OBJ_USAGE  | 
2679  |  |       xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);  | 
2680  |  | #endif  | 
2681  | 787k  |       return(ret);  | 
2682  | 787k  |   }  | 
2683  | 17.6M  |     }  | 
2684  | 1.19M  |     return(xmlXPathNewFloat(val));  | 
2685  | 17.6M  | }  | 
2686  |  |  | 
2687  |  | /**  | 
2688  |  |  * xmlXPathCacheConvertString:  | 
2689  |  |  * @ctxt: the XPath context  | 
2690  |  |  * @val:  an XPath object  | 
2691  |  |  *  | 
2692  |  |  * This is the cached version of xmlXPathConvertString().  | 
2693  |  |  * Converts an existing object to its string() equivalent  | 
2694  |  |  *  | 
2695  |  |  * Returns a created or reused object, the old one is freed (cached)  | 
2696  |  |  *         (or the operation is done directly on @val)  | 
2697  |  |  */  | 
2698  |  |  | 
2699  |  | static xmlXPathObjectPtr  | 
2700  | 4.68M  | xmlXPathCacheConvertString(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) { | 
2701  | 4.68M  |     xmlChar *res = NULL;  | 
2702  |  |  | 
2703  | 4.68M  |     if (val == NULL)  | 
2704  | 0  |   return(xmlXPathCacheNewCString(ctxt, ""));  | 
2705  |  |  | 
2706  | 4.68M  |     switch (val->type) { | 
2707  | 0  |     case XPATH_UNDEFINED:  | 
2708  |  | #ifdef DEBUG_EXPR  | 
2709  |  |   xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");  | 
2710  |  | #endif  | 
2711  | 0  |   break;  | 
2712  | 1.16M  |     case XPATH_NODESET:  | 
2713  | 1.16M  |     case XPATH_XSLT_TREE:  | 
2714  | 1.16M  |   res = xmlXPathCastNodeSetToString(val->nodesetval);  | 
2715  | 1.16M  |   break;  | 
2716  | 3.36M  |     case XPATH_STRING:  | 
2717  | 3.36M  |   return(val);  | 
2718  | 38.2k  |     case XPATH_BOOLEAN:  | 
2719  | 38.2k  |   res = xmlXPathCastBooleanToString(val->boolval);  | 
2720  | 38.2k  |   break;  | 
2721  | 117k  |     case XPATH_NUMBER:  | 
2722  | 117k  |   res = xmlXPathCastNumberToString(val->floatval);  | 
2723  | 117k  |   break;  | 
2724  | 0  |     case XPATH_USERS:  | 
2725  |  | #ifdef LIBXML_XPTR_LOCS_ENABLED  | 
2726  |  |     case XPATH_POINT:  | 
2727  |  |     case XPATH_RANGE:  | 
2728  |  |     case XPATH_LOCATIONSET:  | 
2729  |  | #endif /* LIBXML_XPTR_LOCS_ENABLED */  | 
2730  | 0  |   TODO;  | 
2731  | 0  |   break;  | 
2732  | 4.68M  |     }  | 
2733  | 1.32M  |     xmlXPathReleaseObject(ctxt, val);  | 
2734  | 1.32M  |     if (res == NULL)  | 
2735  | 0  |   return(xmlXPathCacheNewCString(ctxt, ""));  | 
2736  | 1.32M  |     return(xmlXPathCacheWrapString(ctxt, res));  | 
2737  | 1.32M  | }  | 
2738  |  |  | 
2739  |  | /**  | 
2740  |  |  * xmlXPathCacheObjectCopy:  | 
2741  |  |  * @ctxt: the XPath context  | 
2742  |  |  * @val:  the original object  | 
2743  |  |  *  | 
2744  |  |  * This is the cached version of xmlXPathObjectCopy().  | 
2745  |  |  * Acquire a copy of a given object  | 
2746  |  |  *  | 
2747  |  |  * Returns a created or reused created object.  | 
2748  |  |  */  | 
2749  |  | static xmlXPathObjectPtr  | 
2750  |  | xmlXPathCacheObjectCopy(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val)  | 
2751  | 11.8M  | { | 
2752  | 11.8M  |     if (val == NULL)  | 
2753  | 4.92k  |   return(NULL);  | 
2754  |  |  | 
2755  | 11.8M  |     if (XP_HAS_CACHE(ctxt)) { | 
2756  | 11.8M  |   switch (val->type) { | 
2757  | 0  |       case XPATH_NODESET:  | 
2758  | 0  |     return(xmlXPathCacheWrapNodeSet(ctxt,  | 
2759  | 0  |         xmlXPathNodeSetMerge(NULL, val->nodesetval)));  | 
2760  | 5.07M  |       case XPATH_STRING:  | 
2761  | 5.07M  |     return(xmlXPathCacheNewString(ctxt, val->stringval));  | 
2762  | 0  |       case XPATH_BOOLEAN:  | 
2763  | 0  |     return(xmlXPathCacheNewBoolean(ctxt, val->boolval));  | 
2764  | 6.73M  |       case XPATH_NUMBER:  | 
2765  | 6.73M  |     return(xmlXPathCacheNewFloat(ctxt, val->floatval));  | 
2766  | 0  |       default:  | 
2767  | 0  |     break;  | 
2768  | 11.8M  |   }  | 
2769  | 11.8M  |     }  | 
2770  | 0  |     return(xmlXPathObjectCopy(val));  | 
2771  | 11.8M  | }  | 
2772  |  |  | 
2773  |  | /**  | 
2774  |  |  * xmlXPathCacheConvertBoolean:  | 
2775  |  |  * @ctxt: the XPath context  | 
2776  |  |  * @val:  an XPath object  | 
2777  |  |  *  | 
2778  |  |  * This is the cached version of xmlXPathConvertBoolean().  | 
2779  |  |  * Converts an existing object to its boolean() equivalent  | 
2780  |  |  *  | 
2781  |  |  * Returns a created or reused object, the old one is freed (or the operation  | 
2782  |  |  *         is done directly on @val)  | 
2783  |  |  */  | 
2784  |  | static xmlXPathObjectPtr  | 
2785  | 1.99M  | xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) { | 
2786  | 1.99M  |     xmlXPathObjectPtr ret;  | 
2787  |  |  | 
2788  | 1.99M  |     if (val == NULL)  | 
2789  | 0  |   return(xmlXPathCacheNewBoolean(ctxt, 0));  | 
2790  | 1.99M  |     if (val->type == XPATH_BOOLEAN)  | 
2791  | 254k  |   return(val);  | 
2792  | 1.74M  |     ret = xmlXPathCacheNewBoolean(ctxt, xmlXPathCastToBoolean(val));  | 
2793  | 1.74M  |     xmlXPathReleaseObject(ctxt, val);  | 
2794  | 1.74M  |     return(ret);  | 
2795  | 1.99M  | }  | 
2796  |  |  | 
2797  |  | /**  | 
2798  |  |  * xmlXPathCacheConvertNumber:  | 
2799  |  |  * @ctxt: the XPath context  | 
2800  |  |  * @val:  an XPath object  | 
2801  |  |  *  | 
2802  |  |  * This is the cached version of xmlXPathConvertNumber().  | 
2803  |  |  * Converts an existing object to its number() equivalent  | 
2804  |  |  *  | 
2805  |  |  * Returns a created or reused object, the old one is freed (or the operation  | 
2806  |  |  *         is done directly on @val)  | 
2807  |  |  */  | 
2808  |  | static xmlXPathObjectPtr  | 
2809  | 9.55M  | xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) { | 
2810  | 9.55M  |     xmlXPathObjectPtr ret;  | 
2811  |  |  | 
2812  | 9.55M  |     if (val == NULL)  | 
2813  | 0  |   return(xmlXPathCacheNewFloat(ctxt, 0.0));  | 
2814  | 9.55M  |     if (val->type == XPATH_NUMBER)  | 
2815  | 968  |   return(val);  | 
2816  | 9.55M  |     ret = xmlXPathCacheNewFloat(ctxt, xmlXPathCastToNumber(val));  | 
2817  | 9.55M  |     xmlXPathReleaseObject(ctxt, val);  | 
2818  | 9.55M  |     return(ret);  | 
2819  | 9.55M  | }  | 
2820  |  |  | 
2821  |  | /************************************************************************  | 
2822  |  |  *                  *  | 
2823  |  |  *    Parser stacks related functions and macros    *  | 
2824  |  |  *                  *  | 
2825  |  |  ************************************************************************/  | 
2826  |  |  | 
2827  |  | /**  | 
2828  |  |  * xmlXPathSetFrame:  | 
2829  |  |  * @ctxt: an XPath parser context  | 
2830  |  |  *  | 
2831  |  |  * Set the callee evaluation frame  | 
2832  |  |  *  | 
2833  |  |  * Returns the previous frame value to be restored once done  | 
2834  |  |  */  | 
2835  |  | static int  | 
2836  | 4.86M  | xmlXPathSetFrame(xmlXPathParserContextPtr ctxt) { | 
2837  | 4.86M  |     int ret;  | 
2838  |  |  | 
2839  | 4.86M  |     if (ctxt == NULL)  | 
2840  | 0  |         return(0);  | 
2841  | 4.86M  |     ret = ctxt->valueFrame;  | 
2842  | 4.86M  |     ctxt->valueFrame = ctxt->valueNr;  | 
2843  | 4.86M  |     return(ret);  | 
2844  | 4.86M  | }  | 
2845  |  |  | 
2846  |  | /**  | 
2847  |  |  * xmlXPathPopFrame:  | 
2848  |  |  * @ctxt: an XPath parser context  | 
2849  |  |  * @frame: the previous frame value  | 
2850  |  |  *  | 
2851  |  |  * Remove the callee evaluation frame  | 
2852  |  |  */  | 
2853  |  | static void  | 
2854  | 4.82M  | xmlXPathPopFrame(xmlXPathParserContextPtr ctxt, int frame) { | 
2855  | 4.82M  |     if (ctxt == NULL)  | 
2856  | 0  |         return;  | 
2857  | 4.82M  |     if (ctxt->valueNr < ctxt->valueFrame) { | 
2858  | 0  |         xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);  | 
2859  | 0  |     }  | 
2860  | 4.82M  |     ctxt->valueFrame = frame;  | 
2861  | 4.82M  | }  | 
2862  |  |  | 
2863  |  | /**  | 
2864  |  |  * valuePop:  | 
2865  |  |  * @ctxt: an XPath evaluation context  | 
2866  |  |  *  | 
2867  |  |  * Pops the top XPath object from the value stack  | 
2868  |  |  *  | 
2869  |  |  * Returns the XPath object just removed  | 
2870  |  |  */  | 
2871  |  | xmlXPathObjectPtr  | 
2872  |  | valuePop(xmlXPathParserContextPtr ctxt)  | 
2873  | 103M  | { | 
2874  | 103M  |     xmlXPathObjectPtr ret;  | 
2875  |  |  | 
2876  | 103M  |     if ((ctxt == NULL) || (ctxt->valueNr <= 0))  | 
2877  | 114k  |         return (NULL);  | 
2878  |  |  | 
2879  | 103M  |     if (ctxt->valueNr <= ctxt->valueFrame) { | 
2880  | 0  |         xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);  | 
2881  | 0  |         return (NULL);  | 
2882  | 0  |     }  | 
2883  |  |  | 
2884  | 103M  |     ctxt->valueNr--;  | 
2885  | 103M  |     if (ctxt->valueNr > 0)  | 
2886  | 92.6M  |         ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];  | 
2887  | 10.7M  |     else  | 
2888  | 10.7M  |         ctxt->value = NULL;  | 
2889  | 103M  |     ret = ctxt->valueTab[ctxt->valueNr];  | 
2890  | 103M  |     ctxt->valueTab[ctxt->valueNr] = NULL;  | 
2891  | 103M  |     return (ret);  | 
2892  | 103M  | }  | 
2893  |  | /**  | 
2894  |  |  * valuePush:  | 
2895  |  |  * @ctxt:  an XPath evaluation context  | 
2896  |  |  * @value:  the XPath object  | 
2897  |  |  *  | 
2898  |  |  * Pushes a new XPath object on top of the value stack. If value is NULL,  | 
2899  |  |  * a memory error is recorded in the parser context.  | 
2900  |  |  *  | 
2901  |  |  * Returns the number of items on the value stack, or -1 in case of error.  | 
2902  |  |  */  | 
2903  |  | int  | 
2904  |  | valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)  | 
2905  | 103M  | { | 
2906  | 103M  |     if (ctxt == NULL) return(-1);  | 
2907  | 103M  |     if (value == NULL) { | 
2908  |  |         /*  | 
2909  |  |          * A NULL value typically indicates that a memory allocation failed,  | 
2910  |  |          * so we set ctxt->error here to propagate the error.  | 
2911  |  |          */  | 
2912  | 129  |   ctxt->error = XPATH_MEMORY_ERROR;  | 
2913  | 129  |         return(-1);  | 
2914  | 129  |     }  | 
2915  | 103M  |     if (ctxt->valueNr >= ctxt->valueMax) { | 
2916  | 4.08k  |         xmlXPathObjectPtr *tmp;  | 
2917  |  |  | 
2918  | 4.08k  |         if (ctxt->valueMax >= XPATH_MAX_STACK_DEPTH) { | 
2919  | 0  |             xmlXPathPErrMemory(ctxt, "XPath stack depth limit reached\n");  | 
2920  | 0  |             return (-1);  | 
2921  | 0  |         }  | 
2922  | 4.08k  |         tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,  | 
2923  | 4.08k  |                                              2 * ctxt->valueMax *  | 
2924  | 4.08k  |                                              sizeof(ctxt->valueTab[0]));  | 
2925  | 4.08k  |         if (tmp == NULL) { | 
2926  | 0  |             xmlXPathPErrMemory(ctxt, "pushing value\n");  | 
2927  | 0  |             return (-1);  | 
2928  | 0  |         }  | 
2929  | 4.08k  |         ctxt->valueMax *= 2;  | 
2930  | 4.08k  |   ctxt->valueTab = tmp;  | 
2931  | 4.08k  |     }  | 
2932  | 103M  |     ctxt->valueTab[ctxt->valueNr] = value;  | 
2933  | 103M  |     ctxt->value = value;  | 
2934  | 103M  |     return (ctxt->valueNr++);  | 
2935  | 103M  | }  | 
2936  |  |  | 
2937  |  | /**  | 
2938  |  |  * xmlXPathPopBoolean:  | 
2939  |  |  * @ctxt:  an XPath parser context  | 
2940  |  |  *  | 
2941  |  |  * Pops a boolean from the stack, handling conversion if needed.  | 
2942  |  |  * Check error with #xmlXPathCheckError.  | 
2943  |  |  *  | 
2944  |  |  * Returns the boolean  | 
2945  |  |  */  | 
2946  |  | int  | 
2947  | 4.77k  | xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) { | 
2948  | 4.77k  |     xmlXPathObjectPtr obj;  | 
2949  | 4.77k  |     int ret;  | 
2950  |  |  | 
2951  | 4.77k  |     obj = valuePop(ctxt);  | 
2952  | 4.77k  |     if (obj == NULL) { | 
2953  | 0  |   xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);  | 
2954  | 0  |   return(0);  | 
2955  | 0  |     }  | 
2956  | 4.77k  |     if (obj->type != XPATH_BOOLEAN)  | 
2957  | 1.87k  |   ret = xmlXPathCastToBoolean(obj);  | 
2958  | 2.89k  |     else  | 
2959  | 2.89k  |         ret = obj->boolval;  | 
2960  | 4.77k  |     xmlXPathReleaseObject(ctxt->context, obj);  | 
2961  | 4.77k  |     return(ret);  | 
2962  | 4.77k  | }  | 
2963  |  |  | 
2964  |  | /**  | 
2965  |  |  * xmlXPathPopNumber:  | 
2966  |  |  * @ctxt:  an XPath parser context  | 
2967  |  |  *  | 
2968  |  |  * Pops a number from the stack, handling conversion if needed.  | 
2969  |  |  * Check error with #xmlXPathCheckError.  | 
2970  |  |  *  | 
2971  |  |  * Returns the number  | 
2972  |  |  */  | 
2973  |  | double  | 
2974  | 13.1k  | xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) { | 
2975  | 13.1k  |     xmlXPathObjectPtr obj;  | 
2976  | 13.1k  |     double ret;  | 
2977  |  |  | 
2978  | 13.1k  |     obj = valuePop(ctxt);  | 
2979  | 13.1k  |     if (obj == NULL) { | 
2980  | 0  |   xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);  | 
2981  | 0  |   return(0);  | 
2982  | 0  |     }  | 
2983  | 13.1k  |     if (obj->type != XPATH_NUMBER)  | 
2984  | 5.77k  |   ret = xmlXPathCastToNumber(obj);  | 
2985  | 7.41k  |     else  | 
2986  | 7.41k  |         ret = obj->floatval;  | 
2987  | 13.1k  |     xmlXPathReleaseObject(ctxt->context, obj);  | 
2988  | 13.1k  |     return(ret);  | 
2989  | 13.1k  | }  | 
2990  |  |  | 
2991  |  | /**  | 
2992  |  |  * xmlXPathPopString:  | 
2993  |  |  * @ctxt:  an XPath parser context  | 
2994  |  |  *  | 
2995  |  |  * Pops a string from the stack, handling conversion if needed.  | 
2996  |  |  * Check error with #xmlXPathCheckError.  | 
2997  |  |  *  | 
2998  |  |  * Returns the string  | 
2999  |  |  */  | 
3000  |  | xmlChar *  | 
3001  | 1.93M  | xmlXPathPopString (xmlXPathParserContextPtr ctxt) { | 
3002  | 1.93M  |     xmlXPathObjectPtr obj;  | 
3003  | 1.93M  |     xmlChar * ret;  | 
3004  |  |  | 
3005  | 1.93M  |     obj = valuePop(ctxt);  | 
3006  | 1.93M  |     if (obj == NULL) { | 
3007  | 0  |   xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);  | 
3008  | 0  |   return(NULL);  | 
3009  | 0  |     }  | 
3010  | 1.93M  |     ret = xmlXPathCastToString(obj);  /* this does required strdup */  | 
3011  |  |     /* TODO: needs refactoring somewhere else */  | 
3012  | 1.93M  |     if (obj->stringval == ret)  | 
3013  | 0  |   obj->stringval = NULL;  | 
3014  | 1.93M  |     xmlXPathReleaseObject(ctxt->context, obj);  | 
3015  | 1.93M  |     return(ret);  | 
3016  | 1.93M  | }  | 
3017  |  |  | 
3018  |  | /**  | 
3019  |  |  * xmlXPathPopNodeSet:  | 
3020  |  |  * @ctxt:  an XPath parser context  | 
3021  |  |  *  | 
3022  |  |  * Pops a node-set from the stack, handling conversion if needed.  | 
3023  |  |  * Check error with #xmlXPathCheckError.  | 
3024  |  |  *  | 
3025  |  |  * Returns the node-set  | 
3026  |  |  */  | 
3027  |  | xmlNodeSetPtr  | 
3028  | 1.17M  | xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) { | 
3029  | 1.17M  |     xmlXPathObjectPtr obj;  | 
3030  | 1.17M  |     xmlNodeSetPtr ret;  | 
3031  |  |  | 
3032  | 1.17M  |     if (ctxt == NULL) return(NULL);  | 
3033  | 1.17M  |     if (ctxt->value == NULL) { | 
3034  | 0  |   xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);  | 
3035  | 0  |   return(NULL);  | 
3036  | 0  |     }  | 
3037  | 1.17M  |     if (!xmlXPathStackIsNodeSet(ctxt)) { | 
3038  | 629  |   xmlXPathSetTypeError(ctxt);  | 
3039  | 629  |   return(NULL);  | 
3040  | 629  |     }  | 
3041  | 1.17M  |     obj = valuePop(ctxt);  | 
3042  | 1.17M  |     ret = obj->nodesetval;  | 
3043  |  | #if 0  | 
3044  |  |     /* to fix memory leak of not clearing obj->user */  | 
3045  |  |     if (obj->boolval && obj->user != NULL)  | 
3046  |  |         xmlFreeNodeList((xmlNodePtr) obj->user);  | 
3047  |  | #endif  | 
3048  | 1.17M  |     obj->nodesetval = NULL;  | 
3049  | 1.17M  |     xmlXPathReleaseObject(ctxt->context, obj);  | 
3050  | 1.17M  |     return(ret);  | 
3051  | 1.17M  | }  | 
3052  |  |  | 
3053  |  | /**  | 
3054  |  |  * xmlXPathPopExternal:  | 
3055  |  |  * @ctxt:  an XPath parser context  | 
3056  |  |  *  | 
3057  |  |  * Pops an external object from the stack, handling conversion if needed.  | 
3058  |  |  * Check error with #xmlXPathCheckError.  | 
3059  |  |  *  | 
3060  |  |  * Returns the object  | 
3061  |  |  */  | 
3062  |  | void *  | 
3063  | 4.06k  | xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) { | 
3064  | 4.06k  |     xmlXPathObjectPtr obj;  | 
3065  | 4.06k  |     void * ret;  | 
3066  |  |  | 
3067  | 4.06k  |     if ((ctxt == NULL) || (ctxt->value == NULL)) { | 
3068  | 0  |   xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);  | 
3069  | 0  |   return(NULL);  | 
3070  | 0  |     }  | 
3071  | 4.06k  |     if (ctxt->value->type != XPATH_USERS) { | 
3072  | 0  |   xmlXPathSetTypeError(ctxt);  | 
3073  | 0  |   return(NULL);  | 
3074  | 0  |     }  | 
3075  | 4.06k  |     obj = valuePop(ctxt);  | 
3076  | 4.06k  |     ret = obj->user;  | 
3077  | 4.06k  |     obj->user = NULL;  | 
3078  | 4.06k  |     xmlXPathReleaseObject(ctxt->context, obj);  | 
3079  | 4.06k  |     return(ret);  | 
3080  | 4.06k  | }  | 
3081  |  |  | 
3082  |  | /*  | 
3083  |  |  * Macros for accessing the content. Those should be used only by the parser,  | 
3084  |  |  * and not exported.  | 
3085  |  |  *  | 
3086  |  |  * Dirty macros, i.e. one need to make assumption on the context to use them  | 
3087  |  |  *  | 
3088  |  |  *   CUR_PTR return the current pointer to the xmlChar to be parsed.  | 
3089  |  |  *   CUR     returns the current xmlChar value, i.e. a 8 bit value  | 
3090  |  |  *           in ISO-Latin or UTF-8.  | 
3091  |  |  *           This should be used internally by the parser  | 
3092  |  |  *           only to compare to ASCII values otherwise it would break when  | 
3093  |  |  *           running with UTF-8 encoding.  | 
3094  |  |  *   NXT(n)  returns the n'th next xmlChar. Same as CUR is should be used only  | 
3095  |  |  *           to compare on ASCII based substring.  | 
3096  |  |  *   SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined  | 
3097  |  |  *           strings within the parser.  | 
3098  |  |  *   CURRENT Returns the current char value, with the full decoding of  | 
3099  |  |  *           UTF-8 if we are using this mode. It returns an int.  | 
3100  |  |  *   NEXT    Skip to the next character, this does the proper decoding  | 
3101  |  |  *           in UTF-8 mode. It also pop-up unfinished entities on the fly.  | 
3102  |  |  *           It returns the pointer to the current xmlChar.  | 
3103  |  |  */  | 
3104  |  |  | 
3105  | 413M  | #define CUR (*ctxt->cur)  | 
3106  | 2.76M  | #define SKIP(val) ctxt->cur += (val)  | 
3107  | 24.3M  | #define NXT(val) ctxt->cur[(val)]  | 
3108  | 772k  | #define CUR_PTR ctxt->cur  | 
3109  | 127M  | #define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)  | 
3110  |  |  | 
3111  |  | #define COPY_BUF(l,b,i,v)                                              \  | 
3112  | 52.0M  |     if (l == 1) b[i++] = v;                                            \  | 
3113  | 52.0M  |     else i += xmlCopyChar(l,&b[i],v)  | 
3114  |  |  | 
3115  | 112M  | #define NEXTL(l)  ctxt->cur += l  | 
3116  |  |  | 
3117  |  | #define SKIP_BLANKS             \  | 
3118  | 174M  |     while (IS_BLANK_CH(*(ctxt->cur))) NEXT  | 
3119  |  |  | 
3120  |  | #define CURRENT (*ctxt->cur)  | 
3121  | 186M  | #define NEXT ((*ctxt->cur) ?  ctxt->cur++: ctxt->cur)  | 
3122  |  |  | 
3123  |  |  | 
3124  |  | #ifndef DBL_DIG  | 
3125  |  | #define DBL_DIG 16  | 
3126  |  | #endif  | 
3127  |  | #ifndef DBL_EPSILON  | 
3128  |  | #define DBL_EPSILON 1E-9  | 
3129  |  | #endif  | 
3130  |  |  | 
3131  | 285k  | #define UPPER_DOUBLE 1E9  | 
3132  | 198k  | #define LOWER_DOUBLE 1E-5  | 
3133  |  | #define LOWER_DOUBLE_EXP 5  | 
3134  |  |  | 
3135  |  | #define INTEGER_DIGITS DBL_DIG  | 
3136  |  | #define FRACTION_DIGITS (DBL_DIG + 1 + (LOWER_DOUBLE_EXP))  | 
3137  | 87.6k  | #define EXPONENT_DIGITS (3 + 2)  | 
3138  |  |  | 
3139  |  | /**  | 
3140  |  |  * xmlXPathFormatNumber:  | 
3141  |  |  * @number:     number to format  | 
3142  |  |  * @buffer:     output buffer  | 
3143  |  |  * @buffersize: size of output buffer  | 
3144  |  |  *  | 
3145  |  |  * Convert the number into a string representation.  | 
3146  |  |  */  | 
3147  |  | static void  | 
3148  |  | xmlXPathFormatNumber(double number, char buffer[], int buffersize)  | 
3149  | 395k  | { | 
3150  | 395k  |     switch (xmlXPathIsInf(number)) { | 
3151  | 0  |     case 1:  | 
3152  | 0  |   if (buffersize > (int)sizeof("Infinity")) | 
3153  | 0  |       snprintf(buffer, buffersize, "Infinity");  | 
3154  | 0  |   break;  | 
3155  | 0  |     case -1:  | 
3156  | 0  |   if (buffersize > (int)sizeof("-Infinity")) | 
3157  | 0  |       snprintf(buffer, buffersize, "-Infinity");  | 
3158  | 0  |   break;  | 
3159  | 395k  |     default:  | 
3160  | 395k  |   if (xmlXPathIsNaN(number)) { | 
3161  | 0  |       if (buffersize > (int)sizeof("NaN")) | 
3162  | 0  |     snprintf(buffer, buffersize, "NaN");  | 
3163  | 395k  |   } else if (number == 0) { | 
3164  |  |             /* Omit sign for negative zero. */  | 
3165  | 0  |       snprintf(buffer, buffersize, "0");  | 
3166  | 395k  |   } else if ((number > INT_MIN) && (number < INT_MAX) &&  | 
3167  | 395k  |                    (number == (int) number)) { | 
3168  | 110k  |       char work[30];  | 
3169  | 110k  |       char *ptr, *cur;  | 
3170  | 110k  |       int value = (int) number;  | 
3171  |  |  | 
3172  | 110k  |             ptr = &buffer[0];  | 
3173  | 110k  |       if (value == 0) { | 
3174  | 0  |     *ptr++ = '0';  | 
3175  | 110k  |       } else { | 
3176  | 110k  |     snprintf(work, 29, "%d", value);  | 
3177  | 110k  |     cur = &work[0];  | 
3178  | 406k  |     while ((*cur) && (ptr - buffer < buffersize)) { | 
3179  | 296k  |         *ptr++ = *cur++;  | 
3180  | 296k  |     }  | 
3181  | 110k  |       }  | 
3182  | 110k  |       if (ptr - buffer < buffersize) { | 
3183  | 110k  |     *ptr = 0;  | 
3184  | 110k  |       } else if (buffersize > 0) { | 
3185  | 0  |     ptr--;  | 
3186  | 0  |     *ptr = 0;  | 
3187  | 0  |       }  | 
3188  | 285k  |   } else { | 
3189  |  |       /*  | 
3190  |  |         For the dimension of work,  | 
3191  |  |             DBL_DIG is number of significant digits  | 
3192  |  |       EXPONENT is only needed for "scientific notation"  | 
3193  |  |             3 is sign, decimal point, and terminating zero  | 
3194  |  |       LOWER_DOUBLE_EXP is max number of leading zeroes in fraction  | 
3195  |  |         Note that this dimension is slightly (a few characters)  | 
3196  |  |         larger than actually necessary.  | 
3197  |  |       */  | 
3198  | 285k  |       char work[DBL_DIG + EXPONENT_DIGITS + 3 + LOWER_DOUBLE_EXP];  | 
3199  | 285k  |       int integer_place, fraction_place;  | 
3200  | 285k  |       char *ptr;  | 
3201  | 285k  |       char *after_fraction;  | 
3202  | 285k  |       double absolute_value;  | 
3203  | 285k  |       int size;  | 
3204  |  |  | 
3205  | 285k  |       absolute_value = fabs(number);  | 
3206  |  |  | 
3207  |  |       /*  | 
3208  |  |        * First choose format - scientific or regular floating point.  | 
3209  |  |        * In either case, result is in work, and after_fraction points  | 
3210  |  |        * just past the fractional part.  | 
3211  |  |       */  | 
3212  | 285k  |       if ( ((absolute_value > UPPER_DOUBLE) ||  | 
3213  | 285k  |       (absolute_value < LOWER_DOUBLE)) &&  | 
3214  | 285k  |      (absolute_value != 0.0) ) { | 
3215  |  |     /* Use scientific notation */  | 
3216  | 87.6k  |     integer_place = DBL_DIG + EXPONENT_DIGITS + 1;  | 
3217  | 87.6k  |     fraction_place = DBL_DIG - 1;  | 
3218  | 87.6k  |     size = snprintf(work, sizeof(work),"%*.*e",  | 
3219  | 87.6k  |        integer_place, fraction_place, number);  | 
3220  | 470k  |     while ((size > 0) && (work[size] != 'e')) size--;  | 
3221  |  |  | 
3222  | 87.6k  |       }  | 
3223  | 198k  |       else { | 
3224  |  |     /* Use regular notation */  | 
3225  | 198k  |     if (absolute_value > 0.0) { | 
3226  | 198k  |         integer_place = (int)log10(absolute_value);  | 
3227  | 198k  |         if (integer_place > 0)  | 
3228  | 184k  |             fraction_place = DBL_DIG - integer_place - 1;  | 
3229  | 13.5k  |         else  | 
3230  | 13.5k  |             fraction_place = DBL_DIG - integer_place;  | 
3231  | 198k  |     } else { | 
3232  | 0  |         fraction_place = 1;  | 
3233  | 0  |     }  | 
3234  | 198k  |     size = snprintf(work, sizeof(work), "%0.*f",  | 
3235  | 198k  |         fraction_place, number);  | 
3236  | 198k  |       }  | 
3237  |  |  | 
3238  |  |       /* Remove leading spaces sometimes inserted by snprintf */  | 
3239  | 339k  |       while (work[0] == ' ') { | 
3240  | 1.13M  |           for (ptr = &work[0];(ptr[0] = ptr[1]);ptr++);  | 
3241  | 54.0k  |     size--;  | 
3242  | 54.0k  |       }  | 
3243  |  |  | 
3244  |  |       /* Remove fractional trailing zeroes */  | 
3245  | 285k  |       after_fraction = work + size;  | 
3246  | 285k  |       ptr = after_fraction;  | 
3247  | 2.69M  |       while (*(--ptr) == '0')  | 
3248  | 2.41M  |     ;  | 
3249  | 285k  |       if (*ptr != '.')  | 
3250  | 244k  |           ptr++;  | 
3251  | 669k  |       while ((*ptr++ = *after_fraction++) != 0);  | 
3252  |  |  | 
3253  |  |       /* Finally copy result back to caller */  | 
3254  | 285k  |       size = strlen(work) + 1;  | 
3255  | 285k  |       if (size > buffersize) { | 
3256  | 0  |     work[buffersize - 1] = 0;  | 
3257  | 0  |     size = buffersize;  | 
3258  | 0  |       }  | 
3259  | 285k  |       memmove(buffer, work, size);  | 
3260  | 285k  |   }  | 
3261  | 395k  |   break;  | 
3262  | 395k  |     }  | 
3263  | 395k  | }  | 
3264  |  |  | 
3265  |  |  | 
3266  |  | /************************************************************************  | 
3267  |  |  *                  *  | 
3268  |  |  *      Routines to handle NodeSets     *  | 
3269  |  |  *                  *  | 
3270  |  |  ************************************************************************/  | 
3271  |  |  | 
3272  |  | /**  | 
3273  |  |  * xmlXPathOrderDocElems:  | 
3274  |  |  * @doc:  an input document  | 
3275  |  |  *  | 
3276  |  |  * Call this routine to speed up XPath computation on static documents.  | 
3277  |  |  * This stamps all the element nodes with the document order  | 
3278  |  |  * Like for line information, the order is kept in the element->content  | 
3279  |  |  * field, the value stored is actually - the node number (starting at -1)  | 
3280  |  |  * to be able to differentiate from line numbers.  | 
3281  |  |  *  | 
3282  |  |  * Returns the number of elements found in the document or -1 in case  | 
3283  |  |  *    of error.  | 
3284  |  |  */  | 
3285  |  | long  | 
3286  | 3.70k  | xmlXPathOrderDocElems(xmlDocPtr doc) { | 
3287  | 3.70k  |     ptrdiff_t count = 0;  | 
3288  | 3.70k  |     xmlNodePtr cur;  | 
3289  |  |  | 
3290  | 3.70k  |     if (doc == NULL)  | 
3291  | 0  |   return(-1);  | 
3292  | 3.70k  |     cur = doc->children;  | 
3293  | 148k  |     while (cur != NULL) { | 
3294  | 144k  |   if (cur->type == XML_ELEMENT_NODE) { | 
3295  | 44.4k  |       cur->content = (void *) (-(++count));  | 
3296  | 44.4k  |       if (cur->children != NULL) { | 
3297  | 33.3k  |     cur = cur->children;  | 
3298  | 33.3k  |     continue;  | 
3299  | 33.3k  |       }  | 
3300  | 44.4k  |   }  | 
3301  | 111k  |   if (cur->next != NULL) { | 
3302  | 77.7k  |       cur = cur->next;  | 
3303  | 77.7k  |       continue;  | 
3304  | 77.7k  |   }  | 
3305  | 37.0k  |   do { | 
3306  | 37.0k  |       cur = cur->parent;  | 
3307  | 37.0k  |       if (cur == NULL)  | 
3308  | 0  |     break;  | 
3309  | 37.0k  |       if (cur == (xmlNodePtr) doc) { | 
3310  | 3.70k  |     cur = NULL;  | 
3311  | 3.70k  |     break;  | 
3312  | 3.70k  |       }  | 
3313  | 33.3k  |       if (cur->next != NULL) { | 
3314  | 29.6k  |     cur = cur->next;  | 
3315  | 29.6k  |     break;  | 
3316  | 29.6k  |       }  | 
3317  | 33.3k  |   } while (cur != NULL);  | 
3318  | 33.3k  |     }  | 
3319  | 3.70k  |     return(count);  | 
3320  | 3.70k  | }  | 
3321  |  |  | 
3322  |  | /**  | 
3323  |  |  * xmlXPathCmpNodes:  | 
3324  |  |  * @node1:  the first node  | 
3325  |  |  * @node2:  the second node  | 
3326  |  |  *  | 
3327  |  |  * Compare two nodes w.r.t document order  | 
3328  |  |  *  | 
3329  |  |  * Returns -2 in case of error 1 if first point < second point, 0 if  | 
3330  |  |  *         it's the same node, -1 otherwise  | 
3331  |  |  */  | 
3332  |  | int  | 
3333  | 166k  | xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) { | 
3334  | 166k  |     int depth1, depth2;  | 
3335  | 166k  |     int attr1 = 0, attr2 = 0;  | 
3336  | 166k  |     xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;  | 
3337  | 166k  |     xmlNodePtr cur, root;  | 
3338  |  |  | 
3339  | 166k  |     if ((node1 == NULL) || (node2 == NULL))  | 
3340  | 0  |   return(-2);  | 
3341  |  |     /*  | 
3342  |  |      * a couple of optimizations which will avoid computations in most cases  | 
3343  |  |      */  | 
3344  | 166k  |     if (node1 == node2)    /* trivial case */  | 
3345  | 0  |   return(0);  | 
3346  | 166k  |     if (node1->type == XML_ATTRIBUTE_NODE) { | 
3347  | 8.52k  |   attr1 = 1;  | 
3348  | 8.52k  |   attrNode1 = node1;  | 
3349  | 8.52k  |   node1 = node1->parent;  | 
3350  | 8.52k  |     }  | 
3351  | 166k  |     if (node2->type == XML_ATTRIBUTE_NODE) { | 
3352  | 7.97k  |   attr2 = 1;  | 
3353  | 7.97k  |   attrNode2 = node2;  | 
3354  | 7.97k  |   node2 = node2->parent;  | 
3355  | 7.97k  |     }  | 
3356  | 166k  |     if (node1 == node2) { | 
3357  | 1.85k  |   if (attr1 == attr2) { | 
3358  |  |       /* not required, but we keep attributes in order */  | 
3359  | 1.04k  |       if (attr1 != 0) { | 
3360  | 1.04k  |           cur = attrNode2->prev;  | 
3361  | 1.04k  |     while (cur != NULL) { | 
3362  | 1.04k  |         if (cur == attrNode1)  | 
3363  | 1.04k  |             return (1);  | 
3364  | 0  |         cur = cur->prev;  | 
3365  | 0  |     }  | 
3366  | 0  |     return (-1);  | 
3367  | 1.04k  |       }  | 
3368  | 0  |       return(0);  | 
3369  | 1.04k  |   }  | 
3370  | 810  |   if (attr2 == 1)  | 
3371  | 758  |       return(1);  | 
3372  | 52  |   return(-1);  | 
3373  | 810  |     }  | 
3374  | 164k  |     if ((node1->type == XML_NAMESPACE_DECL) ||  | 
3375  | 164k  |         (node2->type == XML_NAMESPACE_DECL))  | 
3376  | 10.4k  |   return(1);  | 
3377  | 154k  |     if (node1 == node2->prev)  | 
3378  | 543  |   return(1);  | 
3379  | 153k  |     if (node1 == node2->next)  | 
3380  | 149  |   return(-1);  | 
3381  |  |  | 
3382  |  |     /*  | 
3383  |  |      * Speedup using document order if available.  | 
3384  |  |      */  | 
3385  | 153k  |     if ((node1->type == XML_ELEMENT_NODE) &&  | 
3386  | 153k  |   (node2->type == XML_ELEMENT_NODE) &&  | 
3387  | 153k  |   (0 > (ptrdiff_t) node1->content) &&  | 
3388  | 153k  |   (0 > (ptrdiff_t) node2->content) &&  | 
3389  | 153k  |   (node1->doc == node2->doc)) { | 
3390  | 11.6k  |   ptrdiff_t l1, l2;  | 
3391  |  |  | 
3392  | 11.6k  |   l1 = -((ptrdiff_t) node1->content);  | 
3393  | 11.6k  |   l2 = -((ptrdiff_t) node2->content);  | 
3394  | 11.6k  |   if (l1 < l2)  | 
3395  | 11.5k  |       return(1);  | 
3396  | 117  |   if (l1 > l2)  | 
3397  | 117  |       return(-1);  | 
3398  | 117  |     }  | 
3399  |  |  | 
3400  |  |     /*  | 
3401  |  |      * compute depth to root  | 
3402  |  |      */  | 
3403  | 385k  |     for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) { | 
3404  | 278k  |   if (cur->parent == node1)  | 
3405  | 34.7k  |       return(1);  | 
3406  | 243k  |   depth2++;  | 
3407  | 243k  |     }  | 
3408  | 107k  |     root = cur;  | 
3409  | 272k  |     for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) { | 
3410  | 166k  |   if (cur->parent == node2)  | 
3411  | 290  |       return(-1);  | 
3412  | 165k  |   depth1++;  | 
3413  | 165k  |     }  | 
3414  |  |     /*  | 
3415  |  |      * Distinct document (or distinct entities :-( ) case.  | 
3416  |  |      */  | 
3417  | 106k  |     if (root != cur) { | 
3418  | 7.14k  |   return(-2);  | 
3419  | 7.14k  |     }  | 
3420  |  |     /*  | 
3421  |  |      * get the nearest common ancestor.  | 
3422  |  |      */  | 
3423  | 101k  |     while (depth1 > depth2) { | 
3424  | 1.80k  |   depth1--;  | 
3425  | 1.80k  |   node1 = node1->parent;  | 
3426  | 1.80k  |     }  | 
3427  | 126k  |     while (depth2 > depth1) { | 
3428  | 27.3k  |   depth2--;  | 
3429  | 27.3k  |   node2 = node2->parent;  | 
3430  | 27.3k  |     }  | 
3431  | 128k  |     while (node1->parent != node2->parent) { | 
3432  | 29.0k  |   node1 = node1->parent;  | 
3433  | 29.0k  |   node2 = node2->parent;  | 
3434  |  |   /* should not happen but just in case ... */  | 
3435  | 29.0k  |   if ((node1 == NULL) || (node2 == NULL))  | 
3436  | 0  |       return(-2);  | 
3437  | 29.0k  |     }  | 
3438  |  |     /*  | 
3439  |  |      * Find who's first.  | 
3440  |  |      */  | 
3441  | 99.5k  |     if (node1 == node2->prev)  | 
3442  | 12.0k  |   return(1);  | 
3443  | 87.5k  |     if (node1 == node2->next)  | 
3444  | 191  |   return(-1);  | 
3445  |  |     /*  | 
3446  |  |      * Speedup using document order if available.  | 
3447  |  |      */  | 
3448  | 87.3k  |     if ((node1->type == XML_ELEMENT_NODE) &&  | 
3449  | 87.3k  |   (node2->type == XML_ELEMENT_NODE) &&  | 
3450  | 87.3k  |   (0 > (ptrdiff_t) node1->content) &&  | 
3451  | 87.3k  |   (0 > (ptrdiff_t) node2->content) &&  | 
3452  | 87.3k  |   (node1->doc == node2->doc)) { | 
3453  | 2.67k  |   ptrdiff_t l1, l2;  | 
3454  |  |  | 
3455  | 2.67k  |   l1 = -((ptrdiff_t) node1->content);  | 
3456  | 2.67k  |   l2 = -((ptrdiff_t) node2->content);  | 
3457  | 2.67k  |   if (l1 < l2)  | 
3458  | 2.67k  |       return(1);  | 
3459  | 1  |   if (l1 > l2)  | 
3460  | 1  |       return(-1);  | 
3461  | 1  |     }  | 
3462  |  |  | 
3463  | 660M  |     for (cur = node1->next;cur != NULL;cur = cur->next)  | 
3464  | 660M  |   if (cur == node2)  | 
3465  | 84.2k  |       return(1);  | 
3466  | 396  |     return(-1); /* assume there is no sibling list corruption */  | 
3467  | 84.6k  | }  | 
3468  |  |  | 
3469  |  | /**  | 
3470  |  |  * xmlXPathNodeSetSort:  | 
3471  |  |  * @set:  the node set  | 
3472  |  |  *  | 
3473  |  |  * Sort the node set in document order  | 
3474  |  |  */  | 
3475  |  | void  | 
3476  | 2.10M  | xmlXPathNodeSetSort(xmlNodeSetPtr set) { | 
3477  |  | #ifndef WITH_TIM_SORT  | 
3478  |  |     int i, j, incr, len;  | 
3479  |  |     xmlNodePtr tmp;  | 
3480  |  | #endif  | 
3481  |  |  | 
3482  | 2.10M  |     if (set == NULL)  | 
3483  | 0  |   return;  | 
3484  |  |  | 
3485  |  | #ifndef WITH_TIM_SORT  | 
3486  |  |     /*  | 
3487  |  |      * Use the old Shell's sort implementation to sort the node-set  | 
3488  |  |      * Timsort ought to be quite faster  | 
3489  |  |      */  | 
3490  |  |     len = set->nodeNr;  | 
3491  |  |     for (incr = len / 2; incr > 0; incr /= 2) { | 
3492  |  |   for (i = incr; i < len; i++) { | 
3493  |  |       j = i - incr;  | 
3494  |  |       while (j >= 0) { | 
3495  |  | #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON  | 
3496  |  |     if (xmlXPathCmpNodesExt(set->nodeTab[j],  | 
3497  |  |       set->nodeTab[j + incr]) == -1)  | 
3498  |  | #else  | 
3499  |  |     if (xmlXPathCmpNodes(set->nodeTab[j],  | 
3500  |  |       set->nodeTab[j + incr]) == -1)  | 
3501  |  | #endif  | 
3502  |  |     { | 
3503  |  |         tmp = set->nodeTab[j];  | 
3504  |  |         set->nodeTab[j] = set->nodeTab[j + incr];  | 
3505  |  |         set->nodeTab[j + incr] = tmp;  | 
3506  |  |         j -= incr;  | 
3507  |  |     } else  | 
3508  |  |         break;  | 
3509  |  |       }  | 
3510  |  |   }  | 
3511  |  |     }  | 
3512  |  | #else /* WITH_TIM_SORT */  | 
3513  | 2.10M  |     libxml_domnode_tim_sort(set->nodeTab, set->nodeNr);  | 
3514  | 2.10M  | #endif /* WITH_TIM_SORT */  | 
3515  | 2.10M  | }  | 
3516  |  |  | 
3517  | 43.4M  | #define XML_NODESET_DEFAULT 10  | 
3518  |  | /**  | 
3519  |  |  * xmlXPathNodeSetDupNs:  | 
3520  |  |  * @node:  the parent node of the namespace XPath node  | 
3521  |  |  * @ns:  the libxml namespace declaration node.  | 
3522  |  |  *  | 
3523  |  |  * Namespace node in libxml don't match the XPath semantic. In a node set  | 
3524  |  |  * the namespace nodes are duplicated and the next pointer is set to the  | 
3525  |  |  * parent node in the XPath semantic.  | 
3526  |  |  *  | 
3527  |  |  * Returns the newly created object.  | 
3528  |  |  */  | 
3529  |  | static xmlNodePtr  | 
3530  | 1.71M  | xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) { | 
3531  | 1.71M  |     xmlNsPtr cur;  | 
3532  |  |  | 
3533  | 1.71M  |     if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))  | 
3534  | 0  |   return(NULL);  | 
3535  | 1.71M  |     if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))  | 
3536  | 0  |   return((xmlNodePtr) ns);  | 
3537  |  |  | 
3538  |  |     /*  | 
3539  |  |      * Allocate a new Namespace and fill the fields.  | 
3540  |  |      */  | 
3541  | 1.71M  |     cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));  | 
3542  | 1.71M  |     if (cur == NULL) { | 
3543  | 0  |         xmlXPathErrMemory(NULL, "duplicating namespace\n");  | 
3544  | 0  |   return(NULL);  | 
3545  | 0  |     }  | 
3546  | 1.71M  |     memset(cur, 0, sizeof(xmlNs));  | 
3547  | 1.71M  |     cur->type = XML_NAMESPACE_DECL;  | 
3548  | 1.71M  |     if (ns->href != NULL)  | 
3549  | 1.71M  |   cur->href = xmlStrdup(ns->href);  | 
3550  | 1.71M  |     if (ns->prefix != NULL)  | 
3551  | 1.71M  |   cur->prefix = xmlStrdup(ns->prefix);  | 
3552  | 1.71M  |     cur->next = (xmlNsPtr) node;  | 
3553  | 1.71M  |     return((xmlNodePtr) cur);  | 
3554  | 1.71M  | }  | 
3555  |  |  | 
3556  |  | /**  | 
3557  |  |  * xmlXPathNodeSetFreeNs:  | 
3558  |  |  * @ns:  the XPath namespace node found in a nodeset.  | 
3559  |  |  *  | 
3560  |  |  * Namespace nodes in libxml don't match the XPath semantic. In a node set  | 
3561  |  |  * the namespace nodes are duplicated and the next pointer is set to the  | 
3562  |  |  * parent node in the XPath semantic. Check if such a node needs to be freed  | 
3563  |  |  */  | 
3564  |  | void  | 
3565  | 1.67M  | xmlXPathNodeSetFreeNs(xmlNsPtr ns) { | 
3566  | 1.67M  |     if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))  | 
3567  | 0  |   return;  | 
3568  |  |  | 
3569  | 1.67M  |     if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) { | 
3570  | 1.67M  |   if (ns->href != NULL)  | 
3571  | 1.67M  |       xmlFree((xmlChar *)ns->href);  | 
3572  | 1.67M  |   if (ns->prefix != NULL)  | 
3573  | 1.67M  |       xmlFree((xmlChar *)ns->prefix);  | 
3574  | 1.67M  |   xmlFree(ns);  | 
3575  | 1.67M  |     }  | 
3576  | 1.67M  | }  | 
3577  |  |  | 
3578  |  | /**  | 
3579  |  |  * xmlXPathNodeSetCreate:  | 
3580  |  |  * @val:  an initial xmlNodePtr, or NULL  | 
3581  |  |  *  | 
3582  |  |  * Create a new xmlNodeSetPtr of type double and of value @val  | 
3583  |  |  *  | 
3584  |  |  * Returns the newly created object.  | 
3585  |  |  */  | 
3586  |  | xmlNodeSetPtr  | 
3587  | 29.1M  | xmlXPathNodeSetCreate(xmlNodePtr val) { | 
3588  | 29.1M  |     xmlNodeSetPtr ret;  | 
3589  |  |  | 
3590  | 29.1M  |     ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));  | 
3591  | 29.1M  |     if (ret == NULL) { | 
3592  | 0  |         xmlXPathErrMemory(NULL, "creating nodeset\n");  | 
3593  | 0  |   return(NULL);  | 
3594  | 0  |     }  | 
3595  | 29.1M  |     memset(ret, 0 , sizeof(xmlNodeSet));  | 
3596  | 29.1M  |     if (val != NULL) { | 
3597  | 2.14M  |         ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *  | 
3598  | 2.14M  |                sizeof(xmlNodePtr));  | 
3599  | 2.14M  |   if (ret->nodeTab == NULL) { | 
3600  | 0  |       xmlXPathErrMemory(NULL, "creating nodeset\n");  | 
3601  | 0  |       xmlFree(ret);  | 
3602  | 0  |       return(NULL);  | 
3603  | 0  |   }  | 
3604  | 2.14M  |   memset(ret->nodeTab, 0 ,  | 
3605  | 2.14M  |          XML_NODESET_DEFAULT * sizeof(xmlNodePtr));  | 
3606  | 2.14M  |         ret->nodeMax = XML_NODESET_DEFAULT;  | 
3607  | 2.14M  |   if (val->type == XML_NAMESPACE_DECL) { | 
3608  | 8.08k  |       xmlNsPtr ns = (xmlNsPtr) val;  | 
3609  |  |  | 
3610  |  |             /* TODO: Check memory error. */  | 
3611  | 8.08k  |       ret->nodeTab[ret->nodeNr++] =  | 
3612  | 8.08k  |     xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);  | 
3613  | 8.08k  |   } else  | 
3614  | 2.13M  |       ret->nodeTab[ret->nodeNr++] = val;  | 
3615  | 2.14M  |     }  | 
3616  | 29.1M  |     return(ret);  | 
3617  | 29.1M  | }  | 
3618  |  |  | 
3619  |  | /**  | 
3620  |  |  * xmlXPathNodeSetContains:  | 
3621  |  |  * @cur:  the node-set  | 
3622  |  |  * @val:  the node  | 
3623  |  |  *  | 
3624  |  |  * checks whether @cur contains @val  | 
3625  |  |  *  | 
3626  |  |  * Returns true (1) if @cur contains @val, false (0) otherwise  | 
3627  |  |  */  | 
3628  |  | int  | 
3629  | 11.2k  | xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) { | 
3630  | 11.2k  |     int i;  | 
3631  |  |  | 
3632  | 11.2k  |     if ((cur == NULL) || (val == NULL)) return(0);  | 
3633  | 11.2k  |     if (val->type == XML_NAMESPACE_DECL) { | 
3634  | 1.82k  |   for (i = 0; i < cur->nodeNr; i++) { | 
3635  | 1.60k  |       if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) { | 
3636  | 233  |     xmlNsPtr ns1, ns2;  | 
3637  |  |  | 
3638  | 233  |     ns1 = (xmlNsPtr) val;  | 
3639  | 233  |     ns2 = (xmlNsPtr) cur->nodeTab[i];  | 
3640  | 233  |     if (ns1 == ns2)  | 
3641  | 0  |         return(1);  | 
3642  | 233  |     if ((ns1->next != NULL) && (ns2->next == ns1->next) &&  | 
3643  | 233  |               (xmlStrEqual(ns1->prefix, ns2->prefix)))  | 
3644  | 27  |         return(1);  | 
3645  | 233  |       }  | 
3646  | 1.60k  |   }  | 
3647  | 10.9k  |     } else { | 
3648  | 63.1k  |   for (i = 0; i < cur->nodeNr; i++) { | 
3649  | 55.0k  |       if (cur->nodeTab[i] == val)  | 
3650  | 2.93k  |     return(1);  | 
3651  | 55.0k  |   }  | 
3652  | 10.9k  |     }  | 
3653  | 8.25k  |     return(0);  | 
3654  | 11.2k  | }  | 
3655  |  |  | 
3656  |  | /**  | 
3657  |  |  * xmlXPathNodeSetAddNs:  | 
3658  |  |  * @cur:  the initial node set  | 
3659  |  |  * @node:  the hosting node  | 
3660  |  |  * @ns:  a the namespace node  | 
3661  |  |  *  | 
3662  |  |  * add a new namespace node to an existing NodeSet  | 
3663  |  |  *  | 
3664  |  |  * Returns 0 in case of success and -1 in case of error  | 
3665  |  |  */  | 
3666  |  | int  | 
3667  | 879k  | xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) { | 
3668  | 879k  |     int i;  | 
3669  |  |  | 
3670  |  |  | 
3671  | 879k  |     if ((cur == NULL) || (ns == NULL) || (node == NULL) ||  | 
3672  | 879k  |         (ns->type != XML_NAMESPACE_DECL) ||  | 
3673  | 879k  |   (node->type != XML_ELEMENT_NODE))  | 
3674  | 0  |   return(-1);  | 
3675  |  |  | 
3676  |  |     /* @@ with_ns to check whether namespace nodes should be looked at @@ */  | 
3677  |  |     /*  | 
3678  |  |      * prevent duplicates  | 
3679  |  |      */  | 
3680  | 1.50M  |     for (i = 0;i < cur->nodeNr;i++) { | 
3681  | 622k  |         if ((cur->nodeTab[i] != NULL) &&  | 
3682  | 622k  |       (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&  | 
3683  | 622k  |       (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&  | 
3684  | 622k  |       (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))  | 
3685  | 0  |       return(0);  | 
3686  | 622k  |     }  | 
3687  |  |  | 
3688  |  |     /*  | 
3689  |  |      * grow the nodeTab if needed  | 
3690  |  |      */  | 
3691  | 879k  |     if (cur->nodeMax == 0) { | 
3692  | 123k  |         cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *  | 
3693  | 123k  |                sizeof(xmlNodePtr));  | 
3694  | 123k  |   if (cur->nodeTab == NULL) { | 
3695  | 0  |       xmlXPathErrMemory(NULL, "growing nodeset\n");  | 
3696  | 0  |       return(-1);  | 
3697  | 0  |   }  | 
3698  | 123k  |   memset(cur->nodeTab, 0 ,  | 
3699  | 123k  |          XML_NODESET_DEFAULT * sizeof(xmlNodePtr));  | 
3700  | 123k  |         cur->nodeMax = XML_NODESET_DEFAULT;  | 
3701  | 755k  |     } else if (cur->nodeNr == cur->nodeMax) { | 
3702  | 0  |         xmlNodePtr *temp;  | 
3703  |  | 
  | 
3704  | 0  |         if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) { | 
3705  | 0  |             xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");  | 
3706  | 0  |             return(-1);  | 
3707  | 0  |         }  | 
3708  | 0  |   temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *  | 
3709  | 0  |               sizeof(xmlNodePtr));  | 
3710  | 0  |   if (temp == NULL) { | 
3711  | 0  |       xmlXPathErrMemory(NULL, "growing nodeset\n");  | 
3712  | 0  |       return(-1);  | 
3713  | 0  |   }  | 
3714  | 0  |         cur->nodeMax *= 2;  | 
3715  | 0  |   cur->nodeTab = temp;  | 
3716  | 0  |     }  | 
3717  |  |     /* TODO: Check memory error. */  | 
3718  | 879k  |     cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);  | 
3719  | 879k  |     return(0);  | 
3720  | 879k  | }  | 
3721  |  |  | 
3722  |  | /**  | 
3723  |  |  * xmlXPathNodeSetAdd:  | 
3724  |  |  * @cur:  the initial node set  | 
3725  |  |  * @val:  a new xmlNodePtr  | 
3726  |  |  *  | 
3727  |  |  * add a new xmlNodePtr to an existing NodeSet  | 
3728  |  |  *  | 
3729  |  |  * Returns 0 in case of success, and -1 in case of error  | 
3730  |  |  */  | 
3731  |  | int  | 
3732  | 1.24M  | xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) { | 
3733  | 1.24M  |     int i;  | 
3734  |  |  | 
3735  | 1.24M  |     if ((cur == NULL) || (val == NULL)) return(-1);  | 
3736  |  |  | 
3737  |  |     /* @@ with_ns to check whether namespace nodes should be looked at @@ */  | 
3738  |  |     /*  | 
3739  |  |      * prevent duplicates  | 
3740  |  |      */  | 
3741  | 23.6M  |     for (i = 0;i < cur->nodeNr;i++)  | 
3742  | 23.3M  |         if (cur->nodeTab[i] == val) return(0);  | 
3743  |  |  | 
3744  |  |     /*  | 
3745  |  |      * grow the nodeTab if needed  | 
3746  |  |      */  | 
3747  | 251k  |     if (cur->nodeMax == 0) { | 
3748  | 15.9k  |         cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *  | 
3749  | 15.9k  |                sizeof(xmlNodePtr));  | 
3750  | 15.9k  |   if (cur->nodeTab == NULL) { | 
3751  | 0  |       xmlXPathErrMemory(NULL, "growing nodeset\n");  | 
3752  | 0  |       return(-1);  | 
3753  | 0  |   }  | 
3754  | 15.9k  |   memset(cur->nodeTab, 0 ,  | 
3755  | 15.9k  |          XML_NODESET_DEFAULT * sizeof(xmlNodePtr));  | 
3756  | 15.9k  |         cur->nodeMax = XML_NODESET_DEFAULT;  | 
3757  | 235k  |     } else if (cur->nodeNr == cur->nodeMax) { | 
3758  | 13.9k  |         xmlNodePtr *temp;  | 
3759  |  |  | 
3760  | 13.9k  |         if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) { | 
3761  | 0  |             xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");  | 
3762  | 0  |             return(-1);  | 
3763  | 0  |         }  | 
3764  | 13.9k  |   temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *  | 
3765  | 13.9k  |               sizeof(xmlNodePtr));  | 
3766  | 13.9k  |   if (temp == NULL) { | 
3767  | 0  |       xmlXPathErrMemory(NULL, "growing nodeset\n");  | 
3768  | 0  |       return(-1);  | 
3769  | 0  |   }  | 
3770  | 13.9k  |         cur->nodeMax *= 2;  | 
3771  | 13.9k  |   cur->nodeTab = temp;  | 
3772  | 13.9k  |     }  | 
3773  | 251k  |     if (val->type == XML_NAMESPACE_DECL) { | 
3774  | 8.40k  |   xmlNsPtr ns = (xmlNsPtr) val;  | 
3775  |  |  | 
3776  |  |         /* TODO: Check memory error. */  | 
3777  | 8.40k  |   cur->nodeTab[cur->nodeNr++] =  | 
3778  | 8.40k  |       xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);  | 
3779  | 8.40k  |     } else  | 
3780  | 243k  |   cur->nodeTab[cur->nodeNr++] = val;  | 
3781  | 251k  |     return(0);  | 
3782  | 251k  | }  | 
3783  |  |  | 
3784  |  | /**  | 
3785  |  |  * xmlXPathNodeSetAddUnique:  | 
3786  |  |  * @cur:  the initial node set  | 
3787  |  |  * @val:  a new xmlNodePtr  | 
3788  |  |  *  | 
3789  |  |  * add a new xmlNodePtr to an existing NodeSet, optimized version  | 
3790  |  |  * when we are sure the node is not already in the set.  | 
3791  |  |  *  | 
3792  |  |  * Returns 0 in case of success and -1 in case of failure  | 
3793  |  |  */  | 
3794  |  | int  | 
3795  | 95.5M  | xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) { | 
3796  | 95.5M  |     if ((cur == NULL) || (val == NULL)) return(-1);  | 
3797  |  |  | 
3798  |  |     /* @@ with_ns to check whether namespace nodes should be looked at @@ */  | 
3799  |  |     /*  | 
3800  |  |      * grow the nodeTab if needed  | 
3801  |  |      */  | 
3802  | 95.5M  |     if (cur->nodeMax == 0) { | 
3803  | 10.8M  |         cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *  | 
3804  | 10.8M  |                sizeof(xmlNodePtr));  | 
3805  | 10.8M  |   if (cur->nodeTab == NULL) { | 
3806  | 0  |       xmlXPathErrMemory(NULL, "growing nodeset\n");  | 
3807  | 0  |       return(-1);  | 
3808  | 0  |   }  | 
3809  | 10.8M  |   memset(cur->nodeTab, 0 ,  | 
3810  | 10.8M  |          XML_NODESET_DEFAULT * sizeof(xmlNodePtr));  | 
3811  | 10.8M  |         cur->nodeMax = XML_NODESET_DEFAULT;  | 
3812  | 84.6M  |     } else if (cur->nodeNr == cur->nodeMax) { | 
3813  | 3.65M  |         xmlNodePtr *temp;  | 
3814  |  |  | 
3815  | 3.65M  |         if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) { | 
3816  | 0  |             xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");  | 
3817  | 0  |             return(-1);  | 
3818  | 0  |         }  | 
3819  | 3.65M  |   temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *  | 
3820  | 3.65M  |               sizeof(xmlNodePtr));  | 
3821  | 3.65M  |   if (temp == NULL) { | 
3822  | 0  |       xmlXPathErrMemory(NULL, "growing nodeset\n");  | 
3823  | 0  |       return(-1);  | 
3824  | 0  |   }  | 
3825  | 3.65M  |   cur->nodeTab = temp;  | 
3826  | 3.65M  |         cur->nodeMax *= 2;  | 
3827  | 3.65M  |     }  | 
3828  | 95.5M  |     if (val->type == XML_NAMESPACE_DECL) { | 
3829  | 560k  |   xmlNsPtr ns = (xmlNsPtr) val;  | 
3830  |  |  | 
3831  |  |         /* TODO: Check memory error. */  | 
3832  | 560k  |   cur->nodeTab[cur->nodeNr++] =  | 
3833  | 560k  |       xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);  | 
3834  | 560k  |     } else  | 
3835  | 94.9M  |   cur->nodeTab[cur->nodeNr++] = val;  | 
3836  | 95.5M  |     return(0);  | 
3837  | 95.5M  | }  | 
3838  |  |  | 
3839  |  | /**  | 
3840  |  |  * xmlXPathNodeSetMerge:  | 
3841  |  |  * @val1:  the first NodeSet or NULL  | 
3842  |  |  * @val2:  the second NodeSet  | 
3843  |  |  *  | 
3844  |  |  * Merges two nodesets, all nodes from @val2 are added to @val1  | 
3845  |  |  * if @val1 is NULL, a new set is created and copied from @val2  | 
3846  |  |  *  | 
3847  |  |  * Returns @val1 once extended or NULL in case of error.  | 
3848  |  |  */  | 
3849  |  | xmlNodeSetPtr  | 
3850  | 3.38M  | xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) { | 
3851  | 3.38M  |     int i, j, initNr, skip;  | 
3852  | 3.38M  |     xmlNodePtr n1, n2;  | 
3853  |  |  | 
3854  | 3.38M  |     if (val2 == NULL) return(val1);  | 
3855  | 3.18M  |     if (val1 == NULL) { | 
3856  | 515k  |   val1 = xmlXPathNodeSetCreate(NULL);  | 
3857  | 515k  |     if (val1 == NULL)  | 
3858  | 0  |         return (NULL);  | 
3859  |  | #if 0  | 
3860  |  |   /*  | 
3861  |  |   * TODO: The optimization won't work in every case, since  | 
3862  |  |   *  those nasty namespace nodes need to be added with  | 
3863  |  |   *  xmlXPathNodeSetDupNs() to the set; thus a pure  | 
3864  |  |   *  memcpy is not possible.  | 
3865  |  |   *  If there was a flag on the nodesetval, indicating that  | 
3866  |  |   *  some temporary nodes are in, that would be helpful.  | 
3867  |  |   */  | 
3868  |  |   /*  | 
3869  |  |   * Optimization: Create an equally sized node-set  | 
3870  |  |   * and memcpy the content.  | 
3871  |  |   */  | 
3872  |  |   val1 = xmlXPathNodeSetCreateSize(val2->nodeNr);  | 
3873  |  |   if (val1 == NULL)  | 
3874  |  |       return(NULL);  | 
3875  |  |   if (val2->nodeNr != 0) { | 
3876  |  |       if (val2->nodeNr == 1)  | 
3877  |  |     *(val1->nodeTab) = *(val2->nodeTab);  | 
3878  |  |       else { | 
3879  |  |     memcpy(val1->nodeTab, val2->nodeTab,  | 
3880  |  |         val2->nodeNr * sizeof(xmlNodePtr));  | 
3881  |  |       }  | 
3882  |  |       val1->nodeNr = val2->nodeNr;  | 
3883  |  |   }  | 
3884  |  |   return(val1);  | 
3885  |  | #endif  | 
3886  | 515k  |     }  | 
3887  |  |  | 
3888  |  |     /* @@ with_ns to check whether namespace nodes should be looked at @@ */  | 
3889  | 3.18M  |     initNr = val1->nodeNr;  | 
3890  |  |  | 
3891  | 17.5M  |     for (i = 0;i < val2->nodeNr;i++) { | 
3892  | 14.3M  |   n2 = val2->nodeTab[i];  | 
3893  |  |   /*  | 
3894  |  |    * check against duplicates  | 
3895  |  |    */  | 
3896  | 14.3M  |   skip = 0;  | 
3897  | 102M  |   for (j = 0; j < initNr; j++) { | 
3898  | 91.8M  |       n1 = val1->nodeTab[j];  | 
3899  | 91.8M  |       if (n1 == n2) { | 
3900  | 3.64M  |     skip = 1;  | 
3901  | 3.64M  |     break;  | 
3902  | 88.2M  |       } else if ((n1->type == XML_NAMESPACE_DECL) &&  | 
3903  | 88.2M  |            (n2->type == XML_NAMESPACE_DECL)) { | 
3904  | 637k  |     if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&  | 
3905  | 637k  |         (xmlStrEqual(((xmlNsPtr) n1)->prefix,  | 
3906  | 72.3k  |       ((xmlNsPtr) n2)->prefix)))  | 
3907  | 40.5k  |     { | 
3908  | 40.5k  |         skip = 1;  | 
3909  | 40.5k  |         break;  | 
3910  | 40.5k  |     }  | 
3911  | 637k  |       }  | 
3912  | 91.8M  |   }  | 
3913  | 14.3M  |   if (skip)  | 
3914  | 3.68M  |       continue;  | 
3915  |  |  | 
3916  |  |   /*  | 
3917  |  |    * grow the nodeTab if needed  | 
3918  |  |    */  | 
3919  | 10.6M  |   if (val1->nodeMax == 0) { | 
3920  | 687k  |       val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *  | 
3921  | 687k  |                 sizeof(xmlNodePtr));  | 
3922  | 687k  |       if (val1->nodeTab == NULL) { | 
3923  | 0  |           xmlXPathErrMemory(NULL, "merging nodeset\n");  | 
3924  | 0  |     return(NULL);  | 
3925  | 0  |       }  | 
3926  | 687k  |       memset(val1->nodeTab, 0 ,  | 
3927  | 687k  |        XML_NODESET_DEFAULT * sizeof(xmlNodePtr));  | 
3928  | 687k  |       val1->nodeMax = XML_NODESET_DEFAULT;  | 
3929  | 9.95M  |   } else if (val1->nodeNr == val1->nodeMax) { | 
3930  | 472k  |       xmlNodePtr *temp;  | 
3931  |  |  | 
3932  | 472k  |             if (val1->nodeMax >= XPATH_MAX_NODESET_LENGTH) { | 
3933  | 0  |                 xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");  | 
3934  | 0  |                 return(NULL);  | 
3935  | 0  |             }  | 
3936  | 472k  |       temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax * 2 *  | 
3937  | 472k  |                sizeof(xmlNodePtr));  | 
3938  | 472k  |       if (temp == NULL) { | 
3939  | 0  |           xmlXPathErrMemory(NULL, "merging nodeset\n");  | 
3940  | 0  |     return(NULL);  | 
3941  | 0  |       }  | 
3942  | 472k  |       val1->nodeTab = temp;  | 
3943  | 472k  |       val1->nodeMax *= 2;  | 
3944  | 472k  |   }  | 
3945  | 10.6M  |   if (n2->type == XML_NAMESPACE_DECL) { | 
3946  | 259k  |       xmlNsPtr ns = (xmlNsPtr) n2;  | 
3947  |  |  | 
3948  |  |             /* TODO: Check memory error. */  | 
3949  | 259k  |       val1->nodeTab[val1->nodeNr++] =  | 
3950  | 259k  |     xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);  | 
3951  | 259k  |   } else  | 
3952  | 10.3M  |       val1->nodeTab[val1->nodeNr++] = n2;  | 
3953  | 10.6M  |     }  | 
3954  |  |  | 
3955  | 3.18M  |     return(val1);  | 
3956  | 3.18M  | }  | 
3957  |  |  | 
3958  |  |  | 
3959  |  | /**  | 
3960  |  |  * xmlXPathNodeSetMergeAndClear:  | 
3961  |  |  * @set1:  the first NodeSet or NULL  | 
3962  |  |  * @set2:  the second NodeSet  | 
3963  |  |  *  | 
3964  |  |  * Merges two nodesets, all nodes from @set2 are added to @set1.  | 
3965  |  |  * Checks for duplicate nodes. Clears set2.  | 
3966  |  |  *  | 
3967  |  |  * Returns @set1 once extended or NULL in case of error.  | 
3968  |  |  */  | 
3969  |  | static xmlNodeSetPtr  | 
3970  |  | xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2)  | 
3971  | 6.02M  | { | 
3972  | 6.02M  |     { | 
3973  | 6.02M  |   int i, j, initNbSet1;  | 
3974  | 6.02M  |   xmlNodePtr n1, n2;  | 
3975  |  |  | 
3976  | 6.02M  |   initNbSet1 = set1->nodeNr;  | 
3977  | 18.9M  |   for (i = 0;i < set2->nodeNr;i++) { | 
3978  | 12.9M  |       n2 = set2->nodeTab[i];  | 
3979  |  |       /*  | 
3980  |  |       * Skip duplicates.  | 
3981  |  |       */  | 
3982  | 7.94G  |       for (j = 0; j < initNbSet1; j++) { | 
3983  | 7.93G  |     n1 = set1->nodeTab[j];  | 
3984  | 7.93G  |     if (n1 == n2) { | 
3985  | 10.1M  |         goto skip_node;  | 
3986  | 7.92G  |     } else if ((n1->type == XML_NAMESPACE_DECL) &&  | 
3987  | 7.92G  |         (n2->type == XML_NAMESPACE_DECL))  | 
3988  | 817k  |     { | 
3989  | 817k  |         if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&  | 
3990  | 817k  |       (xmlStrEqual(((xmlNsPtr) n1)->prefix,  | 
3991  | 37.3k  |       ((xmlNsPtr) n2)->prefix)))  | 
3992  | 0  |         { | 
3993  |  |       /*  | 
3994  |  |       * Free the namespace node.  | 
3995  |  |       */  | 
3996  | 0  |       set2->nodeTab[i] = NULL;  | 
3997  | 0  |       xmlXPathNodeSetFreeNs((xmlNsPtr) n2);  | 
3998  | 0  |       goto skip_node;  | 
3999  | 0  |         }  | 
4000  | 817k  |     }  | 
4001  | 7.93G  |       }  | 
4002  |  |       /*  | 
4003  |  |       * grow the nodeTab if needed  | 
4004  |  |       */  | 
4005  | 2.84M  |       if (set1->nodeMax == 0) { | 
4006  | 0  |     set1->nodeTab = (xmlNodePtr *) xmlMalloc(  | 
4007  | 0  |         XML_NODESET_DEFAULT * sizeof(xmlNodePtr));  | 
4008  | 0  |     if (set1->nodeTab == NULL) { | 
4009  | 0  |         xmlXPathErrMemory(NULL, "merging nodeset\n");  | 
4010  | 0  |         return(NULL);  | 
4011  | 0  |     }  | 
4012  | 0  |     memset(set1->nodeTab, 0,  | 
4013  | 0  |         XML_NODESET_DEFAULT * sizeof(xmlNodePtr));  | 
4014  | 0  |     set1->nodeMax = XML_NODESET_DEFAULT;  | 
4015  | 2.84M  |       } else if (set1->nodeNr >= set1->nodeMax) { | 
4016  | 96.7k  |     xmlNodePtr *temp;  | 
4017  |  |  | 
4018  | 96.7k  |                 if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) { | 
4019  | 0  |                     xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");  | 
4020  | 0  |                     return(NULL);  | 
4021  | 0  |                 }  | 
4022  | 96.7k  |     temp = (xmlNodePtr *) xmlRealloc(  | 
4023  | 96.7k  |         set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));  | 
4024  | 96.7k  |     if (temp == NULL) { | 
4025  | 0  |         xmlXPathErrMemory(NULL, "merging nodeset\n");  | 
4026  | 0  |         return(NULL);  | 
4027  | 0  |     }  | 
4028  | 96.7k  |     set1->nodeTab = temp;  | 
4029  | 96.7k  |     set1->nodeMax *= 2;  | 
4030  | 96.7k  |       }  | 
4031  | 2.84M  |       set1->nodeTab[set1->nodeNr++] = n2;  | 
4032  | 12.9M  | skip_node:  | 
4033  | 12.9M  |       {} | 
4034  | 12.9M  |   }  | 
4035  | 6.02M  |     }  | 
4036  | 6.02M  |     set2->nodeNr = 0;  | 
4037  | 6.02M  |     return(set1);  | 
4038  | 6.02M  | }  | 
4039  |  |  | 
4040  |  | /**  | 
4041  |  |  * xmlXPathNodeSetMergeAndClearNoDupls:  | 
4042  |  |  * @set1:  the first NodeSet or NULL  | 
4043  |  |  * @set2:  the second NodeSet  | 
4044  |  |  *  | 
4045  |  |  * Merges two nodesets, all nodes from @set2 are added to @set1.  | 
4046  |  |  * Doesn't check for duplicate nodes. Clears set2.  | 
4047  |  |  *  | 
4048  |  |  * Returns @set1 once extended or NULL in case of error.  | 
4049  |  |  */  | 
4050  |  | static xmlNodeSetPtr  | 
4051  |  | xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1, xmlNodeSetPtr set2)  | 
4052  | 2.90M  | { | 
4053  | 2.90M  |     { | 
4054  | 2.90M  |   int i;  | 
4055  | 2.90M  |   xmlNodePtr n2;  | 
4056  |  |  | 
4057  | 7.19M  |   for (i = 0;i < set2->nodeNr;i++) { | 
4058  | 4.29M  |       n2 = set2->nodeTab[i];  | 
4059  | 4.29M  |       if (set1->nodeMax == 0) { | 
4060  | 0  |     set1->nodeTab = (xmlNodePtr *) xmlMalloc(  | 
4061  | 0  |         XML_NODESET_DEFAULT * sizeof(xmlNodePtr));  | 
4062  | 0  |     if (set1->nodeTab == NULL) { | 
4063  | 0  |         xmlXPathErrMemory(NULL, "merging nodeset\n");  | 
4064  | 0  |         return(NULL);  | 
4065  | 0  |     }  | 
4066  | 0  |     memset(set1->nodeTab, 0,  | 
4067  | 0  |         XML_NODESET_DEFAULT * sizeof(xmlNodePtr));  | 
4068  | 0  |     set1->nodeMax = XML_NODESET_DEFAULT;  | 
4069  | 4.29M  |       } else if (set1->nodeNr >= set1->nodeMax) { | 
4070  | 205k  |     xmlNodePtr *temp;  | 
4071  |  |  | 
4072  | 205k  |                 if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) { | 
4073  | 0  |                     xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");  | 
4074  | 0  |                     return(NULL);  | 
4075  | 0  |                 }  | 
4076  | 205k  |     temp = (xmlNodePtr *) xmlRealloc(  | 
4077  | 205k  |         set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));  | 
4078  | 205k  |     if (temp == NULL) { | 
4079  | 0  |         xmlXPathErrMemory(NULL, "merging nodeset\n");  | 
4080  | 0  |         return(NULL);  | 
4081  | 0  |     }  | 
4082  | 205k  |     set1->nodeTab = temp;  | 
4083  | 205k  |     set1->nodeMax *= 2;  | 
4084  | 205k  |       }  | 
4085  | 4.29M  |       set1->nodeTab[set1->nodeNr++] = n2;  | 
4086  | 4.29M  |   }  | 
4087  | 2.90M  |     }  | 
4088  | 2.90M  |     set2->nodeNr = 0;  | 
4089  | 2.90M  |     return(set1);  | 
4090  | 2.90M  | }  | 
4091  |  |  | 
4092  |  | /**  | 
4093  |  |  * xmlXPathNodeSetDel:  | 
4094  |  |  * @cur:  the initial node set  | 
4095  |  |  * @val:  an xmlNodePtr  | 
4096  |  |  *  | 
4097  |  |  * Removes an xmlNodePtr from an existing NodeSet  | 
4098  |  |  */  | 
4099  |  | void  | 
4100  | 0  | xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) { | 
4101  | 0  |     int i;  | 
4102  |  | 
  | 
4103  | 0  |     if (cur == NULL) return;  | 
4104  | 0  |     if (val == NULL) return;  | 
4105  |  |  | 
4106  |  |     /*  | 
4107  |  |      * find node in nodeTab  | 
4108  |  |      */  | 
4109  | 0  |     for (i = 0;i < cur->nodeNr;i++)  | 
4110  | 0  |         if (cur->nodeTab[i] == val) break;  | 
4111  |  | 
  | 
4112  | 0  |     if (i >= cur->nodeNr) { /* not found */ | 
4113  |  | #ifdef DEBUG  | 
4114  |  |         xmlGenericError(xmlGenericErrorContext,  | 
4115  |  |           "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",  | 
4116  |  |     val->name);  | 
4117  |  | #endif  | 
4118  | 0  |         return;  | 
4119  | 0  |     }  | 
4120  | 0  |     if ((cur->nodeTab[i] != NULL) &&  | 
4121  | 0  |   (cur->nodeTab[i]->type == XML_NAMESPACE_DECL))  | 
4122  | 0  |   xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);  | 
4123  | 0  |     cur->nodeNr--;  | 
4124  | 0  |     for (;i < cur->nodeNr;i++)  | 
4125  | 0  |         cur->nodeTab[i] = cur->nodeTab[i + 1];  | 
4126  | 0  |     cur->nodeTab[cur->nodeNr] = NULL;  | 
4127  | 0  | }  | 
4128  |  |  | 
4129  |  | /**  | 
4130  |  |  * xmlXPathNodeSetRemove:  | 
4131  |  |  * @cur:  the initial node set  | 
4132  |  |  * @val:  the index to remove  | 
4133  |  |  *  | 
4134  |  |  * Removes an entry from an existing NodeSet list.  | 
4135  |  |  */  | 
4136  |  | void  | 
4137  | 0  | xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) { | 
4138  | 0  |     if (cur == NULL) return;  | 
4139  | 0  |     if (val >= cur->nodeNr) return;  | 
4140  | 0  |     if ((cur->nodeTab[val] != NULL) &&  | 
4141  | 0  |   (cur->nodeTab[val]->type == XML_NAMESPACE_DECL))  | 
4142  | 0  |   xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);  | 
4143  | 0  |     cur->nodeNr--;  | 
4144  | 0  |     for (;val < cur->nodeNr;val++)  | 
4145  | 0  |         cur->nodeTab[val] = cur->nodeTab[val + 1];  | 
4146  | 0  |     cur->nodeTab[cur->nodeNr] = NULL;  | 
4147  | 0  | }  | 
4148  |  |  | 
4149  |  | /**  | 
4150  |  |  * xmlXPathFreeNodeSet:  | 
4151  |  |  * @obj:  the xmlNodeSetPtr to free  | 
4152  |  |  *  | 
4153  |  |  * Free the NodeSet compound (not the actual nodes !).  | 
4154  |  |  */  | 
4155  |  | void  | 
4156  | 25.4M  | xmlXPathFreeNodeSet(xmlNodeSetPtr obj) { | 
4157  | 25.4M  |     if (obj == NULL) return;  | 
4158  | 25.4M  |     if (obj->nodeTab != NULL) { | 
4159  | 10.9M  |   int i;  | 
4160  |  |  | 
4161  |  |   /* @@ with_ns to check whether namespace nodes should be looked at @@ */  | 
4162  | 88.3M  |   for (i = 0;i < obj->nodeNr;i++)  | 
4163  | 77.3M  |       if ((obj->nodeTab[i] != NULL) &&  | 
4164  | 77.3M  |     (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))  | 
4165  | 724k  |     xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);  | 
4166  | 10.9M  |   xmlFree(obj->nodeTab);  | 
4167  | 10.9M  |     }  | 
4168  | 25.4M  |     xmlFree(obj);  | 
4169  | 25.4M  | }  | 
4170  |  |  | 
4171  |  | /**  | 
4172  |  |  * xmlXPathNodeSetClearFromPos:  | 
4173  |  |  * @set: the node set to be cleared  | 
4174  |  |  * @pos: the start position to clear from  | 
4175  |  |  *  | 
4176  |  |  * Clears the list from temporary XPath objects (e.g. namespace nodes  | 
4177  |  |  * are feed) starting with the entry at @pos, but does *not* free the list  | 
4178  |  |  * itself. Sets the length of the list to @pos.  | 
4179  |  |  */  | 
4180  |  | static void  | 
4181  |  | xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set, int pos, int hasNsNodes)  | 
4182  | 50.4k  | { | 
4183  | 50.4k  |     if ((set == NULL) || (pos >= set->nodeNr))  | 
4184  | 0  |   return;  | 
4185  | 50.4k  |     else if ((hasNsNodes)) { | 
4186  | 33.5k  |   int i;  | 
4187  | 33.5k  |   xmlNodePtr node;  | 
4188  |  |  | 
4189  | 203k  |   for (i = pos; i < set->nodeNr; i++) { | 
4190  | 169k  |       node = set->nodeTab[i];  | 
4191  | 169k  |       if ((node != NULL) &&  | 
4192  | 169k  |     (node->type == XML_NAMESPACE_DECL))  | 
4193  | 35.6k  |     xmlXPathNodeSetFreeNs((xmlNsPtr) node);  | 
4194  | 169k  |   }  | 
4195  | 33.5k  |     }  | 
4196  | 50.4k  |     set->nodeNr = pos;  | 
4197  | 50.4k  | }  | 
4198  |  |  | 
4199  |  | /**  | 
4200  |  |  * xmlXPathNodeSetClear:  | 
4201  |  |  * @set:  the node set to clear  | 
4202  |  |  *  | 
4203  |  |  * Clears the list from all temporary XPath objects (e.g. namespace nodes  | 
4204  |  |  * are feed), but does *not* free the list itself. Sets the length of the  | 
4205  |  |  * list to 0.  | 
4206  |  |  */  | 
4207  |  | static void  | 
4208  |  | xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes)  | 
4209  | 27.6k  | { | 
4210  | 27.6k  |     xmlXPathNodeSetClearFromPos(set, 0, hasNsNodes);  | 
4211  | 27.6k  | }  | 
4212  |  |  | 
4213  |  | /**  | 
4214  |  |  * xmlXPathNodeSetKeepLast:  | 
4215  |  |  * @set: the node set to be cleared  | 
4216  |  |  *  | 
4217  |  |  * Move the last node to the first position and clear temporary XPath objects  | 
4218  |  |  * (e.g. namespace nodes) from all other nodes. Sets the length of the list  | 
4219  |  |  * to 1.  | 
4220  |  |  */  | 
4221  |  | static void  | 
4222  |  | xmlXPathNodeSetKeepLast(xmlNodeSetPtr set)  | 
4223  | 7.98k  | { | 
4224  | 7.98k  |     int i;  | 
4225  | 7.98k  |     xmlNodePtr node;  | 
4226  |  |  | 
4227  | 7.98k  |     if ((set == NULL) || (set->nodeNr <= 1))  | 
4228  | 0  |   return;  | 
4229  | 110k  |     for (i = 0; i < set->nodeNr - 1; i++) { | 
4230  | 102k  |         node = set->nodeTab[i];  | 
4231  | 102k  |         if ((node != NULL) &&  | 
4232  | 102k  |             (node->type == XML_NAMESPACE_DECL))  | 
4233  | 2.61k  |             xmlXPathNodeSetFreeNs((xmlNsPtr) node);  | 
4234  | 102k  |     }  | 
4235  | 7.98k  |     set->nodeTab[0] = set->nodeTab[set->nodeNr-1];  | 
4236  | 7.98k  |     set->nodeNr = 1;  | 
4237  | 7.98k  | }  | 
4238  |  |  | 
4239  |  | /**  | 
4240  |  |  * xmlXPathFreeValueTree:  | 
4241  |  |  * @obj:  the xmlNodeSetPtr to free  | 
4242  |  |  *  | 
4243  |  |  * Free the NodeSet compound and the actual tree, this is different  | 
4244  |  |  * from xmlXPathFreeNodeSet()  | 
4245  |  |  */  | 
4246  |  | static void  | 
4247  | 0  | xmlXPathFreeValueTree(xmlNodeSetPtr obj) { | 
4248  | 0  |     int i;  | 
4249  |  | 
  | 
4250  | 0  |     if (obj == NULL) return;  | 
4251  |  |  | 
4252  | 0  |     if (obj->nodeTab != NULL) { | 
4253  | 0  |   for (i = 0;i < obj->nodeNr;i++) { | 
4254  | 0  |       if (obj->nodeTab[i] != NULL) { | 
4255  | 0  |     if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) { | 
4256  | 0  |         xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);  | 
4257  | 0  |     } else { | 
4258  | 0  |         xmlFreeNodeList(obj->nodeTab[i]);  | 
4259  | 0  |     }  | 
4260  | 0  |       }  | 
4261  | 0  |   }  | 
4262  | 0  |   xmlFree(obj->nodeTab);  | 
4263  | 0  |     }  | 
4264  | 0  |     xmlFree(obj);  | 
4265  | 0  | }  | 
4266  |  |  | 
4267  |  | #if defined(DEBUG) || defined(DEBUG_STEP)  | 
4268  |  | /**  | 
4269  |  |  * xmlGenericErrorContextNodeSet:  | 
4270  |  |  * @output:  a FILE * for the output  | 
4271  |  |  * @obj:  the xmlNodeSetPtr to display  | 
4272  |  |  *  | 
4273  |  |  * Quick display of a NodeSet  | 
4274  |  |  */  | 
4275  |  | void  | 
4276  |  | xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) { | 
4277  |  |     int i;  | 
4278  |  |  | 
4279  |  |     if (output == NULL) output = xmlGenericErrorContext;  | 
4280  |  |     if (obj == NULL)  { | 
4281  |  |         fprintf(output, "NodeSet == NULL !\n");  | 
4282  |  |   return;  | 
4283  |  |     }  | 
4284  |  |     if (obj->nodeNr == 0) { | 
4285  |  |         fprintf(output, "NodeSet is empty\n");  | 
4286  |  |   return;  | 
4287  |  |     }  | 
4288  |  |     if (obj->nodeTab == NULL) { | 
4289  |  |   fprintf(output, " nodeTab == NULL !\n");  | 
4290  |  |   return;  | 
4291  |  |     }  | 
4292  |  |     for (i = 0; i < obj->nodeNr; i++) { | 
4293  |  |         if (obj->nodeTab[i] == NULL) { | 
4294  |  |       fprintf(output, " NULL !\n");  | 
4295  |  |       return;  | 
4296  |  |         }  | 
4297  |  |   if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||  | 
4298  |  |       (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))  | 
4299  |  |       fprintf(output, " /");  | 
4300  |  |   else if (obj->nodeTab[i]->name == NULL)  | 
4301  |  |       fprintf(output, " noname!");  | 
4302  |  |   else fprintf(output, " %s", obj->nodeTab[i]->name);  | 
4303  |  |     }  | 
4304  |  |     fprintf(output, "\n");  | 
4305  |  | }  | 
4306  |  | #endif  | 
4307  |  |  | 
4308  |  | /**  | 
4309  |  |  * xmlXPathNewNodeSet:  | 
4310  |  |  * @val:  the NodePtr value  | 
4311  |  |  *  | 
4312  |  |  * Create a new xmlXPathObjectPtr of type NodeSet and initialize  | 
4313  |  |  * it with the single Node @val  | 
4314  |  |  *  | 
4315  |  |  * Returns the newly created object.  | 
4316  |  |  */  | 
4317  |  | xmlXPathObjectPtr  | 
4318  | 6.95M  | xmlXPathNewNodeSet(xmlNodePtr val) { | 
4319  | 6.95M  |     xmlXPathObjectPtr ret;  | 
4320  |  |  | 
4321  | 6.95M  |     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));  | 
4322  | 6.95M  |     if (ret == NULL) { | 
4323  | 0  |         xmlXPathErrMemory(NULL, "creating nodeset\n");  | 
4324  | 0  |   return(NULL);  | 
4325  | 0  |     }  | 
4326  | 6.95M  |     memset(ret, 0 , sizeof(xmlXPathObject));  | 
4327  | 6.95M  |     ret->type = XPATH_NODESET;  | 
4328  | 6.95M  |     ret->boolval = 0;  | 
4329  |  |     /* TODO: Check memory error. */  | 
4330  | 6.95M  |     ret->nodesetval = xmlXPathNodeSetCreate(val);  | 
4331  |  |     /* @@ with_ns to check whether namespace nodes should be looked at @@ */  | 
4332  |  | #ifdef XP_DEBUG_OBJ_USAGE  | 
4333  |  |     xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);  | 
4334  |  | #endif  | 
4335  | 6.95M  |     return(ret);  | 
4336  | 6.95M  | }  | 
4337  |  |  | 
4338  |  | /**  | 
4339  |  |  * xmlXPathNewValueTree:  | 
4340  |  |  * @val:  the NodePtr value  | 
4341  |  |  *  | 
4342  |  |  * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize  | 
4343  |  |  * it with the tree root @val  | 
4344  |  |  *  | 
4345  |  |  * Returns the newly created object.  | 
4346  |  |  */  | 
4347  |  | xmlXPathObjectPtr  | 
4348  | 0  | xmlXPathNewValueTree(xmlNodePtr val) { | 
4349  | 0  |     xmlXPathObjectPtr ret;  | 
4350  |  | 
  | 
4351  | 0  |     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));  | 
4352  | 0  |     if (ret == NULL) { | 
4353  | 0  |         xmlXPathErrMemory(NULL, "creating result value tree\n");  | 
4354  | 0  |   return(NULL);  | 
4355  | 0  |     }  | 
4356  | 0  |     memset(ret, 0 , sizeof(xmlXPathObject));  | 
4357  | 0  |     ret->type = XPATH_XSLT_TREE;  | 
4358  | 0  |     ret->boolval = 1;  | 
4359  | 0  |     ret->user = (void *) val;  | 
4360  | 0  |     ret->nodesetval = xmlXPathNodeSetCreate(val);  | 
4361  |  | #ifdef XP_DEBUG_OBJ_USAGE  | 
4362  |  |     xmlXPathDebugObjUsageRequested(NULL, XPATH_XSLT_TREE);  | 
4363  |  | #endif  | 
4364  | 0  |     return(ret);  | 
4365  | 0  | }  | 
4366  |  |  | 
4367  |  | /**  | 
4368  |  |  * xmlXPathNewNodeSetList:  | 
4369  |  |  * @val:  an existing NodeSet  | 
4370  |  |  *  | 
4371  |  |  * Create a new xmlXPathObjectPtr of type NodeSet and initialize  | 
4372  |  |  * it with the Nodeset @val  | 
4373  |  |  *  | 
4374  |  |  * Returns the newly created object.  | 
4375  |  |  */  | 
4376  |  | xmlXPathObjectPtr  | 
4377  |  | xmlXPathNewNodeSetList(xmlNodeSetPtr val)  | 
4378  | 0  | { | 
4379  | 0  |     xmlXPathObjectPtr ret;  | 
4380  | 0  |     int i;  | 
4381  |  | 
  | 
4382  | 0  |     if (val == NULL)  | 
4383  | 0  |         ret = NULL;  | 
4384  | 0  |     else if (val->nodeTab == NULL)  | 
4385  | 0  |         ret = xmlXPathNewNodeSet(NULL);  | 
4386  | 0  |     else { | 
4387  | 0  |         ret = xmlXPathNewNodeSet(val->nodeTab[0]);  | 
4388  | 0  |         if (ret) { | 
4389  | 0  |             for (i = 1; i < val->nodeNr; ++i) { | 
4390  |  |                 /* TODO: Propagate memory error. */  | 
4391  | 0  |                 if (xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i])  | 
4392  | 0  |         < 0) break;  | 
4393  | 0  |       }  | 
4394  | 0  |   }  | 
4395  | 0  |     }  | 
4396  |  | 
  | 
4397  | 0  |     return (ret);  | 
4398  | 0  | }  | 
4399  |  |  | 
4400  |  | /**  | 
4401  |  |  * xmlXPathWrapNodeSet:  | 
4402  |  |  * @val:  the NodePtr value  | 
4403  |  |  *  | 
4404  |  |  * Wrap the Nodeset @val in a new xmlXPathObjectPtr  | 
4405  |  |  *  | 
4406  |  |  * Returns the newly created object.  | 
4407  |  |  */  | 
4408  |  | xmlXPathObjectPtr  | 
4409  | 5.71M  | xmlXPathWrapNodeSet(xmlNodeSetPtr val) { | 
4410  | 5.71M  |     xmlXPathObjectPtr ret;  | 
4411  |  |  | 
4412  | 5.71M  |     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));  | 
4413  | 5.71M  |     if (ret == NULL) { | 
4414  | 0  |         xmlXPathErrMemory(NULL, "creating node set object\n");  | 
4415  | 0  |   return(NULL);  | 
4416  | 0  |     }  | 
4417  | 5.71M  |     memset(ret, 0 , sizeof(xmlXPathObject));  | 
4418  | 5.71M  |     ret->type = XPATH_NODESET;  | 
4419  | 5.71M  |     ret->nodesetval = val;  | 
4420  |  | #ifdef XP_DEBUG_OBJ_USAGE  | 
4421  |  |     xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);  | 
4422  |  | #endif  | 
4423  | 5.71M  |     return(ret);  | 
4424  | 5.71M  | }  | 
4425  |  |  | 
4426  |  | /**  | 
4427  |  |  * xmlXPathFreeNodeSetList:  | 
4428  |  |  * @obj:  an existing NodeSetList object  | 
4429  |  |  *  | 
4430  |  |  * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in  | 
4431  |  |  * the list contrary to xmlXPathFreeObject().  | 
4432  |  |  */  | 
4433  |  | void  | 
4434  | 0  | xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) { | 
4435  | 0  |     if (obj == NULL) return;  | 
4436  |  | #ifdef XP_DEBUG_OBJ_USAGE  | 
4437  |  |     xmlXPathDebugObjUsageReleased(NULL, obj->type);  | 
4438  |  | #endif  | 
4439  | 0  |     xmlFree(obj);  | 
4440  | 0  | }  | 
4441  |  |  | 
4442  |  | /**  | 
4443  |  |  * xmlXPathDifference:  | 
4444  |  |  * @nodes1:  a node-set  | 
4445  |  |  * @nodes2:  a node-set  | 
4446  |  |  *  | 
4447  |  |  * Implements the EXSLT - Sets difference() function:  | 
4448  |  |  *    node-set set:difference (node-set, node-set)  | 
4449  |  |  *  | 
4450  |  |  * Returns the difference between the two node sets, or nodes1 if  | 
4451  |  |  *         nodes2 is empty  | 
4452  |  |  */  | 
4453  |  | xmlNodeSetPtr  | 
4454  | 2.99k  | xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) { | 
4455  | 2.99k  |     xmlNodeSetPtr ret;  | 
4456  | 2.99k  |     int i, l1;  | 
4457  | 2.99k  |     xmlNodePtr cur;  | 
4458  |  |  | 
4459  | 2.99k  |     if (xmlXPathNodeSetIsEmpty(nodes2))  | 
4460  | 789  |   return(nodes1);  | 
4461  |  |  | 
4462  |  |     /* TODO: Check memory error. */  | 
4463  | 2.20k  |     ret = xmlXPathNodeSetCreate(NULL);  | 
4464  | 2.20k  |     if (xmlXPathNodeSetIsEmpty(nodes1))  | 
4465  | 1.21k  |   return(ret);  | 
4466  |  |  | 
4467  | 992  |     l1 = xmlXPathNodeSetGetLength(nodes1);  | 
4468  |  |  | 
4469  | 6.11k  |     for (i = 0; i < l1; i++) { | 
4470  | 5.12k  |   cur = xmlXPathNodeSetItem(nodes1, i);  | 
4471  | 5.12k  |   if (!xmlXPathNodeSetContains(nodes2, cur)) { | 
4472  |  |             /* TODO: Propagate memory error. */  | 
4473  | 3.88k  |       if (xmlXPathNodeSetAddUnique(ret, cur) < 0)  | 
4474  | 0  |           break;  | 
4475  | 3.88k  |   }  | 
4476  | 5.12k  |     }  | 
4477  | 992  |     return(ret);  | 
4478  | 2.20k  | }  | 
4479  |  |  | 
4480  |  | /**  | 
4481  |  |  * xmlXPathIntersection:  | 
4482  |  |  * @nodes1:  a node-set  | 
4483  |  |  * @nodes2:  a node-set  | 
4484  |  |  *  | 
4485  |  |  * Implements the EXSLT - Sets intersection() function:  | 
4486  |  |  *    node-set set:intersection (node-set, node-set)  | 
4487  |  |  *  | 
4488  |  |  * Returns a node set comprising the nodes that are within both the  | 
4489  |  |  *         node sets passed as arguments  | 
4490  |  |  */  | 
4491  |  | xmlNodeSetPtr  | 
4492  | 631  | xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) { | 
4493  | 631  |     xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);  | 
4494  | 631  |     int i, l1;  | 
4495  | 631  |     xmlNodePtr cur;  | 
4496  |  |  | 
4497  | 631  |     if (ret == NULL)  | 
4498  | 0  |         return(ret);  | 
4499  | 631  |     if (xmlXPathNodeSetIsEmpty(nodes1))  | 
4500  | 284  |   return(ret);  | 
4501  | 347  |     if (xmlXPathNodeSetIsEmpty(nodes2))  | 
4502  | 95  |   return(ret);  | 
4503  |  |  | 
4504  | 252  |     l1 = xmlXPathNodeSetGetLength(nodes1);  | 
4505  |  |  | 
4506  | 2.83k  |     for (i = 0; i < l1; i++) { | 
4507  | 2.58k  |   cur = xmlXPathNodeSetItem(nodes1, i);  | 
4508  | 2.58k  |   if (xmlXPathNodeSetContains(nodes2, cur)) { | 
4509  |  |             /* TODO: Propagate memory error. */  | 
4510  | 776  |       if (xmlXPathNodeSetAddUnique(ret, cur) < 0)  | 
4511  | 0  |           break;  | 
4512  | 776  |   }  | 
4513  | 2.58k  |     }  | 
4514  | 252  |     return(ret);  | 
4515  | 347  | }  | 
4516  |  |  | 
4517  |  | /**  | 
4518  |  |  * xmlXPathDistinctSorted:  | 
4519  |  |  * @nodes:  a node-set, sorted by document order  | 
4520  |  |  *  | 
4521  |  |  * Implements the EXSLT - Sets distinct() function:  | 
4522  |  |  *    node-set set:distinct (node-set)  | 
4523  |  |  *  | 
4524  |  |  * Returns a subset of the nodes contained in @nodes, or @nodes if  | 
4525  |  |  *         it is empty  | 
4526  |  |  */  | 
4527  |  | xmlNodeSetPtr  | 
4528  | 1.12k  | xmlXPathDistinctSorted (xmlNodeSetPtr nodes) { | 
4529  | 1.12k  |     xmlNodeSetPtr ret;  | 
4530  | 1.12k  |     xmlHashTablePtr hash;  | 
4531  | 1.12k  |     int i, l;  | 
4532  | 1.12k  |     xmlChar * strval;  | 
4533  | 1.12k  |     xmlNodePtr cur;  | 
4534  |  |  | 
4535  | 1.12k  |     if (xmlXPathNodeSetIsEmpty(nodes))  | 
4536  | 260  |   return(nodes);  | 
4537  |  |  | 
4538  | 867  |     ret = xmlXPathNodeSetCreate(NULL);  | 
4539  | 867  |     if (ret == NULL)  | 
4540  | 0  |         return(ret);  | 
4541  | 867  |     l = xmlXPathNodeSetGetLength(nodes);  | 
4542  | 867  |     hash = xmlHashCreate (l);  | 
4543  | 16.1k  |     for (i = 0; i < l; i++) { | 
4544  | 15.2k  |   cur = xmlXPathNodeSetItem(nodes, i);  | 
4545  | 15.2k  |   strval = xmlXPathCastNodeToString(cur);  | 
4546  | 15.2k  |   if (xmlHashLookup(hash, strval) == NULL) { | 
4547  | 5.83k  |       xmlHashAddEntry(hash, strval, strval);  | 
4548  |  |             /* TODO: Propagate memory error. */  | 
4549  | 5.83k  |       if (xmlXPathNodeSetAddUnique(ret, cur) < 0)  | 
4550  | 0  |           break;  | 
4551  | 9.41k  |   } else { | 
4552  | 9.41k  |       xmlFree(strval);  | 
4553  | 9.41k  |   }  | 
4554  | 15.2k  |     }  | 
4555  | 867  |     xmlHashFree(hash, xmlHashDefaultDeallocator);  | 
4556  | 867  |     return(ret);  | 
4557  | 867  | }  | 
4558  |  |  | 
4559  |  | /**  | 
4560  |  |  * xmlXPathDistinct:  | 
4561  |  |  * @nodes:  a node-set  | 
4562  |  |  *  | 
4563  |  |  * Implements the EXSLT - Sets distinct() function:  | 
4564  |  |  *    node-set set:distinct (node-set)  | 
4565  |  |  * @nodes is sorted by document order, then #exslSetsDistinctSorted  | 
4566  |  |  * is called with the sorted node-set  | 
4567  |  |  *  | 
4568  |  |  * Returns a subset of the nodes contained in @nodes, or @nodes if  | 
4569  |  |  *         it is empty  | 
4570  |  |  */  | 
4571  |  | xmlNodeSetPtr  | 
4572  | 0  | xmlXPathDistinct (xmlNodeSetPtr nodes) { | 
4573  | 0  |     if (xmlXPathNodeSetIsEmpty(nodes))  | 
4574  | 0  |   return(nodes);  | 
4575  |  |  | 
4576  | 0  |     xmlXPathNodeSetSort(nodes);  | 
4577  | 0  |     return(xmlXPathDistinctSorted(nodes));  | 
4578  | 0  | }  | 
4579  |  |  | 
4580  |  | /**  | 
4581  |  |  * xmlXPathHasSameNodes:  | 
4582  |  |  * @nodes1:  a node-set  | 
4583  |  |  * @nodes2:  a node-set  | 
4584  |  |  *  | 
4585  |  |  * Implements the EXSLT - Sets has-same-nodes function:  | 
4586  |  |  *    boolean set:has-same-node(node-set, node-set)  | 
4587  |  |  *  | 
4588  |  |  * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)  | 
4589  |  |  *         otherwise  | 
4590  |  |  */  | 
4591  |  | int  | 
4592  | 2.31k  | xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) { | 
4593  | 2.31k  |     int i, l;  | 
4594  | 2.31k  |     xmlNodePtr cur;  | 
4595  |  |  | 
4596  | 2.31k  |     if (xmlXPathNodeSetIsEmpty(nodes1) ||  | 
4597  | 2.31k  |   xmlXPathNodeSetIsEmpty(nodes2))  | 
4598  | 1.07k  |   return(0);  | 
4599  |  |  | 
4600  | 1.23k  |     l = xmlXPathNodeSetGetLength(nodes1);  | 
4601  | 3.23k  |     for (i = 0; i < l; i++) { | 
4602  | 2.07k  |   cur = xmlXPathNodeSetItem(nodes1, i);  | 
4603  | 2.07k  |   if (xmlXPathNodeSetContains(nodes2, cur))  | 
4604  | 76  |       return(1);  | 
4605  | 2.07k  |     }  | 
4606  | 1.16k  |     return(0);  | 
4607  | 1.23k  | }  | 
4608  |  |  | 
4609  |  | /**  | 
4610  |  |  * xmlXPathNodeLeadingSorted:  | 
4611  |  |  * @nodes: a node-set, sorted by document order  | 
4612  |  |  * @node: a node  | 
4613  |  |  *  | 
4614  |  |  * Implements the EXSLT - Sets leading() function:  | 
4615  |  |  *    node-set set:leading (node-set, node-set)  | 
4616  |  |  *  | 
4617  |  |  * Returns the nodes in @nodes that precede @node in document order,  | 
4618  |  |  *         @nodes if @node is NULL or an empty node-set if @nodes  | 
4619  |  |  *         doesn't contain @node  | 
4620  |  |  */  | 
4621  |  | xmlNodeSetPtr  | 
4622  | 1.76k  | xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) { | 
4623  | 1.76k  |     int i, l;  | 
4624  | 1.76k  |     xmlNodePtr cur;  | 
4625  | 1.76k  |     xmlNodeSetPtr ret;  | 
4626  |  |  | 
4627  | 1.76k  |     if (node == NULL)  | 
4628  | 0  |   return(nodes);  | 
4629  |  |  | 
4630  | 1.76k  |     ret = xmlXPathNodeSetCreate(NULL);  | 
4631  | 1.76k  |     if (ret == NULL)  | 
4632  | 0  |         return(ret);  | 
4633  | 1.76k  |     if (xmlXPathNodeSetIsEmpty(nodes) ||  | 
4634  | 1.76k  |   (!xmlXPathNodeSetContains(nodes, node)))  | 
4635  | 1.08k  |   return(ret);  | 
4636  |  |  | 
4637  | 680  |     l = xmlXPathNodeSetGetLength(nodes);  | 
4638  | 8.44k  |     for (i = 0; i < l; i++) { | 
4639  | 8.44k  |   cur = xmlXPathNodeSetItem(nodes, i);  | 
4640  | 8.44k  |   if (cur == node)  | 
4641  | 675  |       break;  | 
4642  |  |         /* TODO: Propagate memory error. */  | 
4643  | 7.76k  |   if (xmlXPathNodeSetAddUnique(ret, cur) < 0)  | 
4644  | 0  |       break;  | 
4645  | 7.76k  |     }  | 
4646  | 680  |     return(ret);  | 
4647  | 1.76k  | }  | 
4648  |  |  | 
4649  |  | /**  | 
4650  |  |  * xmlXPathNodeLeading:  | 
4651  |  |  * @nodes:  a node-set  | 
4652  |  |  * @node:  a node  | 
4653  |  |  *  | 
4654  |  |  * Implements the EXSLT - Sets leading() function:  | 
4655  |  |  *    node-set set:leading (node-set, node-set)  | 
4656  |  |  * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted  | 
4657  |  |  * is called.  | 
4658  |  |  *  | 
4659  |  |  * Returns the nodes in @nodes that precede @node in document order,  | 
4660  |  |  *         @nodes if @node is NULL or an empty node-set if @nodes  | 
4661  |  |  *         doesn't contain @node  | 
4662  |  |  */  | 
4663  |  | xmlNodeSetPtr  | 
4664  | 0  | xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) { | 
4665  | 0  |     xmlXPathNodeSetSort(nodes);  | 
4666  | 0  |     return(xmlXPathNodeLeadingSorted(nodes, node));  | 
4667  | 0  | }  | 
4668  |  |  | 
4669  |  | /**  | 
4670  |  |  * xmlXPathLeadingSorted:  | 
4671  |  |  * @nodes1:  a node-set, sorted by document order  | 
4672  |  |  * @nodes2:  a node-set, sorted by document order  | 
4673  |  |  *  | 
4674  |  |  * Implements the EXSLT - Sets leading() function:  | 
4675  |  |  *    node-set set:leading (node-set, node-set)  | 
4676  |  |  *  | 
4677  |  |  * Returns the nodes in @nodes1 that precede the first node in @nodes2  | 
4678  |  |  *         in document order, @nodes1 if @nodes2 is NULL or empty or  | 
4679  |  |  *         an empty node-set if @nodes1 doesn't contain @nodes2  | 
4680  |  |  */  | 
4681  |  | xmlNodeSetPtr  | 
4682  | 0  | xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) { | 
4683  | 0  |     if (xmlXPathNodeSetIsEmpty(nodes2))  | 
4684  | 0  |   return(nodes1);  | 
4685  | 0  |     return(xmlXPathNodeLeadingSorted(nodes1,  | 
4686  | 0  |              xmlXPathNodeSetItem(nodes2, 1)));  | 
4687  | 0  | }  | 
4688  |  |  | 
4689  |  | /**  | 
4690  |  |  * xmlXPathLeading:  | 
4691  |  |  * @nodes1:  a node-set  | 
4692  |  |  * @nodes2:  a node-set  | 
4693  |  |  *  | 
4694  |  |  * Implements the EXSLT - Sets leading() function:  | 
4695  |  |  *    node-set set:leading (node-set, node-set)  | 
4696  |  |  * @nodes1 and @nodes2 are sorted by document order, then  | 
4697  |  |  * #exslSetsLeadingSorted is called.  | 
4698  |  |  *  | 
4699  |  |  * Returns the nodes in @nodes1 that precede the first node in @nodes2  | 
4700  |  |  *         in document order, @nodes1 if @nodes2 is NULL or empty or  | 
4701  |  |  *         an empty node-set if @nodes1 doesn't contain @nodes2  | 
4702  |  |  */  | 
4703  |  | xmlNodeSetPtr  | 
4704  | 0  | xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) { | 
4705  | 0  |     if (xmlXPathNodeSetIsEmpty(nodes2))  | 
4706  | 0  |   return(nodes1);  | 
4707  | 0  |     if (xmlXPathNodeSetIsEmpty(nodes1))  | 
4708  | 0  |   return(xmlXPathNodeSetCreate(NULL));  | 
4709  | 0  |     xmlXPathNodeSetSort(nodes1);  | 
4710  | 0  |     xmlXPathNodeSetSort(nodes2);  | 
4711  | 0  |     return(xmlXPathNodeLeadingSorted(nodes1,  | 
4712  | 0  |              xmlXPathNodeSetItem(nodes2, 1)));  | 
4713  | 0  | }  | 
4714  |  |  | 
4715  |  | /**  | 
4716  |  |  * xmlXPathNodeTrailingSorted:  | 
4717  |  |  * @nodes: a node-set, sorted by document order  | 
4718  |  |  * @node: a node  | 
4719  |  |  *  | 
4720  |  |  * Implements the EXSLT - Sets trailing() function:  | 
4721  |  |  *    node-set set:trailing (node-set, node-set)  | 
4722  |  |  *  | 
4723  |  |  * Returns the nodes in @nodes that follow @node in document order,  | 
4724  |  |  *         @nodes if @node is NULL or an empty node-set if @nodes  | 
4725  |  |  *         doesn't contain @node  | 
4726  |  |  */  | 
4727  |  | xmlNodeSetPtr  | 
4728  | 464  | xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) { | 
4729  | 464  |     int i, l;  | 
4730  | 464  |     xmlNodePtr cur;  | 
4731  | 464  |     xmlNodeSetPtr ret;  | 
4732  |  |  | 
4733  | 464  |     if (node == NULL)  | 
4734  | 0  |   return(nodes);  | 
4735  |  |  | 
4736  | 464  |     ret = xmlXPathNodeSetCreate(NULL);  | 
4737  | 464  |     if (ret == NULL)  | 
4738  | 0  |         return(ret);  | 
4739  | 464  |     if (xmlXPathNodeSetIsEmpty(nodes) ||  | 
4740  | 464  |   (!xmlXPathNodeSetContains(nodes, node)))  | 
4741  | 278  |   return(ret);  | 
4742  |  |  | 
4743  | 186  |     l = xmlXPathNodeSetGetLength(nodes);  | 
4744  | 2.11k  |     for (i = l - 1; i >= 0; i--) { | 
4745  | 2.09k  |   cur = xmlXPathNodeSetItem(nodes, i);  | 
4746  | 2.09k  |   if (cur == node)  | 
4747  | 174  |       break;  | 
4748  |  |         /* TODO: Propagate memory error. */  | 
4749  | 1.92k  |   if (xmlXPathNodeSetAddUnique(ret, cur) < 0)  | 
4750  | 0  |       break;  | 
4751  | 1.92k  |     }  | 
4752  | 186  |     xmlXPathNodeSetSort(ret); /* bug 413451 */  | 
4753  | 186  |     return(ret);  | 
4754  | 464  | }  | 
4755  |  |  | 
4756  |  | /**  | 
4757  |  |  * xmlXPathNodeTrailing:  | 
4758  |  |  * @nodes:  a node-set  | 
4759  |  |  * @node:  a node  | 
4760  |  |  *  | 
4761  |  |  * Implements the EXSLT - Sets trailing() function:  | 
4762  |  |  *    node-set set:trailing (node-set, node-set)  | 
4763  |  |  * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted  | 
4764  |  |  * is called.  | 
4765  |  |  *  | 
4766  |  |  * Returns the nodes in @nodes that follow @node in document order,  | 
4767  |  |  *         @nodes if @node is NULL or an empty node-set if @nodes  | 
4768  |  |  *         doesn't contain @node  | 
4769  |  |  */  | 
4770  |  | xmlNodeSetPtr  | 
4771  | 0  | xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) { | 
4772  | 0  |     xmlXPathNodeSetSort(nodes);  | 
4773  | 0  |     return(xmlXPathNodeTrailingSorted(nodes, node));  | 
4774  | 0  | }  | 
4775  |  |  | 
4776  |  | /**  | 
4777  |  |  * xmlXPathTrailingSorted:  | 
4778  |  |  * @nodes1:  a node-set, sorted by document order  | 
4779  |  |  * @nodes2:  a node-set, sorted by document order  | 
4780  |  |  *  | 
4781  |  |  * Implements the EXSLT - Sets trailing() function:  | 
4782  |  |  *    node-set set:trailing (node-set, node-set)  | 
4783  |  |  *  | 
4784  |  |  * Returns the nodes in @nodes1 that follow the first node in @nodes2  | 
4785  |  |  *         in document order, @nodes1 if @nodes2 is NULL or empty or  | 
4786  |  |  *         an empty node-set if @nodes1 doesn't contain @nodes2  | 
4787  |  |  */  | 
4788  |  | xmlNodeSetPtr  | 
4789  | 0  | xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) { | 
4790  | 0  |     if (xmlXPathNodeSetIsEmpty(nodes2))  | 
4791  | 0  |   return(nodes1);  | 
4792  | 0  |     return(xmlXPathNodeTrailingSorted(nodes1,  | 
4793  | 0  |               xmlXPathNodeSetItem(nodes2, 0)));  | 
4794  | 0  | }  | 
4795  |  |  | 
4796  |  | /**  | 
4797  |  |  * xmlXPathTrailing:  | 
4798  |  |  * @nodes1:  a node-set  | 
4799  |  |  * @nodes2:  a node-set  | 
4800  |  |  *  | 
4801  |  |  * Implements the EXSLT - Sets trailing() function:  | 
4802  |  |  *    node-set set:trailing (node-set, node-set)  | 
4803  |  |  * @nodes1 and @nodes2 are sorted by document order, then  | 
4804  |  |  * #xmlXPathTrailingSorted is called.  | 
4805  |  |  *  | 
4806  |  |  * Returns the nodes in @nodes1 that follow the first node in @nodes2  | 
4807  |  |  *         in document order, @nodes1 if @nodes2 is NULL or empty or  | 
4808  |  |  *         an empty node-set if @nodes1 doesn't contain @nodes2  | 
4809  |  |  */  | 
4810  |  | xmlNodeSetPtr  | 
4811  | 0  | xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) { | 
4812  | 0  |     if (xmlXPathNodeSetIsEmpty(nodes2))  | 
4813  | 0  |   return(nodes1);  | 
4814  | 0  |     if (xmlXPathNodeSetIsEmpty(nodes1))  | 
4815  | 0  |   return(xmlXPathNodeSetCreate(NULL));  | 
4816  | 0  |     xmlXPathNodeSetSort(nodes1);  | 
4817  | 0  |     xmlXPathNodeSetSort(nodes2);  | 
4818  | 0  |     return(xmlXPathNodeTrailingSorted(nodes1,  | 
4819  | 0  |               xmlXPathNodeSetItem(nodes2, 0)));  | 
4820  | 0  | }  | 
4821  |  |  | 
4822  |  | /************************************************************************  | 
4823  |  |  *                  *  | 
4824  |  |  *    Routines to handle extra functions      *  | 
4825  |  |  *                  *  | 
4826  |  |  ************************************************************************/  | 
4827  |  |  | 
4828  |  | /**  | 
4829  |  |  * xmlXPathRegisterFunc:  | 
4830  |  |  * @ctxt:  the XPath context  | 
4831  |  |  * @name:  the function name  | 
4832  |  |  * @f:  the function implementation or NULL  | 
4833  |  |  *  | 
4834  |  |  * Register a new function. If @f is NULL it unregisters the function  | 
4835  |  |  *  | 
4836  |  |  * Returns 0 in case of success, -1 in case of error  | 
4837  |  |  */  | 
4838  |  | int  | 
4839  |  | xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,  | 
4840  | 1.95M  |          xmlXPathFunction f) { | 
4841  | 1.95M  |     return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));  | 
4842  | 1.95M  | }  | 
4843  |  |  | 
4844  |  | /**  | 
4845  |  |  * xmlXPathRegisterFuncNS:  | 
4846  |  |  * @ctxt:  the XPath context  | 
4847  |  |  * @name:  the function name  | 
4848  |  |  * @ns_uri:  the function namespace URI  | 
4849  |  |  * @f:  the function implementation or NULL  | 
4850  |  |  *  | 
4851  |  |  * Register a new function. If @f is NULL it unregisters the function  | 
4852  |  |  *  | 
4853  |  |  * Returns 0 in case of success, -1 in case of error  | 
4854  |  |  */  | 
4855  |  | int  | 
4856  |  | xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,  | 
4857  | 2.02M  |            const xmlChar *ns_uri, xmlXPathFunction f) { | 
4858  | 2.02M  |     if (ctxt == NULL)  | 
4859  | 0  |   return(-1);  | 
4860  | 2.02M  |     if (name == NULL)  | 
4861  | 0  |   return(-1);  | 
4862  |  |  | 
4863  | 2.02M  |     if (ctxt->funcHash == NULL)  | 
4864  | 0  |   ctxt->funcHash = xmlHashCreate(0);  | 
4865  | 2.02M  |     if (ctxt->funcHash == NULL)  | 
4866  | 0  |   return(-1);  | 
4867  | 2.02M  |     if (f == NULL)  | 
4868  | 0  |         return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));  | 
4869  | 2.02M  | XML_IGNORE_FPTR_CAST_WARNINGS  | 
4870  | 2.02M  |     return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, (void *) f));  | 
4871  | 2.02M  | XML_POP_WARNINGS  | 
4872  | 2.02M  | }  | 
4873  |  |  | 
4874  |  | /**  | 
4875  |  |  * xmlXPathRegisterFuncLookup:  | 
4876  |  |  * @ctxt:  the XPath context  | 
4877  |  |  * @f:  the lookup function  | 
4878  |  |  * @funcCtxt:  the lookup data  | 
4879  |  |  *  | 
4880  |  |  * Registers an external mechanism to do function lookup.  | 
4881  |  |  */  | 
4882  |  | void  | 
4883  |  | xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,  | 
4884  |  |           xmlXPathFuncLookupFunc f,  | 
4885  | 3.70k  |           void *funcCtxt) { | 
4886  | 3.70k  |     if (ctxt == NULL)  | 
4887  | 0  |   return;  | 
4888  | 3.70k  |     ctxt->funcLookupFunc = f;  | 
4889  | 3.70k  |     ctxt->funcLookupData = funcCtxt;  | 
4890  | 3.70k  | }  | 
4891  |  |  | 
4892  |  | /**  | 
4893  |  |  * xmlXPathFunctionLookup:  | 
4894  |  |  * @ctxt:  the XPath context  | 
4895  |  |  * @name:  the function name  | 
4896  |  |  *  | 
4897  |  |  * Search in the Function array of the context for the given  | 
4898  |  |  * function.  | 
4899  |  |  *  | 
4900  |  |  * Returns the xmlXPathFunction or NULL if not found  | 
4901  |  |  */  | 
4902  |  | xmlXPathFunction  | 
4903  | 238k  | xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) { | 
4904  | 238k  |     if (ctxt == NULL)  | 
4905  | 0  |   return (NULL);  | 
4906  |  |  | 
4907  | 238k  |     if (ctxt->funcLookupFunc != NULL) { | 
4908  | 238k  |   xmlXPathFunction ret;  | 
4909  | 238k  |   xmlXPathFuncLookupFunc f;  | 
4910  |  |  | 
4911  | 238k  |   f = ctxt->funcLookupFunc;  | 
4912  | 238k  |   ret = f(ctxt->funcLookupData, name, NULL);  | 
4913  | 238k  |   if (ret != NULL)  | 
4914  | 0  |       return(ret);  | 
4915  | 238k  |     }  | 
4916  | 238k  |     return(xmlXPathFunctionLookupNS(ctxt, name, NULL));  | 
4917  | 238k  | }  | 
4918  |  |  | 
4919  |  | /**  | 
4920  |  |  * xmlXPathFunctionLookupNS:  | 
4921  |  |  * @ctxt:  the XPath context  | 
4922  |  |  * @name:  the function name  | 
4923  |  |  * @ns_uri:  the function namespace URI  | 
4924  |  |  *  | 
4925  |  |  * Search in the Function array of the context for the given  | 
4926  |  |  * function.  | 
4927  |  |  *  | 
4928  |  |  * Returns the xmlXPathFunction or NULL if not found  | 
4929  |  |  */  | 
4930  |  | xmlXPathFunction  | 
4931  |  | xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,  | 
4932  | 342k  |        const xmlChar *ns_uri) { | 
4933  | 342k  |     xmlXPathFunction ret;  | 
4934  |  |  | 
4935  | 342k  |     if (ctxt == NULL)  | 
4936  | 0  |   return(NULL);  | 
4937  | 342k  |     if (name == NULL)  | 
4938  | 0  |   return(NULL);  | 
4939  |  |  | 
4940  | 342k  |     if (ctxt->funcLookupFunc != NULL) { | 
4941  | 342k  |   xmlXPathFuncLookupFunc f;  | 
4942  |  |  | 
4943  | 342k  |   f = ctxt->funcLookupFunc;  | 
4944  | 342k  |   ret = f(ctxt->funcLookupData, name, ns_uri);  | 
4945  | 342k  |   if (ret != NULL)  | 
4946  | 100k  |       return(ret);  | 
4947  | 342k  |     }  | 
4948  |  |  | 
4949  | 242k  |     if (ctxt->funcHash == NULL)  | 
4950  | 0  |   return(NULL);  | 
4951  |  |  | 
4952  | 242k  | XML_IGNORE_FPTR_CAST_WARNINGS  | 
4953  | 242k  |     ret = (xmlXPathFunction) xmlHashLookup2(ctxt->funcHash, name, ns_uri);  | 
4954  | 242k  | XML_POP_WARNINGS  | 
4955  | 242k  |     return(ret);  | 
4956  | 242k  | }  | 
4957  |  |  | 
4958  |  | /**  | 
4959  |  |  * xmlXPathRegisteredFuncsCleanup:  | 
4960  |  |  * @ctxt:  the XPath context  | 
4961  |  |  *  | 
4962  |  |  * Cleanup the XPath context data associated to registered functions  | 
4963  |  |  */  | 
4964  |  | void  | 
4965  | 63.7k  | xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) { | 
4966  | 63.7k  |     if (ctxt == NULL)  | 
4967  | 0  |   return;  | 
4968  |  |  | 
4969  | 63.7k  |     xmlHashFree(ctxt->funcHash, NULL);  | 
4970  | 63.7k  |     ctxt->funcHash = NULL;  | 
4971  | 63.7k  | }  | 
4972  |  |  | 
4973  |  | /************************************************************************  | 
4974  |  |  *                  *  | 
4975  |  |  *      Routines to handle Variables      *  | 
4976  |  |  *                  *  | 
4977  |  |  ************************************************************************/  | 
4978  |  |  | 
4979  |  | /**  | 
4980  |  |  * xmlXPathRegisterVariable:  | 
4981  |  |  * @ctxt:  the XPath context  | 
4982  |  |  * @name:  the variable name  | 
4983  |  |  * @value:  the variable value or NULL  | 
4984  |  |  *  | 
4985  |  |  * Register a new variable value. If @value is NULL it unregisters  | 
4986  |  |  * the variable  | 
4987  |  |  *  | 
4988  |  |  * Returns 0 in case of success, -1 in case of error  | 
4989  |  |  */  | 
4990  |  | int  | 
4991  |  | xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,  | 
4992  | 14.8k  |        xmlXPathObjectPtr value) { | 
4993  | 14.8k  |     return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));  | 
4994  | 14.8k  | }  | 
4995  |  |  | 
4996  |  | /**  | 
4997  |  |  * xmlXPathRegisterVariableNS:  | 
4998  |  |  * @ctxt:  the XPath context  | 
4999  |  |  * @name:  the variable name  | 
5000  |  |  * @ns_uri:  the variable namespace URI  | 
5001  |  |  * @value:  the variable value or NULL  | 
5002  |  |  *  | 
5003  |  |  * Register a new variable value. If @value is NULL it unregisters  | 
5004  |  |  * the variable  | 
5005  |  |  *  | 
5006  |  |  * Returns 0 in case of success, -1 in case of error  | 
5007  |  |  */  | 
5008  |  | int  | 
5009  |  | xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,  | 
5010  |  |          const xmlChar *ns_uri,  | 
5011  | 14.8k  |          xmlXPathObjectPtr value) { | 
5012  | 14.8k  |     if (ctxt == NULL)  | 
5013  | 0  |   return(-1);  | 
5014  | 14.8k  |     if (name == NULL)  | 
5015  | 0  |   return(-1);  | 
5016  |  |  | 
5017  | 14.8k  |     if (ctxt->varHash == NULL)  | 
5018  | 3.70k  |   ctxt->varHash = xmlHashCreate(0);  | 
5019  | 14.8k  |     if (ctxt->varHash == NULL)  | 
5020  | 0  |   return(-1);  | 
5021  | 14.8k  |     if (value == NULL)  | 
5022  | 0  |         return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,  | 
5023  | 0  |                              xmlXPathFreeObjectEntry));  | 
5024  | 14.8k  |     return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,  | 
5025  | 14.8k  |              (void *) value, xmlXPathFreeObjectEntry));  | 
5026  | 14.8k  | }  | 
5027  |  |  | 
5028  |  | /**  | 
5029  |  |  * xmlXPathRegisterVariableLookup:  | 
5030  |  |  * @ctxt:  the XPath context  | 
5031  |  |  * @f:  the lookup function  | 
5032  |  |  * @data:  the lookup data  | 
5033  |  |  *  | 
5034  |  |  * register an external mechanism to do variable lookup  | 
5035  |  |  */  | 
5036  |  | void  | 
5037  |  | xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,  | 
5038  | 3.70k  |    xmlXPathVariableLookupFunc f, void *data) { | 
5039  | 3.70k  |     if (ctxt == NULL)  | 
5040  | 0  |   return;  | 
5041  | 3.70k  |     ctxt->varLookupFunc = f;  | 
5042  | 3.70k  |     ctxt->varLookupData = data;  | 
5043  | 3.70k  | }  | 
5044  |  |  | 
5045  |  | /**  | 
5046  |  |  * xmlXPathVariableLookup:  | 
5047  |  |  * @ctxt:  the XPath context  | 
5048  |  |  * @name:  the variable name  | 
5049  |  |  *  | 
5050  |  |  * Search in the Variable array of the context for the given  | 
5051  |  |  * variable value.  | 
5052  |  |  *  | 
5053  |  |  * Returns a copy of the value or NULL if not found  | 
5054  |  |  */  | 
5055  |  | xmlXPathObjectPtr  | 
5056  | 39.5k  | xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) { | 
5057  | 39.5k  |     if (ctxt == NULL)  | 
5058  | 0  |   return(NULL);  | 
5059  |  |  | 
5060  | 39.5k  |     if (ctxt->varLookupFunc != NULL) { | 
5061  | 39.5k  |   xmlXPathObjectPtr ret;  | 
5062  |  |  | 
5063  | 39.5k  |   ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)  | 
5064  | 39.5k  |           (ctxt->varLookupData, name, NULL);  | 
5065  | 39.5k  |   return(ret);  | 
5066  | 39.5k  |     }  | 
5067  | 0  |     return(xmlXPathVariableLookupNS(ctxt, name, NULL));  | 
5068  | 39.5k  | }  | 
5069  |  |  | 
5070  |  | /**  | 
5071  |  |  * xmlXPathVariableLookupNS:  | 
5072  |  |  * @ctxt:  the XPath context  | 
5073  |  |  * @name:  the variable name  | 
5074  |  |  * @ns_uri:  the variable namespace URI  | 
5075  |  |  *  | 
5076  |  |  * Search in the Variable array of the context for the given  | 
5077  |  |  * variable value.  | 
5078  |  |  *  | 
5079  |  |  * Returns the a copy of the value or NULL if not found  | 
5080  |  |  */  | 
5081  |  | xmlXPathObjectPtr  | 
5082  |  | xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,  | 
5083  | 4.92k  |        const xmlChar *ns_uri) { | 
5084  | 4.92k  |     if (ctxt == NULL)  | 
5085  | 0  |   return(NULL);  | 
5086  |  |  | 
5087  | 4.92k  |     if (ctxt->varLookupFunc != NULL) { | 
5088  | 4.92k  |   xmlXPathObjectPtr ret;  | 
5089  |  |  | 
5090  | 4.92k  |   ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)  | 
5091  | 4.92k  |           (ctxt->varLookupData, name, ns_uri);  | 
5092  | 4.92k  |   if (ret != NULL) return(ret);  | 
5093  | 4.92k  |     }  | 
5094  |  |  | 
5095  | 4.92k  |     if (ctxt->varHash == NULL)  | 
5096  | 0  |   return(NULL);  | 
5097  | 4.92k  |     if (name == NULL)  | 
5098  | 0  |   return(NULL);  | 
5099  |  |  | 
5100  | 4.92k  |     return(xmlXPathCacheObjectCopy(ctxt, (xmlXPathObjectPtr)  | 
5101  | 4.92k  |     xmlHashLookup2(ctxt->varHash, name, ns_uri)));  | 
5102  | 4.92k  | }  | 
5103  |  |  | 
5104  |  | /**  | 
5105  |  |  * xmlXPathRegisteredVariablesCleanup:  | 
5106  |  |  * @ctxt:  the XPath context  | 
5107  |  |  *  | 
5108  |  |  * Cleanup the XPath context data associated to registered variables  | 
5109  |  |  */  | 
5110  |  | void  | 
5111  | 63.7k  | xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) { | 
5112  | 63.7k  |     if (ctxt == NULL)  | 
5113  | 0  |   return;  | 
5114  |  |  | 
5115  | 63.7k  |     xmlHashFree(ctxt->varHash, xmlXPathFreeObjectEntry);  | 
5116  | 63.7k  |     ctxt->varHash = NULL;  | 
5117  | 63.7k  | }  | 
5118  |  |  | 
5119  |  | /**  | 
5120  |  |  * xmlXPathRegisterNs:  | 
5121  |  |  * @ctxt:  the XPath context  | 
5122  |  |  * @prefix:  the namespace prefix cannot be NULL or empty string  | 
5123  |  |  * @ns_uri:  the namespace name  | 
5124  |  |  *  | 
5125  |  |  * Register a new namespace. If @ns_uri is NULL it unregisters  | 
5126  |  |  * the namespace  | 
5127  |  |  *  | 
5128  |  |  * Returns 0 in case of success, -1 in case of error  | 
5129  |  |  */  | 
5130  |  | int  | 
5131  |  | xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,  | 
5132  | 40.7k  |          const xmlChar *ns_uri) { | 
5133  | 40.7k  |     if (ctxt == NULL)  | 
5134  | 0  |   return(-1);  | 
5135  | 40.7k  |     if (prefix == NULL)  | 
5136  | 0  |   return(-1);  | 
5137  | 40.7k  |     if (prefix[0] == 0)  | 
5138  | 0  |   return(-1);  | 
5139  |  |  | 
5140  | 40.7k  |     if (ctxt->nsHash == NULL)  | 
5141  | 3.70k  |   ctxt->nsHash = xmlHashCreate(10);  | 
5142  | 40.7k  |     if (ctxt->nsHash == NULL)  | 
5143  | 0  |   return(-1);  | 
5144  | 40.7k  |     if (ns_uri == NULL)  | 
5145  | 0  |         return(xmlHashRemoveEntry(ctxt->nsHash, prefix,  | 
5146  | 0  |                             xmlHashDefaultDeallocator));  | 
5147  | 40.7k  |     return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),  | 
5148  | 40.7k  |             xmlHashDefaultDeallocator));  | 
5149  | 40.7k  | }  | 
5150  |  |  | 
5151  |  | /**  | 
5152  |  |  * xmlXPathNsLookup:  | 
5153  |  |  * @ctxt:  the XPath context  | 
5154  |  |  * @prefix:  the namespace prefix value  | 
5155  |  |  *  | 
5156  |  |  * Search in the namespace declaration array of the context for the given  | 
5157  |  |  * namespace name associated to the given prefix  | 
5158  |  |  *  | 
5159  |  |  * Returns the value or NULL if not found  | 
5160  |  |  */  | 
5161  |  | const xmlChar *  | 
5162  | 754k  | xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) { | 
5163  | 754k  |     if (ctxt == NULL)  | 
5164  | 0  |   return(NULL);  | 
5165  | 754k  |     if (prefix == NULL)  | 
5166  | 0  |   return(NULL);  | 
5167  |  |  | 
5168  | 754k  | #ifdef XML_XML_NAMESPACE  | 
5169  | 754k  |     if (xmlStrEqual(prefix, (const xmlChar *) "xml"))  | 
5170  | 817  |   return(XML_XML_NAMESPACE);  | 
5171  | 754k  | #endif  | 
5172  |  |  | 
5173  | 754k  |     if (ctxt->namespaces != NULL) { | 
5174  | 0  |   int i;  | 
5175  |  | 
  | 
5176  | 0  |   for (i = 0;i < ctxt->nsNr;i++) { | 
5177  | 0  |       if ((ctxt->namespaces[i] != NULL) &&  | 
5178  | 0  |     (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))  | 
5179  | 0  |     return(ctxt->namespaces[i]->href);  | 
5180  | 0  |   }  | 
5181  | 0  |     }  | 
5182  |  |  | 
5183  | 754k  |     return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));  | 
5184  | 754k  | }  | 
5185  |  |  | 
5186  |  | /**  | 
5187  |  |  * xmlXPathRegisteredNsCleanup:  | 
5188  |  |  * @ctxt:  the XPath context  | 
5189  |  |  *  | 
5190  |  |  * Cleanup the XPath context data associated to registered variables  | 
5191  |  |  */  | 
5192  |  | void  | 
5193  | 63.7k  | xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) { | 
5194  | 63.7k  |     if (ctxt == NULL)  | 
5195  | 0  |   return;  | 
5196  |  |  | 
5197  | 63.7k  |     xmlHashFree(ctxt->nsHash, xmlHashDefaultDeallocator);  | 
5198  | 63.7k  |     ctxt->nsHash = NULL;  | 
5199  | 63.7k  | }  | 
5200  |  |  | 
5201  |  | /************************************************************************  | 
5202  |  |  *                  *  | 
5203  |  |  *      Routines to handle Values     *  | 
5204  |  |  *                  *  | 
5205  |  |  ************************************************************************/  | 
5206  |  |  | 
5207  |  | /* Allocations are terrible, one needs to optimize all this !!! */  | 
5208  |  |  | 
5209  |  | /**  | 
5210  |  |  * xmlXPathNewFloat:  | 
5211  |  |  * @val:  the double value  | 
5212  |  |  *  | 
5213  |  |  * Create a new xmlXPathObjectPtr of type double and of value @val  | 
5214  |  |  *  | 
5215  |  |  * Returns the newly created object.  | 
5216  |  |  */  | 
5217  |  | xmlXPathObjectPtr  | 
5218  | 1.28M  | xmlXPathNewFloat(double val) { | 
5219  | 1.28M  |     xmlXPathObjectPtr ret;  | 
5220  |  |  | 
5221  | 1.28M  |     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));  | 
5222  | 1.28M  |     if (ret == NULL) { | 
5223  | 0  |         xmlXPathErrMemory(NULL, "creating float object\n");  | 
5224  | 0  |   return(NULL);  | 
5225  | 0  |     }  | 
5226  | 1.28M  |     memset(ret, 0 , sizeof(xmlXPathObject));  | 
5227  | 1.28M  |     ret->type = XPATH_NUMBER;  | 
5228  | 1.28M  |     ret->floatval = val;  | 
5229  |  | #ifdef XP_DEBUG_OBJ_USAGE  | 
5230  |  |     xmlXPathDebugObjUsageRequested(NULL, XPATH_NUMBER);  | 
5231  |  | #endif  | 
5232  | 1.28M  |     return(ret);  | 
5233  | 1.28M  | }  | 
5234  |  |  | 
5235  |  | /**  | 
5236  |  |  * xmlXPathNewBoolean:  | 
5237  |  |  * @val:  the boolean value  | 
5238  |  |  *  | 
5239  |  |  * Create a new xmlXPathObjectPtr of type boolean and of value @val  | 
5240  |  |  *  | 
5241  |  |  * Returns the newly created object.  | 
5242  |  |  */  | 
5243  |  | xmlXPathObjectPtr  | 
5244  | 188k  | xmlXPathNewBoolean(int val) { | 
5245  | 188k  |     xmlXPathObjectPtr ret;  | 
5246  |  |  | 
5247  | 188k  |     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));  | 
5248  | 188k  |     if (ret == NULL) { | 
5249  | 0  |         xmlXPathErrMemory(NULL, "creating boolean object\n");  | 
5250  | 0  |   return(NULL);  | 
5251  | 0  |     }  | 
5252  | 188k  |     memset(ret, 0 , sizeof(xmlXPathObject));  | 
5253  | 188k  |     ret->type = XPATH_BOOLEAN;  | 
5254  | 188k  |     ret->boolval = (val != 0);  | 
5255  |  | #ifdef XP_DEBUG_OBJ_USAGE  | 
5256  |  |     xmlXPathDebugObjUsageRequested(NULL, XPATH_BOOLEAN);  | 
5257  |  | #endif  | 
5258  | 188k  |     return(ret);  | 
5259  | 188k  | }  | 
5260  |  |  | 
5261  |  | /**  | 
5262  |  |  * xmlXPathNewString:  | 
5263  |  |  * @val:  the xmlChar * value  | 
5264  |  |  *  | 
5265  |  |  * Create a new xmlXPathObjectPtr of type string and of value @val  | 
5266  |  |  *  | 
5267  |  |  * Returns the newly created object.  | 
5268  |  |  */  | 
5269  |  | xmlXPathObjectPtr  | 
5270  | 1.42M  | xmlXPathNewString(const xmlChar *val) { | 
5271  | 1.42M  |     xmlXPathObjectPtr ret;  | 
5272  |  |  | 
5273  | 1.42M  |     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));  | 
5274  | 1.42M  |     if (ret == NULL) { | 
5275  | 0  |         xmlXPathErrMemory(NULL, "creating string object\n");  | 
5276  | 0  |   return(NULL);  | 
5277  | 0  |     }  | 
5278  | 1.42M  |     memset(ret, 0 , sizeof(xmlXPathObject));  | 
5279  | 1.42M  |     ret->type = XPATH_STRING;  | 
5280  | 1.42M  |     if (val != NULL)  | 
5281  | 1.42M  |   ret->stringval = xmlStrdup(val);  | 
5282  | 226  |     else  | 
5283  | 226  |   ret->stringval = xmlStrdup((const xmlChar *)"");  | 
5284  |  | #ifdef XP_DEBUG_OBJ_USAGE  | 
5285  |  |     xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);  | 
5286  |  | #endif  | 
5287  | 1.42M  |     return(ret);  | 
5288  | 1.42M  | }  | 
5289  |  |  | 
5290  |  | /**  | 
5291  |  |  * xmlXPathWrapString:  | 
5292  |  |  * @val:  the xmlChar * value  | 
5293  |  |  *  | 
5294  |  |  * Wraps the @val string into an XPath object.  | 
5295  |  |  *  | 
5296  |  |  * Returns the newly created object.  | 
5297  |  |  */  | 
5298  |  | xmlXPathObjectPtr  | 
5299  | 334k  | xmlXPathWrapString (xmlChar *val) { | 
5300  | 334k  |     xmlXPathObjectPtr ret;  | 
5301  |  |  | 
5302  | 334k  |     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));  | 
5303  | 334k  |     if (ret == NULL) { | 
5304  | 0  |         xmlXPathErrMemory(NULL, "creating string object\n");  | 
5305  | 0  |   return(NULL);  | 
5306  | 0  |     }  | 
5307  | 334k  |     memset(ret, 0 , sizeof(xmlXPathObject));  | 
5308  | 334k  |     ret->type = XPATH_STRING;  | 
5309  | 334k  |     ret->stringval = val;  | 
5310  |  | #ifdef XP_DEBUG_OBJ_USAGE  | 
5311  |  |     xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);  | 
5312  |  | #endif  | 
5313  | 334k  |     return(ret);  | 
5314  | 334k  | }  | 
5315  |  |  | 
5316  |  | /**  | 
5317  |  |  * xmlXPathNewCString:  | 
5318  |  |  * @val:  the char * value  | 
5319  |  |  *  | 
5320  |  |  * Create a new xmlXPathObjectPtr of type string and of value @val  | 
5321  |  |  *  | 
5322  |  |  * Returns the newly created object.  | 
5323  |  |  */  | 
5324  |  | xmlXPathObjectPtr  | 
5325  | 308k  | xmlXPathNewCString(const char *val) { | 
5326  | 308k  |     xmlXPathObjectPtr ret;  | 
5327  |  |  | 
5328  | 308k  |     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));  | 
5329  | 308k  |     if (ret == NULL) { | 
5330  | 0  |         xmlXPathErrMemory(NULL, "creating string object\n");  | 
5331  | 0  |   return(NULL);  | 
5332  | 0  |     }  | 
5333  | 308k  |     memset(ret, 0 , sizeof(xmlXPathObject));  | 
5334  | 308k  |     ret->type = XPATH_STRING;  | 
5335  | 308k  |     ret->stringval = xmlStrdup(BAD_CAST val);  | 
5336  |  | #ifdef XP_DEBUG_OBJ_USAGE  | 
5337  |  |     xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);  | 
5338  |  | #endif  | 
5339  | 308k  |     return(ret);  | 
5340  | 308k  | }  | 
5341  |  |  | 
5342  |  | /**  | 
5343  |  |  * xmlXPathWrapCString:  | 
5344  |  |  * @val:  the char * value  | 
5345  |  |  *  | 
5346  |  |  * Wraps a string into an XPath object.  | 
5347  |  |  *  | 
5348  |  |  * Returns the newly created object.  | 
5349  |  |  */  | 
5350  |  | xmlXPathObjectPtr  | 
5351  | 0  | xmlXPathWrapCString (char * val) { | 
5352  | 0  |     return(xmlXPathWrapString((xmlChar *)(val)));  | 
5353  | 0  | }  | 
5354  |  |  | 
5355  |  | /**  | 
5356  |  |  * xmlXPathWrapExternal:  | 
5357  |  |  * @val:  the user data  | 
5358  |  |  *  | 
5359  |  |  * Wraps the @val data into an XPath object.  | 
5360  |  |  *  | 
5361  |  |  * Returns the newly created object.  | 
5362  |  |  */  | 
5363  |  | xmlXPathObjectPtr  | 
5364  | 5.71k  | xmlXPathWrapExternal (void *val) { | 
5365  | 5.71k  |     xmlXPathObjectPtr ret;  | 
5366  |  |  | 
5367  | 5.71k  |     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));  | 
5368  | 5.71k  |     if (ret == NULL) { | 
5369  | 0  |         xmlXPathErrMemory(NULL, "creating user object\n");  | 
5370  | 0  |   return(NULL);  | 
5371  | 0  |     }  | 
5372  | 5.71k  |     memset(ret, 0 , sizeof(xmlXPathObject));  | 
5373  | 5.71k  |     ret->type = XPATH_USERS;  | 
5374  | 5.71k  |     ret->user = val;  | 
5375  |  | #ifdef XP_DEBUG_OBJ_USAGE  | 
5376  |  |     xmlXPathDebugObjUsageRequested(NULL, XPATH_USERS);  | 
5377  |  | #endif  | 
5378  | 5.71k  |     return(ret);  | 
5379  | 5.71k  | }  | 
5380  |  |  | 
5381  |  | /**  | 
5382  |  |  * xmlXPathObjectCopy:  | 
5383  |  |  * @val:  the original object  | 
5384  |  |  *  | 
5385  |  |  * allocate a new copy of a given object  | 
5386  |  |  *  | 
5387  |  |  * Returns the newly created object.  | 
5388  |  |  */  | 
5389  |  | xmlXPathObjectPtr  | 
5390  | 140k  | xmlXPathObjectCopy(xmlXPathObjectPtr val) { | 
5391  | 140k  |     xmlXPathObjectPtr ret;  | 
5392  |  |  | 
5393  | 140k  |     if (val == NULL)  | 
5394  | 0  |   return(NULL);  | 
5395  |  |  | 
5396  | 140k  |     ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));  | 
5397  | 140k  |     if (ret == NULL) { | 
5398  | 0  |         xmlXPathErrMemory(NULL, "copying object\n");  | 
5399  | 0  |   return(NULL);  | 
5400  | 0  |     }  | 
5401  | 140k  |     memcpy(ret, val , sizeof(xmlXPathObject));  | 
5402  |  | #ifdef XP_DEBUG_OBJ_USAGE  | 
5403  |  |     xmlXPathDebugObjUsageRequested(NULL, val->type);  | 
5404  |  | #endif  | 
5405  | 140k  |     switch (val->type) { | 
5406  | 0  |   case XPATH_BOOLEAN:  | 
5407  | 0  |   case XPATH_NUMBER:  | 
5408  |  | #ifdef LIBXML_XPTR_LOCS_ENABLED  | 
5409  |  |   case XPATH_POINT:  | 
5410  |  |   case XPATH_RANGE:  | 
5411  |  | #endif /* LIBXML_XPTR_LOCS_ENABLED */  | 
5412  | 0  |       break;  | 
5413  | 666  |   case XPATH_STRING:  | 
5414  | 666  |       ret->stringval = xmlStrdup(val->stringval);  | 
5415  | 666  |       break;  | 
5416  | 0  |   case XPATH_XSLT_TREE:  | 
5417  |  | #if 0  | 
5418  |  | /*  | 
5419  |  |   Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that  | 
5420  |  |   this previous handling is no longer correct, and can cause some serious  | 
5421  |  |   problems (ref. bug 145547)  | 
5422  |  | */  | 
5423  |  |       if ((val->nodesetval != NULL) &&  | 
5424  |  |     (val->nodesetval->nodeTab != NULL)) { | 
5425  |  |     xmlNodePtr cur, tmp;  | 
5426  |  |     xmlDocPtr top;  | 
5427  |  |  | 
5428  |  |     ret->boolval = 1;  | 
5429  |  |     top =  xmlNewDoc(NULL);  | 
5430  |  |     top->name = (char *)  | 
5431  |  |         xmlStrdup(val->nodesetval->nodeTab[0]->name);  | 
5432  |  |     ret->user = top;  | 
5433  |  |     if (top != NULL) { | 
5434  |  |         top->doc = top;  | 
5435  |  |         cur = val->nodesetval->nodeTab[0]->children;  | 
5436  |  |         while (cur != NULL) { | 
5437  |  |       tmp = xmlDocCopyNode(cur, top, 1);  | 
5438  |  |       xmlAddChild((xmlNodePtr) top, tmp);  | 
5439  |  |       cur = cur->next;  | 
5440  |  |         }  | 
5441  |  |     }  | 
5442  |  |  | 
5443  |  |     ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);  | 
5444  |  |       } else  | 
5445  |  |     ret->nodesetval = xmlXPathNodeSetCreate(NULL);  | 
5446  |  |       /* Deallocate the copied tree value */  | 
5447  |  |       break;  | 
5448  |  | #endif  | 
5449  | 139k  |   case XPATH_NODESET:  | 
5450  |  |             /* TODO: Check memory error. */  | 
5451  | 139k  |       ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);  | 
5452  |  |       /* Do not deallocate the copied tree value */  | 
5453  | 139k  |       ret->boolval = 0;  | 
5454  | 139k  |       break;  | 
5455  |  | #ifdef LIBXML_XPTR_LOCS_ENABLED  | 
5456  |  |   case XPATH_LOCATIONSET:  | 
5457  |  |   { | 
5458  |  |       xmlLocationSetPtr loc = val->user;  | 
5459  |  |       ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);  | 
5460  |  |       break;  | 
5461  |  |   }  | 
5462  |  | #endif  | 
5463  | 0  |         case XPATH_USERS:  | 
5464  | 0  |       ret->user = val->user;  | 
5465  | 0  |       break;  | 
5466  | 0  |         case XPATH_UNDEFINED:  | 
5467  | 0  |       xmlGenericError(xmlGenericErrorContext,  | 
5468  | 0  |         "xmlXPathObjectCopy: unsupported type %d\n",  | 
5469  | 0  |         val->type);  | 
5470  | 0  |       break;  | 
5471  | 140k  |     }  | 
5472  | 140k  |     return(ret);  | 
5473  | 140k  | }  | 
5474  |  |  | 
5475  |  | /**  | 
5476  |  |  * xmlXPathFreeObject:  | 
5477  |  |  * @obj:  the object to free  | 
5478  |  |  *  | 
5479  |  |  * Free up an xmlXPathObjectPtr object.  | 
5480  |  |  */  | 
5481  |  | void  | 
5482  | 11.8M  | xmlXPathFreeObject(xmlXPathObjectPtr obj) { | 
5483  | 11.8M  |     if (obj == NULL) return;  | 
5484  | 11.5M  |     if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) { | 
5485  | 5.28M  |   if (obj->boolval) { | 
5486  |  | #if 0  | 
5487  |  |       if (obj->user != NULL) { | 
5488  |  |                 xmlXPathFreeNodeSet(obj->nodesetval);  | 
5489  |  |     xmlFreeNodeList((xmlNodePtr) obj->user);  | 
5490  |  |       } else  | 
5491  |  | #endif  | 
5492  | 0  |       obj->type = XPATH_XSLT_TREE; /* TODO: Just for debugging. */  | 
5493  | 0  |       if (obj->nodesetval != NULL)  | 
5494  | 0  |     xmlXPathFreeValueTree(obj->nodesetval);  | 
5495  | 5.28M  |   } else { | 
5496  | 5.28M  |       if (obj->nodesetval != NULL)  | 
5497  | 4.73M  |     xmlXPathFreeNodeSet(obj->nodesetval);  | 
5498  | 5.28M  |   }  | 
5499  |  | #ifdef LIBXML_XPTR_LOCS_ENABLED  | 
5500  |  |     } else if (obj->type == XPATH_LOCATIONSET) { | 
5501  |  |   if (obj->user != NULL)  | 
5502  |  |       xmlXPtrFreeLocationSet(obj->user);  | 
5503  |  | #endif  | 
5504  | 6.25M  |     } else if (obj->type == XPATH_STRING) { | 
5505  | 4.12M  |   if (obj->stringval != NULL)  | 
5506  | 4.12M  |       xmlFree(obj->stringval);  | 
5507  | 4.12M  |     }  | 
5508  |  | #ifdef XP_DEBUG_OBJ_USAGE  | 
5509  |  |     xmlXPathDebugObjUsageReleased(NULL, obj->type);  | 
5510  |  | #endif  | 
5511  | 11.5M  |     xmlFree(obj);  | 
5512  | 11.5M  | }  | 
5513  |  |  | 
5514  |  | static void  | 
5515  | 0  | xmlXPathFreeObjectEntry(void *obj, const xmlChar *name ATTRIBUTE_UNUSED) { | 
5516  | 0  |     xmlXPathFreeObject((xmlXPathObjectPtr) obj);  | 
5517  | 0  | }  | 
5518  |  |  | 
5519  |  | /**  | 
5520  |  |  * xmlXPathReleaseObject:  | 
5521  |  |  * @obj:  the xmlXPathObjectPtr to free or to cache  | 
5522  |  |  *  | 
5523  |  |  * Depending on the state of the cache this frees the given  | 
5524  |  |  * XPath object or stores it in the cache.  | 
5525  |  |  */  | 
5526  |  | static void  | 
5527  |  | xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj)  | 
5528  | 79.9M  | { | 
5529  | 79.9M  | #define XP_CACHE_ADD(sl, o) if (sl == NULL) { \ | 
5530  | 378k  |   sl = xmlPointerListCreate(10); if (sl == NULL) goto free_obj; } \  | 
5531  | 79.6M  |     if (xmlPointerListAddSize(sl, obj, 0) == -1) goto free_obj;  | 
5532  |  |  | 
5533  | 98.3M  | #define XP_CACHE_WANTS(sl, n) ((sl == NULL) || ((sl)->number < n))  | 
5534  |  |  | 
5535  | 79.9M  |     if (obj == NULL)  | 
5536  | 0  |   return;  | 
5537  | 79.9M  |     if ((ctxt == NULL) || (ctxt->cache == NULL)) { | 
5538  | 9.92k  |    xmlXPathFreeObject(obj);  | 
5539  | 79.8M  |     } else { | 
5540  | 79.8M  |   xmlXPathContextCachePtr cache =  | 
5541  | 79.8M  |       (xmlXPathContextCachePtr) ctxt->cache;  | 
5542  |  |  | 
5543  | 79.8M  |   switch (obj->type) { | 
5544  | 48.4M  |       case XPATH_NODESET:  | 
5545  | 48.4M  |       case XPATH_XSLT_TREE:  | 
5546  | 48.4M  |     if (obj->nodesetval != NULL) { | 
5547  | 42.7M  |         if (obj->boolval) { | 
5548  |  |       /*  | 
5549  |  |       * It looks like the @boolval is used for  | 
5550  |  |       * evaluation if this an XSLT Result Tree Fragment.  | 
5551  |  |       * TODO: Check if this assumption is correct.  | 
5552  |  |       */  | 
5553  | 0  |       obj->type = XPATH_XSLT_TREE; /* just for debugging */  | 
5554  | 0  |       xmlXPathFreeValueTree(obj->nodesetval);  | 
5555  | 0  |       obj->nodesetval = NULL;  | 
5556  | 42.7M  |         } else if ((obj->nodesetval->nodeMax <= 40) &&  | 
5557  | 42.7M  |       (XP_CACHE_WANTS(cache->nodesetObjs,  | 
5558  | 42.7M  |           cache->maxNodeset)))  | 
5559  | 24.4M  |         { | 
5560  | 24.4M  |       XP_CACHE_ADD(cache->nodesetObjs, obj);  | 
5561  | 24.4M  |       goto obj_cached;  | 
5562  | 24.4M  |         } else { | 
5563  | 18.2M  |       xmlXPathFreeNodeSet(obj->nodesetval);  | 
5564  | 18.2M  |       obj->nodesetval = NULL;  | 
5565  | 18.2M  |         }  | 
5566  | 42.7M  |     }  | 
5567  | 23.9M  |     break;  | 
5568  | 23.9M  |       case XPATH_STRING:  | 
5569  | 5.40M  |     if (obj->stringval != NULL)  | 
5570  | 5.40M  |         xmlFree(obj->stringval);  | 
5571  |  |  | 
5572  | 5.40M  |     if (XP_CACHE_WANTS(cache->stringObjs, cache->maxString)) { | 
5573  | 5.28M  |         XP_CACHE_ADD(cache->stringObjs, obj);  | 
5574  | 5.28M  |         goto obj_cached;  | 
5575  | 5.28M  |     }  | 
5576  | 121k  |     break;  | 
5577  | 10.1M  |       case XPATH_BOOLEAN:  | 
5578  | 10.1M  |     if (XP_CACHE_WANTS(cache->booleanObjs, cache->maxBoolean)) { | 
5579  | 10.1M  |         XP_CACHE_ADD(cache->booleanObjs, obj);  | 
5580  | 10.1M  |         goto obj_cached;  | 
5581  | 10.1M  |     }  | 
5582  | 4.98k  |     break;  | 
5583  | 15.9M  |       case XPATH_NUMBER:  | 
5584  | 15.9M  |     if (XP_CACHE_WANTS(cache->numberObjs, cache->maxNumber)) { | 
5585  | 15.8M  |         XP_CACHE_ADD(cache->numberObjs, obj);  | 
5586  | 15.8M  |         goto obj_cached;  | 
5587  | 15.8M  |     }  | 
5588  | 61.5k  |     break;  | 
5589  |  | #ifdef LIBXML_XPTR_LOCS_ENABLED  | 
5590  |  |       case XPATH_LOCATIONSET:  | 
5591  |  |     if (obj->user != NULL) { | 
5592  |  |         xmlXPtrFreeLocationSet(obj->user);  | 
5593  |  |     }  | 
5594  |  |     goto free_obj;  | 
5595  |  | #endif  | 
5596  | 61.5k  |       default:  | 
5597  | 5.71k  |     goto free_obj;  | 
5598  | 79.8M  |   }  | 
5599  |  |  | 
5600  |  |   /*  | 
5601  |  |   * Fallback to adding to the misc-objects slot.  | 
5602  |  |   */  | 
5603  | 24.1M  |   if (XP_CACHE_WANTS(cache->miscObjs, cache->maxMisc)) { | 
5604  | 23.9M  |       XP_CACHE_ADD(cache->miscObjs, obj);  | 
5605  | 23.9M  |   } else  | 
5606  | 238k  |       goto free_obj;  | 
5607  |  |  | 
5608  | 79.6M  | obj_cached:  | 
5609  |  |  | 
5610  |  | #ifdef XP_DEBUG_OBJ_USAGE  | 
5611  |  |   xmlXPathDebugObjUsageReleased(ctxt, obj->type);  | 
5612  |  | #endif  | 
5613  |  |  | 
5614  | 79.6M  |   if (obj->nodesetval != NULL) { | 
5615  | 24.4M  |       xmlNodeSetPtr tmpset = obj->nodesetval;  | 
5616  |  |  | 
5617  |  |       /*  | 
5618  |  |       * TODO: Due to those nasty ns-nodes, we need to traverse  | 
5619  |  |       *  the list and free the ns-nodes.  | 
5620  |  |       * URGENT TODO: Check if it's actually slowing things down.  | 
5621  |  |       *  Maybe we shouldn't try to preserve the list.  | 
5622  |  |       */  | 
5623  | 24.4M  |       if (tmpset->nodeNr > 1) { | 
5624  | 882k  |     int i;  | 
5625  | 882k  |     xmlNodePtr node;  | 
5626  |  |  | 
5627  | 15.7M  |     for (i = 0; i < tmpset->nodeNr; i++) { | 
5628  | 14.8M  |         node = tmpset->nodeTab[i];  | 
5629  | 14.8M  |         if ((node != NULL) &&  | 
5630  | 14.8M  |       (node->type == XML_NAMESPACE_DECL))  | 
5631  | 273k  |         { | 
5632  | 273k  |       xmlXPathNodeSetFreeNs((xmlNsPtr) node);  | 
5633  | 273k  |         }  | 
5634  | 14.8M  |     }  | 
5635  | 23.6M  |       } else if (tmpset->nodeNr == 1) { | 
5636  | 20.5M  |     if ((tmpset->nodeTab[0] != NULL) &&  | 
5637  | 20.5M  |         (tmpset->nodeTab[0]->type == XML_NAMESPACE_DECL))  | 
5638  | 499k  |         xmlXPathNodeSetFreeNs((xmlNsPtr) tmpset->nodeTab[0]);  | 
5639  | 20.5M  |       }  | 
5640  | 24.4M  |       tmpset->nodeNr = 0;  | 
5641  | 24.4M  |       memset(obj, 0, sizeof(xmlXPathObject));  | 
5642  | 24.4M  |       obj->nodesetval = tmpset;  | 
5643  | 24.4M  |   } else  | 
5644  | 55.1M  |       memset(obj, 0, sizeof(xmlXPathObject));  | 
5645  |  |  | 
5646  | 79.6M  |   return;  | 
5647  |  |  | 
5648  | 244k  | free_obj:  | 
5649  |  |   /*  | 
5650  |  |   * Cache is full; free the object.  | 
5651  |  |   */  | 
5652  | 244k  |   if (obj->nodesetval != NULL)  | 
5653  | 0  |       xmlXPathFreeNodeSet(obj->nodesetval);  | 
5654  |  | #ifdef XP_DEBUG_OBJ_USAGE  | 
5655  |  |   xmlXPathDebugObjUsageReleased(NULL, obj->type);  | 
5656  |  | #endif  | 
5657  | 244k  |   xmlFree(obj);  | 
5658  | 244k  |     }  | 
5659  | 254k  |     return;  | 
5660  | 79.9M  | }  | 
5661  |  |  | 
5662  |  |  | 
5663  |  | /************************************************************************  | 
5664  |  |  *                  *  | 
5665  |  |  *      Type Casting Routines       *  | 
5666  |  |  *                  *  | 
5667  |  |  ************************************************************************/  | 
5668  |  |  | 
5669  |  | /**  | 
5670  |  |  * xmlXPathCastBooleanToString:  | 
5671  |  |  * @val:  a boolean  | 
5672  |  |  *  | 
5673  |  |  * Converts a boolean to its string value.  | 
5674  |  |  *  | 
5675  |  |  * Returns a newly allocated string.  | 
5676  |  |  */  | 
5677  |  | xmlChar *  | 
5678  | 67.0k  | xmlXPathCastBooleanToString (int val) { | 
5679  | 67.0k  |     xmlChar *ret;  | 
5680  | 67.0k  |     if (val)  | 
5681  | 20.9k  |   ret = xmlStrdup((const xmlChar *) "true");  | 
5682  | 46.1k  |     else  | 
5683  | 46.1k  |   ret = xmlStrdup((const xmlChar *) "false");  | 
5684  | 67.0k  |     return(ret);  | 
5685  | 67.0k  | }  | 
5686  |  |  | 
5687  |  | /**  | 
5688  |  |  * xmlXPathCastNumberToString:  | 
5689  |  |  * @val:  a number  | 
5690  |  |  *  | 
5691  |  |  * Converts a number to its string value.  | 
5692  |  |  *  | 
5693  |  |  * Returns a newly allocated string.  | 
5694  |  |  */  | 
5695  |  | xmlChar *  | 
5696  | 637k  | xmlXPathCastNumberToString (double val) { | 
5697  | 637k  |     xmlChar *ret;  | 
5698  | 637k  |     switch (xmlXPathIsInf(val)) { | 
5699  | 4.67k  |     case 1:  | 
5700  | 4.67k  |   ret = xmlStrdup((const xmlChar *) "Infinity");  | 
5701  | 4.67k  |   break;  | 
5702  | 2.60k  |     case -1:  | 
5703  | 2.60k  |   ret = xmlStrdup((const xmlChar *) "-Infinity");  | 
5704  | 2.60k  |   break;  | 
5705  | 629k  |     default:  | 
5706  | 629k  |   if (xmlXPathIsNaN(val)) { | 
5707  | 215k  |       ret = xmlStrdup((const xmlChar *) "NaN");  | 
5708  | 414k  |   } else if (val == 0) { | 
5709  |  |             /* Omit sign for negative zero. */  | 
5710  | 18.3k  |       ret = xmlStrdup((const xmlChar *) "0");  | 
5711  | 395k  |   } else { | 
5712  |  |       /* could be improved */  | 
5713  | 395k  |       char buf[100];  | 
5714  | 395k  |       xmlXPathFormatNumber(val, buf, 99);  | 
5715  | 395k  |       buf[99] = 0;  | 
5716  | 395k  |       ret = xmlStrdup((const xmlChar *) buf);  | 
5717  | 395k  |   }  | 
5718  | 637k  |     }  | 
5719  | 637k  |     return(ret);  | 
5720  | 637k  | }  | 
5721  |  |  | 
5722  |  | /**  | 
5723  |  |  * xmlXPathCastNodeToString:  | 
5724  |  |  * @node:  a node  | 
5725  |  |  *  | 
5726  |  |  * Converts a node to its string value.  | 
5727  |  |  *  | 
5728  |  |  * Returns a newly allocated string.  | 
5729  |  |  */  | 
5730  |  | xmlChar *  | 
5731  | 7.12M  | xmlXPathCastNodeToString (xmlNodePtr node) { | 
5732  | 7.12M  | xmlChar *ret;  | 
5733  | 7.12M  |     if ((ret = xmlNodeGetContent(node)) == NULL)  | 
5734  | 0  |   ret = xmlStrdup((const xmlChar *) "");  | 
5735  | 7.12M  |     return(ret);  | 
5736  | 7.12M  | }  | 
5737  |  |  | 
5738  |  | /**  | 
5739  |  |  * xmlXPathCastNodeSetToString:  | 
5740  |  |  * @ns:  a node-set  | 
5741  |  |  *  | 
5742  |  |  * Converts a node-set to its string value.  | 
5743  |  |  *  | 
5744  |  |  * Returns a newly allocated string.  | 
5745  |  |  */  | 
5746  |  | xmlChar *  | 
5747  | 9.30M  | xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) { | 
5748  | 9.30M  |     if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))  | 
5749  | 6.27M  |   return(xmlStrdup((const xmlChar *) ""));  | 
5750  |  |  | 
5751  | 3.02M  |     if (ns->nodeNr > 1)  | 
5752  | 1.22M  |   xmlXPathNodeSetSort(ns);  | 
5753  | 3.02M  |     return(xmlXPathCastNodeToString(ns->nodeTab[0]));  | 
5754  | 9.30M  | }  | 
5755  |  |  | 
5756  |  | /**  | 
5757  |  |  * xmlXPathCastToString:  | 
5758  |  |  * @val:  an XPath object  | 
5759  |  |  *  | 
5760  |  |  * Converts an existing object to its string() equivalent  | 
5761  |  |  *  | 
5762  |  |  * Returns the allocated string value of the object, NULL in case of error.  | 
5763  |  |  *         It's up to the caller to free the string memory with xmlFree().  | 
5764  |  |  */  | 
5765  |  | xmlChar *  | 
5766  | 1.93M  | xmlXPathCastToString(xmlXPathObjectPtr val) { | 
5767  | 1.93M  |     xmlChar *ret = NULL;  | 
5768  |  |  | 
5769  | 1.93M  |     if (val == NULL)  | 
5770  | 0  |   return(xmlStrdup((const xmlChar *) ""));  | 
5771  | 1.93M  |     switch (val->type) { | 
5772  | 0  |   case XPATH_UNDEFINED:  | 
5773  |  | #ifdef DEBUG_EXPR  | 
5774  |  |       xmlGenericError(xmlGenericErrorContext, "String: undefined\n");  | 
5775  |  | #endif  | 
5776  | 0  |       ret = xmlStrdup((const xmlChar *) "");  | 
5777  | 0  |       break;  | 
5778  | 22.0k  |         case XPATH_NODESET:  | 
5779  | 22.0k  |         case XPATH_XSLT_TREE:  | 
5780  | 22.0k  |       ret = xmlXPathCastNodeSetToString(val->nodesetval);  | 
5781  | 22.0k  |       break;  | 
5782  | 1.73M  |   case XPATH_STRING:  | 
5783  | 1.73M  |       return(xmlStrdup(val->stringval));  | 
5784  | 28.3k  |         case XPATH_BOOLEAN:  | 
5785  | 28.3k  |       ret = xmlXPathCastBooleanToString(val->boolval);  | 
5786  | 28.3k  |       break;  | 
5787  | 151k  |   case XPATH_NUMBER: { | 
5788  | 151k  |       ret = xmlXPathCastNumberToString(val->floatval);  | 
5789  | 151k  |       break;  | 
5790  | 22.0k  |   }  | 
5791  | 0  |   case XPATH_USERS:  | 
5792  |  | #ifdef LIBXML_XPTR_LOCS_ENABLED  | 
5793  |  |   case XPATH_POINT:  | 
5794  |  |   case XPATH_RANGE:  | 
5795  |  |   case XPATH_LOCATIONSET:  | 
5796  |  | #endif /* LIBXML_XPTR_LOCS_ENABLED */  | 
5797  | 0  |       TODO  | 
5798  | 0  |       ret = xmlStrdup((const xmlChar *) "");  | 
5799  | 0  |       break;  | 
5800  | 1.93M  |     }  | 
5801  | 202k  |     return(ret);  | 
5802  | 1.93M  | }  | 
5803  |  |  | 
5804  |  | /**  | 
5805  |  |  * xmlXPathConvertString:  | 
5806  |  |  * @val:  an XPath object  | 
5807  |  |  *  | 
5808  |  |  * Converts an existing object to its string() equivalent  | 
5809  |  |  *  | 
5810  |  |  * Returns the new object, the old one is freed (or the operation  | 
5811  |  |  *         is done directly on @val)  | 
5812  |  |  */  | 
5813  |  | xmlXPathObjectPtr  | 
5814  | 945  | xmlXPathConvertString(xmlXPathObjectPtr val) { | 
5815  | 945  |     xmlChar *res = NULL;  | 
5816  |  |  | 
5817  | 945  |     if (val == NULL)  | 
5818  | 0  |   return(xmlXPathNewCString("")); | 
5819  |  |  | 
5820  | 945  |     switch (val->type) { | 
5821  | 0  |     case XPATH_UNDEFINED:  | 
5822  |  | #ifdef DEBUG_EXPR  | 
5823  |  |   xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");  | 
5824  |  | #endif  | 
5825  | 0  |   break;  | 
5826  | 403  |     case XPATH_NODESET:  | 
5827  | 403  |     case XPATH_XSLT_TREE:  | 
5828  | 403  |   res = xmlXPathCastNodeSetToString(val->nodesetval);  | 
5829  | 403  |   break;  | 
5830  | 0  |     case XPATH_STRING:  | 
5831  | 0  |   return(val);  | 
5832  | 376  |     case XPATH_BOOLEAN:  | 
5833  | 376  |   res = xmlXPathCastBooleanToString(val->boolval);  | 
5834  | 376  |   break;  | 
5835  | 166  |     case XPATH_NUMBER:  | 
5836  | 166  |   res = xmlXPathCastNumberToString(val->floatval);  | 
5837  | 166  |   break;  | 
5838  | 0  |     case XPATH_USERS:  | 
5839  |  | #ifdef LIBXML_XPTR_LOCS_ENABLED  | 
5840  |  |     case XPATH_POINT:  | 
5841  |  |     case XPATH_RANGE:  | 
5842  |  |     case XPATH_LOCATIONSET:  | 
5843  |  | #endif /* LIBXML_XPTR_LOCS_ENABLED */  | 
5844  | 0  |   TODO;  | 
5845  | 0  |   break;  | 
5846  | 945  |     }  | 
5847  | 945  |     xmlXPathFreeObject(val);  | 
5848  | 945  |     if (res == NULL)  | 
5849  | 0  |   return(xmlXPathNewCString("")); | 
5850  | 945  |     return(xmlXPathWrapString(res));  | 
5851  | 945  | }  | 
5852  |  |  | 
5853  |  | /**  | 
5854  |  |  * xmlXPathCastBooleanToNumber:  | 
5855  |  |  * @val:  a boolean  | 
5856  |  |  *  | 
5857  |  |  * Converts a boolean to its number value  | 
5858  |  |  *  | 
5859  |  |  * Returns the number value  | 
5860  |  |  */  | 
5861  |  | double  | 
5862  | 2.98M  | xmlXPathCastBooleanToNumber(int val) { | 
5863  | 2.98M  |     if (val)  | 
5864  | 681k  |   return(1.0);  | 
5865  | 2.30M  |     return(0.0);  | 
5866  | 2.98M  | }  | 
5867  |  |  | 
5868  |  | /**  | 
5869  |  |  * xmlXPathCastStringToNumber:  | 
5870  |  |  * @val:  a string  | 
5871  |  |  *  | 
5872  |  |  * Converts a string to its number value  | 
5873  |  |  *  | 
5874  |  |  * Returns the number value  | 
5875  |  |  */  | 
5876  |  | double  | 
5877  | 13.0M  | xmlXPathCastStringToNumber(const xmlChar * val) { | 
5878  | 13.0M  |     return(xmlXPathStringEvalNumber(val));  | 
5879  | 13.0M  | }  | 
5880  |  |  | 
5881  |  | /**  | 
5882  |  |  * xmlXPathCastNodeToNumber:  | 
5883  |  |  * @node:  a node  | 
5884  |  |  *  | 
5885  |  |  * Converts a node to its number value  | 
5886  |  |  *  | 
5887  |  |  * Returns the number value  | 
5888  |  |  */  | 
5889  |  | double  | 
5890  | 1.96M  | xmlXPathCastNodeToNumber (xmlNodePtr node) { | 
5891  | 1.96M  |     xmlChar *strval;  | 
5892  | 1.96M  |     double ret;  | 
5893  |  |  | 
5894  | 1.96M  |     if (node == NULL)  | 
5895  | 0  |   return(xmlXPathNAN);  | 
5896  | 1.96M  |     strval = xmlXPathCastNodeToString(node);  | 
5897  | 1.96M  |     if (strval == NULL)  | 
5898  | 0  |   return(xmlXPathNAN);  | 
5899  | 1.96M  |     ret = xmlXPathCastStringToNumber(strval);  | 
5900  | 1.96M  |     xmlFree(strval);  | 
5901  |  |  | 
5902  | 1.96M  |     return(ret);  | 
5903  | 1.96M  | }  | 
5904  |  |  | 
5905  |  | /**  | 
5906  |  |  * xmlXPathCastNodeSetToNumber:  | 
5907  |  |  * @ns:  a node-set  | 
5908  |  |  *  | 
5909  |  |  * Converts a node-set to its number value  | 
5910  |  |  *  | 
5911  |  |  * Returns the number value  | 
5912  |  |  */  | 
5913  |  | double  | 
5914  | 8.68M  | xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) { | 
5915  | 8.68M  |     xmlChar *str;  | 
5916  | 8.68M  |     double ret;  | 
5917  |  |  | 
5918  | 8.68M  |     if (ns == NULL)  | 
5919  | 570k  |   return(xmlXPathNAN);  | 
5920  | 8.11M  |     str = xmlXPathCastNodeSetToString(ns);  | 
5921  | 8.11M  |     ret = xmlXPathCastStringToNumber(str);  | 
5922  | 8.11M  |     xmlFree(str);  | 
5923  | 8.11M  |     return(ret);  | 
5924  | 8.68M  | }  | 
5925  |  |  | 
5926  |  | /**  | 
5927  |  |  * xmlXPathCastToNumber:  | 
5928  |  |  * @val:  an XPath object  | 
5929  |  |  *  | 
5930  |  |  * Converts an XPath object to its number value  | 
5931  |  |  *  | 
5932  |  |  * Returns the number value  | 
5933  |  |  */  | 
5934  |  | double  | 
5935  | 17.8M  | xmlXPathCastToNumber(xmlXPathObjectPtr val) { | 
5936  | 17.8M  |     double ret = 0.0;  | 
5937  |  |  | 
5938  | 17.8M  |     if (val == NULL)  | 
5939  | 0  |   return(xmlXPathNAN);  | 
5940  | 17.8M  |     switch (val->type) { | 
5941  | 0  |     case XPATH_UNDEFINED:  | 
5942  |  | #ifdef DEBUG_EXPR  | 
5943  |  |   xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");  | 
5944  |  | #endif  | 
5945  | 0  |   ret = xmlXPathNAN;  | 
5946  | 0  |   break;  | 
5947  | 8.68M  |     case XPATH_NODESET:  | 
5948  | 8.68M  |     case XPATH_XSLT_TREE:  | 
5949  | 8.68M  |   ret = xmlXPathCastNodeSetToNumber(val->nodesetval);  | 
5950  | 8.68M  |   break;  | 
5951  | 2.98M  |     case XPATH_STRING:  | 
5952  | 2.98M  |   ret = xmlXPathCastStringToNumber(val->stringval);  | 
5953  | 2.98M  |   break;  | 
5954  | 3.13M  |     case XPATH_NUMBER:  | 
5955  | 3.13M  |   ret = val->floatval;  | 
5956  | 3.13M  |   break;  | 
5957  | 2.98M  |     case XPATH_BOOLEAN:  | 
5958  | 2.98M  |   ret = xmlXPathCastBooleanToNumber(val->boolval);  | 
5959  | 2.98M  |   break;  | 
5960  | 212  |     case XPATH_USERS:  | 
5961  |  | #ifdef LIBXML_XPTR_LOCS_ENABLED  | 
5962  |  |     case XPATH_POINT:  | 
5963  |  |     case XPATH_RANGE:  | 
5964  |  |     case XPATH_LOCATIONSET:  | 
5965  |  | #endif /* LIBXML_XPTR_LOCS_ENABLED */  | 
5966  | 212  |   TODO;  | 
5967  | 212  |   ret = xmlXPathNAN;  | 
5968  | 212  |   break;  | 
5969  | 17.8M  |     }  | 
5970  | 17.8M  |     return(ret);  | 
5971  | 17.8M  | }  | 
5972  |  |  | 
5973  |  | /**  | 
5974  |  |  * xmlXPathConvertNumber:  | 
5975  |  |  * @val:  an XPath object  | 
5976  |  |  *  | 
5977  |  |  * Converts an existing object to its number() equivalent  | 
5978  |  |  *  | 
5979  |  |  * Returns the new object, the old one is freed (or the operation  | 
5980  |  |  *         is done directly on @val)  | 
5981  |  |  */  | 
5982  |  | xmlXPathObjectPtr  | 
5983  | 0  | xmlXPathConvertNumber(xmlXPathObjectPtr val) { | 
5984  | 0  |     xmlXPathObjectPtr ret;  | 
5985  |  | 
  | 
5986  | 0  |     if (val == NULL)  | 
5987  | 0  |   return(xmlXPathNewFloat(0.0));  | 
5988  | 0  |     if (val->type == XPATH_NUMBER)  | 
5989  | 0  |   return(val);  | 
5990  | 0  |     ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));  | 
5991  | 0  |     xmlXPathFreeObject(val);  | 
5992  | 0  |     return(ret);  | 
5993  | 0  | }  | 
5994  |  |  | 
5995  |  | /**  | 
5996  |  |  * xmlXPathCastNumberToBoolean:  | 
5997  |  |  * @val:  a number  | 
5998  |  |  *  | 
5999  |  |  * Converts a number to its boolean value  | 
6000  |  |  *  | 
6001  |  |  * Returns the boolean value  | 
6002  |  |  */  | 
6003  |  | int  | 
6004  | 1.39M  | xmlXPathCastNumberToBoolean (double val) { | 
6005  | 1.39M  |      if (xmlXPathIsNaN(val) || (val == 0.0))  | 
6006  | 626k  |    return(0);  | 
6007  | 767k  |      return(1);  | 
6008  | 1.39M  | }  | 
6009  |  |  | 
6010  |  | /**  | 
6011  |  |  * xmlXPathCastStringToBoolean:  | 
6012  |  |  * @val:  a string  | 
6013  |  |  *  | 
6014  |  |  * Converts a string to its boolean value  | 
6015  |  |  *  | 
6016  |  |  * Returns the boolean value  | 
6017  |  |  */  | 
6018  |  | int  | 
6019  | 11.2k  | xmlXPathCastStringToBoolean (const xmlChar *val) { | 
6020  | 11.2k  |     if ((val == NULL) || (xmlStrlen(val) == 0))  | 
6021  | 581  |   return(0);  | 
6022  | 10.6k  |     return(1);  | 
6023  | 11.2k  | }  | 
6024  |  |  | 
6025  |  | /**  | 
6026  |  |  * xmlXPathCastNodeSetToBoolean:  | 
6027  |  |  * @ns:  a node-set  | 
6028  |  |  *  | 
6029  |  |  * Converts a node-set to its boolean value  | 
6030  |  |  *  | 
6031  |  |  * Returns the boolean value  | 
6032  |  |  */  | 
6033  |  | int  | 
6034  | 1.27M  | xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) { | 
6035  | 1.27M  |     if ((ns == NULL) || (ns->nodeNr == 0))  | 
6036  | 994k  |   return(0);  | 
6037  | 283k  |     return(1);  | 
6038  | 1.27M  | }  | 
6039  |  |  | 
6040  |  | /**  | 
6041  |  |  * xmlXPathCastToBoolean:  | 
6042  |  |  * @val:  an XPath object  | 
6043  |  |  *  | 
6044  |  |  * Converts an XPath object to its boolean value  | 
6045  |  |  *  | 
6046  |  |  * Returns the boolean value  | 
6047  |  |  */  | 
6048  |  | int  | 
6049  | 1.74M  | xmlXPathCastToBoolean (xmlXPathObjectPtr val) { | 
6050  | 1.74M  |     int ret = 0;  | 
6051  |  |  | 
6052  | 1.74M  |     if (val == NULL)  | 
6053  | 0  |   return(0);  | 
6054  | 1.74M  |     switch (val->type) { | 
6055  | 0  |     case XPATH_UNDEFINED:  | 
6056  |  | #ifdef DEBUG_EXPR  | 
6057  |  |   xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");  | 
6058  |  | #endif  | 
6059  | 0  |   ret = 0;  | 
6060  | 0  |   break;  | 
6061  | 1.27M  |     case XPATH_NODESET:  | 
6062  | 1.27M  |     case XPATH_XSLT_TREE:  | 
6063  | 1.27M  |   ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);  | 
6064  | 1.27M  |   break;  | 
6065  | 11.2k  |     case XPATH_STRING:  | 
6066  | 11.2k  |   ret = xmlXPathCastStringToBoolean(val->stringval);  | 
6067  | 11.2k  |   break;  | 
6068  | 454k  |     case XPATH_NUMBER:  | 
6069  | 454k  |   ret = xmlXPathCastNumberToBoolean(val->floatval);  | 
6070  | 454k  |   break;  | 
6071  | 0  |     case XPATH_BOOLEAN:  | 
6072  | 0  |   ret = val->boolval;  | 
6073  | 0  |   break;  | 
6074  | 102  |     case XPATH_USERS:  | 
6075  |  | #ifdef LIBXML_XPTR_LOCS_ENABLED  | 
6076  |  |     case XPATH_POINT:  | 
6077  |  |     case XPATH_RANGE:  | 
6078  |  |     case XPATH_LOCATIONSET:  | 
6079  |  | #endif /* LIBXML_XPTR_LOCS_ENABLED */  | 
6080  | 102  |   TODO;  | 
6081  | 102  |   ret = 0;  | 
6082  | 102  |   break;  | 
6083  | 1.74M  |     }  | 
6084  | 1.74M  |     return(ret);  | 
6085  | 1.74M  | }  | 
6086  |  |  | 
6087  |  |  | 
6088  |  | /**  | 
6089  |  |  * xmlXPathConvertBoolean:  | 
6090  |  |  * @val:  an XPath object  | 
6091  |  |  *  | 
6092  |  |  * Converts an existing object to its boolean() equivalent  | 
6093  |  |  *  | 
6094  |  |  * Returns the new object, the old one is freed (or the operation  | 
6095  |  |  *         is done directly on @val)  | 
6096  |  |  */  | 
6097  |  | xmlXPathObjectPtr  | 
6098  | 0  | xmlXPathConvertBoolean(xmlXPathObjectPtr val) { | 
6099  | 0  |     xmlXPathObjectPtr ret;  | 
6100  |  | 
  | 
6101  | 0  |     if (val == NULL)  | 
6102  | 0  |   return(xmlXPathNewBoolean(0));  | 
6103  | 0  |     if (val->type == XPATH_BOOLEAN)  | 
6104  | 0  |   return(val);  | 
6105  | 0  |     ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));  | 
6106  | 0  |     xmlXPathFreeObject(val);  | 
6107  | 0  |     return(ret);  | 
6108  | 0  | }  | 
6109  |  |  | 
6110  |  | /************************************************************************  | 
6111  |  |  *                  *  | 
6112  |  |  *    Routines to handle XPath contexts     *  | 
6113  |  |  *                  *  | 
6114  |  |  ************************************************************************/  | 
6115  |  |  | 
6116  |  | /**  | 
6117  |  |  * xmlXPathNewContext:  | 
6118  |  |  * @doc:  the XML document  | 
6119  |  |  *  | 
6120  |  |  * Create a new xmlXPathContext  | 
6121  |  |  *  | 
6122  |  |  * Returns the xmlXPathContext just allocated. The caller will need to free it.  | 
6123  |  |  */  | 
6124  |  | xmlXPathContextPtr  | 
6125  | 71.1k  | xmlXPathNewContext(xmlDocPtr doc) { | 
6126  | 71.1k  |     xmlXPathContextPtr ret;  | 
6127  |  |  | 
6128  | 71.1k  |     ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));  | 
6129  | 71.1k  |     if (ret == NULL) { | 
6130  | 0  |         xmlXPathErrMemory(NULL, "creating context\n");  | 
6131  | 0  |   return(NULL);  | 
6132  | 0  |     }  | 
6133  | 71.1k  |     memset(ret, 0 , sizeof(xmlXPathContext));  | 
6134  | 71.1k  |     ret->doc = doc;  | 
6135  | 71.1k  |     ret->node = NULL;  | 
6136  |  |  | 
6137  | 71.1k  |     ret->varHash = NULL;  | 
6138  |  |  | 
6139  | 71.1k  |     ret->nb_types = 0;  | 
6140  | 71.1k  |     ret->max_types = 0;  | 
6141  | 71.1k  |     ret->types = NULL;  | 
6142  |  |  | 
6143  | 71.1k  |     ret->funcHash = xmlHashCreate(0);  | 
6144  |  |  | 
6145  | 71.1k  |     ret->nb_axis = 0;  | 
6146  | 71.1k  |     ret->max_axis = 0;  | 
6147  | 71.1k  |     ret->axis = NULL;  | 
6148  |  |  | 
6149  | 71.1k  |     ret->nsHash = NULL;  | 
6150  | 71.1k  |     ret->user = NULL;  | 
6151  |  |  | 
6152  | 71.1k  |     ret->contextSize = -1;  | 
6153  | 71.1k  |     ret->proximityPosition = -1;  | 
6154  |  |  | 
6155  |  | #ifdef XP_DEFAULT_CACHE_ON  | 
6156  |  |     if (xmlXPathContextSetCache(ret, 1, -1, 0) == -1) { | 
6157  |  |   xmlXPathFreeContext(ret);  | 
6158  |  |   return(NULL);  | 
6159  |  |     }  | 
6160  |  | #endif  | 
6161  |  |  | 
6162  | 71.1k  |     xmlXPathRegisterAllFunctions(ret);  | 
6163  |  |  | 
6164  | 71.1k  |     return(ret);  | 
6165  | 71.1k  | }  | 
6166  |  |  | 
6167  |  | /**  | 
6168  |  |  * xmlXPathFreeContext:  | 
6169  |  |  * @ctxt:  the context to free  | 
6170  |  |  *  | 
6171  |  |  * Free up an xmlXPathContext  | 
6172  |  |  */  | 
6173  |  | void  | 
6174  | 63.7k  | xmlXPathFreeContext(xmlXPathContextPtr ctxt) { | 
6175  | 63.7k  |     if (ctxt == NULL) return;  | 
6176  |  |  | 
6177  | 63.7k  |     if (ctxt->cache != NULL)  | 
6178  | 0  |   xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);  | 
6179  | 63.7k  |     xmlXPathRegisteredNsCleanup(ctxt);  | 
6180  | 63.7k  |     xmlXPathRegisteredFuncsCleanup(ctxt);  | 
6181  | 63.7k  |     xmlXPathRegisteredVariablesCleanup(ctxt);  | 
6182  | 63.7k  |     xmlResetError(&ctxt->lastError);  | 
6183  | 63.7k  |     xmlFree(ctxt);  | 
6184  | 63.7k  | }  | 
6185  |  |  | 
6186  |  | /************************************************************************  | 
6187  |  |  *                  *  | 
6188  |  |  *    Routines to handle XPath parser contexts    *  | 
6189  |  |  *                  *  | 
6190  |  |  ************************************************************************/  | 
6191  |  |  | 
6192  |  | #define CHECK_CTXT(ctxt)            \  | 
6193  | 4.05k  |     if (ctxt == NULL) {           \ | 
6194  | 0  |   __xmlRaiseError(NULL, NULL, NULL,       \  | 
6195  | 0  |     NULL, NULL, XML_FROM_XPATH,       \  | 
6196  | 0  |     XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL,      \  | 
6197  | 0  |     __FILE__, __LINE__,         \  | 
6198  | 0  |     NULL, NULL, NULL, 0, 0,         \  | 
6199  | 0  |     "NULL context pointer\n");        \  | 
6200  | 0  |   return(NULL);             \  | 
6201  | 0  |     }                  \  | 
6202  |  |  | 
6203  |  | #define CHECK_CTXT_NEG(ctxt)            \  | 
6204  | 1.75M  |     if (ctxt == NULL) {           \ | 
6205  | 0  |   __xmlRaiseError(NULL, NULL, NULL,       \  | 
6206  | 0  |     NULL, NULL, XML_FROM_XPATH,       \  | 
6207  | 0  |     XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL,      \  | 
6208  | 0  |     __FILE__, __LINE__,         \  | 
6209  | 0  |     NULL, NULL, NULL, 0, 0,         \  | 
6210  | 0  |     "NULL context pointer\n");        \  | 
6211  | 0  |   return(-1);             \  | 
6212  | 0  |     }                  \  | 
6213  |  |  | 
6214  |  |  | 
6215  |  | #define CHECK_CONTEXT(ctxt)           \  | 
6216  |  |     if ((ctxt == NULL) || (ctxt->doc == NULL) ||      \  | 
6217  |  |         (ctxt->doc->children == NULL)) {        \ | 
6218  |  |   xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT);  \  | 
6219  |  |   return(NULL);             \  | 
6220  |  |     }  | 
6221  |  |  | 
6222  |  |  | 
6223  |  | /**  | 
6224  |  |  * xmlXPathNewParserContext:  | 
6225  |  |  * @str:  the XPath expression  | 
6226  |  |  * @ctxt:  the XPath context  | 
6227  |  |  *  | 
6228  |  |  * Create a new xmlXPathParserContext  | 
6229  |  |  *  | 
6230  |  |  * Returns the xmlXPathParserContext just allocated.  | 
6231  |  |  */  | 
6232  |  | xmlXPathParserContextPtr  | 
6233  | 1.32M  | xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) { | 
6234  | 1.32M  |     xmlXPathParserContextPtr ret;  | 
6235  |  |  | 
6236  | 1.32M  |     ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));  | 
6237  | 1.32M  |     if (ret == NULL) { | 
6238  | 0  |         xmlXPathErrMemory(ctxt, "creating parser context\n");  | 
6239  | 0  |   return(NULL);  | 
6240  | 0  |     }  | 
6241  | 1.32M  |     memset(ret, 0 , sizeof(xmlXPathParserContext));  | 
6242  | 1.32M  |     ret->cur = ret->base = str;  | 
6243  | 1.32M  |     ret->context = ctxt;  | 
6244  |  |  | 
6245  | 1.32M  |     ret->comp = xmlXPathNewCompExpr();  | 
6246  | 1.32M  |     if (ret->comp == NULL) { | 
6247  | 0  |   xmlFree(ret->valueTab);  | 
6248  | 0  |   xmlFree(ret);  | 
6249  | 0  |   return(NULL);  | 
6250  | 0  |     }  | 
6251  | 1.32M  |     if ((ctxt != NULL) && (ctxt->dict != NULL)) { | 
6252  | 0  |         ret->comp->dict = ctxt->dict;  | 
6253  | 0  |   xmlDictReference(ret->comp->dict);  | 
6254  | 0  |     }  | 
6255  |  |  | 
6256  | 1.32M  |     return(ret);  | 
6257  | 1.32M  | }  | 
6258  |  |  | 
6259  |  | /**  | 
6260  |  |  * xmlXPathCompParserContext:  | 
6261  |  |  * @comp:  the XPath compiled expression  | 
6262  |  |  * @ctxt:  the XPath context  | 
6263  |  |  *  | 
6264  |  |  * Create a new xmlXPathParserContext when processing a compiled expression  | 
6265  |  |  *  | 
6266  |  |  * Returns the xmlXPathParserContext just allocated.  | 
6267  |  |  */  | 
6268  |  | static xmlXPathParserContextPtr  | 
6269  | 1.75M  | xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) { | 
6270  | 1.75M  |     xmlXPathParserContextPtr ret;  | 
6271  |  |  | 
6272  | 1.75M  |     ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));  | 
6273  | 1.75M  |     if (ret == NULL) { | 
6274  | 0  |         xmlXPathErrMemory(ctxt, "creating evaluation context\n");  | 
6275  | 0  |   return(NULL);  | 
6276  | 0  |     }  | 
6277  | 1.75M  |     memset(ret, 0 , sizeof(xmlXPathParserContext));  | 
6278  |  |  | 
6279  |  |     /* Allocate the value stack */  | 
6280  | 1.75M  |     ret->valueTab = (xmlXPathObjectPtr *)  | 
6281  | 1.75M  |                      xmlMalloc(10 * sizeof(xmlXPathObjectPtr));  | 
6282  | 1.75M  |     if (ret->valueTab == NULL) { | 
6283  | 0  |   xmlFree(ret);  | 
6284  | 0  |   xmlXPathErrMemory(ctxt, "creating evaluation context\n");  | 
6285  | 0  |   return(NULL);  | 
6286  | 0  |     }  | 
6287  | 1.75M  |     ret->valueNr = 0;  | 
6288  | 1.75M  |     ret->valueMax = 10;  | 
6289  | 1.75M  |     ret->value = NULL;  | 
6290  | 1.75M  |     ret->valueFrame = 0;  | 
6291  |  |  | 
6292  | 1.75M  |     ret->context = ctxt;  | 
6293  | 1.75M  |     ret->comp = comp;  | 
6294  |  |  | 
6295  | 1.75M  |     return(ret);  | 
6296  | 1.75M  | }  | 
6297  |  |  | 
6298  |  | /**  | 
6299  |  |  * xmlXPathFreeParserContext:  | 
6300  |  |  * @ctxt:  the context to free  | 
6301  |  |  *  | 
6302  |  |  * Free up an xmlXPathParserContext  | 
6303  |  |  */  | 
6304  |  | void  | 
6305  | 3.07M  | xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) { | 
6306  | 3.07M  |     int i;  | 
6307  |  |  | 
6308  | 3.07M  |     if (ctxt->valueTab != NULL) { | 
6309  | 2.25M  |         for (i = 0; i < ctxt->valueNr; i++) { | 
6310  | 434k  |             if (ctxt->context)  | 
6311  | 434k  |                 xmlXPathReleaseObject(ctxt->context, ctxt->valueTab[i]);  | 
6312  | 0  |             else  | 
6313  | 0  |                 xmlXPathFreeObject(ctxt->valueTab[i]);  | 
6314  | 434k  |         }  | 
6315  | 1.81M  |         xmlFree(ctxt->valueTab);  | 
6316  | 1.81M  |     }  | 
6317  | 3.07M  |     if (ctxt->comp != NULL) { | 
6318  | 971k  | #ifdef XPATH_STREAMING  | 
6319  | 971k  |   if (ctxt->comp->stream != NULL) { | 
6320  | 126  |       xmlFreePatternList(ctxt->comp->stream);  | 
6321  | 126  |       ctxt->comp->stream = NULL;  | 
6322  | 126  |   }  | 
6323  | 971k  | #endif  | 
6324  | 971k  |   xmlXPathFreeCompExpr(ctxt->comp);  | 
6325  | 971k  |     }  | 
6326  | 3.07M  |     xmlFree(ctxt);  | 
6327  | 3.07M  | }  | 
6328  |  |  | 
6329  |  | /************************************************************************  | 
6330  |  |  *                  *  | 
6331  |  |  *    The implicit core function library      *  | 
6332  |  |  *                  *  | 
6333  |  |  ************************************************************************/  | 
6334  |  |  | 
6335  |  | /**  | 
6336  |  |  * xmlXPathNodeValHash:  | 
6337  |  |  * @node:  a node pointer  | 
6338  |  |  *  | 
6339  |  |  * Function computing the beginning of the string value of the node,  | 
6340  |  |  * used to speed up comparisons  | 
6341  |  |  *  | 
6342  |  |  * Returns an int usable as a hash  | 
6343  |  |  */  | 
6344  |  | static unsigned int  | 
6345  | 741k  | xmlXPathNodeValHash(xmlNodePtr node) { | 
6346  | 741k  |     int len = 2;  | 
6347  | 741k  |     const xmlChar * string = NULL;  | 
6348  | 741k  |     xmlNodePtr tmp = NULL;  | 
6349  | 741k  |     unsigned int ret = 0;  | 
6350  |  |  | 
6351  | 741k  |     if (node == NULL)  | 
6352  | 0  |   return(0);  | 
6353  |  |  | 
6354  | 741k  |     if (node->type == XML_DOCUMENT_NODE) { | 
6355  | 50.9k  |   tmp = xmlDocGetRootElement((xmlDocPtr) node);  | 
6356  | 50.9k  |   if (tmp == NULL)  | 
6357  | 26  |       node = node->children;  | 
6358  | 50.8k  |   else  | 
6359  | 50.8k  |       node = tmp;  | 
6360  |  |  | 
6361  | 50.9k  |   if (node == NULL)  | 
6362  | 0  |       return(0);  | 
6363  | 50.9k  |     }  | 
6364  |  |  | 
6365  | 741k  |     switch (node->type) { | 
6366  | 17.4k  |   case XML_COMMENT_NODE:  | 
6367  | 35.4k  |   case XML_PI_NODE:  | 
6368  | 49.4k  |   case XML_CDATA_SECTION_NODE:  | 
6369  | 316k  |   case XML_TEXT_NODE:  | 
6370  | 316k  |       string = node->content;  | 
6371  | 316k  |       if (string == NULL)  | 
6372  | 0  |     return(0);  | 
6373  | 316k  |       if (string[0] == 0)  | 
6374  | 176  |     return(0);  | 
6375  | 316k  |       return(string[0] + (string[1] << 8));  | 
6376  | 16.2k  |   case XML_NAMESPACE_DECL:  | 
6377  | 16.2k  |       string = ((xmlNsPtr)node)->href;  | 
6378  | 16.2k  |       if (string == NULL)  | 
6379  | 0  |     return(0);  | 
6380  | 16.2k  |       if (string[0] == 0)  | 
6381  | 0  |     return(0);  | 
6382  | 16.2k  |       return(string[0] + (string[1] << 8));  | 
6383  | 32.3k  |   case XML_ATTRIBUTE_NODE:  | 
6384  | 32.3k  |       tmp = ((xmlAttrPtr) node)->children;  | 
6385  | 32.3k  |       break;  | 
6386  | 375k  |   case XML_ELEMENT_NODE:  | 
6387  | 375k  |       tmp = node->children;  | 
6388  | 375k  |       break;  | 
6389  | 0  |   default:  | 
6390  | 0  |       return(0);  | 
6391  | 741k  |     }  | 
6392  | 449k  |     while (tmp != NULL) { | 
6393  | 341k  |   switch (tmp->type) { | 
6394  | 18.8k  |       case XML_CDATA_SECTION_NODE:  | 
6395  | 341k  |       case XML_TEXT_NODE:  | 
6396  | 341k  |     string = tmp->content;  | 
6397  | 341k  |     break;  | 
6398  | 0  |       default:  | 
6399  | 0  |                 string = NULL;  | 
6400  | 0  |     break;  | 
6401  | 341k  |   }  | 
6402  | 341k  |   if ((string != NULL) && (string[0] != 0)) { | 
6403  | 339k  |       if (len == 1) { | 
6404  | 0  |     return(ret + (string[0] << 8));  | 
6405  | 0  |       }  | 
6406  | 339k  |       if (string[1] == 0) { | 
6407  | 40.2k  |     len = 1;  | 
6408  | 40.2k  |     ret = string[0];  | 
6409  | 299k  |       } else { | 
6410  | 299k  |     return(string[0] + (string[1] << 8));  | 
6411  | 299k  |       }  | 
6412  | 339k  |   }  | 
6413  |  |   /*  | 
6414  |  |    * Skip to next node  | 
6415  |  |    */  | 
6416  | 41.5k  |   if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) { | 
6417  | 0  |       if (tmp->children->type != XML_ENTITY_DECL) { | 
6418  | 0  |     tmp = tmp->children;  | 
6419  | 0  |     continue;  | 
6420  | 0  |       }  | 
6421  | 0  |   }  | 
6422  | 41.5k  |   if (tmp == node)  | 
6423  | 0  |       break;  | 
6424  |  |  | 
6425  | 41.5k  |   if (tmp->next != NULL) { | 
6426  | 0  |       tmp = tmp->next;  | 
6427  | 0  |       continue;  | 
6428  | 0  |   }  | 
6429  |  |  | 
6430  | 41.5k  |   do { | 
6431  | 41.5k  |       tmp = tmp->parent;  | 
6432  | 41.5k  |       if (tmp == NULL)  | 
6433  | 0  |     break;  | 
6434  | 41.5k  |       if (tmp == node) { | 
6435  | 41.5k  |     tmp = NULL;  | 
6436  | 41.5k  |     break;  | 
6437  | 41.5k  |       }  | 
6438  | 0  |       if (tmp->next != NULL) { | 
6439  | 0  |     tmp = tmp->next;  | 
6440  | 0  |     break;  | 
6441  | 0  |       }  | 
6442  | 0  |   } while (tmp != NULL);  | 
6443  | 41.5k  |     }  | 
6444  | 108k  |     return(ret);  | 
6445  | 408k  | }  | 
6446  |  |  | 
6447  |  | /**  | 
6448  |  |  * xmlXPathStringHash:  | 
6449  |  |  * @string:  a string  | 
6450  |  |  *  | 
6451  |  |  * Function computing the beginning of the string value of the node,  | 
6452  |  |  * used to speed up comparisons  | 
6453  |  |  *  | 
6454  |  |  * Returns an int usable as a hash  | 
6455  |  |  */  | 
6456  |  | static unsigned int  | 
6457  | 51.6k  | xmlXPathStringHash(const xmlChar * string) { | 
6458  | 51.6k  |     if (string == NULL)  | 
6459  | 0  |   return(0);  | 
6460  | 51.6k  |     if (string[0] == 0)  | 
6461  | 13.1k  |   return(0);  | 
6462  | 38.4k  |     return(string[0] + (string[1] << 8));  | 
6463  | 51.6k  | }  | 
6464  |  |  | 
6465  |  | /**  | 
6466  |  |  * xmlXPathCompareNodeSetFloat:  | 
6467  |  |  * @ctxt:  the XPath Parser context  | 
6468  |  |  * @inf:  less than (1) or greater than (0)  | 
6469  |  |  * @strict:  is the comparison strict  | 
6470  |  |  * @arg:  the node set  | 
6471  |  |  * @f:  the value  | 
6472  |  |  *  | 
6473  |  |  * Implement the compare operation between a nodeset and a number  | 
6474  |  |  *     @ns < @val    (1, 1, ...  | 
6475  |  |  *     @ns <= @val   (1, 0, ...  | 
6476  |  |  *     @ns > @val    (0, 1, ...  | 
6477  |  |  *     @ns >= @val   (0, 0, ...  | 
6478  |  |  *  | 
6479  |  |  * If one object to be compared is a node-set and the other is a number,  | 
6480  |  |  * then the comparison will be true if and only if there is a node in the  | 
6481  |  |  * node-set such that the result of performing the comparison on the number  | 
6482  |  |  * to be compared and on the result of converting the string-value of that  | 
6483  |  |  * node to a number using the number function is true.  | 
6484  |  |  *  | 
6485  |  |  * Returns 0 or 1 depending on the results of the test.  | 
6486  |  |  */  | 
6487  |  | static int  | 
6488  |  | xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,  | 
6489  | 761k  |                       xmlXPathObjectPtr arg, xmlXPathObjectPtr f) { | 
6490  | 761k  |     int i, ret = 0;  | 
6491  | 761k  |     xmlNodeSetPtr ns;  | 
6492  | 761k  |     xmlChar *str2;  | 
6493  |  |  | 
6494  | 761k  |     if ((f == NULL) || (arg == NULL) ||  | 
6495  | 761k  |   ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) { | 
6496  | 0  |   xmlXPathReleaseObject(ctxt->context, arg);  | 
6497  | 0  |   xmlXPathReleaseObject(ctxt->context, f);  | 
6498  | 0  |         return(0);  | 
6499  | 0  |     }  | 
6500  | 761k  |     ns = arg->nodesetval;  | 
6501  | 761k  |     if (ns != NULL) { | 
6502  | 1.83M  |   for (i = 0;i < ns->nodeNr;i++) { | 
6503  | 1.17M  |        str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);  | 
6504  | 1.17M  |        if (str2 != NULL) { | 
6505  | 1.17M  |      valuePush(ctxt,  | 
6506  | 1.17M  |          xmlXPathCacheNewString(ctxt->context, str2));  | 
6507  | 1.17M  |      xmlFree(str2);  | 
6508  | 1.17M  |      xmlXPathNumberFunction(ctxt, 1);  | 
6509  | 1.17M  |      valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, f));  | 
6510  | 1.17M  |      ret = xmlXPathCompareValues(ctxt, inf, strict);  | 
6511  | 1.17M  |      if (ret)  | 
6512  | 14.9k  |          break;  | 
6513  | 1.17M  |        }  | 
6514  | 1.17M  |   }  | 
6515  | 672k  |     }  | 
6516  | 761k  |     xmlXPathReleaseObject(ctxt->context, arg);  | 
6517  | 761k  |     xmlXPathReleaseObject(ctxt->context, f);  | 
6518  | 761k  |     return(ret);  | 
6519  | 761k  | }  | 
6520  |  |  | 
6521  |  | /**  | 
6522  |  |  * xmlXPathCompareNodeSetString:  | 
6523  |  |  * @ctxt:  the XPath Parser context  | 
6524  |  |  * @inf:  less than (1) or greater than (0)  | 
6525  |  |  * @strict:  is the comparison strict  | 
6526  |  |  * @arg:  the node set  | 
6527  |  |  * @s:  the value  | 
6528  |  |  *  | 
6529  |  |  * Implement the compare operation between a nodeset and a string  | 
6530  |  |  *     @ns < @val    (1, 1, ...  | 
6531  |  |  *     @ns <= @val   (1, 0, ...  | 
6532  |  |  *     @ns > @val    (0, 1, ...  | 
6533  |  |  *     @ns >= @val   (0, 0, ...  | 
6534  |  |  *  | 
6535  |  |  * If one object to be compared is a node-set and the other is a string,  | 
6536  |  |  * then the comparison will be true if and only if there is a node in  | 
6537  |  |  * the node-set such that the result of performing the comparison on the  | 
6538  |  |  * string-value of the node and the other string is true.  | 
6539  |  |  *  | 
6540  |  |  * Returns 0 or 1 depending on the results of the test.  | 
6541  |  |  */  | 
6542  |  | static int  | 
6543  |  | xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,  | 
6544  | 113k  |                       xmlXPathObjectPtr arg, xmlXPathObjectPtr s) { | 
6545  | 113k  |     int i, ret = 0;  | 
6546  | 113k  |     xmlNodeSetPtr ns;  | 
6547  | 113k  |     xmlChar *str2;  | 
6548  |  |  | 
6549  | 113k  |     if ((s == NULL) || (arg == NULL) ||  | 
6550  | 113k  |   ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) { | 
6551  | 0  |   xmlXPathReleaseObject(ctxt->context, arg);  | 
6552  | 0  |   xmlXPathReleaseObject(ctxt->context, s);  | 
6553  | 0  |         return(0);  | 
6554  | 0  |     }  | 
6555  | 113k  |     ns = arg->nodesetval;  | 
6556  | 113k  |     if (ns != NULL) { | 
6557  | 225k  |   for (i = 0;i < ns->nodeNr;i++) { | 
6558  | 150k  |        str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);  | 
6559  | 150k  |        if (str2 != NULL) { | 
6560  | 150k  |      valuePush(ctxt,  | 
6561  | 150k  |          xmlXPathCacheNewString(ctxt->context, str2));  | 
6562  | 150k  |      xmlFree(str2);  | 
6563  | 150k  |      valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, s));  | 
6564  | 150k  |      ret = xmlXPathCompareValues(ctxt, inf, strict);  | 
6565  | 150k  |      if (ret)  | 
6566  | 1.11k  |          break;  | 
6567  | 150k  |        }  | 
6568  | 150k  |   }  | 
6569  | 76.1k  |     }  | 
6570  | 113k  |     xmlXPathReleaseObject(ctxt->context, arg);  | 
6571  | 113k  |     xmlXPathReleaseObject(ctxt->context, s);  | 
6572  | 113k  |     return(ret);  | 
6573  | 113k  | }  | 
6574  |  |  | 
6575  |  | /**  | 
6576  |  |  * xmlXPathCompareNodeSets:  | 
6577  |  |  * @inf:  less than (1) or greater than (0)  | 
6578  |  |  * @strict:  is the comparison strict  | 
6579  |  |  * @arg1:  the first node set object  | 
6580  |  |  * @arg2:  the second node set object  | 
6581  |  |  *  | 
6582  |  |  * Implement the compare operation on nodesets:  | 
6583  |  |  *  | 
6584  |  |  * If both objects to be compared are node-sets, then the comparison  | 
6585  |  |  * will be true if and only if there is a node in the first node-set  | 
6586  |  |  * and a node in the second node-set such that the result of performing  | 
6587  |  |  * the comparison on the string-values of the two nodes is true.  | 
6588  |  |  * ....  | 
6589  |  |  * When neither object to be compared is a node-set and the operator  | 
6590  |  |  * is <=, <, >= or >, then the objects are compared by converting both  | 
6591  |  |  * objects to numbers and comparing the numbers according to IEEE 754.  | 
6592  |  |  * ....  | 
6593  |  |  * The number function converts its argument to a number as follows:  | 
6594  |  |  *  - a string that consists of optional whitespace followed by an  | 
6595  |  |  *    optional minus sign followed by a Number followed by whitespace  | 
6596  |  |  *    is converted to the IEEE 754 number that is nearest (according  | 
6597  |  |  *    to the IEEE 754 round-to-nearest rule) to the mathematical value  | 
6598  |  |  *    represented by the string; any other string is converted to NaN  | 
6599  |  |  *  | 
6600  |  |  * Conclusion all nodes need to be converted first to their string value  | 
6601  |  |  * and then the comparison must be done when possible  | 
6602  |  |  */  | 
6603  |  | static int  | 
6604  |  | xmlXPathCompareNodeSets(int inf, int strict,  | 
6605  | 1.16M  |                   xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) { | 
6606  | 1.16M  |     int i, j, init = 0;  | 
6607  | 1.16M  |     double val1;  | 
6608  | 1.16M  |     double *values2;  | 
6609  | 1.16M  |     int ret = 0;  | 
6610  | 1.16M  |     xmlNodeSetPtr ns1;  | 
6611  | 1.16M  |     xmlNodeSetPtr ns2;  | 
6612  |  |  | 
6613  | 1.16M  |     if ((arg1 == NULL) ||  | 
6614  | 1.16M  |   ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) { | 
6615  | 0  |   xmlXPathFreeObject(arg2);  | 
6616  | 0  |         return(0);  | 
6617  | 0  |     }  | 
6618  | 1.16M  |     if ((arg2 == NULL) ||  | 
6619  | 1.16M  |   ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) { | 
6620  | 0  |   xmlXPathFreeObject(arg1);  | 
6621  | 0  |   xmlXPathFreeObject(arg2);  | 
6622  | 0  |         return(0);  | 
6623  | 0  |     }  | 
6624  |  |  | 
6625  | 1.16M  |     ns1 = arg1->nodesetval;  | 
6626  | 1.16M  |     ns2 = arg2->nodesetval;  | 
6627  |  |  | 
6628  | 1.16M  |     if ((ns1 == NULL) || (ns1->nodeNr <= 0)) { | 
6629  | 756k  |   xmlXPathFreeObject(arg1);  | 
6630  | 756k  |   xmlXPathFreeObject(arg2);  | 
6631  | 756k  |   return(0);  | 
6632  | 756k  |     }  | 
6633  | 408k  |     if ((ns2 == NULL) || (ns2->nodeNr <= 0)) { | 
6634  | 266k  |   xmlXPathFreeObject(arg1);  | 
6635  | 266k  |   xmlXPathFreeObject(arg2);  | 
6636  | 266k  |   return(0);  | 
6637  | 266k  |     }  | 
6638  |  |  | 
6639  | 142k  |     values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));  | 
6640  | 142k  |     if (values2 == NULL) { | 
6641  |  |         /* TODO: Propagate memory error. */  | 
6642  | 0  |         xmlXPathErrMemory(NULL, "comparing nodesets\n");  | 
6643  | 0  |   xmlXPathFreeObject(arg1);  | 
6644  | 0  |   xmlXPathFreeObject(arg2);  | 
6645  | 0  |   return(0);  | 
6646  | 0  |     }  | 
6647  | 1.39M  |     for (i = 0;i < ns1->nodeNr;i++) { | 
6648  | 1.30M  |   val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);  | 
6649  | 1.30M  |   if (xmlXPathIsNaN(val1))  | 
6650  | 1.02M  |       continue;  | 
6651  | 1.36M  |   for (j = 0;j < ns2->nodeNr;j++) { | 
6652  | 1.13M  |       if (init == 0) { | 
6653  | 512k  |     values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);  | 
6654  | 512k  |       }  | 
6655  | 1.13M  |       if (xmlXPathIsNaN(values2[j]))  | 
6656  | 970k  |     continue;  | 
6657  | 166k  |       if (inf && strict)  | 
6658  | 26.7k  |     ret = (val1 < values2[j]);  | 
6659  | 139k  |       else if (inf && !strict)  | 
6660  | 11.3k  |     ret = (val1 <= values2[j]);  | 
6661  | 128k  |       else if (!inf && strict)  | 
6662  | 36.5k  |     ret = (val1 > values2[j]);  | 
6663  | 91.4k  |       else if (!inf && !strict)  | 
6664  | 91.4k  |     ret = (val1 >= values2[j]);  | 
6665  | 166k  |       if (ret)  | 
6666  | 58.7k  |     break;  | 
6667  | 166k  |   }  | 
6668  | 285k  |   if (ret)  | 
6669  | 58.7k  |       break;  | 
6670  | 226k  |   init = 1;  | 
6671  | 226k  |     }  | 
6672  | 142k  |     xmlFree(values2);  | 
6673  | 142k  |     xmlXPathFreeObject(arg1);  | 
6674  | 142k  |     xmlXPathFreeObject(arg2);  | 
6675  | 142k  |     return(ret);  | 
6676  | 142k  | }  | 
6677  |  |  | 
6678  |  | /**  | 
6679  |  |  * xmlXPathCompareNodeSetValue:  | 
6680  |  |  * @ctxt:  the XPath Parser context  | 
6681  |  |  * @inf:  less than (1) or greater than (0)  | 
6682  |  |  * @strict:  is the comparison strict  | 
6683  |  |  * @arg:  the node set  | 
6684  |  |  * @val:  the value  | 
6685  |  |  *  | 
6686  |  |  * Implement the compare operation between a nodeset and a value  | 
6687  |  |  *     @ns < @val    (1, 1, ...  | 
6688  |  |  *     @ns <= @val   (1, 0, ...  | 
6689  |  |  *     @ns > @val    (0, 1, ...  | 
6690  |  |  *     @ns >= @val   (0, 0, ...  | 
6691  |  |  *  | 
6692  |  |  * If one object to be compared is a node-set and the other is a boolean,  | 
6693  |  |  * then the comparison will be true if and only if the result of performing  | 
6694  |  |  * the comparison on the boolean and on the result of converting  | 
6695  |  |  * the node-set to a boolean using the boolean function is true.  | 
6696  |  |  *  | 
6697  |  |  * Returns 0 or 1 depending on the results of the test.  | 
6698  |  |  */  | 
6699  |  | static int  | 
6700  |  | xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,  | 
6701  | 2.09M  |                       xmlXPathObjectPtr arg, xmlXPathObjectPtr val) { | 
6702  | 2.09M  |     if ((val == NULL) || (arg == NULL) ||  | 
6703  | 2.09M  |   ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))  | 
6704  | 0  |         return(0);  | 
6705  |  |  | 
6706  | 2.09M  |     switch(val->type) { | 
6707  | 761k  |         case XPATH_NUMBER:  | 
6708  | 761k  |       return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));  | 
6709  | 0  |         case XPATH_NODESET:  | 
6710  | 0  |         case XPATH_XSLT_TREE:  | 
6711  | 0  |       return(xmlXPathCompareNodeSets(inf, strict, arg, val));  | 
6712  | 113k  |         case XPATH_STRING:  | 
6713  | 113k  |       return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));  | 
6714  | 1.21M  |         case XPATH_BOOLEAN:  | 
6715  | 1.21M  |       valuePush(ctxt, arg);  | 
6716  | 1.21M  |       xmlXPathBooleanFunction(ctxt, 1);  | 
6717  | 1.21M  |       valuePush(ctxt, val);  | 
6718  | 1.21M  |       return(xmlXPathCompareValues(ctxt, inf, strict));  | 
6719  | 10  |   default:  | 
6720  | 10  |             xmlGenericError(xmlGenericErrorContext,  | 
6721  | 10  |                     "xmlXPathCompareNodeSetValue: Can't compare node set "  | 
6722  | 10  |                     "and object of type %d\n",  | 
6723  | 10  |                     val->type);  | 
6724  | 10  |             xmlXPathReleaseObject(ctxt->context, arg);  | 
6725  | 10  |             xmlXPathReleaseObject(ctxt->context, val);  | 
6726  | 10  |             XP_ERROR0(XPATH_INVALID_TYPE);  | 
6727  | 2.09M  |     }  | 
6728  | 0  |     return(0);  | 
6729  | 2.09M  | }  | 
6730  |  |  | 
6731  |  | /**  | 
6732  |  |  * xmlXPathEqualNodeSetString:  | 
6733  |  |  * @arg:  the nodeset object argument  | 
6734  |  |  * @str:  the string to compare to.  | 
6735  |  |  * @neq:  flag to show whether for '=' (0) or '!=' (1)  | 
6736  |  |  *  | 
6737  |  |  * Implement the equal operation on XPath objects content: @arg1 == @arg2  | 
6738  |  |  * If one object to be compared is a node-set and the other is a string,  | 
6739  |  |  * then the comparison will be true if and only if there is a node in  | 
6740  |  |  * the node-set such that the result of performing the comparison on the  | 
6741  |  |  * string-value of the node and the other string is true.  | 
6742  |  |  *  | 
6743  |  |  * Returns 0 or 1 depending on the results of the test.  | 
6744  |  |  */  | 
6745  |  | static int  | 
6746  |  | xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)  | 
6747  | 123k  | { | 
6748  | 123k  |     int i;  | 
6749  | 123k  |     xmlNodeSetPtr ns;  | 
6750  | 123k  |     xmlChar *str2;  | 
6751  | 123k  |     unsigned int hash;  | 
6752  |  |  | 
6753  | 123k  |     if ((str == NULL) || (arg == NULL) ||  | 
6754  | 123k  |         ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))  | 
6755  | 0  |         return (0);  | 
6756  | 123k  |     ns = arg->nodesetval;  | 
6757  |  |     /*  | 
6758  |  |      * A NULL nodeset compared with a string is always false  | 
6759  |  |      * (since there is no node equal, and no node not equal)  | 
6760  |  |      */  | 
6761  | 123k  |     if ((ns == NULL) || (ns->nodeNr <= 0) )  | 
6762  | 72.1k  |         return (0);  | 
6763  | 51.6k  |     hash = xmlXPathStringHash(str);  | 
6764  | 313k  |     for (i = 0; i < ns->nodeNr; i++) { | 
6765  | 279k  |         if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) { | 
6766  | 6.95k  |             str2 = xmlNodeGetContent(ns->nodeTab[i]);  | 
6767  | 6.95k  |             if ((str2 != NULL) && (xmlStrEqual(str, str2))) { | 
6768  | 6.24k  |                 xmlFree(str2);  | 
6769  | 6.24k  |     if (neq)  | 
6770  | 1.90k  |         continue;  | 
6771  | 4.33k  |                 return (1);  | 
6772  | 6.24k  |       } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) { | 
6773  | 0  |     if (neq)  | 
6774  | 0  |         continue;  | 
6775  | 0  |                 return (1);  | 
6776  | 718  |             } else if (neq) { | 
6777  | 205  |     if (str2 != NULL)  | 
6778  | 205  |         xmlFree(str2);  | 
6779  | 205  |     return (1);  | 
6780  | 205  |       }  | 
6781  | 513  |             if (str2 != NULL)  | 
6782  | 513  |                 xmlFree(str2);  | 
6783  | 272k  |         } else if (neq)  | 
6784  | 12.7k  |       return (1);  | 
6785  | 279k  |     }  | 
6786  | 34.2k  |     return (0);  | 
6787  | 51.6k  | }  | 
6788  |  |  | 
6789  |  | /**  | 
6790  |  |  * xmlXPathEqualNodeSetFloat:  | 
6791  |  |  * @arg:  the nodeset object argument  | 
6792  |  |  * @f:  the float to compare to  | 
6793  |  |  * @neq:  flag to show whether to compare '=' (0) or '!=' (1)  | 
6794  |  |  *  | 
6795  |  |  * Implement the equal operation on XPath objects content: @arg1 == @arg2  | 
6796  |  |  * If one object to be compared is a node-set and the other is a number,  | 
6797  |  |  * then the comparison will be true if and only if there is a node in  | 
6798  |  |  * the node-set such that the result of performing the comparison on the  | 
6799  |  |  * number to be compared and on the result of converting the string-value  | 
6800  |  |  * of that node to a number using the number function is true.  | 
6801  |  |  *  | 
6802  |  |  * Returns 0 or 1 depending on the results of the test.  | 
6803  |  |  */  | 
6804  |  | static int  | 
6805  |  | xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,  | 
6806  | 427k  |     xmlXPathObjectPtr arg, double f, int neq) { | 
6807  | 427k  |   int i, ret=0;  | 
6808  | 427k  |   xmlNodeSetPtr ns;  | 
6809  | 427k  |   xmlChar *str2;  | 
6810  | 427k  |   xmlXPathObjectPtr val;  | 
6811  | 427k  |   double v;  | 
6812  |  |  | 
6813  | 427k  |     if ((arg == NULL) ||  | 
6814  | 427k  |   ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))  | 
6815  | 0  |         return(0);  | 
6816  |  |  | 
6817  | 427k  |     ns = arg->nodesetval;  | 
6818  | 427k  |     if (ns != NULL) { | 
6819  | 991k  |   for (i=0;i<ns->nodeNr;i++) { | 
6820  | 626k  |       str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);  | 
6821  | 626k  |       if (str2 != NULL) { | 
6822  | 626k  |     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, str2));  | 
6823  | 626k  |     xmlFree(str2);  | 
6824  | 626k  |     xmlXPathNumberFunction(ctxt, 1);  | 
6825  | 626k  |     val = valuePop(ctxt);  | 
6826  | 626k  |     v = val->floatval;  | 
6827  | 626k  |     xmlXPathReleaseObject(ctxt->context, val);  | 
6828  | 626k  |     if (!xmlXPathIsNaN(v)) { | 
6829  | 141k  |         if ((!neq) && (v==f)) { | 
6830  | 1.70k  |       ret = 1;  | 
6831  | 1.70k  |       break;  | 
6832  | 140k  |         } else if ((neq) && (v!=f)) { | 
6833  | 6.22k  |       ret = 1;  | 
6834  | 6.22k  |       break;  | 
6835  | 6.22k  |         }  | 
6836  | 485k  |     } else { /* NaN is unequal to any value */ | 
6837  | 485k  |         if (neq)  | 
6838  | 78.6k  |       ret = 1;  | 
6839  | 485k  |     }  | 
6840  | 626k  |       }  | 
6841  | 626k  |   }  | 
6842  | 373k  |     }  | 
6843  |  |  | 
6844  | 427k  |     return(ret);  | 
6845  | 427k  | }  | 
6846  |  |  | 
6847  |  |  | 
6848  |  | /**  | 
6849  |  |  * xmlXPathEqualNodeSets:  | 
6850  |  |  * @arg1:  first nodeset object argument  | 
6851  |  |  * @arg2:  second nodeset object argument  | 
6852  |  |  * @neq:   flag to show whether to test '=' (0) or '!=' (1)  | 
6853  |  |  *  | 
6854  |  |  * Implement the equal / not equal operation on XPath nodesets:  | 
6855  |  |  * @arg1 == @arg2  or  @arg1 != @arg2  | 
6856  |  |  * If both objects to be compared are node-sets, then the comparison  | 
6857  |  |  * will be true if and only if there is a node in the first node-set and  | 
6858  |  |  * a node in the second node-set such that the result of performing the  | 
6859  |  |  * comparison on the string-values of the two nodes is true.  | 
6860  |  |  *  | 
6861  |  |  * (needless to say, this is a costly operation)  | 
6862  |  |  *  | 
6863  |  |  * Returns 0 or 1 depending on the results of the test.  | 
6864  |  |  */  | 
6865  |  | static int  | 
6866  | 452k  | xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) { | 
6867  | 452k  |     int i, j;  | 
6868  | 452k  |     unsigned int *hashs1;  | 
6869  | 452k  |     unsigned int *hashs2;  | 
6870  | 452k  |     xmlChar **values1;  | 
6871  | 452k  |     xmlChar **values2;  | 
6872  | 452k  |     int ret = 0;  | 
6873  | 452k  |     xmlNodeSetPtr ns1;  | 
6874  | 452k  |     xmlNodeSetPtr ns2;  | 
6875  |  |  | 
6876  | 452k  |     if ((arg1 == NULL) ||  | 
6877  | 452k  |   ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))  | 
6878  | 0  |         return(0);  | 
6879  | 452k  |     if ((arg2 == NULL) ||  | 
6880  | 452k  |   ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))  | 
6881  | 0  |         return(0);  | 
6882  |  |  | 
6883  | 452k  |     ns1 = arg1->nodesetval;  | 
6884  | 452k  |     ns2 = arg2->nodesetval;  | 
6885  |  |  | 
6886  | 452k  |     if ((ns1 == NULL) || (ns1->nodeNr <= 0))  | 
6887  | 244k  |   return(0);  | 
6888  | 208k  |     if ((ns2 == NULL) || (ns2->nodeNr <= 0))  | 
6889  | 82.8k  |   return(0);  | 
6890  |  |  | 
6891  |  |     /*  | 
6892  |  |      * for equal, check if there is a node pertaining to both sets  | 
6893  |  |      */  | 
6894  | 125k  |     if (neq == 0)  | 
6895  | 350k  |   for (i = 0;i < ns1->nodeNr;i++)  | 
6896  | 1.03M  |       for (j = 0;j < ns2->nodeNr;j++)  | 
6897  | 785k  |     if (ns1->nodeTab[i] == ns2->nodeTab[j])  | 
6898  | 32.1k  |         return(1);  | 
6899  |  |  | 
6900  | 93.2k  |     values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));  | 
6901  | 93.2k  |     if (values1 == NULL) { | 
6902  |  |         /* TODO: Propagate memory error. */  | 
6903  | 0  |         xmlXPathErrMemory(NULL, "comparing nodesets\n");  | 
6904  | 0  |   return(0);  | 
6905  | 0  |     }  | 
6906  | 93.2k  |     hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));  | 
6907  | 93.2k  |     if (hashs1 == NULL) { | 
6908  |  |         /* TODO: Propagate memory error. */  | 
6909  | 0  |         xmlXPathErrMemory(NULL, "comparing nodesets\n");  | 
6910  | 0  |   xmlFree(values1);  | 
6911  | 0  |   return(0);  | 
6912  | 0  |     }  | 
6913  | 93.2k  |     memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));  | 
6914  | 93.2k  |     values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));  | 
6915  | 93.2k  |     if (values2 == NULL) { | 
6916  |  |         /* TODO: Propagate memory error. */  | 
6917  | 0  |         xmlXPathErrMemory(NULL, "comparing nodesets\n");  | 
6918  | 0  |   xmlFree(hashs1);  | 
6919  | 0  |   xmlFree(values1);  | 
6920  | 0  |   return(0);  | 
6921  | 0  |     }  | 
6922  | 93.2k  |     hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));  | 
6923  | 93.2k  |     if (hashs2 == NULL) { | 
6924  |  |         /* TODO: Propagate memory error. */  | 
6925  | 0  |         xmlXPathErrMemory(NULL, "comparing nodesets\n");  | 
6926  | 0  |   xmlFree(hashs1);  | 
6927  | 0  |   xmlFree(values1);  | 
6928  | 0  |   xmlFree(values2);  | 
6929  | 0  |   return(0);  | 
6930  | 0  |     }  | 
6931  | 93.2k  |     memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));  | 
6932  | 257k  |     for (i = 0;i < ns1->nodeNr;i++) { | 
6933  | 195k  |   hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);  | 
6934  | 661k  |   for (j = 0;j < ns2->nodeNr;j++) { | 
6935  | 497k  |       if (i == 0)  | 
6936  | 266k  |     hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);  | 
6937  | 497k  |       if (hashs1[i] != hashs2[j]) { | 
6938  | 372k  |     if (neq) { | 
6939  | 12.8k  |         ret = 1;  | 
6940  | 12.8k  |         break;  | 
6941  | 12.8k  |     }  | 
6942  | 372k  |       }  | 
6943  | 124k  |       else { | 
6944  | 124k  |     if (values1[i] == NULL)  | 
6945  | 76.8k  |         values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);  | 
6946  | 124k  |     if (values2[j] == NULL)  | 
6947  | 74.1k  |         values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);  | 
6948  | 124k  |     ret = xmlStrEqual(values1[i], values2[j]) ^ neq;  | 
6949  | 124k  |     if (ret)  | 
6950  | 18.7k  |         break;  | 
6951  | 124k  |       }  | 
6952  | 497k  |   }  | 
6953  | 195k  |   if (ret)  | 
6954  | 31.5k  |       break;  | 
6955  | 195k  |     }  | 
6956  | 459k  |     for (i = 0;i < ns1->nodeNr;i++)  | 
6957  | 366k  |   if (values1[i] != NULL)  | 
6958  | 76.8k  |       xmlFree(values1[i]);  | 
6959  | 417k  |     for (j = 0;j < ns2->nodeNr;j++)  | 
6960  | 324k  |   if (values2[j] != NULL)  | 
6961  | 74.1k  |       xmlFree(values2[j]);  | 
6962  | 93.2k  |     xmlFree(values1);  | 
6963  | 93.2k  |     xmlFree(values2);  | 
6964  | 93.2k  |     xmlFree(hashs1);  | 
6965  | 93.2k  |     xmlFree(hashs2);  | 
6966  | 93.2k  |     return(ret);  | 
6967  | 93.2k  | }  | 
6968  |  |  | 
6969  |  | static int  | 
6970  |  | xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,  | 
6971  | 2.62M  |   xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) { | 
6972  | 2.62M  |     int ret = 0;  | 
6973  |  |     /*  | 
6974  |  |      *At this point we are assured neither arg1 nor arg2  | 
6975  |  |      *is a nodeset, so we can just pick the appropriate routine.  | 
6976  |  |      */  | 
6977  | 2.62M  |     switch (arg1->type) { | 
6978  | 0  |         case XPATH_UNDEFINED:  | 
6979  |  | #ifdef DEBUG_EXPR  | 
6980  |  |       xmlGenericError(xmlGenericErrorContext,  | 
6981  |  |         "Equal: undefined\n");  | 
6982  |  | #endif  | 
6983  | 0  |       break;  | 
6984  | 1.66M  |         case XPATH_BOOLEAN:  | 
6985  | 1.66M  |       switch (arg2->type) { | 
6986  | 0  |           case XPATH_UNDEFINED:  | 
6987  |  | #ifdef DEBUG_EXPR  | 
6988  |  |         xmlGenericError(xmlGenericErrorContext,  | 
6989  |  |           "Equal: undefined\n");  | 
6990  |  | #endif  | 
6991  | 0  |         break;  | 
6992  | 773k  |     case XPATH_BOOLEAN:  | 
6993  |  | #ifdef DEBUG_EXPR  | 
6994  |  |         xmlGenericError(xmlGenericErrorContext,  | 
6995  |  |           "Equal: %d boolean %d \n",  | 
6996  |  |           arg1->boolval, arg2->boolval);  | 
6997  |  | #endif  | 
6998  | 773k  |         ret = (arg1->boolval == arg2->boolval);  | 
6999  | 773k  |         break;  | 
7000  | 794k  |     case XPATH_NUMBER:  | 
7001  | 794k  |         ret = (arg1->boolval ==  | 
7002  | 794k  |          xmlXPathCastNumberToBoolean(arg2->floatval));  | 
7003  | 794k  |         break;  | 
7004  | 92.1k  |     case XPATH_STRING:  | 
7005  | 92.1k  |         if ((arg2->stringval == NULL) ||  | 
7006  | 92.1k  |       (arg2->stringval[0] == 0)) ret = 0;  | 
7007  | 73.5k  |         else  | 
7008  | 73.5k  |       ret = 1;  | 
7009  | 92.1k  |         ret = (arg1->boolval == ret);  | 
7010  | 92.1k  |         break;  | 
7011  | 370  |     case XPATH_USERS:  | 
7012  |  | #ifdef LIBXML_XPTR_LOCS_ENABLED  | 
7013  |  |     case XPATH_POINT:  | 
7014  |  |     case XPATH_RANGE:  | 
7015  |  |     case XPATH_LOCATIONSET:  | 
7016  |  | #endif /* LIBXML_XPTR_LOCS_ENABLED */  | 
7017  | 370  |         TODO  | 
7018  | 370  |         break;  | 
7019  | 0  |     case XPATH_NODESET:  | 
7020  | 0  |     case XPATH_XSLT_TREE:  | 
7021  | 0  |         break;  | 
7022  | 1.66M  |       }  | 
7023  | 1.66M  |       break;  | 
7024  | 1.66M  |         case XPATH_NUMBER:  | 
7025  | 832k  |       switch (arg2->type) { | 
7026  | 0  |           case XPATH_UNDEFINED:  | 
7027  |  | #ifdef DEBUG_EXPR  | 
7028  |  |         xmlGenericError(xmlGenericErrorContext,  | 
7029  |  |           "Equal: undefined\n");  | 
7030  |  | #endif  | 
7031  | 0  |         break;  | 
7032  | 144k  |     case XPATH_BOOLEAN:  | 
7033  | 144k  |         ret = (arg2->boolval==  | 
7034  | 144k  |          xmlXPathCastNumberToBoolean(arg1->floatval));  | 
7035  | 144k  |         break;  | 
7036  | 32.0k  |     case XPATH_STRING:  | 
7037  | 32.0k  |         valuePush(ctxt, arg2);  | 
7038  | 32.0k  |         xmlXPathNumberFunction(ctxt, 1);  | 
7039  | 32.0k  |         arg2 = valuePop(ctxt);  | 
7040  |  |                     /* Falls through. */  | 
7041  | 687k  |     case XPATH_NUMBER:  | 
7042  |  |         /* Hand check NaN and Infinity equalities */  | 
7043  | 687k  |         if (xmlXPathIsNaN(arg1->floatval) ||  | 
7044  | 687k  |           xmlXPathIsNaN(arg2->floatval)) { | 
7045  | 288k  |             ret = 0;  | 
7046  | 398k  |         } else if (xmlXPathIsInf(arg1->floatval) == 1) { | 
7047  | 7.56k  |             if (xmlXPathIsInf(arg2->floatval) == 1)  | 
7048  | 250  |           ret = 1;  | 
7049  | 7.31k  |       else  | 
7050  | 7.31k  |           ret = 0;  | 
7051  | 390k  |         } else if (xmlXPathIsInf(arg1->floatval) == -1) { | 
7052  | 12.9k  |       if (xmlXPathIsInf(arg2->floatval) == -1)  | 
7053  | 88  |           ret = 1;  | 
7054  | 12.8k  |       else  | 
7055  | 12.8k  |           ret = 0;  | 
7056  | 377k  |         } else if (xmlXPathIsInf(arg2->floatval) == 1) { | 
7057  | 6.54k  |       if (xmlXPathIsInf(arg1->floatval) == 1)  | 
7058  | 0  |           ret = 1;  | 
7059  | 6.54k  |       else  | 
7060  | 6.54k  |           ret = 0;  | 
7061  | 371k  |         } else if (xmlXPathIsInf(arg2->floatval) == -1) { | 
7062  | 2.05k  |       if (xmlXPathIsInf(arg1->floatval) == -1)  | 
7063  | 0  |           ret = 1;  | 
7064  | 2.05k  |       else  | 
7065  | 2.05k  |           ret = 0;  | 
7066  | 369k  |         } else { | 
7067  | 369k  |             ret = (arg1->floatval == arg2->floatval);  | 
7068  | 369k  |         }  | 
7069  | 687k  |         break;  | 
7070  | 475  |     case XPATH_USERS:  | 
7071  |  | #ifdef LIBXML_XPTR_LOCS_ENABLED  | 
7072  |  |     case XPATH_POINT:  | 
7073  |  |     case XPATH_RANGE:  | 
7074  |  |     case XPATH_LOCATIONSET:  | 
7075  |  | #endif /* LIBXML_XPTR_LOCS_ENABLED */  | 
7076  | 475  |         TODO  | 
7077  | 475  |         break;  | 
7078  | 0  |     case XPATH_NODESET:  | 
7079  | 0  |     case XPATH_XSLT_TREE:  | 
7080  | 0  |         break;  | 
7081  | 832k  |       }  | 
7082  | 832k  |       break;  | 
7083  | 832k  |         case XPATH_STRING:  | 
7084  | 131k  |       switch (arg2->type) { | 
7085  | 0  |           case XPATH_UNDEFINED:  | 
7086  |  | #ifdef DEBUG_EXPR  | 
7087  |  |         xmlGenericError(xmlGenericErrorContext,  | 
7088  |  |           "Equal: undefined\n");  | 
7089  |  | #endif  | 
7090  | 0  |         break;  | 
7091  | 12.9k  |     case XPATH_BOOLEAN:  | 
7092  | 12.9k  |         if ((arg1->stringval == NULL) ||  | 
7093  | 12.9k  |       (arg1->stringval[0] == 0)) ret = 0;  | 
7094  | 11.1k  |         else  | 
7095  | 11.1k  |       ret = 1;  | 
7096  | 12.9k  |         ret = (arg2->boolval == ret);  | 
7097  | 12.9k  |         break;  | 
7098  | 9.95k  |     case XPATH_STRING:  | 
7099  | 9.95k  |         ret = xmlStrEqual(arg1->stringval, arg2->stringval);  | 
7100  | 9.95k  |         break;  | 
7101  | 108k  |     case XPATH_NUMBER:  | 
7102  | 108k  |         valuePush(ctxt, arg1);  | 
7103  | 108k  |         xmlXPathNumberFunction(ctxt, 1);  | 
7104  | 108k  |         arg1 = valuePop(ctxt);  | 
7105  |  |         /* Hand check NaN and Infinity equalities */  | 
7106  | 108k  |         if (xmlXPathIsNaN(arg1->floatval) ||  | 
7107  | 108k  |           xmlXPathIsNaN(arg2->floatval)) { | 
7108  | 90.8k  |             ret = 0;  | 
7109  | 90.8k  |         } else if (xmlXPathIsInf(arg1->floatval) == 1) { | 
7110  | 347  |       if (xmlXPathIsInf(arg2->floatval) == 1)  | 
7111  | 11  |           ret = 1;  | 
7112  | 336  |       else  | 
7113  | 336  |           ret = 0;  | 
7114  | 16.9k  |         } else if (xmlXPathIsInf(arg1->floatval) == -1) { | 
7115  | 2.29k  |       if (xmlXPathIsInf(arg2->floatval) == -1)  | 
7116  | 0  |           ret = 1;  | 
7117  | 2.29k  |       else  | 
7118  | 2.29k  |           ret = 0;  | 
7119  | 14.6k  |         } else if (xmlXPathIsInf(arg2->floatval) == 1) { | 
7120  | 304  |       if (xmlXPathIsInf(arg1->floatval) == 1)  | 
7121  | 0  |           ret = 1;  | 
7122  | 304  |       else  | 
7123  | 304  |           ret = 0;  | 
7124  | 14.3k  |         } else if (xmlXPathIsInf(arg2->floatval) == -1) { | 
7125  | 90  |       if (xmlXPathIsInf(arg1->floatval) == -1)  | 
7126  | 0  |           ret = 1;  | 
7127  | 90  |       else  | 
7128  | 90  |           ret = 0;  | 
7129  | 14.2k  |         } else { | 
7130  | 14.2k  |             ret = (arg1->floatval == arg2->floatval);  | 
7131  | 14.2k  |         }  | 
7132  | 108k  |         break;  | 
7133  | 12  |     case XPATH_USERS:  | 
7134  |  | #ifdef LIBXML_XPTR_LOCS_ENABLED  | 
7135  |  |     case XPATH_POINT:  | 
7136  |  |     case XPATH_RANGE:  | 
7137  |  |     case XPATH_LOCATIONSET:  | 
7138  |  | #endif /* LIBXML_XPTR_LOCS_ENABLED */  | 
7139  | 12  |         TODO  | 
7140  | 12  |         break;  | 
7141  | 0  |     case XPATH_NODESET:  | 
7142  | 0  |     case XPATH_XSLT_TREE:  | 
7143  | 0  |         break;  | 
7144  | 131k  |       }  | 
7145  | 131k  |       break;  | 
7146  | 131k  |         case XPATH_USERS:  | 
7147  |  | #ifdef LIBXML_XPTR_LOCS_ENABLED  | 
7148  |  |   case XPATH_POINT:  | 
7149  |  |   case XPATH_RANGE:  | 
7150  |  |   case XPATH_LOCATIONSET:  | 
7151  |  | #endif /* LIBXML_XPTR_LOCS_ENABLED */  | 
7152  | 56  |       TODO  | 
7153  | 56  |       break;  | 
7154  | 0  |   case XPATH_NODESET:  | 
7155  | 0  |   case XPATH_XSLT_TREE:  | 
7156  | 0  |       break;  | 
7157  | 2.62M  |     }  | 
7158  | 2.62M  |     xmlXPathReleaseObject(ctxt->context, arg1);  | 
7159  | 2.62M  |     xmlXPathReleaseObject(ctxt->context, arg2);  | 
7160  | 2.62M  |     return(ret);  | 
7161  | 2.62M  | }  | 
7162  |  |  | 
7163  |  | /**  | 
7164  |  |  * xmlXPathEqualValues:  | 
7165  |  |  * @ctxt:  the XPath Parser context  | 
7166  |  |  *  | 
7167  |  |  * Implement the equal operation on XPath objects content: @arg1 == @arg2  | 
7168  |  |  *  | 
7169  |  |  * Returns 0 or 1 depending on the results of the test.  | 
7170  |  |  */  | 
7171  |  | int  | 
7172  | 4.29M  | xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) { | 
7173  | 4.29M  |     xmlXPathObjectPtr arg1, arg2, argtmp;  | 
7174  | 4.29M  |     int ret = 0;  | 
7175  |  |  | 
7176  | 4.29M  |     if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);  | 
7177  | 4.29M  |     arg2 = valuePop(ctxt);  | 
7178  | 4.29M  |     arg1 = valuePop(ctxt);  | 
7179  | 4.29M  |     if ((arg1 == NULL) || (arg2 == NULL)) { | 
7180  | 0  |   if (arg1 != NULL)  | 
7181  | 0  |       xmlXPathReleaseObject(ctxt->context, arg1);  | 
7182  | 0  |   else  | 
7183  | 0  |       xmlXPathReleaseObject(ctxt->context, arg2);  | 
7184  | 0  |   XP_ERROR0(XPATH_INVALID_OPERAND);  | 
7185  | 0  |     }  | 
7186  |  |  | 
7187  | 4.29M  |     if (arg1 == arg2) { | 
7188  |  | #ifdef DEBUG_EXPR  | 
7189  |  |         xmlGenericError(xmlGenericErrorContext,  | 
7190  |  |     "Equal: by pointer\n");  | 
7191  |  | #endif  | 
7192  | 0  |   xmlXPathFreeObject(arg1);  | 
7193  | 0  |         return(1);  | 
7194  | 0  |     }  | 
7195  |  |  | 
7196  |  |     /*  | 
7197  |  |      *If either argument is a nodeset, it's a 'special case'  | 
7198  |  |      */  | 
7199  | 4.29M  |     if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||  | 
7200  | 4.29M  |       (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) { | 
7201  |  |   /*  | 
7202  |  |    *Hack it to assure arg1 is the nodeset  | 
7203  |  |    */  | 
7204  | 1.83M  |   if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) { | 
7205  | 978k  |     argtmp = arg2;  | 
7206  | 978k  |     arg2 = arg1;  | 
7207  | 978k  |     arg1 = argtmp;  | 
7208  | 978k  |   }  | 
7209  | 1.83M  |   switch (arg2->type) { | 
7210  | 0  |       case XPATH_UNDEFINED:  | 
7211  |  | #ifdef DEBUG_EXPR  | 
7212  |  |     xmlGenericError(xmlGenericErrorContext,  | 
7213  |  |       "Equal: undefined\n");  | 
7214  |  | #endif  | 
7215  | 0  |     break;  | 
7216  | 404k  |       case XPATH_NODESET:  | 
7217  | 404k  |       case XPATH_XSLT_TREE:  | 
7218  | 404k  |     ret = xmlXPathEqualNodeSets(arg1, arg2, 0);  | 
7219  | 404k  |     break;  | 
7220  | 974k  |       case XPATH_BOOLEAN:  | 
7221  | 974k  |     if ((arg1->nodesetval == NULL) ||  | 
7222  | 974k  |       (arg1->nodesetval->nodeNr == 0)) ret = 0;  | 
7223  | 362k  |     else  | 
7224  | 362k  |         ret = 1;  | 
7225  | 974k  |     ret = (ret == arg2->boolval);  | 
7226  | 974k  |     break;  | 
7227  | 363k  |       case XPATH_NUMBER:  | 
7228  | 363k  |     ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);  | 
7229  | 363k  |     break;  | 
7230  | 90.4k  |       case XPATH_STRING:  | 
7231  | 90.4k  |     ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);  | 
7232  | 90.4k  |     break;  | 
7233  | 329  |       case XPATH_USERS:  | 
7234  |  | #ifdef LIBXML_XPTR_LOCS_ENABLED  | 
7235  |  |       case XPATH_POINT:  | 
7236  |  |       case XPATH_RANGE:  | 
7237  |  |       case XPATH_LOCATIONSET:  | 
7238  |  | #endif /* LIBXML_XPTR_LOCS_ENABLED */  | 
7239  | 329  |     TODO  | 
7240  | 329  |     break;  | 
7241  | 1.83M  |   }  | 
7242  | 1.83M  |   xmlXPathReleaseObject(ctxt->context, arg1);  | 
7243  | 1.83M  |   xmlXPathReleaseObject(ctxt->context, arg2);  | 
7244  | 1.83M  |   return(ret);  | 
7245  | 1.83M  |     }  | 
7246  |  |  | 
7247  | 2.46M  |     return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));  | 
7248  | 4.29M  | }  | 
7249  |  |  | 
7250  |  | /**  | 
7251  |  |  * xmlXPathNotEqualValues:  | 
7252  |  |  * @ctxt:  the XPath Parser context  | 
7253  |  |  *  | 
7254  |  |  * Implement the equal operation on XPath objects content: @arg1 == @arg2  | 
7255  |  |  *  | 
7256  |  |  * Returns 0 or 1 depending on the results of the test.  | 
7257  |  |  */  | 
7258  |  | int  | 
7259  | 359k  | xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) { | 
7260  | 359k  |     xmlXPathObjectPtr arg1, arg2, argtmp;  | 
7261  | 359k  |     int ret = 0;  | 
7262  |  |  | 
7263  | 359k  |     if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);  | 
7264  | 359k  |     arg2 = valuePop(ctxt);  | 
7265  | 359k  |     arg1 = valuePop(ctxt);  | 
7266  | 359k  |     if ((arg1 == NULL) || (arg2 == NULL)) { | 
7267  | 0  |   if (arg1 != NULL)  | 
7268  | 0  |       xmlXPathReleaseObject(ctxt->context, arg1);  | 
7269  | 0  |   else  | 
7270  | 0  |       xmlXPathReleaseObject(ctxt->context, arg2);  | 
7271  | 0  |   XP_ERROR0(XPATH_INVALID_OPERAND);  | 
7272  | 0  |     }  | 
7273  |  |  | 
7274  | 359k  |     if (arg1 == arg2) { | 
7275  |  | #ifdef DEBUG_EXPR  | 
7276  |  |         xmlGenericError(xmlGenericErrorContext,  | 
7277  |  |     "NotEqual: by pointer\n");  | 
7278  |  | #endif  | 
7279  | 0  |   xmlXPathReleaseObject(ctxt->context, arg1);  | 
7280  | 0  |         return(0);  | 
7281  | 0  |     }  | 
7282  |  |  | 
7283  |  |     /*  | 
7284  |  |      *If either argument is a nodeset, it's a 'special case'  | 
7285  |  |      */  | 
7286  | 359k  |     if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||  | 
7287  | 359k  |       (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) { | 
7288  |  |   /*  | 
7289  |  |    *Hack it to assure arg1 is the nodeset  | 
7290  |  |    */  | 
7291  | 195k  |   if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) { | 
7292  | 86.9k  |     argtmp = arg2;  | 
7293  | 86.9k  |     arg2 = arg1;  | 
7294  | 86.9k  |     arg1 = argtmp;  | 
7295  | 86.9k  |   }  | 
7296  | 195k  |   switch (arg2->type) { | 
7297  | 0  |       case XPATH_UNDEFINED:  | 
7298  |  | #ifdef DEBUG_EXPR  | 
7299  |  |     xmlGenericError(xmlGenericErrorContext,  | 
7300  |  |       "NotEqual: undefined\n");  | 
7301  |  | #endif  | 
7302  | 0  |     break;  | 
7303  | 47.8k  |       case XPATH_NODESET:  | 
7304  | 47.8k  |       case XPATH_XSLT_TREE:  | 
7305  | 47.8k  |     ret = xmlXPathEqualNodeSets(arg1, arg2, 1);  | 
7306  | 47.8k  |     break;  | 
7307  | 49.6k  |       case XPATH_BOOLEAN:  | 
7308  | 49.6k  |     if ((arg1->nodesetval == NULL) ||  | 
7309  | 49.6k  |       (arg1->nodesetval->nodeNr == 0)) ret = 0;  | 
7310  | 11.9k  |     else  | 
7311  | 11.9k  |         ret = 1;  | 
7312  | 49.6k  |     ret = (ret != arg2->boolval);  | 
7313  | 49.6k  |     break;  | 
7314  | 64.6k  |       case XPATH_NUMBER:  | 
7315  | 64.6k  |     ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);  | 
7316  | 64.6k  |     break;  | 
7317  | 33.2k  |       case XPATH_STRING:  | 
7318  | 33.2k  |     ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);  | 
7319  | 33.2k  |     break;  | 
7320  | 6  |       case XPATH_USERS:  | 
7321  |  | #ifdef LIBXML_XPTR_LOCS_ENABLED  | 
7322  |  |       case XPATH_POINT:  | 
7323  |  |       case XPATH_RANGE:  | 
7324  |  |       case XPATH_LOCATIONSET:  | 
7325  |  | #endif /* LIBXML_XPTR_LOCS_ENABLED */  | 
7326  | 6  |     TODO  | 
7327  | 6  |     break;  | 
7328  | 195k  |   }  | 
7329  | 195k  |   xmlXPathReleaseObject(ctxt->context, arg1);  | 
7330  | 195k  |   xmlXPathReleaseObject(ctxt->context, arg2);  | 
7331  | 195k  |   return(ret);  | 
7332  | 195k  |     }  | 
7333  |  |  | 
7334  | 163k  |     return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));  | 
7335  | 359k  | }  | 
7336  |  |  | 
7337  |  | /**  | 
7338  |  |  * xmlXPathCompareValues:  | 
7339  |  |  * @ctxt:  the XPath Parser context  | 
7340  |  |  * @inf:  less than (1) or greater than (0)  | 
7341  |  |  * @strict:  is the comparison strict  | 
7342  |  |  *  | 
7343  |  |  * Implement the compare operation on XPath objects:  | 
7344  |  |  *     @arg1 < @arg2    (1, 1, ...  | 
7345  |  |  *     @arg1 <= @arg2   (1, 0, ...  | 
7346  |  |  *     @arg1 > @arg2    (0, 1, ...  | 
7347  |  |  *     @arg1 >= @arg2   (0, 0, ...  | 
7348  |  |  *  | 
7349  |  |  * When neither object to be compared is a node-set and the operator is  | 
7350  |  |  * <=, <, >=, >, then the objects are compared by converted both objects  | 
7351  |  |  * to numbers and comparing the numbers according to IEEE 754. The <  | 
7352  |  |  * comparison will be true if and only if the first number is less than the  | 
7353  |  |  * second number. The <= comparison will be true if and only if the first  | 
7354  |  |  * number is less than or equal to the second number. The > comparison  | 
7355  |  |  * will be true if and only if the first number is greater than the second  | 
7356  |  |  * number. The >= comparison will be true if and only if the first number  | 
7357  |  |  * is greater than or equal to the second number.  | 
7358  |  |  *  | 
7359  |  |  * Returns 1 if the comparison succeeded, 0 if it failed  | 
7360  |  |  */  | 
7361  |  | int  | 
7362  | 6.57M  | xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) { | 
7363  | 6.57M  |     int ret = 0, arg1i = 0, arg2i = 0;  | 
7364  | 6.57M  |     xmlXPathObjectPtr arg1, arg2;  | 
7365  |  |  | 
7366  | 6.57M  |     if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);  | 
7367  | 6.57M  |     arg2 = valuePop(ctxt);  | 
7368  | 6.57M  |     arg1 = valuePop(ctxt);  | 
7369  | 6.57M  |     if ((arg1 == NULL) || (arg2 == NULL)) { | 
7370  | 0  |   if (arg1 != NULL)  | 
7371  | 0  |       xmlXPathReleaseObject(ctxt->context, arg1);  | 
7372  | 0  |   else  | 
7373  | 0  |       xmlXPathReleaseObject(ctxt->context, arg2);  | 
7374  | 0  |   XP_ERROR0(XPATH_INVALID_OPERAND);  | 
7375  | 0  |     }  | 
7376  |  |  | 
7377  | 6.57M  |     if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||  | 
7378  | 6.57M  |       (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) { | 
7379  |  |   /*  | 
7380  |  |    * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments  | 
7381  |  |    * are not freed from within this routine; they will be freed from the  | 
7382  |  |    * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue  | 
7383  |  |    */  | 
7384  | 3.25M  |   if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&  | 
7385  | 3.25M  |     ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){ | 
7386  | 1.16M  |       ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);  | 
7387  | 2.09M  |   } else { | 
7388  | 2.09M  |       if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) { | 
7389  | 544k  |     ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,  | 
7390  | 544k  |                                 arg1, arg2);  | 
7391  | 1.55M  |       } else { | 
7392  | 1.55M  |     ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,  | 
7393  | 1.55M  |                                 arg2, arg1);  | 
7394  | 1.55M  |       }  | 
7395  | 2.09M  |   }  | 
7396  | 3.25M  |   return(ret);  | 
7397  | 3.25M  |     }  | 
7398  |  |  | 
7399  | 3.31M  |     if (arg1->type != XPATH_NUMBER) { | 
7400  | 1.93M  |   valuePush(ctxt, arg1);  | 
7401  | 1.93M  |   xmlXPathNumberFunction(ctxt, 1);  | 
7402  | 1.93M  |   arg1 = valuePop(ctxt);  | 
7403  | 1.93M  |     }  | 
7404  | 3.31M  |     if (arg1->type != XPATH_NUMBER) { | 
7405  | 0  |   xmlXPathFreeObject(arg1);  | 
7406  | 0  |   xmlXPathFreeObject(arg2);  | 
7407  | 0  |   XP_ERROR0(XPATH_INVALID_OPERAND);  | 
7408  | 0  |     }  | 
7409  | 3.31M  |     if (arg2->type != XPATH_NUMBER) { | 
7410  | 1.40M  |   valuePush(ctxt, arg2);  | 
7411  | 1.40M  |   xmlXPathNumberFunction(ctxt, 1);  | 
7412  | 1.40M  |   arg2 = valuePop(ctxt);  | 
7413  | 1.40M  |     }  | 
7414  | 3.31M  |     if (arg2->type != XPATH_NUMBER) { | 
7415  | 0  |   xmlXPathReleaseObject(ctxt->context, arg1);  | 
7416  | 0  |   xmlXPathReleaseObject(ctxt->context, arg2);  | 
7417  | 0  |   XP_ERROR0(XPATH_INVALID_OPERAND);  | 
7418  | 0  |     }  | 
7419  |  |     /*  | 
7420  |  |      * Add tests for infinity and nan  | 
7421  |  |      * => feedback on 3.4 for Inf and NaN  | 
7422  |  |      */  | 
7423  |  |     /* Hand check NaN and Infinity comparisons */  | 
7424  | 3.31M  |     if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) { | 
7425  | 1.66M  |   ret=0;  | 
7426  | 1.66M  |     } else { | 
7427  | 1.64M  |   arg1i=xmlXPathIsInf(arg1->floatval);  | 
7428  | 1.64M  |   arg2i=xmlXPathIsInf(arg2->floatval);  | 
7429  | 1.64M  |   if (inf && strict) { | 
7430  | 593k  |       if ((arg1i == -1 && arg2i != -1) ||  | 
7431  | 593k  |     (arg2i == 1 && arg1i != 1)) { | 
7432  | 13.0k  |     ret = 1;  | 
7433  | 580k  |       } else if (arg1i == 0 && arg2i == 0) { | 
7434  | 579k  |     ret = (arg1->floatval < arg2->floatval);  | 
7435  | 579k  |       } else { | 
7436  | 1.30k  |     ret = 0;  | 
7437  | 1.30k  |       }  | 
7438  | 593k  |   }  | 
7439  | 1.04M  |   else if (inf && !strict) { | 
7440  | 505k  |       if (arg1i == -1 || arg2i == 1) { | 
7441  | 10.4k  |     ret = 1;  | 
7442  | 495k  |       } else if (arg1i == 0 && arg2i == 0) { | 
7443  | 495k  |     ret = (arg1->floatval <= arg2->floatval);  | 
7444  | 495k  |       } else { | 
7445  | 108  |     ret = 0;  | 
7446  | 108  |       }  | 
7447  | 505k  |   }  | 
7448  | 542k  |   else if (!inf && strict) { | 
7449  | 491k  |       if ((arg1i == 1 && arg2i != 1) ||  | 
7450  | 491k  |     (arg2i == -1 && arg1i != -1)) { | 
7451  | 11.0k  |     ret = 1;  | 
7452  | 480k  |       } else if (arg1i == 0 && arg2i == 0) { | 
7453  | 475k  |     ret = (arg1->floatval > arg2->floatval);  | 
7454  | 475k  |       } else { | 
7455  | 5.85k  |     ret = 0;  | 
7456  | 5.85k  |       }  | 
7457  | 491k  |   }  | 
7458  | 50.9k  |   else if (!inf && !strict) { | 
7459  | 50.9k  |       if (arg1i == 1 || arg2i == -1) { | 
7460  | 6.80k  |     ret = 1;  | 
7461  | 44.1k  |       } else if (arg1i == 0 && arg2i == 0) { | 
7462  | 43.6k  |     ret = (arg1->floatval >= arg2->floatval);  | 
7463  | 43.6k  |       } else { | 
7464  | 437  |     ret = 0;  | 
7465  | 437  |       }  | 
7466  | 50.9k  |   }  | 
7467  | 1.64M  |     }  | 
7468  | 3.31M  |     xmlXPathReleaseObject(ctxt->context, arg1);  | 
7469  | 3.31M  |     xmlXPathReleaseObject(ctxt->context, arg2);  | 
7470  | 3.31M  |     return(ret);  | 
7471  | 3.31M  | }  | 
7472  |  |  | 
7473  |  | /**  | 
7474  |  |  * xmlXPathValueFlipSign:  | 
7475  |  |  * @ctxt:  the XPath Parser context  | 
7476  |  |  *  | 
7477  |  |  * Implement the unary - operation on an XPath object  | 
7478  |  |  * The numeric operators convert their operands to numbers as if  | 
7479  |  |  * by calling the number function.  | 
7480  |  |  */  | 
7481  |  | void  | 
7482  | 1.60M  | xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) { | 
7483  | 1.60M  |     if ((ctxt == NULL) || (ctxt->context == NULL)) return;  | 
7484  | 1.60M  |     CAST_TO_NUMBER;  | 
7485  | 1.60M  |     CHECK_TYPE(XPATH_NUMBER);  | 
7486  | 1.60M  |     ctxt->value->floatval = -ctxt->value->floatval;  | 
7487  | 1.60M  | }  | 
7488  |  |  | 
7489  |  | /**  | 
7490  |  |  * xmlXPathAddValues:  | 
7491  |  |  * @ctxt:  the XPath Parser context  | 
7492  |  |  *  | 
7493  |  |  * Implement the add operation on XPath objects:  | 
7494  |  |  * The numeric operators convert their operands to numbers as if  | 
7495  |  |  * by calling the number function.  | 
7496  |  |  */  | 
7497  |  | void  | 
7498  | 383k  | xmlXPathAddValues(xmlXPathParserContextPtr ctxt) { | 
7499  | 383k  |     xmlXPathObjectPtr arg;  | 
7500  | 383k  |     double val;  | 
7501  |  |  | 
7502  | 383k  |     arg = valuePop(ctxt);  | 
7503  | 383k  |     if (arg == NULL)  | 
7504  | 383k  |   XP_ERROR(XPATH_INVALID_OPERAND);  | 
7505  | 383k  |     val = xmlXPathCastToNumber(arg);  | 
7506  | 383k  |     xmlXPathReleaseObject(ctxt->context, arg);  | 
7507  | 383k  |     CAST_TO_NUMBER;  | 
7508  | 383k  |     CHECK_TYPE(XPATH_NUMBER);  | 
7509  | 383k  |     ctxt->value->floatval += val;  | 
7510  | 383k  | }  | 
7511  |  |  | 
7512  |  | /**  | 
7513  |  |  * xmlXPathSubValues:  | 
7514  |  |  * @ctxt:  the XPath Parser context  | 
7515  |  |  *  | 
7516  |  |  * Implement the subtraction operation on XPath objects:  | 
7517  |  |  * The numeric operators convert their operands to numbers as if  | 
7518  |  |  * by calling the number function.  | 
7519  |  |  */  | 
7520  |  | void  | 
7521  | 3.22M  | xmlXPathSubValues(xmlXPathParserContextPtr ctxt) { | 
7522  | 3.22M  |     xmlXPathObjectPtr arg;  | 
7523  | 3.22M  |     double val;  | 
7524  |  |  | 
7525  | 3.22M  |     arg = valuePop(ctxt);  | 
7526  | 3.22M  |     if (arg == NULL)  | 
7527  | 3.22M  |   XP_ERROR(XPATH_INVALID_OPERAND);  | 
7528  | 3.22M  |     val = xmlXPathCastToNumber(arg);  | 
7529  | 3.22M  |     xmlXPathReleaseObject(ctxt->context, arg);  | 
7530  | 3.22M  |     CAST_TO_NUMBER;  | 
7531  | 3.22M  |     CHECK_TYPE(XPATH_NUMBER);  | 
7532  | 3.22M  |     ctxt->value->floatval -= val;  | 
7533  | 3.22M  | }  | 
7534  |  |  | 
7535  |  | /**  | 
7536  |  |  * xmlXPathMultValues:  | 
7537  |  |  * @ctxt:  the XPath Parser context  | 
7538  |  |  *  | 
7539  |  |  * Implement the multiply operation on XPath objects:  | 
7540  |  |  * The numeric operators convert their operands to numbers as if  | 
7541  |  |  * by calling the number function.  | 
7542  |  |  */  | 
7543  |  | void  | 
7544  | 4.13M  | xmlXPathMultValues(xmlXPathParserContextPtr ctxt) { | 
7545  | 4.13M  |     xmlXPathObjectPtr arg;  | 
7546  | 4.13M  |     double val;  | 
7547  |  |  | 
7548  | 4.13M  |     arg = valuePop(ctxt);  | 
7549  | 4.13M  |     if (arg == NULL)  | 
7550  | 4.13M  |   XP_ERROR(XPATH_INVALID_OPERAND);  | 
7551  | 4.13M  |     val = xmlXPathCastToNumber(arg);  | 
7552  | 4.13M  |     xmlXPathReleaseObject(ctxt->context, arg);  | 
7553  | 4.13M  |     CAST_TO_NUMBER;  | 
7554  | 4.13M  |     CHECK_TYPE(XPATH_NUMBER);  | 
7555  | 4.13M  |     ctxt->value->floatval *= val;  | 
7556  | 4.13M  | }  | 
7557  |  |  | 
7558  |  | /**  | 
7559  |  |  * xmlXPathDivValues:  | 
7560  |  |  * @ctxt:  the XPath Parser context  | 
7561  |  |  *  | 
7562  |  |  * Implement the div operation on XPath objects @arg1 / @arg2:  | 
7563  |  |  * The numeric operators convert their operands to numbers as if  | 
7564  |  |  * by calling the number function.  | 
7565  |  |  */  | 
7566  |  | ATTRIBUTE_NO_SANITIZE("float-divide-by-zero") | 
7567  |  | void  | 
7568  | 415k  | xmlXPathDivValues(xmlXPathParserContextPtr ctxt) { | 
7569  | 415k  |     xmlXPathObjectPtr arg;  | 
7570  | 415k  |     double val;  | 
7571  |  |  | 
7572  | 415k  |     arg = valuePop(ctxt);  | 
7573  | 415k  |     if (arg == NULL)  | 
7574  | 415k  |   XP_ERROR(XPATH_INVALID_OPERAND);  | 
7575  | 415k  |     val = xmlXPathCastToNumber(arg);  | 
7576  | 415k  |     xmlXPathReleaseObject(ctxt->context, arg);  | 
7577  | 415k  |     CAST_TO_NUMBER;  | 
7578  | 415k  |     CHECK_TYPE(XPATH_NUMBER);  | 
7579  | 415k  |     ctxt->value->floatval /= val;  | 
7580  | 415k  | }  | 
7581  |  |  | 
7582  |  | /**  | 
7583  |  |  * xmlXPathModValues:  | 
7584  |  |  * @ctxt:  the XPath Parser context  | 
7585  |  |  *  | 
7586  |  |  * Implement the mod operation on XPath objects: @arg1 / @arg2  | 
7587  |  |  * The numeric operators convert their operands to numbers as if  | 
7588  |  |  * by calling the number function.  | 
7589  |  |  */  | 
7590  |  | void  | 
7591  | 91.9k  | xmlXPathModValues(xmlXPathParserContextPtr ctxt) { | 
7592  | 91.9k  |     xmlXPathObjectPtr arg;  | 
7593  | 91.9k  |     double arg1, arg2;  | 
7594  |  |  | 
7595  | 91.9k  |     arg = valuePop(ctxt);  | 
7596  | 91.9k  |     if (arg == NULL)  | 
7597  | 91.9k  |   XP_ERROR(XPATH_INVALID_OPERAND);  | 
7598  | 91.9k  |     arg2 = xmlXPathCastToNumber(arg);  | 
7599  | 91.9k  |     xmlXPathReleaseObject(ctxt->context, arg);  | 
7600  | 91.9k  |     CAST_TO_NUMBER;  | 
7601  | 91.9k  |     CHECK_TYPE(XPATH_NUMBER);  | 
7602  | 91.9k  |     arg1 = ctxt->value->floatval;  | 
7603  | 91.9k  |     if (arg2 == 0)  | 
7604  | 7.52k  |   ctxt->value->floatval = xmlXPathNAN;  | 
7605  | 84.3k  |     else { | 
7606  | 84.3k  |   ctxt->value->floatval = fmod(arg1, arg2);  | 
7607  | 84.3k  |     }  | 
7608  | 91.9k  | }  | 
7609  |  |  | 
7610  |  | /************************************************************************  | 
7611  |  |  *                  *  | 
7612  |  |  *    The traversal functions         *  | 
7613  |  |  *                  *  | 
7614  |  |  ************************************************************************/  | 
7615  |  |  | 
7616  |  | /*  | 
7617  |  |  * A traversal function enumerates nodes along an axis.  | 
7618  |  |  * Initially it must be called with NULL, and it indicates  | 
7619  |  |  * termination on the axis by returning NULL.  | 
7620  |  |  */  | 
7621  |  | typedef xmlNodePtr (*xmlXPathTraversalFunction)  | 
7622  |  |                     (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);  | 
7623  |  |  | 
7624  |  | /*  | 
7625  |  |  * xmlXPathTraversalFunctionExt:  | 
7626  |  |  * A traversal function enumerates nodes along an axis.  | 
7627  |  |  * Initially it must be called with NULL, and it indicates  | 
7628  |  |  * termination on the axis by returning NULL.  | 
7629  |  |  * The context node of the traversal is specified via @contextNode.  | 
7630  |  |  */  | 
7631  |  | typedef xmlNodePtr (*xmlXPathTraversalFunctionExt)  | 
7632  |  |                     (xmlNodePtr cur, xmlNodePtr contextNode);  | 
7633  |  |  | 
7634  |  | /*  | 
7635  |  |  * xmlXPathNodeSetMergeFunction:  | 
7636  |  |  * Used for merging node sets in xmlXPathCollectAndTest().  | 
7637  |  |  */  | 
7638  |  | typedef xmlNodeSetPtr (*xmlXPathNodeSetMergeFunction)  | 
7639  |  |         (xmlNodeSetPtr, xmlNodeSetPtr);  | 
7640  |  |  | 
7641  |  |  | 
7642  |  | /**  | 
7643  |  |  * xmlXPathNextSelf:  | 
7644  |  |  * @ctxt:  the XPath Parser context  | 
7645  |  |  * @cur:  the current node in the traversal  | 
7646  |  |  *  | 
7647  |  |  * Traversal function for the "self" direction  | 
7648  |  |  * The self axis contains just the context node itself  | 
7649  |  |  *  | 
7650  |  |  * Returns the next element following that axis  | 
7651  |  |  */  | 
7652  |  | xmlNodePtr  | 
7653  | 63.5k  | xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { | 
7654  | 63.5k  |     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);  | 
7655  | 63.5k  |     if (cur == NULL)  | 
7656  | 33.8k  |         return(ctxt->context->node);  | 
7657  | 29.7k  |     return(NULL);  | 
7658  | 63.5k  | }  | 
7659  |  |  | 
7660  |  | /**  | 
7661  |  |  * xmlXPathNextChild:  | 
7662  |  |  * @ctxt:  the XPath Parser context  | 
7663  |  |  * @cur:  the current node in the traversal  | 
7664  |  |  *  | 
7665  |  |  * Traversal function for the "child" direction  | 
7666  |  |  * The child axis contains the children of the context node in document order.  | 
7667  |  |  *  | 
7668  |  |  * Returns the next element following that axis  | 
7669  |  |  */  | 
7670  |  | xmlNodePtr  | 
7671  | 2.96M  | xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { | 
7672  | 2.96M  |     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);  | 
7673  | 2.96M  |     if (cur == NULL) { | 
7674  | 1.63M  |   if (ctxt->context->node == NULL) return(NULL);  | 
7675  | 1.63M  |   switch (ctxt->context->node->type) { | 
7676  | 549k  |             case XML_ELEMENT_NODE:  | 
7677  | 1.37M  |             case XML_TEXT_NODE:  | 
7678  | 1.41M  |             case XML_CDATA_SECTION_NODE:  | 
7679  | 1.41M  |             case XML_ENTITY_REF_NODE:  | 
7680  | 1.41M  |             case XML_ENTITY_NODE:  | 
7681  | 1.48M  |             case XML_PI_NODE:  | 
7682  | 1.55M  |             case XML_COMMENT_NODE:  | 
7683  | 1.55M  |             case XML_NOTATION_NODE:  | 
7684  | 1.55M  |             case XML_DTD_NODE:  | 
7685  | 1.55M  |     return(ctxt->context->node->children);  | 
7686  | 65.3k  |             case XML_DOCUMENT_NODE:  | 
7687  | 65.3k  |             case XML_DOCUMENT_TYPE_NODE:  | 
7688  | 65.3k  |             case XML_DOCUMENT_FRAG_NODE:  | 
7689  | 65.3k  |             case XML_HTML_DOCUMENT_NODE:  | 
7690  | 65.3k  |     return(((xmlDocPtr) ctxt->context->node)->children);  | 
7691  | 0  |       case XML_ELEMENT_DECL:  | 
7692  | 0  |       case XML_ATTRIBUTE_DECL:  | 
7693  | 0  |       case XML_ENTITY_DECL:  | 
7694  | 5.96k  |             case XML_ATTRIBUTE_NODE:  | 
7695  | 12.4k  |       case XML_NAMESPACE_DECL:  | 
7696  | 12.4k  |       case XML_XINCLUDE_START:  | 
7697  | 12.4k  |       case XML_XINCLUDE_END:  | 
7698  | 12.4k  |     return(NULL);  | 
7699  | 1.63M  |   }  | 
7700  | 0  |   return(NULL);  | 
7701  | 1.63M  |     }  | 
7702  | 1.33M  |     if ((cur->type == XML_DOCUMENT_NODE) ||  | 
7703  | 1.33M  |         (cur->type == XML_HTML_DOCUMENT_NODE))  | 
7704  | 0  |   return(NULL);  | 
7705  | 1.33M  |     return(cur->next);  | 
7706  | 1.33M  | }  | 
7707  |  |  | 
7708  |  | /**  | 
7709  |  |  * xmlXPathNextChildElement:  | 
7710  |  |  * @ctxt:  the XPath Parser context  | 
7711  |  |  * @cur:  the current node in the traversal  | 
7712  |  |  *  | 
7713  |  |  * Traversal function for the "child" direction and nodes of type element.  | 
7714  |  |  * The child axis contains the children of the context node in document order.  | 
7715  |  |  *  | 
7716  |  |  * Returns the next element following that axis  | 
7717  |  |  */  | 
7718  |  | static xmlNodePtr  | 
7719  | 38.3M  | xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { | 
7720  | 38.3M  |     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);  | 
7721  | 38.3M  |     if (cur == NULL) { | 
7722  | 23.0M  |   cur = ctxt->context->node;  | 
7723  | 23.0M  |   if (cur == NULL) return(NULL);  | 
7724  |  |   /*  | 
7725  |  |   * Get the first element child.  | 
7726  |  |   */  | 
7727  | 23.0M  |   switch (cur->type) { | 
7728  | 12.8M  |             case XML_ELEMENT_NODE:  | 
7729  | 12.8M  |       case XML_DOCUMENT_FRAG_NODE:  | 
7730  | 12.8M  |       case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */  | 
7731  | 12.8M  |             case XML_ENTITY_NODE:  | 
7732  | 12.8M  |     cur = cur->children;  | 
7733  | 12.8M  |     if (cur != NULL) { | 
7734  | 9.88M  |         if (cur->type == XML_ELEMENT_NODE)  | 
7735  | 0  |       return(cur);  | 
7736  | 9.88M  |         do { | 
7737  | 9.88M  |       cur = cur->next;  | 
7738  | 9.88M  |         } while ((cur != NULL) &&  | 
7739  | 9.88M  |       (cur->type != XML_ELEMENT_NODE));  | 
7740  | 9.88M  |         return(cur);  | 
7741  | 9.88M  |     }  | 
7742  | 2.99M  |     return(NULL);  | 
7743  | 2.37M  |             case XML_DOCUMENT_NODE:  | 
7744  | 2.37M  |             case XML_HTML_DOCUMENT_NODE:  | 
7745  | 2.37M  |     return(xmlDocGetRootElement((xmlDocPtr) cur));  | 
7746  | 7.77M  |       default:  | 
7747  | 7.77M  |     return(NULL);  | 
7748  | 23.0M  |   }  | 
7749  | 0  |   return(NULL);  | 
7750  | 23.0M  |     }  | 
7751  |  |     /*  | 
7752  |  |     * Get the next sibling element node.  | 
7753  |  |     */  | 
7754  | 15.2M  |     switch (cur->type) { | 
7755  | 15.2M  |   case XML_ELEMENT_NODE:  | 
7756  | 15.2M  |   case XML_TEXT_NODE:  | 
7757  | 15.2M  |   case XML_ENTITY_REF_NODE:  | 
7758  | 15.2M  |   case XML_ENTITY_NODE:  | 
7759  | 15.2M  |   case XML_CDATA_SECTION_NODE:  | 
7760  | 15.2M  |   case XML_PI_NODE:  | 
7761  | 15.2M  |   case XML_COMMENT_NODE:  | 
7762  | 15.2M  |   case XML_XINCLUDE_END:  | 
7763  | 15.2M  |       break;  | 
7764  |  |   /* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */  | 
7765  | 0  |   default:  | 
7766  | 0  |       return(NULL);  | 
7767  | 15.2M  |     }  | 
7768  | 15.2M  |     if (cur->next != NULL) { | 
7769  | 12.9M  |   if (cur->next->type == XML_ELEMENT_NODE)  | 
7770  | 700k  |       return(cur->next);  | 
7771  | 12.2M  |   cur = cur->next;  | 
7772  | 19.2M  |   do { | 
7773  | 19.2M  |       cur = cur->next;  | 
7774  | 19.2M  |   } while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE));  | 
7775  | 12.2M  |   return(cur);  | 
7776  | 12.9M  |     }  | 
7777  | 2.30M  |     return(NULL);  | 
7778  | 15.2M  | }  | 
7779  |  |  | 
7780  |  | #if 0  | 
7781  |  | /**  | 
7782  |  |  * xmlXPathNextDescendantOrSelfElemParent:  | 
7783  |  |  * @ctxt:  the XPath Parser context  | 
7784  |  |  * @cur:  the current node in the traversal  | 
7785  |  |  *  | 
7786  |  |  * Traversal function for the "descendant-or-self" axis.  | 
7787  |  |  * Additionally it returns only nodes which can be parents of  | 
7788  |  |  * element nodes.  | 
7789  |  |  *  | 
7790  |  |  *  | 
7791  |  |  * Returns the next element following that axis  | 
7792  |  |  */  | 
7793  |  | static xmlNodePtr  | 
7794  |  | xmlXPathNextDescendantOrSelfElemParent(xmlNodePtr cur,  | 
7795  |  |                xmlNodePtr contextNode)  | 
7796  |  | { | 
7797  |  |     if (cur == NULL) { | 
7798  |  |   if (contextNode == NULL)  | 
7799  |  |       return(NULL);  | 
7800  |  |   switch (contextNode->type) { | 
7801  |  |       case XML_ELEMENT_NODE:  | 
7802  |  |       case XML_XINCLUDE_START:  | 
7803  |  |       case XML_DOCUMENT_FRAG_NODE:  | 
7804  |  |       case XML_DOCUMENT_NODE:  | 
7805  |  |       case XML_HTML_DOCUMENT_NODE:  | 
7806  |  |     return(contextNode);  | 
7807  |  |       default:  | 
7808  |  |     return(NULL);  | 
7809  |  |   }  | 
7810  |  |   return(NULL);  | 
7811  |  |     } else { | 
7812  |  |   xmlNodePtr start = cur;  | 
7813  |  |  | 
7814  |  |   while (cur != NULL) { | 
7815  |  |       switch (cur->type) { | 
7816  |  |     case XML_ELEMENT_NODE:  | 
7817  |  |     /* TODO: OK to have XInclude here? */  | 
7818  |  |     case XML_XINCLUDE_START:  | 
7819  |  |     case XML_DOCUMENT_FRAG_NODE:  | 
7820  |  |         if (cur != start)  | 
7821  |  |       return(cur);  | 
7822  |  |         if (cur->children != NULL) { | 
7823  |  |       cur = cur->children;  | 
7824  |  |       continue;  | 
7825  |  |         }  | 
7826  |  |         break;  | 
7827  |  |     /* Not sure if we need those here. */  | 
7828  |  |     case XML_DOCUMENT_NODE:  | 
7829  |  |     case XML_HTML_DOCUMENT_NODE:  | 
7830  |  |         if (cur != start)  | 
7831  |  |       return(cur);  | 
7832  |  |         return(xmlDocGetRootElement((xmlDocPtr) cur));  | 
7833  |  |     default:  | 
7834  |  |         break;  | 
7835  |  |       }  | 
7836  |  |  | 
7837  |  | next_sibling:  | 
7838  |  |       if ((cur == NULL) || (cur == contextNode))  | 
7839  |  |     return(NULL);  | 
7840  |  |       if (cur->next != NULL) { | 
7841  |  |     cur = cur->next;  | 
7842  |  |       } else { | 
7843  |  |     cur = cur->parent;  | 
7844  |  |     goto next_sibling;  | 
7845  |  |       }  | 
7846  |  |   }  | 
7847  |  |     }  | 
7848  |  |     return(NULL);  | 
7849  |  | }  | 
7850  |  | #endif  | 
7851  |  |  | 
7852  |  | /**  | 
7853  |  |  * xmlXPathNextDescendant:  | 
7854  |  |  * @ctxt:  the XPath Parser context  | 
7855  |  |  * @cur:  the current node in the traversal  | 
7856  |  |  *  | 
7857  |  |  * Traversal function for the "descendant" direction  | 
7858  |  |  * the descendant axis contains the descendants of the context node in document  | 
7859  |  |  * order; a descendant is a child or a child of a child and so on.  | 
7860  |  |  *  | 
7861  |  |  * Returns the next element following that axis  | 
7862  |  |  */  | 
7863  |  | xmlNodePtr  | 
7864  | 202M  | xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { | 
7865  | 202M  |     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);  | 
7866  | 202M  |     if (cur == NULL) { | 
7867  | 9.29M  |   if (ctxt->context->node == NULL)  | 
7868  | 0  |       return(NULL);  | 
7869  | 9.29M  |   if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||  | 
7870  | 9.29M  |       (ctxt->context->node->type == XML_NAMESPACE_DECL))  | 
7871  | 67.5k  |       return(NULL);  | 
7872  |  |  | 
7873  | 9.22M  |         if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)  | 
7874  | 3.08M  |       return(ctxt->context->doc->children);  | 
7875  | 6.14M  |         return(ctxt->context->node->children);  | 
7876  | 9.22M  |     }  | 
7877  |  |  | 
7878  | 192M  |     if (cur->type == XML_NAMESPACE_DECL)  | 
7879  | 0  |         return(NULL);  | 
7880  | 192M  |     if (cur->children != NULL) { | 
7881  |  |   /*  | 
7882  |  |    * Do not descend on entities declarations  | 
7883  |  |    */  | 
7884  | 46.1M  |   if (cur->children->type != XML_ENTITY_DECL) { | 
7885  | 46.1M  |       cur = cur->children;  | 
7886  |  |       /*  | 
7887  |  |        * Skip DTDs  | 
7888  |  |        */  | 
7889  | 46.1M  |       if (cur->type != XML_DTD_NODE)  | 
7890  | 46.1M  |     return(cur);  | 
7891  | 46.1M  |   }  | 
7892  | 46.1M  |     }  | 
7893  |  |  | 
7894  | 146M  |     if (cur == ctxt->context->node) return(NULL);  | 
7895  |  |  | 
7896  | 146M  |     while (cur->next != NULL) { | 
7897  | 98.3M  |   cur = cur->next;  | 
7898  | 98.3M  |   if ((cur->type != XML_ENTITY_DECL) &&  | 
7899  | 98.3M  |       (cur->type != XML_DTD_NODE))  | 
7900  | 98.3M  |       return(cur);  | 
7901  | 98.3M  |     }  | 
7902  |  |  | 
7903  | 51.9M  |     do { | 
7904  | 51.9M  |         cur = cur->parent;  | 
7905  | 51.9M  |   if (cur == NULL) break;  | 
7906  | 51.9M  |   if (cur == ctxt->context->node) return(NULL);  | 
7907  | 43.3M  |   if (cur->next != NULL) { | 
7908  | 39.3M  |       cur = cur->next;  | 
7909  | 39.3M  |       return(cur);  | 
7910  | 39.3M  |   }  | 
7911  | 43.3M  |     } while (cur != NULL);  | 
7912  | 0  |     return(cur);  | 
7913  | 47.9M  | }  | 
7914  |  |  | 
7915  |  | /**  | 
7916  |  |  * xmlXPathNextDescendantOrSelf:  | 
7917  |  |  * @ctxt:  the XPath Parser context  | 
7918  |  |  * @cur:  the current node in the traversal  | 
7919  |  |  *  | 
7920  |  |  * Traversal function for the "descendant-or-self" direction  | 
7921  |  |  * the descendant-or-self axis contains the context node and the descendants  | 
7922  |  |  * of the context node in document order; thus the context node is the first  | 
7923  |  |  * node on the axis, and the first child of the context node is the second node  | 
7924  |  |  * on the axis  | 
7925  |  |  *  | 
7926  |  |  * Returns the next element following that axis  | 
7927  |  |  */  | 
7928  |  | xmlNodePtr  | 
7929  | 57.8M  | xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { | 
7930  | 57.8M  |     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);  | 
7931  | 57.8M  |     if (cur == NULL)  | 
7932  | 3.33M  |         return(ctxt->context->node);  | 
7933  |  |  | 
7934  | 54.5M  |     if (ctxt->context->node == NULL)  | 
7935  | 0  |         return(NULL);  | 
7936  | 54.5M  |     if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||  | 
7937  | 54.5M  |         (ctxt->context->node->type == XML_NAMESPACE_DECL))  | 
7938  | 93.6k  |         return(NULL);  | 
7939  |  |  | 
7940  | 54.4M  |     return(xmlXPathNextDescendant(ctxt, cur));  | 
7941  | 54.5M  | }  | 
7942  |  |  | 
7943  |  | /**  | 
7944  |  |  * xmlXPathNextParent:  | 
7945  |  |  * @ctxt:  the XPath Parser context  | 
7946  |  |  * @cur:  the current node in the traversal  | 
7947  |  |  *  | 
7948  |  |  * Traversal function for the "parent" direction  | 
7949  |  |  * The parent axis contains the parent of the context node, if there is one.  | 
7950  |  |  *  | 
7951  |  |  * Returns the next element following that axis  | 
7952  |  |  */  | 
7953  |  | xmlNodePtr  | 
7954  | 5.63M  | xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { | 
7955  | 5.63M  |     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);  | 
7956  |  |     /*  | 
7957  |  |      * the parent of an attribute or namespace node is the element  | 
7958  |  |      * to which the attribute or namespace node is attached  | 
7959  |  |      * Namespace handling !!!  | 
7960  |  |      */  | 
7961  | 5.63M  |     if (cur == NULL) { | 
7962  | 2.85M  |   if (ctxt->context->node == NULL) return(NULL);  | 
7963  | 2.85M  |   switch (ctxt->context->node->type) { | 
7964  | 1.04M  |             case XML_ELEMENT_NODE:  | 
7965  | 2.45M  |             case XML_TEXT_NODE:  | 
7966  | 2.51M  |             case XML_CDATA_SECTION_NODE:  | 
7967  | 2.51M  |             case XML_ENTITY_REF_NODE:  | 
7968  | 2.51M  |             case XML_ENTITY_NODE:  | 
7969  | 2.63M  |             case XML_PI_NODE:  | 
7970  | 2.75M  |             case XML_COMMENT_NODE:  | 
7971  | 2.75M  |             case XML_NOTATION_NODE:  | 
7972  | 2.75M  |             case XML_DTD_NODE:  | 
7973  | 2.75M  |       case XML_ELEMENT_DECL:  | 
7974  | 2.75M  |       case XML_ATTRIBUTE_DECL:  | 
7975  | 2.75M  |       case XML_XINCLUDE_START:  | 
7976  | 2.75M  |       case XML_XINCLUDE_END:  | 
7977  | 2.75M  |       case XML_ENTITY_DECL:  | 
7978  | 2.75M  |     if (ctxt->context->node->parent == NULL)  | 
7979  | 0  |         return((xmlNodePtr) ctxt->context->doc);  | 
7980  | 2.75M  |     if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&  | 
7981  | 2.75M  |         ((ctxt->context->node->parent->name[0] == ' ') ||  | 
7982  | 2.54M  |          (xmlStrEqual(ctxt->context->node->parent->name,  | 
7983  | 2.54M  |          BAD_CAST "fake node libxslt"))))  | 
7984  | 0  |         return(NULL);  | 
7985  | 2.75M  |     return(ctxt->context->node->parent);  | 
7986  | 17.8k  |             case XML_ATTRIBUTE_NODE: { | 
7987  | 17.8k  |     xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;  | 
7988  |  |  | 
7989  | 17.8k  |     return(att->parent);  | 
7990  | 2.75M  |       }  | 
7991  | 71.5k  |             case XML_DOCUMENT_NODE:  | 
7992  | 71.5k  |             case XML_DOCUMENT_TYPE_NODE:  | 
7993  | 71.5k  |             case XML_DOCUMENT_FRAG_NODE:  | 
7994  | 71.5k  |             case XML_HTML_DOCUMENT_NODE:  | 
7995  | 71.5k  |                 return(NULL);  | 
7996  | 14.2k  |       case XML_NAMESPACE_DECL: { | 
7997  | 14.2k  |     xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;  | 
7998  |  |  | 
7999  | 14.2k  |     if ((ns->next != NULL) &&  | 
8000  | 14.2k  |         (ns->next->type != XML_NAMESPACE_DECL))  | 
8001  | 14.2k  |         return((xmlNodePtr) ns->next);  | 
8002  | 0  |                 return(NULL);  | 
8003  | 14.2k  |       }  | 
8004  | 2.85M  |   }  | 
8005  | 2.85M  |     }  | 
8006  | 2.77M  |     return(NULL);  | 
8007  | 5.63M  | }  | 
8008  |  |  | 
8009  |  | /**  | 
8010  |  |  * xmlXPathNextAncestor:  | 
8011  |  |  * @ctxt:  the XPath Parser context  | 
8012  |  |  * @cur:  the current node in the traversal  | 
8013  |  |  *  | 
8014  |  |  * Traversal function for the "ancestor" direction  | 
8015  |  |  * the ancestor axis contains the ancestors of the context node; the ancestors  | 
8016  |  |  * of the context node consist of the parent of context node and the parent's  | 
8017  |  |  * parent and so on; the nodes are ordered in reverse document order; thus the  | 
8018  |  |  * parent is the first node on the axis, and the parent's parent is the second  | 
8019  |  |  * node on the axis  | 
8020  |  |  *  | 
8021  |  |  * Returns the next element following that axis  | 
8022  |  |  */  | 
8023  |  | xmlNodePtr  | 
8024  | 11.3M  | xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { | 
8025  | 11.3M  |     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);  | 
8026  |  |     /*  | 
8027  |  |      * the parent of an attribute or namespace node is the element  | 
8028  |  |      * to which the attribute or namespace node is attached  | 
8029  |  |      * !!!!!!!!!!!!!  | 
8030  |  |      */  | 
8031  | 11.3M  |     if (cur == NULL) { | 
8032  | 2.26M  |   if (ctxt->context->node == NULL) return(NULL);  | 
8033  | 2.26M  |   switch (ctxt->context->node->type) { | 
8034  | 900k  |             case XML_ELEMENT_NODE:  | 
8035  | 2.08M  |             case XML_TEXT_NODE:  | 
8036  | 2.12M  |             case XML_CDATA_SECTION_NODE:  | 
8037  | 2.12M  |             case XML_ENTITY_REF_NODE:  | 
8038  | 2.12M  |             case XML_ENTITY_NODE:  | 
8039  | 2.16M  |             case XML_PI_NODE:  | 
8040  | 2.23M  |             case XML_COMMENT_NODE:  | 
8041  | 2.23M  |       case XML_DTD_NODE:  | 
8042  | 2.23M  |       case XML_ELEMENT_DECL:  | 
8043  | 2.23M  |       case XML_ATTRIBUTE_DECL:  | 
8044  | 2.23M  |       case XML_ENTITY_DECL:  | 
8045  | 2.23M  |             case XML_NOTATION_NODE:  | 
8046  | 2.23M  |       case XML_XINCLUDE_START:  | 
8047  | 2.23M  |       case XML_XINCLUDE_END:  | 
8048  | 2.23M  |     if (ctxt->context->node->parent == NULL)  | 
8049  | 0  |         return((xmlNodePtr) ctxt->context->doc);  | 
8050  | 2.23M  |     if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&  | 
8051  | 2.23M  |         ((ctxt->context->node->parent->name[0] == ' ') ||  | 
8052  | 1.65M  |          (xmlStrEqual(ctxt->context->node->parent->name,  | 
8053  | 1.65M  |          BAD_CAST "fake node libxslt"))))  | 
8054  | 0  |         return(NULL);  | 
8055  | 2.23M  |     return(ctxt->context->node->parent);  | 
8056  | 4.02k  |             case XML_ATTRIBUTE_NODE: { | 
8057  | 4.02k  |     xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;  | 
8058  |  |  | 
8059  | 4.02k  |     return(tmp->parent);  | 
8060  | 2.23M  |       }  | 
8061  | 24.5k  |             case XML_DOCUMENT_NODE:  | 
8062  | 24.5k  |             case XML_DOCUMENT_TYPE_NODE:  | 
8063  | 24.5k  |             case XML_DOCUMENT_FRAG_NODE:  | 
8064  | 24.5k  |             case XML_HTML_DOCUMENT_NODE:  | 
8065  | 24.5k  |                 return(NULL);  | 
8066  | 8.51k  |       case XML_NAMESPACE_DECL: { | 
8067  | 8.51k  |     xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;  | 
8068  |  |  | 
8069  | 8.51k  |     if ((ns->next != NULL) &&  | 
8070  | 8.51k  |         (ns->next->type != XML_NAMESPACE_DECL))  | 
8071  | 8.51k  |         return((xmlNodePtr) ns->next);  | 
8072  |  |     /* Bad, how did that namespace end up here ? */  | 
8073  | 0  |                 return(NULL);  | 
8074  | 8.51k  |       }  | 
8075  | 2.26M  |   }  | 
8076  | 0  |   return(NULL);  | 
8077  | 2.26M  |     }  | 
8078  | 9.07M  |     if (cur == ctxt->context->doc->children)  | 
8079  | 26.8k  |   return((xmlNodePtr) ctxt->context->doc);  | 
8080  | 9.04M  |     if (cur == (xmlNodePtr) ctxt->context->doc)  | 
8081  | 3.33M  |   return(NULL);  | 
8082  | 5.71M  |     switch (cur->type) { | 
8083  | 4.92M  |   case XML_ELEMENT_NODE:  | 
8084  | 5.54M  |   case XML_TEXT_NODE:  | 
8085  | 5.57M  |   case XML_CDATA_SECTION_NODE:  | 
8086  | 5.57M  |   case XML_ENTITY_REF_NODE:  | 
8087  | 5.57M  |   case XML_ENTITY_NODE:  | 
8088  | 5.60M  |   case XML_PI_NODE:  | 
8089  | 5.65M  |   case XML_COMMENT_NODE:  | 
8090  | 5.65M  |   case XML_NOTATION_NODE:  | 
8091  | 5.65M  |   case XML_DTD_NODE:  | 
8092  | 5.65M  |         case XML_ELEMENT_DECL:  | 
8093  | 5.65M  |         case XML_ATTRIBUTE_DECL:  | 
8094  | 5.65M  |         case XML_ENTITY_DECL:  | 
8095  | 5.65M  |   case XML_XINCLUDE_START:  | 
8096  | 5.65M  |   case XML_XINCLUDE_END:  | 
8097  | 5.65M  |       if (cur->parent == NULL)  | 
8098  | 0  |     return(NULL);  | 
8099  | 5.65M  |       if ((cur->parent->type == XML_ELEMENT_NODE) &&  | 
8100  | 5.65M  |     ((cur->parent->name[0] == ' ') ||  | 
8101  | 2.89M  |      (xmlStrEqual(cur->parent->name,  | 
8102  | 2.89M  |             BAD_CAST "fake node libxslt"))))  | 
8103  | 0  |     return(NULL);  | 
8104  | 5.65M  |       return(cur->parent);  | 
8105  | 3.12k  |   case XML_ATTRIBUTE_NODE: { | 
8106  | 3.12k  |       xmlAttrPtr att = (xmlAttrPtr) cur;  | 
8107  |  |  | 
8108  | 3.12k  |       return(att->parent);  | 
8109  | 5.65M  |   }  | 
8110  | 5.29k  |   case XML_NAMESPACE_DECL: { | 
8111  | 5.29k  |       xmlNsPtr ns = (xmlNsPtr) cur;  | 
8112  |  |  | 
8113  | 5.29k  |       if ((ns->next != NULL) &&  | 
8114  | 5.29k  |           (ns->next->type != XML_NAMESPACE_DECL))  | 
8115  | 5.29k  |           return((xmlNodePtr) ns->next);  | 
8116  |  |       /* Bad, how did that namespace end up here ? */  | 
8117  | 0  |             return(NULL);  | 
8118  | 5.29k  |   }  | 
8119  | 45.4k  |   case XML_DOCUMENT_NODE:  | 
8120  | 45.4k  |   case XML_DOCUMENT_TYPE_NODE:  | 
8121  | 45.4k  |   case XML_DOCUMENT_FRAG_NODE:  | 
8122  | 45.4k  |   case XML_HTML_DOCUMENT_NODE:  | 
8123  | 45.4k  |       return(NULL);  | 
8124  | 5.71M  |     }  | 
8125  | 0  |     return(NULL);  | 
8126  | 5.71M  | }  | 
8127  |  |  | 
8128  |  | /**  | 
8129  |  |  * xmlXPathNextAncestorOrSelf:  | 
8130  |  |  * @ctxt:  the XPath Parser context  | 
8131  |  |  * @cur:  the current node in the traversal  | 
8132  |  |  *  | 
8133  |  |  * Traversal function for the "ancestor-or-self" direction  | 
8134  |  |  * he ancestor-or-self axis contains the context node and ancestors of  | 
8135  |  |  * the context node in reverse document order; thus the context node is  | 
8136  |  |  * the first node on the axis, and the context node's parent the second;  | 
8137  |  |  * parent here is defined the same as with the parent axis.  | 
8138  |  |  *  | 
8139  |  |  * Returns the next element following that axis  | 
8140  |  |  */  | 
8141  |  | xmlNodePtr  | 
8142  | 5.36M  | xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { | 
8143  | 5.36M  |     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);  | 
8144  | 5.36M  |     if (cur == NULL)  | 
8145  | 1.15M  |         return(ctxt->context->node);  | 
8146  | 4.20M  |     return(xmlXPathNextAncestor(ctxt, cur));  | 
8147  | 5.36M  | }  | 
8148  |  |  | 
8149  |  | /**  | 
8150  |  |  * xmlXPathNextFollowingSibling:  | 
8151  |  |  * @ctxt:  the XPath Parser context  | 
8152  |  |  * @cur:  the current node in the traversal  | 
8153  |  |  *  | 
8154  |  |  * Traversal function for the "following-sibling" direction  | 
8155  |  |  * The following-sibling axis contains the following siblings of the context  | 
8156  |  |  * node in document order.  | 
8157  |  |  *  | 
8158  |  |  * Returns the next element following that axis  | 
8159  |  |  */  | 
8160  |  | xmlNodePtr  | 
8161  | 379k  | xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { | 
8162  | 379k  |     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);  | 
8163  | 379k  |     if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||  | 
8164  | 379k  |   (ctxt->context->node->type == XML_NAMESPACE_DECL))  | 
8165  | 6.59k  |   return(NULL);  | 
8166  | 373k  |     if (cur == (xmlNodePtr) ctxt->context->doc)  | 
8167  | 0  |         return(NULL);  | 
8168  | 373k  |     if (cur == NULL)  | 
8169  | 77.1k  |         return(ctxt->context->node->next);  | 
8170  | 296k  |     return(cur->next);  | 
8171  | 373k  | }  | 
8172  |  |  | 
8173  |  | /**  | 
8174  |  |  * xmlXPathNextPrecedingSibling:  | 
8175  |  |  * @ctxt:  the XPath Parser context  | 
8176  |  |  * @cur:  the current node in the traversal  | 
8177  |  |  *  | 
8178  |  |  * Traversal function for the "preceding-sibling" direction  | 
8179  |  |  * The preceding-sibling axis contains the preceding siblings of the context  | 
8180  |  |  * node in reverse document order; the first preceding sibling is first on the  | 
8181  |  |  * axis; the sibling preceding that node is the second on the axis and so on.  | 
8182  |  |  *  | 
8183  |  |  * Returns the next element following that axis  | 
8184  |  |  */  | 
8185  |  | xmlNodePtr  | 
8186  | 785k  | xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { | 
8187  | 785k  |     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);  | 
8188  | 785k  |     if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||  | 
8189  | 785k  |   (ctxt->context->node->type == XML_NAMESPACE_DECL))  | 
8190  | 3.64k  |   return(NULL);  | 
8191  | 781k  |     if (cur == (xmlNodePtr) ctxt->context->doc)  | 
8192  | 0  |         return(NULL);  | 
8193  | 781k  |     if (cur == NULL)  | 
8194  | 164k  |         return(ctxt->context->node->prev);  | 
8195  | 616k  |     if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) { | 
8196  | 0  |   cur = cur->prev;  | 
8197  | 0  |   if (cur == NULL)  | 
8198  | 0  |       return(ctxt->context->node->prev);  | 
8199  | 0  |     }  | 
8200  | 616k  |     return(cur->prev);  | 
8201  | 616k  | }  | 
8202  |  |  | 
8203  |  | /**  | 
8204  |  |  * xmlXPathNextFollowing:  | 
8205  |  |  * @ctxt:  the XPath Parser context  | 
8206  |  |  * @cur:  the current node in the traversal  | 
8207  |  |  *  | 
8208  |  |  * Traversal function for the "following" direction  | 
8209  |  |  * The following axis contains all nodes in the same document as the context  | 
8210  |  |  * node that are after the context node in document order, excluding any  | 
8211  |  |  * descendants and excluding attribute nodes and namespace nodes; the nodes  | 
8212  |  |  * are ordered in document order  | 
8213  |  |  *  | 
8214  |  |  * Returns the next element following that axis  | 
8215  |  |  */  | 
8216  |  | xmlNodePtr  | 
8217  | 14.6M  | xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { | 
8218  | 14.6M  |     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);  | 
8219  | 14.6M  |     if ((cur != NULL) && (cur->type  != XML_ATTRIBUTE_NODE) &&  | 
8220  | 14.6M  |         (cur->type != XML_NAMESPACE_DECL) && (cur->children != NULL))  | 
8221  | 2.30M  |         return(cur->children);  | 
8222  |  |  | 
8223  | 12.3M  |     if (cur == NULL) { | 
8224  | 902k  |         cur = ctxt->context->node;  | 
8225  | 902k  |         if (cur->type == XML_ATTRIBUTE_NODE) { | 
8226  | 3.67k  |             cur = cur->parent;  | 
8227  | 898k  |         } else if (cur->type == XML_NAMESPACE_DECL) { | 
8228  | 2.41k  |             xmlNsPtr ns = (xmlNsPtr) cur;  | 
8229  |  |  | 
8230  | 2.41k  |             if ((ns->next == NULL) ||  | 
8231  | 2.41k  |                 (ns->next->type == XML_NAMESPACE_DECL))  | 
8232  | 0  |                 return (NULL);  | 
8233  | 2.41k  |             cur = (xmlNodePtr) ns->next;  | 
8234  | 2.41k  |         }  | 
8235  | 902k  |     }  | 
8236  | 12.3M  |     if (cur == NULL) return(NULL) ; /* ERROR */  | 
8237  | 12.3M  |     if (cur->next != NULL) return(cur->next) ;  | 
8238  | 4.43M  |     do { | 
8239  | 4.43M  |         cur = cur->parent;  | 
8240  | 4.43M  |         if (cur == NULL) break;  | 
8241  | 4.41M  |         if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);  | 
8242  | 3.62M  |         if (cur->next != NULL) return(cur->next);  | 
8243  | 3.62M  |     } while (cur != NULL);  | 
8244  | 25.2k  |     return(cur);  | 
8245  | 3.67M  | }  | 
8246  |  |  | 
8247  |  | /*  | 
8248  |  |  * xmlXPathIsAncestor:  | 
8249  |  |  * @ancestor:  the ancestor node  | 
8250  |  |  * @node:  the current node  | 
8251  |  |  *  | 
8252  |  |  * Check that @ancestor is a @node's ancestor  | 
8253  |  |  *  | 
8254  |  |  * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.  | 
8255  |  |  */  | 
8256  |  | static int  | 
8257  | 0  | xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) { | 
8258  | 0  |     if ((ancestor == NULL) || (node == NULL)) return(0);  | 
8259  | 0  |     if (node->type == XML_NAMESPACE_DECL)  | 
8260  | 0  |         return(0);  | 
8261  | 0  |     if (ancestor->type == XML_NAMESPACE_DECL)  | 
8262  | 0  |         return(0);  | 
8263  |  |     /* nodes need to be in the same document */  | 
8264  | 0  |     if (ancestor->doc != node->doc) return(0);  | 
8265  |  |     /* avoid searching if ancestor or node is the root node */  | 
8266  | 0  |     if (ancestor == (xmlNodePtr) node->doc) return(1);  | 
8267  | 0  |     if (node == (xmlNodePtr) ancestor->doc) return(0);  | 
8268  | 0  |     while (node->parent != NULL) { | 
8269  | 0  |         if (node->parent == ancestor)  | 
8270  | 0  |             return(1);  | 
8271  | 0  |   node = node->parent;  | 
8272  | 0  |     }  | 
8273  | 0  |     return(0);  | 
8274  | 0  | }  | 
8275  |  |  | 
8276  |  | /**  | 
8277  |  |  * xmlXPathNextPreceding:  | 
8278  |  |  * @ctxt:  the XPath Parser context  | 
8279  |  |  * @cur:  the current node in the traversal  | 
8280  |  |  *  | 
8281  |  |  * Traversal function for the "preceding" direction  | 
8282  |  |  * the preceding axis contains all nodes in the same document as the context  | 
8283  |  |  * node that are before the context node in document order, excluding any  | 
8284  |  |  * ancestors and excluding attribute nodes and namespace nodes; the nodes are  | 
8285  |  |  * ordered in reverse document order  | 
8286  |  |  *  | 
8287  |  |  * Returns the next element following that axis  | 
8288  |  |  */  | 
8289  |  | xmlNodePtr  | 
8290  |  | xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)  | 
8291  | 0  | { | 
8292  | 0  |     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);  | 
8293  | 0  |     if (cur == NULL) { | 
8294  | 0  |         cur = ctxt->context->node;  | 
8295  | 0  |         if (cur->type == XML_ATTRIBUTE_NODE) { | 
8296  | 0  |             cur = cur->parent;  | 
8297  | 0  |         } else if (cur->type == XML_NAMESPACE_DECL) { | 
8298  | 0  |             xmlNsPtr ns = (xmlNsPtr) cur;  | 
8299  |  | 
  | 
8300  | 0  |             if ((ns->next == NULL) ||  | 
8301  | 0  |                 (ns->next->type == XML_NAMESPACE_DECL))  | 
8302  | 0  |                 return (NULL);  | 
8303  | 0  |             cur = (xmlNodePtr) ns->next;  | 
8304  | 0  |         }  | 
8305  | 0  |     }  | 
8306  | 0  |     if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL))  | 
8307  | 0  |   return (NULL);  | 
8308  | 0  |     if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))  | 
8309  | 0  |   cur = cur->prev;  | 
8310  | 0  |     do { | 
8311  | 0  |         if (cur->prev != NULL) { | 
8312  | 0  |             for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;  | 
8313  | 0  |             return (cur);  | 
8314  | 0  |         }  | 
8315  |  |  | 
8316  | 0  |         cur = cur->parent;  | 
8317  | 0  |         if (cur == NULL)  | 
8318  | 0  |             return (NULL);  | 
8319  | 0  |         if (cur == ctxt->context->doc->children)  | 
8320  | 0  |             return (NULL);  | 
8321  | 0  |     } while (xmlXPathIsAncestor(cur, ctxt->context->node));  | 
8322  | 0  |     return (cur);  | 
8323  | 0  | }  | 
8324  |  |  | 
8325  |  | /**  | 
8326  |  |  * xmlXPathNextPrecedingInternal:  | 
8327  |  |  * @ctxt:  the XPath Parser context  | 
8328  |  |  * @cur:  the current node in the traversal  | 
8329  |  |  *  | 
8330  |  |  * Traversal function for the "preceding" direction  | 
8331  |  |  * the preceding axis contains all nodes in the same document as the context  | 
8332  |  |  * node that are before the context node in document order, excluding any  | 
8333  |  |  * ancestors and excluding attribute nodes and namespace nodes; the nodes are  | 
8334  |  |  * ordered in reverse document order  | 
8335  |  |  * This is a faster implementation but internal only since it requires a  | 
8336  |  |  * state kept in the parser context: ctxt->ancestor.  | 
8337  |  |  *  | 
8338  |  |  * Returns the next element following that axis  | 
8339  |  |  */  | 
8340  |  | static xmlNodePtr  | 
8341  |  | xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,  | 
8342  |  |                               xmlNodePtr cur)  | 
8343  | 10.4M  | { | 
8344  | 10.4M  |     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);  | 
8345  | 10.4M  |     if (cur == NULL) { | 
8346  | 528k  |         cur = ctxt->context->node;  | 
8347  | 528k  |         if (cur == NULL)  | 
8348  | 0  |             return (NULL);  | 
8349  | 528k  |         if (cur->type == XML_ATTRIBUTE_NODE) { | 
8350  | 6.74k  |             cur = cur->parent;  | 
8351  | 521k  |         } else if (cur->type == XML_NAMESPACE_DECL) { | 
8352  | 4.15k  |             xmlNsPtr ns = (xmlNsPtr) cur;  | 
8353  |  |  | 
8354  | 4.15k  |             if ((ns->next == NULL) ||  | 
8355  | 4.15k  |                 (ns->next->type == XML_NAMESPACE_DECL))  | 
8356  | 0  |                 return (NULL);  | 
8357  | 4.15k  |             cur = (xmlNodePtr) ns->next;  | 
8358  | 4.15k  |         }  | 
8359  | 528k  |         ctxt->ancestor = cur->parent;  | 
8360  | 528k  |     }  | 
8361  | 10.4M  |     if (cur->type == XML_NAMESPACE_DECL)  | 
8362  | 0  |         return(NULL);  | 
8363  | 10.4M  |     if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))  | 
8364  | 0  |   cur = cur->prev;  | 
8365  | 11.8M  |     while (cur->prev == NULL) { | 
8366  | 4.61M  |         cur = cur->parent;  | 
8367  | 4.61M  |         if (cur == NULL)  | 
8368  | 499k  |             return (NULL);  | 
8369  | 4.11M  |         if (cur == ctxt->context->doc->children)  | 
8370  | 17.6k  |             return (NULL);  | 
8371  | 4.10M  |         if (cur != ctxt->ancestor)  | 
8372  | 2.78M  |             return (cur);  | 
8373  | 1.31M  |         ctxt->ancestor = cur->parent;  | 
8374  | 1.31M  |     }  | 
8375  | 7.20M  |     cur = cur->prev;  | 
8376  | 10.0M  |     while (cur->last != NULL)  | 
8377  | 2.80M  |         cur = cur->last;  | 
8378  | 7.20M  |     return (cur);  | 
8379  | 10.4M  | }  | 
8380  |  |  | 
8381  |  | /**  | 
8382  |  |  * xmlXPathNextNamespace:  | 
8383  |  |  * @ctxt:  the XPath Parser context  | 
8384  |  |  * @cur:  the current attribute in the traversal  | 
8385  |  |  *  | 
8386  |  |  * Traversal function for the "namespace" direction  | 
8387  |  |  * the namespace axis contains the namespace nodes of the context node;  | 
8388  |  |  * the order of nodes on this axis is implementation-defined; the axis will  | 
8389  |  |  * be empty unless the context node is an element  | 
8390  |  |  *  | 
8391  |  |  * We keep the XML namespace node at the end of the list.  | 
8392  |  |  *  | 
8393  |  |  * Returns the next element following that axis  | 
8394  |  |  */  | 
8395  |  | xmlNodePtr  | 
8396  | 3.69M  | xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { | 
8397  | 3.69M  |     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);  | 
8398  | 3.69M  |     if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);  | 
8399  | 2.39M  |     if (cur == NULL) { | 
8400  | 676k  |         if (ctxt->context->tmpNsList != NULL)  | 
8401  | 28.9k  |       xmlFree(ctxt->context->tmpNsList);  | 
8402  | 676k  |   ctxt->context->tmpNsList =  | 
8403  | 676k  |       xmlGetNsList(ctxt->context->doc, ctxt->context->node);  | 
8404  | 676k  |   ctxt->context->tmpNsNr = 0;  | 
8405  | 676k  |   if (ctxt->context->tmpNsList != NULL) { | 
8406  | 1.79M  |       while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) { | 
8407  | 1.13M  |     ctxt->context->tmpNsNr++;  | 
8408  | 1.13M  |       }  | 
8409  | 654k  |   }  | 
8410  | 676k  |   return((xmlNodePtr) xmlXPathXMLNamespace);  | 
8411  | 676k  |     }  | 
8412  | 1.72M  |     if (ctxt->context->tmpNsNr > 0) { | 
8413  | 1.08M  |   return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];  | 
8414  | 1.08M  |     } else { | 
8415  | 634k  |   if (ctxt->context->tmpNsList != NULL)  | 
8416  | 614k  |       xmlFree(ctxt->context->tmpNsList);  | 
8417  | 634k  |   ctxt->context->tmpNsList = NULL;  | 
8418  | 634k  |   return(NULL);  | 
8419  | 634k  |     }  | 
8420  | 1.72M  | }  | 
8421  |  |  | 
8422  |  | /**  | 
8423  |  |  * xmlXPathNextAttribute:  | 
8424  |  |  * @ctxt:  the XPath Parser context  | 
8425  |  |  * @cur:  the current attribute in the traversal  | 
8426  |  |  *  | 
8427  |  |  * Traversal function for the "attribute" direction  | 
8428  |  |  * TODO: support DTD inherited default attributes  | 
8429  |  |  *  | 
8430  |  |  * Returns the next element following that axis  | 
8431  |  |  */  | 
8432  |  | xmlNodePtr  | 
8433  | 18.1M  | xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { | 
8434  | 18.1M  |     if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);  | 
8435  | 18.1M  |     if (ctxt->context->node == NULL)  | 
8436  | 0  |   return(NULL);  | 
8437  | 18.1M  |     if (ctxt->context->node->type != XML_ELEMENT_NODE)  | 
8438  | 9.59M  |   return(NULL);  | 
8439  | 8.57M  |     if (cur == NULL) { | 
8440  | 4.93M  |         if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)  | 
8441  | 0  |       return(NULL);  | 
8442  | 4.93M  |         return((xmlNodePtr)ctxt->context->node->properties);  | 
8443  | 4.93M  |     }  | 
8444  | 3.63M  |     return((xmlNodePtr)cur->next);  | 
8445  | 8.57M  | }  | 
8446  |  |  | 
8447  |  | /************************************************************************  | 
8448  |  |  *                  *  | 
8449  |  |  *    NodeTest Functions          *  | 
8450  |  |  *                  *  | 
8451  |  |  ************************************************************************/  | 
8452  |  |  | 
8453  |  | #define IS_FUNCTION     200  | 
8454  |  |  | 
8455  |  |  | 
8456  |  | /************************************************************************  | 
8457  |  |  *                  *  | 
8458  |  |  *    Implicit tree core function library     *  | 
8459  |  |  *                  *  | 
8460  |  |  ************************************************************************/  | 
8461  |  |  | 
8462  |  | /**  | 
8463  |  |  * xmlXPathRoot:  | 
8464  |  |  * @ctxt:  the XPath Parser context  | 
8465  |  |  *  | 
8466  |  |  * Initialize the context to the root of the document  | 
8467  |  |  */  | 
8468  |  | void  | 
8469  | 8.49M  | xmlXPathRoot(xmlXPathParserContextPtr ctxt) { | 
8470  | 8.49M  |     if ((ctxt == NULL) || (ctxt->context == NULL))  | 
8471  | 0  |   return;  | 
8472  | 8.49M  |     valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,  | 
8473  | 8.49M  |   (xmlNodePtr) ctxt->context->doc));  | 
8474  | 8.49M  | }  | 
8475  |  |  | 
8476  |  | /************************************************************************  | 
8477  |  |  *                  *  | 
8478  |  |  *    The explicit core function library      *  | 
8479  |  |  *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *  | 
8480  |  |  *                  *  | 
8481  |  |  ************************************************************************/  | 
8482  |  |  | 
8483  |  |  | 
8484  |  | /**  | 
8485  |  |  * xmlXPathLastFunction:  | 
8486  |  |  * @ctxt:  the XPath Parser context  | 
8487  |  |  * @nargs:  the number of arguments  | 
8488  |  |  *  | 
8489  |  |  * Implement the last() XPath function  | 
8490  |  |  *    number last()  | 
8491  |  |  * The last function returns the number of nodes in the context node list.  | 
8492  |  |  */  | 
8493  |  | void  | 
8494  | 171k  | xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) { | 
8495  | 513k  |     CHECK_ARITY(0);  | 
8496  | 513k  |     if (ctxt->context->contextSize >= 0) { | 
8497  | 171k  |   valuePush(ctxt,  | 
8498  | 171k  |       xmlXPathCacheNewFloat(ctxt->context,  | 
8499  | 171k  |     (double) ctxt->context->contextSize));  | 
8500  |  | #ifdef DEBUG_EXPR  | 
8501  |  |   xmlGenericError(xmlGenericErrorContext,  | 
8502  |  |     "last() : %d\n", ctxt->context->contextSize);  | 
8503  |  | #endif  | 
8504  | 171k  |     } else { | 
8505  | 0  |   XP_ERROR(XPATH_INVALID_CTXT_SIZE);  | 
8506  | 0  |     }  | 
8507  | 513k  | }  | 
8508  |  |  | 
8509  |  | /**  | 
8510  |  |  * xmlXPathPositionFunction:  | 
8511  |  |  * @ctxt:  the XPath Parser context  | 
8512  |  |  * @nargs:  the number of arguments  | 
8513  |  |  *  | 
8514  |  |  * Implement the position() XPath function  | 
8515  |  |  *    number position()  | 
8516  |  |  * The position function returns the position of the context node in the  | 
8517  |  |  * context node list. The first position is 1, and so the last position  | 
8518  |  |  * will be equal to last().  | 
8519  |  |  */  | 
8520  |  | void  | 
8521  | 1.45k  | xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) { | 
8522  | 4.32k  |     CHECK_ARITY(0);  | 
8523  | 4.32k  |     if (ctxt->context->proximityPosition >= 0) { | 
8524  | 1.43k  |   valuePush(ctxt,  | 
8525  | 1.43k  |         xmlXPathCacheNewFloat(ctxt->context,  | 
8526  | 1.43k  |     (double) ctxt->context->proximityPosition));  | 
8527  |  | #ifdef DEBUG_EXPR  | 
8528  |  |   xmlGenericError(xmlGenericErrorContext, "position() : %d\n",  | 
8529  |  |     ctxt->context->proximityPosition);  | 
8530  |  | #endif  | 
8531  | 1.43k  |     } else { | 
8532  | 0  |   XP_ERROR(XPATH_INVALID_CTXT_POSITION);  | 
8533  | 0  |     }  | 
8534  | 4.32k  | }  | 
8535  |  |  | 
8536  |  | /**  | 
8537  |  |  * xmlXPathCountFunction:  | 
8538  |  |  * @ctxt:  the XPath Parser context  | 
8539  |  |  * @nargs:  the number of arguments  | 
8540  |  |  *  | 
8541  |  |  * Implement the count() XPath function  | 
8542  |  |  *    number count(node-set)  | 
8543  |  |  */  | 
8544  |  | void  | 
8545  | 10.4k  | xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) { | 
8546  | 10.4k  |     xmlXPathObjectPtr cur;  | 
8547  |  |  | 
8548  | 30.9k  |     CHECK_ARITY(1);  | 
8549  | 30.9k  |     if ((ctxt->value == NULL) ||  | 
8550  | 10.2k  |   ((ctxt->value->type != XPATH_NODESET) &&  | 
8551  | 10.2k  |    (ctxt->value->type != XPATH_XSLT_TREE)))  | 
8552  | 9.87k  |   XP_ERROR(XPATH_INVALID_TYPE);  | 
8553  | 9.87k  |     cur = valuePop(ctxt);  | 
8554  |  |  | 
8555  | 9.87k  |     if ((cur == NULL) || (cur->nodesetval == NULL))  | 
8556  | 3.66k  |   valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));  | 
8557  | 6.21k  |     else  | 
8558  | 6.21k  |   valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,  | 
8559  | 6.21k  |       (double) cur->nodesetval->nodeNr));  | 
8560  | 9.87k  |     xmlXPathReleaseObject(ctxt->context, cur);  | 
8561  | 9.87k  | }  | 
8562  |  |  | 
8563  |  | /**  | 
8564  |  |  * xmlXPathGetElementsByIds:  | 
8565  |  |  * @doc:  the document  | 
8566  |  |  * @ids:  a whitespace separated list of IDs  | 
8567  |  |  *  | 
8568  |  |  * Selects elements by their unique ID.  | 
8569  |  |  *  | 
8570  |  |  * Returns a node-set of selected elements.  | 
8571  |  |  */  | 
8572  |  | static xmlNodeSetPtr  | 
8573  | 125k  | xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) { | 
8574  | 125k  |     xmlNodeSetPtr ret;  | 
8575  | 125k  |     const xmlChar *cur = ids;  | 
8576  | 125k  |     xmlChar *ID;  | 
8577  | 125k  |     xmlAttrPtr attr;  | 
8578  | 125k  |     xmlNodePtr elem = NULL;  | 
8579  |  |  | 
8580  | 125k  |     if (ids == NULL) return(NULL);  | 
8581  |  |  | 
8582  | 125k  |     ret = xmlXPathNodeSetCreate(NULL);  | 
8583  | 125k  |     if (ret == NULL)  | 
8584  | 0  |         return(ret);  | 
8585  |  |  | 
8586  | 448k  |     while (IS_BLANK_CH(*cur)) cur++;  | 
8587  | 287k  |     while (*cur != 0) { | 
8588  | 1.79M  |   while ((!IS_BLANK_CH(*cur)) && (*cur != 0))  | 
8589  | 1.63M  |       cur++;  | 
8590  |  |  | 
8591  | 162k  |         ID = xmlStrndup(ids, cur - ids);  | 
8592  | 162k  |   if (ID != NULL) { | 
8593  |  |       /*  | 
8594  |  |        * We used to check the fact that the value passed  | 
8595  |  |        * was an NCName, but this generated much troubles for  | 
8596  |  |        * me and Aleksey Sanin, people blatantly violated that  | 
8597  |  |        * constraint, like Visa3D spec.  | 
8598  |  |        * if (xmlValidateNCName(ID, 1) == 0)  | 
8599  |  |        */  | 
8600  | 162k  |       attr = xmlGetID(doc, ID);  | 
8601  | 162k  |       if (attr != NULL) { | 
8602  | 0  |     if (attr->type == XML_ATTRIBUTE_NODE)  | 
8603  | 0  |         elem = attr->parent;  | 
8604  | 0  |     else if (attr->type == XML_ELEMENT_NODE)  | 
8605  | 0  |         elem = (xmlNodePtr) attr;  | 
8606  | 0  |     else  | 
8607  | 0  |         elem = NULL;  | 
8608  |  |                 /* TODO: Check memory error. */  | 
8609  | 0  |     if (elem != NULL)  | 
8610  | 0  |         xmlXPathNodeSetAdd(ret, elem);  | 
8611  | 0  |       }  | 
8612  | 162k  |       xmlFree(ID);  | 
8613  | 162k  |   }  | 
8614  |  |  | 
8615  | 1.08M  |   while (IS_BLANK_CH(*cur)) cur++;  | 
8616  | 162k  |   ids = cur;  | 
8617  | 162k  |     }  | 
8618  | 125k  |     return(ret);  | 
8619  | 125k  | }  | 
8620  |  |  | 
8621  |  | /**  | 
8622  |  |  * xmlXPathIdFunction:  | 
8623  |  |  * @ctxt:  the XPath Parser context  | 
8624  |  |  * @nargs:  the number of arguments  | 
8625  |  |  *  | 
8626  |  |  * Implement the id() XPath function  | 
8627  |  |  *    node-set id(object)  | 
8628  |  |  * The id function selects elements by their unique ID  | 
8629  |  |  * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,  | 
8630  |  |  * then the result is the union of the result of applying id to the  | 
8631  |  |  * string value of each of the nodes in the argument node-set. When the  | 
8632  |  |  * argument to id is of any other type, the argument is converted to a  | 
8633  |  |  * string as if by a call to the string function; the string is split  | 
8634  |  |  * into a whitespace-separated list of tokens (whitespace is any sequence  | 
8635  |  |  * of characters matching the production S); the result is a node-set  | 
8636  |  |  * containing the elements in the same document as the context node that  | 
8637  |  |  * have a unique ID equal to any of the tokens in the list.  | 
8638  |  |  */  | 
8639  |  | void  | 
8640  | 106k  | xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) { | 
8641  | 106k  |     xmlChar *tokens;  | 
8642  | 106k  |     xmlNodeSetPtr ret;  | 
8643  | 106k  |     xmlXPathObjectPtr obj;  | 
8644  |  |  | 
8645  | 319k  |     CHECK_ARITY(1);  | 
8646  | 319k  |     obj = valuePop(ctxt);  | 
8647  | 319k  |     if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);  | 
8648  | 106k  |     if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) { | 
8649  | 49.7k  |   xmlNodeSetPtr ns;  | 
8650  | 49.7k  |   int i;  | 
8651  |  |  | 
8652  |  |         /* TODO: Check memory error. */  | 
8653  | 49.7k  |   ret = xmlXPathNodeSetCreate(NULL);  | 
8654  |  |  | 
8655  | 49.7k  |   if (obj->nodesetval != NULL) { | 
8656  | 112k  |       for (i = 0; i < obj->nodesetval->nodeNr; i++) { | 
8657  | 68.3k  |     tokens =  | 
8658  | 68.3k  |         xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);  | 
8659  | 68.3k  |     ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);  | 
8660  |  |                 /* TODO: Check memory error. */  | 
8661  | 68.3k  |     ret = xmlXPathNodeSetMerge(ret, ns);  | 
8662  | 68.3k  |     xmlXPathFreeNodeSet(ns);  | 
8663  | 68.3k  |     if (tokens != NULL)  | 
8664  | 68.3k  |         xmlFree(tokens);  | 
8665  | 68.3k  |       }  | 
8666  | 44.0k  |   }  | 
8667  | 49.7k  |   xmlXPathReleaseObject(ctxt->context, obj);  | 
8668  | 49.7k  |   valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));  | 
8669  | 49.7k  |   return;  | 
8670  | 49.7k  |     }  | 
8671  | 56.7k  |     obj = xmlXPathCacheConvertString(ctxt->context, obj);  | 
8672  | 56.7k  |     if (obj == NULL) return;  | 
8673  | 56.7k  |     ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);  | 
8674  | 56.7k  |     valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));  | 
8675  | 56.7k  |     xmlXPathReleaseObject(ctxt->context, obj);  | 
8676  | 56.7k  |     return;  | 
8677  | 56.7k  | }  | 
8678  |  |  | 
8679  |  | /**  | 
8680  |  |  * xmlXPathLocalNameFunction:  | 
8681  |  |  * @ctxt:  the XPath Parser context  | 
8682  |  |  * @nargs:  the number of arguments  | 
8683  |  |  *  | 
8684  |  |  * Implement the local-name() XPath function  | 
8685  |  |  *    string local-name(node-set?)  | 
8686  |  |  * The local-name function returns a string containing the local part  | 
8687  |  |  * of the name of the node in the argument node-set that is first in  | 
8688  |  |  * document order. If the node-set is empty or the first node has no  | 
8689  |  |  * name, an empty string is returned. If the argument is omitted it  | 
8690  |  |  * defaults to the context node.  | 
8691  |  |  */  | 
8692  |  | void  | 
8693  | 21.0k  | xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) { | 
8694  | 21.0k  |     xmlXPathObjectPtr cur;  | 
8695  |  |  | 
8696  | 21.0k  |     if (ctxt == NULL) return;  | 
8697  |  |  | 
8698  | 21.0k  |     if (nargs == 0) { | 
8699  | 18  |   valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,  | 
8700  | 18  |       ctxt->context->node));  | 
8701  | 18  |   nargs = 1;  | 
8702  | 18  |     }  | 
8703  |  |  | 
8704  | 63.0k  |     CHECK_ARITY(1);  | 
8705  | 63.0k  |     if ((ctxt->value == NULL) ||  | 
8706  | 21.0k  |   ((ctxt->value->type != XPATH_NODESET) &&  | 
8707  | 21.0k  |    (ctxt->value->type != XPATH_XSLT_TREE)))  | 
8708  | 21.0k  |   XP_ERROR(XPATH_INVALID_TYPE);  | 
8709  | 21.0k  |     cur = valuePop(ctxt);  | 
8710  |  |  | 
8711  | 21.0k  |     if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) { | 
8712  | 127  |   valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));  | 
8713  | 20.8k  |     } else { | 
8714  | 20.8k  |   int i = 0; /* Should be first in document order !!!!! */  | 
8715  | 20.8k  |   switch (cur->nodesetval->nodeTab[i]->type) { | 
8716  | 16  |   case XML_ELEMENT_NODE:  | 
8717  | 22  |   case XML_ATTRIBUTE_NODE:  | 
8718  | 2.64k  |   case XML_PI_NODE:  | 
8719  | 2.64k  |       if (cur->nodesetval->nodeTab[i]->name[0] == ' ')  | 
8720  | 0  |     valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));  | 
8721  | 2.64k  |       else  | 
8722  | 2.64k  |     valuePush(ctxt,  | 
8723  | 2.64k  |           xmlXPathCacheNewString(ctxt->context,  | 
8724  | 2.64k  |       cur->nodesetval->nodeTab[i]->name));  | 
8725  | 2.64k  |       break;  | 
8726  | 10.7k  |   case XML_NAMESPACE_DECL:  | 
8727  | 10.7k  |       valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,  | 
8728  | 10.7k  |       ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));  | 
8729  | 10.7k  |       break;  | 
8730  | 7.47k  |   default:  | 
8731  | 7.47k  |       valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));  | 
8732  | 20.8k  |   }  | 
8733  | 20.8k  |     }  | 
8734  | 21.0k  |     xmlXPathReleaseObject(ctxt->context, cur);  | 
8735  | 21.0k  | }  | 
8736  |  |  | 
8737  |  | /**  | 
8738  |  |  * xmlXPathNamespaceURIFunction:  | 
8739  |  |  * @ctxt:  the XPath Parser context  | 
8740  |  |  * @nargs:  the number of arguments  | 
8741  |  |  *  | 
8742  |  |  * Implement the namespace-uri() XPath function  | 
8743  |  |  *    string namespace-uri(node-set?)  | 
8744  |  |  * The namespace-uri function returns a string containing the  | 
8745  |  |  * namespace URI of the expanded name of the node in the argument  | 
8746  |  |  * node-set that is first in document order. If the node-set is empty,  | 
8747  |  |  * the first node has no name, or the expanded name has no namespace  | 
8748  |  |  * URI, an empty string is returned. If the argument is omitted it  | 
8749  |  |  * defaults to the context node.  | 
8750  |  |  */  | 
8751  |  | void  | 
8752  | 664  | xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) { | 
8753  | 664  |     xmlXPathObjectPtr cur;  | 
8754  |  |  | 
8755  | 664  |     if (ctxt == NULL) return;  | 
8756  |  |  | 
8757  | 664  |     if (nargs == 0) { | 
8758  | 164  |   valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,  | 
8759  | 164  |       ctxt->context->node));  | 
8760  | 164  |   nargs = 1;  | 
8761  | 164  |     }  | 
8762  | 1.95k  |     CHECK_ARITY(1);  | 
8763  | 1.95k  |     if ((ctxt->value == NULL) ||  | 
8764  | 645  |   ((ctxt->value->type != XPATH_NODESET) &&  | 
8765  | 645  |    (ctxt->value->type != XPATH_XSLT_TREE)))  | 
8766  | 629  |   XP_ERROR(XPATH_INVALID_TYPE);  | 
8767  | 629  |     cur = valuePop(ctxt);  | 
8768  |  |  | 
8769  | 629  |     if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) { | 
8770  | 310  |   valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));  | 
8771  | 319  |     } else { | 
8772  | 319  |   int i = 0; /* Should be first in document order !!!!! */  | 
8773  | 319  |   switch (cur->nodesetval->nodeTab[i]->type) { | 
8774  | 139  |   case XML_ELEMENT_NODE:  | 
8775  | 139  |   case XML_ATTRIBUTE_NODE:  | 
8776  | 139  |       if (cur->nodesetval->nodeTab[i]->ns == NULL)  | 
8777  | 98  |     valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));  | 
8778  | 41  |       else  | 
8779  | 41  |     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,  | 
8780  | 41  |         cur->nodesetval->nodeTab[i]->ns->href));  | 
8781  | 139  |       break;  | 
8782  | 180  |   default:  | 
8783  | 180  |       valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));  | 
8784  | 319  |   }  | 
8785  | 319  |     }  | 
8786  | 629  |     xmlXPathReleaseObject(ctxt->context, cur);  | 
8787  | 629  | }  | 
8788  |  |  | 
8789  |  | /**  | 
8790  |  |  * xmlXPathNameFunction:  | 
8791  |  |  * @ctxt:  the XPath Parser context  | 
8792  |  |  * @nargs:  the number of arguments  | 
8793  |  |  *  | 
8794  |  |  * Implement the name() XPath function  | 
8795  |  |  *    string name(node-set?)  | 
8796  |  |  * The name function returns a string containing a QName representing  | 
8797  |  |  * the name of the node in the argument node-set that is first in document  | 
8798  |  |  * order. The QName must represent the name with respect to the namespace  | 
8799  |  |  * declarations in effect on the node whose name is being represented.  | 
8800  |  |  * Typically, this will be the form in which the name occurred in the XML  | 
8801  |  |  * source. This need not be the case if there are namespace declarations  | 
8802  |  |  * in effect on the node that associate multiple prefixes with the same  | 
8803  |  |  * namespace. However, an implementation may include information about  | 
8804  |  |  * the original prefix in its representation of nodes; in this case, an  | 
8805  |  |  * implementation can ensure that the returned string is always the same  | 
8806  |  |  * as the QName used in the XML source. If the argument it omitted it  | 
8807  |  |  * defaults to the context node.  | 
8808  |  |  * Libxml keep the original prefix so the "real qualified name" used is  | 
8809  |  |  * returned.  | 
8810  |  |  */  | 
8811  |  | static void  | 
8812  |  | xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)  | 
8813  | 88.5k  | { | 
8814  | 88.5k  |     xmlXPathObjectPtr cur;  | 
8815  |  |  | 
8816  | 88.5k  |     if (nargs == 0) { | 
8817  | 29.3k  |   valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,  | 
8818  | 29.3k  |       ctxt->context->node));  | 
8819  | 29.3k  |         nargs = 1;  | 
8820  | 29.3k  |     }  | 
8821  |  |  | 
8822  | 265k  |     CHECK_ARITY(1);  | 
8823  | 265k  |     if ((ctxt->value == NULL) ||  | 
8824  | 88.5k  |         ((ctxt->value->type != XPATH_NODESET) &&  | 
8825  | 88.5k  |          (ctxt->value->type != XPATH_XSLT_TREE)))  | 
8826  | 88.5k  |         XP_ERROR(XPATH_INVALID_TYPE);  | 
8827  | 88.5k  |     cur = valuePop(ctxt);  | 
8828  |  |  | 
8829  | 88.5k  |     if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) { | 
8830  | 50.4k  |         valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));  | 
8831  | 50.4k  |     } else { | 
8832  | 38.0k  |         int i = 0;              /* Should be first in document order !!!!! */  | 
8833  |  |  | 
8834  | 38.0k  |         switch (cur->nodesetval->nodeTab[i]->type) { | 
8835  | 17.1k  |             case XML_ELEMENT_NODE:  | 
8836  | 17.2k  |             case XML_ATTRIBUTE_NODE:  | 
8837  | 17.2k  |     if (cur->nodesetval->nodeTab[i]->name[0] == ' ')  | 
8838  | 0  |         valuePush(ctxt,  | 
8839  | 0  |       xmlXPathCacheNewCString(ctxt->context, ""));  | 
8840  | 17.2k  |     else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||  | 
8841  | 17.2k  |                          (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) { | 
8842  | 7.55k  |         valuePush(ctxt,  | 
8843  | 7.55k  |             xmlXPathCacheNewString(ctxt->context,  | 
8844  | 7.55k  |           cur->nodesetval->nodeTab[i]->name));  | 
8845  | 9.72k  |     } else { | 
8846  | 9.72k  |         xmlChar *fullname;  | 
8847  |  |  | 
8848  | 9.72k  |         fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,  | 
8849  | 9.72k  |              cur->nodesetval->nodeTab[i]->ns->prefix,  | 
8850  | 9.72k  |              NULL, 0);  | 
8851  | 9.72k  |         if (fullname == cur->nodesetval->nodeTab[i]->name)  | 
8852  | 0  |       fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);  | 
8853  | 9.72k  |         if (fullname == NULL) { | 
8854  | 0  |       XP_ERROR(XPATH_MEMORY_ERROR);  | 
8855  | 0  |         }  | 
8856  | 9.72k  |         valuePush(ctxt, xmlXPathCacheWrapString(  | 
8857  | 9.72k  |       ctxt->context, fullname));  | 
8858  | 9.72k  |                 }  | 
8859  | 17.2k  |                 break;  | 
8860  | 20.8k  |             default:  | 
8861  | 20.8k  |     valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,  | 
8862  | 20.8k  |         cur->nodesetval->nodeTab[i]));  | 
8863  | 20.8k  |                 xmlXPathLocalNameFunction(ctxt, 1);  | 
8864  | 38.0k  |         }  | 
8865  | 38.0k  |     }  | 
8866  | 88.5k  |     xmlXPathReleaseObject(ctxt->context, cur);  | 
8867  | 88.5k  | }  | 
8868  |  |  | 
8869  |  |  | 
8870  |  | /**  | 
8871  |  |  * xmlXPathStringFunction:  | 
8872  |  |  * @ctxt:  the XPath Parser context  | 
8873  |  |  * @nargs:  the number of arguments  | 
8874  |  |  *  | 
8875  |  |  * Implement the string() XPath function  | 
8876  |  |  *    string string(object?)  | 
8877  |  |  * The string function converts an object to a string as follows:  | 
8878  |  |  *    - A node-set is converted to a string by returning the value of  | 
8879  |  |  *      the node in the node-set that is first in document order.  | 
8880  |  |  *      If the node-set is empty, an empty string is returned.  | 
8881  |  |  *    - A number is converted to a string as follows  | 
8882  |  |  *      + NaN is converted to the string NaN  | 
8883  |  |  *      + positive zero is converted to the string 0  | 
8884  |  |  *      + negative zero is converted to the string 0  | 
8885  |  |  *      + positive infinity is converted to the string Infinity  | 
8886  |  |  *      + negative infinity is converted to the string -Infinity  | 
8887  |  |  *      + if the number is an integer, the number is represented in  | 
8888  |  |  *        decimal form as a Number with no decimal point and no leading  | 
8889  |  |  *        zeros, preceded by a minus sign (-) if the number is negative  | 
8890  |  |  *      + otherwise, the number is represented in decimal form as a  | 
8891  |  |  *        Number including a decimal point with at least one digit  | 
8892  |  |  *        before the decimal point and at least one digit after the  | 
8893  |  |  *        decimal point, preceded by a minus sign (-) if the number  | 
8894  |  |  *        is negative; there must be no leading zeros before the decimal  | 
8895  |  |  *        point apart possibly from the one required digit immediately  | 
8896  |  |  *        before the decimal point; beyond the one required digit  | 
8897  |  |  *        after the decimal point there must be as many, but only as  | 
8898  |  |  *        many, more digits as are needed to uniquely distinguish the  | 
8899  |  |  *        number from all other IEEE 754 numeric values.  | 
8900  |  |  *    - The boolean false value is converted to the string false.  | 
8901  |  |  *      The boolean true value is converted to the string true.  | 
8902  |  |  *  | 
8903  |  |  * If the argument is omitted, it defaults to a node-set with the  | 
8904  |  |  * context node as its only member.  | 
8905  |  |  */  | 
8906  |  | void  | 
8907  | 4.63M  | xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) { | 
8908  | 4.63M  |     xmlXPathObjectPtr cur;  | 
8909  |  |  | 
8910  | 4.63M  |     if (ctxt == NULL) return;  | 
8911  | 4.63M  |     if (nargs == 0) { | 
8912  | 37  |     valuePush(ctxt,  | 
8913  | 37  |   xmlXPathCacheWrapString(ctxt->context,  | 
8914  | 37  |       xmlXPathCastNodeToString(ctxt->context->node)));  | 
8915  | 37  |   return;  | 
8916  | 37  |     }  | 
8917  |  |  | 
8918  | 18.5M  |     CHECK_ARITY(1);  | 
8919  | 18.5M  |     cur = valuePop(ctxt);  | 
8920  | 18.5M  |     if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);  | 
8921  | 4.63M  |     valuePush(ctxt, xmlXPathCacheConvertString(ctxt->context, cur));  | 
8922  | 4.63M  | }  | 
8923  |  |  | 
8924  |  | /**  | 
8925  |  |  * xmlXPathStringLengthFunction:  | 
8926  |  |  * @ctxt:  the XPath Parser context  | 
8927  |  |  * @nargs:  the number of arguments  | 
8928  |  |  *  | 
8929  |  |  * Implement the string-length() XPath function  | 
8930  |  |  *    number string-length(string?)  | 
8931  |  |  * The string-length returns the number of characters in the string  | 
8932  |  |  * (see [3.6 Strings]). If the argument is omitted, it defaults to  | 
8933  |  |  * the context node converted to a string, in other words the value  | 
8934  |  |  * of the context node.  | 
8935  |  |  */  | 
8936  |  | void  | 
8937  | 24.5k  | xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) { | 
8938  | 24.5k  |     xmlXPathObjectPtr cur;  | 
8939  |  |  | 
8940  | 24.5k  |     if (nargs == 0) { | 
8941  | 3.45k  |         if ((ctxt == NULL) || (ctxt->context == NULL))  | 
8942  | 0  |       return;  | 
8943  | 3.45k  |   if (ctxt->context->node == NULL) { | 
8944  | 0  |       valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0));  | 
8945  | 3.45k  |   } else { | 
8946  | 3.45k  |       xmlChar *content;  | 
8947  |  |  | 
8948  | 3.45k  |       content = xmlXPathCastNodeToString(ctxt->context->node);  | 
8949  | 3.45k  |       valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,  | 
8950  | 3.45k  |     xmlUTF8Strlen(content)));  | 
8951  | 3.45k  |       xmlFree(content);  | 
8952  | 3.45k  |   }  | 
8953  | 3.45k  |   return;  | 
8954  | 3.45k  |     }  | 
8955  | 84.1k  |     CHECK_ARITY(1);  | 
8956  | 84.1k  |     CAST_TO_STRING;  | 
8957  | 84.1k  |     CHECK_TYPE(XPATH_STRING);  | 
8958  | 21.0k  |     cur = valuePop(ctxt);  | 
8959  | 21.0k  |     valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,  | 
8960  | 21.0k  |   xmlUTF8Strlen(cur->stringval)));  | 
8961  | 21.0k  |     xmlXPathReleaseObject(ctxt->context, cur);  | 
8962  | 21.0k  | }  | 
8963  |  |  | 
8964  |  | /**  | 
8965  |  |  * xmlXPathConcatFunction:  | 
8966  |  |  * @ctxt:  the XPath Parser context  | 
8967  |  |  * @nargs:  the number of arguments  | 
8968  |  |  *  | 
8969  |  |  * Implement the concat() XPath function  | 
8970  |  |  *    string concat(string, string, string*)  | 
8971  |  |  * The concat function returns the concatenation of its arguments.  | 
8972  |  |  */  | 
8973  |  | void  | 
8974  | 8.61k  | xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) { | 
8975  | 8.61k  |     xmlXPathObjectPtr cur, newobj;  | 
8976  | 8.61k  |     xmlChar *tmp;  | 
8977  |  |  | 
8978  | 8.61k  |     if (ctxt == NULL) return;  | 
8979  | 8.61k  |     if (nargs < 2) { | 
8980  | 418  |   CHECK_ARITY(2);  | 
8981  | 418  |     }  | 
8982  |  |  | 
8983  | 8.20k  |     CAST_TO_STRING;  | 
8984  | 8.20k  |     cur = valuePop(ctxt);  | 
8985  | 8.20k  |     if ((cur == NULL) || (cur->type != XPATH_STRING)) { | 
8986  | 0  |   xmlXPathReleaseObject(ctxt->context, cur);  | 
8987  | 0  |   return;  | 
8988  | 0  |     }  | 
8989  | 8.20k  |     nargs--;  | 
8990  |  |  | 
8991  | 58.6k  |     while (nargs > 0) { | 
8992  | 50.4k  |   CAST_TO_STRING;  | 
8993  | 50.4k  |   newobj = valuePop(ctxt);  | 
8994  | 50.4k  |   if ((newobj == NULL) || (newobj->type != XPATH_STRING)) { | 
8995  | 0  |       xmlXPathReleaseObject(ctxt->context, newobj);  | 
8996  | 0  |       xmlXPathReleaseObject(ctxt->context, cur);  | 
8997  | 0  |       XP_ERROR(XPATH_INVALID_TYPE);  | 
8998  | 0  |   }  | 
8999  | 50.4k  |   tmp = xmlStrcat(newobj->stringval, cur->stringval);  | 
9000  | 50.4k  |   newobj->stringval = cur->stringval;  | 
9001  | 50.4k  |   cur->stringval = tmp;  | 
9002  | 50.4k  |   xmlXPathReleaseObject(ctxt->context, newobj);  | 
9003  | 50.4k  |   nargs--;  | 
9004  | 50.4k  |     }  | 
9005  | 8.20k  |     valuePush(ctxt, cur);  | 
9006  | 8.20k  | }  | 
9007  |  |  | 
9008  |  | /**  | 
9009  |  |  * xmlXPathContainsFunction:  | 
9010  |  |  * @ctxt:  the XPath Parser context  | 
9011  |  |  * @nargs:  the number of arguments  | 
9012  |  |  *  | 
9013  |  |  * Implement the contains() XPath function  | 
9014  |  |  *    boolean contains(string, string)  | 
9015  |  |  * The contains function returns true if the first argument string  | 
9016  |  |  * contains the second argument string, and otherwise returns false.  | 
9017  |  |  */  | 
9018  |  | void  | 
9019  | 1.35k  | xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) { | 
9020  | 1.35k  |     xmlXPathObjectPtr hay, needle;  | 
9021  |  |  | 
9022  | 4.03k  |     CHECK_ARITY(2);  | 
9023  | 4.03k  |     CAST_TO_STRING;  | 
9024  | 4.03k  |     CHECK_TYPE(XPATH_STRING);  | 
9025  | 1.33k  |     needle = valuePop(ctxt);  | 
9026  | 1.33k  |     CAST_TO_STRING;  | 
9027  | 1.33k  |     hay = valuePop(ctxt);  | 
9028  |  |  | 
9029  | 1.33k  |     if ((hay == NULL) || (hay->type != XPATH_STRING)) { | 
9030  | 0  |   xmlXPathReleaseObject(ctxt->context, hay);  | 
9031  | 0  |   xmlXPathReleaseObject(ctxt->context, needle);  | 
9032  | 0  |   XP_ERROR(XPATH_INVALID_TYPE);  | 
9033  | 0  |     }  | 
9034  | 1.33k  |     if (xmlStrstr(hay->stringval, needle->stringval))  | 
9035  | 239  |   valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));  | 
9036  | 1.09k  |     else  | 
9037  | 1.09k  |   valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));  | 
9038  | 1.33k  |     xmlXPathReleaseObject(ctxt->context, hay);  | 
9039  | 1.33k  |     xmlXPathReleaseObject(ctxt->context, needle);  | 
9040  | 1.33k  | }  | 
9041  |  |  | 
9042  |  | /**  | 
9043  |  |  * xmlXPathStartsWithFunction:  | 
9044  |  |  * @ctxt:  the XPath Parser context  | 
9045  |  |  * @nargs:  the number of arguments  | 
9046  |  |  *  | 
9047  |  |  * Implement the starts-with() XPath function  | 
9048  |  |  *    boolean starts-with(string, string)  | 
9049  |  |  * The starts-with function returns true if the first argument string  | 
9050  |  |  * starts with the second argument string, and otherwise returns false.  | 
9051  |  |  */  | 
9052  |  | void  | 
9053  | 668  | xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) { | 
9054  | 668  |     xmlXPathObjectPtr hay, needle;  | 
9055  | 668  |     int n;  | 
9056  |  |  | 
9057  | 1.94k  |     CHECK_ARITY(2);  | 
9058  | 1.94k  |     CAST_TO_STRING;  | 
9059  | 1.94k  |     CHECK_TYPE(XPATH_STRING);  | 
9060  | 640  |     needle = valuePop(ctxt);  | 
9061  | 640  |     CAST_TO_STRING;  | 
9062  | 640  |     hay = valuePop(ctxt);  | 
9063  |  |  | 
9064  | 640  |     if ((hay == NULL) || (hay->type != XPATH_STRING)) { | 
9065  | 0  |   xmlXPathReleaseObject(ctxt->context, hay);  | 
9066  | 0  |   xmlXPathReleaseObject(ctxt->context, needle);  | 
9067  | 0  |   XP_ERROR(XPATH_INVALID_TYPE);  | 
9068  | 0  |     }  | 
9069  | 640  |     n = xmlStrlen(needle->stringval);  | 
9070  | 640  |     if (xmlStrncmp(hay->stringval, needle->stringval, n))  | 
9071  | 180  |         valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));  | 
9072  | 460  |     else  | 
9073  | 460  |         valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));  | 
9074  | 640  |     xmlXPathReleaseObject(ctxt->context, hay);  | 
9075  | 640  |     xmlXPathReleaseObject(ctxt->context, needle);  | 
9076  | 640  | }  | 
9077  |  |  | 
9078  |  | /**  | 
9079  |  |  * xmlXPathSubstringFunction:  | 
9080  |  |  * @ctxt:  the XPath Parser context  | 
9081  |  |  * @nargs:  the number of arguments  | 
9082  |  |  *  | 
9083  |  |  * Implement the substring() XPath function  | 
9084  |  |  *    string substring(string, number, number?)  | 
9085  |  |  * The substring function returns the substring of the first argument  | 
9086  |  |  * starting at the position specified in the second argument with  | 
9087  |  |  * length specified in the third argument. For example,  | 
9088  |  |  * substring("12345",2,3) returns "234". If the third argument is not | 
9089  |  |  * specified, it returns the substring starting at the position specified  | 
9090  |  |  * in the second argument and continuing to the end of the string. For  | 
9091  |  |  * example, substring("12345",2) returns "2345".  More precisely, each | 
9092  |  |  * character in the string (see [3.6 Strings]) is considered to have a  | 
9093  |  |  * numeric position: the position of the first character is 1, the position  | 
9094  |  |  * of the second character is 2 and so on. The returned substring contains  | 
9095  |  |  * those characters for which the position of the character is greater than  | 
9096  |  |  * or equal to the second argument and, if the third argument is specified,  | 
9097  |  |  * less than the sum of the second and third arguments; the comparisons  | 
9098  |  |  * and addition used for the above follow the standard IEEE 754 rules. Thus:  | 
9099  |  |  *  - substring("12345", 1.5, 2.6) returns "234" | 
9100  |  |  *  - substring("12345", 0, 3) returns "12" | 
9101  |  |  *  - substring("12345", 0 div 0, 3) returns "" | 
9102  |  |  *  - substring("12345", 1, 0 div 0) returns "" | 
9103  |  |  *  - substring("12345", -42, 1 div 0) returns "12345" | 
9104  |  |  *  - substring("12345", -1 div 0, 1 div 0) returns "" | 
9105  |  |  */  | 
9106  |  | void  | 
9107  | 20.7k  | xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) { | 
9108  | 20.7k  |     xmlXPathObjectPtr str, start, len;  | 
9109  | 20.7k  |     double le=0, in;  | 
9110  | 20.7k  |     int i = 1, j = INT_MAX;  | 
9111  |  |  | 
9112  | 20.7k  |     if (nargs < 2) { | 
9113  | 85  |   CHECK_ARITY(2);  | 
9114  | 85  |     }  | 
9115  | 20.7k  |     if (nargs > 3) { | 
9116  | 178  |   CHECK_ARITY(3);  | 
9117  | 178  |     }  | 
9118  |  |     /*  | 
9119  |  |      * take care of possible last (position) argument  | 
9120  |  |     */  | 
9121  | 20.5k  |     if (nargs == 3) { | 
9122  | 14.2k  |   CAST_TO_NUMBER;  | 
9123  | 14.2k  |   CHECK_TYPE(XPATH_NUMBER);  | 
9124  | 14.2k  |   len = valuePop(ctxt);  | 
9125  | 14.2k  |   le = len->floatval;  | 
9126  | 14.2k  |   xmlXPathReleaseObject(ctxt->context, len);  | 
9127  | 14.2k  |     }  | 
9128  |  |  | 
9129  | 20.5k  |     CAST_TO_NUMBER;  | 
9130  | 20.5k  |     CHECK_TYPE(XPATH_NUMBER);  | 
9131  | 20.5k  |     start = valuePop(ctxt);  | 
9132  | 20.5k  |     in = start->floatval;  | 
9133  | 20.5k  |     xmlXPathReleaseObject(ctxt->context, start);  | 
9134  | 20.5k  |     CAST_TO_STRING;  | 
9135  | 20.5k  |     CHECK_TYPE(XPATH_STRING);  | 
9136  | 20.5k  |     str = valuePop(ctxt);  | 
9137  |  |  | 
9138  | 20.5k  |     if (!(in < INT_MAX)) { /* Logical NOT to handle NaNs */ | 
9139  | 1.97k  |         i = INT_MAX;  | 
9140  | 18.5k  |     } else if (in >= 1.0) { | 
9141  | 5.10k  |         i = (int)in;  | 
9142  | 5.10k  |         if (in - floor(in) >= 0.5)  | 
9143  | 443  |             i += 1;  | 
9144  | 5.10k  |     }  | 
9145  |  |  | 
9146  | 20.5k  |     if (nargs == 3) { | 
9147  | 14.2k  |         double rin, rle, end;  | 
9148  |  |  | 
9149  | 14.2k  |         rin = floor(in);  | 
9150  | 14.2k  |         if (in - rin >= 0.5)  | 
9151  | 1.34k  |             rin += 1.0;  | 
9152  |  |  | 
9153  | 14.2k  |         rle = floor(le);  | 
9154  | 14.2k  |         if (le - rle >= 0.5)  | 
9155  | 46  |             rle += 1.0;  | 
9156  |  |  | 
9157  | 14.2k  |         end = rin + rle;  | 
9158  | 14.2k  |         if (!(end >= 1.0)) { /* Logical NOT to handle NaNs */ | 
9159  | 1.12k  |             j = 1;  | 
9160  | 13.0k  |         } else if (end < INT_MAX) { | 
9161  | 12.3k  |             j = (int)end;  | 
9162  | 12.3k  |         }  | 
9163  | 14.2k  |     }  | 
9164  |  |  | 
9165  | 20.5k  |     if (i < j) { | 
9166  | 17.2k  |         xmlChar *ret = xmlUTF8Strsub(str->stringval, i - 1, j - i);  | 
9167  | 17.2k  |   valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, ret));  | 
9168  | 17.2k  |   xmlFree(ret);  | 
9169  | 17.2k  |     } else { | 
9170  | 3.26k  |   valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));  | 
9171  | 3.26k  |     }  | 
9172  |  |  | 
9173  | 20.5k  |     xmlXPathReleaseObject(ctxt->context, str);  | 
9174  | 20.5k  | }  | 
9175  |  |  | 
9176  |  | /**  | 
9177  |  |  * xmlXPathSubstringBeforeFunction:  | 
9178  |  |  * @ctxt:  the XPath Parser context  | 
9179  |  |  * @nargs:  the number of arguments  | 
9180  |  |  *  | 
9181  |  |  * Implement the substring-before() XPath function  | 
9182  |  |  *    string substring-before(string, string)  | 
9183  |  |  * The substring-before function returns the substring of the first  | 
9184  |  |  * argument string that precedes the first occurrence of the second  | 
9185  |  |  * argument string in the first argument string, or the empty string  | 
9186  |  |  * if the first argument string does not contain the second argument  | 
9187  |  |  * string. For example, substring-before("1999/04/01","/") returns 1999. | 
9188  |  |  */  | 
9189  |  | void  | 
9190  | 2.42k  | xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) { | 
9191  | 2.42k  |   xmlXPathObjectPtr str;  | 
9192  | 2.42k  |   xmlXPathObjectPtr find;  | 
9193  | 2.42k  |   xmlBufPtr target;  | 
9194  | 2.42k  |   const xmlChar *point;  | 
9195  | 2.42k  |   int offset;  | 
9196  |  |  | 
9197  | 7.24k  |   CHECK_ARITY(2);  | 
9198  | 7.24k  |   CAST_TO_STRING;  | 
9199  | 7.24k  |   find = valuePop(ctxt);  | 
9200  | 7.24k  |   CAST_TO_STRING;  | 
9201  | 7.24k  |   str = valuePop(ctxt);  | 
9202  |  |  | 
9203  | 7.24k  |   target = xmlBufCreate();  | 
9204  | 7.24k  |   if (target) { | 
9205  | 2.40k  |     point = xmlStrstr(str->stringval, find->stringval);  | 
9206  | 2.40k  |     if (point) { | 
9207  | 1.45k  |       offset = point - str->stringval;  | 
9208  | 1.45k  |       xmlBufAdd(target, str->stringval, offset);  | 
9209  | 1.45k  |     }  | 
9210  | 2.40k  |     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,  | 
9211  | 2.40k  |   xmlBufContent(target)));  | 
9212  | 2.40k  |     xmlBufFree(target);  | 
9213  | 2.40k  |   }  | 
9214  | 7.24k  |   xmlXPathReleaseObject(ctxt->context, str);  | 
9215  | 7.24k  |   xmlXPathReleaseObject(ctxt->context, find);  | 
9216  | 7.24k  | }  | 
9217  |  |  | 
9218  |  | /**  | 
9219  |  |  * xmlXPathSubstringAfterFunction:  | 
9220  |  |  * @ctxt:  the XPath Parser context  | 
9221  |  |  * @nargs:  the number of arguments  | 
9222  |  |  *  | 
9223  |  |  * Implement the substring-after() XPath function  | 
9224  |  |  *    string substring-after(string, string)  | 
9225  |  |  * The substring-after function returns the substring of the first  | 
9226  |  |  * argument string that follows the first occurrence of the second  | 
9227  |  |  * argument string in the first argument string, or the empty stringi  | 
9228  |  |  * if the first argument string does not contain the second argument  | 
9229  |  |  * string. For example, substring-after("1999/04/01","/") returns 04/01, | 
9230  |  |  * and substring-after("1999/04/01","19") returns 99/04/01. | 
9231  |  |  */  | 
9232  |  | void  | 
9233  | 3.36k  | xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) { | 
9234  | 3.36k  |   xmlXPathObjectPtr str;  | 
9235  | 3.36k  |   xmlXPathObjectPtr find;  | 
9236  | 3.36k  |   xmlBufPtr target;  | 
9237  | 3.36k  |   const xmlChar *point;  | 
9238  | 3.36k  |   int offset;  | 
9239  |  |  | 
9240  | 9.73k  |   CHECK_ARITY(2);  | 
9241  | 9.73k  |   CAST_TO_STRING;  | 
9242  | 9.73k  |   find = valuePop(ctxt);  | 
9243  | 9.73k  |   CAST_TO_STRING;  | 
9244  | 9.73k  |   str = valuePop(ctxt);  | 
9245  |  |  | 
9246  | 9.73k  |   target = xmlBufCreate();  | 
9247  | 9.73k  |   if (target) { | 
9248  | 3.18k  |     point = xmlStrstr(str->stringval, find->stringval);  | 
9249  | 3.18k  |     if (point) { | 
9250  | 2.07k  |       offset = point - str->stringval + xmlStrlen(find->stringval);  | 
9251  | 2.07k  |       xmlBufAdd(target, &str->stringval[offset],  | 
9252  | 2.07k  |        xmlStrlen(str->stringval) - offset);  | 
9253  | 2.07k  |     }  | 
9254  | 3.18k  |     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,  | 
9255  | 3.18k  |   xmlBufContent(target)));  | 
9256  | 3.18k  |     xmlBufFree(target);  | 
9257  | 3.18k  |   }  | 
9258  | 9.73k  |   xmlXPathReleaseObject(ctxt->context, str);  | 
9259  | 9.73k  |   xmlXPathReleaseObject(ctxt->context, find);  | 
9260  | 9.73k  | }  | 
9261  |  |  | 
9262  |  | /**  | 
9263  |  |  * xmlXPathNormalizeFunction:  | 
9264  |  |  * @ctxt:  the XPath Parser context  | 
9265  |  |  * @nargs:  the number of arguments  | 
9266  |  |  *  | 
9267  |  |  * Implement the normalize-space() XPath function  | 
9268  |  |  *    string normalize-space(string?)  | 
9269  |  |  * The normalize-space function returns the argument string with white  | 
9270  |  |  * space normalized by stripping leading and trailing whitespace  | 
9271  |  |  * and replacing sequences of whitespace characters by a single  | 
9272  |  |  * space. Whitespace characters are the same allowed by the S production  | 
9273  |  |  * in XML. If the argument is omitted, it defaults to the context  | 
9274  |  |  * node converted to a string, in other words the value of the context node.  | 
9275  |  |  */  | 
9276  |  | void  | 
9277  | 2.98k  | xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) { | 
9278  | 2.98k  |     xmlChar *source, *target;  | 
9279  | 2.98k  |     int blank;  | 
9280  |  |  | 
9281  | 2.98k  |     if (ctxt == NULL) return;  | 
9282  | 2.98k  |     if (nargs == 0) { | 
9283  |  |         /* Use current context node */  | 
9284  | 439  |         valuePush(ctxt,  | 
9285  | 439  |             xmlXPathCacheWrapString(ctxt->context,  | 
9286  | 439  |                 xmlXPathCastNodeToString(ctxt->context->node)));  | 
9287  | 439  |         nargs = 1;  | 
9288  | 439  |     }  | 
9289  |  |  | 
9290  | 8.91k  |     CHECK_ARITY(1);  | 
9291  | 8.91k  |     CAST_TO_STRING;  | 
9292  | 8.91k  |     CHECK_TYPE(XPATH_STRING);  | 
9293  | 2.96k  |     source = ctxt->value->stringval;  | 
9294  | 2.96k  |     if (source == NULL)  | 
9295  | 0  |         return;  | 
9296  | 2.96k  |     target = source;  | 
9297  |  |  | 
9298  |  |     /* Skip leading whitespaces */  | 
9299  | 2.96k  |     while (IS_BLANK_CH(*source))  | 
9300  | 30.9k  |         source++;  | 
9301  |  |  | 
9302  |  |     /* Collapse intermediate whitespaces, and skip trailing whitespaces */  | 
9303  | 2.96k  |     blank = 0;  | 
9304  | 244k  |     while (*source) { | 
9305  | 241k  |         if (IS_BLANK_CH(*source)) { | 
9306  | 76.7k  |       blank = 1;  | 
9307  | 164k  |         } else { | 
9308  | 164k  |             if (blank) { | 
9309  | 8.15k  |                 *target++ = 0x20;  | 
9310  | 8.15k  |                 blank = 0;  | 
9311  | 8.15k  |             }  | 
9312  | 164k  |             *target++ = *source;  | 
9313  | 164k  |         }  | 
9314  | 241k  |         source++;  | 
9315  | 241k  |     }  | 
9316  | 2.96k  |     *target = 0;  | 
9317  | 2.96k  | }  | 
9318  |  |  | 
9319  |  | /**  | 
9320  |  |  * xmlXPathTranslateFunction:  | 
9321  |  |  * @ctxt:  the XPath Parser context  | 
9322  |  |  * @nargs:  the number of arguments  | 
9323  |  |  *  | 
9324  |  |  * Implement the translate() XPath function  | 
9325  |  |  *    string translate(string, string, string)  | 
9326  |  |  * The translate function returns the first argument string with  | 
9327  |  |  * occurrences of characters in the second argument string replaced  | 
9328  |  |  * by the character at the corresponding position in the third argument  | 
9329  |  |  * string. For example, translate("bar","abc","ABC") returns the string | 
9330  |  |  * BAr. If there is a character in the second argument string with no  | 
9331  |  |  * character at a corresponding position in the third argument string  | 
9332  |  |  * (because the second argument string is longer than the third argument  | 
9333  |  |  * string), then occurrences of that character in the first argument  | 
9334  |  |  * string are removed. For example, translate("--aaa--","abc-","ABC") | 
9335  |  |  * returns "AAA". If a character occurs more than once in second  | 
9336  |  |  * argument string, then the first occurrence determines the replacement  | 
9337  |  |  * character. If the third argument string is longer than the second  | 
9338  |  |  * argument string, then excess characters are ignored.  | 
9339  |  |  */  | 
9340  |  | void  | 
9341  | 17.4k  | xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) { | 
9342  | 17.4k  |     xmlXPathObjectPtr str;  | 
9343  | 17.4k  |     xmlXPathObjectPtr from;  | 
9344  | 17.4k  |     xmlXPathObjectPtr to;  | 
9345  | 17.4k  |     xmlBufPtr target;  | 
9346  | 17.4k  |     int offset, max;  | 
9347  | 17.4k  |     xmlChar ch;  | 
9348  | 17.4k  |     const xmlChar *point;  | 
9349  | 17.4k  |     xmlChar *cptr;  | 
9350  |  |  | 
9351  | 52.1k  |     CHECK_ARITY(3);  | 
9352  |  |  | 
9353  | 52.1k  |     CAST_TO_STRING;  | 
9354  | 52.1k  |     to = valuePop(ctxt);  | 
9355  | 52.1k  |     CAST_TO_STRING;  | 
9356  | 52.1k  |     from = valuePop(ctxt);  | 
9357  | 52.1k  |     CAST_TO_STRING;  | 
9358  | 52.1k  |     str = valuePop(ctxt);  | 
9359  |  |  | 
9360  | 52.1k  |     target = xmlBufCreate();  | 
9361  | 52.1k  |     if (target) { | 
9362  | 17.3k  |   max = xmlUTF8Strlen(to->stringval);  | 
9363  | 1.51M  |   for (cptr = str->stringval; (ch=*cptr); ) { | 
9364  | 1.50M  |       offset = xmlUTF8Strloc(from->stringval, cptr);  | 
9365  | 1.50M  |       if (offset >= 0) { | 
9366  | 320k  |     if (offset < max) { | 
9367  | 240k  |         point = xmlUTF8Strpos(to->stringval, offset);  | 
9368  | 240k  |         if (point)  | 
9369  | 235k  |       xmlBufAdd(target, point, xmlUTF8Strsize(point, 1));  | 
9370  | 240k  |     }  | 
9371  | 320k  |       } else  | 
9372  | 1.18M  |     xmlBufAdd(target, cptr, xmlUTF8Strsize(cptr, 1));  | 
9373  |  |  | 
9374  |  |       /* Step to next character in input */  | 
9375  | 1.50M  |       cptr++;  | 
9376  | 1.50M  |       if ( ch & 0x80 ) { | 
9377  |  |     /* if not simple ascii, verify proper format */  | 
9378  | 15.3k  |     if ( (ch & 0xc0) != 0xc0 ) { | 
9379  | 4.44k  |         xmlGenericError(xmlGenericErrorContext,  | 
9380  | 4.44k  |       "xmlXPathTranslateFunction: Invalid UTF8 string\n");  | 
9381  |  |                     /* not asserting an XPath error is probably better */  | 
9382  | 4.44k  |         break;  | 
9383  | 4.44k  |     }  | 
9384  |  |     /* then skip over remaining bytes for this char */  | 
9385  | 27.1k  |     while ( (ch <<= 1) & 0x80 )  | 
9386  | 17.9k  |         if ( (*cptr++ & 0xc0) != 0x80 ) { | 
9387  | 1.72k  |       xmlGenericError(xmlGenericErrorContext,  | 
9388  | 1.72k  |           "xmlXPathTranslateFunction: Invalid UTF8 string\n");  | 
9389  |  |                         /* not asserting an XPath error is probably better */  | 
9390  | 1.72k  |       break;  | 
9391  | 1.72k  |         }  | 
9392  | 10.9k  |     if (ch & 0x80) /* must have had error encountered */  | 
9393  | 1.72k  |         break;  | 
9394  | 10.9k  |       }  | 
9395  | 1.50M  |   }  | 
9396  | 17.3k  |     }  | 
9397  | 52.1k  |     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,  | 
9398  | 52.1k  |   xmlBufContent(target)));  | 
9399  | 52.1k  |     xmlBufFree(target);  | 
9400  | 52.1k  |     xmlXPathReleaseObject(ctxt->context, str);  | 
9401  | 52.1k  |     xmlXPathReleaseObject(ctxt->context, from);  | 
9402  | 52.1k  |     xmlXPathReleaseObject(ctxt->context, to);  | 
9403  | 52.1k  | }  | 
9404  |  |  | 
9405  |  | /**  | 
9406  |  |  * xmlXPathBooleanFunction:  | 
9407  |  |  * @ctxt:  the XPath Parser context  | 
9408  |  |  * @nargs:  the number of arguments  | 
9409  |  |  *  | 
9410  |  |  * Implement the boolean() XPath function  | 
9411  |  |  *    boolean boolean(object)  | 
9412  |  |  * The boolean function converts its argument to a boolean as follows:  | 
9413  |  |  *    - a number is true if and only if it is neither positive or  | 
9414  |  |  *      negative zero nor NaN  | 
9415  |  |  *    - a node-set is true if and only if it is non-empty  | 
9416  |  |  *    - a string is true if and only if its length is non-zero  | 
9417  |  |  */  | 
9418  |  | void  | 
9419  | 1.99M  | xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) { | 
9420  | 1.99M  |     xmlXPathObjectPtr cur;  | 
9421  |  |  | 
9422  | 5.99M  |     CHECK_ARITY(1);  | 
9423  | 5.99M  |     cur = valuePop(ctxt);  | 
9424  | 5.99M  |     if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);  | 
9425  | 1.99M  |     cur = xmlXPathCacheConvertBoolean(ctxt->context, cur);  | 
9426  | 1.99M  |     valuePush(ctxt, cur);  | 
9427  | 1.99M  | }  | 
9428  |  |  | 
9429  |  | /**  | 
9430  |  |  * xmlXPathNotFunction:  | 
9431  |  |  * @ctxt:  the XPath Parser context  | 
9432  |  |  * @nargs:  the number of arguments  | 
9433  |  |  *  | 
9434  |  |  * Implement the not() XPath function  | 
9435  |  |  *    boolean not(boolean)  | 
9436  |  |  * The not function returns true if its argument is false,  | 
9437  |  |  * and false otherwise.  | 
9438  |  |  */  | 
9439  |  | void  | 
9440  | 2.33k  | xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) { | 
9441  | 6.88k  |     CHECK_ARITY(1);  | 
9442  | 6.88k  |     CAST_TO_BOOLEAN;  | 
9443  | 6.88k  |     CHECK_TYPE(XPATH_BOOLEAN);  | 
9444  | 2.27k  |     ctxt->value->boolval = ! ctxt->value->boolval;  | 
9445  | 2.27k  | }  | 
9446  |  |  | 
9447  |  | /**  | 
9448  |  |  * xmlXPathTrueFunction:  | 
9449  |  |  * @ctxt:  the XPath Parser context  | 
9450  |  |  * @nargs:  the number of arguments  | 
9451  |  |  *  | 
9452  |  |  * Implement the true() XPath function  | 
9453  |  |  *    boolean true()  | 
9454  |  |  */  | 
9455  |  | void  | 
9456  | 912  | xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) { | 
9457  | 2.68k  |     CHECK_ARITY(0);  | 
9458  | 2.68k  |     valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));  | 
9459  | 2.68k  | }  | 
9460  |  |  | 
9461  |  | /**  | 
9462  |  |  * xmlXPathFalseFunction:  | 
9463  |  |  * @ctxt:  the XPath Parser context  | 
9464  |  |  * @nargs:  the number of arguments  | 
9465  |  |  *  | 
9466  |  |  * Implement the false() XPath function  | 
9467  |  |  *    boolean false()  | 
9468  |  |  */  | 
9469  |  | void  | 
9470  | 2.31k  | xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) { | 
9471  | 6.77k  |     CHECK_ARITY(0);  | 
9472  | 6.77k  |     valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));  | 
9473  | 6.77k  | }  | 
9474  |  |  | 
9475  |  | /**  | 
9476  |  |  * xmlXPathLangFunction:  | 
9477  |  |  * @ctxt:  the XPath Parser context  | 
9478  |  |  * @nargs:  the number of arguments  | 
9479  |  |  *  | 
9480  |  |  * Implement the lang() XPath function  | 
9481  |  |  *    boolean lang(string)  | 
9482  |  |  * The lang function returns true or false depending on whether the  | 
9483  |  |  * language of the context node as specified by xml:lang attributes  | 
9484  |  |  * is the same as or is a sublanguage of the language specified by  | 
9485  |  |  * the argument string. The language of the context node is determined  | 
9486  |  |  * by the value of the xml:lang attribute on the context node, or, if  | 
9487  |  |  * the context node has no xml:lang attribute, by the value of the  | 
9488  |  |  * xml:lang attribute on the nearest ancestor of the context node that  | 
9489  |  |  * has an xml:lang attribute. If there is no such attribute, then lang  | 
9490  |  |  * returns false. If there is such an attribute, then lang returns  | 
9491  |  |  * true if the attribute value is equal to the argument ignoring case,  | 
9492  |  |  * or if there is some suffix starting with - such that the attribute  | 
9493  |  |  * value is equal to the argument ignoring that suffix of the attribute  | 
9494  |  |  * value and ignoring case.  | 
9495  |  |  */  | 
9496  |  | void  | 
9497  | 17.9k  | xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) { | 
9498  | 17.9k  |     xmlXPathObjectPtr val = NULL;  | 
9499  | 17.9k  |     const xmlChar *theLang = NULL;  | 
9500  | 17.9k  |     const xmlChar *lang;  | 
9501  | 17.9k  |     int ret = 0;  | 
9502  | 17.9k  |     int i;  | 
9503  |  |  | 
9504  | 53.6k  |     CHECK_ARITY(1);  | 
9505  | 53.6k  |     CAST_TO_STRING;  | 
9506  | 53.6k  |     CHECK_TYPE(XPATH_STRING);  | 
9507  | 17.8k  |     val = valuePop(ctxt);  | 
9508  | 17.8k  |     lang = val->stringval;  | 
9509  | 17.8k  |     theLang = xmlNodeGetLang(ctxt->context->node);  | 
9510  | 17.8k  |     if ((theLang != NULL) && (lang != NULL)) { | 
9511  | 0  |         for (i = 0;lang[i] != 0;i++)  | 
9512  | 0  |       if (toupper(lang[i]) != toupper(theLang[i]))  | 
9513  | 0  |           goto not_equal;  | 
9514  | 0  |   if ((theLang[i] == 0) || (theLang[i] == '-'))  | 
9515  | 0  |       ret = 1;  | 
9516  | 0  |     }  | 
9517  | 17.8k  | not_equal:  | 
9518  | 17.8k  |     if (theLang != NULL)  | 
9519  | 0  |   xmlFree((void *)theLang);  | 
9520  |  |  | 
9521  | 17.8k  |     xmlXPathReleaseObject(ctxt->context, val);  | 
9522  | 17.8k  |     valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));  | 
9523  | 17.8k  | }  | 
9524  |  |  | 
9525  |  | /**  | 
9526  |  |  * xmlXPathNumberFunction:  | 
9527  |  |  * @ctxt:  the XPath Parser context  | 
9528  |  |  * @nargs:  the number of arguments  | 
9529  |  |  *  | 
9530  |  |  * Implement the number() XPath function  | 
9531  |  |  *    number number(object?)  | 
9532  |  |  */  | 
9533  |  | void  | 
9534  | 9.55M  | xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) { | 
9535  | 9.55M  |     xmlXPathObjectPtr cur;  | 
9536  | 9.55M  |     double res;  | 
9537  |  |  | 
9538  | 9.55M  |     if (ctxt == NULL) return;  | 
9539  | 9.55M  |     if (nargs == 0) { | 
9540  | 2.98k  |   if (ctxt->context->node == NULL) { | 
9541  | 0  |       valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0.0));  | 
9542  | 2.98k  |   } else { | 
9543  | 2.98k  |       xmlChar* content = xmlNodeGetContent(ctxt->context->node);  | 
9544  |  |  | 
9545  | 2.98k  |       res = xmlXPathStringEvalNumber(content);  | 
9546  | 2.98k  |       valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));  | 
9547  | 2.98k  |       xmlFree(content);  | 
9548  | 2.98k  |   }  | 
9549  | 2.98k  |   return;  | 
9550  | 2.98k  |     }  | 
9551  |  |  | 
9552  | 38.2M  |     CHECK_ARITY(1);  | 
9553  | 38.2M  |     cur = valuePop(ctxt);  | 
9554  | 38.2M  |     valuePush(ctxt, xmlXPathCacheConvertNumber(ctxt->context, cur));  | 
9555  | 38.2M  | }  | 
9556  |  |  | 
9557  |  | /**  | 
9558  |  |  * xmlXPathSumFunction:  | 
9559  |  |  * @ctxt:  the XPath Parser context  | 
9560  |  |  * @nargs:  the number of arguments  | 
9561  |  |  *  | 
9562  |  |  * Implement the sum() XPath function  | 
9563  |  |  *    number sum(node-set)  | 
9564  |  |  * The sum function returns the sum of the values of the nodes in  | 
9565  |  |  * the argument node-set.  | 
9566  |  |  */  | 
9567  |  | void  | 
9568  | 9.89k  | xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) { | 
9569  | 9.89k  |     xmlXPathObjectPtr cur;  | 
9570  | 9.89k  |     int i;  | 
9571  | 9.89k  |     double res = 0.0;  | 
9572  |  |  | 
9573  | 29.0k  |     CHECK_ARITY(1);  | 
9574  | 29.0k  |     if ((ctxt->value == NULL) ||  | 
9575  | 9.57k  |   ((ctxt->value->type != XPATH_NODESET) &&  | 
9576  | 9.57k  |    (ctxt->value->type != XPATH_XSLT_TREE)))  | 
9577  | 8.44k  |   XP_ERROR(XPATH_INVALID_TYPE);  | 
9578  | 8.44k  |     cur = valuePop(ctxt);  | 
9579  |  |  | 
9580  | 8.44k  |     if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) { | 
9581  | 66.5k  |   for (i = 0; i < cur->nodesetval->nodeNr; i++) { | 
9582  | 63.6k  |       res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);  | 
9583  | 63.6k  |   }  | 
9584  | 2.83k  |     }  | 
9585  | 8.44k  |     valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));  | 
9586  | 8.44k  |     xmlXPathReleaseObject(ctxt->context, cur);  | 
9587  | 8.44k  | }  | 
9588  |  |  | 
9589  |  | /**  | 
9590  |  |  * xmlXPathFloorFunction:  | 
9591  |  |  * @ctxt:  the XPath Parser context  | 
9592  |  |  * @nargs:  the number of arguments  | 
9593  |  |  *  | 
9594  |  |  * Implement the floor() XPath function  | 
9595  |  |  *    number floor(number)  | 
9596  |  |  * The floor function returns the largest (closest to positive infinity)  | 
9597  |  |  * number that is not greater than the argument and that is an integer.  | 
9598  |  |  */  | 
9599  |  | void  | 
9600  | 1.01k  | xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) { | 
9601  | 3.01k  |     CHECK_ARITY(1);  | 
9602  | 3.01k  |     CAST_TO_NUMBER;  | 
9603  | 3.01k  |     CHECK_TYPE(XPATH_NUMBER);  | 
9604  |  |  | 
9605  | 999  |     ctxt->value->floatval = floor(ctxt->value->floatval);  | 
9606  | 999  | }  | 
9607  |  |  | 
9608  |  | /**  | 
9609  |  |  * xmlXPathCeilingFunction:  | 
9610  |  |  * @ctxt:  the XPath Parser context  | 
9611  |  |  * @nargs:  the number of arguments  | 
9612  |  |  *  | 
9613  |  |  * Implement the ceiling() XPath function  | 
9614  |  |  *    number ceiling(number)  | 
9615  |  |  * The ceiling function returns the smallest (closest to negative infinity)  | 
9616  |  |  * number that is not less than the argument and that is an integer.  | 
9617  |  |  */  | 
9618  |  | void  | 
9619  | 206  | xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) { | 
9620  | 588  |     CHECK_ARITY(1);  | 
9621  | 588  |     CAST_TO_NUMBER;  | 
9622  | 588  |     CHECK_TYPE(XPATH_NUMBER);  | 
9623  |  |  | 
9624  |  | #ifdef _AIX  | 
9625  |  |     /* Work around buggy ceil() function on AIX */  | 
9626  |  |     ctxt->value->floatval = copysign(ceil(ctxt->value->floatval), ctxt->value->floatval);  | 
9627  |  | #else  | 
9628  | 191  |     ctxt->value->floatval = ceil(ctxt->value->floatval);  | 
9629  | 191  | #endif  | 
9630  | 191  | }  | 
9631  |  |  | 
9632  |  | /**  | 
9633  |  |  * xmlXPathRoundFunction:  | 
9634  |  |  * @ctxt:  the XPath Parser context  | 
9635  |  |  * @nargs:  the number of arguments  | 
9636  |  |  *  | 
9637  |  |  * Implement the round() XPath function  | 
9638  |  |  *    number round(number)  | 
9639  |  |  * The round function returns the number that is closest to the  | 
9640  |  |  * argument and that is an integer. If there are two such numbers,  | 
9641  |  |  * then the one that is closest to positive infinity is returned.  | 
9642  |  |  */  | 
9643  |  | void  | 
9644  | 1.55k  | xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) { | 
9645  | 1.55k  |     double f;  | 
9646  |  |  | 
9647  | 4.63k  |     CHECK_ARITY(1);  | 
9648  | 4.63k  |     CAST_TO_NUMBER;  | 
9649  | 4.63k  |     CHECK_TYPE(XPATH_NUMBER);  | 
9650  |  |  | 
9651  | 1.54k  |     f = ctxt->value->floatval;  | 
9652  |  |  | 
9653  | 1.54k  |     if ((f >= -0.5) && (f < 0.5)) { | 
9654  |  |         /* Handles negative zero. */  | 
9655  | 580  |         ctxt->value->floatval *= 0.0;  | 
9656  | 580  |     }  | 
9657  | 961  |     else { | 
9658  | 961  |         double rounded = floor(f);  | 
9659  | 961  |         if (f - rounded >= 0.5)  | 
9660  | 0  |             rounded += 1.0;  | 
9661  | 961  |         ctxt->value->floatval = rounded;  | 
9662  | 961  |     }  | 
9663  | 1.54k  | }  | 
9664  |  |  | 
9665  |  | /************************************************************************  | 
9666  |  |  *                  *  | 
9667  |  |  *      The Parser          *  | 
9668  |  |  *                  *  | 
9669  |  |  ************************************************************************/  | 
9670  |  |  | 
9671  |  | /*  | 
9672  |  |  * a few forward declarations since we use a recursive call based  | 
9673  |  |  * implementation.  | 
9674  |  |  */  | 
9675  |  | static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort);  | 
9676  |  | static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);  | 
9677  |  | static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);  | 
9678  |  | static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);  | 
9679  |  | static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,  | 
9680  |  |                                     int qualified);  | 
9681  |  |  | 
9682  |  | /**  | 
9683  |  |  * xmlXPathCurrentChar:  | 
9684  |  |  * @ctxt:  the XPath parser context  | 
9685  |  |  * @cur:  pointer to the beginning of the char  | 
9686  |  |  * @len:  pointer to the length of the char read  | 
9687  |  |  *  | 
9688  |  |  * The current char value, if using UTF-8 this may actually span multiple  | 
9689  |  |  * bytes in the input buffer.  | 
9690  |  |  *  | 
9691  |  |  * Returns the current char value and its length  | 
9692  |  |  */  | 
9693  |  |  | 
9694  |  | static int  | 
9695  | 127M  | xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) { | 
9696  | 127M  |     unsigned char c;  | 
9697  | 127M  |     unsigned int val;  | 
9698  | 127M  |     const xmlChar *cur;  | 
9699  |  |  | 
9700  | 127M  |     if (ctxt == NULL)  | 
9701  | 0  |   return(0);  | 
9702  | 127M  |     cur = ctxt->cur;  | 
9703  |  |  | 
9704  |  |     /*  | 
9705  |  |      * We are supposed to handle UTF8, check it's valid  | 
9706  |  |      * From rfc2044: encoding of the Unicode values on UTF-8:  | 
9707  |  |      *  | 
9708  |  |      * UCS-4 range (hex.)           UTF-8 octet sequence (binary)  | 
9709  |  |      * 0000 0000-0000 007F   0xxxxxxx  | 
9710  |  |      * 0000 0080-0000 07FF   110xxxxx 10xxxxxx  | 
9711  |  |      * 0000 0800-0000 FFFF   1110xxxx 10xxxxxx 10xxxxxx  | 
9712  |  |      *  | 
9713  |  |      * Check for the 0x110000 limit too  | 
9714  |  |      */  | 
9715  | 127M  |     c = *cur;  | 
9716  | 127M  |     if (c & 0x80) { | 
9717  | 11.2M  |   if ((cur[1] & 0xc0) != 0x80)  | 
9718  | 172k  |       goto encoding_error;  | 
9719  | 11.1M  |   if ((c & 0xe0) == 0xe0) { | 
9720  |  |  | 
9721  | 126k  |       if ((cur[2] & 0xc0) != 0x80)  | 
9722  | 16.1k  |     goto encoding_error;  | 
9723  | 110k  |       if ((c & 0xf0) == 0xf0) { | 
9724  | 51.5k  |     if (((c & 0xf8) != 0xf0) ||  | 
9725  | 51.5k  |         ((cur[3] & 0xc0) != 0x80))  | 
9726  | 19.1k  |         goto encoding_error;  | 
9727  |  |     /* 4-byte code */  | 
9728  | 32.3k  |     *len = 4;  | 
9729  | 32.3k  |     val = (cur[0] & 0x7) << 18;  | 
9730  | 32.3k  |     val |= (cur[1] & 0x3f) << 12;  | 
9731  | 32.3k  |     val |= (cur[2] & 0x3f) << 6;  | 
9732  | 32.3k  |     val |= cur[3] & 0x3f;  | 
9733  | 58.5k  |       } else { | 
9734  |  |         /* 3-byte code */  | 
9735  | 58.5k  |     *len = 3;  | 
9736  | 58.5k  |     val = (cur[0] & 0xf) << 12;  | 
9737  | 58.5k  |     val |= (cur[1] & 0x3f) << 6;  | 
9738  | 58.5k  |     val |= cur[2] & 0x3f;  | 
9739  | 58.5k  |       }  | 
9740  | 10.9M  |   } else { | 
9741  |  |     /* 2-byte code */  | 
9742  | 10.9M  |       *len = 2;  | 
9743  | 10.9M  |       val = (cur[0] & 0x1f) << 6;  | 
9744  | 10.9M  |       val |= cur[1] & 0x3f;  | 
9745  | 10.9M  |   }  | 
9746  | 11.0M  |   if (!IS_CHAR(val)) { | 
9747  | 17.3k  |       XP_ERROR0(XPATH_INVALID_CHAR_ERROR);  | 
9748  | 0  |   }  | 
9749  | 11.0M  |   return(val);  | 
9750  | 116M  |     } else { | 
9751  |  |   /* 1-byte code */  | 
9752  | 116M  |   *len = 1;  | 
9753  | 116M  |   return(*cur);  | 
9754  | 116M  |     }  | 
9755  | 208k  | encoding_error:  | 
9756  |  |     /*  | 
9757  |  |      * If we detect an UTF8 error that probably means that the  | 
9758  |  |      * input encoding didn't get properly advertised in the  | 
9759  |  |      * declaration header. Report the error and switch the encoding  | 
9760  |  |      * to ISO-Latin-1 (if you don't like this policy, just declare the  | 
9761  |  |      * encoding !)  | 
9762  |  |      */  | 
9763  | 208k  |     *len = 0;  | 
9764  | 208k  |     XP_ERROR0(XPATH_ENCODING_ERROR);  | 
9765  | 0  | }  | 
9766  |  |  | 
9767  |  | /**  | 
9768  |  |  * xmlXPathParseNCName:  | 
9769  |  |  * @ctxt:  the XPath Parser context  | 
9770  |  |  *  | 
9771  |  |  * parse an XML namespace non qualified name.  | 
9772  |  |  *  | 
9773  |  |  * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*  | 
9774  |  |  *  | 
9775  |  |  * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |  | 
9776  |  |  *                       CombiningChar | Extender  | 
9777  |  |  *  | 
9778  |  |  * Returns the namespace name or NULL  | 
9779  |  |  */  | 
9780  |  |  | 
9781  |  | xmlChar *  | 
9782  | 6.73M  | xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) { | 
9783  | 6.73M  |     const xmlChar *in;  | 
9784  | 6.73M  |     xmlChar *ret;  | 
9785  | 6.73M  |     int count = 0;  | 
9786  |  |  | 
9787  | 6.73M  |     if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);  | 
9788  |  |     /*  | 
9789  |  |      * Accelerator for simple ASCII names  | 
9790  |  |      */  | 
9791  | 6.73M  |     in = ctxt->cur;  | 
9792  | 6.73M  |     if (((*in >= 0x61) && (*in <= 0x7A)) ||  | 
9793  | 6.73M  |   ((*in >= 0x41) && (*in <= 0x5A)) ||  | 
9794  | 6.73M  |   (*in == '_')) { | 
9795  | 5.69M  |   in++;  | 
9796  | 85.1M  |   while (((*in >= 0x61) && (*in <= 0x7A)) ||  | 
9797  | 85.1M  |          ((*in >= 0x41) && (*in <= 0x5A)) ||  | 
9798  | 85.1M  |          ((*in >= 0x30) && (*in <= 0x39)) ||  | 
9799  | 85.1M  |          (*in == '_') || (*in == '.') ||  | 
9800  | 85.1M  |          (*in == '-'))  | 
9801  | 79.4M  |       in++;  | 
9802  | 5.69M  |   if ((*in == ' ') || (*in == '>') || (*in == '/') ||  | 
9803  | 5.69M  |             (*in == '[') || (*in == ']') || (*in == ':') ||  | 
9804  | 5.69M  |             (*in == '@') || (*in == '*')) { | 
9805  | 3.24M  |       count = in - ctxt->cur;  | 
9806  | 3.24M  |       if (count == 0)  | 
9807  | 0  |     return(NULL);  | 
9808  | 3.24M  |       ret = xmlStrndup(ctxt->cur, count);  | 
9809  | 3.24M  |       ctxt->cur = in;  | 
9810  | 3.24M  |       return(ret);  | 
9811  | 3.24M  |   }  | 
9812  | 5.69M  |     }  | 
9813  | 3.49M  |     return(xmlXPathParseNameComplex(ctxt, 0));  | 
9814  | 6.73M  | }  | 
9815  |  |  | 
9816  |  |  | 
9817  |  | /**  | 
9818  |  |  * xmlXPathParseQName:  | 
9819  |  |  * @ctxt:  the XPath Parser context  | 
9820  |  |  * @prefix:  a xmlChar **  | 
9821  |  |  *  | 
9822  |  |  * parse an XML qualified name  | 
9823  |  |  *  | 
9824  |  |  * [NS 5] QName ::= (Prefix ':')? LocalPart  | 
9825  |  |  *  | 
9826  |  |  * [NS 6] Prefix ::= NCName  | 
9827  |  |  *  | 
9828  |  |  * [NS 7] LocalPart ::= NCName  | 
9829  |  |  *  | 
9830  |  |  * Returns the function returns the local part, and prefix is updated  | 
9831  |  |  *   to get the Prefix if any.  | 
9832  |  |  */  | 
9833  |  |  | 
9834  |  | static xmlChar *  | 
9835  | 823k  | xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) { | 
9836  | 823k  |     xmlChar *ret = NULL;  | 
9837  |  |  | 
9838  | 823k  |     *prefix = NULL;  | 
9839  | 823k  |     ret = xmlXPathParseNCName(ctxt);  | 
9840  | 823k  |     if (ret && CUR == ':') { | 
9841  | 290k  |         *prefix = ret;  | 
9842  | 290k  |   NEXT;  | 
9843  | 290k  |   ret = xmlXPathParseNCName(ctxt);  | 
9844  | 290k  |     }  | 
9845  | 823k  |     return(ret);  | 
9846  | 823k  | }  | 
9847  |  |  | 
9848  |  | /**  | 
9849  |  |  * xmlXPathParseName:  | 
9850  |  |  * @ctxt:  the XPath Parser context  | 
9851  |  |  *  | 
9852  |  |  * parse an XML name  | 
9853  |  |  *  | 
9854  |  |  * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |  | 
9855  |  |  *                  CombiningChar | Extender  | 
9856  |  |  *  | 
9857  |  |  * [5] Name ::= (Letter | '_' | ':') (NameChar)*  | 
9858  |  |  *  | 
9859  |  |  * Returns the namespace name or NULL  | 
9860  |  |  */  | 
9861  |  |  | 
9862  |  | xmlChar *  | 
9863  | 61.8k  | xmlXPathParseName(xmlXPathParserContextPtr ctxt) { | 
9864  | 61.8k  |     const xmlChar *in;  | 
9865  | 61.8k  |     xmlChar *ret;  | 
9866  | 61.8k  |     size_t count = 0;  | 
9867  |  |  | 
9868  | 61.8k  |     if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);  | 
9869  |  |     /*  | 
9870  |  |      * Accelerator for simple ASCII names  | 
9871  |  |      */  | 
9872  | 61.8k  |     in = ctxt->cur;  | 
9873  | 61.8k  |     if (((*in >= 0x61) && (*in <= 0x7A)) ||  | 
9874  | 61.8k  |   ((*in >= 0x41) && (*in <= 0x5A)) ||  | 
9875  | 61.8k  |   (*in == '_') || (*in == ':')) { | 
9876  | 11.7k  |   in++;  | 
9877  | 300k  |   while (((*in >= 0x61) && (*in <= 0x7A)) ||  | 
9878  | 300k  |          ((*in >= 0x41) && (*in <= 0x5A)) ||  | 
9879  | 300k  |          ((*in >= 0x30) && (*in <= 0x39)) ||  | 
9880  | 300k  |          (*in == '_') || (*in == '-') ||  | 
9881  | 300k  |          (*in == ':') || (*in == '.'))  | 
9882  | 288k  |       in++;  | 
9883  | 11.7k  |   if ((*in > 0) && (*in < 0x80)) { | 
9884  | 9.08k  |       count = in - ctxt->cur;  | 
9885  | 9.08k  |             if (count > XML_MAX_NAME_LENGTH) { | 
9886  | 0  |                 ctxt->cur = in;  | 
9887  | 0  |                 XP_ERRORNULL(XPATH_EXPR_ERROR);  | 
9888  | 0  |             }  | 
9889  | 9.08k  |       ret = xmlStrndup(ctxt->cur, count);  | 
9890  | 9.08k  |       ctxt->cur = in;  | 
9891  | 9.08k  |       return(ret);  | 
9892  | 9.08k  |   }  | 
9893  | 11.7k  |     }  | 
9894  | 52.7k  |     return(xmlXPathParseNameComplex(ctxt, 1));  | 
9895  | 61.8k  | }  | 
9896  |  |  | 
9897  |  | static xmlChar *  | 
9898  | 3.54M  | xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) { | 
9899  | 3.54M  |     xmlChar buf[XML_MAX_NAMELEN + 5];  | 
9900  | 3.54M  |     int len = 0, l;  | 
9901  | 3.54M  |     int c;  | 
9902  |  |  | 
9903  |  |     /*  | 
9904  |  |      * Handler for more complex cases  | 
9905  |  |      */  | 
9906  | 3.54M  |     c = CUR_CHAR(l);  | 
9907  | 3.54M  |     if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */  | 
9908  | 3.54M  |         (c == '[') || (c == ']') || (c == '@') || /* accelerators */  | 
9909  | 3.54M  |         (c == '*') || /* accelerators */  | 
9910  | 3.54M  |   (!IS_LETTER(c) && (c != '_') &&  | 
9911  | 2.82M  |          ((!qualified) || (c != ':')))) { | 
9912  | 996k  |   return(NULL);  | 
9913  | 996k  |     }  | 
9914  |  |  | 
9915  | 31.0M  |     while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */  | 
9916  | 31.0M  |      ((IS_LETTER(c)) || (IS_DIGIT(c)) ||  | 
9917  | 30.9M  |             (c == '.') || (c == '-') ||  | 
9918  | 30.9M  |       (c == '_') || ((qualified) && (c == ':')) ||  | 
9919  | 30.9M  |       (IS_COMBINING(c)) ||  | 
9920  | 30.9M  |       (IS_EXTENDER(c)))) { | 
9921  | 28.6M  |   COPY_BUF(l,buf,len,c);  | 
9922  | 28.6M  |   NEXTL(l);  | 
9923  | 28.6M  |   c = CUR_CHAR(l);  | 
9924  | 28.6M  |   if (len >= XML_MAX_NAMELEN) { | 
9925  |  |       /*  | 
9926  |  |        * Okay someone managed to make a huge name, so he's ready to pay  | 
9927  |  |        * for the processing speed.  | 
9928  |  |        */  | 
9929  | 128k  |       xmlChar *buffer;  | 
9930  | 128k  |       int max = len * 2;  | 
9931  |  |  | 
9932  | 128k  |             if (len > XML_MAX_NAME_LENGTH) { | 
9933  | 0  |                 XP_ERRORNULL(XPATH_EXPR_ERROR);  | 
9934  | 0  |             }  | 
9935  | 128k  |       buffer = (xmlChar *) xmlMallocAtomic(max);  | 
9936  | 128k  |       if (buffer == NULL) { | 
9937  | 0  |     XP_ERRORNULL(XPATH_MEMORY_ERROR);  | 
9938  | 0  |       }  | 
9939  | 128k  |       memcpy(buffer, buf, len);  | 
9940  | 23.5M  |       while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */  | 
9941  | 23.5M  |        (c == '.') || (c == '-') ||  | 
9942  | 23.5M  |        (c == '_') || ((qualified) && (c == ':')) ||  | 
9943  | 23.5M  |        (IS_COMBINING(c)) ||  | 
9944  | 23.5M  |        (IS_EXTENDER(c))) { | 
9945  | 23.4M  |     if (len + 10 > max) { | 
9946  | 102k  |                     xmlChar *tmp;  | 
9947  | 102k  |                     if (max > XML_MAX_NAME_LENGTH) { | 
9948  | 15  |                         xmlFree(buffer);  | 
9949  | 15  |                         XP_ERRORNULL(XPATH_EXPR_ERROR);  | 
9950  | 0  |                     }  | 
9951  | 102k  |         max *= 2;  | 
9952  | 102k  |         tmp = (xmlChar *) xmlRealloc(buffer, max);  | 
9953  | 102k  |         if (tmp == NULL) { | 
9954  | 0  |                         xmlFree(buffer);  | 
9955  | 0  |       XP_ERRORNULL(XPATH_MEMORY_ERROR);  | 
9956  | 0  |         }  | 
9957  | 102k  |                     buffer = tmp;  | 
9958  | 102k  |     }  | 
9959  | 23.4M  |     COPY_BUF(l,buffer,len,c);  | 
9960  | 23.4M  |     NEXTL(l);  | 
9961  | 23.4M  |     c = CUR_CHAR(l);  | 
9962  | 23.4M  |       }  | 
9963  | 128k  |       buffer[len] = 0;  | 
9964  | 128k  |       return(buffer);  | 
9965  | 128k  |   }  | 
9966  | 28.6M  |     }  | 
9967  | 2.42M  |     if (len == 0)  | 
9968  | 0  |   return(NULL);  | 
9969  | 2.42M  |     return(xmlStrndup(buf, len));  | 
9970  | 2.42M  | }  | 
9971  |  |  | 
9972  | 457k  | #define MAX_FRAC 20  | 
9973  |  |  | 
9974  |  | /**  | 
9975  |  |  * xmlXPathStringEvalNumber:  | 
9976  |  |  * @str:  A string to scan  | 
9977  |  |  *  | 
9978  |  |  *  [30a]  Float  ::= Number ('e' Digits?)? | 
9979  |  |  *  | 
9980  |  |  *  [30]   Number ::=   Digits ('.' Digits?)? | 
9981  |  |  *                    | '.' Digits  | 
9982  |  |  *  [31]   Digits ::=   [0-9]+  | 
9983  |  |  *  | 
9984  |  |  * Compile a Number in the string  | 
9985  |  |  * In complement of the Number expression, this function also handles  | 
9986  |  |  * negative values : '-' Number.  | 
9987  |  |  *  | 
9988  |  |  * Returns the double value.  | 
9989  |  |  */  | 
9990  |  | double  | 
9991  | 13.0M  | xmlXPathStringEvalNumber(const xmlChar *str) { | 
9992  | 13.0M  |     const xmlChar *cur = str;  | 
9993  | 13.0M  |     double ret;  | 
9994  | 13.0M  |     int ok = 0;  | 
9995  | 13.0M  |     int isneg = 0;  | 
9996  | 13.0M  |     int exponent = 0;  | 
9997  | 13.0M  |     int is_exponent_negative = 0;  | 
9998  | 13.0M  | #ifdef __GNUC__  | 
9999  | 13.0M  |     unsigned long tmp = 0;  | 
10000  | 13.0M  |     double temp;  | 
10001  | 13.0M  | #endif  | 
10002  | 13.0M  |     if (cur == NULL) return(0);  | 
10003  | 26.5M  |     while (IS_BLANK_CH(*cur)) cur++;  | 
10004  | 13.0M  |     if (*cur == '-') { | 
10005  | 138k  |   isneg = 1;  | 
10006  | 138k  |   cur++;  | 
10007  | 138k  |     }  | 
10008  | 13.0M  |     if ((*cur != '.') && ((*cur < '0') || (*cur > '9'))) { | 
10009  | 11.6M  |         return(xmlXPathNAN);  | 
10010  | 11.6M  |     }  | 
10011  |  |  | 
10012  | 1.47M  | #ifdef __GNUC__  | 
10013  |  |     /*  | 
10014  |  |      * tmp/temp is a workaround against a gcc compiler bug  | 
10015  |  |      * http://veillard.com/gcc.bug  | 
10016  |  |      */  | 
10017  | 1.47M  |     ret = 0;  | 
10018  | 4.40M  |     while ((*cur >= '0') && (*cur <= '9')) { | 
10019  | 2.92M  |   ret = ret * 10;  | 
10020  | 2.92M  |   tmp = (*cur - '0');  | 
10021  | 2.92M  |   ok = 1;  | 
10022  | 2.92M  |   cur++;  | 
10023  | 2.92M  |   temp = (double) tmp;  | 
10024  | 2.92M  |   ret = ret + temp;  | 
10025  | 2.92M  |     }  | 
10026  |  | #else  | 
10027  |  |     ret = 0;  | 
10028  |  |     while ((*cur >= '0') && (*cur <= '9')) { | 
10029  |  |   ret = ret * 10 + (*cur - '0');  | 
10030  |  |   ok = 1;  | 
10031  |  |   cur++;  | 
10032  |  |     }  | 
10033  |  | #endif  | 
10034  |  |  | 
10035  | 1.47M  |     if (*cur == '.') { | 
10036  | 181k  |   int v, frac = 0, max;  | 
10037  | 181k  |   double fraction = 0;  | 
10038  |  |  | 
10039  | 181k  |         cur++;  | 
10040  | 181k  |   if (((*cur < '0') || (*cur > '9')) && (!ok)) { | 
10041  | 6.53k  |       return(xmlXPathNAN);  | 
10042  | 6.53k  |   }  | 
10043  | 332k  |         while (*cur == '0') { | 
10044  | 157k  |       frac = frac + 1;  | 
10045  | 157k  |       cur++;  | 
10046  | 157k  |         }  | 
10047  | 175k  |         max = frac + MAX_FRAC;  | 
10048  | 392k  |   while (((*cur >= '0') && (*cur <= '9')) && (frac < max)) { | 
10049  | 216k  |       v = (*cur - '0');  | 
10050  | 216k  |       fraction = fraction * 10 + v;  | 
10051  | 216k  |       frac = frac + 1;  | 
10052  | 216k  |       cur++;  | 
10053  | 216k  |   }  | 
10054  | 175k  |   fraction /= pow(10.0, frac);  | 
10055  | 175k  |   ret = ret + fraction;  | 
10056  | 348k  |   while ((*cur >= '0') && (*cur <= '9'))  | 
10057  | 172k  |       cur++;  | 
10058  | 175k  |     }  | 
10059  | 1.46M  |     if ((*cur == 'e') || (*cur == 'E')) { | 
10060  | 38.6k  |       cur++;  | 
10061  | 38.6k  |       if (*cur == '-') { | 
10062  | 4.24k  |   is_exponent_negative = 1;  | 
10063  | 4.24k  |   cur++;  | 
10064  | 34.3k  |       } else if (*cur == '+') { | 
10065  | 6.32k  |         cur++;  | 
10066  | 6.32k  |       }  | 
10067  | 213k  |       while ((*cur >= '0') && (*cur <= '9')) { | 
10068  | 174k  |         if (exponent < 1000000)  | 
10069  | 84.8k  |     exponent = exponent * 10 + (*cur - '0');  | 
10070  | 174k  |   cur++;  | 
10071  | 174k  |       }  | 
10072  | 38.6k  |     }  | 
10073  | 1.46M  |     while (IS_BLANK_CH(*cur)) cur++;  | 
10074  | 1.46M  |     if (*cur != 0) return(xmlXPathNAN);  | 
10075  | 1.27M  |     if (isneg) ret = -ret;  | 
10076  | 1.27M  |     if (is_exponent_negative) exponent = -exponent;  | 
10077  | 1.27M  |     ret *= pow(10.0, (double)exponent);  | 
10078  | 1.27M  |     return(ret);  | 
10079  | 1.46M  | }  | 
10080  |  |  | 
10081  |  | /**  | 
10082  |  |  * xmlXPathCompNumber:  | 
10083  |  |  * @ctxt:  the XPath Parser context  | 
10084  |  |  *  | 
10085  |  |  *  [30]   Number ::=   Digits ('.' Digits?)? | 
10086  |  |  *                    | '.' Digits  | 
10087  |  |  *  [31]   Digits ::=   [0-9]+  | 
10088  |  |  *  | 
10089  |  |  * Compile a Number, then push it on the stack  | 
10090  |  |  *  | 
10091  |  |  */  | 
10092  |  | static void  | 
10093  |  | xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)  | 
10094  | 1.15M  | { | 
10095  | 1.15M  |     double ret = 0.0;  | 
10096  | 1.15M  |     int ok = 0;  | 
10097  | 1.15M  |     int exponent = 0;  | 
10098  | 1.15M  |     int is_exponent_negative = 0;  | 
10099  | 1.15M  |     xmlXPathObjectPtr num;  | 
10100  | 1.15M  | #ifdef __GNUC__  | 
10101  | 1.15M  |     unsigned long tmp = 0;  | 
10102  | 1.15M  |     double temp;  | 
10103  | 1.15M  | #endif  | 
10104  |  |  | 
10105  | 1.15M  |     CHECK_ERROR;  | 
10106  | 1.14M  |     if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) { | 
10107  | 0  |         XP_ERROR(XPATH_NUMBER_ERROR);  | 
10108  | 0  |     }  | 
10109  | 1.14M  | #ifdef __GNUC__  | 
10110  |  |     /*  | 
10111  |  |      * tmp/temp is a workaround against a gcc compiler bug  | 
10112  |  |      * http://veillard.com/gcc.bug  | 
10113  |  |      */  | 
10114  | 1.14M  |     ret = 0;  | 
10115  | 6.98M  |     while ((CUR >= '0') && (CUR <= '9')) { | 
10116  | 5.83M  |   ret = ret * 10;  | 
10117  | 5.83M  |   tmp = (CUR - '0');  | 
10118  | 5.83M  |         ok = 1;  | 
10119  | 5.83M  |         NEXT;  | 
10120  | 5.83M  |   temp = (double) tmp;  | 
10121  | 5.83M  |   ret = ret + temp;  | 
10122  | 5.83M  |     }  | 
10123  |  | #else  | 
10124  |  |     ret = 0;  | 
10125  |  |     while ((CUR >= '0') && (CUR <= '9')) { | 
10126  |  |   ret = ret * 10 + (CUR - '0');  | 
10127  |  |   ok = 1;  | 
10128  |  |   NEXT;  | 
10129  |  |     }  | 
10130  |  | #endif  | 
10131  | 1.14M  |     if (CUR == '.') { | 
10132  | 281k  |   int v, frac = 0, max;  | 
10133  | 281k  |   double fraction = 0;  | 
10134  |  |  | 
10135  | 281k  |         NEXT;  | 
10136  | 281k  |         if (((CUR < '0') || (CUR > '9')) && (!ok)) { | 
10137  | 0  |             XP_ERROR(XPATH_NUMBER_ERROR);  | 
10138  | 0  |         }  | 
10139  | 324k  |         while (CUR == '0') { | 
10140  | 42.3k  |             frac = frac + 1;  | 
10141  | 42.3k  |             NEXT;  | 
10142  | 42.3k  |         }  | 
10143  | 281k  |         max = frac + MAX_FRAC;  | 
10144  | 735k  |         while ((CUR >= '0') && (CUR <= '9') && (frac < max)) { | 
10145  | 454k  |       v = (CUR - '0');  | 
10146  | 454k  |       fraction = fraction * 10 + v;  | 
10147  | 454k  |       frac = frac + 1;  | 
10148  | 454k  |             NEXT;  | 
10149  | 454k  |         }  | 
10150  | 281k  |         fraction /= pow(10.0, frac);  | 
10151  | 281k  |         ret = ret + fraction;  | 
10152  | 680k  |         while ((CUR >= '0') && (CUR <= '9'))  | 
10153  | 399k  |             NEXT;  | 
10154  | 281k  |     }  | 
10155  | 1.14M  |     if ((CUR == 'e') || (CUR == 'E')) { | 
10156  | 110k  |         NEXT;  | 
10157  | 110k  |         if (CUR == '-') { | 
10158  | 6.03k  |             is_exponent_negative = 1;  | 
10159  | 6.03k  |             NEXT;  | 
10160  | 104k  |         } else if (CUR == '+') { | 
10161  | 31.8k  |       NEXT;  | 
10162  | 31.8k  |   }  | 
10163  | 415k  |         while ((CUR >= '0') && (CUR <= '9')) { | 
10164  | 304k  |             if (exponent < 1000000)  | 
10165  | 260k  |                 exponent = exponent * 10 + (CUR - '0');  | 
10166  | 304k  |             NEXT;  | 
10167  | 304k  |         }  | 
10168  | 110k  |         if (is_exponent_negative)  | 
10169  | 6.03k  |             exponent = -exponent;  | 
10170  | 110k  |         ret *= pow(10.0, (double) exponent);  | 
10171  | 110k  |     }  | 
10172  | 1.14M  |     num = xmlXPathCacheNewFloat(ctxt->context, ret);  | 
10173  | 1.14M  |     if (num == NULL) { | 
10174  | 0  |   ctxt->error = XPATH_MEMORY_ERROR;  | 
10175  | 1.14M  |     } else if (PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0, num,  | 
10176  | 1.14M  |                               NULL) == -1) { | 
10177  | 0  |         xmlXPathReleaseObject(ctxt->context, num);  | 
10178  | 0  |     }  | 
10179  | 1.14M  | }  | 
10180  |  |  | 
10181  |  | /**  | 
10182  |  |  * xmlXPathParseLiteral:  | 
10183  |  |  * @ctxt:  the XPath Parser context  | 
10184  |  |  *  | 
10185  |  |  * Parse a Literal  | 
10186  |  |  *  | 
10187  |  |  *  [29]   Literal ::=   '"' [^"]* '"'  | 
10188  |  |  *                    | "'" [^']* "'"  | 
10189  |  |  *  | 
10190  |  |  * Returns the value found or NULL in case of error  | 
10191  |  |  */  | 
10192  |  | static xmlChar *  | 
10193  | 10.8k  | xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) { | 
10194  | 10.8k  |     const xmlChar *q;  | 
10195  | 10.8k  |     xmlChar *ret = NULL;  | 
10196  |  |  | 
10197  | 10.8k  |     if (CUR == '"') { | 
10198  | 5.93k  |         NEXT;  | 
10199  | 5.93k  |   q = CUR_PTR;  | 
10200  | 757k  |   while ((IS_CHAR_CH(CUR)) && (CUR != '"'))  | 
10201  | 751k  |       NEXT;  | 
10202  | 5.93k  |   if (!IS_CHAR_CH(CUR)) { | 
10203  | 2.64k  |       XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);  | 
10204  | 3.29k  |   } else { | 
10205  | 3.29k  |       ret = xmlStrndup(q, CUR_PTR - q);  | 
10206  | 3.29k  |       NEXT;  | 
10207  | 3.29k  |         }  | 
10208  | 5.93k  |     } else if (CUR == '\'') { | 
10209  | 1.25k  |         NEXT;  | 
10210  | 1.25k  |   q = CUR_PTR;  | 
10211  | 71.4k  |   while ((IS_CHAR_CH(CUR)) && (CUR != '\''))  | 
10212  | 70.1k  |       NEXT;  | 
10213  | 1.25k  |   if (!IS_CHAR_CH(CUR)) { | 
10214  | 404  |       XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);  | 
10215  | 847  |   } else { | 
10216  | 847  |       ret = xmlStrndup(q, CUR_PTR - q);  | 
10217  | 847  |       NEXT;  | 
10218  | 847  |         }  | 
10219  | 3.70k  |     } else { | 
10220  | 3.70k  |   XP_ERRORNULL(XPATH_START_LITERAL_ERROR);  | 
10221  | 0  |     }  | 
10222  | 4.13k  |     return(ret);  | 
10223  | 10.8k  | }  | 
10224  |  |  | 
10225  |  | /**  | 
10226  |  |  * xmlXPathCompLiteral:  | 
10227  |  |  * @ctxt:  the XPath Parser context  | 
10228  |  |  *  | 
10229  |  |  * Parse a Literal and push it on the stack.  | 
10230  |  |  *  | 
10231  |  |  *  [29]   Literal ::=   '"' [^"]* '"'  | 
10232  |  |  *                    | "'" [^']* "'"  | 
10233  |  |  *  | 
10234  |  |  * TODO: xmlXPathCompLiteral memory allocation could be improved.  | 
10235  |  |  */  | 
10236  |  | static void  | 
10237  | 384k  | xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) { | 
10238  | 384k  |     const xmlChar *q;  | 
10239  | 384k  |     xmlChar *ret = NULL;  | 
10240  | 384k  |     xmlXPathObjectPtr lit;  | 
10241  |  |  | 
10242  | 384k  |     if (CUR == '"') { | 
10243  | 47.4k  |         NEXT;  | 
10244  | 47.4k  |   q = CUR_PTR;  | 
10245  | 2.22M  |   while ((IS_CHAR_CH(CUR)) && (CUR != '"'))  | 
10246  | 2.17M  |       NEXT;  | 
10247  | 47.4k  |   if (!IS_CHAR_CH(CUR)) { | 
10248  | 6.72k  |       XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);  | 
10249  | 40.6k  |   } else { | 
10250  | 40.6k  |       ret = xmlStrndup(q, CUR_PTR - q);  | 
10251  | 40.6k  |       NEXT;  | 
10252  | 40.6k  |         }  | 
10253  | 336k  |     } else if (CUR == '\'') { | 
10254  | 336k  |         NEXT;  | 
10255  | 336k  |   q = CUR_PTR;  | 
10256  | 58.5M  |   while ((IS_CHAR_CH(CUR)) && (CUR != '\''))  | 
10257  | 58.2M  |       NEXT;  | 
10258  | 336k  |   if (!IS_CHAR_CH(CUR)) { | 
10259  | 1.03k  |       XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);  | 
10260  | 335k  |   } else { | 
10261  | 335k  |       ret = xmlStrndup(q, CUR_PTR - q);  | 
10262  | 335k  |       NEXT;  | 
10263  | 335k  |         }  | 
10264  | 336k  |     } else { | 
10265  | 0  |   XP_ERROR(XPATH_START_LITERAL_ERROR);  | 
10266  | 0  |     }  | 
10267  | 376k  |     if (ret == NULL) return;  | 
10268  | 376k  |     lit = xmlXPathCacheNewString(ctxt->context, ret);  | 
10269  | 376k  |     if (lit == NULL) { | 
10270  | 0  |   ctxt->error = XPATH_MEMORY_ERROR;  | 
10271  | 376k  |     } else if (PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0, lit,  | 
10272  | 376k  |                               NULL) == -1) { | 
10273  | 0  |         xmlXPathReleaseObject(ctxt->context, lit);  | 
10274  | 0  |     }  | 
10275  | 376k  |     xmlFree(ret);  | 
10276  | 376k  | }  | 
10277  |  |  | 
10278  |  | /**  | 
10279  |  |  * xmlXPathCompVariableReference:  | 
10280  |  |  * @ctxt:  the XPath Parser context  | 
10281  |  |  *  | 
10282  |  |  * Parse a VariableReference, evaluate it and push it on the stack.  | 
10283  |  |  *  | 
10284  |  |  * The variable bindings consist of a mapping from variable names  | 
10285  |  |  * to variable values. The value of a variable is an object, which can be  | 
10286  |  |  * of any of the types that are possible for the value of an expression,  | 
10287  |  |  * and may also be of additional types not specified here.  | 
10288  |  |  *  | 
10289  |  |  * Early evaluation is possible since:  | 
10290  |  |  * The variable bindings [...] used to evaluate a subexpression are  | 
10291  |  |  * always the same as those used to evaluate the containing expression.  | 
10292  |  |  *  | 
10293  |  |  *  [36]   VariableReference ::=   '$' QName  | 
10294  |  |  */  | 
10295  |  | static void  | 
10296  | 232k  | xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) { | 
10297  | 232k  |     xmlChar *name;  | 
10298  | 232k  |     xmlChar *prefix;  | 
10299  |  |  | 
10300  | 232k  |     SKIP_BLANKS;  | 
10301  | 232k  |     if (CUR != '$') { | 
10302  | 0  |   XP_ERROR(XPATH_VARIABLE_REF_ERROR);  | 
10303  | 0  |     }  | 
10304  | 232k  |     NEXT;  | 
10305  | 232k  |     name = xmlXPathParseQName(ctxt, &prefix);  | 
10306  | 232k  |     if (name == NULL) { | 
10307  | 19.4k  |         xmlFree(prefix);  | 
10308  | 19.4k  |   XP_ERROR(XPATH_VARIABLE_REF_ERROR);  | 
10309  | 0  |     }  | 
10310  | 213k  |     ctxt->comp->last = -1;  | 
10311  | 213k  |     if (PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0, name, prefix) == -1) { | 
10312  | 0  |         xmlFree(prefix);  | 
10313  | 0  |         xmlFree(name);  | 
10314  | 0  |     }  | 
10315  | 213k  |     SKIP_BLANKS;  | 
10316  | 213k  |     if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) { | 
10317  | 0  |   XP_ERROR(XPATH_FORBID_VARIABLE_ERROR);  | 
10318  | 0  |     }  | 
10319  | 213k  | }  | 
10320  |  |  | 
10321  |  | /**  | 
10322  |  |  * xmlXPathIsNodeType:  | 
10323  |  |  * @name:  a name string  | 
10324  |  |  *  | 
10325  |  |  * Is the name given a NodeType one.  | 
10326  |  |  *  | 
10327  |  |  *  [38]   NodeType ::=   'comment'  | 
10328  |  |  *                    | 'text'  | 
10329  |  |  *                    | 'processing-instruction'  | 
10330  |  |  *                    | 'node'  | 
10331  |  |  *  | 
10332  |  |  * Returns 1 if true 0 otherwise  | 
10333  |  |  */  | 
10334  |  | int  | 
10335  | 612k  | xmlXPathIsNodeType(const xmlChar *name) { | 
10336  | 612k  |     if (name == NULL)  | 
10337  | 0  |   return(0);  | 
10338  |  |  | 
10339  | 612k  |     if (xmlStrEqual(name, BAD_CAST "node"))  | 
10340  | 11.3k  |   return(1);  | 
10341  | 601k  |     if (xmlStrEqual(name, BAD_CAST "text"))  | 
10342  | 6.71k  |   return(1);  | 
10343  | 594k  |     if (xmlStrEqual(name, BAD_CAST "comment"))  | 
10344  | 2.95k  |   return(1);  | 
10345  | 591k  |     if (xmlStrEqual(name, BAD_CAST "processing-instruction"))  | 
10346  | 475  |   return(1);  | 
10347  | 591k  |     return(0);  | 
10348  | 591k  | }  | 
10349  |  |  | 
10350  |  | /**  | 
10351  |  |  * xmlXPathCompFunctionCall:  | 
10352  |  |  * @ctxt:  the XPath Parser context  | 
10353  |  |  *  | 
10354  |  |  *  [16]   FunctionCall ::=   FunctionName '(' ( Argument ( ',' Argument)*)? ')' | 
10355  |  |  *  [17]   Argument ::=   Expr  | 
10356  |  |  *  | 
10357  |  |  * Compile a function call, the evaluation of all arguments are  | 
10358  |  |  * pushed on the stack  | 
10359  |  |  */  | 
10360  |  | static void  | 
10361  | 591k  | xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) { | 
10362  | 591k  |     xmlChar *name;  | 
10363  | 591k  |     xmlChar *prefix;  | 
10364  | 591k  |     int nbargs = 0;  | 
10365  | 591k  |     int sort = 1;  | 
10366  |  |  | 
10367  | 591k  |     name = xmlXPathParseQName(ctxt, &prefix);  | 
10368  | 591k  |     if (name == NULL) { | 
10369  | 7.89k  |   xmlFree(prefix);  | 
10370  | 7.89k  |   XP_ERROR(XPATH_EXPR_ERROR);  | 
10371  | 0  |     }  | 
10372  | 583k  |     SKIP_BLANKS;  | 
10373  |  | #ifdef DEBUG_EXPR  | 
10374  |  |     if (prefix == NULL)  | 
10375  |  |   xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",  | 
10376  |  |       name);  | 
10377  |  |     else  | 
10378  |  |   xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",  | 
10379  |  |       prefix, name);  | 
10380  |  | #endif  | 
10381  |  |  | 
10382  | 583k  |     if (CUR != '(') { | 
10383  | 8.40k  |   xmlFree(name);  | 
10384  | 8.40k  |   xmlFree(prefix);  | 
10385  | 8.40k  |   XP_ERROR(XPATH_EXPR_ERROR);  | 
10386  | 0  |     }  | 
10387  | 574k  |     NEXT;  | 
10388  | 574k  |     SKIP_BLANKS;  | 
10389  |  |  | 
10390  |  |     /*  | 
10391  |  |     * Optimization for count(): we don't need the node-set to be sorted.  | 
10392  |  |     */  | 
10393  | 574k  |     if ((prefix == NULL) && (name[0] == 'c') &&  | 
10394  | 574k  |   xmlStrEqual(name, BAD_CAST "count"))  | 
10395  | 5.35k  |     { | 
10396  | 5.35k  |   sort = 0;  | 
10397  | 5.35k  |     }  | 
10398  | 574k  |     ctxt->comp->last = -1;  | 
10399  | 574k  |     if (CUR != ')') { | 
10400  | 813k  |   while (CUR != 0) { | 
10401  | 792k  |       int op1 = ctxt->comp->last;  | 
10402  | 792k  |       ctxt->comp->last = -1;  | 
10403  | 792k  |       xmlXPathCompileExpr(ctxt, sort);  | 
10404  | 792k  |       if (ctxt->error != XPATH_EXPRESSION_OK) { | 
10405  | 99.1k  |     xmlFree(name);  | 
10406  | 99.1k  |     xmlFree(prefix);  | 
10407  | 99.1k  |     return;  | 
10408  | 99.1k  |       }  | 
10409  | 693k  |       PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);  | 
10410  | 693k  |       nbargs++;  | 
10411  | 693k  |       if (CUR == ')') break;  | 
10412  | 362k  |       if (CUR != ',') { | 
10413  | 31.5k  |     xmlFree(name);  | 
10414  | 31.5k  |     xmlFree(prefix);  | 
10415  | 31.5k  |     XP_ERROR(XPATH_EXPR_ERROR);  | 
10416  | 0  |       }  | 
10417  | 331k  |       NEXT;  | 
10418  | 331k  |       SKIP_BLANKS;  | 
10419  | 331k  |   }  | 
10420  | 481k  |     }  | 
10421  | 444k  |     if (PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0, name, prefix) == -1) { | 
10422  | 0  |         xmlFree(prefix);  | 
10423  | 0  |         xmlFree(name);  | 
10424  | 0  |     }  | 
10425  | 444k  |     NEXT;  | 
10426  | 444k  |     SKIP_BLANKS;  | 
10427  | 444k  | }  | 
10428  |  |  | 
10429  |  | /**  | 
10430  |  |  * xmlXPathCompPrimaryExpr:  | 
10431  |  |  * @ctxt:  the XPath Parser context  | 
10432  |  |  *  | 
10433  |  |  *  [15]   PrimaryExpr ::=   VariableReference  | 
10434  |  |  *                | '(' Expr ')' | 
10435  |  |  *                | Literal  | 
10436  |  |  *                | Number  | 
10437  |  |  *                | FunctionCall  | 
10438  |  |  *  | 
10439  |  |  * Compile a primary expression.  | 
10440  |  |  */  | 
10441  |  | static void  | 
10442  | 2.64M  | xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) { | 
10443  | 2.64M  |     SKIP_BLANKS;  | 
10444  | 2.64M  |     if (CUR == '$') xmlXPathCompVariableReference(ctxt);  | 
10445  | 2.41M  |     else if (CUR == '(') { | 
10446  | 282k  |   NEXT;  | 
10447  | 282k  |   SKIP_BLANKS;  | 
10448  | 282k  |   xmlXPathCompileExpr(ctxt, 1);  | 
10449  | 282k  |   CHECK_ERROR;  | 
10450  | 143k  |   if (CUR != ')') { | 
10451  | 31.5k  |       XP_ERROR(XPATH_EXPR_ERROR);  | 
10452  | 0  |   }  | 
10453  | 111k  |   NEXT;  | 
10454  | 111k  |   SKIP_BLANKS;  | 
10455  | 2.12M  |     } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) { | 
10456  | 1.15M  |   xmlXPathCompNumber(ctxt);  | 
10457  | 1.15M  |     } else if ((CUR == '\'') || (CUR == '"')) { | 
10458  | 384k  |   xmlXPathCompLiteral(ctxt);  | 
10459  | 591k  |     } else { | 
10460  | 591k  |   xmlXPathCompFunctionCall(ctxt);  | 
10461  | 591k  |     }  | 
10462  | 2.47M  |     SKIP_BLANKS;  | 
10463  | 2.47M  | }  | 
10464  |  |  | 
10465  |  | /**  | 
10466  |  |  * xmlXPathCompFilterExpr:  | 
10467  |  |  * @ctxt:  the XPath Parser context  | 
10468  |  |  *  | 
10469  |  |  *  [20]   FilterExpr ::=   PrimaryExpr  | 
10470  |  |  *               | FilterExpr Predicate  | 
10471  |  |  *  | 
10472  |  |  * Compile a filter expression.  | 
10473  |  |  * Square brackets are used to filter expressions in the same way that  | 
10474  |  |  * they are used in location paths. It is an error if the expression to  | 
10475  |  |  * be filtered does not evaluate to a node-set. The context node list  | 
10476  |  |  * used for evaluating the expression in square brackets is the node-set  | 
10477  |  |  * to be filtered listed in document order.  | 
10478  |  |  */  | 
10479  |  |  | 
10480  |  | static void  | 
10481  | 2.64M  | xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) { | 
10482  | 2.64M  |     xmlXPathCompPrimaryExpr(ctxt);  | 
10483  | 2.64M  |     CHECK_ERROR;  | 
10484  | 2.29M  |     SKIP_BLANKS;  | 
10485  |  |  | 
10486  | 3.92M  |     while (CUR == '[') { | 
10487  | 1.63M  |   xmlXPathCompPredicate(ctxt, 1);  | 
10488  | 1.63M  |   SKIP_BLANKS;  | 
10489  | 1.63M  |     }  | 
10490  |  |  | 
10491  |  |  | 
10492  | 2.29M  | }  | 
10493  |  |  | 
10494  |  | /**  | 
10495  |  |  * xmlXPathScanName:  | 
10496  |  |  * @ctxt:  the XPath Parser context  | 
10497  |  |  *  | 
10498  |  |  * Trickery: parse an XML name but without consuming the input flow  | 
10499  |  |  * Needed to avoid insanity in the parser state.  | 
10500  |  |  *  | 
10501  |  |  * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |  | 
10502  |  |  *                  CombiningChar | Extender  | 
10503  |  |  *  | 
10504  |  |  * [5] Name ::= (Letter | '_' | ':') (NameChar)*  | 
10505  |  |  *  | 
10506  |  |  * [6] Names ::= Name (S Name)*  | 
10507  |  |  *  | 
10508  |  |  * Returns the Name parsed or NULL  | 
10509  |  |  */  | 
10510  |  |  | 
10511  |  | static xmlChar *  | 
10512  | 11.4M  | xmlXPathScanName(xmlXPathParserContextPtr ctxt) { | 
10513  | 11.4M  |     int l;  | 
10514  | 11.4M  |     int c;  | 
10515  | 11.4M  |     const xmlChar *cur;  | 
10516  | 11.4M  |     xmlChar *ret;  | 
10517  |  |  | 
10518  | 11.4M  |     cur = ctxt->cur;  | 
10519  |  |  | 
10520  | 11.4M  |     c = CUR_CHAR(l);  | 
10521  | 11.4M  |     if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */  | 
10522  | 11.4M  |   (!IS_LETTER(c) && (c != '_') &&  | 
10523  | 11.4M  |          (c != ':'))) { | 
10524  | 9.10M  |   return(NULL);  | 
10525  | 9.10M  |     }  | 
10526  |  |  | 
10527  | 63.2M  |     while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */  | 
10528  | 63.2M  |      ((IS_LETTER(c)) || (IS_DIGIT(c)) ||  | 
10529  | 62.5M  |             (c == '.') || (c == '-') ||  | 
10530  | 62.5M  |       (c == '_') || (c == ':') ||  | 
10531  | 62.5M  |       (IS_COMBINING(c)) ||  | 
10532  | 62.5M  |       (IS_EXTENDER(c)))) { | 
10533  | 60.8M  |   NEXTL(l);  | 
10534  | 60.8M  |   c = CUR_CHAR(l);  | 
10535  | 60.8M  |     }  | 
10536  | 2.38M  |     ret = xmlStrndup(cur, ctxt->cur - cur);  | 
10537  | 2.38M  |     ctxt->cur = cur;  | 
10538  | 2.38M  |     return(ret);  | 
10539  | 11.4M  | }  | 
10540  |  |  | 
10541  |  | /**  | 
10542  |  |  * xmlXPathCompPathExpr:  | 
10543  |  |  * @ctxt:  the XPath Parser context  | 
10544  |  |  *  | 
10545  |  |  *  [19]   PathExpr ::=   LocationPath  | 
10546  |  |  *               | FilterExpr  | 
10547  |  |  *               | FilterExpr '/' RelativeLocationPath  | 
10548  |  |  *               | FilterExpr '//' RelativeLocationPath  | 
10549  |  |  *  | 
10550  |  |  * Compile a path expression.  | 
10551  |  |  * The / operator and // operators combine an arbitrary expression  | 
10552  |  |  * and a relative location path. It is an error if the expression  | 
10553  |  |  * does not evaluate to a node-set.  | 
10554  |  |  * The / operator does composition in the same way as when / is  | 
10555  |  |  * used in a location path. As in location paths, // is short for  | 
10556  |  |  * /descendant-or-self::node()/.  | 
10557  |  |  */  | 
10558  |  |  | 
10559  |  | static void  | 
10560  | 17.5M  | xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) { | 
10561  | 17.5M  |     int lc = 1;           /* Should we branch to LocationPath ?         */  | 
10562  | 17.5M  |     xmlChar *name = NULL; /* we may have to preparse a name to find out */  | 
10563  |  |  | 
10564  | 17.5M  |     SKIP_BLANKS;  | 
10565  | 17.5M  |     if ((CUR == '$') || (CUR == '(') || | 
10566  | 17.5M  |   (IS_ASCII_DIGIT(CUR)) ||  | 
10567  | 17.5M  |         (CUR == '\'') || (CUR == '"') ||  | 
10568  | 17.5M  |   (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) { | 
10569  | 2.05M  |   lc = 0;  | 
10570  | 15.4M  |     } else if (CUR == '*') { | 
10571  |  |   /* relative or absolute location path */  | 
10572  | 2.16M  |   lc = 1;  | 
10573  | 13.3M  |     } else if (CUR == '/') { | 
10574  |  |   /* relative or absolute location path */  | 
10575  | 1.47M  |   lc = 1;  | 
10576  | 11.8M  |     } else if (CUR == '@') { | 
10577  |  |   /* relative abbreviated attribute location path */  | 
10578  | 63.3k  |   lc = 1;  | 
10579  | 11.7M  |     } else if (CUR == '.') { | 
10580  |  |   /* relative abbreviated attribute location path */  | 
10581  | 300k  |   lc = 1;  | 
10582  | 11.4M  |     } else { | 
10583  |  |   /*  | 
10584  |  |    * Problem is finding if we have a name here whether it's:  | 
10585  |  |    *   - a nodetype  | 
10586  |  |    *   - a function call in which case it's followed by '(' | 
10587  |  |    *   - an axis in which case it's followed by ':'  | 
10588  |  |    *   - a element name  | 
10589  |  |    * We do an a priori analysis here rather than having to  | 
10590  |  |    * maintain parsed token content through the recursive function  | 
10591  |  |    * calls. This looks uglier but makes the code easier to  | 
10592  |  |    * read/write/debug.  | 
10593  |  |    */  | 
10594  | 11.4M  |   SKIP_BLANKS;  | 
10595  | 11.4M  |   name = xmlXPathScanName(ctxt);  | 
10596  | 11.4M  |   if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) { | 
10597  |  | #ifdef DEBUG_STEP  | 
10598  |  |       xmlGenericError(xmlGenericErrorContext,  | 
10599  |  |         "PathExpr: Axis\n");  | 
10600  |  | #endif  | 
10601  | 136k  |       lc = 1;  | 
10602  | 136k  |       xmlFree(name);  | 
10603  | 11.3M  |   } else if (name != NULL) { | 
10604  | 2.25M  |       int len =xmlStrlen(name);  | 
10605  |  |  | 
10606  |  |  | 
10607  | 3.37M  |       while (NXT(len) != 0) { | 
10608  | 3.32M  |     if (NXT(len) == '/') { | 
10609  |  |         /* element name */  | 
10610  |  | #ifdef DEBUG_STEP  | 
10611  |  |         xmlGenericError(xmlGenericErrorContext,  | 
10612  |  |           "PathExpr: AbbrRelLocation\n");  | 
10613  |  | #endif  | 
10614  | 367k  |         lc = 1;  | 
10615  | 367k  |         break;  | 
10616  | 2.96M  |     } else if (IS_BLANK_CH(NXT(len))) { | 
10617  |  |         /* ignore blanks */  | 
10618  | 1.12M  |         ;  | 
10619  | 1.83M  |     } else if (NXT(len) == ':') { | 
10620  |  | #ifdef DEBUG_STEP  | 
10621  |  |         xmlGenericError(xmlGenericErrorContext,  | 
10622  |  |           "PathExpr: AbbrRelLocation\n");  | 
10623  |  | #endif  | 
10624  | 1.96k  |         lc = 1;  | 
10625  | 1.96k  |         break;  | 
10626  | 1.83M  |     } else if ((NXT(len) == '(')) { | 
10627  |  |         /* Node Type or Function */  | 
10628  | 612k  |         if (xmlXPathIsNodeType(name)) { | 
10629  |  | #ifdef DEBUG_STEP  | 
10630  |  |             xmlGenericError(xmlGenericErrorContext,  | 
10631  |  |         "PathExpr: Type search\n");  | 
10632  |  | #endif  | 
10633  | 21.4k  |       lc = 1;  | 
10634  |  | #ifdef LIBXML_XPTR_LOCS_ENABLED  | 
10635  |  |                     } else if (ctxt->xptr &&  | 
10636  |  |                                xmlStrEqual(name, BAD_CAST "range-to")) { | 
10637  |  |                         lc = 1;  | 
10638  |  | #endif  | 
10639  | 591k  |         } else { | 
10640  |  | #ifdef DEBUG_STEP  | 
10641  |  |             xmlGenericError(xmlGenericErrorContext,  | 
10642  |  |         "PathExpr: function call\n");  | 
10643  |  | #endif  | 
10644  | 591k  |       lc = 0;  | 
10645  | 591k  |         }  | 
10646  | 612k  |                     break;  | 
10647  | 1.21M  |     } else if ((NXT(len) == '[')) { | 
10648  |  |         /* element name */  | 
10649  |  | #ifdef DEBUG_STEP  | 
10650  |  |         xmlGenericError(xmlGenericErrorContext,  | 
10651  |  |           "PathExpr: AbbrRelLocation\n");  | 
10652  |  | #endif  | 
10653  | 51.2k  |         lc = 1;  | 
10654  | 51.2k  |         break;  | 
10655  | 1.16M  |     } else if ((NXT(len) == '<') || (NXT(len) == '>') ||  | 
10656  | 1.16M  |          (NXT(len) == '=')) { | 
10657  | 356k  |         lc = 1;  | 
10658  | 356k  |         break;  | 
10659  | 810k  |     } else { | 
10660  | 810k  |         lc = 1;  | 
10661  | 810k  |         break;  | 
10662  | 810k  |     }  | 
10663  | 1.12M  |     len++;  | 
10664  | 1.12M  |       }  | 
10665  | 2.25M  |       if (NXT(len) == 0) { | 
10666  |  | #ifdef DEBUG_STEP  | 
10667  |  |     xmlGenericError(xmlGenericErrorContext,  | 
10668  |  |       "PathExpr: AbbrRelLocation\n");  | 
10669  |  | #endif  | 
10670  |  |     /* element name */  | 
10671  | 49.6k  |     lc = 1;  | 
10672  | 49.6k  |       }  | 
10673  | 2.25M  |       xmlFree(name);  | 
10674  | 9.10M  |   } else { | 
10675  |  |       /* make sure all cases are covered explicitly */  | 
10676  | 9.10M  |       XP_ERROR(XPATH_EXPR_ERROR);  | 
10677  | 0  |   }  | 
10678  | 11.4M  |     }  | 
10679  |  |  | 
10680  | 8.44M  |     if (lc) { | 
10681  | 5.79M  |   if (CUR == '/') { | 
10682  | 1.47M  |       PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);  | 
10683  | 4.32M  |   } else { | 
10684  | 4.32M  |       PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);  | 
10685  | 4.32M  |   }  | 
10686  | 5.79M  |   xmlXPathCompLocationPath(ctxt);  | 
10687  | 5.79M  |     } else { | 
10688  | 2.64M  |   xmlXPathCompFilterExpr(ctxt);  | 
10689  | 2.64M  |   CHECK_ERROR;  | 
10690  | 2.23M  |   if ((CUR == '/') && (NXT(1) == '/')) { | 
10691  | 63.0k  |       SKIP(2);  | 
10692  | 63.0k  |       SKIP_BLANKS;  | 
10693  |  |  | 
10694  | 63.0k  |       PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,  | 
10695  | 63.0k  |         NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);  | 
10696  |  |  | 
10697  | 63.0k  |       xmlXPathCompRelativeLocationPath(ctxt);  | 
10698  | 2.17M  |   } else if (CUR == '/') { | 
10699  | 91.6k  |       xmlXPathCompRelativeLocationPath(ctxt);  | 
10700  | 91.6k  |   }  | 
10701  | 2.23M  |     }  | 
10702  | 8.03M  |     SKIP_BLANKS;  | 
10703  | 8.03M  | }  | 
10704  |  |  | 
10705  |  | /**  | 
10706  |  |  * xmlXPathCompUnionExpr:  | 
10707  |  |  * @ctxt:  the XPath Parser context  | 
10708  |  |  *  | 
10709  |  |  *  [18]   UnionExpr ::=   PathExpr  | 
10710  |  |  *               | UnionExpr '|' PathExpr  | 
10711  |  |  *  | 
10712  |  |  * Compile an union expression.  | 
10713  |  |  */  | 
10714  |  |  | 
10715  |  | static void  | 
10716  | 7.22M  | xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) { | 
10717  | 7.22M  |     xmlXPathCompPathExpr(ctxt);  | 
10718  | 7.22M  |     CHECK_ERROR;  | 
10719  | 6.31M  |     SKIP_BLANKS;  | 
10720  | 16.6M  |     while (CUR == '|') { | 
10721  | 10.3M  |   int op1 = ctxt->comp->last;  | 
10722  | 10.3M  |   PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);  | 
10723  |  |  | 
10724  | 10.3M  |   NEXT;  | 
10725  | 10.3M  |   SKIP_BLANKS;  | 
10726  | 10.3M  |   xmlXPathCompPathExpr(ctxt);  | 
10727  |  |  | 
10728  | 10.3M  |   PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);  | 
10729  |  |  | 
10730  | 10.3M  |   SKIP_BLANKS;  | 
10731  | 10.3M  |     }  | 
10732  | 6.31M  | }  | 
10733  |  |  | 
10734  |  | /**  | 
10735  |  |  * xmlXPathCompUnaryExpr:  | 
10736  |  |  * @ctxt:  the XPath Parser context  | 
10737  |  |  *  | 
10738  |  |  *  [27]   UnaryExpr ::=   UnionExpr  | 
10739  |  |  *                   | '-' UnaryExpr  | 
10740  |  |  *  | 
10741  |  |  * Compile an unary expression.  | 
10742  |  |  */  | 
10743  |  |  | 
10744  |  | static void  | 
10745  | 7.22M  | xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) { | 
10746  | 7.22M  |     int minus = 0;  | 
10747  | 7.22M  |     int found = 0;  | 
10748  |  |  | 
10749  | 7.22M  |     SKIP_BLANKS;  | 
10750  | 8.36M  |     while (CUR == '-') { | 
10751  | 1.14M  |         minus = 1 - minus;  | 
10752  | 1.14M  |   found = 1;  | 
10753  | 1.14M  |   NEXT;  | 
10754  | 1.14M  |   SKIP_BLANKS;  | 
10755  | 1.14M  |     }  | 
10756  |  |  | 
10757  | 7.22M  |     xmlXPathCompUnionExpr(ctxt);  | 
10758  | 7.22M  |     CHECK_ERROR;  | 
10759  | 6.23M  |     if (found) { | 
10760  | 243k  |   if (minus)  | 
10761  | 198k  |       PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);  | 
10762  | 44.8k  |   else  | 
10763  | 44.8k  |       PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);  | 
10764  | 243k  |     }  | 
10765  | 6.23M  | }  | 
10766  |  |  | 
10767  |  | /**  | 
10768  |  |  * xmlXPathCompMultiplicativeExpr:  | 
10769  |  |  * @ctxt:  the XPath Parser context  | 
10770  |  |  *  | 
10771  |  |  *  [26]   MultiplicativeExpr ::=   UnaryExpr  | 
10772  |  |  *                   | MultiplicativeExpr MultiplyOperator UnaryExpr  | 
10773  |  |  *                   | MultiplicativeExpr 'div' UnaryExpr  | 
10774  |  |  *                   | MultiplicativeExpr 'mod' UnaryExpr  | 
10775  |  |  *  [34]   MultiplyOperator ::=   '*'  | 
10776  |  |  *  | 
10777  |  |  * Compile an Additive expression.  | 
10778  |  |  */  | 
10779  |  |  | 
10780  |  | static void  | 
10781  | 4.77M  | xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) { | 
10782  | 4.77M  |     xmlXPathCompUnaryExpr(ctxt);  | 
10783  | 4.77M  |     CHECK_ERROR;  | 
10784  | 3.88M  |     SKIP_BLANKS;  | 
10785  | 6.23M  |     while ((CUR == '*') ||  | 
10786  | 6.23M  |            ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||  | 
10787  | 6.23M  |            ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) { | 
10788  | 2.44M  |   int op = -1;  | 
10789  | 2.44M  |   int op1 = ctxt->comp->last;  | 
10790  |  |  | 
10791  | 2.44M  |         if (CUR == '*') { | 
10792  | 2.35M  |       op = 0;  | 
10793  | 2.35M  |       NEXT;  | 
10794  | 2.35M  |   } else if (CUR == 'd') { | 
10795  | 68.2k  |       op = 1;  | 
10796  | 68.2k  |       SKIP(3);  | 
10797  | 68.2k  |   } else if (CUR == 'm') { | 
10798  | 18.9k  |       op = 2;  | 
10799  | 18.9k  |       SKIP(3);  | 
10800  | 18.9k  |   }  | 
10801  | 2.44M  |   SKIP_BLANKS;  | 
10802  | 2.44M  |         xmlXPathCompUnaryExpr(ctxt);  | 
10803  | 2.44M  |   CHECK_ERROR;  | 
10804  | 2.35M  |   PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);  | 
10805  | 2.35M  |   SKIP_BLANKS;  | 
10806  | 2.35M  |     }  | 
10807  | 3.88M  | }  | 
10808  |  |  | 
10809  |  | /**  | 
10810  |  |  * xmlXPathCompAdditiveExpr:  | 
10811  |  |  * @ctxt:  the XPath Parser context  | 
10812  |  |  *  | 
10813  |  |  *  [25]   AdditiveExpr ::=   MultiplicativeExpr  | 
10814  |  |  *                   | AdditiveExpr '+' MultiplicativeExpr  | 
10815  |  |  *                   | AdditiveExpr '-' MultiplicativeExpr  | 
10816  |  |  *  | 
10817  |  |  * Compile an Additive expression.  | 
10818  |  |  */  | 
10819  |  |  | 
10820  |  | static void  | 
10821  | 4.40M  | xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) { | 
10822  |  |  | 
10823  | 4.40M  |     xmlXPathCompMultiplicativeExpr(ctxt);  | 
10824  | 4.40M  |     CHECK_ERROR;  | 
10825  | 3.46M  |     SKIP_BLANKS;  | 
10826  | 3.78M  |     while ((CUR == '+') || (CUR == '-')) { | 
10827  | 371k  |   int plus;  | 
10828  | 371k  |   int op1 = ctxt->comp->last;  | 
10829  |  |  | 
10830  | 371k  |         if (CUR == '+') plus = 1;  | 
10831  | 286k  |   else plus = 0;  | 
10832  | 371k  |   NEXT;  | 
10833  | 371k  |   SKIP_BLANKS;  | 
10834  | 371k  |         xmlXPathCompMultiplicativeExpr(ctxt);  | 
10835  | 371k  |   CHECK_ERROR;  | 
10836  | 318k  |   PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);  | 
10837  | 318k  |   SKIP_BLANKS;  | 
10838  | 318k  |     }  | 
10839  | 3.46M  | }  | 
10840  |  |  | 
10841  |  | /**  | 
10842  |  |  * xmlXPathCompRelationalExpr:  | 
10843  |  |  * @ctxt:  the XPath Parser context  | 
10844  |  |  *  | 
10845  |  |  *  [24]   RelationalExpr ::=   AdditiveExpr  | 
10846  |  |  *                 | RelationalExpr '<' AdditiveExpr  | 
10847  |  |  *                 | RelationalExpr '>' AdditiveExpr  | 
10848  |  |  *                 | RelationalExpr '<=' AdditiveExpr  | 
10849  |  |  *                 | RelationalExpr '>=' AdditiveExpr  | 
10850  |  |  *  | 
10851  |  |  *  A <= B > C is allowed ? Answer from James, yes with  | 
10852  |  |  *  (AdditiveExpr <= AdditiveExpr) > AdditiveExpr  | 
10853  |  |  *  which is basically what got implemented.  | 
10854  |  |  *  | 
10855  |  |  * Compile a Relational expression, then push the result  | 
10856  |  |  * on the stack  | 
10857  |  |  */  | 
10858  |  |  | 
10859  |  | static void  | 
10860  | 3.81M  | xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) { | 
10861  | 3.81M  |     xmlXPathCompAdditiveExpr(ctxt);  | 
10862  | 3.81M  |     CHECK_ERROR;  | 
10863  | 2.90M  |     SKIP_BLANKS;  | 
10864  | 3.41M  |     while ((CUR == '<') || (CUR == '>')) { | 
10865  | 594k  |   int inf, strict;  | 
10866  | 594k  |   int op1 = ctxt->comp->last;  | 
10867  |  |  | 
10868  | 594k  |         if (CUR == '<') inf = 1;  | 
10869  | 393k  |   else inf = 0;  | 
10870  | 594k  |   if (NXT(1) == '=') strict = 0;  | 
10871  | 505k  |   else strict = 1;  | 
10872  | 594k  |   NEXT;  | 
10873  | 594k  |   if (!strict) NEXT;  | 
10874  | 594k  |   SKIP_BLANKS;  | 
10875  | 594k  |         xmlXPathCompAdditiveExpr(ctxt);  | 
10876  | 594k  |   CHECK_ERROR;  | 
10877  | 511k  |   PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);  | 
10878  | 511k  |   SKIP_BLANKS;  | 
10879  | 511k  |     }  | 
10880  | 2.90M  | }  | 
10881  |  |  | 
10882  |  | /**  | 
10883  |  |  * xmlXPathCompEqualityExpr:  | 
10884  |  |  * @ctxt:  the XPath Parser context  | 
10885  |  |  *  | 
10886  |  |  *  [23]   EqualityExpr ::=   RelationalExpr  | 
10887  |  |  *                 | EqualityExpr '=' RelationalExpr  | 
10888  |  |  *                 | EqualityExpr '!=' RelationalExpr  | 
10889  |  |  *  | 
10890  |  |  *  A != B != C is allowed ? Answer from James, yes with  | 
10891  |  |  *  (RelationalExpr = RelationalExpr) = RelationalExpr  | 
10892  |  |  *  (RelationalExpr != RelationalExpr) != RelationalExpr  | 
10893  |  |  *  which is basically what got implemented.  | 
10894  |  |  *  | 
10895  |  |  * Compile an Equality expression.  | 
10896  |  |  *  | 
10897  |  |  */  | 
10898  |  | static void  | 
10899  | 2.99M  | xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) { | 
10900  | 2.99M  |     xmlXPathCompRelationalExpr(ctxt);  | 
10901  | 2.99M  |     CHECK_ERROR;  | 
10902  | 2.18M  |     SKIP_BLANKS;  | 
10903  | 2.82M  |     while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) { | 
10904  | 815k  |   int eq;  | 
10905  | 815k  |   int op1 = ctxt->comp->last;  | 
10906  |  |  | 
10907  | 815k  |         if (CUR == '=') eq = 1;  | 
10908  | 64.6k  |   else eq = 0;  | 
10909  | 815k  |   NEXT;  | 
10910  | 815k  |   if (!eq) NEXT;  | 
10911  | 815k  |   SKIP_BLANKS;  | 
10912  | 815k  |         xmlXPathCompRelationalExpr(ctxt);  | 
10913  | 815k  |   CHECK_ERROR;  | 
10914  | 638k  |   PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);  | 
10915  | 638k  |   SKIP_BLANKS;  | 
10916  | 638k  |     }  | 
10917  | 2.18M  | }  | 
10918  |  |  | 
10919  |  | /**  | 
10920  |  |  * xmlXPathCompAndExpr:  | 
10921  |  |  * @ctxt:  the XPath Parser context  | 
10922  |  |  *  | 
10923  |  |  *  [22]   AndExpr ::=   EqualityExpr  | 
10924  |  |  *                 | AndExpr 'and' EqualityExpr  | 
10925  |  |  *  | 
10926  |  |  * Compile an AND expression.  | 
10927  |  |  *  | 
10928  |  |  */  | 
10929  |  | static void  | 
10930  | 2.94M  | xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) { | 
10931  | 2.94M  |     xmlXPathCompEqualityExpr(ctxt);  | 
10932  | 2.94M  |     CHECK_ERROR;  | 
10933  | 1.97M  |     SKIP_BLANKS;  | 
10934  | 2.00M  |     while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) { | 
10935  | 46.4k  |   int op1 = ctxt->comp->last;  | 
10936  | 46.4k  |         SKIP(3);  | 
10937  | 46.4k  |   SKIP_BLANKS;  | 
10938  | 46.4k  |         xmlXPathCompEqualityExpr(ctxt);  | 
10939  | 46.4k  |   CHECK_ERROR;  | 
10940  | 35.3k  |   PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);  | 
10941  | 35.3k  |   SKIP_BLANKS;  | 
10942  | 35.3k  |     }  | 
10943  | 1.97M  | }  | 
10944  |  |  | 
10945  |  | /**  | 
10946  |  |  * xmlXPathCompileExpr:  | 
10947  |  |  * @ctxt:  the XPath Parser context  | 
10948  |  |  *  | 
10949  |  |  *  [14]   Expr ::=   OrExpr  | 
10950  |  |  *  [21]   OrExpr ::=   AndExpr  | 
10951  |  |  *                 | OrExpr 'or' AndExpr  | 
10952  |  |  *  | 
10953  |  |  * Parse and compile an expression  | 
10954  |  |  */  | 
10955  |  | static void  | 
10956  | 8.51M  | xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) { | 
10957  | 8.51M  |     xmlXPathContextPtr xpctxt = ctxt->context;  | 
10958  |  |  | 
10959  | 8.51M  |     if (xpctxt != NULL) { | 
10960  | 8.51M  |         if (xpctxt->depth >= XPATH_MAX_RECURSION_DEPTH)  | 
10961  | 5.69M  |             XP_ERROR(XPATH_RECURSION_LIMIT_EXCEEDED);  | 
10962  |  |         /*  | 
10963  |  |          * Parsing a single '(' pushes about 10 functions on the call stack | 
10964  |  |          * before recursing!  | 
10965  |  |          */  | 
10966  | 2.82M  |         xpctxt->depth += 10;  | 
10967  | 2.82M  |     }  | 
10968  |  |  | 
10969  | 2.82M  |     xmlXPathCompAndExpr(ctxt);  | 
10970  | 2.82M  |     CHECK_ERROR;  | 
10971  | 1.89M  |     SKIP_BLANKS;  | 
10972  | 1.96M  |     while ((CUR == 'o') && (NXT(1) == 'r')) { | 
10973  | 119k  |   int op1 = ctxt->comp->last;  | 
10974  | 119k  |         SKIP(2);  | 
10975  | 119k  |   SKIP_BLANKS;  | 
10976  | 119k  |         xmlXPathCompAndExpr(ctxt);  | 
10977  | 119k  |   CHECK_ERROR;  | 
10978  | 61.5k  |   PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);  | 
10979  | 61.5k  |   SKIP_BLANKS;  | 
10980  | 61.5k  |     }  | 
10981  | 1.84M  |     if ((sort) && (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE)) { | 
10982  |  |   /* more ops could be optimized too */  | 
10983  |  |   /*  | 
10984  |  |   * This is the main place to eliminate sorting for  | 
10985  |  |   * operations which don't require a sorted node-set.  | 
10986  |  |   * E.g. count().  | 
10987  |  |   */  | 
10988  | 1.08M  |   PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);  | 
10989  | 1.08M  |     }  | 
10990  |  |  | 
10991  | 1.84M  |     if (xpctxt != NULL)  | 
10992  | 1.84M  |         xpctxt->depth -= 10;  | 
10993  | 1.84M  | }  | 
10994  |  |  | 
10995  |  | /**  | 
10996  |  |  * xmlXPathCompPredicate:  | 
10997  |  |  * @ctxt:  the XPath Parser context  | 
10998  |  |  * @filter:  act as a filter  | 
10999  |  |  *  | 
11000  |  |  *  [8]   Predicate ::=   '[' PredicateExpr ']'  | 
11001  |  |  *  [9]   PredicateExpr ::=   Expr  | 
11002  |  |  *  | 
11003  |  |  * Compile a predicate expression  | 
11004  |  |  */  | 
11005  |  | static void  | 
11006  | 6.18M  | xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) { | 
11007  | 6.18M  |     int op1 = ctxt->comp->last;  | 
11008  |  |  | 
11009  | 6.18M  |     SKIP_BLANKS;  | 
11010  | 6.18M  |     if (CUR != '[') { | 
11011  | 0  |   XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);  | 
11012  | 0  |     }  | 
11013  | 6.18M  |     NEXT;  | 
11014  | 6.18M  |     SKIP_BLANKS;  | 
11015  |  |  | 
11016  | 6.18M  |     ctxt->comp->last = -1;  | 
11017  |  |     /*  | 
11018  |  |     * This call to xmlXPathCompileExpr() will deactivate sorting  | 
11019  |  |     * of the predicate result.  | 
11020  |  |     * TODO: Sorting is still activated for filters, since I'm not  | 
11021  |  |     *  sure if needed. Normally sorting should not be needed, since  | 
11022  |  |     *  a filter can only diminish the number of items in a sequence,  | 
11023  |  |     *  but won't change its order; so if the initial sequence is sorted,  | 
11024  |  |     *  subsequent sorting is not needed.  | 
11025  |  |     */  | 
11026  | 6.18M  |     if (! filter)  | 
11027  | 4.55M  |   xmlXPathCompileExpr(ctxt, 0);  | 
11028  | 1.63M  |     else  | 
11029  | 1.63M  |   xmlXPathCompileExpr(ctxt, 1);  | 
11030  | 6.18M  |     CHECK_ERROR;  | 
11031  |  |  | 
11032  | 310k  |     if (CUR != ']') { | 
11033  | 36.9k  |   XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);  | 
11034  | 0  |     }  | 
11035  |  |  | 
11036  | 273k  |     if (filter)  | 
11037  | 88.3k  |   PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);  | 
11038  | 185k  |     else  | 
11039  | 185k  |   PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);  | 
11040  |  |  | 
11041  | 273k  |     NEXT;  | 
11042  | 273k  |     SKIP_BLANKS;  | 
11043  | 273k  | }  | 
11044  |  |  | 
11045  |  | /**  | 
11046  |  |  * xmlXPathCompNodeTest:  | 
11047  |  |  * @ctxt:  the XPath Parser context  | 
11048  |  |  * @test:  pointer to a xmlXPathTestVal  | 
11049  |  |  * @type:  pointer to a xmlXPathTypeVal  | 
11050  |  |  * @prefix:  placeholder for a possible name prefix  | 
11051  |  |  *  | 
11052  |  |  * [7] NodeTest ::=   NameTest  | 
11053  |  |  *        | NodeType '(' ')' | 
11054  |  |  *        | 'processing-instruction' '(' Literal ')' | 
11055  |  |  *  | 
11056  |  |  * [37] NameTest ::=  '*'  | 
11057  |  |  *        | NCName ':' '*'  | 
11058  |  |  *        | QName  | 
11059  |  |  * [38] NodeType ::= 'comment'  | 
11060  |  |  *       | 'text'  | 
11061  |  |  *       | 'processing-instruction'  | 
11062  |  |  *       | 'node'  | 
11063  |  |  *  | 
11064  |  |  * Returns the name found and updates @test, @type and @prefix appropriately  | 
11065  |  |  */  | 
11066  |  | static xmlChar *  | 
11067  |  | xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,  | 
11068  |  |                xmlXPathTypeVal *type, xmlChar **prefix,  | 
11069  | 7.25M  |          xmlChar *name) { | 
11070  | 7.25M  |     int blanks;  | 
11071  |  |  | 
11072  | 7.25M  |     if ((test == NULL) || (type == NULL) || (prefix == NULL)) { | 
11073  | 0  |   STRANGE;  | 
11074  | 0  |   return(NULL);  | 
11075  | 0  |     }  | 
11076  | 7.25M  |     *type = (xmlXPathTypeVal) 0;  | 
11077  | 7.25M  |     *test = (xmlXPathTestVal) 0;  | 
11078  | 7.25M  |     *prefix = NULL;  | 
11079  | 7.25M  |     SKIP_BLANKS;  | 
11080  |  |  | 
11081  | 7.25M  |     if ((name == NULL) && (CUR == '*')) { | 
11082  |  |   /*  | 
11083  |  |    * All elements  | 
11084  |  |    */  | 
11085  | 3.04M  |   NEXT;  | 
11086  | 3.04M  |   *test = NODE_TEST_ALL;  | 
11087  | 3.04M  |   return(NULL);  | 
11088  | 3.04M  |     }  | 
11089  |  |  | 
11090  | 4.21M  |     if (name == NULL)  | 
11091  | 375k  |   name = xmlXPathParseNCName(ctxt);  | 
11092  | 4.21M  |     if (name == NULL) { | 
11093  | 104k  |   XP_ERRORNULL(XPATH_EXPR_ERROR);  | 
11094  | 0  |     }  | 
11095  |  |  | 
11096  | 4.10M  |     blanks = IS_BLANK_CH(CUR);  | 
11097  | 4.10M  |     SKIP_BLANKS;  | 
11098  | 4.10M  |     if (CUR == '(') { | 
11099  | 136k  |   NEXT;  | 
11100  |  |   /*  | 
11101  |  |    * NodeType or PI search  | 
11102  |  |    */  | 
11103  | 136k  |   if (xmlStrEqual(name, BAD_CAST "comment"))  | 
11104  | 15.3k  |       *type = NODE_TYPE_COMMENT;  | 
11105  | 121k  |   else if (xmlStrEqual(name, BAD_CAST "node"))  | 
11106  | 50.3k  |       *type = NODE_TYPE_NODE;  | 
11107  | 70.8k  |   else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))  | 
11108  | 19.2k  |       *type = NODE_TYPE_PI;  | 
11109  | 51.5k  |   else if (xmlStrEqual(name, BAD_CAST "text"))  | 
11110  | 41.1k  |       *type = NODE_TYPE_TEXT;  | 
11111  | 10.4k  |   else { | 
11112  | 10.4k  |       if (name != NULL)  | 
11113  | 10.4k  |     xmlFree(name);  | 
11114  | 10.4k  |       XP_ERRORNULL(XPATH_EXPR_ERROR);  | 
11115  | 0  |   }  | 
11116  |  |  | 
11117  | 126k  |   *test = NODE_TEST_TYPE;  | 
11118  |  |  | 
11119  | 126k  |   SKIP_BLANKS;  | 
11120  | 126k  |   if (*type == NODE_TYPE_PI) { | 
11121  |  |       /*  | 
11122  |  |        * Specific case: search a PI by name.  | 
11123  |  |        */  | 
11124  | 19.2k  |       if (name != NULL)  | 
11125  | 19.2k  |     xmlFree(name);  | 
11126  | 19.2k  |       name = NULL;  | 
11127  | 19.2k  |       if (CUR != ')') { | 
11128  | 10.8k  |     name = xmlXPathParseLiteral(ctxt);  | 
11129  | 10.8k  |                 if (name == NULL) { | 
11130  | 6.75k  |               XP_ERRORNULL(XPATH_EXPR_ERROR);  | 
11131  | 0  |                 }  | 
11132  | 4.13k  |     *test = NODE_TEST_PI;  | 
11133  | 4.13k  |     SKIP_BLANKS;  | 
11134  | 4.13k  |       }  | 
11135  | 19.2k  |   }  | 
11136  | 119k  |   if (CUR != ')') { | 
11137  | 6.66k  |       if (name != NULL)  | 
11138  | 6.66k  |     xmlFree(name);  | 
11139  | 6.66k  |       XP_ERRORNULL(XPATH_UNCLOSED_ERROR);  | 
11140  | 0  |   }  | 
11141  | 112k  |   NEXT;  | 
11142  | 112k  |   return(name);  | 
11143  | 119k  |     }  | 
11144  | 3.97M  |     *test = NODE_TEST_NAME;  | 
11145  | 3.97M  |     if ((!blanks) && (CUR == ':')) { | 
11146  | 318k  |   NEXT;  | 
11147  |  |  | 
11148  |  |   /*  | 
11149  |  |    * Since currently the parser context don't have a  | 
11150  |  |    * namespace list associated:  | 
11151  |  |    * The namespace name for this prefix can be computed  | 
11152  |  |    * only at evaluation time. The compilation is done  | 
11153  |  |    * outside of any context.  | 
11154  |  |    */  | 
11155  |  | #if 0  | 
11156  |  |   *prefix = xmlXPathNsLookup(ctxt->context, name);  | 
11157  |  |   if (name != NULL)  | 
11158  |  |       xmlFree(name);  | 
11159  |  |   if (*prefix == NULL) { | 
11160  |  |       XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);  | 
11161  |  |   }  | 
11162  |  | #else  | 
11163  | 318k  |   *prefix = name;  | 
11164  | 318k  | #endif  | 
11165  |  |  | 
11166  | 318k  |   if (CUR == '*') { | 
11167  |  |       /*  | 
11168  |  |        * All elements  | 
11169  |  |        */  | 
11170  | 19.0k  |       NEXT;  | 
11171  | 19.0k  |       *test = NODE_TEST_ALL;  | 
11172  | 19.0k  |       return(NULL);  | 
11173  | 19.0k  |   }  | 
11174  |  |  | 
11175  | 299k  |   name = xmlXPathParseNCName(ctxt);  | 
11176  | 299k  |   if (name == NULL) { | 
11177  | 67.1k  |       XP_ERRORNULL(XPATH_EXPR_ERROR);  | 
11178  | 0  |   }  | 
11179  | 299k  |     }  | 
11180  | 3.88M  |     return(name);  | 
11181  | 3.97M  | }  | 
11182  |  |  | 
11183  |  | /**  | 
11184  |  |  * xmlXPathIsAxisName:  | 
11185  |  |  * @name:  a preparsed name token  | 
11186  |  |  *  | 
11187  |  |  * [6] AxisName ::=   'ancestor'  | 
11188  |  |  *                  | 'ancestor-or-self'  | 
11189  |  |  *                  | 'attribute'  | 
11190  |  |  *                  | 'child'  | 
11191  |  |  *                  | 'descendant'  | 
11192  |  |  *                  | 'descendant-or-self'  | 
11193  |  |  *                  | 'following'  | 
11194  |  |  *                  | 'following-sibling'  | 
11195  |  |  *                  | 'namespace'  | 
11196  |  |  *                  | 'parent'  | 
11197  |  |  *                  | 'preceding'  | 
11198  |  |  *                  | 'preceding-sibling'  | 
11199  |  |  *                  | 'self'  | 
11200  |  |  *  | 
11201  |  |  * Returns the axis or 0  | 
11202  |  |  */  | 
11203  |  | static xmlXPathAxisVal  | 
11204  | 4.19M  | xmlXPathIsAxisName(const xmlChar *name) { | 
11205  | 4.19M  |     xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;  | 
11206  | 4.19M  |     switch (name[0]) { | 
11207  | 248k  |   case 'a':  | 
11208  | 248k  |       if (xmlStrEqual(name, BAD_CAST "ancestor"))  | 
11209  | 16.2k  |     ret = AXIS_ANCESTOR;  | 
11210  | 248k  |       if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))  | 
11211  | 9.65k  |     ret = AXIS_ANCESTOR_OR_SELF;  | 
11212  | 248k  |       if (xmlStrEqual(name, BAD_CAST "attribute"))  | 
11213  | 6.54k  |     ret = AXIS_ATTRIBUTE;  | 
11214  | 248k  |       break;  | 
11215  | 231k  |   case 'c':  | 
11216  | 231k  |       if (xmlStrEqual(name, BAD_CAST "child"))  | 
11217  | 10.3k  |     ret = AXIS_CHILD;  | 
11218  | 231k  |       break;  | 
11219  | 408k  |   case 'd':  | 
11220  | 408k  |       if (xmlStrEqual(name, BAD_CAST "descendant"))  | 
11221  | 10.7k  |     ret = AXIS_DESCENDANT;  | 
11222  | 408k  |       if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))  | 
11223  | 19.5k  |     ret = AXIS_DESCENDANT_OR_SELF;  | 
11224  | 408k  |       break;  | 
11225  | 80.8k  |   case 'f':  | 
11226  | 80.8k  |       if (xmlStrEqual(name, BAD_CAST "following"))  | 
11227  | 17.2k  |     ret = AXIS_FOLLOWING;  | 
11228  | 80.8k  |       if (xmlStrEqual(name, BAD_CAST "following-sibling"))  | 
11229  | 8.91k  |     ret = AXIS_FOLLOWING_SIBLING;  | 
11230  | 80.8k  |       break;  | 
11231  | 270k  |   case 'n':  | 
11232  | 270k  |       if (xmlStrEqual(name, BAD_CAST "namespace"))  | 
11233  | 39.5k  |     ret = AXIS_NAMESPACE;  | 
11234  | 270k  |       break;  | 
11235  | 226k  |   case 'p':  | 
11236  | 226k  |       if (xmlStrEqual(name, BAD_CAST "parent"))  | 
11237  | 11.1k  |     ret = AXIS_PARENT;  | 
11238  | 226k  |       if (xmlStrEqual(name, BAD_CAST "preceding"))  | 
11239  | 28.1k  |     ret = AXIS_PRECEDING;  | 
11240  | 226k  |       if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))  | 
11241  | 34.1k  |     ret = AXIS_PRECEDING_SIBLING;  | 
11242  | 226k  |       break;  | 
11243  | 228k  |   case 's':  | 
11244  | 228k  |       if (xmlStrEqual(name, BAD_CAST "self"))  | 
11245  | 73.8k  |     ret = AXIS_SELF;  | 
11246  | 228k  |       break;  | 
11247  | 4.19M  |     }  | 
11248  | 4.19M  |     return(ret);  | 
11249  | 4.19M  | }  | 
11250  |  |  | 
11251  |  | /**  | 
11252  |  |  * xmlXPathCompStep:  | 
11253  |  |  * @ctxt:  the XPath Parser context  | 
11254  |  |  *  | 
11255  |  |  * [4] Step ::=   AxisSpecifier NodeTest Predicate*  | 
11256  |  |  *                  | AbbreviatedStep  | 
11257  |  |  *  | 
11258  |  |  * [12] AbbreviatedStep ::=   '.' | '..'  | 
11259  |  |  *  | 
11260  |  |  * [5] AxisSpecifier ::= AxisName '::'  | 
11261  |  |  *                  | AbbreviatedAxisSpecifier  | 
11262  |  |  *  | 
11263  |  |  * [13] AbbreviatedAxisSpecifier ::= '@'?  | 
11264  |  |  *  | 
11265  |  |  * Modified for XPtr range support as:  | 
11266  |  |  *  | 
11267  |  |  *  [4xptr] Step ::= AxisSpecifier NodeTest Predicate*  | 
11268  |  |  *                     | AbbreviatedStep  | 
11269  |  |  *                     | 'range-to' '(' Expr ')' Predicate* | 
11270  |  |  *  | 
11271  |  |  * Compile one step in a Location Path  | 
11272  |  |  * A location step of . is short for self::node(). This is  | 
11273  |  |  * particularly useful in conjunction with //. For example, the  | 
11274  |  |  * location path .//para is short for  | 
11275  |  |  * self::node()/descendant-or-self::node()/child::para  | 
11276  |  |  * and so will select all para descendant elements of the context  | 
11277  |  |  * node.  | 
11278  |  |  * Similarly, a location step of .. is short for parent::node().  | 
11279  |  |  * For example, ../title is short for parent::node()/child::title  | 
11280  |  |  * and so will select the title children of the parent of the context  | 
11281  |  |  * node.  | 
11282  |  |  */  | 
11283  |  | static void  | 
11284  | 8.79M  | xmlXPathCompStep(xmlXPathParserContextPtr ctxt) { | 
11285  |  | #ifdef LIBXML_XPTR_LOCS_ENABLED  | 
11286  |  |     int rangeto = 0;  | 
11287  |  |     int op2 = -1;  | 
11288  |  | #endif  | 
11289  |  |  | 
11290  | 8.79M  |     SKIP_BLANKS;  | 
11291  | 8.79M  |     if ((CUR == '.') && (NXT(1) == '.')) { | 
11292  | 60.6k  |   SKIP(2);  | 
11293  | 60.6k  |   SKIP_BLANKS;  | 
11294  | 60.6k  |   PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,  | 
11295  | 60.6k  |         NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);  | 
11296  | 8.73M  |     } else if (CUR == '.') { | 
11297  | 868k  |   NEXT;  | 
11298  | 868k  |   SKIP_BLANKS;  | 
11299  | 7.86M  |     } else { | 
11300  | 7.86M  |   xmlChar *name = NULL;  | 
11301  | 7.86M  |   xmlChar *prefix = NULL;  | 
11302  | 7.86M  |   xmlXPathTestVal test = (xmlXPathTestVal) 0;  | 
11303  | 7.86M  |   xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;  | 
11304  | 7.86M  |   xmlXPathTypeVal type = (xmlXPathTypeVal) 0;  | 
11305  | 7.86M  |   int op1;  | 
11306  |  |  | 
11307  |  |   /*  | 
11308  |  |    * The modification needed for XPointer change to the production  | 
11309  |  |    */  | 
11310  |  | #ifdef LIBXML_XPTR_LOCS_ENABLED  | 
11311  |  |   if (ctxt->xptr) { | 
11312  |  |       name = xmlXPathParseNCName(ctxt);  | 
11313  |  |       if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) { | 
11314  |  |                 op2 = ctxt->comp->last;  | 
11315  |  |     xmlFree(name);  | 
11316  |  |     SKIP_BLANKS;  | 
11317  |  |     if (CUR != '(') { | 
11318  |  |         XP_ERROR(XPATH_EXPR_ERROR);  | 
11319  |  |     }  | 
11320  |  |     NEXT;  | 
11321  |  |     SKIP_BLANKS;  | 
11322  |  |  | 
11323  |  |     xmlXPathCompileExpr(ctxt, 1);  | 
11324  |  |     /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */  | 
11325  |  |     CHECK_ERROR;  | 
11326  |  |  | 
11327  |  |     SKIP_BLANKS;  | 
11328  |  |     if (CUR != ')') { | 
11329  |  |         XP_ERROR(XPATH_EXPR_ERROR);  | 
11330  |  |     }  | 
11331  |  |     NEXT;  | 
11332  |  |     rangeto = 1;  | 
11333  |  |     goto eval_predicates;  | 
11334  |  |       }  | 
11335  |  |   }  | 
11336  |  | #endif  | 
11337  | 7.86M  |   if (CUR == '*') { | 
11338  | 2.91M  |       axis = AXIS_CHILD;  | 
11339  | 4.94M  |   } else { | 
11340  | 4.94M  |       if (name == NULL)  | 
11341  | 4.94M  |     name = xmlXPathParseNCName(ctxt);  | 
11342  | 4.94M  |       if (name != NULL) { | 
11343  | 4.19M  |     axis = xmlXPathIsAxisName(name);  | 
11344  | 4.19M  |     if (axis != 0) { | 
11345  | 286k  |         SKIP_BLANKS;  | 
11346  | 286k  |         if ((CUR == ':') && (NXT(1) == ':')) { | 
11347  | 227k  |       SKIP(2);  | 
11348  | 227k  |       xmlFree(name);  | 
11349  | 227k  |       name = NULL;  | 
11350  | 227k  |         } else { | 
11351  |  |       /* an element name can conflict with an axis one :-\ */  | 
11352  | 58.7k  |       axis = AXIS_CHILD;  | 
11353  | 58.7k  |         }  | 
11354  | 3.91M  |     } else { | 
11355  | 3.91M  |         axis = AXIS_CHILD;  | 
11356  | 3.91M  |     }  | 
11357  | 4.19M  |       } else if (CUR == '@') { | 
11358  | 208k  |     NEXT;  | 
11359  | 208k  |     axis = AXIS_ATTRIBUTE;  | 
11360  | 539k  |       } else { | 
11361  | 539k  |     axis = AXIS_CHILD;  | 
11362  | 539k  |       }  | 
11363  | 4.94M  |   }  | 
11364  |  |  | 
11365  | 7.86M  |         if (ctxt->error != XPATH_EXPRESSION_OK) { | 
11366  | 605k  |             xmlFree(name);  | 
11367  | 605k  |             return;  | 
11368  | 605k  |         }  | 
11369  |  |  | 
11370  | 7.25M  |   name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);  | 
11371  | 7.25M  |   if (test == 0)  | 
11372  | 115k  |       return;  | 
11373  |  |  | 
11374  | 7.14M  |         if ((prefix != NULL) && (ctxt->context != NULL) &&  | 
11375  | 7.14M  |       (ctxt->context->flags & XML_XPATH_CHECKNS)) { | 
11376  | 0  |       if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) { | 
11377  | 0  |     xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR);  | 
11378  | 0  |       }  | 
11379  | 0  |   }  | 
11380  |  | #ifdef DEBUG_STEP  | 
11381  |  |   xmlGenericError(xmlGenericErrorContext,  | 
11382  |  |     "Basis : computing new set\n");  | 
11383  |  | #endif  | 
11384  |  |  | 
11385  |  | #ifdef DEBUG_STEP  | 
11386  |  |   xmlGenericError(xmlGenericErrorContext, "Basis : ");  | 
11387  |  |   if (ctxt->value == NULL)  | 
11388  |  |       xmlGenericError(xmlGenericErrorContext, "no value\n");  | 
11389  |  |   else if (ctxt->value->nodesetval == NULL)  | 
11390  |  |       xmlGenericError(xmlGenericErrorContext, "Empty\n");  | 
11391  |  |   else  | 
11392  |  |       xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);  | 
11393  |  | #endif  | 
11394  |  |  | 
11395  |  | #ifdef LIBXML_XPTR_LOCS_ENABLED  | 
11396  |  | eval_predicates:  | 
11397  |  | #endif  | 
11398  | 7.14M  |   op1 = ctxt->comp->last;  | 
11399  | 7.14M  |   ctxt->comp->last = -1;  | 
11400  |  |  | 
11401  | 7.14M  |   SKIP_BLANKS;  | 
11402  | 11.6M  |   while (CUR == '[') { | 
11403  | 4.55M  |       xmlXPathCompPredicate(ctxt, 0);  | 
11404  | 4.55M  |   }  | 
11405  |  |  | 
11406  |  | #ifdef LIBXML_XPTR_LOCS_ENABLED  | 
11407  |  |   if (rangeto) { | 
11408  |  |       PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);  | 
11409  |  |   } else  | 
11410  |  | #endif  | 
11411  | 7.14M  |         if (PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,  | 
11412  | 7.14M  |                            test, type, (void *)prefix, (void *)name) == -1) { | 
11413  | 0  |             xmlFree(prefix);  | 
11414  | 0  |             xmlFree(name);  | 
11415  | 0  |         }  | 
11416  | 7.14M  |     }  | 
11417  |  | #ifdef DEBUG_STEP  | 
11418  |  |     xmlGenericError(xmlGenericErrorContext, "Step : ");  | 
11419  |  |     if (ctxt->value == NULL)  | 
11420  |  |   xmlGenericError(xmlGenericErrorContext, "no value\n");  | 
11421  |  |     else if (ctxt->value->nodesetval == NULL)  | 
11422  |  |   xmlGenericError(xmlGenericErrorContext, "Empty\n");  | 
11423  |  |     else  | 
11424  |  |   xmlGenericErrorContextNodeSet(xmlGenericErrorContext,  | 
11425  |  |     ctxt->value->nodesetval);  | 
11426  |  | #endif  | 
11427  | 8.79M  | }  | 
11428  |  |  | 
11429  |  | /**  | 
11430  |  |  * xmlXPathCompRelativeLocationPath:  | 
11431  |  |  * @ctxt:  the XPath Parser context  | 
11432  |  |  *  | 
11433  |  |  *  [3]   RelativeLocationPath ::=   Step  | 
11434  |  |  *                     | RelativeLocationPath '/' Step  | 
11435  |  |  *                     | AbbreviatedRelativeLocationPath  | 
11436  |  |  *  [11]  AbbreviatedRelativeLocationPath ::=   RelativeLocationPath '//' Step  | 
11437  |  |  *  | 
11438  |  |  * Compile a relative location path.  | 
11439  |  |  */  | 
11440  |  | static void  | 
11441  |  | xmlXPathCompRelativeLocationPath  | 
11442  | 5.84M  | (xmlXPathParserContextPtr ctxt) { | 
11443  | 5.84M  |     SKIP_BLANKS;  | 
11444  | 5.84M  |     if ((CUR == '/') && (NXT(1) == '/')) { | 
11445  | 20.8k  |   SKIP(2);  | 
11446  | 20.8k  |   SKIP_BLANKS;  | 
11447  | 20.8k  |   PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,  | 
11448  | 20.8k  |              NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);  | 
11449  | 5.81M  |     } else if (CUR == '/') { | 
11450  | 211k  |       NEXT;  | 
11451  | 211k  |   SKIP_BLANKS;  | 
11452  | 211k  |     }  | 
11453  | 5.84M  |     xmlXPathCompStep(ctxt);  | 
11454  | 5.84M  |     CHECK_ERROR;  | 
11455  | 5.49M  |     SKIP_BLANKS;  | 
11456  | 8.44M  |     while (CUR == '/') { | 
11457  | 2.95M  |   if ((CUR == '/') && (NXT(1) == '/')) { | 
11458  | 1.30M  |       SKIP(2);  | 
11459  | 1.30M  |       SKIP_BLANKS;  | 
11460  | 1.30M  |       PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,  | 
11461  | 1.30M  |            NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);  | 
11462  | 1.30M  |       xmlXPathCompStep(ctxt);  | 
11463  | 1.64M  |   } else if (CUR == '/') { | 
11464  | 1.64M  |       NEXT;  | 
11465  | 1.64M  |       SKIP_BLANKS;  | 
11466  | 1.64M  |       xmlXPathCompStep(ctxt);  | 
11467  | 1.64M  |   }  | 
11468  | 2.95M  |   SKIP_BLANKS;  | 
11469  | 2.95M  |     }  | 
11470  | 5.49M  | }  | 
11471  |  |  | 
11472  |  | /**  | 
11473  |  |  * xmlXPathCompLocationPath:  | 
11474  |  |  * @ctxt:  the XPath Parser context  | 
11475  |  |  *  | 
11476  |  |  *  [1]   LocationPath ::=   RelativeLocationPath  | 
11477  |  |  *                     | AbsoluteLocationPath  | 
11478  |  |  *  [2]   AbsoluteLocationPath ::=   '/' RelativeLocationPath?  | 
11479  |  |  *                     | AbbreviatedAbsoluteLocationPath  | 
11480  |  |  *  [10]   AbbreviatedAbsoluteLocationPath ::=  | 
11481  |  |  *                           '//' RelativeLocationPath  | 
11482  |  |  *  | 
11483  |  |  * Compile a location path  | 
11484  |  |  *  | 
11485  |  |  * // is short for /descendant-or-self::node()/. For example,  | 
11486  |  |  * //para is short for /descendant-or-self::node()/child::para and  | 
11487  |  |  * so will select any para element in the document (even a para element  | 
11488  |  |  * that is a document element will be selected by //para since the  | 
11489  |  |  * document element node is a child of the root node); div//para is  | 
11490  |  |  * short for div/descendant-or-self::node()/child::para and so will  | 
11491  |  |  * select all para descendants of div children.  | 
11492  |  |  */  | 
11493  |  | static void  | 
11494  | 5.79M  | xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) { | 
11495  | 5.79M  |     SKIP_BLANKS;  | 
11496  | 5.79M  |     if (CUR != '/') { | 
11497  | 4.32M  |         xmlXPathCompRelativeLocationPath(ctxt);  | 
11498  | 4.32M  |     } else { | 
11499  | 2.81M  |   while (CUR == '/') { | 
11500  | 1.49M  |       if ((CUR == '/') && (NXT(1) == '/')) { | 
11501  | 832k  |     SKIP(2);  | 
11502  | 832k  |     SKIP_BLANKS;  | 
11503  | 832k  |     PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,  | 
11504  | 832k  |            NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);  | 
11505  | 832k  |     xmlXPathCompRelativeLocationPath(ctxt);  | 
11506  | 832k  |       } else if (CUR == '/') { | 
11507  | 659k  |     NEXT;  | 
11508  | 659k  |     SKIP_BLANKS;  | 
11509  | 659k  |     if ((CUR != 0 ) &&  | 
11510  | 659k  |         ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||  | 
11511  | 649k  |          (CUR == '@') || (CUR == '*')))  | 
11512  | 527k  |         xmlXPathCompRelativeLocationPath(ctxt);  | 
11513  | 659k  |       }  | 
11514  | 1.49M  |       CHECK_ERROR;  | 
11515  | 1.49M  |   }  | 
11516  | 1.47M  |     }  | 
11517  | 5.79M  | }  | 
11518  |  |  | 
11519  |  | /************************************************************************  | 
11520  |  |  *                  *  | 
11521  |  |  *    XPath precompiled expression evaluation     *  | 
11522  |  |  *                  *  | 
11523  |  |  ************************************************************************/  | 
11524  |  |  | 
11525  |  | static int  | 
11526  |  | xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);  | 
11527  |  |  | 
11528  |  | #ifdef DEBUG_STEP  | 
11529  |  | static void  | 
11530  |  | xmlXPathDebugDumpStepAxis(xmlXPathStepOpPtr op,  | 
11531  |  |         int nbNodes)  | 
11532  |  | { | 
11533  |  |     xmlGenericError(xmlGenericErrorContext, "new step : ");  | 
11534  |  |     switch (op->value) { | 
11535  |  |         case AXIS_ANCESTOR:  | 
11536  |  |             xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");  | 
11537  |  |             break;  | 
11538  |  |         case AXIS_ANCESTOR_OR_SELF:  | 
11539  |  |             xmlGenericError(xmlGenericErrorContext,  | 
11540  |  |                             "axis 'ancestors-or-self' ");  | 
11541  |  |             break;  | 
11542  |  |         case AXIS_ATTRIBUTE:  | 
11543  |  |             xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");  | 
11544  |  |             break;  | 
11545  |  |         case AXIS_CHILD:  | 
11546  |  |             xmlGenericError(xmlGenericErrorContext, "axis 'child' ");  | 
11547  |  |             break;  | 
11548  |  |         case AXIS_DESCENDANT:  | 
11549  |  |             xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");  | 
11550  |  |             break;  | 
11551  |  |         case AXIS_DESCENDANT_OR_SELF:  | 
11552  |  |             xmlGenericError(xmlGenericErrorContext,  | 
11553  |  |                             "axis 'descendant-or-self' ");  | 
11554  |  |             break;  | 
11555  |  |         case AXIS_FOLLOWING:  | 
11556  |  |             xmlGenericError(xmlGenericErrorContext, "axis 'following' ");  | 
11557  |  |             break;  | 
11558  |  |         case AXIS_FOLLOWING_SIBLING:  | 
11559  |  |             xmlGenericError(xmlGenericErrorContext,  | 
11560  |  |                             "axis 'following-siblings' ");  | 
11561  |  |             break;  | 
11562  |  |         case AXIS_NAMESPACE:  | 
11563  |  |             xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");  | 
11564  |  |             break;  | 
11565  |  |         case AXIS_PARENT:  | 
11566  |  |             xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");  | 
11567  |  |             break;  | 
11568  |  |         case AXIS_PRECEDING:  | 
11569  |  |             xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");  | 
11570  |  |             break;  | 
11571  |  |         case AXIS_PRECEDING_SIBLING:  | 
11572  |  |             xmlGenericError(xmlGenericErrorContext,  | 
11573  |  |                             "axis 'preceding-sibling' ");  | 
11574  |  |             break;  | 
11575  |  |         case AXIS_SELF:  | 
11576  |  |             xmlGenericError(xmlGenericErrorContext, "axis 'self' ");  | 
11577  |  |             break;  | 
11578  |  |     }  | 
11579  |  |     xmlGenericError(xmlGenericErrorContext,  | 
11580  |  |   " context contains %d nodes\n", nbNodes);  | 
11581  |  |     switch (op->value2) { | 
11582  |  |         case NODE_TEST_NONE:  | 
11583  |  |             xmlGenericError(xmlGenericErrorContext,  | 
11584  |  |                             "           searching for none !!!\n");  | 
11585  |  |             break;  | 
11586  |  |         case NODE_TEST_TYPE:  | 
11587  |  |             xmlGenericError(xmlGenericErrorContext,  | 
11588  |  |                             "           searching for type %d\n", op->value3);  | 
11589  |  |             break;  | 
11590  |  |         case NODE_TEST_PI:  | 
11591  |  |             xmlGenericError(xmlGenericErrorContext,  | 
11592  |  |                             "           searching for PI !!!\n");  | 
11593  |  |             break;  | 
11594  |  |         case NODE_TEST_ALL:  | 
11595  |  |             xmlGenericError(xmlGenericErrorContext,  | 
11596  |  |                             "           searching for *\n");  | 
11597  |  |             break;  | 
11598  |  |         case NODE_TEST_NS:  | 
11599  |  |             xmlGenericError(xmlGenericErrorContext,  | 
11600  |  |                             "           searching for namespace %s\n",  | 
11601  |  |                             op->value5);  | 
11602  |  |             break;  | 
11603  |  |         case NODE_TEST_NAME:  | 
11604  |  |             xmlGenericError(xmlGenericErrorContext,  | 
11605  |  |                             "           searching for name %s\n", op->value5);  | 
11606  |  |             if (op->value4)  | 
11607  |  |                 xmlGenericError(xmlGenericErrorContext,  | 
11608  |  |                                 "           with namespace %s\n", op->value4);  | 
11609  |  |             break;  | 
11610  |  |     }  | 
11611  |  |     xmlGenericError(xmlGenericErrorContext, "Testing : ");  | 
11612  |  | }  | 
11613  |  | #endif /* DEBUG_STEP */  | 
11614  |  |  | 
11615  |  | /**  | 
11616  |  |  * xmlXPathNodeSetFilter:  | 
11617  |  |  * @ctxt:  the XPath Parser context  | 
11618  |  |  * @set: the node set to filter  | 
11619  |  |  * @filterOpIndex: the index of the predicate/filter op  | 
11620  |  |  * @minPos: minimum position in the filtered set (1-based)  | 
11621  |  |  * @maxPos: maximum position in the filtered set (1-based)  | 
11622  |  |  * @hasNsNodes: true if the node set may contain namespace nodes  | 
11623  |  |  *  | 
11624  |  |  * Filter a node set, keeping only nodes for which the predicate expression  | 
11625  |  |  * matches. Afterwards, keep only nodes between minPos and maxPos in the  | 
11626  |  |  * filtered result.  | 
11627  |  |  */  | 
11628  |  | static void  | 
11629  |  | xmlXPathNodeSetFilter(xmlXPathParserContextPtr ctxt,  | 
11630  |  |           xmlNodeSetPtr set,  | 
11631  |  |           int filterOpIndex,  | 
11632  |  |                       int minPos, int maxPos,  | 
11633  |  |           int hasNsNodes)  | 
11634  | 1.98M  | { | 
11635  | 1.98M  |     xmlXPathContextPtr xpctxt;  | 
11636  | 1.98M  |     xmlNodePtr oldnode;  | 
11637  | 1.98M  |     xmlDocPtr olddoc;  | 
11638  | 1.98M  |     xmlXPathStepOpPtr filterOp;  | 
11639  | 1.98M  |     int oldcs, oldpp;  | 
11640  | 1.98M  |     int i, j, pos;  | 
11641  |  |  | 
11642  | 1.98M  |     if ((set == NULL) || (set->nodeNr == 0))  | 
11643  | 152k  |         return;  | 
11644  |  |  | 
11645  |  |     /*  | 
11646  |  |     * Check if the node set contains a sufficient number of nodes for  | 
11647  |  |     * the requested range.  | 
11648  |  |     */  | 
11649  | 1.83M  |     if (set->nodeNr < minPos) { | 
11650  | 27.6k  |         xmlXPathNodeSetClear(set, hasNsNodes);  | 
11651  | 27.6k  |         return;  | 
11652  | 27.6k  |     }  | 
11653  |  |  | 
11654  | 1.80M  |     xpctxt = ctxt->context;  | 
11655  | 1.80M  |     oldnode = xpctxt->node;  | 
11656  | 1.80M  |     olddoc = xpctxt->doc;  | 
11657  | 1.80M  |     oldcs = xpctxt->contextSize;  | 
11658  | 1.80M  |     oldpp = xpctxt->proximityPosition;  | 
11659  | 1.80M  |     filterOp = &ctxt->comp->steps[filterOpIndex];  | 
11660  |  |  | 
11661  | 1.80M  |     xpctxt->contextSize = set->nodeNr;  | 
11662  |  |  | 
11663  | 7.47M  |     for (i = 0, j = 0, pos = 1; i < set->nodeNr; i++) { | 
11664  | 6.44M  |         xmlNodePtr node = set->nodeTab[i];  | 
11665  | 6.44M  |         int res;  | 
11666  |  |  | 
11667  | 6.44M  |         xpctxt->node = node;  | 
11668  | 6.44M  |         xpctxt->proximityPosition = i + 1;  | 
11669  |  |  | 
11670  |  |         /*  | 
11671  |  |         * Also set the xpath document in case things like  | 
11672  |  |         * key() are evaluated in the predicate.  | 
11673  |  |         *  | 
11674  |  |         * TODO: Get real doc for namespace nodes.  | 
11675  |  |         */  | 
11676  | 6.44M  |         if ((node->type != XML_NAMESPACE_DECL) &&  | 
11677  | 6.44M  |             (node->doc != NULL))  | 
11678  | 6.22M  |             xpctxt->doc = node->doc;  | 
11679  |  |  | 
11680  | 6.44M  |         res = xmlXPathCompOpEvalToBoolean(ctxt, filterOp, 1);  | 
11681  |  |  | 
11682  | 6.44M  |         if (ctxt->error != XPATH_EXPRESSION_OK)  | 
11683  | 7.35k  |             break;  | 
11684  | 6.44M  |         if (res < 0) { | 
11685  |  |             /* Shouldn't happen */  | 
11686  | 0  |             xmlXPathErr(ctxt, XPATH_EXPR_ERROR);  | 
11687  | 0  |             break;  | 
11688  | 0  |         }  | 
11689  |  |  | 
11690  | 6.44M  |         if ((res != 0) && ((pos >= minPos) && (pos <= maxPos))) { | 
11691  | 2.61M  |             if (i != j) { | 
11692  | 93.5k  |                 set->nodeTab[j] = node;  | 
11693  | 93.5k  |                 set->nodeTab[i] = NULL;  | 
11694  | 93.5k  |             }  | 
11695  |  |  | 
11696  | 2.61M  |             j += 1;  | 
11697  | 3.82M  |         } else { | 
11698  |  |             /* Remove the entry from the initial node set. */  | 
11699  | 3.82M  |             set->nodeTab[i] = NULL;  | 
11700  | 3.82M  |             if (node->type == XML_NAMESPACE_DECL)  | 
11701  | 133k  |                 xmlXPathNodeSetFreeNs((xmlNsPtr) node);  | 
11702  | 3.82M  |         }  | 
11703  |  |  | 
11704  | 6.44M  |         if (res != 0) { | 
11705  | 2.64M  |             if (pos == maxPos) { | 
11706  | 772k  |                 i += 1;  | 
11707  | 772k  |                 break;  | 
11708  | 772k  |             }  | 
11709  |  |  | 
11710  | 1.87M  |             pos += 1;  | 
11711  | 1.87M  |         }  | 
11712  | 6.44M  |     }  | 
11713  |  |  | 
11714  |  |     /* Free remaining nodes. */  | 
11715  | 1.80M  |     if (hasNsNodes) { | 
11716  | 209k  |         for (; i < set->nodeNr; i++) { | 
11717  | 74.9k  |             xmlNodePtr node = set->nodeTab[i];  | 
11718  | 74.9k  |             if ((node != NULL) && (node->type == XML_NAMESPACE_DECL))  | 
11719  | 9.59k  |                 xmlXPathNodeSetFreeNs((xmlNsPtr) node);  | 
11720  | 74.9k  |         }  | 
11721  | 134k  |     }  | 
11722  |  |  | 
11723  | 1.80M  |     set->nodeNr = j;  | 
11724  |  |  | 
11725  |  |     /* If too many elements were removed, shrink table to preserve memory. */  | 
11726  | 1.80M  |     if ((set->nodeMax > XML_NODESET_DEFAULT) &&  | 
11727  | 1.80M  |         (set->nodeNr < set->nodeMax / 2)) { | 
11728  | 73.5k  |         xmlNodePtr *tmp;  | 
11729  | 73.5k  |         int nodeMax = set->nodeNr;  | 
11730  |  |  | 
11731  | 73.5k  |         if (nodeMax < XML_NODESET_DEFAULT)  | 
11732  | 73.1k  |             nodeMax = XML_NODESET_DEFAULT;  | 
11733  | 73.5k  |         tmp = (xmlNodePtr *) xmlRealloc(set->nodeTab,  | 
11734  | 73.5k  |                 nodeMax * sizeof(xmlNodePtr));  | 
11735  | 73.5k  |         if (tmp == NULL) { | 
11736  | 0  |             xmlXPathPErrMemory(ctxt, "shrinking nodeset\n");  | 
11737  | 73.5k  |         } else { | 
11738  | 73.5k  |             set->nodeTab = tmp;  | 
11739  | 73.5k  |             set->nodeMax = nodeMax;  | 
11740  | 73.5k  |         }  | 
11741  | 73.5k  |     }  | 
11742  |  |  | 
11743  | 1.80M  |     xpctxt->node = oldnode;  | 
11744  | 1.80M  |     xpctxt->doc = olddoc;  | 
11745  | 1.80M  |     xpctxt->contextSize = oldcs;  | 
11746  | 1.80M  |     xpctxt->proximityPosition = oldpp;  | 
11747  | 1.80M  | }  | 
11748  |  |  | 
11749  |  | #ifdef LIBXML_XPTR_LOCS_ENABLED  | 
11750  |  | /**  | 
11751  |  |  * xmlXPathLocationSetFilter:  | 
11752  |  |  * @ctxt:  the XPath Parser context  | 
11753  |  |  * @locset: the location set to filter  | 
11754  |  |  * @filterOpIndex: the index of the predicate/filter op  | 
11755  |  |  * @minPos: minimum position in the filtered set (1-based)  | 
11756  |  |  * @maxPos: maximum position in the filtered set (1-based)  | 
11757  |  |  *  | 
11758  |  |  * Filter a location set, keeping only nodes for which the predicate  | 
11759  |  |  * expression matches. Afterwards, keep only nodes between minPos and maxPos  | 
11760  |  |  * in the filtered result.  | 
11761  |  |  */  | 
11762  |  | static void  | 
11763  |  | xmlXPathLocationSetFilter(xmlXPathParserContextPtr ctxt,  | 
11764  |  |               xmlLocationSetPtr locset,  | 
11765  |  |               int filterOpIndex,  | 
11766  |  |                           int minPos, int maxPos)  | 
11767  |  | { | 
11768  |  |     xmlXPathContextPtr xpctxt;  | 
11769  |  |     xmlNodePtr oldnode;  | 
11770  |  |     xmlDocPtr olddoc;  | 
11771  |  |     xmlXPathStepOpPtr filterOp;  | 
11772  |  |     int oldcs, oldpp;  | 
11773  |  |     int i, j, pos;  | 
11774  |  |  | 
11775  |  |     if ((locset == NULL) || (locset->locNr == 0) || (filterOpIndex == -1))  | 
11776  |  |         return;  | 
11777  |  |  | 
11778  |  |     xpctxt = ctxt->context;  | 
11779  |  |     oldnode = xpctxt->node;  | 
11780  |  |     olddoc = xpctxt->doc;  | 
11781  |  |     oldcs = xpctxt->contextSize;  | 
11782  |  |     oldpp = xpctxt->proximityPosition;  | 
11783  |  |     filterOp = &ctxt->comp->steps[filterOpIndex];  | 
11784  |  |  | 
11785  |  |     xpctxt->contextSize = locset->locNr;  | 
11786  |  |  | 
11787  |  |     for (i = 0, j = 0, pos = 1; i < locset->locNr; i++) { | 
11788  |  |         xmlNodePtr contextNode = locset->locTab[i]->user;  | 
11789  |  |         int res;  | 
11790  |  |  | 
11791  |  |         xpctxt->node = contextNode;  | 
11792  |  |         xpctxt->proximityPosition = i + 1;  | 
11793  |  |  | 
11794  |  |         /*  | 
11795  |  |         * Also set the xpath document in case things like  | 
11796  |  |         * key() are evaluated in the predicate.  | 
11797  |  |         *  | 
11798  |  |         * TODO: Get real doc for namespace nodes.  | 
11799  |  |         */  | 
11800  |  |         if ((contextNode->type != XML_NAMESPACE_DECL) &&  | 
11801  |  |             (contextNode->doc != NULL))  | 
11802  |  |             xpctxt->doc = contextNode->doc;  | 
11803  |  |  | 
11804  |  |         res = xmlXPathCompOpEvalToBoolean(ctxt, filterOp, 1);  | 
11805  |  |  | 
11806  |  |         if (ctxt->error != XPATH_EXPRESSION_OK)  | 
11807  |  |             break;  | 
11808  |  |         if (res < 0) { | 
11809  |  |             /* Shouldn't happen */  | 
11810  |  |             xmlXPathErr(ctxt, XPATH_EXPR_ERROR);  | 
11811  |  |             break;  | 
11812  |  |         }  | 
11813  |  |  | 
11814  |  |         if ((res != 0) && ((pos >= minPos) && (pos <= maxPos))) { | 
11815  |  |             if (i != j) { | 
11816  |  |                 locset->locTab[j] = locset->locTab[i];  | 
11817  |  |                 locset->locTab[i] = NULL;  | 
11818  |  |             }  | 
11819  |  |  | 
11820  |  |             j += 1;  | 
11821  |  |         } else { | 
11822  |  |             /* Remove the entry from the initial location set. */  | 
11823  |  |             xmlXPathFreeObject(locset->locTab[i]);  | 
11824  |  |             locset->locTab[i] = NULL;  | 
11825  |  |         }  | 
11826  |  |  | 
11827  |  |         if (res != 0) { | 
11828  |  |             if (pos == maxPos) { | 
11829  |  |                 i += 1;  | 
11830  |  |                 break;  | 
11831  |  |             }  | 
11832  |  |  | 
11833  |  |             pos += 1;  | 
11834  |  |         }  | 
11835  |  |     }  | 
11836  |  |  | 
11837  |  |     /* Free remaining nodes. */  | 
11838  |  |     for (; i < locset->locNr; i++)  | 
11839  |  |         xmlXPathFreeObject(locset->locTab[i]);  | 
11840  |  |  | 
11841  |  |     locset->locNr = j;  | 
11842  |  |  | 
11843  |  |     /* If too many elements were removed, shrink table to preserve memory. */  | 
11844  |  |     if ((locset->locMax > XML_NODESET_DEFAULT) &&  | 
11845  |  |         (locset->locNr < locset->locMax / 2)) { | 
11846  |  |         xmlXPathObjectPtr *tmp;  | 
11847  |  |         int locMax = locset->locNr;  | 
11848  |  |  | 
11849  |  |         if (locMax < XML_NODESET_DEFAULT)  | 
11850  |  |             locMax = XML_NODESET_DEFAULT;  | 
11851  |  |         tmp = (xmlXPathObjectPtr *) xmlRealloc(locset->locTab,  | 
11852  |  |                 locMax * sizeof(xmlXPathObjectPtr));  | 
11853  |  |         if (tmp == NULL) { | 
11854  |  |             xmlXPathPErrMemory(ctxt, "shrinking locset\n");  | 
11855  |  |         } else { | 
11856  |  |             locset->locTab = tmp;  | 
11857  |  |             locset->locMax = locMax;  | 
11858  |  |         }  | 
11859  |  |     }  | 
11860  |  |  | 
11861  |  |     xpctxt->node = oldnode;  | 
11862  |  |     xpctxt->doc = olddoc;  | 
11863  |  |     xpctxt->contextSize = oldcs;  | 
11864  |  |     xpctxt->proximityPosition = oldpp;  | 
11865  |  | }  | 
11866  |  | #endif /* LIBXML_XPTR_LOCS_ENABLED */  | 
11867  |  |  | 
11868  |  | /**  | 
11869  |  |  * xmlXPathCompOpEvalPredicate:  | 
11870  |  |  * @ctxt:  the XPath Parser context  | 
11871  |  |  * @op: the predicate op  | 
11872  |  |  * @set: the node set to filter  | 
11873  |  |  * @minPos: minimum position in the filtered set (1-based)  | 
11874  |  |  * @maxPos: maximum position in the filtered set (1-based)  | 
11875  |  |  * @hasNsNodes: true if the node set may contain namespace nodes  | 
11876  |  |  *  | 
11877  |  |  * Filter a node set, keeping only nodes for which the sequence of predicate  | 
11878  |  |  * expressions matches. Afterwards, keep only nodes between minPos and maxPos  | 
11879  |  |  * in the filtered result.  | 
11880  |  |  */  | 
11881  |  | static void  | 
11882  |  | xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,  | 
11883  |  |           xmlXPathStepOpPtr op,  | 
11884  |  |           xmlNodeSetPtr set,  | 
11885  |  |                             int minPos, int maxPos,  | 
11886  |  |           int hasNsNodes)  | 
11887  | 1.85M  | { | 
11888  | 1.85M  |     if (op->ch1 != -1) { | 
11889  | 127k  |   xmlXPathCompExprPtr comp = ctxt->comp;  | 
11890  |  |   /*  | 
11891  |  |   * Process inner predicates first.  | 
11892  |  |   */  | 
11893  | 127k  |   if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) { | 
11894  | 0  |             xmlGenericError(xmlGenericErrorContext,  | 
11895  | 0  |                 "xmlXPathCompOpEvalPredicate: Expected a predicate\n");  | 
11896  | 0  |             XP_ERROR(XPATH_INVALID_OPERAND);  | 
11897  | 0  |   }  | 
11898  | 127k  |         if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)  | 
11899  | 127k  |             XP_ERROR(XPATH_RECURSION_LIMIT_EXCEEDED);  | 
11900  | 127k  |         ctxt->context->depth += 1;  | 
11901  | 127k  |   xmlXPathCompOpEvalPredicate(ctxt, &comp->steps[op->ch1], set,  | 
11902  | 127k  |                                     1, set->nodeNr, hasNsNodes);  | 
11903  | 127k  |         ctxt->context->depth -= 1;  | 
11904  | 127k  |   CHECK_ERROR;  | 
11905  | 127k  |     }  | 
11906  |  |  | 
11907  | 1.85M  |     if (op->ch2 != -1)  | 
11908  | 1.85M  |         xmlXPathNodeSetFilter(ctxt, set, op->ch2, minPos, maxPos, hasNsNodes);  | 
11909  | 1.85M  | }  | 
11910  |  |  | 
11911  |  | static int  | 
11912  |  | xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,  | 
11913  |  |           xmlXPathStepOpPtr op,  | 
11914  |  |           int *maxPos)  | 
11915  | 761k  | { | 
11916  |  |  | 
11917  | 761k  |     xmlXPathStepOpPtr exprOp;  | 
11918  |  |  | 
11919  |  |     /*  | 
11920  |  |     * BIG NOTE: This is not intended for XPATH_OP_FILTER yet!  | 
11921  |  |     */  | 
11922  |  |  | 
11923  |  |     /*  | 
11924  |  |     * If not -1, then ch1 will point to:  | 
11925  |  |     * 1) For predicates (XPATH_OP_PREDICATE):  | 
11926  |  |     *    - an inner predicate operator  | 
11927  |  |     * 2) For filters (XPATH_OP_FILTER):  | 
11928  |  |     *    - an inner filter operator OR  | 
11929  |  |     *    - an expression selecting the node set.  | 
11930  |  |     *      E.g. "key('a', 'b')" or "(//foo | //bar)". | 
11931  |  |     */  | 
11932  | 761k  |     if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER))  | 
11933  | 0  |   return(0);  | 
11934  |  |  | 
11935  | 761k  |     if (op->ch2 != -1) { | 
11936  | 761k  |   exprOp = &ctxt->comp->steps[op->ch2];  | 
11937  | 761k  |     } else  | 
11938  | 0  |   return(0);  | 
11939  |  |  | 
11940  | 761k  |     if ((exprOp != NULL) &&  | 
11941  | 761k  |   (exprOp->op == XPATH_OP_VALUE) &&  | 
11942  | 761k  |   (exprOp->value4 != NULL) &&  | 
11943  | 761k  |   (((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER))  | 
11944  | 269k  |     { | 
11945  | 269k  |         double floatval = ((xmlXPathObjectPtr) exprOp->value4)->floatval;  | 
11946  |  |  | 
11947  |  |   /*  | 
11948  |  |   * We have a "[n]" predicate here.  | 
11949  |  |   * TODO: Unfortunately this simplistic test here is not  | 
11950  |  |   * able to detect a position() predicate in compound  | 
11951  |  |   * expressions like "[@attr = 'a" and position() = 1],  | 
11952  |  |   * and even not the usage of position() in  | 
11953  |  |   * "[position() = 1]"; thus - obviously - a position-range,  | 
11954  |  |   * like it "[position() < 5]", is also not detected.  | 
11955  |  |   * Maybe we could rewrite the AST to ease the optimization.  | 
11956  |  |   */  | 
11957  |  |  | 
11958  | 269k  |         if ((floatval > INT_MIN) && (floatval < INT_MAX)) { | 
11959  | 262k  |       *maxPos = (int) floatval;  | 
11960  | 262k  |             if (floatval == (double) *maxPos)  | 
11961  | 258k  |                 return(1);  | 
11962  | 262k  |         }  | 
11963  | 269k  |     }  | 
11964  | 502k  |     return(0);  | 
11965  | 761k  | }  | 
11966  |  |  | 
11967  |  | static int  | 
11968  |  | xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,  | 
11969  |  |                            xmlXPathStepOpPtr op,  | 
11970  |  |          xmlNodePtr * first, xmlNodePtr * last,  | 
11971  |  |          int toBool)  | 
11972  | 25.7M  | { | 
11973  |  |  | 
11974  | 25.7M  | #define XP_TEST_HIT \  | 
11975  | 89.9M  |     if (hasAxisRange != 0) { \ | 
11976  | 783k  |   if (++pos == maxPos) { \ | 
11977  | 432k  |       if (addNode(seq, cur) < 0) \  | 
11978  | 432k  |           ctxt->error = XPATH_MEMORY_ERROR; \  | 
11979  | 432k  |       goto axis_range_end; } \  | 
11980  | 89.1M  |     } else { \ | 
11981  | 89.1M  |   if (addNode(seq, cur) < 0) \  | 
11982  | 89.1M  |       ctxt->error = XPATH_MEMORY_ERROR; \  | 
11983  | 89.1M  |   if (breakOnFirstHit) goto first_hit; }  | 
11984  |  |  | 
11985  | 25.7M  | #define XP_TEST_HIT_NS \  | 
11986  | 25.7M  |     if (hasAxisRange != 0) { \ | 
11987  | 61.8k  |   if (++pos == maxPos) { \ | 
11988  | 36.6k  |       hasNsNodes = 1; \  | 
11989  | 36.6k  |       if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \  | 
11990  | 36.6k  |           ctxt->error = XPATH_MEMORY_ERROR; \  | 
11991  | 36.6k  |   goto axis_range_end; } \  | 
11992  | 842k  |     } else { \ | 
11993  | 842k  |   hasNsNodes = 1; \  | 
11994  | 842k  |   if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \  | 
11995  | 842k  |       ctxt->error = XPATH_MEMORY_ERROR; \  | 
11996  | 842k  |   if (breakOnFirstHit) goto first_hit; }  | 
11997  |  |  | 
11998  | 25.7M  |     xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;  | 
11999  | 25.7M  |     xmlXPathTestVal test = (xmlXPathTestVal) op->value2;  | 
12000  | 25.7M  |     xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;  | 
12001  | 25.7M  |     const xmlChar *prefix = op->value4;  | 
12002  | 25.7M  |     const xmlChar *name = op->value5;  | 
12003  | 25.7M  |     const xmlChar *URI = NULL;  | 
12004  |  |  | 
12005  |  | #ifdef DEBUG_STEP  | 
12006  |  |     int nbMatches = 0, prevMatches = 0;  | 
12007  |  | #endif  | 
12008  | 25.7M  |     int total = 0, hasNsNodes = 0;  | 
12009  |  |     /* The popped object holding the context nodes */  | 
12010  | 25.7M  |     xmlXPathObjectPtr obj;  | 
12011  |  |     /* The set of context nodes for the node tests */  | 
12012  | 25.7M  |     xmlNodeSetPtr contextSeq;  | 
12013  | 25.7M  |     int contextIdx;  | 
12014  | 25.7M  |     xmlNodePtr contextNode;  | 
12015  |  |     /* The final resulting node set wrt to all context nodes */  | 
12016  | 25.7M  |     xmlNodeSetPtr outSeq;  | 
12017  |  |     /*  | 
12018  |  |     * The temporary resulting node set wrt 1 context node.  | 
12019  |  |     * Used to feed predicate evaluation.  | 
12020  |  |     */  | 
12021  | 25.7M  |     xmlNodeSetPtr seq;  | 
12022  | 25.7M  |     xmlNodePtr cur;  | 
12023  |  |     /* First predicate operator */  | 
12024  | 25.7M  |     xmlXPathStepOpPtr predOp;  | 
12025  | 25.7M  |     int maxPos; /* The requested position() (when a "[n]" predicate) */  | 
12026  | 25.7M  |     int hasPredicateRange, hasAxisRange, pos;  | 
12027  | 25.7M  |     int breakOnFirstHit;  | 
12028  |  |  | 
12029  | 25.7M  |     xmlXPathTraversalFunction next = NULL;  | 
12030  | 25.7M  |     int (*addNode) (xmlNodeSetPtr, xmlNodePtr);  | 
12031  | 25.7M  |     xmlXPathNodeSetMergeFunction mergeAndClear;  | 
12032  | 25.7M  |     xmlNodePtr oldContextNode;  | 
12033  | 25.7M  |     xmlXPathContextPtr xpctxt = ctxt->context;  | 
12034  |  |  | 
12035  |  |  | 
12036  | 25.7M  |     CHECK_TYPE0(XPATH_NODESET);  | 
12037  | 25.7M  |     obj = valuePop(ctxt);  | 
12038  |  |     /*  | 
12039  |  |     * Setup namespaces.  | 
12040  |  |     */  | 
12041  | 25.7M  |     if (prefix != NULL) { | 
12042  | 595k  |         URI = xmlXPathNsLookup(xpctxt, prefix);  | 
12043  | 595k  |         if (URI == NULL) { | 
12044  | 45.1k  |       xmlXPathReleaseObject(xpctxt, obj);  | 
12045  | 45.1k  |             XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);  | 
12046  | 0  |   }  | 
12047  | 595k  |     }  | 
12048  |  |     /*  | 
12049  |  |     * Setup axis.  | 
12050  |  |     *  | 
12051  |  |     * MAYBE FUTURE TODO: merging optimizations:  | 
12052  |  |     * - If the nodes to be traversed wrt to the initial nodes and  | 
12053  |  |     *   the current axis cannot overlap, then we could avoid searching  | 
12054  |  |     *   for duplicates during the merge.  | 
12055  |  |     *   But the question is how/when to evaluate if they cannot overlap.  | 
12056  |  |     *   Example: if we know that for two initial nodes, the one is  | 
12057  |  |     *   not in the ancestor-or-self axis of the other, then we could safely  | 
12058  |  |     *   avoid a duplicate-aware merge, if the axis to be traversed is e.g.  | 
12059  |  |     *   the descendant-or-self axis.  | 
12060  |  |     */  | 
12061  | 25.6M  |     mergeAndClear = xmlXPathNodeSetMergeAndClear;  | 
12062  | 25.6M  |     switch (axis) { | 
12063  | 128k  |         case AXIS_ANCESTOR:  | 
12064  | 128k  |             first = NULL;  | 
12065  | 128k  |             next = xmlXPathNextAncestor;  | 
12066  | 128k  |             break;  | 
12067  | 76.6k  |         case AXIS_ANCESTOR_OR_SELF:  | 
12068  | 76.6k  |             first = NULL;  | 
12069  | 76.6k  |             next = xmlXPathNextAncestorOrSelf;  | 
12070  | 76.6k  |             break;  | 
12071  | 1.70M  |         case AXIS_ATTRIBUTE:  | 
12072  | 1.70M  |             first = NULL;  | 
12073  | 1.70M  |       last = NULL;  | 
12074  | 1.70M  |             next = xmlXPathNextAttribute;  | 
12075  | 1.70M  |       mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;  | 
12076  | 1.70M  |             break;  | 
12077  | 15.6M  |         case AXIS_CHILD:  | 
12078  | 15.6M  |       last = NULL;  | 
12079  | 15.6M  |       if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) &&  | 
12080  | 15.6M  |     (type == NODE_TYPE_NODE))  | 
12081  | 15.4M  |       { | 
12082  |  |     /*  | 
12083  |  |     * Optimization if an element node type is 'element'.  | 
12084  |  |     */  | 
12085  | 15.4M  |     next = xmlXPathNextChildElement;  | 
12086  | 15.4M  |       } else  | 
12087  | 193k  |     next = xmlXPathNextChild;  | 
12088  | 15.6M  |       mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;  | 
12089  | 15.6M  |             break;  | 
12090  | 5.06M  |         case AXIS_DESCENDANT:  | 
12091  | 5.06M  |       last = NULL;  | 
12092  | 5.06M  |             next = xmlXPathNextDescendant;  | 
12093  | 5.06M  |             break;  | 
12094  | 2.43M  |         case AXIS_DESCENDANT_OR_SELF:  | 
12095  | 2.43M  |       last = NULL;  | 
12096  | 2.43M  |             next = xmlXPathNextDescendantOrSelf;  | 
12097  | 2.43M  |             break;  | 
12098  | 42.0k  |         case AXIS_FOLLOWING:  | 
12099  | 42.0k  |       last = NULL;  | 
12100  | 42.0k  |             next = xmlXPathNextFollowing;  | 
12101  | 42.0k  |             break;  | 
12102  | 14.9k  |         case AXIS_FOLLOWING_SIBLING:  | 
12103  | 14.9k  |       last = NULL;  | 
12104  | 14.9k  |             next = xmlXPathNextFollowingSibling;  | 
12105  | 14.9k  |             break;  | 
12106  | 137k  |         case AXIS_NAMESPACE:  | 
12107  | 137k  |             first = NULL;  | 
12108  | 137k  |       last = NULL;  | 
12109  | 137k  |             next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;  | 
12110  | 137k  |       mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;  | 
12111  | 137k  |             break;  | 
12112  | 332k  |         case AXIS_PARENT:  | 
12113  | 332k  |             first = NULL;  | 
12114  | 332k  |             next = xmlXPathNextParent;  | 
12115  | 332k  |             break;  | 
12116  | 38.9k  |         case AXIS_PRECEDING:  | 
12117  | 38.9k  |             first = NULL;  | 
12118  | 38.9k  |             next = xmlXPathNextPrecedingInternal;  | 
12119  | 38.9k  |             break;  | 
12120  | 29.3k  |         case AXIS_PRECEDING_SIBLING:  | 
12121  | 29.3k  |             first = NULL;  | 
12122  | 29.3k  |             next = xmlXPathNextPrecedingSibling;  | 
12123  | 29.3k  |             break;  | 
12124  | 26.6k  |         case AXIS_SELF:  | 
12125  | 26.6k  |             first = NULL;  | 
12126  | 26.6k  |       last = NULL;  | 
12127  | 26.6k  |             next = xmlXPathNextSelf;  | 
12128  | 26.6k  |       mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;  | 
12129  | 26.6k  |             break;  | 
12130  | 25.6M  |     }  | 
12131  |  |  | 
12132  |  | #ifdef DEBUG_STEP  | 
12133  |  |     xmlXPathDebugDumpStepAxis(op,  | 
12134  |  |   (obj->nodesetval != NULL) ? obj->nodesetval->nodeNr : 0);  | 
12135  |  | #endif  | 
12136  |  |  | 
12137  | 25.6M  |     if (next == NULL) { | 
12138  | 0  |   xmlXPathReleaseObject(xpctxt, obj);  | 
12139  | 0  |         return(0);  | 
12140  | 0  |     }  | 
12141  | 25.6M  |     contextSeq = obj->nodesetval;  | 
12142  | 25.6M  |     if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) { | 
12143  | 5.52M  |   xmlXPathReleaseObject(xpctxt, obj);  | 
12144  | 5.52M  |         valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, NULL));  | 
12145  | 5.52M  |         return(0);  | 
12146  | 5.52M  |     }  | 
12147  |  |     /*  | 
12148  |  |     * Predicate optimization ---------------------------------------------  | 
12149  |  |     * If this step has a last predicate, which contains a position(),  | 
12150  |  |     * then we'll optimize (although not exactly "position()", but only  | 
12151  |  |     * the  short-hand form, i.e., "[n]".  | 
12152  |  |     *  | 
12153  |  |     * Example - expression "/foo[parent::bar][1]":  | 
12154  |  |     *  | 
12155  |  |     * COLLECT 'child' 'name' 'node' foo    -- op (we are here)  | 
12156  |  |     *   ROOT                               -- op->ch1  | 
12157  |  |     *   PREDICATE                          -- op->ch2 (predOp)  | 
12158  |  |     *     PREDICATE                          -- predOp->ch1 = [parent::bar]  | 
12159  |  |     *       SORT  | 
12160  |  |     *         COLLECT  'parent' 'name' 'node' bar  | 
12161  |  |     *           NODE  | 
12162  |  |     *     ELEM Object is a number : 1        -- predOp->ch2 = [1]  | 
12163  |  |     *  | 
12164  |  |     */  | 
12165  | 20.1M  |     maxPos = 0;  | 
12166  | 20.1M  |     predOp = NULL;  | 
12167  | 20.1M  |     hasPredicateRange = 0;  | 
12168  | 20.1M  |     hasAxisRange = 0;  | 
12169  | 20.1M  |     if (op->ch2 != -1) { | 
12170  |  |   /*  | 
12171  |  |   * There's at least one predicate. 16 == XPATH_OP_PREDICATE  | 
12172  |  |   */  | 
12173  | 761k  |   predOp = &ctxt->comp->steps[op->ch2];  | 
12174  | 761k  |   if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) { | 
12175  | 258k  |       if (predOp->ch1 != -1) { | 
12176  |  |     /*  | 
12177  |  |     * Use the next inner predicate operator.  | 
12178  |  |     */  | 
12179  | 29.0k  |     predOp = &ctxt->comp->steps[predOp->ch1];  | 
12180  | 29.0k  |     hasPredicateRange = 1;  | 
12181  | 229k  |       } else { | 
12182  |  |     /*  | 
12183  |  |     * There's no other predicate than the [n] predicate.  | 
12184  |  |     */  | 
12185  | 229k  |     predOp = NULL;  | 
12186  | 229k  |     hasAxisRange = 1;  | 
12187  | 229k  |       }  | 
12188  | 258k  |   }  | 
12189  | 761k  |     }  | 
12190  | 20.1M  |     breakOnFirstHit = ((toBool) && (predOp == NULL)) ? 1 : 0;  | 
12191  |  |     /*  | 
12192  |  |     * Axis traversal -----------------------------------------------------  | 
12193  |  |     */  | 
12194  |  |     /*  | 
12195  |  |      * 2.3 Node Tests  | 
12196  |  |      *  - For the attribute axis, the principal node type is attribute.  | 
12197  |  |      *  - For the namespace axis, the principal node type is namespace.  | 
12198  |  |      *  - For other axes, the principal node type is element.  | 
12199  |  |      *  | 
12200  |  |      * A node test * is true for any node of the  | 
12201  |  |      * principal node type. For example, child::* will  | 
12202  |  |      * select all element children of the context node  | 
12203  |  |      */  | 
12204  | 20.1M  |     oldContextNode = xpctxt->node;  | 
12205  | 20.1M  |     addNode = xmlXPathNodeSetAddUnique;  | 
12206  | 20.1M  |     outSeq = NULL;  | 
12207  | 20.1M  |     seq = NULL;  | 
12208  | 20.1M  |     contextNode = NULL;  | 
12209  | 20.1M  |     contextIdx = 0;  | 
12210  |  |  | 
12211  |  |  | 
12212  | 81.6M  |     while (((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) &&  | 
12213  | 81.6M  |            (ctxt->error == XPATH_EXPRESSION_OK)) { | 
12214  | 61.7M  |   xpctxt->node = contextSeq->nodeTab[contextIdx++];  | 
12215  |  |  | 
12216  | 61.7M  |   if (seq == NULL) { | 
12217  | 21.4M  |       seq = xmlXPathNodeSetCreate(NULL);  | 
12218  | 21.4M  |       if (seq == NULL) { | 
12219  |  |                 /* TODO: Propagate memory error. */  | 
12220  | 0  |     total = 0;  | 
12221  | 0  |     goto error;  | 
12222  | 0  |       }  | 
12223  | 21.4M  |   }  | 
12224  |  |   /*  | 
12225  |  |   * Traverse the axis and test the nodes.  | 
12226  |  |   */  | 
12227  | 61.7M  |   pos = 0;  | 
12228  | 61.7M  |   cur = NULL;  | 
12229  | 61.7M  |   hasNsNodes = 0;  | 
12230  | 313M  |         do { | 
12231  | 313M  |             if (OP_LIMIT_EXCEEDED(ctxt, 1))  | 
12232  | 163  |                 goto error;  | 
12233  |  |  | 
12234  | 313M  |             cur = next(ctxt, cur);  | 
12235  | 313M  |             if (cur == NULL)  | 
12236  | 60.9M  |                 break;  | 
12237  |  |  | 
12238  |  |       /*  | 
12239  |  |       * QUESTION TODO: What does the "first" and "last" stuff do?  | 
12240  |  |       */  | 
12241  | 252M  |             if ((first != NULL) && (*first != NULL)) { | 
12242  | 369k  |     if (*first == cur)  | 
12243  | 29.0k  |         break;  | 
12244  | 340k  |     if (((total % 256) == 0) &&  | 
12245  | 340k  | #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON  | 
12246  | 340k  |         (xmlXPathCmpNodesExt(*first, cur) >= 0))  | 
12247  |  | #else  | 
12248  |  |         (xmlXPathCmpNodes(*first, cur) >= 0))  | 
12249  |  | #endif  | 
12250  | 72.6k  |     { | 
12251  | 72.6k  |         break;  | 
12252  | 72.6k  |     }  | 
12253  | 340k  |       }  | 
12254  | 252M  |       if ((last != NULL) && (*last != NULL)) { | 
12255  | 114k  |     if (*last == cur)  | 
12256  | 9.79k  |         break;  | 
12257  | 104k  |     if (((total % 256) == 0) &&  | 
12258  | 104k  | #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON  | 
12259  | 104k  |         (xmlXPathCmpNodesExt(cur, *last) >= 0))  | 
12260  |  | #else  | 
12261  |  |         (xmlXPathCmpNodes(cur, *last) >= 0))  | 
12262  |  | #endif  | 
12263  | 15.8k  |     { | 
12264  | 15.8k  |         break;  | 
12265  | 15.8k  |     }  | 
12266  | 104k  |       }  | 
12267  |  |  | 
12268  | 252M  |             total++;  | 
12269  |  |  | 
12270  |  | #ifdef DEBUG_STEP  | 
12271  |  |             xmlGenericError(xmlGenericErrorContext, " %s", cur->name);  | 
12272  |  | #endif  | 
12273  |  |  | 
12274  | 252M  |       switch (test) { | 
12275  | 0  |                 case NODE_TEST_NONE:  | 
12276  | 0  |         total = 0;  | 
12277  | 0  |                     STRANGE  | 
12278  | 0  |         goto error;  | 
12279  | 64.3M  |                 case NODE_TEST_TYPE:  | 
12280  | 64.3M  |         if (type == NODE_TYPE_NODE) { | 
12281  | 60.9M  |       switch (cur->type) { | 
12282  | 1.31M  |           case XML_DOCUMENT_NODE:  | 
12283  | 1.31M  |           case XML_HTML_DOCUMENT_NODE:  | 
12284  | 22.5M  |           case XML_ELEMENT_NODE:  | 
12285  | 22.6M  |           case XML_ATTRIBUTE_NODE:  | 
12286  | 25.0M  |           case XML_PI_NODE:  | 
12287  | 27.6M  |           case XML_COMMENT_NODE:  | 
12288  | 29.1M  |           case XML_CDATA_SECTION_NODE:  | 
12289  | 60.8M  |           case XML_TEXT_NODE:  | 
12290  | 60.8M  |         XP_TEST_HIT  | 
12291  | 60.7M  |         break;  | 
12292  | 60.7M  |           case XML_NAMESPACE_DECL: { | 
12293  | 139k  |         if (axis == AXIS_NAMESPACE) { | 
12294  | 86.6k  |             XP_TEST_HIT_NS  | 
12295  | 86.6k  |         } else { | 
12296  | 52.5k  |                               hasNsNodes = 1;  | 
12297  | 52.5k  |             XP_TEST_HIT  | 
12298  | 52.5k  |         }  | 
12299  | 123k  |         break;  | 
12300  | 139k  |                             }  | 
12301  | 123k  |           default:  | 
12302  | 0  |         break;  | 
12303  | 60.9M  |       }  | 
12304  | 60.9M  |         } else if (cur->type == (xmlElementType) type) { | 
12305  | 1.50M  |       if (cur->type == XML_NAMESPACE_DECL)  | 
12306  | 0  |           XP_TEST_HIT_NS  | 
12307  | 1.50M  |       else  | 
12308  | 1.50M  |           XP_TEST_HIT  | 
12309  | 1.85M  |         } else if ((type == NODE_TYPE_TEXT) &&  | 
12310  | 1.85M  |        (cur->type == XML_CDATA_SECTION_NODE))  | 
12311  | 64.4k  |         { | 
12312  | 64.4k  |       XP_TEST_HIT  | 
12313  | 64.4k  |         }  | 
12314  | 64.0M  |         break;  | 
12315  | 64.0M  |                 case NODE_TEST_PI:  | 
12316  | 26.8k  |                     if ((cur->type == XML_PI_NODE) &&  | 
12317  | 26.8k  |                         ((name == NULL) || xmlStrEqual(name, cur->name)))  | 
12318  | 0  |         { | 
12319  | 0  |       XP_TEST_HIT  | 
12320  | 0  |                     }  | 
12321  | 26.8k  |                     break;  | 
12322  | 57.6M  |                 case NODE_TEST_ALL:  | 
12323  | 57.6M  |                     if (axis == AXIS_ATTRIBUTE) { | 
12324  | 2.83M  |                         if (cur->type == XML_ATTRIBUTE_NODE)  | 
12325  | 2.83M  |       { | 
12326  | 2.83M  |                             if (prefix == NULL)  | 
12327  | 2.81M  |           { | 
12328  | 2.81M  |         XP_TEST_HIT  | 
12329  | 2.81M  |                             } else if ((cur->ns != NULL) &&  | 
12330  | 16.0k  |         (xmlStrEqual(URI, cur->ns->href)))  | 
12331  | 0  |           { | 
12332  | 0  |         XP_TEST_HIT  | 
12333  | 0  |                             }  | 
12334  | 2.83M  |                         }  | 
12335  | 54.7M  |                     } else if (axis == AXIS_NAMESPACE) { | 
12336  | 665k  |                         if (cur->type == XML_NAMESPACE_DECL)  | 
12337  | 665k  |       { | 
12338  | 665k  |           XP_TEST_HIT_NS  | 
12339  | 665k  |                         }  | 
12340  | 54.1M  |                     } else { | 
12341  | 54.1M  |                         if (cur->type == XML_ELEMENT_NODE) { | 
12342  | 22.5M  |                             if (prefix == NULL)  | 
12343  | 22.2M  |           { | 
12344  | 22.2M  |         XP_TEST_HIT  | 
12345  |  |  | 
12346  | 22.2M  |                             } else if ((cur->ns != NULL) &&  | 
12347  | 331k  |         (xmlStrEqual(URI, cur->ns->href)))  | 
12348  | 88.8k  |           { | 
12349  | 88.8k  |         XP_TEST_HIT  | 
12350  | 88.8k  |                             }  | 
12351  | 22.5M  |                         }  | 
12352  | 54.1M  |                     }  | 
12353  | 57.2M  |                     break;  | 
12354  | 57.2M  |                 case NODE_TEST_NS:{ | 
12355  | 0  |                         TODO;  | 
12356  | 0  |                         break;  | 
12357  | 57.6M  |                     }  | 
12358  | 130M  |                 case NODE_TEST_NAME:  | 
12359  | 130M  |                     if (axis == AXIS_ATTRIBUTE) { | 
12360  | 896k  |                         if (cur->type != XML_ATTRIBUTE_NODE)  | 
12361  | 0  |           break;  | 
12362  | 129M  |         } else if (axis == AXIS_NAMESPACE) { | 
12363  | 1.00M  |                         if (cur->type != XML_NAMESPACE_DECL)  | 
12364  | 0  |           break;  | 
12365  | 128M  |         } else { | 
12366  | 128M  |             if (cur->type != XML_ELEMENT_NODE)  | 
12367  | 82.9M  |           break;  | 
12368  | 128M  |         }  | 
12369  | 47.3M  |                     switch (cur->type) { | 
12370  | 45.4M  |                         case XML_ELEMENT_NODE:  | 
12371  | 45.4M  |                             if (xmlStrEqual(name, cur->name)) { | 
12372  | 3.74M  |                                 if (prefix == NULL) { | 
12373  | 3.52M  |                                     if (cur->ns == NULL)  | 
12374  | 1.97M  |             { | 
12375  | 1.97M  |           XP_TEST_HIT  | 
12376  | 1.97M  |                                     }  | 
12377  | 3.52M  |                                 } else { | 
12378  | 218k  |                                     if ((cur->ns != NULL) &&  | 
12379  | 218k  |                                         (xmlStrEqual(URI, cur->ns->href)))  | 
12380  | 96.3k  |             { | 
12381  | 96.3k  |           XP_TEST_HIT  | 
12382  | 96.3k  |                                     }  | 
12383  | 218k  |                                 }  | 
12384  | 3.74M  |                             }  | 
12385  | 45.3M  |                             break;  | 
12386  | 45.3M  |                         case XML_ATTRIBUTE_NODE:{ | 
12387  | 896k  |                                 xmlAttrPtr attr = (xmlAttrPtr) cur;  | 
12388  |  |  | 
12389  | 896k  |                                 if (xmlStrEqual(name, attr->name)) { | 
12390  | 330k  |                                     if (prefix == NULL) { | 
12391  | 311k  |                                         if ((attr->ns == NULL) ||  | 
12392  | 311k  |                                             (attr->ns->prefix == NULL))  | 
12393  | 311k  |           { | 
12394  | 311k  |               XP_TEST_HIT  | 
12395  | 311k  |                                         }  | 
12396  | 311k  |                                     } else { | 
12397  | 18.8k  |                                         if ((attr->ns != NULL) &&  | 
12398  | 18.8k  |                                             (xmlStrEqual(URI,  | 
12399  | 0  |                 attr->ns->href)))  | 
12400  | 0  |           { | 
12401  | 0  |               XP_TEST_HIT  | 
12402  | 0  |                                         }  | 
12403  | 18.8k  |                                     }  | 
12404  | 330k  |                                 }  | 
12405  | 875k  |                                 break;  | 
12406  | 896k  |                             }  | 
12407  | 1.00M  |                         case XML_NAMESPACE_DECL:  | 
12408  | 1.00M  |                             if (cur->type == XML_NAMESPACE_DECL) { | 
12409  | 1.00M  |                                 xmlNsPtr ns = (xmlNsPtr) cur;  | 
12410  |  |  | 
12411  | 1.00M  |                                 if ((ns->prefix != NULL) && (name != NULL)  | 
12412  | 1.00M  |                                     && (xmlStrEqual(ns->prefix, name)))  | 
12413  | 152k  |         { | 
12414  | 152k  |             XP_TEST_HIT_NS  | 
12415  | 152k  |                                 }  | 
12416  | 1.00M  |                             }  | 
12417  | 998k  |                             break;  | 
12418  | 998k  |                         default:  | 
12419  | 0  |                             break;  | 
12420  | 47.3M  |                     }  | 
12421  | 47.1M  |                     break;  | 
12422  | 252M  |       } /* switch(test) */  | 
12423  | 252M  |         } while ((cur != NULL) && (ctxt->error == XPATH_EXPRESSION_OK));  | 
12424  |  |  | 
12425  | 61.0M  |   goto apply_predicates;  | 
12426  |  |  | 
12427  | 61.0M  | axis_range_end: /* ----------------------------------------------------- */  | 
12428  |  |   /*  | 
12429  |  |   * We have a "/foo[n]", and position() = n was reached.  | 
12430  |  |   * Note that we can have as well "/foo/::parent::foo[1]", so  | 
12431  |  |   * a duplicate-aware merge is still needed.  | 
12432  |  |   * Merge with the result.  | 
12433  |  |   */  | 
12434  | 469k  |   if (outSeq == NULL) { | 
12435  | 124k  |       outSeq = seq;  | 
12436  | 124k  |       seq = NULL;  | 
12437  | 124k  |   } else  | 
12438  |  |             /* TODO: Check memory error. */  | 
12439  | 344k  |       outSeq = mergeAndClear(outSeq, seq);  | 
12440  |  |   /*  | 
12441  |  |   * Break if only a true/false result was requested.  | 
12442  |  |   */  | 
12443  | 469k  |   if (toBool)  | 
12444  | 8.11k  |       break;  | 
12445  | 461k  |   continue;  | 
12446  |  |  | 
12447  | 461k  | first_hit: /* ---------------------------------------------------------- */  | 
12448  |  |   /*  | 
12449  |  |   * Break if only a true/false result was requested and  | 
12450  |  |   * no predicates existed and a node test succeeded.  | 
12451  |  |   */  | 
12452  | 255k  |   if (outSeq == NULL) { | 
12453  | 255k  |       outSeq = seq;  | 
12454  | 255k  |       seq = NULL;  | 
12455  | 255k  |   } else  | 
12456  |  |             /* TODO: Check memory error. */  | 
12457  | 0  |       outSeq = mergeAndClear(outSeq, seq);  | 
12458  | 255k  |   break;  | 
12459  |  |  | 
12460  |  | #ifdef DEBUG_STEP  | 
12461  |  |   if (seq != NULL)  | 
12462  |  |       nbMatches += seq->nodeNr;  | 
12463  |  | #endif  | 
12464  |  |  | 
12465  | 61.0M  | apply_predicates: /* --------------------------------------------------- */  | 
12466  | 61.0M  |         if (ctxt->error != XPATH_EXPRESSION_OK)  | 
12467  | 0  |       goto error;  | 
12468  |  |  | 
12469  |  |         /*  | 
12470  |  |   * Apply predicates.  | 
12471  |  |   */  | 
12472  | 61.0M  |         if ((predOp != NULL) && (seq->nodeNr > 0)) { | 
12473  |  |       /*  | 
12474  |  |       * E.g. when we have a "/foo[some expression][n]".  | 
12475  |  |       */  | 
12476  |  |       /*  | 
12477  |  |       * QUESTION TODO: The old predicate evaluation took into  | 
12478  |  |       *  account location-sets.  | 
12479  |  |       *  (E.g. ctxt->value->type == XPATH_LOCATIONSET)  | 
12480  |  |       *  Do we expect such a set here?  | 
12481  |  |       *  All what I learned now from the evaluation semantics  | 
12482  |  |       *  does not indicate that a location-set will be processed  | 
12483  |  |       *  here, so this looks OK.  | 
12484  |  |       */  | 
12485  |  |       /*  | 
12486  |  |       * Iterate over all predicates, starting with the outermost  | 
12487  |  |       * predicate.  | 
12488  |  |       * TODO: Problem: we cannot execute the inner predicates first  | 
12489  |  |       *  since we cannot go back *up* the operator tree!  | 
12490  |  |       *  Options we have:  | 
12491  |  |       *  1) Use of recursive functions (like is it currently done  | 
12492  |  |       *     via xmlXPathCompOpEval())  | 
12493  |  |       *  2) Add a predicate evaluation information stack to the  | 
12494  |  |       *     context struct  | 
12495  |  |       *  3) Change the way the operators are linked; we need a  | 
12496  |  |       *     "parent" field on xmlXPathStepOp  | 
12497  |  |       *  | 
12498  |  |       * For the moment, I'll try to solve this with a recursive  | 
12499  |  |       * function: xmlXPathCompOpEvalPredicate().  | 
12500  |  |       */  | 
12501  | 1.72M  |       if (hasPredicateRange != 0)  | 
12502  | 112k  |     xmlXPathCompOpEvalPredicate(ctxt, predOp, seq, maxPos, maxPos,  | 
12503  | 112k  |               hasNsNodes);  | 
12504  | 1.61M  |       else  | 
12505  | 1.61M  |     xmlXPathCompOpEvalPredicate(ctxt, predOp, seq, 1, seq->nodeNr,  | 
12506  | 1.61M  |               hasNsNodes);  | 
12507  |  |  | 
12508  | 1.72M  |       if (ctxt->error != XPATH_EXPRESSION_OK) { | 
12509  | 6.15k  |     total = 0;  | 
12510  | 6.15k  |     goto error;  | 
12511  | 6.15k  |       }  | 
12512  | 1.72M  |         }  | 
12513  |  |  | 
12514  | 61.0M  |         if (seq->nodeNr > 0) { | 
12515  |  |       /*  | 
12516  |  |       * Add to result set.  | 
12517  |  |       */  | 
12518  | 15.4M  |       if (outSeq == NULL) { | 
12519  | 6.85M  |     outSeq = seq;  | 
12520  | 6.85M  |     seq = NULL;  | 
12521  | 8.58M  |       } else { | 
12522  |  |                 /* TODO: Check memory error. */  | 
12523  | 8.58M  |     outSeq = mergeAndClear(outSeq, seq);  | 
12524  | 8.58M  |       }  | 
12525  |  |  | 
12526  | 15.4M  |             if (toBool)  | 
12527  | 13.0k  |                 break;  | 
12528  | 15.4M  |   }  | 
12529  | 61.0M  |     }  | 
12530  |  |  | 
12531  | 20.1M  | error:  | 
12532  | 20.1M  |     if ((obj->boolval) && (obj->user != NULL)) { | 
12533  |  |   /*  | 
12534  |  |   * QUESTION TODO: What does this do and why?  | 
12535  |  |   * TODO: Do we have to do this also for the "error"  | 
12536  |  |   * cleanup further down?  | 
12537  |  |   */  | 
12538  | 0  |   ctxt->value->boolval = 1;  | 
12539  | 0  |   ctxt->value->user = obj->user;  | 
12540  | 0  |   obj->user = NULL;  | 
12541  | 0  |   obj->boolval = 0;  | 
12542  | 0  |     }  | 
12543  | 20.1M  |     xmlXPathReleaseObject(xpctxt, obj);  | 
12544  |  |  | 
12545  |  |     /*  | 
12546  |  |     * Ensure we return at least an empty set.  | 
12547  |  |     */  | 
12548  | 20.1M  |     if (outSeq == NULL) { | 
12549  | 12.9M  |   if ((seq != NULL) && (seq->nodeNr == 0))  | 
12550  | 12.9M  |       outSeq = seq;  | 
12551  | 117  |   else  | 
12552  |  |             /* TODO: Check memory error. */  | 
12553  | 117  |       outSeq = xmlXPathNodeSetCreate(NULL);  | 
12554  | 12.9M  |     }  | 
12555  | 20.1M  |     if ((seq != NULL) && (seq != outSeq)) { | 
12556  | 1.30M  |    xmlXPathFreeNodeSet(seq);  | 
12557  | 1.30M  |     }  | 
12558  |  |     /*  | 
12559  |  |     * Hand over the result. Better to push the set also in  | 
12560  |  |     * case of errors.  | 
12561  |  |     */  | 
12562  | 20.1M  |     valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, outSeq));  | 
12563  |  |     /*  | 
12564  |  |     * Reset the context node.  | 
12565  |  |     */  | 
12566  | 20.1M  |     xpctxt->node = oldContextNode;  | 
12567  |  |     /*  | 
12568  |  |     * When traversing the namespace axis in "toBool" mode, it's  | 
12569  |  |     * possible that tmpNsList wasn't freed.  | 
12570  |  |     */  | 
12571  | 20.1M  |     if (xpctxt->tmpNsList != NULL) { | 
12572  | 11.3k  |         xmlFree(xpctxt->tmpNsList);  | 
12573  | 11.3k  |         xpctxt->tmpNsList = NULL;  | 
12574  | 11.3k  |     }  | 
12575  |  |  | 
12576  |  | #ifdef DEBUG_STEP  | 
12577  |  |     xmlGenericError(xmlGenericErrorContext,  | 
12578  |  |   "\nExamined %d nodes, found %d nodes at that step\n",  | 
12579  |  |   total, nbMatches);  | 
12580  |  | #endif  | 
12581  |  |  | 
12582  | 20.1M  |     return(total);  | 
12583  | 20.1M  | }  | 
12584  |  |  | 
12585  |  | static int  | 
12586  |  | xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,  | 
12587  |  |             xmlXPathStepOpPtr op, xmlNodePtr * first);  | 
12588  |  |  | 
12589  |  | /**  | 
12590  |  |  * xmlXPathCompOpEvalFirst:  | 
12591  |  |  * @ctxt:  the XPath parser context with the compiled expression  | 
12592  |  |  * @op:  an XPath compiled operation  | 
12593  |  |  * @first:  the first elem found so far  | 
12594  |  |  *  | 
12595  |  |  * Evaluate the Precompiled XPath operation searching only the first  | 
12596  |  |  * element in document order  | 
12597  |  |  *  | 
12598  |  |  * Returns the number of examined objects.  | 
12599  |  |  */  | 
12600  |  | static int  | 
12601  |  | xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,  | 
12602  |  |                         xmlXPathStepOpPtr op, xmlNodePtr * first)  | 
12603  | 584k  | { | 
12604  | 584k  |     int total = 0, cur;  | 
12605  | 584k  |     xmlXPathCompExprPtr comp;  | 
12606  | 584k  |     xmlXPathObjectPtr arg1, arg2;  | 
12607  |  |  | 
12608  | 584k  |     CHECK_ERROR0;  | 
12609  | 584k  |     if (OP_LIMIT_EXCEEDED(ctxt, 1))  | 
12610  | 1  |         return(0);  | 
12611  | 584k  |     if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)  | 
12612  | 584k  |         XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);  | 
12613  | 584k  |     ctxt->context->depth += 1;  | 
12614  | 584k  |     comp = ctxt->comp;  | 
12615  | 584k  |     switch (op->op) { | 
12616  | 0  |         case XPATH_OP_END:  | 
12617  | 0  |             break;  | 
12618  | 183k  |         case XPATH_OP_UNION:  | 
12619  | 183k  |             total =  | 
12620  | 183k  |                 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],  | 
12621  | 183k  |                                         first);  | 
12622  | 183k  |       CHECK_ERROR0;  | 
12623  | 175k  |             if ((ctxt->value != NULL)  | 
12624  | 175k  |                 && (ctxt->value->type == XPATH_NODESET)  | 
12625  | 175k  |                 && (ctxt->value->nodesetval != NULL)  | 
12626  | 175k  |                 && (ctxt->value->nodesetval->nodeNr >= 1)) { | 
12627  |  |                 /*  | 
12628  |  |                  * limit tree traversing to first node in the result  | 
12629  |  |                  */  | 
12630  |  |     /*  | 
12631  |  |     * OPTIMIZE TODO: This implicitly sorts  | 
12632  |  |     *  the result, even if not needed. E.g. if the argument  | 
12633  |  |     *  of the count() function, no sorting is needed.  | 
12634  |  |     * OPTIMIZE TODO: How do we know if the node-list wasn't  | 
12635  |  |     *  already sorted?  | 
12636  |  |     */  | 
12637  | 68.9k  |     if (ctxt->value->nodesetval->nodeNr > 1)  | 
12638  | 32.1k  |         xmlXPathNodeSetSort(ctxt->value->nodesetval);  | 
12639  | 68.9k  |                 *first = ctxt->value->nodesetval->nodeTab[0];  | 
12640  | 68.9k  |             }  | 
12641  | 175k  |             cur =  | 
12642  | 175k  |                 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],  | 
12643  | 175k  |                                         first);  | 
12644  | 175k  |       CHECK_ERROR0;  | 
12645  |  |  | 
12646  | 175k  |             arg2 = valuePop(ctxt);  | 
12647  | 175k  |             arg1 = valuePop(ctxt);  | 
12648  | 175k  |             if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||  | 
12649  | 175k  |                 (arg2 == NULL) || (arg2->type != XPATH_NODESET)) { | 
12650  | 157  |           xmlXPathReleaseObject(ctxt->context, arg1);  | 
12651  | 157  |           xmlXPathReleaseObject(ctxt->context, arg2);  | 
12652  | 157  |                 XP_ERROR0(XPATH_INVALID_TYPE);  | 
12653  | 0  |             }  | 
12654  | 174k  |             if ((ctxt->context->opLimit != 0) &&  | 
12655  | 174k  |                 (((arg1->nodesetval != NULL) &&  | 
12656  | 174k  |                   (xmlXPathCheckOpLimit(ctxt,  | 
12657  | 134k  |                                         arg1->nodesetval->nodeNr) < 0)) ||  | 
12658  | 174k  |                  ((arg2->nodesetval != NULL) &&  | 
12659  | 174k  |                   (xmlXPathCheckOpLimit(ctxt,  | 
12660  | 146k  |                                         arg2->nodesetval->nodeNr) < 0)))) { | 
12661  | 0  |           xmlXPathReleaseObject(ctxt->context, arg1);  | 
12662  | 0  |           xmlXPathReleaseObject(ctxt->context, arg2);  | 
12663  | 0  |                 break;  | 
12664  | 0  |             }  | 
12665  |  |  | 
12666  |  |             /* TODO: Check memory error. */  | 
12667  | 174k  |             arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,  | 
12668  | 174k  |                                                     arg2->nodesetval);  | 
12669  | 174k  |             valuePush(ctxt, arg1);  | 
12670  | 174k  |       xmlXPathReleaseObject(ctxt->context, arg2);  | 
12671  |  |             /* optimizer */  | 
12672  | 174k  |       if (total > cur)  | 
12673  | 40.9k  |     xmlXPathCompSwap(op);  | 
12674  | 174k  |             total += cur;  | 
12675  | 174k  |             break;  | 
12676  | 7.10k  |         case XPATH_OP_ROOT:  | 
12677  | 7.10k  |             xmlXPathRoot(ctxt);  | 
12678  | 7.10k  |             break;  | 
12679  | 6.62k  |         case XPATH_OP_NODE:  | 
12680  | 6.62k  |             if (op->ch1 != -1)  | 
12681  | 0  |                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);  | 
12682  | 6.62k  |       CHECK_ERROR0;  | 
12683  | 6.62k  |             if (op->ch2 != -1)  | 
12684  | 0  |                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);  | 
12685  | 6.62k  |       CHECK_ERROR0;  | 
12686  | 6.62k  |       valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,  | 
12687  | 6.62k  |     ctxt->context->node));  | 
12688  | 6.62k  |             break;  | 
12689  | 242k  |         case XPATH_OP_COLLECT:{ | 
12690  | 242k  |                 if (op->ch1 == -1)  | 
12691  | 0  |                     break;  | 
12692  |  |  | 
12693  | 242k  |                 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);  | 
12694  | 242k  |     CHECK_ERROR0;  | 
12695  |  |  | 
12696  | 242k  |                 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0);  | 
12697  | 242k  |                 break;  | 
12698  | 242k  |             }  | 
12699  | 185  |         case XPATH_OP_VALUE:  | 
12700  | 185  |             valuePush(ctxt,  | 
12701  | 185  |                       xmlXPathCacheObjectCopy(ctxt->context,  | 
12702  | 185  |       (xmlXPathObjectPtr) op->value4));  | 
12703  | 185  |             break;  | 
12704  | 87.1k  |         case XPATH_OP_SORT:  | 
12705  | 87.1k  |             if (op->ch1 != -1)  | 
12706  | 87.1k  |                 total +=  | 
12707  | 87.1k  |                     xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],  | 
12708  | 87.1k  |                                             first);  | 
12709  | 87.1k  |       CHECK_ERROR0;  | 
12710  | 85.6k  |             if ((ctxt->value != NULL)  | 
12711  | 85.6k  |                 && (ctxt->value->type == XPATH_NODESET)  | 
12712  | 85.6k  |                 && (ctxt->value->nodesetval != NULL)  | 
12713  | 85.6k  |     && (ctxt->value->nodesetval->nodeNr > 1))  | 
12714  | 22.8k  |                 xmlXPathNodeSetSort(ctxt->value->nodesetval);  | 
12715  | 85.6k  |             break;  | 
12716  | 0  | #ifdef XP_OPTIMIZED_FILTER_FIRST  | 
12717  | 51.4k  |   case XPATH_OP_FILTER:  | 
12718  | 51.4k  |                 total += xmlXPathCompOpEvalFilterFirst(ctxt, op, first);  | 
12719  | 51.4k  |             break;  | 
12720  | 0  | #endif  | 
12721  | 5.64k  |         default:  | 
12722  | 5.64k  |             total += xmlXPathCompOpEval(ctxt, op);  | 
12723  | 5.64k  |             break;  | 
12724  | 584k  |     }  | 
12725  |  |  | 
12726  | 574k  |     ctxt->context->depth -= 1;  | 
12727  | 574k  |     return(total);  | 
12728  | 584k  | }  | 
12729  |  |  | 
12730  |  | /**  | 
12731  |  |  * xmlXPathCompOpEvalLast:  | 
12732  |  |  * @ctxt:  the XPath parser context with the compiled expression  | 
12733  |  |  * @op:  an XPath compiled operation  | 
12734  |  |  * @last:  the last elem found so far  | 
12735  |  |  *  | 
12736  |  |  * Evaluate the Precompiled XPath operation searching only the last  | 
12737  |  |  * element in document order  | 
12738  |  |  *  | 
12739  |  |  * Returns the number of nodes traversed  | 
12740  |  |  */  | 
12741  |  | static int  | 
12742  |  | xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,  | 
12743  |  |                        xmlNodePtr * last)  | 
12744  | 348k  | { | 
12745  | 348k  |     int total = 0, cur;  | 
12746  | 348k  |     xmlXPathCompExprPtr comp;  | 
12747  | 348k  |     xmlXPathObjectPtr arg1, arg2;  | 
12748  |  |  | 
12749  | 348k  |     CHECK_ERROR0;  | 
12750  | 348k  |     if (OP_LIMIT_EXCEEDED(ctxt, 1))  | 
12751  | 0  |         return(0);  | 
12752  | 348k  |     if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)  | 
12753  | 348k  |         XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);  | 
12754  | 348k  |     ctxt->context->depth += 1;  | 
12755  | 348k  |     comp = ctxt->comp;  | 
12756  | 348k  |     switch (op->op) { | 
12757  | 0  |         case XPATH_OP_END:  | 
12758  | 0  |             break;  | 
12759  | 125k  |         case XPATH_OP_UNION:  | 
12760  | 125k  |             total =  | 
12761  | 125k  |                 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);  | 
12762  | 125k  |       CHECK_ERROR0;  | 
12763  | 120k  |             if ((ctxt->value != NULL)  | 
12764  | 120k  |                 && (ctxt->value->type == XPATH_NODESET)  | 
12765  | 120k  |                 && (ctxt->value->nodesetval != NULL)  | 
12766  | 120k  |                 && (ctxt->value->nodesetval->nodeNr >= 1)) { | 
12767  |  |                 /*  | 
12768  |  |                  * limit tree traversing to first node in the result  | 
12769  |  |                  */  | 
12770  | 46.4k  |     if (ctxt->value->nodesetval->nodeNr > 1)  | 
12771  | 24.3k  |         xmlXPathNodeSetSort(ctxt->value->nodesetval);  | 
12772  | 46.4k  |                 *last =  | 
12773  | 46.4k  |                     ctxt->value->nodesetval->nodeTab[ctxt->value->  | 
12774  | 46.4k  |                                                      nodesetval->nodeNr -  | 
12775  | 46.4k  |                                                      1];  | 
12776  | 46.4k  |             }  | 
12777  | 120k  |             cur =  | 
12778  | 120k  |                 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);  | 
12779  | 120k  |       CHECK_ERROR0;  | 
12780  | 120k  |             if ((ctxt->value != NULL)  | 
12781  | 120k  |                 && (ctxt->value->type == XPATH_NODESET)  | 
12782  | 120k  |                 && (ctxt->value->nodesetval != NULL)  | 
12783  | 120k  |                 && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */ | 
12784  | 58.7k  |             }  | 
12785  |  |  | 
12786  | 120k  |             arg2 = valuePop(ctxt);  | 
12787  | 120k  |             arg1 = valuePop(ctxt);  | 
12788  | 120k  |             if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||  | 
12789  | 120k  |                 (arg2 == NULL) || (arg2->type != XPATH_NODESET)) { | 
12790  | 125  |           xmlXPathReleaseObject(ctxt->context, arg1);  | 
12791  | 125  |           xmlXPathReleaseObject(ctxt->context, arg2);  | 
12792  | 125  |                 XP_ERROR0(XPATH_INVALID_TYPE);  | 
12793  | 0  |             }  | 
12794  | 120k  |             if ((ctxt->context->opLimit != 0) &&  | 
12795  | 120k  |                 (((arg1->nodesetval != NULL) &&  | 
12796  | 120k  |                   (xmlXPathCheckOpLimit(ctxt,  | 
12797  | 91.3k  |                                         arg1->nodesetval->nodeNr) < 0)) ||  | 
12798  | 120k  |                  ((arg2->nodesetval != NULL) &&  | 
12799  | 120k  |                   (xmlXPathCheckOpLimit(ctxt,  | 
12800  | 101k  |                                         arg2->nodesetval->nodeNr) < 0)))) { | 
12801  | 0  |           xmlXPathReleaseObject(ctxt->context, arg1);  | 
12802  | 0  |           xmlXPathReleaseObject(ctxt->context, arg2);  | 
12803  | 0  |                 break;  | 
12804  | 0  |             }  | 
12805  |  |  | 
12806  |  |             /* TODO: Check memory error. */  | 
12807  | 120k  |             arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,  | 
12808  | 120k  |                                                     arg2->nodesetval);  | 
12809  | 120k  |             valuePush(ctxt, arg1);  | 
12810  | 120k  |       xmlXPathReleaseObject(ctxt->context, arg2);  | 
12811  |  |             /* optimizer */  | 
12812  | 120k  |       if (total > cur)  | 
12813  | 27.9k  |     xmlXPathCompSwap(op);  | 
12814  | 120k  |             total += cur;  | 
12815  | 120k  |             break;  | 
12816  | 7.33k  |         case XPATH_OP_ROOT:  | 
12817  | 7.33k  |             xmlXPathRoot(ctxt);  | 
12818  | 7.33k  |             break;  | 
12819  | 8.11k  |         case XPATH_OP_NODE:  | 
12820  | 8.11k  |             if (op->ch1 != -1)  | 
12821  | 0  |                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);  | 
12822  | 8.11k  |       CHECK_ERROR0;  | 
12823  | 8.11k  |             if (op->ch2 != -1)  | 
12824  | 0  |                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);  | 
12825  | 8.11k  |       CHECK_ERROR0;  | 
12826  | 8.11k  |       valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,  | 
12827  | 8.11k  |     ctxt->context->node));  | 
12828  | 8.11k  |             break;  | 
12829  | 148k  |         case XPATH_OP_COLLECT:{ | 
12830  | 148k  |                 if (op->ch1 == -1)  | 
12831  | 0  |                     break;  | 
12832  |  |  | 
12833  | 148k  |                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);  | 
12834  | 148k  |     CHECK_ERROR0;  | 
12835  |  |  | 
12836  | 147k  |                 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0);  | 
12837  | 147k  |                 break;  | 
12838  | 148k  |             }  | 
12839  | 159  |         case XPATH_OP_VALUE:  | 
12840  | 159  |             valuePush(ctxt,  | 
12841  | 159  |                       xmlXPathCacheObjectCopy(ctxt->context,  | 
12842  | 159  |       (xmlXPathObjectPtr) op->value4));  | 
12843  | 159  |             break;  | 
12844  | 51.4k  |         case XPATH_OP_SORT:  | 
12845  | 51.4k  |             if (op->ch1 != -1)  | 
12846  | 51.4k  |                 total +=  | 
12847  | 51.4k  |                     xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],  | 
12848  | 51.4k  |                                            last);  | 
12849  | 51.4k  |       CHECK_ERROR0;  | 
12850  | 50.5k  |             if ((ctxt->value != NULL)  | 
12851  | 50.5k  |                 && (ctxt->value->type == XPATH_NODESET)  | 
12852  | 50.5k  |                 && (ctxt->value->nodesetval != NULL)  | 
12853  | 50.5k  |     && (ctxt->value->nodesetval->nodeNr > 1))  | 
12854  | 7.99k  |                 xmlXPathNodeSetSort(ctxt->value->nodesetval);  | 
12855  | 50.5k  |             break;  | 
12856  | 8.21k  |         default:  | 
12857  | 8.21k  |             total += xmlXPathCompOpEval(ctxt, op);  | 
12858  | 8.21k  |             break;  | 
12859  | 348k  |     }  | 
12860  |  |  | 
12861  | 342k  |     ctxt->context->depth -= 1;  | 
12862  | 342k  |     return (total);  | 
12863  | 348k  | }  | 
12864  |  |  | 
12865  |  | #ifdef XP_OPTIMIZED_FILTER_FIRST  | 
12866  |  | static int  | 
12867  |  | xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,  | 
12868  |  |             xmlXPathStepOpPtr op, xmlNodePtr * first)  | 
12869  | 51.4k  | { | 
12870  | 51.4k  |     int total = 0;  | 
12871  | 51.4k  |     xmlXPathCompExprPtr comp;  | 
12872  | 51.4k  |     xmlNodeSetPtr set;  | 
12873  |  |  | 
12874  | 51.4k  |     CHECK_ERROR0;  | 
12875  | 51.4k  |     comp = ctxt->comp;  | 
12876  |  |     /*  | 
12877  |  |     * Optimization for ()[last()] selection i.e. the last elem  | 
12878  |  |     */  | 
12879  | 51.4k  |     if ((op->ch1 != -1) && (op->ch2 != -1) &&  | 
12880  | 51.4k  |   (comp->steps[op->ch1].op == XPATH_OP_SORT) &&  | 
12881  | 51.4k  |   (comp->steps[op->ch2].op == XPATH_OP_SORT)) { | 
12882  | 31.4k  |   int f = comp->steps[op->ch2].ch1;  | 
12883  |  |  | 
12884  | 31.4k  |   if ((f != -1) &&  | 
12885  | 31.4k  |       (comp->steps[f].op == XPATH_OP_FUNCTION) &&  | 
12886  | 31.4k  |       (comp->steps[f].value5 == NULL) &&  | 
12887  | 31.4k  |       (comp->steps[f].value == 0) &&  | 
12888  | 31.4k  |       (comp->steps[f].value4 != NULL) &&  | 
12889  | 31.4k  |       (xmlStrEqual  | 
12890  | 20.6k  |       (comp->steps[f].value4, BAD_CAST "last"))) { | 
12891  | 15.4k  |       xmlNodePtr last = NULL;  | 
12892  |  |  | 
12893  | 15.4k  |       total +=  | 
12894  | 15.4k  |     xmlXPathCompOpEvalLast(ctxt,  | 
12895  | 15.4k  |         &comp->steps[op->ch1],  | 
12896  | 15.4k  |         &last);  | 
12897  | 15.4k  |       CHECK_ERROR0;  | 
12898  |  |       /*  | 
12899  |  |       * The nodeset should be in document order,  | 
12900  |  |       * Keep only the last value  | 
12901  |  |       */  | 
12902  | 15.2k  |       if ((ctxt->value != NULL) &&  | 
12903  | 15.2k  |     (ctxt->value->type == XPATH_NODESET) &&  | 
12904  | 15.2k  |     (ctxt->value->nodesetval != NULL) &&  | 
12905  | 15.2k  |     (ctxt->value->nodesetval->nodeTab != NULL) &&  | 
12906  | 15.2k  |     (ctxt->value->nodesetval->nodeNr > 1)) { | 
12907  | 1.23k  |                 xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);  | 
12908  | 1.23k  |     *first = *(ctxt->value->nodesetval->nodeTab);  | 
12909  | 1.23k  |       }  | 
12910  | 15.2k  |       return (total);  | 
12911  | 15.4k  |   }  | 
12912  | 31.4k  |     }  | 
12913  |  |  | 
12914  | 36.0k  |     if (op->ch1 != -1)  | 
12915  | 36.0k  |   total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);  | 
12916  | 36.0k  |     CHECK_ERROR0;  | 
12917  | 35.5k  |     if (op->ch2 == -1)  | 
12918  | 0  |   return (total);  | 
12919  | 35.5k  |     if (ctxt->value == NULL)  | 
12920  | 0  |   return (total);  | 
12921  |  |  | 
12922  |  | #ifdef LIBXML_XPTR_LOCS_ENABLED  | 
12923  |  |     /*  | 
12924  |  |     * Hum are we filtering the result of an XPointer expression  | 
12925  |  |     */  | 
12926  |  |     if (ctxt->value->type == XPATH_LOCATIONSET) { | 
12927  |  |         xmlLocationSetPtr locset = ctxt->value->user;  | 
12928  |  |  | 
12929  |  |         if (locset != NULL) { | 
12930  |  |             xmlXPathLocationSetFilter(ctxt, locset, op->ch2, 1, 1);  | 
12931  |  |             if (locset->locNr > 0)  | 
12932  |  |                 *first = (xmlNodePtr) locset->locTab[0]->user;  | 
12933  |  |         }  | 
12934  |  |  | 
12935  |  |   return (total);  | 
12936  |  |     }  | 
12937  |  | #endif /* LIBXML_XPTR_LOCS_ENABLED */  | 
12938  |  |  | 
12939  | 35.5k  |     CHECK_TYPE0(XPATH_NODESET);  | 
12940  | 35.2k  |     set = ctxt->value->nodesetval;  | 
12941  | 35.2k  |     if (set != NULL) { | 
12942  | 27.8k  |         xmlXPathNodeSetFilter(ctxt, set, op->ch2, 1, 1, 1);  | 
12943  | 27.8k  |         if (set->nodeNr > 0)  | 
12944  | 6.86k  |             *first = set->nodeTab[0];  | 
12945  | 27.8k  |     }  | 
12946  |  |  | 
12947  | 35.2k  |     return (total);  | 
12948  | 35.5k  | }  | 
12949  |  | #endif /* XP_OPTIMIZED_FILTER_FIRST */  | 
12950  |  |  | 
12951  |  | /**  | 
12952  |  |  * xmlXPathCompOpEval:  | 
12953  |  |  * @ctxt:  the XPath parser context with the compiled expression  | 
12954  |  |  * @op:  an XPath compiled operation  | 
12955  |  |  *  | 
12956  |  |  * Evaluate the Precompiled XPath operation  | 
12957  |  |  * Returns the number of nodes traversed  | 
12958  |  |  */  | 
12959  |  | static int  | 
12960  |  | xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)  | 
12961  | 96.1M  | { | 
12962  | 96.1M  |     int total = 0;  | 
12963  | 96.1M  |     int equal, ret;  | 
12964  | 96.1M  |     xmlXPathCompExprPtr comp;  | 
12965  | 96.1M  |     xmlXPathObjectPtr arg1, arg2;  | 
12966  |  |  | 
12967  | 96.1M  |     CHECK_ERROR0;  | 
12968  | 96.1M  |     if (OP_LIMIT_EXCEEDED(ctxt, 1))  | 
12969  | 1.94k  |         return(0);  | 
12970  | 96.1M  |     if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)  | 
12971  | 96.1M  |         XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);  | 
12972  | 96.1M  |     ctxt->context->depth += 1;  | 
12973  | 96.1M  |     comp = ctxt->comp;  | 
12974  | 96.1M  |     switch (op->op) { | 
12975  | 0  |         case XPATH_OP_END:  | 
12976  | 0  |             break;  | 
12977  | 393k  |         case XPATH_OP_AND:  | 
12978  | 393k  |             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);  | 
12979  | 393k  |       CHECK_ERROR0;  | 
12980  | 386k  |             xmlXPathBooleanFunction(ctxt, 1);  | 
12981  | 386k  |             if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))  | 
12982  | 146k  |                 break;  | 
12983  | 239k  |             arg2 = valuePop(ctxt);  | 
12984  | 239k  |             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);  | 
12985  | 239k  |       if (ctxt->error) { | 
12986  | 7.66k  |     xmlXPathFreeObject(arg2);  | 
12987  | 7.66k  |     break;  | 
12988  | 7.66k  |       }  | 
12989  | 232k  |             xmlXPathBooleanFunction(ctxt, 1);  | 
12990  | 232k  |             if (ctxt->value != NULL)  | 
12991  | 232k  |                 ctxt->value->boolval &= arg2->boolval;  | 
12992  | 232k  |       xmlXPathReleaseObject(ctxt->context, arg2);  | 
12993  | 232k  |             break;  | 
12994  | 108k  |         case XPATH_OP_OR:  | 
12995  | 108k  |             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);  | 
12996  | 108k  |       CHECK_ERROR0;  | 
12997  | 101k  |             xmlXPathBooleanFunction(ctxt, 1);  | 
12998  | 101k  |             if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))  | 
12999  | 33.5k  |                 break;  | 
13000  | 67.6k  |             arg2 = valuePop(ctxt);  | 
13001  | 67.6k  |             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);  | 
13002  | 67.6k  |       if (ctxt->error) { | 
13003  | 10.8k  |     xmlXPathFreeObject(arg2);  | 
13004  | 10.8k  |     break;  | 
13005  | 10.8k  |       }  | 
13006  | 56.8k  |             xmlXPathBooleanFunction(ctxt, 1);  | 
13007  | 56.8k  |             if (ctxt->value != NULL)  | 
13008  | 56.8k  |                 ctxt->value->boolval |= arg2->boolval;  | 
13009  | 56.8k  |       xmlXPathReleaseObject(ctxt->context, arg2);  | 
13010  | 56.8k  |             break;  | 
13011  | 4.94M  |         case XPATH_OP_EQUAL:  | 
13012  | 4.94M  |             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);  | 
13013  | 4.94M  |       CHECK_ERROR0;  | 
13014  | 4.77M  |             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);  | 
13015  | 4.77M  |       CHECK_ERROR0;  | 
13016  | 4.65M  |       if (op->value)  | 
13017  | 4.29M  |     equal = xmlXPathEqualValues(ctxt);  | 
13018  | 359k  |       else  | 
13019  | 359k  |     equal = xmlXPathNotEqualValues(ctxt);  | 
13020  | 4.65M  |       valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, equal));  | 
13021  | 4.65M  |             break;  | 
13022  | 4.08M  |         case XPATH_OP_CMP:  | 
13023  | 4.08M  |             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);  | 
13024  | 4.08M  |       CHECK_ERROR0;  | 
13025  | 4.05M  |             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);  | 
13026  | 4.05M  |       CHECK_ERROR0;  | 
13027  | 4.02M  |             ret = xmlXPathCompareValues(ctxt, op->value, op->value2);  | 
13028  | 4.02M  |       valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));  | 
13029  | 4.02M  |             break;  | 
13030  | 6.12M  |         case XPATH_OP_PLUS:  | 
13031  | 6.12M  |             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);  | 
13032  | 6.12M  |       CHECK_ERROR0;  | 
13033  | 6.07M  |             if (op->ch2 != -1) { | 
13034  | 3.63M  |                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);  | 
13035  | 3.63M  |       }  | 
13036  | 6.07M  |       CHECK_ERROR0;  | 
13037  | 6.04M  |             if (op->value == 0)  | 
13038  | 3.22M  |                 xmlXPathSubValues(ctxt);  | 
13039  | 2.82M  |             else if (op->value == 1)  | 
13040  | 383k  |                 xmlXPathAddValues(ctxt);  | 
13041  | 2.44M  |             else if (op->value == 2)  | 
13042  | 1.60M  |                 xmlXPathValueFlipSign(ctxt);  | 
13043  | 836k  |             else if (op->value == 3) { | 
13044  | 836k  |                 CAST_TO_NUMBER;  | 
13045  | 836k  |                 CHECK_TYPE0(XPATH_NUMBER);  | 
13046  | 836k  |             }  | 
13047  | 6.04M  |             break;  | 
13048  | 6.04M  |         case XPATH_OP_MULT:  | 
13049  | 5.18M  |             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);  | 
13050  | 5.18M  |       CHECK_ERROR0;  | 
13051  | 4.66M  |             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);  | 
13052  | 4.66M  |       CHECK_ERROR0;  | 
13053  | 4.64M  |             if (op->value == 0)  | 
13054  | 4.13M  |                 xmlXPathMultValues(ctxt);  | 
13055  | 507k  |             else if (op->value == 1)  | 
13056  | 415k  |                 xmlXPathDivValues(ctxt);  | 
13057  | 91.9k  |             else if (op->value == 2)  | 
13058  | 91.9k  |                 xmlXPathModValues(ctxt);  | 
13059  | 4.64M  |             break;  | 
13060  | 4.25M  |         case XPATH_OP_UNION:  | 
13061  | 4.25M  |             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);  | 
13062  | 4.25M  |       CHECK_ERROR0;  | 
13063  | 4.14M  |             total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);  | 
13064  | 4.14M  |       CHECK_ERROR0;  | 
13065  |  |  | 
13066  | 4.11M  |             arg2 = valuePop(ctxt);  | 
13067  | 4.11M  |             arg1 = valuePop(ctxt);  | 
13068  | 4.11M  |             if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||  | 
13069  | 4.11M  |                 (arg2 == NULL) || (arg2->type != XPATH_NODESET)) { | 
13070  | 32.7k  |           xmlXPathReleaseObject(ctxt->context, arg1);  | 
13071  | 32.7k  |           xmlXPathReleaseObject(ctxt->context, arg2);  | 
13072  | 32.7k  |                 XP_ERROR0(XPATH_INVALID_TYPE);  | 
13073  | 0  |             }  | 
13074  | 4.08M  |             if ((ctxt->context->opLimit != 0) &&  | 
13075  | 4.08M  |                 (((arg1->nodesetval != NULL) &&  | 
13076  | 4.08M  |                   (xmlXPathCheckOpLimit(ctxt,  | 
13077  | 3.61M  |                                         arg1->nodesetval->nodeNr) < 0)) ||  | 
13078  | 4.08M  |                  ((arg2->nodesetval != NULL) &&  | 
13079  | 4.08M  |                   (xmlXPathCheckOpLimit(ctxt,  | 
13080  | 3.35M  |                                         arg2->nodesetval->nodeNr) < 0)))) { | 
13081  | 20  |           xmlXPathReleaseObject(ctxt->context, arg1);  | 
13082  | 20  |           xmlXPathReleaseObject(ctxt->context, arg2);  | 
13083  | 20  |                 break;  | 
13084  | 20  |             }  | 
13085  |  |  | 
13086  | 4.08M  |       if ((arg1->nodesetval == NULL) ||  | 
13087  | 4.08M  |     ((arg2->nodesetval != NULL) &&  | 
13088  | 3.61M  |      (arg2->nodesetval->nodeNr != 0)))  | 
13089  | 1.82M  |       { | 
13090  |  |                 /* TODO: Check memory error. */  | 
13091  | 1.82M  |     arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,  | 
13092  | 1.82M  |               arg2->nodesetval);  | 
13093  | 1.82M  |       }  | 
13094  |  |  | 
13095  | 4.08M  |             valuePush(ctxt, arg1);  | 
13096  | 4.08M  |       xmlXPathReleaseObject(ctxt->context, arg2);  | 
13097  | 4.08M  |             break;  | 
13098  | 8.47M  |         case XPATH_OP_ROOT:  | 
13099  | 8.47M  |             xmlXPathRoot(ctxt);  | 
13100  | 8.47M  |             break;  | 
13101  | 12.0M  |         case XPATH_OP_NODE:  | 
13102  | 12.0M  |             if (op->ch1 != -1)  | 
13103  | 0  |                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);  | 
13104  | 12.0M  |       CHECK_ERROR0;  | 
13105  | 12.0M  |             if (op->ch2 != -1)  | 
13106  | 0  |                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);  | 
13107  | 12.0M  |       CHECK_ERROR0;  | 
13108  | 12.0M  |       valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,  | 
13109  | 12.0M  |     ctxt->context->node));  | 
13110  | 12.0M  |             break;  | 
13111  | 24.6M  |         case XPATH_OP_COLLECT:{ | 
13112  | 24.6M  |                 if (op->ch1 == -1)  | 
13113  | 0  |                     break;  | 
13114  |  |  | 
13115  | 24.6M  |                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);  | 
13116  | 24.6M  |     CHECK_ERROR0;  | 
13117  |  |  | 
13118  | 24.5M  |                 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0);  | 
13119  | 24.5M  |                 break;  | 
13120  | 24.6M  |             }  | 
13121  | 10.4M  |         case XPATH_OP_VALUE:  | 
13122  | 10.4M  |             valuePush(ctxt,  | 
13123  | 10.4M  |                       xmlXPathCacheObjectCopy(ctxt->context,  | 
13124  | 10.4M  |       (xmlXPathObjectPtr) op->value4));  | 
13125  | 10.4M  |             break;  | 
13126  | 81.3k  |         case XPATH_OP_VARIABLE:{ | 
13127  | 81.3k  |     xmlXPathObjectPtr val;  | 
13128  |  |  | 
13129  | 81.3k  |                 if (op->ch1 != -1)  | 
13130  | 0  |                     total +=  | 
13131  | 0  |                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);  | 
13132  | 81.3k  |                 if (op->value5 == NULL) { | 
13133  | 39.5k  |         val = xmlXPathVariableLookup(ctxt->context, op->value4);  | 
13134  | 39.5k  |         if (val == NULL)  | 
13135  | 39.5k  |       XP_ERROR0(XPATH_UNDEF_VARIABLE_ERROR);  | 
13136  | 0  |                     valuePush(ctxt, val);  | 
13137  | 41.7k  |     } else { | 
13138  | 41.7k  |                     const xmlChar *URI;  | 
13139  |  |  | 
13140  | 41.7k  |                     URI = xmlXPathNsLookup(ctxt->context, op->value5);  | 
13141  | 41.7k  |                     if (URI == NULL) { | 
13142  | 36.8k  |                         xmlGenericError(xmlGenericErrorContext,  | 
13143  | 36.8k  |             "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",  | 
13144  | 36.8k  |                                     (char *) op->value4, (char *)op->value5);  | 
13145  | 36.8k  |                         ctxt->error = XPATH_UNDEF_PREFIX_ERROR;  | 
13146  | 36.8k  |                         break;  | 
13147  | 36.8k  |                     }  | 
13148  | 4.92k  |         val = xmlXPathVariableLookupNS(ctxt->context,  | 
13149  | 4.92k  |                                                        op->value4, URI);  | 
13150  | 4.92k  |         if (val == NULL)  | 
13151  | 4.92k  |       XP_ERROR0(XPATH_UNDEF_VARIABLE_ERROR);  | 
13152  | 0  |                     valuePush(ctxt, val);  | 
13153  | 0  |                 }  | 
13154  | 0  |                 break;  | 
13155  | 81.3k  |             }  | 
13156  | 4.86M  |         case XPATH_OP_FUNCTION:{ | 
13157  | 4.86M  |                 xmlXPathFunction func;  | 
13158  | 4.86M  |                 const xmlChar *oldFunc, *oldFuncURI;  | 
13159  | 4.86M  |     int i;  | 
13160  | 4.86M  |                 int frame;  | 
13161  |  |  | 
13162  | 4.86M  |                 frame = xmlXPathSetFrame(ctxt);  | 
13163  | 4.86M  |                 if (op->ch1 != -1) { | 
13164  | 4.62M  |                     total +=  | 
13165  | 4.62M  |                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);  | 
13166  | 4.62M  |                     if (ctxt->error != XPATH_EXPRESSION_OK) { | 
13167  | 12.5k  |                         xmlXPathPopFrame(ctxt, frame);  | 
13168  | 12.5k  |                         break;  | 
13169  | 12.5k  |                     }  | 
13170  | 4.62M  |                 }  | 
13171  | 4.84M  |     if (ctxt->valueNr < ctxt->valueFrame + op->value) { | 
13172  | 0  |         xmlGenericError(xmlGenericErrorContext,  | 
13173  | 0  |           "xmlXPathCompOpEval: parameter error\n");  | 
13174  | 0  |         ctxt->error = XPATH_INVALID_OPERAND;  | 
13175  | 0  |                     xmlXPathPopFrame(ctxt, frame);  | 
13176  | 0  |         break;  | 
13177  | 0  |     }  | 
13178  | 11.4M  |     for (i = 0; i < op->value; i++) { | 
13179  | 6.63M  |         if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) { | 
13180  | 0  |       xmlGenericError(xmlGenericErrorContext,  | 
13181  | 0  |         "xmlXPathCompOpEval: parameter error\n");  | 
13182  | 0  |       ctxt->error = XPATH_INVALID_OPERAND;  | 
13183  | 0  |                         xmlXPathPopFrame(ctxt, frame);  | 
13184  | 0  |       break;  | 
13185  | 0  |         }  | 
13186  | 6.63M  |                 }  | 
13187  | 4.84M  |                 if (op->cache != NULL)  | 
13188  | 4.49M  |                     func = op->cache;  | 
13189  | 355k  |                 else { | 
13190  | 355k  |                     const xmlChar *URI = NULL;  | 
13191  |  |  | 
13192  | 355k  |                     if (op->value5 == NULL)  | 
13193  | 238k  |                         func =  | 
13194  | 238k  |                             xmlXPathFunctionLookup(ctxt->context,  | 
13195  | 238k  |                                                    op->value4);  | 
13196  | 116k  |                     else { | 
13197  | 116k  |                         URI = xmlXPathNsLookup(ctxt->context, op->value5);  | 
13198  | 116k  |                         if (URI == NULL) { | 
13199  | 12.2k  |                             xmlGenericError(xmlGenericErrorContext,  | 
13200  | 12.2k  |             "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",  | 
13201  | 12.2k  |                                     (char *)op->value4, (char *)op->value5);  | 
13202  | 12.2k  |                             xmlXPathPopFrame(ctxt, frame);  | 
13203  | 12.2k  |                             ctxt->error = XPATH_UNDEF_PREFIX_ERROR;  | 
13204  | 12.2k  |                             break;  | 
13205  | 12.2k  |                         }  | 
13206  | 104k  |                         func = xmlXPathFunctionLookupNS(ctxt->context,  | 
13207  | 104k  |                                                         op->value4, URI);  | 
13208  | 104k  |                     }  | 
13209  | 342k  |                     if (func == NULL) { | 
13210  | 38.7k  |                         xmlGenericError(xmlGenericErrorContext,  | 
13211  | 38.7k  |                                 "xmlXPathCompOpEval: function %s not found\n",  | 
13212  | 38.7k  |                                         (char *)op->value4);  | 
13213  | 38.7k  |                         XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);  | 
13214  | 0  |                     }  | 
13215  | 304k  |                     op->cache = func;  | 
13216  | 304k  |                     op->cacheURI = (void *) URI;  | 
13217  | 304k  |                 }  | 
13218  | 4.79M  |                 oldFunc = ctxt->context->function;  | 
13219  | 4.79M  |                 oldFuncURI = ctxt->context->functionURI;  | 
13220  | 4.79M  |                 ctxt->context->function = op->value4;  | 
13221  | 4.79M  |                 ctxt->context->functionURI = op->cacheURI;  | 
13222  | 4.79M  |                 func(ctxt, op->value);  | 
13223  | 4.79M  |                 ctxt->context->function = oldFunc;  | 
13224  | 4.79M  |                 ctxt->context->functionURI = oldFuncURI;  | 
13225  | 4.79M  |                 if ((ctxt->error == XPATH_EXPRESSION_OK) &&  | 
13226  | 4.79M  |                     (ctxt->valueNr != ctxt->valueFrame + 1))  | 
13227  | 4.79M  |                     XP_ERROR0(XPATH_STACK_ERROR);  | 
13228  | 4.79M  |                 xmlXPathPopFrame(ctxt, frame);  | 
13229  | 4.79M  |                 break;  | 
13230  | 4.79M  |             }  | 
13231  | 6.66M  |         case XPATH_OP_ARG:  | 
13232  | 6.66M  |             if (op->ch1 != -1) { | 
13233  | 2.04M  |                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);  | 
13234  | 2.04M  |           CHECK_ERROR0;  | 
13235  | 2.04M  |             }  | 
13236  | 6.65M  |             if (op->ch2 != -1) { | 
13237  | 6.65M  |                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);  | 
13238  | 6.65M  |           CHECK_ERROR0;  | 
13239  | 6.65M  |       }  | 
13240  | 6.64M  |             break;  | 
13241  | 6.64M  |         case XPATH_OP_PREDICATE:  | 
13242  | 312k  |         case XPATH_OP_FILTER:{ | 
13243  | 312k  |                 xmlNodeSetPtr set;  | 
13244  |  |  | 
13245  |  |                 /*  | 
13246  |  |                  * Optimization for ()[1] selection i.e. the first elem  | 
13247  |  |                  */  | 
13248  | 312k  |                 if ((op->ch1 != -1) && (op->ch2 != -1) &&  | 
13249  | 312k  | #ifdef XP_OPTIMIZED_FILTER_FIRST  | 
13250  |  |         /*  | 
13251  |  |         * FILTER TODO: Can we assume that the inner processing  | 
13252  |  |         *  will result in an ordered list if we have an  | 
13253  |  |         *  XPATH_OP_FILTER?  | 
13254  |  |         *  What about an additional field or flag on  | 
13255  |  |         *  xmlXPathObject like @sorted ? This way we wouldn't need  | 
13256  |  |         *  to assume anything, so it would be more robust and  | 
13257  |  |         *  easier to optimize.  | 
13258  |  |         */  | 
13259  | 312k  |                     ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */  | 
13260  | 312k  |          (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */  | 
13261  |  | #else  | 
13262  |  |         (comp->steps[op->ch1].op == XPATH_OP_SORT) &&  | 
13263  |  | #endif  | 
13264  | 312k  |                     (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */ | 
13265  | 166k  |                     xmlXPathObjectPtr val;  | 
13266  |  |  | 
13267  | 166k  |                     val = comp->steps[op->ch2].value4;  | 
13268  | 166k  |                     if ((val != NULL) && (val->type == XPATH_NUMBER) &&  | 
13269  | 166k  |                         (val->floatval == 1.0)) { | 
13270  | 138k  |                         xmlNodePtr first = NULL;  | 
13271  |  |  | 
13272  | 138k  |                         total +=  | 
13273  | 138k  |                             xmlXPathCompOpEvalFirst(ctxt,  | 
13274  | 138k  |                                                     &comp->steps[op->ch1],  | 
13275  | 138k  |                                                     &first);  | 
13276  | 138k  |       CHECK_ERROR0;  | 
13277  |  |                         /*  | 
13278  |  |                          * The nodeset should be in document order,  | 
13279  |  |                          * Keep only the first value  | 
13280  |  |                          */  | 
13281  | 136k  |                         if ((ctxt->value != NULL) &&  | 
13282  | 136k  |                             (ctxt->value->type == XPATH_NODESET) &&  | 
13283  | 136k  |                             (ctxt->value->nodesetval != NULL) &&  | 
13284  | 136k  |                             (ctxt->value->nodesetval->nodeNr > 1))  | 
13285  | 22.8k  |                             xmlXPathNodeSetClearFromPos(ctxt->value->nodesetval,  | 
13286  | 22.8k  |                                                         1, 1);  | 
13287  | 136k  |                         break;  | 
13288  | 138k  |                     }  | 
13289  | 166k  |                 }  | 
13290  |  |                 /*  | 
13291  |  |                  * Optimization for ()[last()] selection i.e. the last elem  | 
13292  |  |                  */  | 
13293  | 174k  |                 if ((op->ch1 != -1) && (op->ch2 != -1) &&  | 
13294  | 174k  |                     (comp->steps[op->ch1].op == XPATH_OP_SORT) &&  | 
13295  | 174k  |                     (comp->steps[op->ch2].op == XPATH_OP_SORT)) { | 
13296  | 99.8k  |                     int f = comp->steps[op->ch2].ch1;  | 
13297  |  |  | 
13298  | 99.8k  |                     if ((f != -1) &&  | 
13299  | 99.8k  |                         (comp->steps[f].op == XPATH_OP_FUNCTION) &&  | 
13300  | 99.8k  |                         (comp->steps[f].value5 == NULL) &&  | 
13301  | 99.8k  |                         (comp->steps[f].value == 0) &&  | 
13302  | 99.8k  |                         (comp->steps[f].value4 != NULL) &&  | 
13303  | 99.8k  |                         (xmlStrEqual  | 
13304  | 45.0k  |                          (comp->steps[f].value4, BAD_CAST "last"))) { | 
13305  | 35.7k  |                         xmlNodePtr last = NULL;  | 
13306  |  |  | 
13307  | 35.7k  |                         total +=  | 
13308  | 35.7k  |                             xmlXPathCompOpEvalLast(ctxt,  | 
13309  | 35.7k  |                                                    &comp->steps[op->ch1],  | 
13310  | 35.7k  |                                                    &last);  | 
13311  | 35.7k  |       CHECK_ERROR0;  | 
13312  |  |                         /*  | 
13313  |  |                          * The nodeset should be in document order,  | 
13314  |  |                          * Keep only the last value  | 
13315  |  |                          */  | 
13316  | 35.0k  |                         if ((ctxt->value != NULL) &&  | 
13317  | 35.0k  |                             (ctxt->value->type == XPATH_NODESET) &&  | 
13318  | 35.0k  |                             (ctxt->value->nodesetval != NULL) &&  | 
13319  | 35.0k  |                             (ctxt->value->nodesetval->nodeTab != NULL) &&  | 
13320  | 35.0k  |                             (ctxt->value->nodesetval->nodeNr > 1))  | 
13321  | 6.75k  |                             xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);  | 
13322  | 35.0k  |                         break;  | 
13323  | 35.7k  |                     }  | 
13324  | 99.8k  |                 }  | 
13325  |  |     /*  | 
13326  |  |     * Process inner predicates first.  | 
13327  |  |     * Example "index[parent::book][1]":  | 
13328  |  |     * ...  | 
13329  |  |     *   PREDICATE   <-- we are here "[1]"  | 
13330  |  |     *     PREDICATE <-- process "[parent::book]" first  | 
13331  |  |     *       SORT  | 
13332  |  |     *         COLLECT  'parent' 'name' 'node' book  | 
13333  |  |     *           NODE  | 
13334  |  |     *     ELEM Object is a number : 1  | 
13335  |  |     */  | 
13336  | 138k  |                 if (op->ch1 != -1)  | 
13337  | 138k  |                     total +=  | 
13338  | 138k  |                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);  | 
13339  | 138k  |     CHECK_ERROR0;  | 
13340  | 128k  |                 if (op->ch2 == -1)  | 
13341  | 0  |                     break;  | 
13342  | 128k  |                 if (ctxt->value == NULL)  | 
13343  | 0  |                     break;  | 
13344  |  |  | 
13345  |  | #ifdef LIBXML_XPTR_LOCS_ENABLED  | 
13346  |  |                 /*  | 
13347  |  |                  * Hum are we filtering the result of an XPointer expression  | 
13348  |  |                  */  | 
13349  |  |                 if (ctxt->value->type == XPATH_LOCATIONSET) { | 
13350  |  |                     xmlLocationSetPtr locset = ctxt->value->user;  | 
13351  |  |                     xmlXPathLocationSetFilter(ctxt, locset, op->ch2,  | 
13352  |  |                                               1, locset->locNr);  | 
13353  |  |                     break;  | 
13354  |  |                 }  | 
13355  |  | #endif /* LIBXML_XPTR_LOCS_ENABLED */  | 
13356  |  |  | 
13357  | 128k  |                 CHECK_TYPE0(XPATH_NODESET);  | 
13358  | 118k  |                 set = ctxt->value->nodesetval;  | 
13359  | 118k  |                 if (set != NULL)  | 
13360  | 105k  |                     xmlXPathNodeSetFilter(ctxt, set, op->ch2,  | 
13361  | 105k  |                                           1, set->nodeNr, 1);  | 
13362  | 118k  |                 break;  | 
13363  | 128k  |             }  | 
13364  | 3.47M  |         case XPATH_OP_SORT:  | 
13365  | 3.47M  |             if (op->ch1 != -1)  | 
13366  | 3.47M  |                 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);  | 
13367  | 3.47M  |       CHECK_ERROR0;  | 
13368  | 3.18M  |             if ((ctxt->value != NULL) &&  | 
13369  | 3.18M  |                 (ctxt->value->type == XPATH_NODESET) &&  | 
13370  | 3.18M  |                 (ctxt->value->nodesetval != NULL) &&  | 
13371  | 3.18M  |     (ctxt->value->nodesetval->nodeNr > 1))  | 
13372  | 604k  |       { | 
13373  | 604k  |                 xmlXPathNodeSetSort(ctxt->value->nodesetval);  | 
13374  | 604k  |       }  | 
13375  | 3.18M  |             break;  | 
13376  |  | #ifdef LIBXML_XPTR_LOCS_ENABLED  | 
13377  |  |         case XPATH_OP_RANGETO:{ | 
13378  |  |                 xmlXPathObjectPtr range;  | 
13379  |  |                 xmlXPathObjectPtr res, obj;  | 
13380  |  |                 xmlXPathObjectPtr tmp;  | 
13381  |  |                 xmlLocationSetPtr newlocset = NULL;  | 
13382  |  |         xmlLocationSetPtr oldlocset;  | 
13383  |  |                 xmlNodeSetPtr oldset;  | 
13384  |  |                 xmlNodePtr oldnode = ctxt->context->node;  | 
13385  |  |                 int oldcs = ctxt->context->contextSize;  | 
13386  |  |                 int oldpp = ctxt->context->proximityPosition;  | 
13387  |  |                 int i, j;  | 
13388  |  |  | 
13389  |  |                 if (op->ch1 != -1) { | 
13390  |  |                     total +=  | 
13391  |  |                         xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);  | 
13392  |  |                     CHECK_ERROR0;  | 
13393  |  |                 }  | 
13394  |  |                 if (ctxt->value == NULL) { | 
13395  |  |                     XP_ERROR0(XPATH_INVALID_OPERAND);  | 
13396  |  |                 }  | 
13397  |  |                 if (op->ch2 == -1)  | 
13398  |  |                     break;  | 
13399  |  |  | 
13400  |  |                 if (ctxt->value->type == XPATH_LOCATIONSET) { | 
13401  |  |                     /*  | 
13402  |  |                      * Extract the old locset, and then evaluate the result of the  | 
13403  |  |                      * expression for all the element in the locset. use it to grow  | 
13404  |  |                      * up a new locset.  | 
13405  |  |                      */  | 
13406  |  |                     CHECK_TYPE0(XPATH_LOCATIONSET);  | 
13407  |  |  | 
13408  |  |                     if ((ctxt->value->user == NULL) ||  | 
13409  |  |                         (((xmlLocationSetPtr) ctxt->value->user)->locNr == 0))  | 
13410  |  |                         break;  | 
13411  |  |  | 
13412  |  |                     obj = valuePop(ctxt);  | 
13413  |  |                     oldlocset = obj->user;  | 
13414  |  |  | 
13415  |  |                     newlocset = xmlXPtrLocationSetCreate(NULL);  | 
13416  |  |  | 
13417  |  |                     for (i = 0; i < oldlocset->locNr; i++) { | 
13418  |  |                         /*  | 
13419  |  |                          * Run the evaluation with a node list made of a  | 
13420  |  |                          * single item in the nodelocset.  | 
13421  |  |                          */  | 
13422  |  |                         ctxt->context->node = oldlocset->locTab[i]->user;  | 
13423  |  |                         ctxt->context->contextSize = oldlocset->locNr;  | 
13424  |  |                         ctxt->context->proximityPosition = i + 1;  | 
13425  |  |       tmp = xmlXPathCacheNewNodeSet(ctxt->context,  | 
13426  |  |           ctxt->context->node);  | 
13427  |  |                         valuePush(ctxt, tmp);  | 
13428  |  |  | 
13429  |  |                         if (op->ch2 != -1)  | 
13430  |  |                             total +=  | 
13431  |  |                                 xmlXPathCompOpEval(ctxt,  | 
13432  |  |                                                    &comp->steps[op->ch2]);  | 
13433  |  |       if (ctxt->error != XPATH_EXPRESSION_OK) { | 
13434  |  |                             xmlXPtrFreeLocationSet(newlocset);  | 
13435  |  |                             goto rangeto_error;  | 
13436  |  |       }  | 
13437  |  |  | 
13438  |  |                         res = valuePop(ctxt);  | 
13439  |  |       if (res->type == XPATH_LOCATIONSET) { | 
13440  |  |           xmlLocationSetPtr rloc =  | 
13441  |  |               (xmlLocationSetPtr)res->user;  | 
13442  |  |           for (j=0; j<rloc->locNr; j++) { | 
13443  |  |               range = xmlXPtrNewRange(  | 
13444  |  |           oldlocset->locTab[i]->user,  | 
13445  |  |           oldlocset->locTab[i]->index,  | 
13446  |  |           rloc->locTab[j]->user2,  | 
13447  |  |           rloc->locTab[j]->index2);  | 
13448  |  |         if (range != NULL) { | 
13449  |  |             xmlXPtrLocationSetAdd(newlocset, range);  | 
13450  |  |         }  | 
13451  |  |           }  | 
13452  |  |       } else { | 
13453  |  |           range = xmlXPtrNewRangeNodeObject(  | 
13454  |  |         (xmlNodePtr)oldlocset->locTab[i]->user, res);  | 
13455  |  |                             if (range != NULL) { | 
13456  |  |                                 xmlXPtrLocationSetAdd(newlocset,range);  | 
13457  |  |           }  | 
13458  |  |                         }  | 
13459  |  |  | 
13460  |  |                         /*  | 
13461  |  |                          * Cleanup  | 
13462  |  |                          */  | 
13463  |  |                         if (res != NULL) { | 
13464  |  |           xmlXPathReleaseObject(ctxt->context, res);  | 
13465  |  |       }  | 
13466  |  |                         if (ctxt->value == tmp) { | 
13467  |  |                             res = valuePop(ctxt);  | 
13468  |  |           xmlXPathReleaseObject(ctxt->context, res);  | 
13469  |  |                         }  | 
13470  |  |                     }  | 
13471  |  |     } else {  /* Not a location set */ | 
13472  |  |                     CHECK_TYPE0(XPATH_NODESET);  | 
13473  |  |                     obj = valuePop(ctxt);  | 
13474  |  |                     oldset = obj->nodesetval;  | 
13475  |  |  | 
13476  |  |                     newlocset = xmlXPtrLocationSetCreate(NULL);  | 
13477  |  |  | 
13478  |  |                     if (oldset != NULL) { | 
13479  |  |                         for (i = 0; i < oldset->nodeNr; i++) { | 
13480  |  |                             /*  | 
13481  |  |                              * Run the evaluation with a node list made of a single item  | 
13482  |  |                              * in the nodeset.  | 
13483  |  |                              */  | 
13484  |  |                             ctxt->context->node = oldset->nodeTab[i];  | 
13485  |  |           /*  | 
13486  |  |           * OPTIMIZE TODO: Avoid recreation for every iteration.  | 
13487  |  |           */  | 
13488  |  |           tmp = xmlXPathCacheNewNodeSet(ctxt->context,  | 
13489  |  |         ctxt->context->node);  | 
13490  |  |                             valuePush(ctxt, tmp);  | 
13491  |  |  | 
13492  |  |                             if (op->ch2 != -1)  | 
13493  |  |                                 total +=  | 
13494  |  |                                     xmlXPathCompOpEval(ctxt,  | 
13495  |  |                                                    &comp->steps[op->ch2]);  | 
13496  |  |           if (ctxt->error != XPATH_EXPRESSION_OK) { | 
13497  |  |                                 xmlXPtrFreeLocationSet(newlocset);  | 
13498  |  |                                 goto rangeto_error;  | 
13499  |  |           }  | 
13500  |  |  | 
13501  |  |                             res = valuePop(ctxt);  | 
13502  |  |                             range =  | 
13503  |  |                                 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],  | 
13504  |  |                                                       res);  | 
13505  |  |                             if (range != NULL) { | 
13506  |  |                                 xmlXPtrLocationSetAdd(newlocset, range);  | 
13507  |  |                             }  | 
13508  |  |  | 
13509  |  |                             /*  | 
13510  |  |                              * Cleanup  | 
13511  |  |                              */  | 
13512  |  |                             if (res != NULL) { | 
13513  |  |         xmlXPathReleaseObject(ctxt->context, res);  | 
13514  |  |           }  | 
13515  |  |                             if (ctxt->value == tmp) { | 
13516  |  |                                 res = valuePop(ctxt);  | 
13517  |  |         xmlXPathReleaseObject(ctxt->context, res);  | 
13518  |  |                             }  | 
13519  |  |                         }  | 
13520  |  |                     }  | 
13521  |  |                 }  | 
13522  |  |  | 
13523  |  |                 /*  | 
13524  |  |                  * The result is used as the new evaluation set.  | 
13525  |  |                  */  | 
13526  |  |                 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));  | 
13527  |  | rangeto_error:  | 
13528  |  |     xmlXPathReleaseObject(ctxt->context, obj);  | 
13529  |  |                 ctxt->context->node = oldnode;  | 
13530  |  |                 ctxt->context->contextSize = oldcs;  | 
13531  |  |                 ctxt->context->proximityPosition = oldpp;  | 
13532  |  |                 break;  | 
13533  |  |             }  | 
13534  |  | #endif /* LIBXML_XPTR_LOCS_ENABLED */  | 
13535  | 0  |         default:  | 
13536  | 0  |             xmlGenericError(xmlGenericErrorContext,  | 
13537  | 0  |                             "XPath: unknown precompiled operation %d\n", op->op);  | 
13538  | 0  |             ctxt->error = XPATH_INVALID_OPERAND;  | 
13539  | 0  |             break;  | 
13540  | 96.1M  |     }  | 
13541  |  |  | 
13542  | 94.4M  |     ctxt->context->depth -= 1;  | 
13543  | 94.4M  |     return (total);  | 
13544  | 96.1M  | }  | 
13545  |  |  | 
13546  |  | /**  | 
13547  |  |  * xmlXPathCompOpEvalToBoolean:  | 
13548  |  |  * @ctxt:  the XPath parser context  | 
13549  |  |  *  | 
13550  |  |  * Evaluates if the expression evaluates to true.  | 
13551  |  |  *  | 
13552  |  |  * Returns 1 if true, 0 if false and -1 on API or internal errors.  | 
13553  |  |  */  | 
13554  |  | static int  | 
13555  |  | xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,  | 
13556  |  |           xmlXPathStepOpPtr op,  | 
13557  |  |           int isPredicate)  | 
13558  | 6.44M  | { | 
13559  | 6.44M  |     xmlXPathObjectPtr resObj = NULL;  | 
13560  |  |  | 
13561  | 6.94M  | start:  | 
13562  | 6.94M  |     if (OP_LIMIT_EXCEEDED(ctxt, 1))  | 
13563  | 5  |         return(0);  | 
13564  |  |     /* comp = ctxt->comp; */  | 
13565  | 6.94M  |     switch (op->op) { | 
13566  | 0  |         case XPATH_OP_END:  | 
13567  | 0  |             return (0);  | 
13568  | 180k  |   case XPATH_OP_VALUE:  | 
13569  | 180k  |       resObj = (xmlXPathObjectPtr) op->value4;  | 
13570  | 180k  |       if (isPredicate)  | 
13571  | 180k  |     return(xmlXPathEvaluatePredicateResult(ctxt, resObj));  | 
13572  | 0  |       return(xmlXPathCastToBoolean(resObj));  | 
13573  | 494k  |   case XPATH_OP_SORT:  | 
13574  |  |       /*  | 
13575  |  |       * We don't need sorting for boolean results. Skip this one.  | 
13576  |  |       */  | 
13577  | 494k  |             if (op->ch1 != -1) { | 
13578  | 494k  |     op = &ctxt->comp->steps[op->ch1];  | 
13579  | 494k  |     goto start;  | 
13580  | 494k  |       }  | 
13581  | 0  |       return(0);  | 
13582  | 825k  |   case XPATH_OP_COLLECT:  | 
13583  | 825k  |       if (op->ch1 == -1)  | 
13584  | 0  |     return(0);  | 
13585  |  |  | 
13586  | 825k  |             xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]);  | 
13587  | 825k  |       if (ctxt->error != XPATH_EXPRESSION_OK)  | 
13588  | 297  |     return(-1);  | 
13589  |  |  | 
13590  | 825k  |             xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1);  | 
13591  | 825k  |       if (ctxt->error != XPATH_EXPRESSION_OK)  | 
13592  | 621  |     return(-1);  | 
13593  |  |  | 
13594  | 824k  |       resObj = valuePop(ctxt);  | 
13595  | 824k  |       if (resObj == NULL)  | 
13596  | 0  |     return(-1);  | 
13597  | 824k  |       break;  | 
13598  | 5.44M  |   default:  | 
13599  |  |       /*  | 
13600  |  |       * Fallback to call xmlXPathCompOpEval().  | 
13601  |  |       */  | 
13602  | 5.44M  |       xmlXPathCompOpEval(ctxt, op);  | 
13603  | 5.44M  |       if (ctxt->error != XPATH_EXPRESSION_OK)  | 
13604  | 6.43k  |     return(-1);  | 
13605  |  |  | 
13606  | 5.43M  |       resObj = valuePop(ctxt);  | 
13607  | 5.43M  |       if (resObj == NULL)  | 
13608  | 0  |     return(-1);  | 
13609  | 5.43M  |       break;  | 
13610  | 6.94M  |     }  | 
13611  |  |  | 
13612  | 6.25M  |     if (resObj) { | 
13613  | 6.25M  |   int res;  | 
13614  |  |  | 
13615  | 6.25M  |   if (resObj->type == XPATH_BOOLEAN) { | 
13616  | 3.12M  |       res = resObj->boolval;  | 
13617  | 3.13M  |   } else if (isPredicate) { | 
13618  |  |       /*  | 
13619  |  |       * For predicates a result of type "number" is handled  | 
13620  |  |       * differently:  | 
13621  |  |       * SPEC XPath 1.0:  | 
13622  |  |       * "If the result is a number, the result will be converted  | 
13623  |  |       *  to true if the number is equal to the context position  | 
13624  |  |       *  and will be converted to false otherwise;"  | 
13625  |  |       */  | 
13626  | 3.13M  |       res = xmlXPathEvaluatePredicateResult(ctxt, resObj);  | 
13627  | 3.13M  |   } else { | 
13628  | 0  |       res = xmlXPathCastToBoolean(resObj);  | 
13629  | 0  |   }  | 
13630  | 6.25M  |   xmlXPathReleaseObject(ctxt->context, resObj);  | 
13631  | 6.25M  |   return(res);  | 
13632  | 6.25M  |     }  | 
13633  |  |  | 
13634  | 0  |     return(0);  | 
13635  | 6.25M  | }  | 
13636  |  |  | 
13637  |  | #ifdef XPATH_STREAMING  | 
13638  |  | /**  | 
13639  |  |  * xmlXPathRunStreamEval:  | 
13640  |  |  * @ctxt:  the XPath parser context with the compiled expression  | 
13641  |  |  *  | 
13642  |  |  * Evaluate the Precompiled Streamable XPath expression in the given context.  | 
13643  |  |  */  | 
13644  |  | static int  | 
13645  |  | xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp,  | 
13646  |  |           xmlXPathObjectPtr *resultSeq, int toBool)  | 
13647  | 584k  | { | 
13648  | 584k  |     int max_depth, min_depth;  | 
13649  | 584k  |     int from_root;  | 
13650  | 584k  |     int ret, depth;  | 
13651  | 584k  |     int eval_all_nodes;  | 
13652  | 584k  |     xmlNodePtr cur = NULL, limit = NULL;  | 
13653  | 584k  |     xmlStreamCtxtPtr patstream = NULL;  | 
13654  |  |  | 
13655  | 584k  |     if ((ctxt == NULL) || (comp == NULL))  | 
13656  | 0  |         return(-1);  | 
13657  | 584k  |     max_depth = xmlPatternMaxDepth(comp);  | 
13658  | 584k  |     if (max_depth == -1)  | 
13659  | 0  |         return(-1);  | 
13660  | 584k  |     if (max_depth == -2)  | 
13661  | 95.6k  |         max_depth = 10000;  | 
13662  | 584k  |     min_depth = xmlPatternMinDepth(comp);  | 
13663  | 584k  |     if (min_depth == -1)  | 
13664  | 0  |         return(-1);  | 
13665  | 584k  |     from_root = xmlPatternFromRoot(comp);  | 
13666  | 584k  |     if (from_root < 0)  | 
13667  | 0  |         return(-1);  | 
13668  |  | #if 0  | 
13669  |  |     printf("stream eval: depth %d from root %d\n", max_depth, from_root); | 
13670  |  | #endif  | 
13671  |  |  | 
13672  | 584k  |     if (! toBool) { | 
13673  | 584k  |   if (resultSeq == NULL)  | 
13674  | 0  |       return(-1);  | 
13675  | 584k  |   *resultSeq = xmlXPathCacheNewNodeSet(ctxt, NULL);  | 
13676  | 584k  |   if (*resultSeq == NULL)  | 
13677  | 0  |       return(-1);  | 
13678  | 584k  |     }  | 
13679  |  |  | 
13680  |  |     /*  | 
13681  |  |      * handle the special cases of "/" amd "." being matched  | 
13682  |  |      */  | 
13683  | 584k  |     if (min_depth == 0) { | 
13684  | 27.7k  |   if (from_root) { | 
13685  |  |       /* Select "/" */  | 
13686  | 0  |       if (toBool)  | 
13687  | 0  |     return(1);  | 
13688  |  |             /* TODO: Check memory error. */  | 
13689  | 0  |       xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,  | 
13690  | 0  |                          (xmlNodePtr) ctxt->doc);  | 
13691  | 27.7k  |   } else { | 
13692  |  |       /* Select "self::node()" */  | 
13693  | 27.7k  |       if (toBool)  | 
13694  | 0  |     return(1);  | 
13695  |  |             /* TODO: Check memory error. */  | 
13696  | 27.7k  |       xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, ctxt->node);  | 
13697  | 27.7k  |   }  | 
13698  | 27.7k  |     }  | 
13699  | 584k  |     if (max_depth == 0) { | 
13700  | 12.6k  |   return(0);  | 
13701  | 12.6k  |     }  | 
13702  |  |  | 
13703  | 572k  |     if (from_root) { | 
13704  | 254k  |         cur = (xmlNodePtr)ctxt->doc;  | 
13705  | 317k  |     } else if (ctxt->node != NULL) { | 
13706  | 317k  |         switch (ctxt->node->type) { | 
13707  | 170k  |             case XML_ELEMENT_NODE:  | 
13708  | 201k  |             case XML_DOCUMENT_NODE:  | 
13709  | 201k  |             case XML_DOCUMENT_FRAG_NODE:  | 
13710  | 201k  |             case XML_HTML_DOCUMENT_NODE:  | 
13711  | 201k  |           cur = ctxt->node;  | 
13712  | 201k  |     break;  | 
13713  | 139  |             case XML_ATTRIBUTE_NODE:  | 
13714  | 92.2k  |             case XML_TEXT_NODE:  | 
13715  | 96.4k  |             case XML_CDATA_SECTION_NODE:  | 
13716  | 96.4k  |             case XML_ENTITY_REF_NODE:  | 
13717  | 96.4k  |             case XML_ENTITY_NODE:  | 
13718  | 105k  |             case XML_PI_NODE:  | 
13719  | 113k  |             case XML_COMMENT_NODE:  | 
13720  | 113k  |             case XML_NOTATION_NODE:  | 
13721  | 113k  |             case XML_DTD_NODE:  | 
13722  | 113k  |             case XML_DOCUMENT_TYPE_NODE:  | 
13723  | 113k  |             case XML_ELEMENT_DECL:  | 
13724  | 113k  |             case XML_ATTRIBUTE_DECL:  | 
13725  | 113k  |             case XML_ENTITY_DECL:  | 
13726  | 116k  |             case XML_NAMESPACE_DECL:  | 
13727  | 116k  |             case XML_XINCLUDE_START:  | 
13728  | 116k  |             case XML_XINCLUDE_END:  | 
13729  | 116k  |     break;  | 
13730  | 317k  |   }  | 
13731  | 317k  |   limit = cur;  | 
13732  | 317k  |     }  | 
13733  | 572k  |     if (cur == NULL) { | 
13734  | 116k  |         return(0);  | 
13735  | 116k  |     }  | 
13736  |  |  | 
13737  | 455k  |     patstream = xmlPatternGetStreamCtxt(comp);  | 
13738  | 455k  |     if (patstream == NULL) { | 
13739  |  |   /*  | 
13740  |  |   * QUESTION TODO: Is this an error?  | 
13741  |  |   */  | 
13742  | 0  |   return(0);  | 
13743  | 0  |     }  | 
13744  |  |  | 
13745  | 455k  |     eval_all_nodes = xmlStreamWantsAnyNode(patstream);  | 
13746  |  |  | 
13747  | 455k  |     if (from_root) { | 
13748  | 254k  |   ret = xmlStreamPush(patstream, NULL, NULL);  | 
13749  | 254k  |   if (ret < 0) { | 
13750  | 254k  |   } else if (ret == 1) { | 
13751  | 5.27k  |       if (toBool)  | 
13752  | 0  |     goto return_1;  | 
13753  |  |             /* TODO: Check memory error. */  | 
13754  | 5.27k  |       xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);  | 
13755  | 5.27k  |   }  | 
13756  | 254k  |     }  | 
13757  | 455k  |     depth = 0;  | 
13758  | 455k  |     goto scan_children;  | 
13759  | 1.78M  | next_node:  | 
13760  | 3.14M  |     do { | 
13761  | 3.14M  |         if (ctxt->opLimit != 0) { | 
13762  | 3.14M  |             if (ctxt->opCount >= ctxt->opLimit) { | 
13763  | 0  |                 xmlGenericError(xmlGenericErrorContext,  | 
13764  | 0  |                         "XPath operation limit exceeded\n");  | 
13765  | 0  |                 xmlFreeStreamCtxt(patstream);  | 
13766  | 0  |                 return(-1);  | 
13767  | 0  |             }  | 
13768  | 3.14M  |             ctxt->opCount++;  | 
13769  | 3.14M  |         }  | 
13770  |  |  | 
13771  | 3.14M  |   switch (cur->type) { | 
13772  | 1.04M  |       case XML_ELEMENT_NODE:  | 
13773  | 2.58M  |       case XML_TEXT_NODE:  | 
13774  | 2.65M  |       case XML_CDATA_SECTION_NODE:  | 
13775  | 2.79M  |       case XML_COMMENT_NODE:  | 
13776  | 3.14M  |       case XML_PI_NODE:  | 
13777  | 3.14M  |     if (cur->type == XML_ELEMENT_NODE) { | 
13778  | 1.04M  |         ret = xmlStreamPush(patstream, cur->name,  | 
13779  | 1.04M  |         (cur->ns ? cur->ns->href : NULL));  | 
13780  | 2.10M  |     } else if (eval_all_nodes)  | 
13781  | 862k  |         ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type);  | 
13782  | 1.23M  |     else  | 
13783  | 1.23M  |         break;  | 
13784  |  |  | 
13785  | 1.91M  |     if (ret < 0) { | 
13786  |  |         /* NOP. */  | 
13787  | 1.91M  |     } else if (ret == 1) { | 
13788  | 881k  |         if (toBool)  | 
13789  | 0  |       goto return_1;  | 
13790  | 881k  |         if (xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur)  | 
13791  | 881k  |             < 0) { | 
13792  | 0  |       ctxt->lastError.domain = XML_FROM_XPATH;  | 
13793  | 0  |       ctxt->lastError.code = XML_ERR_NO_MEMORY;  | 
13794  | 0  |         }  | 
13795  | 881k  |     }  | 
13796  | 1.91M  |     if ((cur->children == NULL) || (depth >= max_depth)) { | 
13797  | 1.41M  |         ret = xmlStreamPop(patstream);  | 
13798  | 1.41M  |         while (cur->next != NULL) { | 
13799  | 882k  |       cur = cur->next;  | 
13800  | 882k  |       if ((cur->type != XML_ENTITY_DECL) &&  | 
13801  | 882k  |           (cur->type != XML_DTD_NODE))  | 
13802  | 882k  |           goto next_node;  | 
13803  | 882k  |         }  | 
13804  | 1.41M  |     }  | 
13805  | 1.02M  |       default:  | 
13806  | 1.02M  |     break;  | 
13807  | 3.14M  |   }  | 
13808  |  |  | 
13809  | 2.72M  | scan_children:  | 
13810  | 2.72M  |   if (cur->type == XML_NAMESPACE_DECL) break;  | 
13811  | 2.72M  |   if ((cur->children != NULL) && (depth < max_depth)) { | 
13812  |  |       /*  | 
13813  |  |        * Do not descend on entities declarations  | 
13814  |  |        */  | 
13815  | 915k  |       if (cur->children->type != XML_ENTITY_DECL) { | 
13816  | 915k  |     cur = cur->children;  | 
13817  | 915k  |     depth++;  | 
13818  |  |     /*  | 
13819  |  |      * Skip DTDs  | 
13820  |  |      */  | 
13821  | 915k  |     if (cur->type != XML_DTD_NODE)  | 
13822  | 915k  |         continue;  | 
13823  | 915k  |       }  | 
13824  | 915k  |   }  | 
13825  |  |  | 
13826  | 1.80M  |   if (cur == limit)  | 
13827  | 40.6k  |       break;  | 
13828  |  |  | 
13829  | 1.76M  |   while (cur->next != NULL) { | 
13830  | 906k  |       cur = cur->next;  | 
13831  | 906k  |       if ((cur->type != XML_ENTITY_DECL) &&  | 
13832  | 906k  |     (cur->type != XML_DTD_NODE))  | 
13833  | 906k  |     goto next_node;  | 
13834  | 906k  |   }  | 
13835  |  |  | 
13836  | 915k  |   do { | 
13837  | 915k  |       cur = cur->parent;  | 
13838  | 915k  |       depth--;  | 
13839  | 915k  |       if ((cur == NULL) || (cur == limit) ||  | 
13840  | 915k  |                 (cur->type == XML_DOCUMENT_NODE))  | 
13841  | 415k  |           goto done;  | 
13842  | 499k  |       if (cur->type == XML_ELEMENT_NODE) { | 
13843  | 499k  |     ret = xmlStreamPop(patstream);  | 
13844  | 499k  |       } else if ((eval_all_nodes) &&  | 
13845  | 0  |     ((cur->type == XML_TEXT_NODE) ||  | 
13846  | 0  |      (cur->type == XML_CDATA_SECTION_NODE) ||  | 
13847  | 0  |      (cur->type == XML_COMMENT_NODE) ||  | 
13848  | 0  |      (cur->type == XML_PI_NODE)))  | 
13849  | 0  |       { | 
13850  | 0  |     ret = xmlStreamPop(patstream);  | 
13851  | 0  |       }  | 
13852  | 499k  |       if (cur->next != NULL) { | 
13853  | 445k  |     cur = cur->next;  | 
13854  | 445k  |     break;  | 
13855  | 445k  |       }  | 
13856  | 499k  |   } while (cur != NULL);  | 
13857  |  |  | 
13858  | 1.36M  |     } while ((cur != NULL) && (depth >= 0));  | 
13859  |  |  | 
13860  | 455k  | done:  | 
13861  |  |  | 
13862  | 455k  |     if (patstream)  | 
13863  | 455k  |   xmlFreeStreamCtxt(patstream);  | 
13864  | 455k  |     return(0);  | 
13865  |  |  | 
13866  | 0  | return_1:  | 
13867  | 0  |     if (patstream)  | 
13868  | 0  |   xmlFreeStreamCtxt(patstream);  | 
13869  | 0  |     return(1);  | 
13870  | 1.78M  | }  | 
13871  |  | #endif /* XPATH_STREAMING */  | 
13872  |  |  | 
13873  |  | /**  | 
13874  |  |  * xmlXPathRunEval:  | 
13875  |  |  * @ctxt:  the XPath parser context with the compiled expression  | 
13876  |  |  * @toBool:  evaluate to a boolean result  | 
13877  |  |  *  | 
13878  |  |  * Evaluate the Precompiled XPath expression in the given context.  | 
13879  |  |  */  | 
13880  |  | static int  | 
13881  |  | xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool)  | 
13882  | 1.75M  | { | 
13883  | 1.75M  |     xmlXPathCompExprPtr comp;  | 
13884  | 1.75M  |     int oldDepth;  | 
13885  |  |  | 
13886  | 1.75M  |     if ((ctxt == NULL) || (ctxt->comp == NULL))  | 
13887  | 0  |   return(-1);  | 
13888  |  |  | 
13889  | 1.75M  |     if (ctxt->valueTab == NULL) { | 
13890  |  |   /* Allocate the value stack */  | 
13891  | 3.94k  |   ctxt->valueTab = (xmlXPathObjectPtr *)  | 
13892  | 3.94k  |        xmlMalloc(10 * sizeof(xmlXPathObjectPtr));  | 
13893  | 3.94k  |   if (ctxt->valueTab == NULL) { | 
13894  | 0  |       xmlXPathPErrMemory(ctxt, "creating evaluation context\n");  | 
13895  | 0  |       return(-1);  | 
13896  | 0  |   }  | 
13897  | 3.94k  |   ctxt->valueNr = 0;  | 
13898  | 3.94k  |   ctxt->valueMax = 10;  | 
13899  | 3.94k  |   ctxt->value = NULL;  | 
13900  | 3.94k  |         ctxt->valueFrame = 0;  | 
13901  | 3.94k  |     }  | 
13902  | 1.75M  | #ifdef XPATH_STREAMING  | 
13903  | 1.75M  |     if (ctxt->comp->stream) { | 
13904  | 584k  |   int res;  | 
13905  |  |  | 
13906  | 584k  |   if (toBool) { | 
13907  |  |       /*  | 
13908  |  |       * Evaluation to boolean result.  | 
13909  |  |       */  | 
13910  | 0  |       res = xmlXPathRunStreamEval(ctxt->context,  | 
13911  | 0  |     ctxt->comp->stream, NULL, 1);  | 
13912  | 0  |       if (res != -1)  | 
13913  | 0  |     return(res);  | 
13914  | 584k  |   } else { | 
13915  | 584k  |       xmlXPathObjectPtr resObj = NULL;  | 
13916  |  |  | 
13917  |  |       /*  | 
13918  |  |       * Evaluation to a sequence.  | 
13919  |  |       */  | 
13920  | 584k  |       res = xmlXPathRunStreamEval(ctxt->context,  | 
13921  | 584k  |     ctxt->comp->stream, &resObj, 0);  | 
13922  |  |  | 
13923  | 584k  |       if ((res != -1) && (resObj != NULL)) { | 
13924  | 584k  |     valuePush(ctxt, resObj);  | 
13925  | 584k  |     return(0);  | 
13926  | 584k  |       }  | 
13927  | 0  |       if (resObj != NULL)  | 
13928  | 0  |     xmlXPathReleaseObject(ctxt->context, resObj);  | 
13929  | 0  |   }  | 
13930  |  |   /*  | 
13931  |  |   * QUESTION TODO: This falls back to normal XPath evaluation  | 
13932  |  |   * if res == -1. Is this intended?  | 
13933  |  |   */  | 
13934  | 584k  |     }  | 
13935  | 1.17M  | #endif  | 
13936  | 1.17M  |     comp = ctxt->comp;  | 
13937  | 1.17M  |     if (comp->last < 0) { | 
13938  | 0  |   xmlGenericError(xmlGenericErrorContext,  | 
13939  | 0  |       "xmlXPathRunEval: last is less than zero\n");  | 
13940  | 0  |   return(-1);  | 
13941  | 0  |     }  | 
13942  | 1.17M  |     oldDepth = ctxt->context->depth;  | 
13943  | 1.17M  |     if (toBool)  | 
13944  | 0  |   return(xmlXPathCompOpEvalToBoolean(ctxt,  | 
13945  | 0  |       &comp->steps[comp->last], 0));  | 
13946  | 1.17M  |     else  | 
13947  | 1.17M  |   xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);  | 
13948  | 1.17M  |     ctxt->context->depth = oldDepth;  | 
13949  |  |  | 
13950  | 1.17M  |     return(0);  | 
13951  | 1.17M  | }  | 
13952  |  |  | 
13953  |  | /************************************************************************  | 
13954  |  |  *                  *  | 
13955  |  |  *      Public interfaces       *  | 
13956  |  |  *                  *  | 
13957  |  |  ************************************************************************/  | 
13958  |  |  | 
13959  |  | /**  | 
13960  |  |  * xmlXPathEvalPredicate:  | 
13961  |  |  * @ctxt:  the XPath context  | 
13962  |  |  * @res:  the Predicate Expression evaluation result  | 
13963  |  |  *  | 
13964  |  |  * Evaluate a predicate result for the current node.  | 
13965  |  |  * A PredicateExpr is evaluated by evaluating the Expr and converting  | 
13966  |  |  * the result to a boolean. If the result is a number, the result will  | 
13967  |  |  * be converted to true if the number is equal to the position of the  | 
13968  |  |  * context node in the context node list (as returned by the position  | 
13969  |  |  * function) and will be converted to false otherwise; if the result  | 
13970  |  |  * is not a number, then the result will be converted as if by a call  | 
13971  |  |  * to the boolean function.  | 
13972  |  |  *  | 
13973  |  |  * Returns 1 if predicate is true, 0 otherwise  | 
13974  |  |  */  | 
13975  |  | int  | 
13976  | 0  | xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) { | 
13977  | 0  |     if ((ctxt == NULL) || (res == NULL)) return(0);  | 
13978  | 0  |     switch (res->type) { | 
13979  | 0  |         case XPATH_BOOLEAN:  | 
13980  | 0  |       return(res->boolval);  | 
13981  | 0  |         case XPATH_NUMBER:  | 
13982  | 0  |       return(res->floatval == ctxt->proximityPosition);  | 
13983  | 0  |         case XPATH_NODESET:  | 
13984  | 0  |         case XPATH_XSLT_TREE:  | 
13985  | 0  |       if (res->nodesetval == NULL)  | 
13986  | 0  |     return(0);  | 
13987  | 0  |       return(res->nodesetval->nodeNr != 0);  | 
13988  | 0  |         case XPATH_STRING:  | 
13989  | 0  |       return((res->stringval != NULL) &&  | 
13990  | 0  |              (xmlStrlen(res->stringval) != 0));  | 
13991  | 0  |         default:  | 
13992  | 0  |       STRANGE  | 
13993  | 0  |     }  | 
13994  | 0  |     return(0);  | 
13995  | 0  | }  | 
13996  |  |  | 
13997  |  | /**  | 
13998  |  |  * xmlXPathEvaluatePredicateResult:  | 
13999  |  |  * @ctxt:  the XPath Parser context  | 
14000  |  |  * @res:  the Predicate Expression evaluation result  | 
14001  |  |  *  | 
14002  |  |  * Evaluate a predicate result for the current node.  | 
14003  |  |  * A PredicateExpr is evaluated by evaluating the Expr and converting  | 
14004  |  |  * the result to a boolean. If the result is a number, the result will  | 
14005  |  |  * be converted to true if the number is equal to the position of the  | 
14006  |  |  * context node in the context node list (as returned by the position  | 
14007  |  |  * function) and will be converted to false otherwise; if the result  | 
14008  |  |  * is not a number, then the result will be converted as if by a call  | 
14009  |  |  * to the boolean function.  | 
14010  |  |  *  | 
14011  |  |  * Returns 1 if predicate is true, 0 otherwise  | 
14012  |  |  */  | 
14013  |  | int  | 
14014  |  | xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,  | 
14015  | 3.31M  |                                 xmlXPathObjectPtr res) { | 
14016  | 3.31M  |     if ((ctxt == NULL) || (res == NULL)) return(0);  | 
14017  | 3.31M  |     switch (res->type) { | 
14018  | 0  |         case XPATH_BOOLEAN:  | 
14019  | 0  |       return(res->boolval);  | 
14020  | 939k  |         case XPATH_NUMBER:  | 
14021  |  | #if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))  | 
14022  |  |       return((res->floatval == ctxt->context->proximityPosition) &&  | 
14023  |  |              (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/  | 
14024  |  | #else  | 
14025  | 939k  |       return(res->floatval == ctxt->context->proximityPosition);  | 
14026  | 0  | #endif  | 
14027  | 2.28M  |         case XPATH_NODESET:  | 
14028  | 2.28M  |         case XPATH_XSLT_TREE:  | 
14029  | 2.28M  |       if (res->nodesetval == NULL)  | 
14030  | 207k  |     return(0);  | 
14031  | 2.07M  |       return(res->nodesetval->nodeNr != 0);  | 
14032  | 96.4k  |         case XPATH_STRING:  | 
14033  | 96.4k  |       return((res->stringval != NULL) && (res->stringval[0] != 0));  | 
14034  |  | #ifdef LIBXML_XPTR_LOCS_ENABLED  | 
14035  |  |   case XPATH_LOCATIONSET:{ | 
14036  |  |       xmlLocationSetPtr ptr = res->user;  | 
14037  |  |       if (ptr == NULL)  | 
14038  |  |           return(0);  | 
14039  |  |       return (ptr->locNr != 0);  | 
14040  |  |       }  | 
14041  |  | #endif  | 
14042  | 43  |         default:  | 
14043  | 43  |       STRANGE  | 
14044  | 3.31M  |     }  | 
14045  | 43  |     return(0);  | 
14046  | 3.31M  | }  | 
14047  |  |  | 
14048  |  | #ifdef XPATH_STREAMING  | 
14049  |  | /**  | 
14050  |  |  * xmlXPathTryStreamCompile:  | 
14051  |  |  * @ctxt: an XPath context  | 
14052  |  |  * @str:  the XPath expression  | 
14053  |  |  *  | 
14054  |  |  * Try to compile the XPath expression as a streamable subset.  | 
14055  |  |  *  | 
14056  |  |  * Returns the compiled expression or NULL if failed to compile.  | 
14057  |  |  */  | 
14058  |  | static xmlXPathCompExprPtr  | 
14059  | 1.35M  | xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) { | 
14060  |  |     /*  | 
14061  |  |      * Optimization: use streaming patterns when the XPath expression can  | 
14062  |  |      * be compiled to a stream lookup  | 
14063  |  |      */  | 
14064  | 1.35M  |     xmlPatternPtr stream;  | 
14065  | 1.35M  |     xmlXPathCompExprPtr comp;  | 
14066  | 1.35M  |     xmlDictPtr dict = NULL;  | 
14067  | 1.35M  |     const xmlChar **namespaces = NULL;  | 
14068  | 1.35M  |     xmlNsPtr ns;  | 
14069  | 1.35M  |     int i, j;  | 
14070  |  |  | 
14071  | 1.35M  |     if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) && | 
14072  | 1.35M  |         (!xmlStrchr(str, '@'))) { | 
14073  | 593k  |   const xmlChar *tmp;  | 
14074  |  |  | 
14075  |  |   /*  | 
14076  |  |    * We don't try to handle expressions using the verbose axis  | 
14077  |  |    * specifiers ("::"), just the simplified form at this point. | 
14078  |  |    * Additionally, if there is no list of namespaces available and  | 
14079  |  |    *  there's a ":" in the expression, indicating a prefixed QName,  | 
14080  |  |    *  then we won't try to compile either. xmlPatterncompile() needs  | 
14081  |  |    *  to have a list of namespaces at compilation time in order to  | 
14082  |  |    *  compile prefixed name tests.  | 
14083  |  |    */  | 
14084  | 593k  |   tmp = xmlStrchr(str, ':');  | 
14085  | 593k  |   if ((tmp != NULL) &&  | 
14086  | 593k  |       ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':')))  | 
14087  | 144k  |       return(NULL);  | 
14088  |  |  | 
14089  | 448k  |   if (ctxt != NULL) { | 
14090  | 448k  |       dict = ctxt->dict;  | 
14091  | 448k  |       if (ctxt->nsNr > 0) { | 
14092  | 0  |     namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*));  | 
14093  | 0  |     if (namespaces == NULL) { | 
14094  | 0  |         xmlXPathErrMemory(ctxt, "allocating namespaces array\n");  | 
14095  | 0  |         return(NULL);  | 
14096  | 0  |     }  | 
14097  | 0  |     for (i = 0, j = 0; (j < ctxt->nsNr); j++) { | 
14098  | 0  |         ns = ctxt->namespaces[j];  | 
14099  | 0  |         namespaces[i++] = ns->href;  | 
14100  | 0  |         namespaces[i++] = ns->prefix;  | 
14101  | 0  |     }  | 
14102  | 0  |     namespaces[i++] = NULL;  | 
14103  | 0  |     namespaces[i] = NULL;  | 
14104  | 0  |       }  | 
14105  | 448k  |   }  | 
14106  |  |  | 
14107  | 448k  |   stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH, namespaces);  | 
14108  | 448k  |   if (namespaces != NULL) { | 
14109  | 0  |       xmlFree((xmlChar **)namespaces);  | 
14110  | 0  |   }  | 
14111  | 448k  |   if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) { | 
14112  | 95.4k  |       comp = xmlXPathNewCompExpr();  | 
14113  | 95.4k  |       if (comp == NULL) { | 
14114  | 0  |     xmlXPathErrMemory(ctxt, "allocating streamable expression\n");  | 
14115  | 0  |     return(NULL);  | 
14116  | 0  |       }  | 
14117  | 95.4k  |       comp->stream = stream;  | 
14118  | 95.4k  |       comp->dict = dict;  | 
14119  | 95.4k  |       if (comp->dict)  | 
14120  | 0  |     xmlDictReference(comp->dict);  | 
14121  | 95.4k  |       return(comp);  | 
14122  | 95.4k  |   }  | 
14123  | 353k  |   xmlFreePattern(stream);  | 
14124  | 353k  |     }  | 
14125  | 1.11M  |     return(NULL);  | 
14126  | 1.35M  | }  | 
14127  |  | #endif /* XPATH_STREAMING */  | 
14128  |  |  | 
14129  |  | static void  | 
14130  |  | xmlXPathOptimizeExpression(xmlXPathParserContextPtr pctxt,  | 
14131  |  |                            xmlXPathStepOpPtr op)  | 
14132  | 9.19M  | { | 
14133  | 9.19M  |     xmlXPathCompExprPtr comp = pctxt->comp;  | 
14134  | 9.19M  |     xmlXPathContextPtr ctxt;  | 
14135  |  |  | 
14136  |  |     /*  | 
14137  |  |     * Try to rewrite "descendant-or-self::node()/foo" to an optimized  | 
14138  |  |     * internal representation.  | 
14139  |  |     */  | 
14140  |  |  | 
14141  | 9.19M  |     if ((op->op == XPATH_OP_COLLECT /* 11 */) &&  | 
14142  | 9.19M  |         (op->ch1 != -1) &&  | 
14143  | 9.19M  |         (op->ch2 == -1 /* no predicate */))  | 
14144  | 2.59M  |     { | 
14145  | 2.59M  |         xmlXPathStepOpPtr prevop = &comp->steps[op->ch1];  | 
14146  |  |  | 
14147  | 2.59M  |         if ((prevop->op == XPATH_OP_COLLECT /* 11 */) &&  | 
14148  | 2.59M  |             ((xmlXPathAxisVal) prevop->value ==  | 
14149  | 1.09M  |                 AXIS_DESCENDANT_OR_SELF) &&  | 
14150  | 2.59M  |             (prevop->ch2 == -1) &&  | 
14151  | 2.59M  |             ((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) &&  | 
14152  | 2.59M  |             ((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE))  | 
14153  | 529k  |         { | 
14154  |  |             /*  | 
14155  |  |             * This is a "descendant-or-self::node()" without predicates.  | 
14156  |  |             * Try to eliminate it.  | 
14157  |  |             */  | 
14158  |  |  | 
14159  | 529k  |             switch ((xmlXPathAxisVal) op->value) { | 
14160  | 445k  |                 case AXIS_CHILD:  | 
14161  | 447k  |                 case AXIS_DESCENDANT:  | 
14162  |  |                     /*  | 
14163  |  |                     * Convert "descendant-or-self::node()/child::" or  | 
14164  |  |                     * "descendant-or-self::node()/descendant::" to  | 
14165  |  |                     * "descendant::"  | 
14166  |  |                     */  | 
14167  | 447k  |                     op->ch1   = prevop->ch1;  | 
14168  | 447k  |                     op->value = AXIS_DESCENDANT;  | 
14169  | 447k  |                     break;  | 
14170  | 1.65k  |                 case AXIS_SELF:  | 
14171  | 15.4k  |                 case AXIS_DESCENDANT_OR_SELF:  | 
14172  |  |                     /*  | 
14173  |  |                     * Convert "descendant-or-self::node()/self::" or  | 
14174  |  |                     * "descendant-or-self::node()/descendant-or-self::" to  | 
14175  |  |                     * to "descendant-or-self::"  | 
14176  |  |                     */  | 
14177  | 15.4k  |                     op->ch1   = prevop->ch1;  | 
14178  | 15.4k  |                     op->value = AXIS_DESCENDANT_OR_SELF;  | 
14179  | 15.4k  |                     break;  | 
14180  | 66.4k  |                 default:  | 
14181  | 66.4k  |                     break;  | 
14182  | 529k  |             }  | 
14183  | 529k  |   }  | 
14184  | 2.59M  |     }  | 
14185  |  |  | 
14186  |  |     /* OP_VALUE has invalid ch1. */  | 
14187  | 9.19M  |     if (op->op == XPATH_OP_VALUE)  | 
14188  | 759k  |         return;  | 
14189  |  |  | 
14190  |  |     /* Recurse */  | 
14191  | 8.43M  |     ctxt = pctxt->context;  | 
14192  | 8.43M  |     if (ctxt != NULL) { | 
14193  | 8.43M  |         if (ctxt->depth >= XPATH_MAX_RECURSION_DEPTH)  | 
14194  | 1.22k  |             return;  | 
14195  | 8.43M  |         ctxt->depth += 1;  | 
14196  | 8.43M  |     }  | 
14197  | 8.43M  |     if (op->ch1 != -1)  | 
14198  | 6.06M  |         xmlXPathOptimizeExpression(pctxt, &comp->steps[op->ch1]);  | 
14199  | 8.43M  |     if (op->ch2 != -1)  | 
14200  | 2.82M  |   xmlXPathOptimizeExpression(pctxt, &comp->steps[op->ch2]);  | 
14201  | 8.43M  |     if (ctxt != NULL)  | 
14202  | 8.43M  |         ctxt->depth -= 1;  | 
14203  | 8.43M  | }  | 
14204  |  |  | 
14205  |  | /**  | 
14206  |  |  * xmlXPathCtxtCompile:  | 
14207  |  |  * @ctxt: an XPath context  | 
14208  |  |  * @str:  the XPath expression  | 
14209  |  |  *  | 
14210  |  |  * Compile an XPath expression  | 
14211  |  |  *  | 
14212  |  |  * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.  | 
14213  |  |  *         the caller has to free the object.  | 
14214  |  |  */  | 
14215  |  | xmlXPathCompExprPtr  | 
14216  | 1.35M  | xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) { | 
14217  | 1.35M  |     xmlXPathParserContextPtr pctxt;  | 
14218  | 1.35M  |     xmlXPathCompExprPtr comp;  | 
14219  | 1.35M  |     int oldDepth = 0;  | 
14220  |  |  | 
14221  | 1.35M  | #ifdef XPATH_STREAMING  | 
14222  | 1.35M  |     comp = xmlXPathTryStreamCompile(ctxt, str);  | 
14223  | 1.35M  |     if (comp != NULL)  | 
14224  | 95.3k  |         return(comp);  | 
14225  | 1.25M  | #endif  | 
14226  |  |  | 
14227  | 1.25M  |     xmlInitParser();  | 
14228  |  |  | 
14229  | 1.25M  |     pctxt = xmlXPathNewParserContext(str, ctxt);  | 
14230  | 1.25M  |     if (pctxt == NULL)  | 
14231  | 0  |         return NULL;  | 
14232  | 1.25M  |     if (ctxt != NULL)  | 
14233  | 1.25M  |         oldDepth = ctxt->depth;  | 
14234  | 1.25M  |     xmlXPathCompileExpr(pctxt, 1);  | 
14235  | 1.25M  |     if (ctxt != NULL)  | 
14236  | 1.25M  |         ctxt->depth = oldDepth;  | 
14237  |  |  | 
14238  | 1.25M  |     if( pctxt->error != XPATH_EXPRESSION_OK )  | 
14239  | 565k  |     { | 
14240  | 565k  |         xmlXPathFreeParserContext(pctxt);  | 
14241  | 565k  |         return(NULL);  | 
14242  | 565k  |     }  | 
14243  |  |  | 
14244  | 689k  |     if (*pctxt->cur != 0) { | 
14245  |  |   /*  | 
14246  |  |    * aleksey: in some cases this line prints *second* error message  | 
14247  |  |    * (see bug #78858) and probably this should be fixed.  | 
14248  |  |    * However, we are not sure that all error messages are printed  | 
14249  |  |    * out in other places. It's not critical so we leave it as-is for now  | 
14250  |  |    */  | 
14251  | 337k  |   xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);  | 
14252  | 337k  |   comp = NULL;  | 
14253  | 351k  |     } else { | 
14254  | 351k  |   comp = pctxt->comp;  | 
14255  | 351k  |   if ((comp->nbStep > 1) && (comp->last >= 0)) { | 
14256  | 301k  |             if (ctxt != NULL)  | 
14257  | 301k  |                 oldDepth = ctxt->depth;  | 
14258  | 301k  |       xmlXPathOptimizeExpression(pctxt, &comp->steps[comp->last]);  | 
14259  | 301k  |             if (ctxt != NULL)  | 
14260  | 301k  |                 ctxt->depth = oldDepth;  | 
14261  | 301k  |   }  | 
14262  | 351k  |   pctxt->comp = NULL;  | 
14263  | 351k  |     }  | 
14264  | 689k  |     xmlXPathFreeParserContext(pctxt);  | 
14265  |  |  | 
14266  | 689k  |     if (comp != NULL) { | 
14267  | 351k  |   comp->expr = xmlStrdup(str);  | 
14268  |  | #ifdef DEBUG_EVAL_COUNTS  | 
14269  |  |   comp->string = xmlStrdup(str);  | 
14270  |  |   comp->nb = 0;  | 
14271  |  | #endif  | 
14272  | 351k  |     }  | 
14273  | 689k  |     return(comp);  | 
14274  | 1.25M  | }  | 
14275  |  |  | 
14276  |  | /**  | 
14277  |  |  * xmlXPathCompile:  | 
14278  |  |  * @str:  the XPath expression  | 
14279  |  |  *  | 
14280  |  |  * Compile an XPath expression  | 
14281  |  |  *  | 
14282  |  |  * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.  | 
14283  |  |  *         the caller has to free the object.  | 
14284  |  |  */  | 
14285  |  | xmlXPathCompExprPtr  | 
14286  | 0  | xmlXPathCompile(const xmlChar *str) { | 
14287  | 0  |     return(xmlXPathCtxtCompile(NULL, str));  | 
14288  | 0  | }  | 
14289  |  |  | 
14290  |  | /**  | 
14291  |  |  * xmlXPathCompiledEvalInternal:  | 
14292  |  |  * @comp:  the compiled XPath expression  | 
14293  |  |  * @ctxt:  the XPath context  | 
14294  |  |  * @resObj: the resulting XPath object or NULL  | 
14295  |  |  * @toBool: 1 if only a boolean result is requested  | 
14296  |  |  *  | 
14297  |  |  * Evaluate the Precompiled XPath expression in the given context.  | 
14298  |  |  * The caller has to free @resObj.  | 
14299  |  |  *  | 
14300  |  |  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.  | 
14301  |  |  *         the caller has to free the object.  | 
14302  |  |  */  | 
14303  |  | static int  | 
14304  |  | xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,  | 
14305  |  |            xmlXPathContextPtr ctxt,  | 
14306  |  |            xmlXPathObjectPtr *resObjPtr,  | 
14307  |  |            int toBool)  | 
14308  | 1.75M  | { | 
14309  | 1.75M  |     xmlXPathParserContextPtr pctxt;  | 
14310  | 1.75M  |     xmlXPathObjectPtr resObj;  | 
14311  |  | #ifndef LIBXML_THREAD_ENABLED  | 
14312  |  |     static int reentance = 0;  | 
14313  |  | #endif  | 
14314  | 1.75M  |     int res;  | 
14315  |  |  | 
14316  | 1.75M  |     CHECK_CTXT_NEG(ctxt)  | 
14317  |  |  | 
14318  | 1.75M  |     if (comp == NULL)  | 
14319  | 0  |   return(-1);  | 
14320  | 1.75M  |     xmlInitParser();  | 
14321  |  |  | 
14322  |  | #ifndef LIBXML_THREAD_ENABLED  | 
14323  |  |     reentance++;  | 
14324  |  |     if (reentance > 1)  | 
14325  |  |   xmlXPathDisableOptimizer = 1;  | 
14326  |  | #endif  | 
14327  |  |  | 
14328  |  | #ifdef DEBUG_EVAL_COUNTS  | 
14329  |  |     comp->nb++;  | 
14330  |  |     if ((comp->string != NULL) && (comp->nb > 100)) { | 
14331  |  |   fprintf(stderr, "100 x %s\n", comp->string);  | 
14332  |  |   comp->nb = 0;  | 
14333  |  |     }  | 
14334  |  | #endif  | 
14335  | 1.75M  |     pctxt = xmlXPathCompParserContext(comp, ctxt);  | 
14336  | 1.75M  |     res = xmlXPathRunEval(pctxt, toBool);  | 
14337  |  |  | 
14338  | 1.75M  |     if (pctxt->error != XPATH_EXPRESSION_OK) { | 
14339  | 277k  |         resObj = NULL;  | 
14340  | 1.47M  |     } else { | 
14341  | 1.47M  |         resObj = valuePop(pctxt);  | 
14342  | 1.47M  |         if (resObj == NULL) { | 
14343  | 0  |             if (!toBool)  | 
14344  | 0  |                 xmlGenericError(xmlGenericErrorContext,  | 
14345  | 0  |                     "xmlXPathCompiledEval: No result on the stack.\n");  | 
14346  | 1.47M  |         } else if (pctxt->valueNr > 0) { | 
14347  | 0  |             xmlGenericError(xmlGenericErrorContext,  | 
14348  | 0  |                 "xmlXPathCompiledEval: %d object(s) left on the stack.\n",  | 
14349  | 0  |                 pctxt->valueNr);  | 
14350  | 0  |         }  | 
14351  | 1.47M  |     }  | 
14352  |  |  | 
14353  | 1.75M  |     if (resObjPtr)  | 
14354  | 1.75M  |         *resObjPtr = resObj;  | 
14355  | 1  |     else  | 
14356  | 1  |         xmlXPathReleaseObject(ctxt, resObj);  | 
14357  |  |  | 
14358  | 1.75M  |     pctxt->comp = NULL;  | 
14359  | 1.75M  |     xmlXPathFreeParserContext(pctxt);  | 
14360  |  | #ifndef LIBXML_THREAD_ENABLED  | 
14361  |  |     reentance--;  | 
14362  |  | #endif  | 
14363  |  |  | 
14364  | 1.75M  |     return(res);  | 
14365  | 1.75M  | }  | 
14366  |  |  | 
14367  |  | /**  | 
14368  |  |  * xmlXPathCompiledEval:  | 
14369  |  |  * @comp:  the compiled XPath expression  | 
14370  |  |  * @ctx:  the XPath context  | 
14371  |  |  *  | 
14372  |  |  * Evaluate the Precompiled XPath expression in the given context.  | 
14373  |  |  *  | 
14374  |  |  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.  | 
14375  |  |  *         the caller has to free the object.  | 
14376  |  |  */  | 
14377  |  | xmlXPathObjectPtr  | 
14378  |  | xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx)  | 
14379  | 1.75M  | { | 
14380  | 1.75M  |     xmlXPathObjectPtr res = NULL;  | 
14381  |  |  | 
14382  | 1.75M  |     xmlXPathCompiledEvalInternal(comp, ctx, &res, 0);  | 
14383  | 1.75M  |     return(res);  | 
14384  | 1.75M  | }  | 
14385  |  |  | 
14386  |  | /**  | 
14387  |  |  * xmlXPathCompiledEvalToBoolean:  | 
14388  |  |  * @comp:  the compiled XPath expression  | 
14389  |  |  * @ctxt:  the XPath context  | 
14390  |  |  *  | 
14391  |  |  * Applies the XPath boolean() function on the result of the given  | 
14392  |  |  * compiled expression.  | 
14393  |  |  *  | 
14394  |  |  * Returns 1 if the expression evaluated to true, 0 if to false and  | 
14395  |  |  *         -1 in API and internal errors.  | 
14396  |  |  */  | 
14397  |  | int  | 
14398  |  | xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp,  | 
14399  |  |             xmlXPathContextPtr ctxt)  | 
14400  | 0  | { | 
14401  | 0  |     return(xmlXPathCompiledEvalInternal(comp, ctxt, NULL, 1));  | 
14402  | 0  | }  | 
14403  |  |  | 
14404  |  | /**  | 
14405  |  |  * xmlXPathEvalExpr:  | 
14406  |  |  * @ctxt:  the XPath Parser context  | 
14407  |  |  *  | 
14408  |  |  * Parse and evaluate an XPath expression in the given context,  | 
14409  |  |  * then push the result on the context stack  | 
14410  |  |  */  | 
14411  |  | void  | 
14412  | 4.05k  | xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) { | 
14413  | 4.05k  | #ifdef XPATH_STREAMING  | 
14414  | 4.05k  |     xmlXPathCompExprPtr comp;  | 
14415  | 4.05k  | #endif  | 
14416  | 4.05k  |     int oldDepth = 0;  | 
14417  |  |  | 
14418  | 4.05k  |     if (ctxt == NULL) return;  | 
14419  |  |  | 
14420  | 4.05k  | #ifdef XPATH_STREAMING  | 
14421  | 4.05k  |     comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base);  | 
14422  | 4.05k  |     if (comp != NULL) { | 
14423  | 126  |         if (ctxt->comp != NULL)  | 
14424  | 126  |       xmlXPathFreeCompExpr(ctxt->comp);  | 
14425  | 126  |         ctxt->comp = comp;  | 
14426  | 126  |     } else  | 
14427  | 3.92k  | #endif  | 
14428  | 3.92k  |     { | 
14429  | 3.92k  |         if (ctxt->context != NULL)  | 
14430  | 3.92k  |             oldDepth = ctxt->context->depth;  | 
14431  | 3.92k  |   xmlXPathCompileExpr(ctxt, 1);  | 
14432  | 3.92k  |         if (ctxt->context != NULL)  | 
14433  | 3.92k  |             ctxt->context->depth = oldDepth;  | 
14434  | 3.92k  |         CHECK_ERROR;  | 
14435  |  |  | 
14436  |  |         /* Check for trailing characters. */  | 
14437  | 3.88k  |         if (*ctxt->cur != 0)  | 
14438  | 3.81k  |             XP_ERROR(XPATH_EXPR_ERROR);  | 
14439  |  |  | 
14440  | 3.81k  |   if ((ctxt->comp->nbStep > 1) && (ctxt->comp->last >= 0)) { | 
14441  | 3.79k  |             if (ctxt->context != NULL)  | 
14442  | 3.79k  |                 oldDepth = ctxt->context->depth;  | 
14443  | 3.79k  |       xmlXPathOptimizeExpression(ctxt,  | 
14444  | 3.79k  |     &ctxt->comp->steps[ctxt->comp->last]);  | 
14445  | 3.79k  |             if (ctxt->context != NULL)  | 
14446  | 3.79k  |                 ctxt->context->depth = oldDepth;  | 
14447  | 3.79k  |         }  | 
14448  | 3.81k  |     }  | 
14449  |  |  | 
14450  | 3.94k  |     xmlXPathRunEval(ctxt, 0);  | 
14451  | 3.94k  | }  | 
14452  |  |  | 
14453  |  | /**  | 
14454  |  |  * xmlXPathEval:  | 
14455  |  |  * @str:  the XPath expression  | 
14456  |  |  * @ctx:  the XPath context  | 
14457  |  |  *  | 
14458  |  |  * Evaluate the XPath Location Path in the given context.  | 
14459  |  |  *  | 
14460  |  |  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.  | 
14461  |  |  *         the caller has to free the object.  | 
14462  |  |  */  | 
14463  |  | xmlXPathObjectPtr  | 
14464  | 4.05k  | xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) { | 
14465  | 4.05k  |     xmlXPathParserContextPtr ctxt;  | 
14466  | 4.05k  |     xmlXPathObjectPtr res;  | 
14467  |  |  | 
14468  | 4.05k  |     CHECK_CTXT(ctx)  | 
14469  |  |  | 
14470  | 4.05k  |     xmlInitParser();  | 
14471  |  |  | 
14472  | 4.05k  |     ctxt = xmlXPathNewParserContext(str, ctx);  | 
14473  | 4.05k  |     if (ctxt == NULL)  | 
14474  | 0  |         return NULL;  | 
14475  | 4.05k  |     xmlXPathEvalExpr(ctxt);  | 
14476  |  |  | 
14477  | 4.05k  |     if (ctxt->error != XPATH_EXPRESSION_OK) { | 
14478  | 173  |   res = NULL;  | 
14479  | 3.87k  |     } else { | 
14480  | 3.87k  |   res = valuePop(ctxt);  | 
14481  | 3.87k  |         if (res == NULL) { | 
14482  | 0  |             xmlGenericError(xmlGenericErrorContext,  | 
14483  | 0  |                 "xmlXPathCompiledEval: No result on the stack.\n");  | 
14484  | 3.87k  |         } else if (ctxt->valueNr > 0) { | 
14485  | 0  |             xmlGenericError(xmlGenericErrorContext,  | 
14486  | 0  |                 "xmlXPathCompiledEval: %d object(s) left on the stack.\n",  | 
14487  | 0  |                 ctxt->valueNr);  | 
14488  | 0  |         }  | 
14489  | 3.87k  |     }  | 
14490  |  |  | 
14491  | 4.05k  |     xmlXPathFreeParserContext(ctxt);  | 
14492  | 4.05k  |     return(res);  | 
14493  | 4.05k  | }  | 
14494  |  |  | 
14495  |  | /**  | 
14496  |  |  * xmlXPathSetContextNode:  | 
14497  |  |  * @node: the node to to use as the context node  | 
14498  |  |  * @ctx:  the XPath context  | 
14499  |  |  *  | 
14500  |  |  * Sets 'node' as the context node. The node must be in the same  | 
14501  |  |  * document as that associated with the context.  | 
14502  |  |  *  | 
14503  |  |  * Returns -1 in case of error or 0 if successful  | 
14504  |  |  */  | 
14505  |  | int  | 
14506  | 0  | xmlXPathSetContextNode(xmlNodePtr node, xmlXPathContextPtr ctx) { | 
14507  | 0  |     if ((node == NULL) || (ctx == NULL))  | 
14508  | 0  |         return(-1);  | 
14509  |  |  | 
14510  | 0  |     if (node->doc == ctx->doc) { | 
14511  | 0  |         ctx->node = node;  | 
14512  | 0  |   return(0);  | 
14513  | 0  |     }  | 
14514  | 0  |     return(-1);  | 
14515  | 0  | }  | 
14516  |  |  | 
14517  |  | /**  | 
14518  |  |  * xmlXPathNodeEval:  | 
14519  |  |  * @node: the node to to use as the context node  | 
14520  |  |  * @str:  the XPath expression  | 
14521  |  |  * @ctx:  the XPath context  | 
14522  |  |  *  | 
14523  |  |  * Evaluate the XPath Location Path in the given context. The node 'node'  | 
14524  |  |  * is set as the context node. The context node is not restored.  | 
14525  |  |  *  | 
14526  |  |  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.  | 
14527  |  |  *         the caller has to free the object.  | 
14528  |  |  */  | 
14529  |  | xmlXPathObjectPtr  | 
14530  | 0  | xmlXPathNodeEval(xmlNodePtr node, const xmlChar *str, xmlXPathContextPtr ctx) { | 
14531  | 0  |     if (str == NULL)  | 
14532  | 0  |         return(NULL);  | 
14533  | 0  |     if (xmlXPathSetContextNode(node, ctx) < 0)  | 
14534  | 0  |         return(NULL);  | 
14535  | 0  |     return(xmlXPathEval(str, ctx));  | 
14536  | 0  | }  | 
14537  |  |  | 
14538  |  | /**  | 
14539  |  |  * xmlXPathEvalExpression:  | 
14540  |  |  * @str:  the XPath expression  | 
14541  |  |  * @ctxt:  the XPath context  | 
14542  |  |  *  | 
14543  |  |  * Alias for xmlXPathEval().  | 
14544  |  |  *  | 
14545  |  |  * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.  | 
14546  |  |  *         the caller has to free the object.  | 
14547  |  |  */  | 
14548  |  | xmlXPathObjectPtr  | 
14549  | 0  | xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) { | 
14550  | 0  |     return(xmlXPathEval(str, ctxt));  | 
14551  | 0  | }  | 
14552  |  |  | 
14553  |  | /************************************************************************  | 
14554  |  |  *                  *  | 
14555  |  |  *  Extra functions not pertaining to the XPath spec    *  | 
14556  |  |  *                  *  | 
14557  |  |  ************************************************************************/  | 
14558  |  | /**  | 
14559  |  |  * xmlXPathEscapeUriFunction:  | 
14560  |  |  * @ctxt:  the XPath Parser context  | 
14561  |  |  * @nargs:  the number of arguments  | 
14562  |  |  *  | 
14563  |  |  * Implement the escape-uri() XPath function  | 
14564  |  |  *    string escape-uri(string $str, bool $escape-reserved)  | 
14565  |  |  *  | 
14566  |  |  * This function applies the URI escaping rules defined in section 2 of [RFC  | 
14567  |  |  * 2396] to the string supplied as $uri-part, which typically represents all  | 
14568  |  |  * or part of a URI. The effect of the function is to replace any special  | 
14569  |  |  * character in the string by an escape sequence of the form %xx%yy...,  | 
14570  |  |  * where xxyy... is the hexadecimal representation of the octets used to  | 
14571  |  |  * represent the character in UTF-8.  | 
14572  |  |  *  | 
14573  |  |  * The set of characters that are escaped depends on the setting of the  | 
14574  |  |  * boolean argument $escape-reserved.  | 
14575  |  |  *  | 
14576  |  |  * If $escape-reserved is true, all characters are escaped other than lower  | 
14577  |  |  * case letters a-z, upper case letters A-Z, digits 0-9, and the characters  | 
14578  |  |  * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"  | 
14579  |  |  * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only | 
14580  |  |  * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and  | 
14581  |  |  * A-F).  | 
14582  |  |  *  | 
14583  |  |  * If $escape-reserved is false, the behavior differs in that characters  | 
14584  |  |  * referred to in [RFC 2396] as reserved characters are not escaped. These  | 
14585  |  |  * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".  | 
14586  |  |  *  | 
14587  |  |  * [RFC 2396] does not define whether escaped URIs should use lower case or  | 
14588  |  |  * upper case for hexadecimal digits. To ensure that escaped URIs can be  | 
14589  |  |  * compared using string comparison functions, this function must always use  | 
14590  |  |  * the upper-case letters A-F.  | 
14591  |  |  *  | 
14592  |  |  * Generally, $escape-reserved should be set to true when escaping a string  | 
14593  |  |  * that is to form a single part of a URI, and to false when escaping an  | 
14594  |  |  * entire URI or URI reference.  | 
14595  |  |  *  | 
14596  |  |  * In the case of non-ascii characters, the string is encoded according to  | 
14597  |  |  * utf-8 and then converted according to RFC 2396.  | 
14598  |  |  *  | 
14599  |  |  * Examples  | 
14600  |  |  *  xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true()) | 
14601  |  |  *  returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"  | 
14602  |  |  *  xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false()) | 
14603  |  |  *  returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"  | 
14604  |  |  *  | 
14605  |  |  */  | 
14606  |  | static void  | 
14607  | 0  | xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) { | 
14608  | 0  |     xmlXPathObjectPtr str;  | 
14609  | 0  |     int escape_reserved;  | 
14610  | 0  |     xmlBufPtr target;  | 
14611  | 0  |     xmlChar *cptr;  | 
14612  | 0  |     xmlChar escape[4];  | 
14613  |  | 
  | 
14614  | 0  |     CHECK_ARITY(2);  | 
14615  |  | 
  | 
14616  | 0  |     escape_reserved = xmlXPathPopBoolean(ctxt);  | 
14617  |  | 
  | 
14618  | 0  |     CAST_TO_STRING;  | 
14619  | 0  |     str = valuePop(ctxt);  | 
14620  |  | 
  | 
14621  | 0  |     target = xmlBufCreate();  | 
14622  |  | 
  | 
14623  | 0  |     escape[0] = '%';  | 
14624  | 0  |     escape[3] = 0;  | 
14625  |  | 
  | 
14626  | 0  |     if (target) { | 
14627  | 0  |   for (cptr = str->stringval; *cptr; cptr++) { | 
14628  | 0  |       if ((*cptr >= 'A' && *cptr <= 'Z') ||  | 
14629  | 0  |     (*cptr >= 'a' && *cptr <= 'z') ||  | 
14630  | 0  |     (*cptr >= '0' && *cptr <= '9') ||  | 
14631  | 0  |     *cptr == '-' || *cptr == '_' || *cptr == '.' ||  | 
14632  | 0  |     *cptr == '!' || *cptr == '~' || *cptr == '*' ||  | 
14633  | 0  |     *cptr == '\''|| *cptr == '(' || *cptr == ')' || | 
14634  | 0  |     (*cptr == '%' &&  | 
14635  | 0  |      ((cptr[1] >= 'A' && cptr[1] <= 'F') ||  | 
14636  | 0  |       (cptr[1] >= 'a' && cptr[1] <= 'f') ||  | 
14637  | 0  |       (cptr[1] >= '0' && cptr[1] <= '9')) &&  | 
14638  | 0  |      ((cptr[2] >= 'A' && cptr[2] <= 'F') ||  | 
14639  | 0  |       (cptr[2] >= 'a' && cptr[2] <= 'f') ||  | 
14640  | 0  |       (cptr[2] >= '0' && cptr[2] <= '9'))) ||  | 
14641  | 0  |     (!escape_reserved &&  | 
14642  | 0  |      (*cptr == ';' || *cptr == '/' || *cptr == '?' ||  | 
14643  | 0  |       *cptr == ':' || *cptr == '@' || *cptr == '&' ||  | 
14644  | 0  |       *cptr == '=' || *cptr == '+' || *cptr == '$' ||  | 
14645  | 0  |       *cptr == ','))) { | 
14646  | 0  |     xmlBufAdd(target, cptr, 1);  | 
14647  | 0  |       } else { | 
14648  | 0  |     if ((*cptr >> 4) < 10)  | 
14649  | 0  |         escape[1] = '0' + (*cptr >> 4);  | 
14650  | 0  |     else  | 
14651  | 0  |         escape[1] = 'A' - 10 + (*cptr >> 4);  | 
14652  | 0  |     if ((*cptr & 0xF) < 10)  | 
14653  | 0  |         escape[2] = '0' + (*cptr & 0xF);  | 
14654  | 0  |     else  | 
14655  | 0  |         escape[2] = 'A' - 10 + (*cptr & 0xF);  | 
14656  |  | 
  | 
14657  | 0  |     xmlBufAdd(target, &escape[0], 3);  | 
14658  | 0  |       }  | 
14659  | 0  |   }  | 
14660  | 0  |     }  | 
14661  | 0  |     valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,  | 
14662  | 0  |   xmlBufContent(target)));  | 
14663  | 0  |     xmlBufFree(target);  | 
14664  | 0  |     xmlXPathReleaseObject(ctxt->context, str);  | 
14665  | 0  | }  | 
14666  |  |  | 
14667  |  | /**  | 
14668  |  |  * xmlXPathRegisterAllFunctions:  | 
14669  |  |  * @ctxt:  the XPath context  | 
14670  |  |  *  | 
14671  |  |  * Registers all default XPath functions in this context  | 
14672  |  |  */  | 
14673  |  | void  | 
14674  |  | xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)  | 
14675  | 71.1k  | { | 
14676  | 71.1k  |     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",  | 
14677  | 71.1k  |                          xmlXPathBooleanFunction);  | 
14678  | 71.1k  |     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",  | 
14679  | 71.1k  |                          xmlXPathCeilingFunction);  | 
14680  | 71.1k  |     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",  | 
14681  | 71.1k  |                          xmlXPathCountFunction);  | 
14682  | 71.1k  |     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",  | 
14683  | 71.1k  |                          xmlXPathConcatFunction);  | 
14684  | 71.1k  |     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",  | 
14685  | 71.1k  |                          xmlXPathContainsFunction);  | 
14686  | 71.1k  |     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",  | 
14687  | 71.1k  |                          xmlXPathIdFunction);  | 
14688  | 71.1k  |     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",  | 
14689  | 71.1k  |                          xmlXPathFalseFunction);  | 
14690  | 71.1k  |     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",  | 
14691  | 71.1k  |                          xmlXPathFloorFunction);  | 
14692  | 71.1k  |     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",  | 
14693  | 71.1k  |                          xmlXPathLastFunction);  | 
14694  | 71.1k  |     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",  | 
14695  | 71.1k  |                          xmlXPathLangFunction);  | 
14696  | 71.1k  |     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",  | 
14697  | 71.1k  |                          xmlXPathLocalNameFunction);  | 
14698  | 71.1k  |     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",  | 
14699  | 71.1k  |                          xmlXPathNotFunction);  | 
14700  | 71.1k  |     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",  | 
14701  | 71.1k  |                          xmlXPathNameFunction);  | 
14702  | 71.1k  |     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",  | 
14703  | 71.1k  |                          xmlXPathNamespaceURIFunction);  | 
14704  | 71.1k  |     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",  | 
14705  | 71.1k  |                          xmlXPathNormalizeFunction);  | 
14706  | 71.1k  |     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",  | 
14707  | 71.1k  |                          xmlXPathNumberFunction);  | 
14708  | 71.1k  |     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",  | 
14709  | 71.1k  |                          xmlXPathPositionFunction);  | 
14710  | 71.1k  |     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",  | 
14711  | 71.1k  |                          xmlXPathRoundFunction);  | 
14712  | 71.1k  |     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",  | 
14713  | 71.1k  |                          xmlXPathStringFunction);  | 
14714  | 71.1k  |     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",  | 
14715  | 71.1k  |                          xmlXPathStringLengthFunction);  | 
14716  | 71.1k  |     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",  | 
14717  | 71.1k  |                          xmlXPathStartsWithFunction);  | 
14718  | 71.1k  |     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",  | 
14719  | 71.1k  |                          xmlXPathSubstringFunction);  | 
14720  | 71.1k  |     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",  | 
14721  | 71.1k  |                          xmlXPathSubstringBeforeFunction);  | 
14722  | 71.1k  |     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",  | 
14723  | 71.1k  |                          xmlXPathSubstringAfterFunction);  | 
14724  | 71.1k  |     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",  | 
14725  | 71.1k  |                          xmlXPathSumFunction);  | 
14726  | 71.1k  |     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",  | 
14727  | 71.1k  |                          xmlXPathTrueFunction);  | 
14728  | 71.1k  |     xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",  | 
14729  | 71.1k  |                          xmlXPathTranslateFunction);  | 
14730  |  |  | 
14731  | 71.1k  |     xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",  | 
14732  | 71.1k  |    (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",  | 
14733  | 71.1k  |                          xmlXPathEscapeUriFunction);  | 
14734  | 71.1k  | }  | 
14735  |  |  | 
14736  |  | #endif /* LIBXML_XPATH_ENABLED */  |