VirtualBox

source: vbox/trunk/src/libs/libxml2-2.12.6/xpointer.c

Last change on this file was 104106, checked in by vboxsync, 8 weeks ago

libxml2-2.9.14: Applied and adjusted our libxml2 changes to 2.9.14. bugref:10640

  • Property svn:eol-style set to native
File size: 74.2 KB
Line 
1/*
2 * xpointer.c : Code to handle XML Pointer
3 *
4 * Base implementation was made accordingly to
5 * W3C Candidate Recommendation 7 June 2000
6 * http://www.w3.org/TR/2000/CR-xptr-20000607
7 *
8 * Added support for the element() scheme described in:
9 * W3C Proposed Recommendation 13 November 2002
10 * http://www.w3.org/TR/2002/PR-xptr-element-20021113/
11 *
12 * See Copyright for the status of this software.
13 *
14 * daniel@veillard.com
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/*
26 * TODO: better handling of error cases, the full expression should
27 * be parsed beforehand instead of a progressive evaluation
28 * TODO: Access into entities references are not supported now ...
29 * need a start to be able to pop out of entities refs since
30 * parent is the entity declaration, not the ref.
31 */
32
33#include <string.h>
34#include <libxml/xpointer.h>
35#include <libxml/xmlmemory.h>
36#include <libxml/parserInternals.h>
37#include <libxml/uri.h>
38#include <libxml/xpath.h>
39#include <libxml/xpathInternals.h>
40#include <libxml/xmlerror.h>
41
42#ifdef LIBXML_XPTR_ENABLED
43
44/* Add support of the xmlns() xpointer scheme to initialize the namespaces */
45#define XPTR_XMLNS_SCHEME
46
47#include "private/error.h"
48
49#define TODO \
50 xmlGenericError(xmlGenericErrorContext, \
51 "Unimplemented block at %s:%d\n", \
52 __FILE__, __LINE__);
53
54#define STRANGE \
55 xmlGenericError(xmlGenericErrorContext, \
56 "Internal error at %s:%d\n", \
57 __FILE__, __LINE__);
58
59/************************************************************************
60 * *
61 * Some factorized error routines *
62 * *
63 ************************************************************************/
64
65/**
66 * xmlXPtrErrMemory:
67 * @extra: extra information
68 *
69 * Handle a redefinition of attribute error
70 */
71static void
72xmlXPtrErrMemory(const char *extra)
73{
74 __xmlRaiseError(NULL, NULL, NULL, NULL, NULL, XML_FROM_XPOINTER,
75 XML_ERR_NO_MEMORY, XML_ERR_ERROR, NULL, 0, extra,
76 NULL, NULL, 0, 0,
77 "Memory allocation failed : %s\n", extra);
78}
79
80/**
81 * xmlXPtrErr:
82 * @ctxt: an XPTR evaluation context
83 * @extra: extra information
84 *
85 * Handle a redefinition of attribute error
86 */
87static void LIBXML_ATTR_FORMAT(3,0)
88xmlXPtrErr(xmlXPathParserContextPtr ctxt, int error,
89 const char * msg, const xmlChar *extra)
90{
91 if (ctxt != NULL)
92 ctxt->error = error;
93 if ((ctxt == NULL) || (ctxt->context == NULL)) {
94 __xmlRaiseError(NULL, NULL, NULL,
95 NULL, NULL, XML_FROM_XPOINTER, error,
96 XML_ERR_ERROR, NULL, 0,
97 (const char *) extra, NULL, NULL, 0, 0,
98 msg, extra);
99 return;
100 }
101
102 /* cleanup current last error */
103 xmlResetError(&ctxt->context->lastError);
104
105 ctxt->context->lastError.domain = XML_FROM_XPOINTER;
106 ctxt->context->lastError.code = error;
107 ctxt->context->lastError.level = XML_ERR_ERROR;
108 ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base);
109 ctxt->context->lastError.int1 = ctxt->cur - ctxt->base;
110 ctxt->context->lastError.node = ctxt->context->debugNode;
111 if (ctxt->context->error != NULL) {
112 ctxt->context->error(ctxt->context->userData,
113 &ctxt->context->lastError);
114 } else {
115 __xmlRaiseError(NULL, NULL, NULL,
116 NULL, ctxt->context->debugNode, XML_FROM_XPOINTER,
117 error, XML_ERR_ERROR, NULL, 0,
118 (const char *) extra, (const char *) ctxt->base, NULL,
119 ctxt->cur - ctxt->base, 0,
120 msg, extra);
121 }
122}
123
124/************************************************************************
125 * *
126 * A few helper functions for child sequences *
127 * *
128 ************************************************************************/
129#ifdef LIBXML_XPTR_LOCS_ENABLED
130/* xmlXPtrAdvanceNode is a private function, but used by xinclude.c */
131xmlNodePtr xmlXPtrAdvanceNode(xmlNodePtr cur, int *level);
132/**
133 * xmlXPtrGetArity:
134 * @cur: the node
135 *
136 * Returns the number of child for an element, -1 in case of error
137 */
138static int
139xmlXPtrGetArity(xmlNodePtr cur) {
140 int i;
141 if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL))
142 return(-1);
143 cur = cur->children;
144 for (i = 0;cur != NULL;cur = cur->next) {
145 if ((cur->type == XML_ELEMENT_NODE) ||
146 (cur->type == XML_DOCUMENT_NODE) ||
147 (cur->type == XML_HTML_DOCUMENT_NODE)) {
148 i++;
149 }
150 }
151 return(i);
152}
153
154/**
155 * xmlXPtrGetIndex:
156 * @cur: the node
157 *
158 * Returns the index of the node in its parent children list, -1
159 * in case of error
160 */
161static int
162xmlXPtrGetIndex(xmlNodePtr cur) {
163 int i;
164 if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL))
165 return(-1);
166 for (i = 1;cur != NULL;cur = cur->prev) {
167 if ((cur->type == XML_ELEMENT_NODE) ||
168 (cur->type == XML_DOCUMENT_NODE) ||
169 (cur->type == XML_HTML_DOCUMENT_NODE)) {
170 i++;
171 }
172 }
173 return(i);
174}
175#endif /* LIBXML_XPTR_LOCS_ENABLED */
176
177/**
178 * xmlXPtrGetNthChild:
179 * @cur: the node
180 * @no: the child number
181 *
182 * Returns the @no'th element child of @cur or NULL
183 */
184static xmlNodePtr
185xmlXPtrGetNthChild(xmlNodePtr cur, int no) {
186 int i;
187 if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL))
188 return(cur);
189 cur = cur->children;
190 for (i = 0;i <= no;cur = cur->next) {
191 if (cur == NULL)
192 return(cur);
193 if ((cur->type == XML_ELEMENT_NODE) ||
194 (cur->type == XML_DOCUMENT_NODE) ||
195 (cur->type == XML_HTML_DOCUMENT_NODE)) {
196 i++;
197 if (i == no)
198 break;
199 }
200 }
201 return(cur);
202}
203
204#ifdef LIBXML_XPTR_LOCS_ENABLED
205/************************************************************************
206 * *
207 * Handling of XPointer specific types *
208 * *
209 ************************************************************************/
210
211/**
212 * xmlXPtrCmpPoints:
213 * @node1: the first node
214 * @index1: the first index
215 * @node2: the second node
216 * @index2: the second index
217 *
218 * Compare two points w.r.t document order
219 *
220 * Returns -2 in case of error 1 if first point < second point, 0 if
221 * that's the same point, -1 otherwise
222 */
223static int
224xmlXPtrCmpPoints(xmlNodePtr node1, int index1, xmlNodePtr node2, int index2) {
225 if ((node1 == NULL) || (node2 == NULL))
226 return(-2);
227 /*
228 * a couple of optimizations which will avoid computations in most cases
229 */
230 if (node1 == node2) {
231 if (index1 < index2)
232 return(1);
233 if (index1 > index2)
234 return(-1);
235 return(0);
236 }
237 return(xmlXPathCmpNodes(node1, node2));
238}
239
240/**
241 * xmlXPtrNewPoint:
242 * @node: the xmlNodePtr
243 * @indx: the indx within the node
244 *
245 * Create a new xmlXPathObjectPtr of type point
246 *
247 * Returns the newly created object.
248 */
249static xmlXPathObjectPtr
250xmlXPtrNewPoint(xmlNodePtr node, int indx) {
251 xmlXPathObjectPtr ret;
252
253 if (node == NULL)
254 return(NULL);
255 if (indx < 0)
256 return(NULL);
257
258 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
259 if (ret == NULL) {
260 xmlXPtrErrMemory("allocating point");
261 return(NULL);
262 }
263 memset(ret, 0 , sizeof(xmlXPathObject));
264 ret->type = XPATH_POINT;
265 ret->user = (void *) node;
266 ret->index = indx;
267 return(ret);
268}
269
270/**
271 * xmlXPtrRangeCheckOrder:
272 * @range: an object range
273 *
274 * Make sure the points in the range are in the right order
275 */
276static void
277xmlXPtrRangeCheckOrder(xmlXPathObjectPtr range) {
278 int tmp;
279 xmlNodePtr tmp2;
280 if (range == NULL)
281 return;
282 if (range->type != XPATH_RANGE)
283 return;
284 if (range->user2 == NULL)
285 return;
286 tmp = xmlXPtrCmpPoints(range->user, range->index,
287 range->user2, range->index2);
288 if (tmp == -1) {
289 tmp2 = range->user;
290 range->user = range->user2;
291 range->user2 = tmp2;
292 tmp = range->index;
293 range->index = range->index2;
294 range->index2 = tmp;
295 }
296}
297
298/**
299 * xmlXPtrRangesEqual:
300 * @range1: the first range
301 * @range2: the second range
302 *
303 * Compare two ranges
304 *
305 * Returns 1 if equal, 0 otherwise
306 */
307static int
308xmlXPtrRangesEqual(xmlXPathObjectPtr range1, xmlXPathObjectPtr range2) {
309 if (range1 == range2)
310 return(1);
311 if ((range1 == NULL) || (range2 == NULL))
312 return(0);
313 if (range1->type != range2->type)
314 return(0);
315 if (range1->type != XPATH_RANGE)
316 return(0);
317 if (range1->user != range2->user)
318 return(0);
319 if (range1->index != range2->index)
320 return(0);
321 if (range1->user2 != range2->user2)
322 return(0);
323 if (range1->index2 != range2->index2)
324 return(0);
325 return(1);
326}
327
328/**
329 * xmlXPtrNewRangeInternal:
330 * @start: the starting node
331 * @startindex: the start index
332 * @end: the ending point
333 * @endindex: the ending index
334 *
335 * Internal function to create a new xmlXPathObjectPtr of type range
336 *
337 * Returns the newly created object.
338 */
339static xmlXPathObjectPtr
340xmlXPtrNewRangeInternal(xmlNodePtr start, int startindex,
341 xmlNodePtr end, int endindex) {
342 xmlXPathObjectPtr ret;
343
344 /*
345 * Namespace nodes must be copied (see xmlXPathNodeSetDupNs).
346 * Disallow them for now.
347 */
348 if ((start != NULL) && (start->type == XML_NAMESPACE_DECL))
349 return(NULL);
350 if ((end != NULL) && (end->type == XML_NAMESPACE_DECL))
351 return(NULL);
352
353 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
354 if (ret == NULL) {
355 xmlXPtrErrMemory("allocating range");
356 return(NULL);
357 }
358 memset(ret, 0, sizeof(xmlXPathObject));
359 ret->type = XPATH_RANGE;
360 ret->user = start;
361 ret->index = startindex;
362 ret->user2 = end;
363 ret->index2 = endindex;
364 return(ret);
365}
366
367/**
368 * xmlXPtrNewRange:
369 * @start: the starting node
370 * @startindex: the start index
371 * @end: the ending point
372 * @endindex: the ending index
373 *
374 * Create a new xmlXPathObjectPtr of type range
375 *
376 * Returns the newly created object.
377 */
378xmlXPathObjectPtr
379xmlXPtrNewRange(xmlNodePtr start, int startindex,
380 xmlNodePtr end, int endindex) {
381 xmlXPathObjectPtr ret;
382
383 if (start == NULL)
384 return(NULL);
385 if (end == NULL)
386 return(NULL);
387 if (startindex < 0)
388 return(NULL);
389 if (endindex < 0)
390 return(NULL);
391
392 ret = xmlXPtrNewRangeInternal(start, startindex, end, endindex);
393 xmlXPtrRangeCheckOrder(ret);
394 return(ret);
395}
396
397/**
398 * xmlXPtrNewRangePoints:
399 * @start: the starting point
400 * @end: the ending point
401 *
402 * Create a new xmlXPathObjectPtr of type range using 2 Points
403 *
404 * Returns the newly created object.
405 */
406xmlXPathObjectPtr
407xmlXPtrNewRangePoints(xmlXPathObjectPtr start, xmlXPathObjectPtr end) {
408 xmlXPathObjectPtr ret;
409
410 if (start == NULL)
411 return(NULL);
412 if (end == NULL)
413 return(NULL);
414 if (start->type != XPATH_POINT)
415 return(NULL);
416 if (end->type != XPATH_POINT)
417 return(NULL);
418
419 ret = xmlXPtrNewRangeInternal(start->user, start->index, end->user,
420 end->index);
421 xmlXPtrRangeCheckOrder(ret);
422 return(ret);
423}
424
425/**
426 * xmlXPtrNewRangePointNode:
427 * @start: the starting point
428 * @end: the ending node
429 *
430 * Create a new xmlXPathObjectPtr of type range from a point to a node
431 *
432 * Returns the newly created object.
433 */
434xmlXPathObjectPtr
435xmlXPtrNewRangePointNode(xmlXPathObjectPtr start, xmlNodePtr end) {
436 xmlXPathObjectPtr ret;
437
438 if (start == NULL)
439 return(NULL);
440 if (end == NULL)
441 return(NULL);
442 if (start->type != XPATH_POINT)
443 return(NULL);
444
445 ret = xmlXPtrNewRangeInternal(start->user, start->index, end, -1);
446 xmlXPtrRangeCheckOrder(ret);
447 return(ret);
448}
449
450/**
451 * xmlXPtrNewRangeNodePoint:
452 * @start: the starting node
453 * @end: the ending point
454 *
455 * Create a new xmlXPathObjectPtr of type range from a node to a point
456 *
457 * Returns the newly created object.
458 */
459xmlXPathObjectPtr
460xmlXPtrNewRangeNodePoint(xmlNodePtr start, xmlXPathObjectPtr end) {
461 xmlXPathObjectPtr ret;
462
463 if (start == NULL)
464 return(NULL);
465 if (end == NULL)
466 return(NULL);
467 if (end->type != XPATH_POINT)
468 return(NULL);
469
470 ret = xmlXPtrNewRangeInternal(start, -1, end->user, end->index);
471 xmlXPtrRangeCheckOrder(ret);
472 return(ret);
473}
474
475/**
476 * xmlXPtrNewRangeNodes:
477 * @start: the starting node
478 * @end: the ending node
479 *
480 * Create a new xmlXPathObjectPtr of type range using 2 nodes
481 *
482 * Returns the newly created object.
483 */
484xmlXPathObjectPtr
485xmlXPtrNewRangeNodes(xmlNodePtr start, xmlNodePtr end) {
486 xmlXPathObjectPtr ret;
487
488 if (start == NULL)
489 return(NULL);
490 if (end == NULL)
491 return(NULL);
492
493 ret = xmlXPtrNewRangeInternal(start, -1, end, -1);
494 xmlXPtrRangeCheckOrder(ret);
495 return(ret);
496}
497
498/**
499 * xmlXPtrNewCollapsedRange:
500 * @start: the starting and ending node
501 *
502 * Create a new xmlXPathObjectPtr of type range using a single nodes
503 *
504 * Returns the newly created object.
505 */
506xmlXPathObjectPtr
507xmlXPtrNewCollapsedRange(xmlNodePtr start) {
508 xmlXPathObjectPtr ret;
509
510 if (start == NULL)
511 return(NULL);
512
513 ret = xmlXPtrNewRangeInternal(start, -1, NULL, -1);
514 return(ret);
515}
516
517/**
518 * xmlXPtrNewRangeNodeObject:
519 * @start: the starting node
520 * @end: the ending object
521 *
522 * Create a new xmlXPathObjectPtr of type range from a not to an object
523 *
524 * Returns the newly created object.
525 */
526xmlXPathObjectPtr
527xmlXPtrNewRangeNodeObject(xmlNodePtr start, xmlXPathObjectPtr end) {
528 xmlNodePtr endNode;
529 int endIndex;
530 xmlXPathObjectPtr ret;
531
532 if (start == NULL)
533 return(NULL);
534 if (end == NULL)
535 return(NULL);
536 switch (end->type) {
537 case XPATH_POINT:
538 endNode = end->user;
539 endIndex = end->index;
540 break;
541 case XPATH_RANGE:
542 endNode = end->user2;
543 endIndex = end->index2;
544 break;
545 case XPATH_NODESET:
546 /*
547 * Empty set ...
548 */
549 if ((end->nodesetval == NULL) || (end->nodesetval->nodeNr <= 0))
550 return(NULL);
551 endNode = end->nodesetval->nodeTab[end->nodesetval->nodeNr - 1];
552 endIndex = -1;
553 break;
554 default:
555 /* TODO */
556 return(NULL);
557 }
558
559 ret = xmlXPtrNewRangeInternal(start, -1, endNode, endIndex);
560 xmlXPtrRangeCheckOrder(ret);
561 return(ret);
562}
563
564#define XML_RANGESET_DEFAULT 10
565
566/**
567 * xmlXPtrLocationSetCreate:
568 * @val: an initial xmlXPathObjectPtr, or NULL
569 *
570 * Create a new xmlLocationSetPtr of type double and of value @val
571 *
572 * Returns the newly created object.
573 */
574xmlLocationSetPtr
575xmlXPtrLocationSetCreate(xmlXPathObjectPtr val) {
576 xmlLocationSetPtr ret;
577
578 ret = (xmlLocationSetPtr) xmlMalloc(sizeof(xmlLocationSet));
579 if (ret == NULL) {
580 xmlXPtrErrMemory("allocating locationset");
581 return(NULL);
582 }
583 memset(ret, 0 , sizeof(xmlLocationSet));
584 if (val != NULL) {
585 ret->locTab = (xmlXPathObjectPtr *) xmlMalloc(XML_RANGESET_DEFAULT *
586 sizeof(xmlXPathObjectPtr));
587 if (ret->locTab == NULL) {
588 xmlXPtrErrMemory("allocating locationset");
589 xmlFree(ret);
590 return(NULL);
591 }
592 memset(ret->locTab, 0 ,
593 XML_RANGESET_DEFAULT * sizeof(xmlXPathObjectPtr));
594 ret->locMax = XML_RANGESET_DEFAULT;
595 ret->locTab[ret->locNr++] = val;
596 }
597 return(ret);
598}
599
600/**
601 * xmlXPtrLocationSetAdd:
602 * @cur: the initial range set
603 * @val: a new xmlXPathObjectPtr
604 *
605 * add a new xmlXPathObjectPtr to an existing LocationSet
606 * If the location already exist in the set @val is freed.
607 */
608void
609xmlXPtrLocationSetAdd(xmlLocationSetPtr cur, xmlXPathObjectPtr val) {
610 int i;
611
612 if ((cur == NULL) || (val == NULL)) return;
613
614 /*
615 * check against doublons
616 */
617 for (i = 0;i < cur->locNr;i++) {
618 if (xmlXPtrRangesEqual(cur->locTab[i], val)) {
619 xmlXPathFreeObject(val);
620 return;
621 }
622 }
623
624 /*
625 * grow the locTab if needed
626 */
627 if (cur->locMax == 0) {
628 cur->locTab = (xmlXPathObjectPtr *) xmlMalloc(XML_RANGESET_DEFAULT *
629 sizeof(xmlXPathObjectPtr));
630 if (cur->locTab == NULL) {
631 xmlXPtrErrMemory("adding location to set");
632 return;
633 }
634 memset(cur->locTab, 0 ,
635 XML_RANGESET_DEFAULT * sizeof(xmlXPathObjectPtr));
636 cur->locMax = XML_RANGESET_DEFAULT;
637 } else if (cur->locNr == cur->locMax) {
638 xmlXPathObjectPtr *temp;
639
640 cur->locMax *= 2;
641 temp = (xmlXPathObjectPtr *) xmlRealloc(cur->locTab, cur->locMax *
642 sizeof(xmlXPathObjectPtr));
643 if (temp == NULL) {
644 xmlXPtrErrMemory("adding location to set");
645 return;
646 }
647 cur->locTab = temp;
648 }
649 cur->locTab[cur->locNr++] = val;
650}
651
652/**
653 * xmlXPtrLocationSetMerge:
654 * @val1: the first LocationSet
655 * @val2: the second LocationSet
656 *
657 * Merges two rangesets, all ranges from @val2 are added to @val1
658 *
659 * Returns val1 once extended or NULL in case of error.
660 */
661xmlLocationSetPtr
662xmlXPtrLocationSetMerge(xmlLocationSetPtr val1, xmlLocationSetPtr val2) {
663 int i;
664
665 if (val1 == NULL) return(NULL);
666 if (val2 == NULL) return(val1);
667
668 /*
669 * !!!!! this can be optimized a lot, knowing that both
670 * val1 and val2 already have unicity of their values.
671 */
672
673 for (i = 0;i < val2->locNr;i++)
674 xmlXPtrLocationSetAdd(val1, val2->locTab[i]);
675
676 return(val1);
677}
678
679/**
680 * xmlXPtrLocationSetDel:
681 * @cur: the initial range set
682 * @val: an xmlXPathObjectPtr
683 *
684 * Removes an xmlXPathObjectPtr from an existing LocationSet
685 */
686void
687xmlXPtrLocationSetDel(xmlLocationSetPtr cur, xmlXPathObjectPtr val) {
688 int i;
689
690 if (cur == NULL) return;
691 if (val == NULL) return;
692
693 /*
694 * check against doublons
695 */
696 for (i = 0;i < cur->locNr;i++)
697 if (cur->locTab[i] == val) break;
698
699 if (i >= cur->locNr) {
700 return;
701 }
702 cur->locNr--;
703 for (;i < cur->locNr;i++)
704 cur->locTab[i] = cur->locTab[i + 1];
705 cur->locTab[cur->locNr] = NULL;
706}
707
708/**
709 * xmlXPtrLocationSetRemove:
710 * @cur: the initial range set
711 * @val: the index to remove
712 *
713 * Removes an entry from an existing LocationSet list.
714 */
715void
716xmlXPtrLocationSetRemove(xmlLocationSetPtr cur, int val) {
717 if (cur == NULL) return;
718 if (val >= cur->locNr) return;
719 cur->locNr--;
720 for (;val < cur->locNr;val++)
721 cur->locTab[val] = cur->locTab[val + 1];
722 cur->locTab[cur->locNr] = NULL;
723}
724
725/**
726 * xmlXPtrFreeLocationSet:
727 * @obj: the xmlLocationSetPtr to free
728 *
729 * Free the LocationSet compound (not the actual ranges !).
730 */
731void
732xmlXPtrFreeLocationSet(xmlLocationSetPtr obj) {
733 int i;
734
735 if (obj == NULL) return;
736 if (obj->locTab != NULL) {
737 for (i = 0;i < obj->locNr; i++) {
738 xmlXPathFreeObject(obj->locTab[i]);
739 }
740 xmlFree(obj->locTab);
741 }
742 xmlFree(obj);
743}
744
745/**
746 * xmlXPtrNewLocationSetNodes:
747 * @start: the start NodePtr value
748 * @end: the end NodePtr value or NULL
749 *
750 * Create a new xmlXPathObjectPtr of type LocationSet and initialize
751 * it with the single range made of the two nodes @start and @end
752 *
753 * Returns the newly created object.
754 */
755xmlXPathObjectPtr
756xmlXPtrNewLocationSetNodes(xmlNodePtr start, xmlNodePtr end) {
757 xmlXPathObjectPtr ret;
758
759 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
760 if (ret == NULL) {
761 xmlXPtrErrMemory("allocating locationset");
762 return(NULL);
763 }
764 memset(ret, 0 , sizeof(xmlXPathObject));
765 ret->type = XPATH_LOCATIONSET;
766 if (end == NULL)
767 ret->user = xmlXPtrLocationSetCreate(xmlXPtrNewCollapsedRange(start));
768 else
769 ret->user = xmlXPtrLocationSetCreate(xmlXPtrNewRangeNodes(start,end));
770 return(ret);
771}
772
773/**
774 * xmlXPtrNewLocationSetNodeSet:
775 * @set: a node set
776 *
777 * Create a new xmlXPathObjectPtr of type LocationSet and initialize
778 * it with all the nodes from @set
779 *
780 * Returns the newly created object.
781 */
782xmlXPathObjectPtr
783xmlXPtrNewLocationSetNodeSet(xmlNodeSetPtr set) {
784 xmlXPathObjectPtr ret;
785
786 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
787 if (ret == NULL) {
788 xmlXPtrErrMemory("allocating locationset");
789 return(NULL);
790 }
791 memset(ret, 0, sizeof(xmlXPathObject));
792 ret->type = XPATH_LOCATIONSET;
793 if (set != NULL) {
794 int i;
795 xmlLocationSetPtr newset;
796
797 newset = xmlXPtrLocationSetCreate(NULL);
798 if (newset == NULL)
799 return(ret);
800
801 for (i = 0;i < set->nodeNr;i++)
802 xmlXPtrLocationSetAdd(newset,
803 xmlXPtrNewCollapsedRange(set->nodeTab[i]));
804
805 ret->user = (void *) newset;
806 }
807 return(ret);
808}
809
810/**
811 * xmlXPtrWrapLocationSet:
812 * @val: the LocationSet value
813 *
814 * Wrap the LocationSet @val in a new xmlXPathObjectPtr
815 *
816 * Returns the newly created object.
817 */
818xmlXPathObjectPtr
819xmlXPtrWrapLocationSet(xmlLocationSetPtr val) {
820 xmlXPathObjectPtr ret;
821
822 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
823 if (ret == NULL) {
824 xmlXPtrErrMemory("allocating locationset");
825 return(NULL);
826 }
827 memset(ret, 0, sizeof(xmlXPathObject));
828 ret->type = XPATH_LOCATIONSET;
829 ret->user = (void *) val;
830 return(ret);
831}
832#endif /* LIBXML_XPTR_LOCS_ENABLED */
833
834/************************************************************************
835 * *
836 * The parser *
837 * *
838 ************************************************************************/
839
840static void xmlXPtrEvalChildSeq(xmlXPathParserContextPtr ctxt, xmlChar *name);
841
842/*
843 * Macros for accessing the content. Those should be used only by the parser,
844 * and not exported.
845 *
846 * Dirty macros, i.e. one need to make assumption on the context to use them
847 *
848 * CUR returns the current xmlChar value, i.e. a 8 bit value
849 * in ISO-Latin or UTF-8.
850 * This should be used internally by the parser
851 * only to compare to ASCII values otherwise it would break when
852 * running with UTF-8 encoding.
853 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only
854 * to compare on ASCII based substring.
855 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
856 * strings within the parser.
857 * CURRENT Returns the current char value, with the full decoding of
858 * UTF-8 if we are using this mode. It returns an int.
859 * NEXT Skip to the next character, this does the proper decoding
860 * in UTF-8 mode. It also pop-up unfinished entities on the fly.
861 * It returns the pointer to the current xmlChar.
862 */
863
864#define CUR (*ctxt->cur)
865#define SKIP(val) ctxt->cur += (val)
866#define NXT(val) ctxt->cur[(val)]
867
868#define SKIP_BLANKS \
869 while (IS_BLANK_CH(*(ctxt->cur))) NEXT
870
871#define CURRENT (*ctxt->cur)
872#define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
873
874/*
875 * xmlXPtrGetChildNo:
876 * @ctxt: the XPointer Parser context
877 * @index: the child number
878 *
879 * Move the current node of the nodeset on the stack to the
880 * given child if found
881 */
882static void
883xmlXPtrGetChildNo(xmlXPathParserContextPtr ctxt, int indx) {
884 xmlNodePtr cur = NULL;
885 xmlXPathObjectPtr obj;
886 xmlNodeSetPtr oldset;
887
888 CHECK_TYPE(XPATH_NODESET);
889 obj = valuePop(ctxt);
890 oldset = obj->nodesetval;
891 if ((indx <= 0) || (oldset == NULL) || (oldset->nodeNr != 1)) {
892 xmlXPathFreeObject(obj);
893 valuePush(ctxt, xmlXPathNewNodeSet(NULL));
894 return;
895 }
896 cur = xmlXPtrGetNthChild(oldset->nodeTab[0], indx);
897 if (cur == NULL) {
898 xmlXPathFreeObject(obj);
899 valuePush(ctxt, xmlXPathNewNodeSet(NULL));
900 return;
901 }
902 oldset->nodeTab[0] = cur;
903 valuePush(ctxt, obj);
904}
905
906/**
907 * xmlXPtrEvalXPtrPart:
908 * @ctxt: the XPointer Parser context
909 * @name: the preparsed Scheme for the XPtrPart
910 *
911 * XPtrPart ::= 'xpointer' '(' XPtrExpr ')'
912 * | Scheme '(' SchemeSpecificExpr ')'
913 *
914 * Scheme ::= NCName - 'xpointer' [VC: Non-XPointer schemes]
915 *
916 * SchemeSpecificExpr ::= StringWithBalancedParens
917 *
918 * StringWithBalancedParens ::=
919 * [^()]* ('(' StringWithBalancedParens ')' [^()]*)*
920 * [VC: Parenthesis escaping]
921 *
922 * XPtrExpr ::= Expr [VC: Parenthesis escaping]
923 *
924 * VC: Parenthesis escaping:
925 * The end of an XPointer part is signaled by the right parenthesis ")"
926 * character that is balanced with the left parenthesis "(" character
927 * that began the part. Any unbalanced parenthesis character inside the
928 * expression, even within literals, must be escaped with a circumflex (^)
929 * character preceding it. If the expression contains any literal
930 * occurrences of the circumflex, each must be escaped with an additional
931 * circumflex (that is, ^^). If the unescaped parentheses in the expression
932 * are not balanced, a syntax error results.
933 *
934 * Parse and evaluate an XPtrPart. Basically it generates the unescaped
935 * string and if the scheme is 'xpointer' it will call the XPath interpreter.
936 *
937 * TODO: there is no new scheme registration mechanism
938 */
939
940static void
941xmlXPtrEvalXPtrPart(xmlXPathParserContextPtr ctxt, xmlChar *name) {
942 xmlChar *buffer, *cur;
943 int len;
944 int level;
945
946 if (name == NULL)
947 name = xmlXPathParseName(ctxt);
948 if (name == NULL)
949 XP_ERROR(XPATH_EXPR_ERROR);
950
951 if (CUR != '(') {
952 xmlFree(name);
953 XP_ERROR(XPATH_EXPR_ERROR);
954 }
955 NEXT;
956 level = 1;
957
958 len = xmlStrlen(ctxt->cur);
959 len++;
960 buffer = (xmlChar *) xmlMallocAtomic(len);
961 if (buffer == NULL) {
962 xmlXPtrErrMemory("allocating buffer");
963 xmlFree(name);
964 return;
965 }
966
967 cur = buffer;
968 while (CUR != 0) {
969 if (CUR == ')') {
970 level--;
971 if (level == 0) {
972 NEXT;
973 break;
974 }
975 } else if (CUR == '(') {
976 level++;
977 } else if (CUR == '^') {
978 if ((NXT(1) == ')') || (NXT(1) == '(') || (NXT(1) == '^')) {
979 NEXT;
980 }
981 }
982 *cur++ = CUR;
983 NEXT;
984 }
985 *cur = 0;
986
987 if ((level != 0) && (CUR == 0)) {
988 xmlFree(name);
989 xmlFree(buffer);
990 XP_ERROR(XPTR_SYNTAX_ERROR);
991 }
992
993 if (xmlStrEqual(name, (xmlChar *) "xpointer") ||
994 xmlStrEqual(name, (xmlChar *) "xpath1")) {
995 const xmlChar *oldBase = ctxt->base;
996 const xmlChar *oldCur = ctxt->cur;
997
998 ctxt->cur = ctxt->base = buffer;
999 /*
1000 * To evaluate an xpointer scheme element (4.3) we need:
1001 * context initialized to the root
1002 * context position initialized to 1
1003 * context size initialized to 1
1004 */
1005 ctxt->context->node = (xmlNodePtr)ctxt->context->doc;
1006 ctxt->context->proximityPosition = 1;
1007 ctxt->context->contextSize = 1;
1008#ifdef LIBXML_XPTR_LOCS_ENABLED
1009 ctxt->xptr = xmlStrEqual(name, (xmlChar *) "xpointer");
1010#endif
1011 xmlXPathEvalExpr(ctxt);
1012 ctxt->base = oldBase;
1013 ctxt->cur = oldCur;
1014 } else if (xmlStrEqual(name, (xmlChar *) "element")) {
1015 const xmlChar *oldBase = ctxt->base;
1016 const xmlChar *oldCur = ctxt->cur;
1017 xmlChar *name2;
1018
1019 ctxt->cur = ctxt->base = buffer;
1020 if (buffer[0] == '/') {
1021 xmlXPathRoot(ctxt);
1022 xmlXPtrEvalChildSeq(ctxt, NULL);
1023 } else {
1024 name2 = xmlXPathParseName(ctxt);
1025 if (name2 == NULL) {
1026 ctxt->base = oldBase;
1027 ctxt->cur = oldCur;
1028 xmlFree(buffer);
1029 xmlFree(name);
1030 XP_ERROR(XPATH_EXPR_ERROR);
1031 }
1032 xmlXPtrEvalChildSeq(ctxt, name2);
1033 }
1034 ctxt->base = oldBase;
1035 ctxt->cur = oldCur;
1036#ifdef XPTR_XMLNS_SCHEME
1037 } else if (xmlStrEqual(name, (xmlChar *) "xmlns")) {
1038 const xmlChar *oldBase = ctxt->base;
1039 const xmlChar *oldCur = ctxt->cur;
1040 xmlChar *prefix;
1041
1042 ctxt->cur = ctxt->base = buffer;
1043 prefix = xmlXPathParseNCName(ctxt);
1044 if (prefix == NULL) {
1045 ctxt->base = oldBase;
1046 ctxt->cur = oldCur;
1047 xmlFree(buffer);
1048 xmlFree(name);
1049 XP_ERROR(XPTR_SYNTAX_ERROR);
1050 }
1051 SKIP_BLANKS;
1052 if (CUR != '=') {
1053 ctxt->base = oldBase;
1054 ctxt->cur = oldCur;
1055 xmlFree(prefix);
1056 xmlFree(buffer);
1057 xmlFree(name);
1058 XP_ERROR(XPTR_SYNTAX_ERROR);
1059 }
1060 NEXT;
1061 SKIP_BLANKS;
1062
1063 xmlXPathRegisterNs(ctxt->context, prefix, ctxt->cur);
1064 ctxt->base = oldBase;
1065 ctxt->cur = oldCur;
1066 xmlFree(prefix);
1067#endif /* XPTR_XMLNS_SCHEME */
1068 } else {
1069 xmlXPtrErr(ctxt, XML_XPTR_UNKNOWN_SCHEME,
1070 "unsupported scheme '%s'\n", name);
1071 }
1072 xmlFree(buffer);
1073 xmlFree(name);
1074}
1075
1076/**
1077 * xmlXPtrEvalFullXPtr:
1078 * @ctxt: the XPointer Parser context
1079 * @name: the preparsed Scheme for the first XPtrPart
1080 *
1081 * FullXPtr ::= XPtrPart (S? XPtrPart)*
1082 *
1083 * As the specs says:
1084 * -----------
1085 * When multiple XPtrParts are provided, they must be evaluated in
1086 * left-to-right order. If evaluation of one part fails, the nexti
1087 * is evaluated. The following conditions cause XPointer part failure:
1088 *
1089 * - An unknown scheme
1090 * - A scheme that does not locate any sub-resource present in the resource
1091 * - A scheme that is not applicable to the media type of the resource
1092 *
1093 * The XPointer application must consume a failed XPointer part and
1094 * attempt to evaluate the next one, if any. The result of the first
1095 * XPointer part whose evaluation succeeds is taken to be the fragment
1096 * located by the XPointer as a whole. If all the parts fail, the result
1097 * for the XPointer as a whole is a sub-resource error.
1098 * -----------
1099 *
1100 * Parse and evaluate a Full XPtr i.e. possibly a cascade of XPath based
1101 * expressions or other schemes.
1102 */
1103static void
1104xmlXPtrEvalFullXPtr(xmlXPathParserContextPtr ctxt, xmlChar *name) {
1105 if (name == NULL)
1106 name = xmlXPathParseName(ctxt);
1107 if (name == NULL)
1108 XP_ERROR(XPATH_EXPR_ERROR);
1109 while (name != NULL) {
1110 ctxt->error = XPATH_EXPRESSION_OK;
1111 xmlXPtrEvalXPtrPart(ctxt, name);
1112
1113 /* in case of syntax error, break here */
1114 if ((ctxt->error != XPATH_EXPRESSION_OK) &&
1115 (ctxt->error != XML_XPTR_UNKNOWN_SCHEME))
1116 return;
1117
1118 /*
1119 * If the returned value is a non-empty nodeset
1120 * or location set, return here.
1121 */
1122 if (ctxt->value != NULL) {
1123 xmlXPathObjectPtr obj = ctxt->value;
1124
1125 switch (obj->type) {
1126#ifdef LIBXML_XPTR_LOCS_ENABLED
1127 case XPATH_LOCATIONSET: {
1128 xmlLocationSetPtr loc = ctxt->value->user;
1129 if ((loc != NULL) && (loc->locNr > 0))
1130 return;
1131 break;
1132 }
1133#endif
1134 case XPATH_NODESET: {
1135 xmlNodeSetPtr loc = ctxt->value->nodesetval;
1136 if ((loc != NULL) && (loc->nodeNr > 0))
1137 return;
1138 break;
1139 }
1140 default:
1141 break;
1142 }
1143
1144 /*
1145 * Evaluating to improper values is equivalent to
1146 * a sub-resource error, clean-up the stack
1147 */
1148 do {
1149 obj = valuePop(ctxt);
1150 if (obj != NULL) {
1151 xmlXPathFreeObject(obj);
1152 }
1153 } while (obj != NULL);
1154 }
1155
1156 /*
1157 * Is there another XPointer part.
1158 */
1159 SKIP_BLANKS;
1160 name = xmlXPathParseName(ctxt);
1161 }
1162}
1163
1164/**
1165 * xmlXPtrEvalChildSeq:
1166 * @ctxt: the XPointer Parser context
1167 * @name: a possible ID name of the child sequence
1168 *
1169 * ChildSeq ::= '/1' ('/' [0-9]*)*
1170 * | Name ('/' [0-9]*)+
1171 *
1172 * Parse and evaluate a Child Sequence. This routine also handle the
1173 * case of a Bare Name used to get a document ID.
1174 */
1175static void
1176xmlXPtrEvalChildSeq(xmlXPathParserContextPtr ctxt, xmlChar *name) {
1177 /*
1178 * XPointer don't allow by syntax to address in multirooted trees
1179 * this might prove useful in some cases, warn about it.
1180 */
1181 if ((name == NULL) && (CUR == '/') && (NXT(1) != '1')) {
1182 xmlXPtrErr(ctxt, XML_XPTR_CHILDSEQ_START,
1183 "warning: ChildSeq not starting by /1\n", NULL);
1184 }
1185
1186 if (name != NULL) {
1187 valuePush(ctxt, xmlXPathNewString(name));
1188 xmlFree(name);
1189 xmlXPathIdFunction(ctxt, 1);
1190 CHECK_ERROR;
1191 }
1192
1193 while (CUR == '/') {
1194 int child = 0, overflow = 0;
1195 NEXT;
1196
1197 while ((CUR >= '0') && (CUR <= '9')) {
1198 int d = CUR - '0';
1199 if (child > INT_MAX / 10)
1200 overflow = 1;
1201 else
1202 child *= 10;
1203 if (child > INT_MAX - d)
1204 overflow = 1;
1205 else
1206 child += d;
1207 NEXT;
1208 }
1209 if (overflow)
1210 child = 0;
1211 xmlXPtrGetChildNo(ctxt, child);
1212 }
1213}
1214
1215
1216/**
1217 * xmlXPtrEvalXPointer:
1218 * @ctxt: the XPointer Parser context
1219 *
1220 * XPointer ::= Name
1221 * | ChildSeq
1222 * | FullXPtr
1223 *
1224 * Parse and evaluate an XPointer
1225 */
1226static void
1227xmlXPtrEvalXPointer(xmlXPathParserContextPtr ctxt) {
1228 if (ctxt->valueTab == NULL) {
1229 /* Allocate the value stack */
1230 ctxt->valueTab = (xmlXPathObjectPtr *)
1231 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
1232 if (ctxt->valueTab == NULL) {
1233 xmlXPtrErrMemory("allocating evaluation context");
1234 return;
1235 }
1236 ctxt->valueNr = 0;
1237 ctxt->valueMax = 10;
1238 ctxt->value = NULL;
1239 }
1240 SKIP_BLANKS;
1241 if (CUR == '/') {
1242 xmlXPathRoot(ctxt);
1243 xmlXPtrEvalChildSeq(ctxt, NULL);
1244 } else {
1245 xmlChar *name;
1246
1247 name = xmlXPathParseName(ctxt);
1248 if (name == NULL)
1249 XP_ERROR(XPATH_EXPR_ERROR);
1250 if (CUR == '(') {
1251 xmlXPtrEvalFullXPtr(ctxt, name);
1252 /* Short evaluation */
1253 return;
1254 } else {
1255 /* this handle both Bare Names and Child Sequences */
1256 xmlXPtrEvalChildSeq(ctxt, name);
1257 }
1258 }
1259 SKIP_BLANKS;
1260 if (CUR != 0)
1261 XP_ERROR(XPATH_EXPR_ERROR);
1262}
1263
1264
1265/************************************************************************
1266 * *
1267 * General routines *
1268 * *
1269 ************************************************************************/
1270
1271#ifdef LIBXML_XPTR_LOCS_ENABLED
1272static
1273void xmlXPtrStringRangeFunction(xmlXPathParserContextPtr ctxt, int nargs);
1274static
1275void xmlXPtrStartPointFunction(xmlXPathParserContextPtr ctxt, int nargs);
1276static
1277void xmlXPtrEndPointFunction(xmlXPathParserContextPtr ctxt, int nargs);
1278static
1279void xmlXPtrHereFunction(xmlXPathParserContextPtr ctxt, int nargs);
1280static
1281void xmlXPtrOriginFunction(xmlXPathParserContextPtr ctxt, int nargs);
1282static
1283void xmlXPtrRangeInsideFunction(xmlXPathParserContextPtr ctxt, int nargs);
1284static
1285void xmlXPtrRangeFunction(xmlXPathParserContextPtr ctxt, int nargs);
1286#endif /* LIBXML_XPTR_LOCS_ENABLED */
1287
1288/**
1289 * xmlXPtrNewContext:
1290 * @doc: the XML document
1291 * @here: the node that directly contains the XPointer being evaluated or NULL
1292 * @origin: the element from which a user or program initiated traversal of
1293 * the link, or NULL.
1294 *
1295 * Create a new XPointer context
1296 *
1297 * Returns the xmlXPathContext just allocated.
1298 */
1299xmlXPathContextPtr
1300xmlXPtrNewContext(xmlDocPtr doc, xmlNodePtr here, xmlNodePtr origin) {
1301 xmlXPathContextPtr ret;
1302 (void) here;
1303 (void) origin;
1304
1305 ret = xmlXPathNewContext(doc);
1306 if (ret == NULL)
1307 return(ret);
1308#ifdef LIBXML_XPTR_LOCS_ENABLED
1309 ret->xptr = 1;
1310 ret->here = here;
1311 ret->origin = origin;
1312
1313 xmlXPathRegisterFunc(ret, (xmlChar *)"range",
1314 xmlXPtrRangeFunction);
1315 xmlXPathRegisterFunc(ret, (xmlChar *)"range-inside",
1316 xmlXPtrRangeInsideFunction);
1317 xmlXPathRegisterFunc(ret, (xmlChar *)"string-range",
1318 xmlXPtrStringRangeFunction);
1319 xmlXPathRegisterFunc(ret, (xmlChar *)"start-point",
1320 xmlXPtrStartPointFunction);
1321 xmlXPathRegisterFunc(ret, (xmlChar *)"end-point",
1322 xmlXPtrEndPointFunction);
1323 xmlXPathRegisterFunc(ret, (xmlChar *)"here",
1324 xmlXPtrHereFunction);
1325 xmlXPathRegisterFunc(ret, (xmlChar *)" origin",
1326 xmlXPtrOriginFunction);
1327#endif /* LIBXML_XPTR_LOCS_ENABLED */
1328
1329 return(ret);
1330}
1331
1332/**
1333 * xmlXPtrEval:
1334 * @str: the XPointer expression
1335 * @ctx: the XPointer context
1336 *
1337 * Evaluate the XPath Location Path in the given context.
1338 *
1339 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
1340 * the caller has to free the object.
1341 */
1342xmlXPathObjectPtr
1343xmlXPtrEval(const xmlChar *str, xmlXPathContextPtr ctx) {
1344 xmlXPathParserContextPtr ctxt;
1345 xmlXPathObjectPtr res = NULL, tmp;
1346 xmlXPathObjectPtr init = NULL;
1347 int stack = 0;
1348
1349 xmlInitParser();
1350
1351 if ((ctx == NULL) || (str == NULL))
1352 return(NULL);
1353
1354 ctxt = xmlXPathNewParserContext(str, ctx);
1355 if (ctxt == NULL)
1356 return(NULL);
1357 xmlXPtrEvalXPointer(ctxt);
1358
1359 if ((ctxt->value != NULL) &&
1360#ifdef LIBXML_XPTR_LOCS_ENABLED
1361 (ctxt->value->type != XPATH_LOCATIONSET) &&
1362#endif
1363 (ctxt->value->type != XPATH_NODESET)) {
1364 xmlXPtrErr(ctxt, XML_XPTR_EVAL_FAILED,
1365 "xmlXPtrEval: evaluation failed to return a node set\n",
1366 NULL);
1367 } else {
1368 res = valuePop(ctxt);
1369 }
1370
1371 do {
1372 tmp = valuePop(ctxt);
1373 if (tmp != NULL) {
1374 if (tmp != init) {
1375 if (tmp->type == XPATH_NODESET) {
1376 /*
1377 * Evaluation may push a root nodeset which is unused
1378 */
1379 xmlNodeSetPtr set;
1380 set = tmp->nodesetval;
1381 if ((set == NULL) || (set->nodeNr != 1) ||
1382 (set->nodeTab[0] != (xmlNodePtr) ctx->doc))
1383 stack++;
1384 } else
1385 stack++;
1386 }
1387 xmlXPathFreeObject(tmp);
1388 }
1389 } while (tmp != NULL);
1390 if (stack != 0) {
1391 xmlXPtrErr(ctxt, XML_XPTR_EXTRA_OBJECTS,
1392 "xmlXPtrEval: object(s) left on the eval stack\n",
1393 NULL);
1394 }
1395 if (ctxt->error != XPATH_EXPRESSION_OK) {
1396 xmlXPathFreeObject(res);
1397 res = NULL;
1398 }
1399
1400 xmlXPathFreeParserContext(ctxt);
1401 return(res);
1402}
1403
1404#ifdef LIBXML_XPTR_LOCS_ENABLED
1405/**
1406 * xmlXPtrBuildRangeNodeList:
1407 * @range: a range object
1408 *
1409 * Build a node list tree copy of the range
1410 *
1411 * Returns an xmlNodePtr list or NULL.
1412 * the caller has to free the node tree.
1413 */
1414static xmlNodePtr
1415xmlXPtrBuildRangeNodeList(xmlXPathObjectPtr range) {
1416 /* pointers to generated nodes */
1417 xmlNodePtr list = NULL, last = NULL, parent = NULL, tmp;
1418 /* pointers to traversal nodes */
1419 xmlNodePtr start, cur, end;
1420 int index1, index2;
1421
1422 if (range == NULL)
1423 return(NULL);
1424 if (range->type != XPATH_RANGE)
1425 return(NULL);
1426 start = (xmlNodePtr) range->user;
1427
1428 if ((start == NULL) || (start->type == XML_NAMESPACE_DECL))
1429 return(NULL);
1430 end = range->user2;
1431 if (end == NULL)
1432 return(xmlCopyNode(start, 1));
1433 if (end->type == XML_NAMESPACE_DECL)
1434 return(NULL);
1435
1436 cur = start;
1437 index1 = range->index;
1438 index2 = range->index2;
1439 while (cur != NULL) {
1440 if (cur == end) {
1441 if (cur->type == XML_TEXT_NODE) {
1442 const xmlChar *content = cur->content;
1443 int len;
1444
1445 if (content == NULL) {
1446 tmp = xmlNewTextLen(NULL, 0);
1447 } else {
1448 len = index2;
1449 if ((cur == start) && (index1 > 1)) {
1450 content += (index1 - 1);
1451 len -= (index1 - 1);
1452 index1 = 0;
1453 } else {
1454 len = index2;
1455 }
1456 tmp = xmlNewTextLen(content, len);
1457 }
1458 /* single sub text node selection */
1459 if (list == NULL)
1460 return(tmp);
1461 /* prune and return full set */
1462 if (last != NULL)
1463 xmlAddNextSibling(last, tmp);
1464 else
1465 xmlAddChild(parent, tmp);
1466 return(list);
1467 } else {
1468 tmp = xmlCopyNode(cur, 0);
1469 if (list == NULL) {
1470 list = tmp;
1471 parent = tmp;
1472 } else {
1473 if (last != NULL)
1474 parent = xmlAddNextSibling(last, tmp);
1475 else
1476 parent = xmlAddChild(parent, tmp);
1477 }
1478 last = NULL;
1479
1480 if (index2 > 1) {
1481 end = xmlXPtrGetNthChild(cur, index2 - 1);
1482 index2 = 0;
1483 }
1484 if ((cur == start) && (index1 > 1)) {
1485 cur = xmlXPtrGetNthChild(cur, index1 - 1);
1486 index1 = 0;
1487 } else {
1488 cur = cur->children;
1489 }
1490 /*
1491 * Now gather the remaining nodes from cur to end
1492 */
1493 continue; /* while */
1494 }
1495 } else if ((cur == start) &&
1496 (list == NULL) /* looks superfluous but ... */ ) {
1497 if ((cur->type == XML_TEXT_NODE) ||
1498 (cur->type == XML_CDATA_SECTION_NODE)) {
1499 const xmlChar *content = cur->content;
1500
1501 if (content == NULL) {
1502 tmp = xmlNewTextLen(NULL, 0);
1503 } else {
1504 if (index1 > 1) {
1505 content += (index1 - 1);
1506 }
1507 tmp = xmlNewText(content);
1508 }
1509 last = list = tmp;
1510 } else {
1511 if ((cur == start) && (index1 > 1)) {
1512 tmp = xmlCopyNode(cur, 0);
1513 list = tmp;
1514 parent = tmp;
1515 last = NULL;
1516 cur = xmlXPtrGetNthChild(cur, index1 - 1);
1517 index1 = 0;
1518 /*
1519 * Now gather the remaining nodes from cur to end
1520 */
1521 continue; /* while */
1522 }
1523 tmp = xmlCopyNode(cur, 1);
1524 list = tmp;
1525 parent = NULL;
1526 last = tmp;
1527 }
1528 } else {
1529 tmp = NULL;
1530 switch (cur->type) {
1531 case XML_DTD_NODE:
1532 case XML_ELEMENT_DECL:
1533 case XML_ATTRIBUTE_DECL:
1534 case XML_ENTITY_NODE:
1535 /* Do not copy DTD information */
1536 break;
1537 case XML_ENTITY_DECL:
1538 TODO /* handle crossing entities -> stack needed */
1539 break;
1540 case XML_XINCLUDE_START:
1541 case XML_XINCLUDE_END:
1542 /* don't consider it part of the tree content */
1543 break;
1544 case XML_ATTRIBUTE_NODE:
1545 /* Humm, should not happen ! */
1546 STRANGE
1547 break;
1548 default:
1549 tmp = xmlCopyNode(cur, 1);
1550 break;
1551 }
1552 if (tmp != NULL) {
1553 if ((list == NULL) || ((last == NULL) && (parent == NULL))) {
1554 STRANGE
1555 return(NULL);
1556 }
1557 if (last != NULL)
1558 xmlAddNextSibling(last, tmp);
1559 else {
1560 last = xmlAddChild(parent, tmp);
1561 }
1562 }
1563 }
1564 /*
1565 * Skip to next node in document order
1566 */
1567 if ((list == NULL) || ((last == NULL) && (parent == NULL))) {
1568 STRANGE
1569 return(NULL);
1570 }
1571 cur = xmlXPtrAdvanceNode(cur, NULL);
1572 }
1573 return(list);
1574}
1575
1576/**
1577 * xmlXPtrBuildNodeList:
1578 * @obj: the XPointer result from the evaluation.
1579 *
1580 * Build a node list tree copy of the XPointer result.
1581 * This will drop Attributes and Namespace declarations.
1582 *
1583 * Returns an xmlNodePtr list or NULL.
1584 * the caller has to free the node tree.
1585 */
1586xmlNodePtr
1587xmlXPtrBuildNodeList(xmlXPathObjectPtr obj) {
1588 xmlNodePtr list = NULL, last = NULL;
1589 int i;
1590
1591 if (obj == NULL)
1592 return(NULL);
1593 switch (obj->type) {
1594 case XPATH_NODESET: {
1595 xmlNodeSetPtr set = obj->nodesetval;
1596 if (set == NULL)
1597 return(NULL);
1598 for (i = 0;i < set->nodeNr;i++) {
1599 if (set->nodeTab[i] == NULL)
1600 continue;
1601 switch (set->nodeTab[i]->type) {
1602 case XML_TEXT_NODE:
1603 case XML_CDATA_SECTION_NODE:
1604 case XML_ELEMENT_NODE:
1605 case XML_ENTITY_REF_NODE:
1606 case XML_ENTITY_NODE:
1607 case XML_PI_NODE:
1608 case XML_COMMENT_NODE:
1609 case XML_DOCUMENT_NODE:
1610 case XML_HTML_DOCUMENT_NODE:
1611 case XML_XINCLUDE_START:
1612 case XML_XINCLUDE_END:
1613 break;
1614 case XML_ATTRIBUTE_NODE:
1615 case XML_NAMESPACE_DECL:
1616 case XML_DOCUMENT_TYPE_NODE:
1617 case XML_DOCUMENT_FRAG_NODE:
1618 case XML_NOTATION_NODE:
1619 case XML_DTD_NODE:
1620 case XML_ELEMENT_DECL:
1621 case XML_ATTRIBUTE_DECL:
1622 case XML_ENTITY_DECL:
1623 continue; /* for */
1624 }
1625 if (last == NULL)
1626 list = last = xmlCopyNode(set->nodeTab[i], 1);
1627 else {
1628 xmlAddNextSibling(last, xmlCopyNode(set->nodeTab[i], 1));
1629 if (last->next != NULL)
1630 last = last->next;
1631 }
1632 }
1633 break;
1634 }
1635 case XPATH_LOCATIONSET: {
1636 xmlLocationSetPtr set = (xmlLocationSetPtr) obj->user;
1637 if (set == NULL)
1638 return(NULL);
1639 for (i = 0;i < set->locNr;i++) {
1640 if (last == NULL)
1641 list = last = xmlXPtrBuildNodeList(set->locTab[i]);
1642 else
1643 xmlAddNextSibling(last,
1644 xmlXPtrBuildNodeList(set->locTab[i]));
1645 if (last != NULL) {
1646 while (last->next != NULL)
1647 last = last->next;
1648 }
1649 }
1650 break;
1651 }
1652 case XPATH_RANGE:
1653 return(xmlXPtrBuildRangeNodeList(obj));
1654 case XPATH_POINT:
1655 return(xmlCopyNode(obj->user, 0));
1656 default:
1657 break;
1658 }
1659 return(list);
1660}
1661
1662/************************************************************************
1663 * *
1664 * XPointer functions *
1665 * *
1666 ************************************************************************/
1667
1668/**
1669 * xmlXPtrNbLocChildren:
1670 * @node: an xmlNodePtr
1671 *
1672 * Count the number of location children of @node or the length of the
1673 * string value in case of text/PI/Comments nodes
1674 *
1675 * Returns the number of location children
1676 */
1677static int
1678xmlXPtrNbLocChildren(xmlNodePtr node) {
1679 int ret = 0;
1680 if (node == NULL)
1681 return(-1);
1682 switch (node->type) {
1683 case XML_HTML_DOCUMENT_NODE:
1684 case XML_DOCUMENT_NODE:
1685 case XML_ELEMENT_NODE:
1686 node = node->children;
1687 while (node != NULL) {
1688 if (node->type == XML_ELEMENT_NODE)
1689 ret++;
1690 node = node->next;
1691 }
1692 break;
1693 case XML_ATTRIBUTE_NODE:
1694 return(-1);
1695
1696 case XML_PI_NODE:
1697 case XML_COMMENT_NODE:
1698 case XML_TEXT_NODE:
1699 case XML_CDATA_SECTION_NODE:
1700 case XML_ENTITY_REF_NODE:
1701 ret = xmlStrlen(node->content);
1702 break;
1703 default:
1704 return(-1);
1705 }
1706 return(ret);
1707}
1708
1709/**
1710 * xmlXPtrHereFunction:
1711 * @ctxt: the XPointer Parser context
1712 * @nargs: the number of args
1713 *
1714 * Function implementing here() operation
1715 * as described in 5.4.3
1716 */
1717static void
1718xmlXPtrHereFunction(xmlXPathParserContextPtr ctxt, int nargs) {
1719 CHECK_ARITY(0);
1720
1721 if (ctxt->context->here == NULL)
1722 XP_ERROR(XPTR_SYNTAX_ERROR);
1723
1724 valuePush(ctxt, xmlXPtrNewLocationSetNodes(ctxt->context->here, NULL));
1725}
1726
1727/**
1728 * xmlXPtrOriginFunction:
1729 * @ctxt: the XPointer Parser context
1730 * @nargs: the number of args
1731 *
1732 * Function implementing origin() operation
1733 * as described in 5.4.3
1734 */
1735static void
1736xmlXPtrOriginFunction(xmlXPathParserContextPtr ctxt, int nargs) {
1737 CHECK_ARITY(0);
1738
1739 if (ctxt->context->origin == NULL)
1740 XP_ERROR(XPTR_SYNTAX_ERROR);
1741
1742 valuePush(ctxt, xmlXPtrNewLocationSetNodes(ctxt->context->origin, NULL));
1743}
1744
1745/**
1746 * xmlXPtrStartPointFunction:
1747 * @ctxt: the XPointer Parser context
1748 * @nargs: the number of args
1749 *
1750 * Function implementing start-point() operation
1751 * as described in 5.4.3
1752 * ----------------
1753 * location-set start-point(location-set)
1754 *
1755 * For each location x in the argument location-set, start-point adds a
1756 * location of type point to the result location-set. That point represents
1757 * the start point of location x and is determined by the following rules:
1758 *
1759 * - If x is of type point, the start point is x.
1760 * - If x is of type range, the start point is the start point of x.
1761 * - If x is of type root, element, text, comment, or processing instruction,
1762 * - the container node of the start point is x and the index is 0.
1763 * - If x is of type attribute or namespace, the function must signal a
1764 * syntax error.
1765 * ----------------
1766 *
1767 */
1768static void
1769xmlXPtrStartPointFunction(xmlXPathParserContextPtr ctxt, int nargs) {
1770 xmlXPathObjectPtr tmp, obj, point;
1771 xmlLocationSetPtr newset = NULL;
1772 xmlLocationSetPtr oldset = NULL;
1773
1774 CHECK_ARITY(1);
1775 if ((ctxt->value == NULL) ||
1776 ((ctxt->value->type != XPATH_LOCATIONSET) &&
1777 (ctxt->value->type != XPATH_NODESET)))
1778 XP_ERROR(XPATH_INVALID_TYPE)
1779
1780 obj = valuePop(ctxt);
1781 if (obj->type == XPATH_NODESET) {
1782 /*
1783 * First convert to a location set
1784 */
1785 tmp = xmlXPtrNewLocationSetNodeSet(obj->nodesetval);
1786 xmlXPathFreeObject(obj);
1787 if (tmp == NULL)
1788 XP_ERROR(XPATH_MEMORY_ERROR)
1789 obj = tmp;
1790 }
1791
1792 newset = xmlXPtrLocationSetCreate(NULL);
1793 if (newset == NULL) {
1794 xmlXPathFreeObject(obj);
1795 XP_ERROR(XPATH_MEMORY_ERROR);
1796 }
1797 oldset = (xmlLocationSetPtr) obj->user;
1798 if (oldset != NULL) {
1799 int i;
1800
1801 for (i = 0; i < oldset->locNr; i++) {
1802 tmp = oldset->locTab[i];
1803 if (tmp == NULL)
1804 continue;
1805 point = NULL;
1806 switch (tmp->type) {
1807 case XPATH_POINT:
1808 point = xmlXPtrNewPoint(tmp->user, tmp->index);
1809 break;
1810 case XPATH_RANGE: {
1811 xmlNodePtr node = tmp->user;
1812 if (node != NULL) {
1813 if ((node->type == XML_ATTRIBUTE_NODE) ||
1814 (node->type == XML_NAMESPACE_DECL)) {
1815 xmlXPathFreeObject(obj);
1816 xmlXPtrFreeLocationSet(newset);
1817 XP_ERROR(XPTR_SYNTAX_ERROR);
1818 }
1819 point = xmlXPtrNewPoint(node, tmp->index);
1820 }
1821 break;
1822 }
1823 default:
1824 /*** Should we raise an error ?
1825 xmlXPathFreeObject(obj);
1826 xmlXPathFreeObject(newset);
1827 XP_ERROR(XPATH_INVALID_TYPE)
1828 ***/
1829 break;
1830 }
1831 if (point != NULL)
1832 xmlXPtrLocationSetAdd(newset, point);
1833 }
1834 }
1835 xmlXPathFreeObject(obj);
1836 valuePush(ctxt, xmlXPtrWrapLocationSet(newset));
1837}
1838
1839/**
1840 * xmlXPtrEndPointFunction:
1841 * @ctxt: the XPointer Parser context
1842 * @nargs: the number of args
1843 *
1844 * Function implementing end-point() operation
1845 * as described in 5.4.3
1846 * ----------------------------
1847 * location-set end-point(location-set)
1848 *
1849 * For each location x in the argument location-set, end-point adds a
1850 * location of type point to the result location-set. That point represents
1851 * the end point of location x and is determined by the following rules:
1852 *
1853 * - If x is of type point, the resulting point is x.
1854 * - If x is of type range, the resulting point is the end point of x.
1855 * - If x is of type root or element, the container node of the resulting
1856 * point is x and the index is the number of location children of x.
1857 * - If x is of type text, comment, or processing instruction, the container
1858 * node of the resulting point is x and the index is the length of the
1859 * string-value of x.
1860 * - If x is of type attribute or namespace, the function must signal a
1861 * syntax error.
1862 * ----------------------------
1863 */
1864static void
1865xmlXPtrEndPointFunction(xmlXPathParserContextPtr ctxt, int nargs) {
1866 xmlXPathObjectPtr tmp, obj, point;
1867 xmlLocationSetPtr newset = NULL;
1868 xmlLocationSetPtr oldset = NULL;
1869
1870 CHECK_ARITY(1);
1871 if ((ctxt->value == NULL) ||
1872 ((ctxt->value->type != XPATH_LOCATIONSET) &&
1873 (ctxt->value->type != XPATH_NODESET)))
1874 XP_ERROR(XPATH_INVALID_TYPE)
1875
1876 obj = valuePop(ctxt);
1877 if (obj->type == XPATH_NODESET) {
1878 /*
1879 * First convert to a location set
1880 */
1881 tmp = xmlXPtrNewLocationSetNodeSet(obj->nodesetval);
1882 xmlXPathFreeObject(obj);
1883 if (tmp == NULL)
1884 XP_ERROR(XPATH_MEMORY_ERROR)
1885 obj = tmp;
1886 }
1887
1888 newset = xmlXPtrLocationSetCreate(NULL);
1889 if (newset == NULL) {
1890 xmlXPathFreeObject(obj);
1891 XP_ERROR(XPATH_MEMORY_ERROR);
1892 }
1893 oldset = (xmlLocationSetPtr) obj->user;
1894 if (oldset != NULL) {
1895 int i;
1896
1897 for (i = 0; i < oldset->locNr; i++) {
1898 tmp = oldset->locTab[i];
1899 if (tmp == NULL)
1900 continue;
1901 point = NULL;
1902 switch (tmp->type) {
1903 case XPATH_POINT:
1904 point = xmlXPtrNewPoint(tmp->user, tmp->index);
1905 break;
1906 case XPATH_RANGE: {
1907 xmlNodePtr node = tmp->user2;
1908 if (node != NULL) {
1909 if ((node->type == XML_ATTRIBUTE_NODE) ||
1910 (node->type == XML_NAMESPACE_DECL)) {
1911 xmlXPathFreeObject(obj);
1912 xmlXPtrFreeLocationSet(newset);
1913 XP_ERROR(XPTR_SYNTAX_ERROR);
1914 }
1915 point = xmlXPtrNewPoint(node, tmp->index2);
1916 } else if (tmp->user == NULL) {
1917 point = xmlXPtrNewPoint(node,
1918 xmlXPtrNbLocChildren(node));
1919 }
1920 break;
1921 }
1922 default:
1923 /*** Should we raise an error ?
1924 xmlXPathFreeObject(obj);
1925 xmlXPathFreeObject(newset);
1926 XP_ERROR(XPATH_INVALID_TYPE)
1927 ***/
1928 break;
1929 }
1930 if (point != NULL)
1931 xmlXPtrLocationSetAdd(newset, point);
1932 }
1933 }
1934 xmlXPathFreeObject(obj);
1935 valuePush(ctxt, xmlXPtrWrapLocationSet(newset));
1936}
1937
1938
1939/**
1940 * xmlXPtrCoveringRange:
1941 * @ctxt: the XPointer Parser context
1942 * @loc: the location for which the covering range must be computed
1943 *
1944 * A covering range is a range that wholly encompasses a location
1945 * Section 5.3.3. Covering Ranges for All Location Types
1946 * http://www.w3.org/TR/xptr#N2267
1947 *
1948 * Returns a new location or NULL in case of error
1949 */
1950static xmlXPathObjectPtr
1951xmlXPtrCoveringRange(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr loc) {
1952 if (loc == NULL)
1953 return(NULL);
1954 if ((ctxt == NULL) || (ctxt->context == NULL) ||
1955 (ctxt->context->doc == NULL))
1956 return(NULL);
1957 switch (loc->type) {
1958 case XPATH_POINT:
1959 return(xmlXPtrNewRange(loc->user, loc->index,
1960 loc->user, loc->index));
1961 case XPATH_RANGE:
1962 if (loc->user2 != NULL) {
1963 return(xmlXPtrNewRange(loc->user, loc->index,
1964 loc->user2, loc->index2));
1965 } else {
1966 xmlNodePtr node = (xmlNodePtr) loc->user;
1967 if (node == (xmlNodePtr) ctxt->context->doc) {
1968 return(xmlXPtrNewRange(node, 0, node,
1969 xmlXPtrGetArity(node)));
1970 } else {
1971 switch (node->type) {
1972 case XML_ATTRIBUTE_NODE:
1973 /* !!! our model is slightly different than XPath */
1974 return(xmlXPtrNewRange(node, 0, node,
1975 xmlXPtrGetArity(node)));
1976 case XML_ELEMENT_NODE:
1977 case XML_TEXT_NODE:
1978 case XML_CDATA_SECTION_NODE:
1979 case XML_ENTITY_REF_NODE:
1980 case XML_PI_NODE:
1981 case XML_COMMENT_NODE:
1982 case XML_DOCUMENT_NODE:
1983 case XML_NOTATION_NODE:
1984 case XML_HTML_DOCUMENT_NODE: {
1985 int indx = xmlXPtrGetIndex(node);
1986
1987 node = node->parent;
1988 return(xmlXPtrNewRange(node, indx - 1,
1989 node, indx + 1));
1990 }
1991 default:
1992 return(NULL);
1993 }
1994 }
1995 }
1996 default:
1997 TODO /* missed one case ??? */
1998 }
1999 return(NULL);
2000}
2001
2002/**
2003 * xmlXPtrRangeFunction:
2004 * @ctxt: the XPointer Parser context
2005 * @nargs: the number of args
2006 *
2007 * Function implementing the range() function 5.4.3
2008 * location-set range(location-set )
2009 *
2010 * The range function returns ranges covering the locations in
2011 * the argument location-set. For each location x in the argument
2012 * location-set, a range location representing the covering range of
2013 * x is added to the result location-set.
2014 */
2015static void
2016xmlXPtrRangeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2017 int i;
2018 xmlXPathObjectPtr set;
2019 xmlLocationSetPtr oldset;
2020 xmlLocationSetPtr newset;
2021
2022 CHECK_ARITY(1);
2023 if ((ctxt->value == NULL) ||
2024 ((ctxt->value->type != XPATH_LOCATIONSET) &&
2025 (ctxt->value->type != XPATH_NODESET)))
2026 XP_ERROR(XPATH_INVALID_TYPE)
2027
2028 set = valuePop(ctxt);
2029 if (set->type == XPATH_NODESET) {
2030 xmlXPathObjectPtr tmp;
2031
2032 /*
2033 * First convert to a location set
2034 */
2035 tmp = xmlXPtrNewLocationSetNodeSet(set->nodesetval);
2036 xmlXPathFreeObject(set);
2037 if (tmp == NULL)
2038 XP_ERROR(XPATH_MEMORY_ERROR)
2039 set = tmp;
2040 }
2041 oldset = (xmlLocationSetPtr) set->user;
2042
2043 /*
2044 * The loop is to compute the covering range for each item and add it
2045 */
2046 newset = xmlXPtrLocationSetCreate(NULL);
2047 if (newset == NULL) {
2048 xmlXPathFreeObject(set);
2049 XP_ERROR(XPATH_MEMORY_ERROR);
2050 }
2051 if (oldset != NULL) {
2052 for (i = 0;i < oldset->locNr;i++) {
2053 xmlXPtrLocationSetAdd(newset,
2054 xmlXPtrCoveringRange(ctxt, oldset->locTab[i]));
2055 }
2056 }
2057
2058 /*
2059 * Save the new value and cleanup
2060 */
2061 valuePush(ctxt, xmlXPtrWrapLocationSet(newset));
2062 xmlXPathFreeObject(set);
2063}
2064
2065/**
2066 * xmlXPtrInsideRange:
2067 * @ctxt: the XPointer Parser context
2068 * @loc: the location for which the inside range must be computed
2069 *
2070 * A inside range is a range described in the range-inside() description
2071 *
2072 * Returns a new location or NULL in case of error
2073 */
2074static xmlXPathObjectPtr
2075xmlXPtrInsideRange(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr loc) {
2076 if (loc == NULL)
2077 return(NULL);
2078 if ((ctxt == NULL) || (ctxt->context == NULL) ||
2079 (ctxt->context->doc == NULL))
2080 return(NULL);
2081 switch (loc->type) {
2082 case XPATH_POINT: {
2083 xmlNodePtr node = (xmlNodePtr) loc->user;
2084 switch (node->type) {
2085 case XML_PI_NODE:
2086 case XML_COMMENT_NODE:
2087 case XML_TEXT_NODE:
2088 case XML_CDATA_SECTION_NODE: {
2089 if (node->content == NULL) {
2090 return(xmlXPtrNewRange(node, 0, node, 0));
2091 } else {
2092 return(xmlXPtrNewRange(node, 0, node,
2093 xmlStrlen(node->content)));
2094 }
2095 }
2096 case XML_ATTRIBUTE_NODE:
2097 case XML_ELEMENT_NODE:
2098 case XML_ENTITY_REF_NODE:
2099 case XML_DOCUMENT_NODE:
2100 case XML_NOTATION_NODE:
2101 case XML_HTML_DOCUMENT_NODE: {
2102 return(xmlXPtrNewRange(node, 0, node,
2103 xmlXPtrGetArity(node)));
2104 }
2105 default:
2106 break;
2107 }
2108 return(NULL);
2109 }
2110 case XPATH_RANGE: {
2111 xmlNodePtr node = (xmlNodePtr) loc->user;
2112 if (loc->user2 != NULL) {
2113 return(xmlXPtrNewRange(node, loc->index,
2114 loc->user2, loc->index2));
2115 } else {
2116 switch (node->type) {
2117 case XML_PI_NODE:
2118 case XML_COMMENT_NODE:
2119 case XML_TEXT_NODE:
2120 case XML_CDATA_SECTION_NODE: {
2121 if (node->content == NULL) {
2122 return(xmlXPtrNewRange(node, 0, node, 0));
2123 } else {
2124 return(xmlXPtrNewRange(node, 0, node,
2125 xmlStrlen(node->content)));
2126 }
2127 }
2128 case XML_ATTRIBUTE_NODE:
2129 case XML_ELEMENT_NODE:
2130 case XML_ENTITY_REF_NODE:
2131 case XML_DOCUMENT_NODE:
2132 case XML_NOTATION_NODE:
2133 case XML_HTML_DOCUMENT_NODE: {
2134 return(xmlXPtrNewRange(node, 0, node,
2135 xmlXPtrGetArity(node)));
2136 }
2137 default:
2138 break;
2139 }
2140 return(NULL);
2141 }
2142 }
2143 default:
2144 TODO /* missed one case ??? */
2145 }
2146 return(NULL);
2147}
2148
2149/**
2150 * xmlXPtrRangeInsideFunction:
2151 * @ctxt: the XPointer Parser context
2152 * @nargs: the number of args
2153 *
2154 * Function implementing the range-inside() function 5.4.3
2155 * location-set range-inside(location-set )
2156 *
2157 * The range-inside function returns ranges covering the contents of
2158 * the locations in the argument location-set. For each location x in
2159 * the argument location-set, a range location is added to the result
2160 * location-set. If x is a range location, then x is added to the
2161 * result location-set. If x is not a range location, then x is used
2162 * as the container location of the start and end points of the range
2163 * location to be added; the index of the start point of the range is
2164 * zero; if the end point is a character point then its index is the
2165 * length of the string-value of x, and otherwise is the number of
2166 * location children of x.
2167 *
2168 */
2169static void
2170xmlXPtrRangeInsideFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2171 int i;
2172 xmlXPathObjectPtr set;
2173 xmlLocationSetPtr oldset;
2174 xmlLocationSetPtr newset;
2175
2176 CHECK_ARITY(1);
2177 if ((ctxt->value == NULL) ||
2178 ((ctxt->value->type != XPATH_LOCATIONSET) &&
2179 (ctxt->value->type != XPATH_NODESET)))
2180 XP_ERROR(XPATH_INVALID_TYPE)
2181
2182 set = valuePop(ctxt);
2183 if (set->type == XPATH_NODESET) {
2184 xmlXPathObjectPtr tmp;
2185
2186 /*
2187 * First convert to a location set
2188 */
2189 tmp = xmlXPtrNewLocationSetNodeSet(set->nodesetval);
2190 xmlXPathFreeObject(set);
2191 if (tmp == NULL)
2192 XP_ERROR(XPATH_MEMORY_ERROR)
2193 set = tmp;
2194 }
2195
2196 /*
2197 * The loop is to compute the covering range for each item and add it
2198 */
2199 newset = xmlXPtrLocationSetCreate(NULL);
2200 if (newset == NULL) {
2201 xmlXPathFreeObject(set);
2202 XP_ERROR(XPATH_MEMORY_ERROR);
2203 }
2204 oldset = (xmlLocationSetPtr) set->user;
2205 if (oldset != NULL) {
2206 for (i = 0;i < oldset->locNr;i++) {
2207 xmlXPtrLocationSetAdd(newset,
2208 xmlXPtrInsideRange(ctxt, oldset->locTab[i]));
2209 }
2210 }
2211
2212 /*
2213 * Save the new value and cleanup
2214 */
2215 valuePush(ctxt, xmlXPtrWrapLocationSet(newset));
2216 xmlXPathFreeObject(set);
2217}
2218
2219/**
2220 * xmlXPtrRangeToFunction:
2221 * @ctxt: the XPointer Parser context
2222 * @nargs: the number of args
2223 *
2224 * Implement the range-to() XPointer function
2225 *
2226 * Obsolete. range-to is not a real function but a special type of location
2227 * step which is handled in xpath.c.
2228 */
2229void
2230xmlXPtrRangeToFunction(xmlXPathParserContextPtr ctxt,
2231 int nargs ATTRIBUTE_UNUSED) {
2232 XP_ERROR(XPATH_EXPR_ERROR);
2233}
2234
2235/**
2236 * xmlXPtrAdvanceNode:
2237 * @cur: the node
2238 * @level: incremented/decremented to show level in tree
2239 *
2240 * Advance to the next element or text node in document order
2241 * TODO: add a stack for entering/exiting entities
2242 *
2243 * Returns -1 in case of failure, 0 otherwise
2244 */
2245xmlNodePtr
2246xmlXPtrAdvanceNode(xmlNodePtr cur, int *level) {
2247next:
2248 if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL))
2249 return(NULL);
2250 if (cur->children != NULL) {
2251 cur = cur->children ;
2252 if (level != NULL)
2253 (*level)++;
2254 goto found;
2255 }
2256skip: /* This label should only be needed if something is wrong! */
2257 if (cur->next != NULL) {
2258 cur = cur->next;
2259 goto found;
2260 }
2261 do {
2262 cur = cur->parent;
2263 if (level != NULL)
2264 (*level)--;
2265 if (cur == NULL) return(NULL);
2266 if (cur->next != NULL) {
2267 cur = cur->next;
2268 goto found;
2269 }
2270 } while (cur != NULL);
2271
2272found:
2273 if ((cur->type != XML_ELEMENT_NODE) &&
2274 (cur->type != XML_TEXT_NODE) &&
2275 (cur->type != XML_DOCUMENT_NODE) &&
2276 (cur->type != XML_HTML_DOCUMENT_NODE) &&
2277 (cur->type != XML_CDATA_SECTION_NODE)) {
2278 if (cur->type == XML_ENTITY_REF_NODE) { /* Shouldn't happen */
2279 TODO
2280 goto skip;
2281 }
2282 goto next;
2283 }
2284 return(cur);
2285}
2286
2287/**
2288 * xmlXPtrAdvanceChar:
2289 * @node: the node
2290 * @indx: the indx
2291 * @bytes: the number of bytes
2292 *
2293 * Advance a point of the associated number of bytes (not UTF8 chars)
2294 *
2295 * Returns -1 in case of failure, 0 otherwise
2296 */
2297static int
2298xmlXPtrAdvanceChar(xmlNodePtr *node, int *indx, int bytes) {
2299 xmlNodePtr cur;
2300 int pos;
2301 int len;
2302
2303 if ((node == NULL) || (indx == NULL))
2304 return(-1);
2305 cur = *node;
2306 if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL))
2307 return(-1);
2308 pos = *indx;
2309
2310 while (bytes >= 0) {
2311 /*
2312 * First position to the beginning of the first text node
2313 * corresponding to this point
2314 */
2315 while ((cur != NULL) &&
2316 ((cur->type == XML_ELEMENT_NODE) ||
2317 (cur->type == XML_DOCUMENT_NODE) ||
2318 (cur->type == XML_HTML_DOCUMENT_NODE))) {
2319 if (pos > 0) {
2320 cur = xmlXPtrGetNthChild(cur, pos);
2321 pos = 0;
2322 } else {
2323 cur = xmlXPtrAdvanceNode(cur, NULL);
2324 pos = 0;
2325 }
2326 }
2327
2328 if (cur == NULL) {
2329 *node = NULL;
2330 *indx = 0;
2331 return(-1);
2332 }
2333
2334 /*
2335 * if there is no move needed return the current value.
2336 */
2337 if (pos == 0) pos = 1;
2338 if (bytes == 0) {
2339 *node = cur;
2340 *indx = pos;
2341 return(0);
2342 }
2343 /*
2344 * We should have a text (or cdata) node ...
2345 */
2346 len = 0;
2347 if ((cur->type != XML_ELEMENT_NODE) &&
2348 (cur->content != NULL)) {
2349 len = xmlStrlen(cur->content);
2350 }
2351 if (pos > len) {
2352 /* Strange, the indx in the text node is greater than it's len */
2353 STRANGE
2354 pos = len;
2355 }
2356 if (pos + bytes >= len) {
2357 bytes -= (len - pos);
2358 cur = xmlXPtrAdvanceNode(cur, NULL);
2359 pos = 0;
2360 } else if (pos + bytes < len) {
2361 pos += bytes;
2362 *node = cur;
2363 *indx = pos;
2364 return(0);
2365 }
2366 }
2367 return(-1);
2368}
2369
2370/**
2371 * xmlXPtrMatchString:
2372 * @string: the string to search
2373 * @start: the start textnode
2374 * @startindex: the start index
2375 * @end: the end textnode IN/OUT
2376 * @endindex: the end index IN/OUT
2377 *
2378 * Check whether the document contains @string at the position
2379 * (@start, @startindex) and limited by the (@end, @endindex) point
2380 *
2381 * Returns -1 in case of failure, 0 if not found, 1 if found in which case
2382 * (@start, @startindex) will indicate the position of the beginning
2383 * of the range and (@end, @endindex) will indicate the end
2384 * of the range
2385 */
2386static int
2387xmlXPtrMatchString(const xmlChar *string, xmlNodePtr start, int startindex,
2388 xmlNodePtr *end, int *endindex) {
2389 xmlNodePtr cur;
2390 int pos; /* 0 based */
2391 int len; /* in bytes */
2392 int stringlen; /* in bytes */
2393 int match;
2394
2395 if (string == NULL)
2396 return(-1);
2397 if ((start == NULL) || (start->type == XML_NAMESPACE_DECL))
2398 return(-1);
2399 if ((end == NULL) || (*end == NULL) ||
2400 ((*end)->type == XML_NAMESPACE_DECL) || (endindex == NULL))
2401 return(-1);
2402 cur = start;
2403 pos = startindex - 1;
2404 stringlen = xmlStrlen(string);
2405
2406 while (stringlen > 0) {
2407 if ((cur == *end) && (pos + stringlen > *endindex))
2408 return(0);
2409
2410 if ((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL)) {
2411 len = xmlStrlen(cur->content);
2412 if (len >= pos + stringlen) {
2413 match = (!xmlStrncmp(&cur->content[pos], string, stringlen));
2414 if (match) {
2415 *end = cur;
2416 *endindex = pos + stringlen;
2417 return(1);
2418 } else {
2419 return(0);
2420 }
2421 } else {
2422 int sub = len - pos;
2423 match = (!xmlStrncmp(&cur->content[pos], string, sub));
2424 if (match) {
2425 string = &string[sub];
2426 stringlen -= sub;
2427 } else {
2428 return(0);
2429 }
2430 }
2431 }
2432 cur = xmlXPtrAdvanceNode(cur, NULL);
2433 if (cur == NULL)
2434 return(0);
2435 pos = 0;
2436 }
2437 return(1);
2438}
2439
2440/**
2441 * xmlXPtrSearchString:
2442 * @string: the string to search
2443 * @start: the start textnode IN/OUT
2444 * @startindex: the start index IN/OUT
2445 * @end: the end textnode
2446 * @endindex: the end index
2447 *
2448 * Search the next occurrence of @string within the document content
2449 * until the (@end, @endindex) point is reached
2450 *
2451 * Returns -1 in case of failure, 0 if not found, 1 if found in which case
2452 * (@start, @startindex) will indicate the position of the beginning
2453 * of the range and (@end, @endindex) will indicate the end
2454 * of the range
2455 */
2456static int
2457xmlXPtrSearchString(const xmlChar *string, xmlNodePtr *start, int *startindex,
2458 xmlNodePtr *end, int *endindex) {
2459 xmlNodePtr cur;
2460 const xmlChar *str;
2461 int pos; /* 0 based */
2462 int len; /* in bytes */
2463 xmlChar first;
2464
2465 if (string == NULL)
2466 return(-1);
2467 if ((start == NULL) || (*start == NULL) ||
2468 ((*start)->type == XML_NAMESPACE_DECL) || (startindex == NULL))
2469 return(-1);
2470 if ((end == NULL) || (endindex == NULL))
2471 return(-1);
2472 cur = *start;
2473 pos = *startindex - 1;
2474 first = string[0];
2475
2476 while (cur != NULL) {
2477 if ((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL)) {
2478 len = xmlStrlen(cur->content);
2479 while (pos <= len) {
2480 if (first != 0) {
2481 str = xmlStrchr(&cur->content[pos], first);
2482 if (str != NULL) {
2483 pos = (str - (xmlChar *)(cur->content));
2484 if (xmlXPtrMatchString(string, cur, pos + 1,
2485 end, endindex)) {
2486 *start = cur;
2487 *startindex = pos + 1;
2488 return(1);
2489 }
2490 pos++;
2491 } else {
2492 pos = len + 1;
2493 }
2494 } else {
2495 /*
2496 * An empty string is considered to match before each
2497 * character of the string-value and after the final
2498 * character.
2499 */
2500 *start = cur;
2501 *startindex = pos + 1;
2502 *end = cur;
2503 *endindex = pos + 1;
2504 return(1);
2505 }
2506 }
2507 }
2508 if ((cur == *end) && (pos >= *endindex))
2509 return(0);
2510 cur = xmlXPtrAdvanceNode(cur, NULL);
2511 if (cur == NULL)
2512 return(0);
2513 pos = 1;
2514 }
2515 return(0);
2516}
2517
2518/**
2519 * xmlXPtrGetLastChar:
2520 * @node: the node
2521 * @index: the index
2522 *
2523 * Computes the point coordinates of the last char of this point
2524 *
2525 * Returns -1 in case of failure, 0 otherwise
2526 */
2527static int
2528xmlXPtrGetLastChar(xmlNodePtr *node, int *indx) {
2529 xmlNodePtr cur;
2530 int pos, len = 0;
2531
2532 if ((node == NULL) || (*node == NULL) ||
2533 ((*node)->type == XML_NAMESPACE_DECL) || (indx == NULL))
2534 return(-1);
2535 cur = *node;
2536 pos = *indx;
2537
2538 if ((cur->type == XML_ELEMENT_NODE) ||
2539 (cur->type == XML_DOCUMENT_NODE) ||
2540 (cur->type == XML_HTML_DOCUMENT_NODE)) {
2541 if (pos > 0) {
2542 cur = xmlXPtrGetNthChild(cur, pos);
2543 }
2544 }
2545 while (cur != NULL) {
2546 if (cur->last != NULL)
2547 cur = cur->last;
2548 else if ((cur->type != XML_ELEMENT_NODE) &&
2549 (cur->content != NULL)) {
2550 len = xmlStrlen(cur->content);
2551 break;
2552 } else {
2553 return(-1);
2554 }
2555 }
2556 if (cur == NULL)
2557 return(-1);
2558 *node = cur;
2559 *indx = len;
2560 return(0);
2561}
2562
2563/**
2564 * xmlXPtrGetStartPoint:
2565 * @obj: an range
2566 * @node: the resulting node
2567 * @indx: the resulting index
2568 *
2569 * read the object and return the start point coordinates.
2570 *
2571 * Returns -1 in case of failure, 0 otherwise
2572 */
2573static int
2574xmlXPtrGetStartPoint(xmlXPathObjectPtr obj, xmlNodePtr *node, int *indx) {
2575 if ((obj == NULL) || (node == NULL) || (indx == NULL))
2576 return(-1);
2577
2578 switch (obj->type) {
2579 case XPATH_POINT:
2580 *node = obj->user;
2581 if (obj->index <= 0)
2582 *indx = 0;
2583 else
2584 *indx = obj->index;
2585 return(0);
2586 case XPATH_RANGE:
2587 *node = obj->user;
2588 if (obj->index <= 0)
2589 *indx = 0;
2590 else
2591 *indx = obj->index;
2592 return(0);
2593 default:
2594 break;
2595 }
2596 return(-1);
2597}
2598
2599/**
2600 * xmlXPtrGetEndPoint:
2601 * @obj: an range
2602 * @node: the resulting node
2603 * @indx: the resulting indx
2604 *
2605 * read the object and return the end point coordinates.
2606 *
2607 * Returns -1 in case of failure, 0 otherwise
2608 */
2609static int
2610xmlXPtrGetEndPoint(xmlXPathObjectPtr obj, xmlNodePtr *node, int *indx) {
2611 if ((obj == NULL) || (node == NULL) || (indx == NULL))
2612 return(-1);
2613
2614 switch (obj->type) {
2615 case XPATH_POINT:
2616 *node = obj->user;
2617 if (obj->index <= 0)
2618 *indx = 0;
2619 else
2620 *indx = obj->index;
2621 return(0);
2622 case XPATH_RANGE:
2623 *node = obj->user;
2624 if (obj->index <= 0)
2625 *indx = 0;
2626 else
2627 *indx = obj->index;
2628 return(0);
2629 default:
2630 break;
2631 }
2632 return(-1);
2633}
2634
2635/**
2636 * xmlXPtrStringRangeFunction:
2637 * @ctxt: the XPointer Parser context
2638 * @nargs: the number of args
2639 *
2640 * Function implementing the string-range() function
2641 * range as described in 5.4.2
2642 *
2643 * ------------------------------
2644 * [Definition: For each location in the location-set argument,
2645 * string-range returns a set of string ranges, a set of substrings in a
2646 * string. Specifically, the string-value of the location is searched for
2647 * substrings that match the string argument, and the resulting location-set
2648 * will contain a range location for each non-overlapping match.]
2649 * An empty string is considered to match before each character of the
2650 * string-value and after the final character. Whitespace in a string
2651 * is matched literally, with no normalization except that provided by
2652 * XML for line ends. The third argument gives the position of the first
2653 * character to be in the resulting range, relative to the start of the
2654 * match. The default value is 1, which makes the range start immediately
2655 * before the first character of the matched string. The fourth argument
2656 * gives the number of characters in the range; the default is that the
2657 * range extends to the end of the matched string.
2658 *
2659 * Element boundaries, as well as entire embedded nodes such as processing
2660 * instructions and comments, are ignored as defined in [XPath].
2661 *
2662 * If the string in the second argument is not found in the string-value
2663 * of the location, or if a value in the third or fourth argument indicates
2664 * a string that is beyond the beginning or end of the document, the
2665 * expression fails.
2666 *
2667 * The points of the range-locations in the returned location-set will
2668 * all be character points.
2669 * ------------------------------
2670 */
2671static void
2672xmlXPtrStringRangeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2673 int i, startindex, endindex = 0, fendindex;
2674 xmlNodePtr start, end = 0, fend;
2675 xmlXPathObjectPtr set = NULL;
2676 xmlLocationSetPtr oldset;
2677 xmlLocationSetPtr newset = NULL;
2678 xmlXPathObjectPtr string = NULL;
2679 xmlXPathObjectPtr position = NULL;
2680 xmlXPathObjectPtr number = NULL;
2681 int found, pos = 0, num = 0;
2682
2683 /*
2684 * Grab the arguments
2685 */
2686 if ((nargs < 2) || (nargs > 4))
2687 XP_ERROR(XPATH_INVALID_ARITY);
2688
2689 if (nargs >= 4) {
2690 if ((ctxt->value == NULL) || (ctxt->value->type != XPATH_NUMBER)) {
2691 xmlXPathErr(ctxt, XPATH_INVALID_TYPE);
2692 goto error;
2693 }
2694 number = valuePop(ctxt);
2695 if (number != NULL)
2696 num = (int) number->floatval;
2697 }
2698 if (nargs >= 3) {
2699 if ((ctxt->value == NULL) || (ctxt->value->type != XPATH_NUMBER)) {
2700 xmlXPathErr(ctxt, XPATH_INVALID_TYPE);
2701 goto error;
2702 }
2703 position = valuePop(ctxt);
2704 if (position != NULL)
2705 pos = (int) position->floatval;
2706 }
2707 if ((ctxt->value == NULL) || (ctxt->value->type != XPATH_STRING)) {
2708 xmlXPathErr(ctxt, XPATH_INVALID_TYPE);
2709 goto error;
2710 }
2711 string = valuePop(ctxt);
2712 if ((ctxt->value == NULL) ||
2713 ((ctxt->value->type != XPATH_LOCATIONSET) &&
2714 (ctxt->value->type != XPATH_NODESET))) {
2715 xmlXPathErr(ctxt, XPATH_INVALID_TYPE);
2716 goto error;
2717 }
2718 set = valuePop(ctxt);
2719 newset = xmlXPtrLocationSetCreate(NULL);
2720 if (newset == NULL) {
2721 xmlXPathErr(ctxt, XPATH_MEMORY_ERROR);
2722 goto error;
2723 }
2724 if (set->nodesetval == NULL) {
2725 goto error;
2726 }
2727 if (set->type == XPATH_NODESET) {
2728 xmlXPathObjectPtr tmp;
2729
2730 /*
2731 * First convert to a location set
2732 */
2733 tmp = xmlXPtrNewLocationSetNodeSet(set->nodesetval);
2734 xmlXPathFreeObject(set);
2735 set = NULL;
2736 if (tmp == NULL) {
2737 xmlXPathErr(ctxt, XPATH_MEMORY_ERROR);
2738 goto error;
2739 }
2740 set = tmp;
2741 }
2742 oldset = (xmlLocationSetPtr) set->user;
2743
2744 /*
2745 * The loop is to search for each element in the location set
2746 * the list of location set corresponding to that search
2747 */
2748 for (i = 0;i < oldset->locNr;i++) {
2749
2750 xmlXPtrGetStartPoint(oldset->locTab[i], &start, &startindex);
2751 xmlXPtrGetEndPoint(oldset->locTab[i], &end, &endindex);
2752 xmlXPtrAdvanceChar(&start, &startindex, 0);
2753 xmlXPtrGetLastChar(&end, &endindex);
2754
2755 do {
2756 fend = end;
2757 fendindex = endindex;
2758 found = xmlXPtrSearchString(string->stringval, &start, &startindex,
2759 &fend, &fendindex);
2760 if (found == 1) {
2761 if (position == NULL) {
2762 xmlXPtrLocationSetAdd(newset,
2763 xmlXPtrNewRange(start, startindex, fend, fendindex));
2764 } else if (xmlXPtrAdvanceChar(&start, &startindex,
2765 pos - 1) == 0) {
2766 if ((number != NULL) && (num > 0)) {
2767 int rindx;
2768 xmlNodePtr rend;
2769 rend = start;
2770 rindx = startindex - 1;
2771 if (xmlXPtrAdvanceChar(&rend, &rindx,
2772 num) == 0) {
2773 xmlXPtrLocationSetAdd(newset,
2774 xmlXPtrNewRange(start, startindex,
2775 rend, rindx));
2776 }
2777 } else if ((number != NULL) && (num <= 0)) {
2778 xmlXPtrLocationSetAdd(newset,
2779 xmlXPtrNewRange(start, startindex,
2780 start, startindex));
2781 } else {
2782 xmlXPtrLocationSetAdd(newset,
2783 xmlXPtrNewRange(start, startindex,
2784 fend, fendindex));
2785 }
2786 }
2787 start = fend;
2788 startindex = fendindex;
2789 if (string->stringval[0] == 0)
2790 startindex++;
2791 }
2792 } while (found == 1);
2793 }
2794
2795 /*
2796 * Save the new value and cleanup
2797 */
2798error:
2799 if (newset != NULL)
2800 valuePush(ctxt, xmlXPtrWrapLocationSet(newset));
2801 xmlXPathFreeObject(set);
2802 xmlXPathFreeObject(string);
2803 if (position) xmlXPathFreeObject(position);
2804 if (number) xmlXPathFreeObject(number);
2805}
2806
2807/**
2808 * xmlXPtrEvalRangePredicate:
2809 * @ctxt: the XPointer Parser context
2810 *
2811 * [8] Predicate ::= '[' PredicateExpr ']'
2812 * [9] PredicateExpr ::= Expr
2813 *
2814 * Evaluate a predicate as in xmlXPathEvalPredicate() but for
2815 * a Location Set instead of a node set
2816 */
2817void
2818xmlXPtrEvalRangePredicate(xmlXPathParserContextPtr ctxt) {
2819 const xmlChar *cur;
2820 xmlXPathObjectPtr res;
2821 xmlXPathObjectPtr obj, tmp;
2822 xmlLocationSetPtr newset = NULL;
2823 xmlLocationSetPtr oldset;
2824 int i;
2825
2826 if (ctxt == NULL) return;
2827
2828 SKIP_BLANKS;
2829 if (CUR != '[') {
2830 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
2831 }
2832 NEXT;
2833 SKIP_BLANKS;
2834
2835 /*
2836 * Extract the old set, and then evaluate the result of the
2837 * expression for all the element in the set. use it to grow
2838 * up a new set.
2839 */
2840 CHECK_TYPE(XPATH_LOCATIONSET);
2841 obj = valuePop(ctxt);
2842 oldset = obj->user;
2843 ctxt->context->node = NULL;
2844
2845 if ((oldset == NULL) || (oldset->locNr == 0)) {
2846 ctxt->context->contextSize = 0;
2847 ctxt->context->proximityPosition = 0;
2848 xmlXPathEvalExpr(ctxt);
2849 res = valuePop(ctxt);
2850 if (res != NULL)
2851 xmlXPathFreeObject(res);
2852 valuePush(ctxt, obj);
2853 CHECK_ERROR;
2854 } else {
2855 /*
2856 * Save the expression pointer since we will have to evaluate
2857 * it multiple times. Initialize the new set.
2858 */
2859 cur = ctxt->cur;
2860 newset = xmlXPtrLocationSetCreate(NULL);
2861
2862 for (i = 0; i < oldset->locNr; i++) {
2863 ctxt->cur = cur;
2864
2865 /*
2866 * Run the evaluation with a node list made of a single item
2867 * in the nodeset.
2868 */
2869 ctxt->context->node = oldset->locTab[i]->user;
2870 tmp = xmlXPathNewNodeSet(ctxt->context->node);
2871 valuePush(ctxt, tmp);
2872 ctxt->context->contextSize = oldset->locNr;
2873 ctxt->context->proximityPosition = i + 1;
2874
2875 xmlXPathEvalExpr(ctxt);
2876 CHECK_ERROR;
2877
2878 /*
2879 * The result of the evaluation need to be tested to
2880 * decided whether the filter succeeded or not
2881 */
2882 res = valuePop(ctxt);
2883 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
2884 xmlXPtrLocationSetAdd(newset,
2885 xmlXPathObjectCopy(oldset->locTab[i]));
2886 }
2887
2888 /*
2889 * Cleanup
2890 */
2891 if (res != NULL)
2892 xmlXPathFreeObject(res);
2893 if (ctxt->value == tmp) {
2894 res = valuePop(ctxt);
2895 xmlXPathFreeObject(res);
2896 }
2897
2898 ctxt->context->node = NULL;
2899 }
2900
2901 /*
2902 * The result is used as the new evaluation set.
2903 */
2904 xmlXPathFreeObject(obj);
2905 ctxt->context->node = NULL;
2906 ctxt->context->contextSize = -1;
2907 ctxt->context->proximityPosition = -1;
2908 valuePush(ctxt, xmlXPtrWrapLocationSet(newset));
2909 }
2910 if (CUR != ']') {
2911 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
2912 }
2913
2914 NEXT;
2915 SKIP_BLANKS;
2916}
2917#endif /* LIBXML_XPTR_LOCS_ENABLED */
2918
2919#endif
2920
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use