Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
wine-mirror
GitHub Repository: wine-mirror/wine
Path: blob/master/libs/xml2/xpointer.c
4389 views
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
* [email protected]
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
*/
71
static void
72
xmlXPtrErrMemory(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
*/
87
static void LIBXML_ATTR_FORMAT(3,0)
88
xmlXPtrErr(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 */
131
xmlNodePtr 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
*/
138
static int
139
xmlXPtrGetArity(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
*/
161
static int
162
xmlXPtrGetIndex(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
*/
184
static xmlNodePtr
185
xmlXPtrGetNthChild(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
*/
223
static int
224
xmlXPtrCmpPoints(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
*/
249
static xmlXPathObjectPtr
250
xmlXPtrNewPoint(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
*/
276
static void
277
xmlXPtrRangeCheckOrder(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
*/
307
static int
308
xmlXPtrRangesEqual(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
*/
339
static xmlXPathObjectPtr
340
xmlXPtrNewRangeInternal(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
*/
378
xmlXPathObjectPtr
379
xmlXPtrNewRange(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
*/
406
xmlXPathObjectPtr
407
xmlXPtrNewRangePoints(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
*/
434
xmlXPathObjectPtr
435
xmlXPtrNewRangePointNode(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
*/
459
xmlXPathObjectPtr
460
xmlXPtrNewRangeNodePoint(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
*/
484
xmlXPathObjectPtr
485
xmlXPtrNewRangeNodes(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
*/
506
xmlXPathObjectPtr
507
xmlXPtrNewCollapsedRange(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
*/
526
xmlXPathObjectPtr
527
xmlXPtrNewRangeNodeObject(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
*/
574
xmlLocationSetPtr
575
xmlXPtrLocationSetCreate(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
*/
608
void
609
xmlXPtrLocationSetAdd(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
*/
661
xmlLocationSetPtr
662
xmlXPtrLocationSetMerge(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
*/
686
void
687
xmlXPtrLocationSetDel(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
*/
715
void
716
xmlXPtrLocationSetRemove(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
*/
731
void
732
xmlXPtrFreeLocationSet(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
*/
755
xmlXPathObjectPtr
756
xmlXPtrNewLocationSetNodes(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
*/
782
xmlXPathObjectPtr
783
xmlXPtrNewLocationSetNodeSet(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
*/
818
xmlXPathObjectPtr
819
xmlXPtrWrapLocationSet(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
840
static 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
*/
882
static void
883
xmlXPtrGetChildNo(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
940
static void
941
xmlXPtrEvalXPtrPart(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
*/
1103
static void
1104
xmlXPtrEvalFullXPtr(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
*/
1175
static void
1176
xmlXPtrEvalChildSeq(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
*/
1226
static void
1227
xmlXPtrEvalXPointer(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
1272
static
1273
void xmlXPtrStringRangeFunction(xmlXPathParserContextPtr ctxt, int nargs);
1274
static
1275
void xmlXPtrStartPointFunction(xmlXPathParserContextPtr ctxt, int nargs);
1276
static
1277
void xmlXPtrEndPointFunction(xmlXPathParserContextPtr ctxt, int nargs);
1278
static
1279
void xmlXPtrHereFunction(xmlXPathParserContextPtr ctxt, int nargs);
1280
static
1281
void xmlXPtrOriginFunction(xmlXPathParserContextPtr ctxt, int nargs);
1282
static
1283
void xmlXPtrRangeInsideFunction(xmlXPathParserContextPtr ctxt, int nargs);
1284
static
1285
void 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
*/
1299
xmlXPathContextPtr
1300
xmlXPtrNewContext(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
*/
1342
xmlXPathObjectPtr
1343
xmlXPtrEval(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
*/
1414
static xmlNodePtr
1415
xmlXPtrBuildRangeNodeList(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
*/
1586
xmlNodePtr
1587
xmlXPtrBuildNodeList(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
*/
1677
static int
1678
xmlXPtrNbLocChildren(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
*/
1717
static void
1718
xmlXPtrHereFunction(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
*/
1735
static void
1736
xmlXPtrOriginFunction(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
*/
1768
static void
1769
xmlXPtrStartPointFunction(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
*/
1864
static void
1865
xmlXPtrEndPointFunction(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
*/
1950
static xmlXPathObjectPtr
1951
xmlXPtrCoveringRange(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
*/
2015
static void
2016
xmlXPtrRangeFunction(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
*/
2074
static xmlXPathObjectPtr
2075
xmlXPtrInsideRange(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
*/
2169
static void
2170
xmlXPtrRangeInsideFunction(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
*/
2229
void
2230
xmlXPtrRangeToFunction(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
*/
2245
xmlNodePtr
2246
xmlXPtrAdvanceNode(xmlNodePtr cur, int *level) {
2247
next:
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
}
2256
skip: /* 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
2272
found:
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
*/
2297
static int
2298
xmlXPtrAdvanceChar(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
*/
2386
static int
2387
xmlXPtrMatchString(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
*/
2456
static int
2457
xmlXPtrSearchString(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
*/
2527
static int
2528
xmlXPtrGetLastChar(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
*/
2573
static int
2574
xmlXPtrGetStartPoint(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
*/
2609
static int
2610
xmlXPtrGetEndPoint(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
*/
2671
static void
2672
xmlXPtrStringRangeFunction(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
*/
2798
error:
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
*/
2817
void
2818
xmlXPtrEvalRangePredicate(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
2921