Coverage Report

Created: 2025-07-18 06:31

/src/libxml2/xpointer.c
Line
Count
Source (jump to first uncovered 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
#include "private/xpath.h"
49
50
/************************************************************************
51
 *                  *
52
 *    Some factorized error routines        *
53
 *                  *
54
 ************************************************************************/
55
56
/**
57
 * xmlXPtrErr:
58
 * @ctxt:  an XPTR evaluation context
59
 * @extra:  extra information
60
 *
61
 * Handle an XPointer error
62
 */
63
static void LIBXML_ATTR_FORMAT(3,0)
64
xmlXPtrErr(xmlXPathParserContextPtr ctxt, int code,
65
           const char * msg, const xmlChar *extra)
66
16.5k
{
67
16.5k
    xmlStructuredErrorFunc serror = NULL;
68
16.5k
    void *data = NULL;
69
16.5k
    xmlNodePtr node = NULL;
70
16.5k
    int res;
71
72
16.5k
    if (ctxt == NULL)
73
0
        return;
74
    /* Only report the first error */
75
16.5k
    if (ctxt->error != 0)
76
4
        return;
77
78
16.5k
    ctxt->error = code;
79
80
16.5k
    if (ctxt->context != NULL) {
81
16.5k
        xmlErrorPtr err = &ctxt->context->lastError;
82
83
        /* cleanup current last error */
84
16.5k
        xmlResetError(err);
85
86
16.5k
        err->domain = XML_FROM_XPOINTER;
87
16.5k
        err->code = code;
88
16.5k
        err->level = XML_ERR_ERROR;
89
16.5k
        err->str1 = (char *) xmlStrdup(ctxt->base);
90
16.5k
        if (err->str1 == NULL) {
91
4
            xmlXPathPErrMemory(ctxt);
92
4
            return;
93
4
        }
94
16.5k
        err->int1 = ctxt->cur - ctxt->base;
95
16.5k
        err->node = ctxt->context->debugNode;
96
97
16.5k
        serror = ctxt->context->error;
98
16.5k
        data = ctxt->context->userData;
99
16.5k
        node = ctxt->context->debugNode;
100
16.5k
    }
101
102
16.5k
    res = xmlRaiseError(serror, NULL, data, NULL, node,
103
16.5k
                        XML_FROM_XPOINTER, code, XML_ERR_ERROR, NULL, 0,
104
16.5k
                        (const char *) extra, (const char *) ctxt->base,
105
16.5k
                        NULL, ctxt->cur - ctxt->base, 0,
106
16.5k
                        msg, extra);
107
16.5k
    if (res < 0)
108
3
        xmlXPathPErrMemory(ctxt);
109
16.5k
}
110
111
/************************************************************************
112
 *                  *
113
 *    A few helper functions for child sequences    *
114
 *                  *
115
 ************************************************************************/
116
117
/**
118
 * xmlXPtrGetNthChild:
119
 * @cur:  the node
120
 * @no:  the child number
121
 *
122
 * Returns the @no'th element child of @cur or NULL
123
 */
124
static xmlNodePtr
125
5.08k
xmlXPtrGetNthChild(xmlNodePtr cur, int no) {
126
5.08k
    int i;
127
5.08k
    if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL))
128
0
  return(cur);
129
5.08k
    cur = cur->children;
130
10.0k
    for (i = 0;i <= no;cur = cur->next) {
131
10.0k
  if (cur == NULL)
132
4.85k
      return(cur);
133
5.16k
  if ((cur->type == XML_ELEMENT_NODE) ||
134
5.16k
      (cur->type == XML_DOCUMENT_NODE) ||
135
5.16k
      (cur->type == XML_HTML_DOCUMENT_NODE)) {
136
5.08k
      i++;
137
5.08k
      if (i == no)
138
231
    break;
139
5.08k
  }
140
5.16k
    }
141
231
    return(cur);
142
5.08k
}
143
144
/************************************************************************
145
 *                  *
146
 *      The parser          *
147
 *                  *
148
 ************************************************************************/
149
150
static void xmlXPtrEvalChildSeq(xmlXPathParserContextPtr ctxt, xmlChar *name);
151
152
/*
153
 * Macros for accessing the content. Those should be used only by the parser,
154
 * and not exported.
155
 *
156
 * Dirty macros, i.e. one need to make assumption on the context to use them
157
 *
158
 *   CUR     returns the current xmlChar value, i.e. a 8 bit value
159
 *           in ISO-Latin or UTF-8.
160
 *           This should be used internally by the parser
161
 *           only to compare to ASCII values otherwise it would break when
162
 *           running with UTF-8 encoding.
163
 *   NXT(n)  returns the n'th next xmlChar. Same as CUR is should be used only
164
 *           to compare on ASCII based substring.
165
 *   SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
166
 *           strings within the parser.
167
 *   CURRENT Returns the current char value, with the full decoding of
168
 *           UTF-8 if we are using this mode. It returns an int.
169
 *   NEXT    Skip to the next character, this does the proper decoding
170
 *           in UTF-8 mode. It also pop-up unfinished entities on the fly.
171
 *           It returns the pointer to the current xmlChar.
172
 */
173
174
3.58M
#define CUR (*ctxt->cur)
175
#define SKIP(val) ctxt->cur += (val)
176
9.69k
#define NXT(val) ctxt->cur[(val)]
177
178
#define SKIP_BLANKS             \
179
87.2k
    while (IS_BLANK_CH(*(ctxt->cur))) NEXT
180
181
#define CURRENT (*ctxt->cur)
182
902k
#define NEXT ((*ctxt->cur) ?  ctxt->cur++: ctxt->cur)
183
184
/*
185
 * xmlXPtrGetChildNo:
186
 * @ctxt:  the XPointer Parser context
187
 * @index:  the child number
188
 *
189
 * Move the current node of the nodeset on the stack to the
190
 * given child if found
191
 */
192
static void
193
9.01k
xmlXPtrGetChildNo(xmlXPathParserContextPtr ctxt, int indx) {
194
9.01k
    xmlNodePtr cur = NULL;
195
9.01k
    xmlXPathObjectPtr obj;
196
9.01k
    xmlNodeSetPtr oldset;
197
198
9.01k
    CHECK_TYPE(XPATH_NODESET);
199
8.49k
    obj = xmlXPathValuePop(ctxt);
200
8.49k
    oldset = obj->nodesetval;
201
8.49k
    if ((indx <= 0) || (oldset == NULL) || (oldset->nodeNr != 1)) {
202
3.40k
  xmlXPathFreeObject(obj);
203
3.40k
  xmlXPathValuePush(ctxt, xmlXPathNewNodeSet(NULL));
204
3.40k
  return;
205
3.40k
    }
206
5.08k
    cur = xmlXPtrGetNthChild(oldset->nodeTab[0], indx);
207
5.08k
    if (cur == NULL) {
208
4.85k
  xmlXPathFreeObject(obj);
209
4.85k
  xmlXPathValuePush(ctxt, xmlXPathNewNodeSet(NULL));
210
4.85k
  return;
211
4.85k
    }
212
231
    oldset->nodeTab[0] = cur;
213
231
    xmlXPathValuePush(ctxt, obj);
214
231
}
215
216
/**
217
 * xmlXPtrEvalXPtrPart:
218
 * @ctxt:  the XPointer Parser context
219
 * @name:  the preparsed Scheme for the XPtrPart
220
 *
221
 * XPtrPart ::= 'xpointer' '(' XPtrExpr ')'
222
 *            | Scheme '(' SchemeSpecificExpr ')'
223
 *
224
 * Scheme   ::=  NCName - 'xpointer' [VC: Non-XPointer schemes]
225
 *
226
 * SchemeSpecificExpr ::= StringWithBalancedParens
227
 *
228
 * StringWithBalancedParens ::=
229
 *              [^()]* ('(' StringWithBalancedParens ')' [^()]*)*
230
 *              [VC: Parenthesis escaping]
231
 *
232
 * XPtrExpr ::= Expr [VC: Parenthesis escaping]
233
 *
234
 * VC: Parenthesis escaping:
235
 *   The end of an XPointer part is signaled by the right parenthesis ")"
236
 *   character that is balanced with the left parenthesis "(" character
237
 *   that began the part. Any unbalanced parenthesis character inside the
238
 *   expression, even within literals, must be escaped with a circumflex (^)
239
 *   character preceding it. If the expression contains any literal
240
 *   occurrences of the circumflex, each must be escaped with an additional
241
 *   circumflex (that is, ^^). If the unescaped parentheses in the expression
242
 *   are not balanced, a syntax error results.
243
 *
244
 * Parse and evaluate an XPtrPart. Basically it generates the unescaped
245
 * string and if the scheme is 'xpointer' it will call the XPath interpreter.
246
 *
247
 * TODO: there is no new scheme registration mechanism
248
 */
249
250
static void
251
41.7k
xmlXPtrEvalXPtrPart(xmlXPathParserContextPtr ctxt, xmlChar *name) {
252
41.7k
    xmlChar *buffer, *cur;
253
41.7k
    int len;
254
41.7k
    int level;
255
256
41.7k
    if (name == NULL)
257
0
    name = xmlXPathParseName(ctxt);
258
41.7k
    if (name == NULL)
259
41.7k
  XP_ERROR(XPATH_EXPR_ERROR);
260
261
41.7k
    if (CUR != '(') {
262
2.54k
        xmlFree(name);
263
2.54k
  XP_ERROR(XPATH_EXPR_ERROR);
264
0
    }
265
39.2k
    NEXT;
266
39.2k
    level = 1;
267
268
39.2k
    len = xmlStrlen(ctxt->cur);
269
39.2k
    len++;
270
39.2k
    buffer = xmlMalloc(len);
271
39.2k
    if (buffer == NULL) {
272
6
        xmlXPathPErrMemory(ctxt);
273
6
        xmlFree(name);
274
6
  return;
275
6
    }
276
277
39.2k
    cur = buffer;
278
683k
    while (CUR != 0) {
279
680k
  if (CUR == ')') {
280
44.6k
      level--;
281
44.6k
      if (level == 0) {
282
36.8k
    NEXT;
283
36.8k
    break;
284
36.8k
      }
285
636k
  } else if (CUR == '(') {
286
7.89k
      level++;
287
628k
  } else if (CUR == '^') {
288
1.48k
            if ((NXT(1) == ')') || (NXT(1) == '(') || (NXT(1) == '^')) {
289
904
                NEXT;
290
904
            }
291
1.48k
  }
292
644k
        *cur++ = CUR;
293
644k
  NEXT;
294
644k
    }
295
39.2k
    *cur = 0;
296
297
39.2k
    if ((level != 0) && (CUR == 0)) {
298
2.38k
        xmlFree(name);
299
2.38k
  xmlFree(buffer);
300
2.38k
  XP_ERROR(XPTR_SYNTAX_ERROR);
301
0
    }
302
303
36.8k
    if (xmlStrEqual(name, (xmlChar *) "xpointer") ||
304
36.8k
        xmlStrEqual(name, (xmlChar *) "xpath1")) {
305
8.96k
  const xmlChar *oldBase = ctxt->base;
306
8.96k
  const xmlChar *oldCur = ctxt->cur;
307
308
8.96k
  ctxt->cur = ctxt->base = buffer;
309
  /*
310
   * To evaluate an xpointer scheme element (4.3) we need:
311
   *   context initialized to the root
312
   *   context position initialized to 1
313
   *   context size initialized to 1
314
   */
315
8.96k
  ctxt->context->node = (xmlNodePtr)ctxt->context->doc;
316
8.96k
  ctxt->context->proximityPosition = 1;
317
8.96k
  ctxt->context->contextSize = 1;
318
8.96k
  xmlXPathEvalExpr(ctxt);
319
8.96k
  ctxt->base = oldBase;
320
8.96k
        ctxt->cur = oldCur;
321
27.8k
    } else if (xmlStrEqual(name, (xmlChar *) "element")) {
322
2.19k
  const xmlChar *oldBase = ctxt->base;
323
2.19k
  const xmlChar *oldCur = ctxt->cur;
324
2.19k
  xmlChar *name2;
325
326
2.19k
  ctxt->cur = ctxt->base = buffer;
327
2.19k
  if (buffer[0] == '/') {
328
693
      xmlXPathRoot(ctxt);
329
693
      xmlXPtrEvalChildSeq(ctxt, NULL);
330
1.50k
  } else {
331
1.50k
      name2 = xmlXPathParseName(ctxt);
332
1.50k
      if (name2 == NULL) {
333
1.06k
                ctxt->base = oldBase;
334
1.06k
                ctxt->cur = oldCur;
335
1.06k
    xmlFree(buffer);
336
1.06k
                xmlFree(name);
337
1.06k
    XP_ERROR(XPATH_EXPR_ERROR);
338
0
      }
339
436
      xmlXPtrEvalChildSeq(ctxt, name2);
340
436
  }
341
1.12k
  ctxt->base = oldBase;
342
1.12k
        ctxt->cur = oldCur;
343
1.12k
#ifdef XPTR_XMLNS_SCHEME
344
25.6k
    } else if (xmlStrEqual(name, (xmlChar *) "xmlns")) {
345
12.8k
  const xmlChar *oldBase = ctxt->base;
346
12.8k
  const xmlChar *oldCur = ctxt->cur;
347
12.8k
  xmlChar *prefix;
348
349
12.8k
  ctxt->cur = ctxt->base = buffer;
350
12.8k
        prefix = xmlXPathParseNCName(ctxt);
351
12.8k
  if (prefix == NULL) {
352
1.27k
            ctxt->base = oldBase;
353
1.27k
            ctxt->cur = oldCur;
354
1.27k
      xmlFree(buffer);
355
1.27k
      xmlFree(name);
356
1.27k
      XP_ERROR(XPTR_SYNTAX_ERROR);
357
0
  }
358
11.5k
  SKIP_BLANKS;
359
11.5k
  if (CUR != '=') {
360
6.23k
            ctxt->base = oldBase;
361
6.23k
            ctxt->cur = oldCur;
362
6.23k
      xmlFree(prefix);
363
6.23k
      xmlFree(buffer);
364
6.23k
      xmlFree(name);
365
6.23k
      XP_ERROR(XPTR_SYNTAX_ERROR);
366
0
  }
367
5.30k
  NEXT;
368
5.30k
  SKIP_BLANKS;
369
370
5.30k
  if (xmlXPathRegisterNs(ctxt->context, prefix, ctxt->cur) < 0)
371
6
            xmlXPathPErrMemory(ctxt);
372
5.30k
        ctxt->base = oldBase;
373
5.30k
        ctxt->cur = oldCur;
374
5.30k
  xmlFree(prefix);
375
5.30k
#endif /* XPTR_XMLNS_SCHEME */
376
12.8k
    } else {
377
12.8k
        xmlXPtrErr(ctxt, XML_XPTR_UNKNOWN_SCHEME,
378
12.8k
       "unsupported scheme '%s'\n", name);
379
12.8k
    }
380
28.2k
    xmlFree(buffer);
381
28.2k
    xmlFree(name);
382
28.2k
}
383
384
/**
385
 * xmlXPtrEvalFullXPtr:
386
 * @ctxt:  the XPointer Parser context
387
 * @name:  the preparsed Scheme for the first XPtrPart
388
 *
389
 * FullXPtr ::= XPtrPart (S? XPtrPart)*
390
 *
391
 * As the specs says:
392
 * -----------
393
 * When multiple XPtrParts are provided, they must be evaluated in
394
 * left-to-right order. If evaluation of one part fails, the nexti
395
 * is evaluated. The following conditions cause XPointer part failure:
396
 *
397
 * - An unknown scheme
398
 * - A scheme that does not locate any sub-resource present in the resource
399
 * - A scheme that is not applicable to the media type of the resource
400
 *
401
 * The XPointer application must consume a failed XPointer part and
402
 * attempt to evaluate the next one, if any. The result of the first
403
 * XPointer part whose evaluation succeeds is taken to be the fragment
404
 * located by the XPointer as a whole. If all the parts fail, the result
405
 * for the XPointer as a whole is a sub-resource error.
406
 * -----------
407
 *
408
 * Parse and evaluate a Full XPtr i.e. possibly a cascade of XPath based
409
 * expressions or other schemes.
410
 */
411
static void
412
26.5k
xmlXPtrEvalFullXPtr(xmlXPathParserContextPtr ctxt, xmlChar *name) {
413
26.5k
    if (name == NULL)
414
0
    name = xmlXPathParseName(ctxt);
415
26.5k
    if (name == NULL)
416
26.5k
  XP_ERROR(XPATH_EXPR_ERROR);
417
48.1k
    while (name != NULL) {
418
41.7k
  ctxt->error = XPATH_EXPRESSION_OK;
419
41.7k
  xmlXPtrEvalXPtrPart(ctxt, name);
420
421
  /* in case of syntax error, break here */
422
41.7k
  if ((ctxt->error != XPATH_EXPRESSION_OK) &&
423
41.7k
            (ctxt->error != XML_XPTR_UNKNOWN_SCHEME))
424
19.9k
      return;
425
426
  /*
427
   * If the returned value is a non-empty nodeset
428
   * or location set, return here.
429
   */
430
21.8k
  if (ctxt->value != NULL) {
431
2.60k
      xmlXPathObjectPtr obj = ctxt->value;
432
433
2.60k
      switch (obj->type) {
434
729
    case XPATH_NODESET: {
435
729
        xmlNodeSetPtr loc = ctxt->value->nodesetval;
436
729
        if ((loc != NULL) && (loc->nodeNr > 0))
437
226
      return;
438
503
        break;
439
729
    }
440
1.87k
    default:
441
1.87k
        break;
442
2.60k
      }
443
444
      /*
445
       * Evaluating to improper values is equivalent to
446
       * a sub-resource error, clean-up the stack
447
       */
448
4.76k
      do {
449
4.76k
    obj = xmlXPathValuePop(ctxt);
450
4.76k
    if (obj != NULL) {
451
2.38k
        xmlXPathFreeObject(obj);
452
2.38k
    }
453
4.76k
      } while (obj != NULL);
454
2.38k
  }
455
456
  /*
457
   * Is there another XPointer part.
458
   */
459
21.6k
  SKIP_BLANKS;
460
21.6k
  name = xmlXPathParseName(ctxt);
461
21.6k
    }
462
26.5k
}
463
464
/**
465
 * xmlXPtrEvalChildSeq:
466
 * @ctxt:  the XPointer Parser context
467
 * @name:  a possible ID name of the child sequence
468
 *
469
 *  ChildSeq ::= '/1' ('/' [0-9]*)*
470
 *             | Name ('/' [0-9]*)+
471
 *
472
 * Parse and evaluate a Child Sequence. This routine also handle the
473
 * case of a Bare Name used to get a document ID.
474
 */
475
static void
476
11.6k
xmlXPtrEvalChildSeq(xmlXPathParserContextPtr ctxt, xmlChar *name) {
477
    /*
478
     * XPointer don't allow by syntax to address in multirooted trees
479
     * this might prove useful in some cases, warn about it.
480
     */
481
11.6k
    if ((name == NULL) && (CUR == '/') && (NXT(1) != '1')) {
482
3.66k
        xmlXPtrErr(ctxt, XML_XPTR_CHILDSEQ_START,
483
3.66k
       "warning: ChildSeq not starting by /1\n", NULL);
484
3.66k
    }
485
486
11.6k
    if (name != NULL) {
487
5.35k
  xmlXPathValuePush(ctxt, xmlXPathNewString(name));
488
5.35k
  xmlFree(name);
489
5.35k
  xmlXPathIdFunction(ctxt, 1);
490
5.35k
  CHECK_ERROR;
491
5.35k
    }
492
493
20.6k
    while (CUR == '/') {
494
9.01k
  int child = 0, overflow = 0;
495
9.01k
  NEXT;
496
497
53.0k
  while ((CUR >= '0') && (CUR <= '9')) {
498
43.9k
            int d = CUR - '0';
499
43.9k
            if (child > INT_MAX / 10)
500
12.0k
                overflow = 1;
501
31.9k
            else
502
31.9k
                child *= 10;
503
43.9k
            if (child > INT_MAX - d)
504
256
                overflow = 1;
505
43.7k
            else
506
43.7k
                child += d;
507
43.9k
      NEXT;
508
43.9k
  }
509
9.01k
        if (overflow)
510
999
            child = 0;
511
9.01k
  xmlXPtrGetChildNo(ctxt, child);
512
9.01k
    }
513
11.6k
}
514
515
516
/**
517
 * xmlXPtrEvalXPointer:
518
 * @ctxt:  the XPointer Parser context
519
 *
520
 *  XPointer ::= Name
521
 *             | ChildSeq
522
 *             | FullXPtr
523
 *
524
 * Parse and evaluate an XPointer
525
 */
526
static void
527
38.2k
xmlXPtrEvalXPointer(xmlXPathParserContextPtr ctxt) {
528
38.2k
    if (ctxt->valueTab == NULL) {
529
  /* Allocate the value stack */
530
38.2k
  ctxt->valueTab = (xmlXPathObjectPtr *)
531
38.2k
       xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
532
38.2k
  if (ctxt->valueTab == NULL) {
533
2
      xmlXPathPErrMemory(ctxt);
534
2
      return;
535
2
  }
536
38.2k
  ctxt->valueNr = 0;
537
38.2k
  ctxt->valueMax = 10;
538
38.2k
  ctxt->value = NULL;
539
38.2k
    }
540
38.2k
    SKIP_BLANKS;
541
38.2k
    if (CUR == '/') {
542
5.60k
  xmlXPathRoot(ctxt);
543
5.60k
        xmlXPtrEvalChildSeq(ctxt, NULL);
544
32.6k
    } else {
545
32.6k
  xmlChar *name;
546
547
32.6k
  name = xmlXPathParseName(ctxt);
548
32.6k
  if (name == NULL)
549
31.4k
      XP_ERROR(XPATH_EXPR_ERROR);
550
31.4k
  if (CUR == '(') {
551
26.5k
      xmlXPtrEvalFullXPtr(ctxt, name);
552
      /* Short evaluation */
553
26.5k
      return;
554
26.5k
  } else {
555
      /* this handle both Bare Names and Child Sequences */
556
4.91k
      xmlXPtrEvalChildSeq(ctxt, name);
557
4.91k
  }
558
31.4k
    }
559
10.5k
    SKIP_BLANKS;
560
10.5k
    if (CUR != 0)
561
10.2k
  XP_ERROR(XPATH_EXPR_ERROR);
562
293
}
563
564
565
/************************************************************************
566
 *                  *
567
 *      General routines        *
568
 *                  *
569
 ************************************************************************/
570
571
/**
572
 * xmlXPtrNewContext:
573
 * @doc:  the XML document
574
 * @here:  the node that directly contains the XPointer being evaluated or NULL
575
 * @origin:  the element from which a user or program initiated traversal of
576
 *           the link, or NULL.
577
 *
578
 * Create a new XPointer context
579
 *
580
 * Returns the xmlXPathContext just allocated.
581
 */
582
xmlXPathContextPtr
583
0
xmlXPtrNewContext(xmlDocPtr doc, xmlNodePtr here, xmlNodePtr origin) {
584
0
    xmlXPathContextPtr ret;
585
0
    (void) here;
586
0
    (void) origin;
587
588
0
    ret = xmlXPathNewContext(doc);
589
0
    if (ret == NULL)
590
0
  return(ret);
591
592
0
    return(ret);
593
0
}
594
595
/**
596
 * xmlXPtrEval:
597
 * @str:  the XPointer expression
598
 * @ctx:  the XPointer context
599
 *
600
 * Evaluate the XPath Location Path in the given context.
601
 *
602
 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
603
 *         the caller has to free the object.
604
 */
605
xmlXPathObjectPtr
606
38.2k
xmlXPtrEval(const xmlChar *str, xmlXPathContextPtr ctx) {
607
38.2k
    xmlXPathParserContextPtr ctxt;
608
38.2k
    xmlXPathObjectPtr res = NULL, tmp;
609
38.2k
    xmlXPathObjectPtr init = NULL;
610
38.2k
    int stack = 0;
611
612
38.2k
    xmlInitParser();
613
614
38.2k
    if ((ctx == NULL) || (str == NULL))
615
0
  return(NULL);
616
617
38.2k
    xmlResetError(&ctx->lastError);
618
619
38.2k
    ctxt = xmlXPathNewParserContext(str, ctx);
620
38.2k
    if (ctxt == NULL) {
621
6
        xmlXPathErrMemory(ctx);
622
6
  return(NULL);
623
6
    }
624
38.2k
    xmlXPtrEvalXPointer(ctxt);
625
38.2k
    if (ctx->lastError.code != XML_ERR_OK)
626
35.8k
        goto error;
627
628
2.38k
    if ((ctxt->value != NULL) &&
629
2.38k
  (ctxt->value->type != XPATH_NODESET)) {
630
0
        xmlXPtrErr(ctxt, XML_XPTR_EVAL_FAILED,
631
0
    "xmlXPtrEval: evaluation failed to return a node set\n",
632
0
       NULL);
633
2.38k
    } else {
634
2.38k
  res = xmlXPathValuePop(ctxt);
635
2.38k
    }
636
637
2.38k
    do {
638
2.38k
        tmp = xmlXPathValuePop(ctxt);
639
2.38k
  if (tmp != NULL) {
640
0
      if (tmp != init) {
641
0
    if (tmp->type == XPATH_NODESET) {
642
        /*
643
         * Evaluation may push a root nodeset which is unused
644
         */
645
0
        xmlNodeSetPtr set;
646
0
        set = tmp->nodesetval;
647
0
        if ((set == NULL) || (set->nodeNr != 1) ||
648
0
      (set->nodeTab[0] != (xmlNodePtr) ctx->doc))
649
0
      stack++;
650
0
    } else
651
0
        stack++;
652
0
      }
653
0
      xmlXPathFreeObject(tmp);
654
0
        }
655
2.38k
    } while (tmp != NULL);
656
2.38k
    if (stack != 0) {
657
0
        xmlXPtrErr(ctxt, XML_XPTR_EXTRA_OBJECTS,
658
0
       "xmlXPtrEval: object(s) left on the eval stack\n",
659
0
       NULL);
660
0
    }
661
2.38k
    if (ctx->lastError.code != XML_ERR_OK) {
662
0
  xmlXPathFreeObject(res);
663
0
  res = NULL;
664
0
    }
665
666
38.2k
error:
667
38.2k
    xmlXPathFreeParserContext(ctxt);
668
38.2k
    return(res);
669
2.38k
}
670
671
#endif
672