pocxxeci 0.30.1

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of pocxxeci might be problematic. Click here for more details.

Files changed (160) hide show
  1. package/LICENSE +19 -0
  2. package/Makefile +18 -0
  3. package/README.md +52 -0
  4. package/binding.gyp +81 -0
  5. package/index.d.ts +273 -0
  6. package/index.js +45 -0
  7. package/lib/bindings.js +1 -0
  8. package/lib/document.js +122 -0
  9. package/lib/element.js +82 -0
  10. package/lib/sax_parser.js +38 -0
  11. package/package.json +70 -0
  12. package/src/html_document.cc +7 -0
  13. package/src/html_document.h +18 -0
  14. package/src/libxmljs.cc +252 -0
  15. package/src/libxmljs.h +53 -0
  16. package/src/xml_attribute.cc +173 -0
  17. package/src/xml_attribute.h +40 -0
  18. package/src/xml_comment.cc +117 -0
  19. package/src/xml_comment.h +30 -0
  20. package/src/xml_document.cc +810 -0
  21. package/src/xml_document.h +67 -0
  22. package/src/xml_element.cc +565 -0
  23. package/src/xml_element.h +61 -0
  24. package/src/xml_namespace.cc +158 -0
  25. package/src/xml_namespace.h +39 -0
  26. package/src/xml_node.cc +761 -0
  27. package/src/xml_node.h +73 -0
  28. package/src/xml_pi.cc +161 -0
  29. package/src/xml_pi.h +34 -0
  30. package/src/xml_sax_parser.cc +424 -0
  31. package/src/xml_sax_parser.h +73 -0
  32. package/src/xml_syntax_error.cc +66 -0
  33. package/src/xml_syntax_error.h +25 -0
  34. package/src/xml_text.cc +320 -0
  35. package/src/xml_text.h +48 -0
  36. package/src/xml_textwriter.cc +315 -0
  37. package/src/xml_textwriter.h +62 -0
  38. package/src/xml_xpath_context.cc +70 -0
  39. package/src/xml_xpath_context.h +23 -0
  40. package/vendor/libxml/Copyright +23 -0
  41. package/vendor/libxml/DOCBparser.c +305 -0
  42. package/vendor/libxml/HTMLparser.c +7287 -0
  43. package/vendor/libxml/HTMLtree.c +1200 -0
  44. package/vendor/libxml/Makefile +2983 -0
  45. package/vendor/libxml/SAX.c +180 -0
  46. package/vendor/libxml/SAX2.c +3036 -0
  47. package/vendor/libxml/buf.c +1351 -0
  48. package/vendor/libxml/buf.h +72 -0
  49. package/vendor/libxml/c14n.c +2234 -0
  50. package/vendor/libxml/catalog.c +3828 -0
  51. package/vendor/libxml/chvalid.c +336 -0
  52. package/vendor/libxml/config.h +294 -0
  53. package/vendor/libxml/config.h.gch +0 -0
  54. package/vendor/libxml/debugXML.c +3423 -0
  55. package/vendor/libxml/dict.c +1298 -0
  56. package/vendor/libxml/elfgcchack.h +17818 -0
  57. package/vendor/libxml/enc.h +32 -0
  58. package/vendor/libxml/encoding.c +3975 -0
  59. package/vendor/libxml/entities.c +1163 -0
  60. package/vendor/libxml/error.c +998 -0
  61. package/vendor/libxml/globals.c +1126 -0
  62. package/vendor/libxml/hash.c +1146 -0
  63. package/vendor/libxml/include/libxml/DOCBparser.h +96 -0
  64. package/vendor/libxml/include/libxml/HTMLparser.h +306 -0
  65. package/vendor/libxml/include/libxml/HTMLtree.h +147 -0
  66. package/vendor/libxml/include/libxml/Makefile +725 -0
  67. package/vendor/libxml/include/libxml/Makefile.am +54 -0
  68. package/vendor/libxml/include/libxml/Makefile.in +725 -0
  69. package/vendor/libxml/include/libxml/SAX.h +173 -0
  70. package/vendor/libxml/include/libxml/SAX2.h +178 -0
  71. package/vendor/libxml/include/libxml/c14n.h +128 -0
  72. package/vendor/libxml/include/libxml/catalog.h +182 -0
  73. package/vendor/libxml/include/libxml/chvalid.h +230 -0
  74. package/vendor/libxml/include/libxml/debugXML.h +217 -0
  75. package/vendor/libxml/include/libxml/dict.h +79 -0
  76. package/vendor/libxml/include/libxml/encoding.h +245 -0
  77. package/vendor/libxml/include/libxml/entities.h +151 -0
  78. package/vendor/libxml/include/libxml/globals.h +508 -0
  79. package/vendor/libxml/include/libxml/hash.h +236 -0
  80. package/vendor/libxml/include/libxml/list.h +137 -0
  81. package/vendor/libxml/include/libxml/nanoftp.h +163 -0
  82. package/vendor/libxml/include/libxml/nanohttp.h +81 -0
  83. package/vendor/libxml/include/libxml/parser.h +1243 -0
  84. package/vendor/libxml/include/libxml/parserInternals.h +644 -0
  85. package/vendor/libxml/include/libxml/pattern.h +100 -0
  86. package/vendor/libxml/include/libxml/relaxng.h +217 -0
  87. package/vendor/libxml/include/libxml/schemasInternals.h +958 -0
  88. package/vendor/libxml/include/libxml/schematron.h +142 -0
  89. package/vendor/libxml/include/libxml/threads.h +89 -0
  90. package/vendor/libxml/include/libxml/tree.h +1311 -0
  91. package/vendor/libxml/include/libxml/uri.h +94 -0
  92. package/vendor/libxml/include/libxml/valid.h +458 -0
  93. package/vendor/libxml/include/libxml/xinclude.h +129 -0
  94. package/vendor/libxml/include/libxml/xlink.h +189 -0
  95. package/vendor/libxml/include/libxml/xmlIO.h +368 -0
  96. package/vendor/libxml/include/libxml/xmlautomata.h +146 -0
  97. package/vendor/libxml/include/libxml/xmlerror.h +945 -0
  98. package/vendor/libxml/include/libxml/xmlexports.h +77 -0
  99. package/vendor/libxml/include/libxml/xmlmemory.h +224 -0
  100. package/vendor/libxml/include/libxml/xmlmodule.h +57 -0
  101. package/vendor/libxml/include/libxml/xmlreader.h +428 -0
  102. package/vendor/libxml/include/libxml/xmlregexp.h +222 -0
  103. package/vendor/libxml/include/libxml/xmlsave.h +88 -0
  104. package/vendor/libxml/include/libxml/xmlschemas.h +246 -0
  105. package/vendor/libxml/include/libxml/xmlschemastypes.h +151 -0
  106. package/vendor/libxml/include/libxml/xmlstring.h +140 -0
  107. package/vendor/libxml/include/libxml/xmlunicode.h +202 -0
  108. package/vendor/libxml/include/libxml/xmlversion.h +484 -0
  109. package/vendor/libxml/include/libxml/xmlwin32version.h +239 -0
  110. package/vendor/libxml/include/libxml/xmlwriter.h +488 -0
  111. package/vendor/libxml/include/libxml/xpath.h +564 -0
  112. package/vendor/libxml/include/libxml/xpathInternals.h +632 -0
  113. package/vendor/libxml/include/libxml/xpointer.h +114 -0
  114. package/vendor/libxml/include/win32config.h +122 -0
  115. package/vendor/libxml/include/wsockcompat.h +54 -0
  116. package/vendor/libxml/legacy.c +1343 -0
  117. package/vendor/libxml/libxml.h +134 -0
  118. package/vendor/libxml/list.c +779 -0
  119. package/vendor/libxml/nanoftp.c +2118 -0
  120. package/vendor/libxml/nanohttp.c +1899 -0
  121. package/vendor/libxml/parser.c +15553 -0
  122. package/vendor/libxml/parserInternals.c +2164 -0
  123. package/vendor/libxml/pattern.c +2621 -0
  124. package/vendor/libxml/relaxng.c +11101 -0
  125. package/vendor/libxml/rngparser.c +1595 -0
  126. package/vendor/libxml/runsuite.c +1157 -0
  127. package/vendor/libxml/save.h +36 -0
  128. package/vendor/libxml/schematron.c +1787 -0
  129. package/vendor/libxml/threads.c +1049 -0
  130. package/vendor/libxml/timsort.h +601 -0
  131. package/vendor/libxml/tree.c +10183 -0
  132. package/vendor/libxml/trio.c +6895 -0
  133. package/vendor/libxml/trio.h +230 -0
  134. package/vendor/libxml/triodef.h +228 -0
  135. package/vendor/libxml/trionan.c +914 -0
  136. package/vendor/libxml/trionan.h +84 -0
  137. package/vendor/libxml/triop.h +150 -0
  138. package/vendor/libxml/triostr.c +2112 -0
  139. package/vendor/libxml/triostr.h +144 -0
  140. package/vendor/libxml/uri.c +2561 -0
  141. package/vendor/libxml/valid.c +7138 -0
  142. package/vendor/libxml/xinclude.c +2657 -0
  143. package/vendor/libxml/xlink.c +183 -0
  144. package/vendor/libxml/xmlIO.c +4135 -0
  145. package/vendor/libxml/xmlcatalog.c +624 -0
  146. package/vendor/libxml/xmllint.c +3796 -0
  147. package/vendor/libxml/xmlmemory.c +1163 -0
  148. package/vendor/libxml/xmlmodule.c +468 -0
  149. package/vendor/libxml/xmlreader.c +6033 -0
  150. package/vendor/libxml/xmlregexp.c +8271 -0
  151. package/vendor/libxml/xmlsave.c +2735 -0
  152. package/vendor/libxml/xmlschemas.c +29173 -0
  153. package/vendor/libxml/xmlschemastypes.c +6276 -0
  154. package/vendor/libxml/xmlstring.c +1050 -0
  155. package/vendor/libxml/xmlunicode.c +3179 -0
  156. package/vendor/libxml/xmlwriter.c +4738 -0
  157. package/vendor/libxml/xpath.c +14734 -0
  158. package/vendor/libxml/xpointer.c +2969 -0
  159. package/vendor/libxml/xzlib.c +815 -0
  160. package/vendor/libxml/xzlib.h +19 -0
@@ -0,0 +1,2621 @@
1
+ /*
2
+ * pattern.c: Implementation of selectors for nodes
3
+ *
4
+ * Reference:
5
+ * http://www.w3.org/TR/2001/REC-xmlschema-1-20010502/
6
+ * to some extent
7
+ * http://www.w3.org/TR/1999/REC-xml-19991116
8
+ *
9
+ * See Copyright for the status of this software.
10
+ *
11
+ * daniel@veillard.com
12
+ */
13
+
14
+ /*
15
+ * TODO:
16
+ * - compilation flags to check for specific syntaxes
17
+ * using flags of xmlPatterncompile()
18
+ * - making clear how pattern starting with / or . need to be handled,
19
+ * currently push(NULL, NULL) means a reset of the streaming context
20
+ * and indicating we are on / (the document node), probably need
21
+ * something similar for .
22
+ * - get rid of the "compile" starting with lowercase
23
+ * - DONE (2006-05-16): get rid of the Strdup/Strndup in case of dictionary
24
+ */
25
+
26
+ #define IN_LIBXML
27
+ #include "libxml.h"
28
+
29
+ #include <string.h>
30
+ #include <libxml/xmlmemory.h>
31
+ #include <libxml/tree.h>
32
+ #include <libxml/hash.h>
33
+ #include <libxml/dict.h>
34
+ #include <libxml/xmlerror.h>
35
+ #include <libxml/parserInternals.h>
36
+ #include <libxml/pattern.h>
37
+
38
+ #ifdef LIBXML_PATTERN_ENABLED
39
+
40
+ /* #define DEBUG_STREAMING */
41
+
42
+ #ifdef ERROR
43
+ #undef ERROR
44
+ #endif
45
+ #define ERROR(a, b, c, d)
46
+ #define ERROR5(a, b, c, d, e)
47
+
48
+ #define XML_STREAM_STEP_DESC 1
49
+ #define XML_STREAM_STEP_FINAL 2
50
+ #define XML_STREAM_STEP_ROOT 4
51
+ #define XML_STREAM_STEP_ATTR 8
52
+ #define XML_STREAM_STEP_NODE 16
53
+ #define XML_STREAM_STEP_IN_SET 32
54
+
55
+ /*
56
+ * NOTE: Those private flags (XML_STREAM_xxx) are used
57
+ * in _xmlStreamCtxt->flag. They extend the public
58
+ * xmlPatternFlags, so be careful not to interfere with the
59
+ * reserved values for xmlPatternFlags.
60
+ */
61
+ #define XML_STREAM_FINAL_IS_ANY_NODE 1<<14
62
+ #define XML_STREAM_FROM_ROOT 1<<15
63
+ #define XML_STREAM_DESC 1<<16
64
+
65
+ /*
66
+ * XML_STREAM_ANY_NODE is used for comparison against
67
+ * xmlElementType enums, to indicate a node of any type.
68
+ */
69
+ #define XML_STREAM_ANY_NODE 100
70
+
71
+ #define XML_PATTERN_NOTPATTERN (XML_PATTERN_XPATH | \
72
+ XML_PATTERN_XSSEL | \
73
+ XML_PATTERN_XSFIELD)
74
+
75
+ #define XML_STREAM_XS_IDC(c) ((c)->flags & \
76
+ (XML_PATTERN_XSSEL | XML_PATTERN_XSFIELD))
77
+
78
+ #define XML_STREAM_XS_IDC_SEL(c) ((c)->flags & XML_PATTERN_XSSEL)
79
+
80
+ #define XML_STREAM_XS_IDC_FIELD(c) ((c)->flags & XML_PATTERN_XSFIELD)
81
+
82
+ #define XML_PAT_COPY_NSNAME(c, r, nsname) \
83
+ if ((c)->comp->dict) \
84
+ r = (xmlChar *) xmlDictLookup((c)->comp->dict, BAD_CAST nsname, -1); \
85
+ else r = xmlStrdup(BAD_CAST nsname);
86
+
87
+ #define XML_PAT_FREE_STRING(c, r) if ((c)->comp->dict == NULL) xmlFree(r);
88
+
89
+ typedef struct _xmlStreamStep xmlStreamStep;
90
+ typedef xmlStreamStep *xmlStreamStepPtr;
91
+ struct _xmlStreamStep {
92
+ int flags; /* properties of that step */
93
+ const xmlChar *name; /* first string value if NULL accept all */
94
+ const xmlChar *ns; /* second string value */
95
+ int nodeType; /* type of node */
96
+ };
97
+
98
+ typedef struct _xmlStreamComp xmlStreamComp;
99
+ typedef xmlStreamComp *xmlStreamCompPtr;
100
+ struct _xmlStreamComp {
101
+ xmlDict *dict; /* the dictionary if any */
102
+ int nbStep; /* number of steps in the automata */
103
+ int maxStep; /* allocated number of steps */
104
+ xmlStreamStepPtr steps; /* the array of steps */
105
+ int flags;
106
+ };
107
+
108
+ struct _xmlStreamCtxt {
109
+ struct _xmlStreamCtxt *next;/* link to next sub pattern if | */
110
+ xmlStreamCompPtr comp; /* the compiled stream */
111
+ int nbState; /* number of states in the automata */
112
+ int maxState; /* allocated number of states */
113
+ int level; /* how deep are we ? */
114
+ int *states; /* the array of step indexes */
115
+ int flags; /* validation options */
116
+ int blockLevel;
117
+ };
118
+
119
+ static void xmlFreeStreamComp(xmlStreamCompPtr comp);
120
+
121
+ /*
122
+ * Types are private:
123
+ */
124
+
125
+ typedef enum {
126
+ XML_OP_END=0,
127
+ XML_OP_ROOT,
128
+ XML_OP_ELEM,
129
+ XML_OP_CHILD,
130
+ XML_OP_ATTR,
131
+ XML_OP_PARENT,
132
+ XML_OP_ANCESTOR,
133
+ XML_OP_NS,
134
+ XML_OP_ALL
135
+ } xmlPatOp;
136
+
137
+
138
+ typedef struct _xmlStepState xmlStepState;
139
+ typedef xmlStepState *xmlStepStatePtr;
140
+ struct _xmlStepState {
141
+ int step;
142
+ xmlNodePtr node;
143
+ };
144
+
145
+ typedef struct _xmlStepStates xmlStepStates;
146
+ typedef xmlStepStates *xmlStepStatesPtr;
147
+ struct _xmlStepStates {
148
+ int nbstates;
149
+ int maxstates;
150
+ xmlStepStatePtr states;
151
+ };
152
+
153
+ typedef struct _xmlStepOp xmlStepOp;
154
+ typedef xmlStepOp *xmlStepOpPtr;
155
+ struct _xmlStepOp {
156
+ xmlPatOp op;
157
+ const xmlChar *value;
158
+ const xmlChar *value2; /* The namespace name */
159
+ };
160
+
161
+ #define PAT_FROM_ROOT (1<<8)
162
+ #define PAT_FROM_CUR (1<<9)
163
+
164
+ struct _xmlPattern {
165
+ void *data; /* the associated template */
166
+ xmlDictPtr dict; /* the optional dictionary */
167
+ struct _xmlPattern *next; /* next pattern if | is used */
168
+ const xmlChar *pattern; /* the pattern */
169
+ int flags; /* flags */
170
+ int nbStep;
171
+ int maxStep;
172
+ xmlStepOpPtr steps; /* ops for computation */
173
+ xmlStreamCompPtr stream; /* the streaming data if any */
174
+ };
175
+
176
+ typedef struct _xmlPatParserContext xmlPatParserContext;
177
+ typedef xmlPatParserContext *xmlPatParserContextPtr;
178
+ struct _xmlPatParserContext {
179
+ const xmlChar *cur; /* the current char being parsed */
180
+ const xmlChar *base; /* the full expression */
181
+ int error; /* error code */
182
+ xmlDictPtr dict; /* the dictionary if any */
183
+ xmlPatternPtr comp; /* the result */
184
+ xmlNodePtr elem; /* the current node if any */
185
+ const xmlChar **namespaces; /* the namespaces definitions */
186
+ int nb_namespaces; /* the number of namespaces */
187
+ };
188
+
189
+ /************************************************************************
190
+ * *
191
+ * Type functions *
192
+ * *
193
+ ************************************************************************/
194
+
195
+ /**
196
+ * xmlNewPattern:
197
+ *
198
+ * Create a new XSLT Pattern
199
+ *
200
+ * Returns the newly allocated xmlPatternPtr or NULL in case of error
201
+ */
202
+ static xmlPatternPtr
203
+ xmlNewPattern(void) {
204
+ xmlPatternPtr cur;
205
+
206
+ cur = (xmlPatternPtr) xmlMalloc(sizeof(xmlPattern));
207
+ if (cur == NULL) {
208
+ ERROR(NULL, NULL, NULL,
209
+ "xmlNewPattern : malloc failed\n");
210
+ return(NULL);
211
+ }
212
+ memset(cur, 0, sizeof(xmlPattern));
213
+ cur->maxStep = 10;
214
+ cur->steps = (xmlStepOpPtr) xmlMalloc(cur->maxStep * sizeof(xmlStepOp));
215
+ if (cur->steps == NULL) {
216
+ xmlFree(cur);
217
+ ERROR(NULL, NULL, NULL,
218
+ "xmlNewPattern : malloc failed\n");
219
+ return(NULL);
220
+ }
221
+ return(cur);
222
+ }
223
+
224
+ /**
225
+ * xmlFreePattern:
226
+ * @comp: an XSLT comp
227
+ *
228
+ * Free up the memory allocated by @comp
229
+ */
230
+ void
231
+ xmlFreePattern(xmlPatternPtr comp) {
232
+ xmlFreePatternList(comp);
233
+ }
234
+
235
+ static void
236
+ xmlFreePatternInternal(xmlPatternPtr comp) {
237
+ xmlStepOpPtr op;
238
+ int i;
239
+
240
+ if (comp == NULL)
241
+ return;
242
+ if (comp->stream != NULL)
243
+ xmlFreeStreamComp(comp->stream);
244
+ if (comp->pattern != NULL)
245
+ xmlFree((xmlChar *)comp->pattern);
246
+ if (comp->steps != NULL) {
247
+ if (comp->dict == NULL) {
248
+ for (i = 0;i < comp->nbStep;i++) {
249
+ op = &comp->steps[i];
250
+ if (op->value != NULL)
251
+ xmlFree((xmlChar *) op->value);
252
+ if (op->value2 != NULL)
253
+ xmlFree((xmlChar *) op->value2);
254
+ }
255
+ }
256
+ xmlFree(comp->steps);
257
+ }
258
+ if (comp->dict != NULL)
259
+ xmlDictFree(comp->dict);
260
+
261
+ memset(comp, -1, sizeof(xmlPattern));
262
+ xmlFree(comp);
263
+ }
264
+
265
+ /**
266
+ * xmlFreePatternList:
267
+ * @comp: an XSLT comp list
268
+ *
269
+ * Free up the memory allocated by all the elements of @comp
270
+ */
271
+ void
272
+ xmlFreePatternList(xmlPatternPtr comp) {
273
+ xmlPatternPtr cur;
274
+
275
+ while (comp != NULL) {
276
+ cur = comp;
277
+ comp = comp->next;
278
+ cur->next = NULL;
279
+ xmlFreePatternInternal(cur);
280
+ }
281
+ }
282
+
283
+ /**
284
+ * xmlNewPatParserContext:
285
+ * @pattern: the pattern context
286
+ * @dict: the inherited dictionary or NULL
287
+ * @namespaces: the prefix definitions, array of [URI, prefix] terminated
288
+ * with [NULL, NULL] or NULL if no namespace is used
289
+ *
290
+ * Create a new XML pattern parser context
291
+ *
292
+ * Returns the newly allocated xmlPatParserContextPtr or NULL in case of error
293
+ */
294
+ static xmlPatParserContextPtr
295
+ xmlNewPatParserContext(const xmlChar *pattern, xmlDictPtr dict,
296
+ const xmlChar **namespaces) {
297
+ xmlPatParserContextPtr cur;
298
+
299
+ if (pattern == NULL)
300
+ return(NULL);
301
+
302
+ cur = (xmlPatParserContextPtr) xmlMalloc(sizeof(xmlPatParserContext));
303
+ if (cur == NULL) {
304
+ ERROR(NULL, NULL, NULL,
305
+ "xmlNewPatParserContext : malloc failed\n");
306
+ return(NULL);
307
+ }
308
+ memset(cur, 0, sizeof(xmlPatParserContext));
309
+ cur->dict = dict;
310
+ cur->cur = pattern;
311
+ cur->base = pattern;
312
+ if (namespaces != NULL) {
313
+ int i;
314
+ for (i = 0;namespaces[2 * i] != NULL;i++)
315
+ ;
316
+ cur->nb_namespaces = i;
317
+ } else {
318
+ cur->nb_namespaces = 0;
319
+ }
320
+ cur->namespaces = namespaces;
321
+ return(cur);
322
+ }
323
+
324
+ /**
325
+ * xmlFreePatParserContext:
326
+ * @ctxt: an XSLT parser context
327
+ *
328
+ * Free up the memory allocated by @ctxt
329
+ */
330
+ static void
331
+ xmlFreePatParserContext(xmlPatParserContextPtr ctxt) {
332
+ if (ctxt == NULL)
333
+ return;
334
+ memset(ctxt, -1, sizeof(xmlPatParserContext));
335
+ xmlFree(ctxt);
336
+ }
337
+
338
+ /**
339
+ * xmlPatternAdd:
340
+ * @comp: the compiled match expression
341
+ * @op: an op
342
+ * @value: the first value
343
+ * @value2: the second value
344
+ *
345
+ * Add a step to an XSLT Compiled Match
346
+ *
347
+ * Returns -1 in case of failure, 0 otherwise.
348
+ */
349
+ static int
350
+ xmlPatternAdd(xmlPatParserContextPtr ctxt ATTRIBUTE_UNUSED,
351
+ xmlPatternPtr comp,
352
+ xmlPatOp op, xmlChar * value, xmlChar * value2)
353
+ {
354
+ if (comp->nbStep >= comp->maxStep) {
355
+ xmlStepOpPtr temp;
356
+ temp = (xmlStepOpPtr) xmlRealloc(comp->steps, comp->maxStep * 2 *
357
+ sizeof(xmlStepOp));
358
+ if (temp == NULL) {
359
+ ERROR(ctxt, NULL, NULL,
360
+ "xmlPatternAdd: realloc failed\n");
361
+ return (-1);
362
+ }
363
+ comp->steps = temp;
364
+ comp->maxStep *= 2;
365
+ }
366
+ comp->steps[comp->nbStep].op = op;
367
+ comp->steps[comp->nbStep].value = value;
368
+ comp->steps[comp->nbStep].value2 = value2;
369
+ comp->nbStep++;
370
+ return (0);
371
+ }
372
+
373
+ #if 0
374
+ /**
375
+ * xsltSwapTopPattern:
376
+ * @comp: the compiled match expression
377
+ *
378
+ * reverse the two top steps.
379
+ */
380
+ static void
381
+ xsltSwapTopPattern(xmlPatternPtr comp) {
382
+ int i;
383
+ int j = comp->nbStep - 1;
384
+
385
+ if (j > 0) {
386
+ register const xmlChar *tmp;
387
+ register xmlPatOp op;
388
+ i = j - 1;
389
+ tmp = comp->steps[i].value;
390
+ comp->steps[i].value = comp->steps[j].value;
391
+ comp->steps[j].value = tmp;
392
+ tmp = comp->steps[i].value2;
393
+ comp->steps[i].value2 = comp->steps[j].value2;
394
+ comp->steps[j].value2 = tmp;
395
+ op = comp->steps[i].op;
396
+ comp->steps[i].op = comp->steps[j].op;
397
+ comp->steps[j].op = op;
398
+ }
399
+ }
400
+ #endif
401
+
402
+ /**
403
+ * xmlReversePattern:
404
+ * @comp: the compiled match expression
405
+ *
406
+ * reverse all the stack of expressions
407
+ *
408
+ * returns 0 in case of success and -1 in case of error.
409
+ */
410
+ static int
411
+ xmlReversePattern(xmlPatternPtr comp) {
412
+ int i, j;
413
+
414
+ /*
415
+ * remove the leading // for //a or .//a
416
+ */
417
+ if ((comp->nbStep > 0) && (comp->steps[0].op == XML_OP_ANCESTOR)) {
418
+ for (i = 0, j = 1;j < comp->nbStep;i++,j++) {
419
+ comp->steps[i].value = comp->steps[j].value;
420
+ comp->steps[i].value2 = comp->steps[j].value2;
421
+ comp->steps[i].op = comp->steps[j].op;
422
+ }
423
+ comp->nbStep--;
424
+ }
425
+ if (comp->nbStep >= comp->maxStep) {
426
+ xmlStepOpPtr temp;
427
+ temp = (xmlStepOpPtr) xmlRealloc(comp->steps, comp->maxStep * 2 *
428
+ sizeof(xmlStepOp));
429
+ if (temp == NULL) {
430
+ ERROR(ctxt, NULL, NULL,
431
+ "xmlReversePattern: realloc failed\n");
432
+ return (-1);
433
+ }
434
+ comp->steps = temp;
435
+ comp->maxStep *= 2;
436
+ }
437
+ i = 0;
438
+ j = comp->nbStep - 1;
439
+ while (j > i) {
440
+ register const xmlChar *tmp;
441
+ register xmlPatOp op;
442
+ tmp = comp->steps[i].value;
443
+ comp->steps[i].value = comp->steps[j].value;
444
+ comp->steps[j].value = tmp;
445
+ tmp = comp->steps[i].value2;
446
+ comp->steps[i].value2 = comp->steps[j].value2;
447
+ comp->steps[j].value2 = tmp;
448
+ op = comp->steps[i].op;
449
+ comp->steps[i].op = comp->steps[j].op;
450
+ comp->steps[j].op = op;
451
+ j--;
452
+ i++;
453
+ }
454
+ comp->steps[comp->nbStep].value = NULL;
455
+ comp->steps[comp->nbStep].value2 = NULL;
456
+ comp->steps[comp->nbStep++].op = XML_OP_END;
457
+ return(0);
458
+ }
459
+
460
+ /************************************************************************
461
+ * *
462
+ * The interpreter for the precompiled patterns *
463
+ * *
464
+ ************************************************************************/
465
+
466
+ static int
467
+ xmlPatPushState(xmlStepStates *states, int step, xmlNodePtr node) {
468
+ if ((states->states == NULL) || (states->maxstates <= 0)) {
469
+ states->maxstates = 4;
470
+ states->nbstates = 0;
471
+ states->states = xmlMalloc(4 * sizeof(xmlStepState));
472
+ }
473
+ else if (states->maxstates <= states->nbstates) {
474
+ xmlStepState *tmp;
475
+
476
+ tmp = (xmlStepStatePtr) xmlRealloc(states->states,
477
+ 2 * states->maxstates * sizeof(xmlStepState));
478
+ if (tmp == NULL)
479
+ return(-1);
480
+ states->states = tmp;
481
+ states->maxstates *= 2;
482
+ }
483
+ states->states[states->nbstates].step = step;
484
+ states->states[states->nbstates++].node = node;
485
+ #if 0
486
+ fprintf(stderr, "Push: %d, %s\n", step, node->name);
487
+ #endif
488
+ return(0);
489
+ }
490
+
491
+ /**
492
+ * xmlPatMatch:
493
+ * @comp: the precompiled pattern
494
+ * @node: a node
495
+ *
496
+ * Test whether the node matches the pattern
497
+ *
498
+ * Returns 1 if it matches, 0 if it doesn't and -1 in case of failure
499
+ */
500
+ static int
501
+ xmlPatMatch(xmlPatternPtr comp, xmlNodePtr node) {
502
+ int i;
503
+ xmlStepOpPtr step;
504
+ xmlStepStates states = {0, 0, NULL}; /* // may require backtrack */
505
+
506
+ if ((comp == NULL) || (node == NULL)) return(-1);
507
+ i = 0;
508
+ restart:
509
+ for (;i < comp->nbStep;i++) {
510
+ step = &comp->steps[i];
511
+ switch (step->op) {
512
+ case XML_OP_END:
513
+ goto found;
514
+ case XML_OP_ROOT:
515
+ if (node->type == XML_NAMESPACE_DECL)
516
+ goto rollback;
517
+ node = node->parent;
518
+ if ((node->type == XML_DOCUMENT_NODE) ||
519
+ #ifdef LIBXML_DOCB_ENABLED
520
+ (node->type == XML_DOCB_DOCUMENT_NODE) ||
521
+ #endif
522
+ (node->type == XML_HTML_DOCUMENT_NODE))
523
+ continue;
524
+ goto rollback;
525
+ case XML_OP_ELEM:
526
+ if (node->type != XML_ELEMENT_NODE)
527
+ goto rollback;
528
+ if (step->value == NULL)
529
+ continue;
530
+ if (step->value[0] != node->name[0])
531
+ goto rollback;
532
+ if (!xmlStrEqual(step->value, node->name))
533
+ goto rollback;
534
+
535
+ /* Namespace test */
536
+ if (node->ns == NULL) {
537
+ if (step->value2 != NULL)
538
+ goto rollback;
539
+ } else if (node->ns->href != NULL) {
540
+ if (step->value2 == NULL)
541
+ goto rollback;
542
+ if (!xmlStrEqual(step->value2, node->ns->href))
543
+ goto rollback;
544
+ }
545
+ continue;
546
+ case XML_OP_CHILD: {
547
+ xmlNodePtr lst;
548
+
549
+ if ((node->type != XML_ELEMENT_NODE) &&
550
+ (node->type != XML_DOCUMENT_NODE) &&
551
+ #ifdef LIBXML_DOCB_ENABLED
552
+ (node->type != XML_DOCB_DOCUMENT_NODE) &&
553
+ #endif
554
+ (node->type != XML_HTML_DOCUMENT_NODE))
555
+ goto rollback;
556
+
557
+ lst = node->children;
558
+
559
+ if (step->value != NULL) {
560
+ while (lst != NULL) {
561
+ if ((lst->type == XML_ELEMENT_NODE) &&
562
+ (step->value[0] == lst->name[0]) &&
563
+ (xmlStrEqual(step->value, lst->name)))
564
+ break;
565
+ lst = lst->next;
566
+ }
567
+ if (lst != NULL)
568
+ continue;
569
+ }
570
+ goto rollback;
571
+ }
572
+ case XML_OP_ATTR:
573
+ if (node->type != XML_ATTRIBUTE_NODE)
574
+ goto rollback;
575
+ if (step->value != NULL) {
576
+ if (step->value[0] != node->name[0])
577
+ goto rollback;
578
+ if (!xmlStrEqual(step->value, node->name))
579
+ goto rollback;
580
+ }
581
+ /* Namespace test */
582
+ if (node->ns == NULL) {
583
+ if (step->value2 != NULL)
584
+ goto rollback;
585
+ } else if (step->value2 != NULL) {
586
+ if (!xmlStrEqual(step->value2, node->ns->href))
587
+ goto rollback;
588
+ }
589
+ continue;
590
+ case XML_OP_PARENT:
591
+ if ((node->type == XML_DOCUMENT_NODE) ||
592
+ (node->type == XML_HTML_DOCUMENT_NODE) ||
593
+ #ifdef LIBXML_DOCB_ENABLED
594
+ (node->type == XML_DOCB_DOCUMENT_NODE) ||
595
+ #endif
596
+ (node->type == XML_NAMESPACE_DECL))
597
+ goto rollback;
598
+ node = node->parent;
599
+ if (node == NULL)
600
+ goto rollback;
601
+ if (step->value == NULL)
602
+ continue;
603
+ if (step->value[0] != node->name[0])
604
+ goto rollback;
605
+ if (!xmlStrEqual(step->value, node->name))
606
+ goto rollback;
607
+ /* Namespace test */
608
+ if (node->ns == NULL) {
609
+ if (step->value2 != NULL)
610
+ goto rollback;
611
+ } else if (node->ns->href != NULL) {
612
+ if (step->value2 == NULL)
613
+ goto rollback;
614
+ if (!xmlStrEqual(step->value2, node->ns->href))
615
+ goto rollback;
616
+ }
617
+ continue;
618
+ case XML_OP_ANCESTOR:
619
+ /* TODO: implement coalescing of ANCESTOR/NODE ops */
620
+ if (step->value == NULL) {
621
+ i++;
622
+ step = &comp->steps[i];
623
+ if (step->op == XML_OP_ROOT)
624
+ goto found;
625
+ if (step->op != XML_OP_ELEM)
626
+ goto rollback;
627
+ if (step->value == NULL)
628
+ return(-1);
629
+ }
630
+ if (node == NULL)
631
+ goto rollback;
632
+ if ((node->type == XML_DOCUMENT_NODE) ||
633
+ (node->type == XML_HTML_DOCUMENT_NODE) ||
634
+ #ifdef LIBXML_DOCB_ENABLED
635
+ (node->type == XML_DOCB_DOCUMENT_NODE) ||
636
+ #endif
637
+ (node->type == XML_NAMESPACE_DECL))
638
+ goto rollback;
639
+ node = node->parent;
640
+ while (node != NULL) {
641
+ if ((node->type == XML_ELEMENT_NODE) &&
642
+ (step->value[0] == node->name[0]) &&
643
+ (xmlStrEqual(step->value, node->name))) {
644
+ /* Namespace test */
645
+ if (node->ns == NULL) {
646
+ if (step->value2 == NULL)
647
+ break;
648
+ } else if (node->ns->href != NULL) {
649
+ if ((step->value2 != NULL) &&
650
+ (xmlStrEqual(step->value2, node->ns->href)))
651
+ break;
652
+ }
653
+ }
654
+ node = node->parent;
655
+ }
656
+ if (node == NULL)
657
+ goto rollback;
658
+ /*
659
+ * prepare a potential rollback from here
660
+ * for ancestors of that node.
661
+ */
662
+ if (step->op == XML_OP_ANCESTOR)
663
+ xmlPatPushState(&states, i, node);
664
+ else
665
+ xmlPatPushState(&states, i - 1, node);
666
+ continue;
667
+ case XML_OP_NS:
668
+ if (node->type != XML_ELEMENT_NODE)
669
+ goto rollback;
670
+ if (node->ns == NULL) {
671
+ if (step->value != NULL)
672
+ goto rollback;
673
+ } else if (node->ns->href != NULL) {
674
+ if (step->value == NULL)
675
+ goto rollback;
676
+ if (!xmlStrEqual(step->value, node->ns->href))
677
+ goto rollback;
678
+ }
679
+ break;
680
+ case XML_OP_ALL:
681
+ if (node->type != XML_ELEMENT_NODE)
682
+ goto rollback;
683
+ break;
684
+ }
685
+ }
686
+ found:
687
+ if (states.states != NULL) {
688
+ /* Free the rollback states */
689
+ xmlFree(states.states);
690
+ }
691
+ return(1);
692
+ rollback:
693
+ /* got an error try to rollback */
694
+ if (states.states == NULL)
695
+ return(0);
696
+ if (states.nbstates <= 0) {
697
+ xmlFree(states.states);
698
+ return(0);
699
+ }
700
+ states.nbstates--;
701
+ i = states.states[states.nbstates].step;
702
+ node = states.states[states.nbstates].node;
703
+ #if 0
704
+ fprintf(stderr, "Pop: %d, %s\n", i, node->name);
705
+ #endif
706
+ goto restart;
707
+ }
708
+
709
+ /************************************************************************
710
+ * *
711
+ * Dedicated parser for templates *
712
+ * *
713
+ ************************************************************************/
714
+
715
+ #define TODO \
716
+ xmlGenericError(xmlGenericErrorContext, \
717
+ "Unimplemented block at %s:%d\n", \
718
+ __FILE__, __LINE__);
719
+ #define CUR (*ctxt->cur)
720
+ #define SKIP(val) ctxt->cur += (val)
721
+ #define NXT(val) ctxt->cur[(val)]
722
+ #define PEEKPREV(val) ctxt->cur[-(val)]
723
+ #define CUR_PTR ctxt->cur
724
+
725
+ #define SKIP_BLANKS \
726
+ while (IS_BLANK_CH(CUR)) NEXT
727
+
728
+ #define CURRENT (*ctxt->cur)
729
+ #define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
730
+
731
+
732
+ #define PUSH(op, val, val2) \
733
+ if (xmlPatternAdd(ctxt, ctxt->comp, (op), (val), (val2))) goto error;
734
+
735
+ #define XSLT_ERROR(X) \
736
+ { xsltError(ctxt, __FILE__, __LINE__, X); \
737
+ ctxt->error = (X); return; }
738
+
739
+ #define XSLT_ERROR0(X) \
740
+ { xsltError(ctxt, __FILE__, __LINE__, X); \
741
+ ctxt->error = (X); return(0); }
742
+
743
+ #if 0
744
+ /**
745
+ * xmlPatScanLiteral:
746
+ * @ctxt: the XPath Parser context
747
+ *
748
+ * Parse an XPath Literal:
749
+ *
750
+ * [29] Literal ::= '"' [^"]* '"'
751
+ * | "'" [^']* "'"
752
+ *
753
+ * Returns the Literal parsed or NULL
754
+ */
755
+
756
+ static xmlChar *
757
+ xmlPatScanLiteral(xmlPatParserContextPtr ctxt) {
758
+ const xmlChar *q, *cur;
759
+ xmlChar *ret = NULL;
760
+ int val, len;
761
+
762
+ SKIP_BLANKS;
763
+ if (CUR == '"') {
764
+ NEXT;
765
+ cur = q = CUR_PTR;
766
+ val = xmlStringCurrentChar(NULL, cur, &len);
767
+ while ((IS_CHAR(val)) && (val != '"')) {
768
+ cur += len;
769
+ val = xmlStringCurrentChar(NULL, cur, &len);
770
+ }
771
+ if (!IS_CHAR(val)) {
772
+ ctxt->error = 1;
773
+ return(NULL);
774
+ } else {
775
+ if (ctxt->dict)
776
+ ret = (xmlChar *) xmlDictLookup(ctxt->dict, q, cur - q);
777
+ else
778
+ ret = xmlStrndup(q, cur - q);
779
+ }
780
+ cur += len;
781
+ CUR_PTR = cur;
782
+ } else if (CUR == '\'') {
783
+ NEXT;
784
+ cur = q = CUR_PTR;
785
+ val = xmlStringCurrentChar(NULL, cur, &len);
786
+ while ((IS_CHAR(val)) && (val != '\'')) {
787
+ cur += len;
788
+ val = xmlStringCurrentChar(NULL, cur, &len);
789
+ }
790
+ if (!IS_CHAR(val)) {
791
+ ctxt->error = 1;
792
+ return(NULL);
793
+ } else {
794
+ if (ctxt->dict)
795
+ ret = (xmlChar *) xmlDictLookup(ctxt->dict, q, cur - q);
796
+ else
797
+ ret = xmlStrndup(q, cur - q);
798
+ }
799
+ cur += len;
800
+ CUR_PTR = cur;
801
+ } else {
802
+ /* XP_ERROR(XPATH_START_LITERAL_ERROR); */
803
+ ctxt->error = 1;
804
+ return(NULL);
805
+ }
806
+ return(ret);
807
+ }
808
+ #endif
809
+
810
+ /**
811
+ * xmlPatScanName:
812
+ * @ctxt: the XPath Parser context
813
+ *
814
+ * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' |
815
+ * CombiningChar | Extender
816
+ *
817
+ * [5] Name ::= (Letter | '_' | ':') (NameChar)*
818
+ *
819
+ * [6] Names ::= Name (S Name)*
820
+ *
821
+ * Returns the Name parsed or NULL
822
+ */
823
+
824
+ static xmlChar *
825
+ xmlPatScanName(xmlPatParserContextPtr ctxt) {
826
+ const xmlChar *q, *cur;
827
+ xmlChar *ret = NULL;
828
+ int val, len;
829
+
830
+ SKIP_BLANKS;
831
+
832
+ cur = q = CUR_PTR;
833
+ val = xmlStringCurrentChar(NULL, cur, &len);
834
+ if (!IS_LETTER(val) && (val != '_') && (val != ':'))
835
+ return(NULL);
836
+
837
+ while ((IS_LETTER(val)) || (IS_DIGIT(val)) ||
838
+ (val == '.') || (val == '-') ||
839
+ (val == '_') ||
840
+ (IS_COMBINING(val)) ||
841
+ (IS_EXTENDER(val))) {
842
+ cur += len;
843
+ val = xmlStringCurrentChar(NULL, cur, &len);
844
+ }
845
+ if (ctxt->dict)
846
+ ret = (xmlChar *) xmlDictLookup(ctxt->dict, q, cur - q);
847
+ else
848
+ ret = xmlStrndup(q, cur - q);
849
+ CUR_PTR = cur;
850
+ return(ret);
851
+ }
852
+
853
+ /**
854
+ * xmlPatScanNCName:
855
+ * @ctxt: the XPath Parser context
856
+ *
857
+ * Parses a non qualified name
858
+ *
859
+ * Returns the Name parsed or NULL
860
+ */
861
+
862
+ static xmlChar *
863
+ xmlPatScanNCName(xmlPatParserContextPtr ctxt) {
864
+ const xmlChar *q, *cur;
865
+ xmlChar *ret = NULL;
866
+ int val, len;
867
+
868
+ SKIP_BLANKS;
869
+
870
+ cur = q = CUR_PTR;
871
+ val = xmlStringCurrentChar(NULL, cur, &len);
872
+ if (!IS_LETTER(val) && (val != '_'))
873
+ return(NULL);
874
+
875
+ while ((IS_LETTER(val)) || (IS_DIGIT(val)) ||
876
+ (val == '.') || (val == '-') ||
877
+ (val == '_') ||
878
+ (IS_COMBINING(val)) ||
879
+ (IS_EXTENDER(val))) {
880
+ cur += len;
881
+ val = xmlStringCurrentChar(NULL, cur, &len);
882
+ }
883
+ if (ctxt->dict)
884
+ ret = (xmlChar *) xmlDictLookup(ctxt->dict, q, cur - q);
885
+ else
886
+ ret = xmlStrndup(q, cur - q);
887
+ CUR_PTR = cur;
888
+ return(ret);
889
+ }
890
+
891
+ #if 0
892
+ /**
893
+ * xmlPatScanQName:
894
+ * @ctxt: the XPath Parser context
895
+ * @prefix: the place to store the prefix
896
+ *
897
+ * Parse a qualified name
898
+ *
899
+ * Returns the Name parsed or NULL
900
+ */
901
+
902
+ static xmlChar *
903
+ xmlPatScanQName(xmlPatParserContextPtr ctxt, xmlChar **prefix) {
904
+ xmlChar *ret = NULL;
905
+
906
+ *prefix = NULL;
907
+ ret = xmlPatScanNCName(ctxt);
908
+ if (CUR == ':') {
909
+ *prefix = ret;
910
+ NEXT;
911
+ ret = xmlPatScanNCName(ctxt);
912
+ }
913
+ return(ret);
914
+ }
915
+ #endif
916
+
917
+ /**
918
+ * xmlCompileAttributeTest:
919
+ * @ctxt: the compilation context
920
+ *
921
+ * Compile an attribute test.
922
+ */
923
+ static void
924
+ xmlCompileAttributeTest(xmlPatParserContextPtr ctxt) {
925
+ xmlChar *token = NULL;
926
+ xmlChar *name = NULL;
927
+ xmlChar *URL = NULL;
928
+
929
+ SKIP_BLANKS;
930
+ name = xmlPatScanNCName(ctxt);
931
+ if (name == NULL) {
932
+ if (CUR == '*') {
933
+ PUSH(XML_OP_ATTR, NULL, NULL);
934
+ NEXT;
935
+ } else {
936
+ ERROR(NULL, NULL, NULL,
937
+ "xmlCompileAttributeTest : Name expected\n");
938
+ ctxt->error = 1;
939
+ }
940
+ return;
941
+ }
942
+ if (CUR == ':') {
943
+ int i;
944
+ xmlChar *prefix = name;
945
+
946
+ NEXT;
947
+
948
+ if (IS_BLANK_CH(CUR)) {
949
+ ERROR5(NULL, NULL, NULL, "Invalid QName.\n", NULL);
950
+ XML_PAT_FREE_STRING(ctxt, prefix);
951
+ ctxt->error = 1;
952
+ goto error;
953
+ }
954
+ /*
955
+ * This is a namespace match
956
+ */
957
+ token = xmlPatScanName(ctxt);
958
+ if ((prefix[0] == 'x') &&
959
+ (prefix[1] == 'm') &&
960
+ (prefix[2] == 'l') &&
961
+ (prefix[3] == 0))
962
+ {
963
+ XML_PAT_COPY_NSNAME(ctxt, URL, XML_XML_NAMESPACE);
964
+ } else {
965
+ for (i = 0;i < ctxt->nb_namespaces;i++) {
966
+ if (xmlStrEqual(ctxt->namespaces[2 * i + 1], prefix)) {
967
+ XML_PAT_COPY_NSNAME(ctxt, URL, ctxt->namespaces[2 * i])
968
+ break;
969
+ }
970
+ }
971
+ if (i >= ctxt->nb_namespaces) {
972
+ ERROR5(NULL, NULL, NULL,
973
+ "xmlCompileAttributeTest : no namespace bound to prefix %s\n",
974
+ prefix);
975
+ XML_PAT_FREE_STRING(ctxt, prefix);
976
+ ctxt->error = 1;
977
+ goto error;
978
+ }
979
+ }
980
+ XML_PAT_FREE_STRING(ctxt, prefix);
981
+ if (token == NULL) {
982
+ if (CUR == '*') {
983
+ NEXT;
984
+ PUSH(XML_OP_ATTR, NULL, URL);
985
+ } else {
986
+ ERROR(NULL, NULL, NULL,
987
+ "xmlCompileAttributeTest : Name expected\n");
988
+ ctxt->error = 1;
989
+ goto error;
990
+ }
991
+ } else {
992
+ PUSH(XML_OP_ATTR, token, URL);
993
+ }
994
+ } else {
995
+ PUSH(XML_OP_ATTR, name, NULL);
996
+ }
997
+ return;
998
+ error:
999
+ if (URL != NULL)
1000
+ XML_PAT_FREE_STRING(ctxt, URL)
1001
+ if (token != NULL)
1002
+ XML_PAT_FREE_STRING(ctxt, token);
1003
+ }
1004
+
1005
+ /**
1006
+ * xmlCompileStepPattern:
1007
+ * @ctxt: the compilation context
1008
+ *
1009
+ * Compile the Step Pattern and generates a precompiled
1010
+ * form suitable for fast matching.
1011
+ *
1012
+ * [3] Step ::= '.' | NameTest
1013
+ * [4] NameTest ::= QName | '*' | NCName ':' '*'
1014
+ */
1015
+
1016
+ static void
1017
+ xmlCompileStepPattern(xmlPatParserContextPtr ctxt) {
1018
+ xmlChar *token = NULL;
1019
+ xmlChar *name = NULL;
1020
+ xmlChar *URL = NULL;
1021
+ int hasBlanks = 0;
1022
+
1023
+ SKIP_BLANKS;
1024
+ if (CUR == '.') {
1025
+ /*
1026
+ * Context node.
1027
+ */
1028
+ NEXT;
1029
+ PUSH(XML_OP_ELEM, NULL, NULL);
1030
+ return;
1031
+ }
1032
+ if (CUR == '@') {
1033
+ /*
1034
+ * Attribute test.
1035
+ */
1036
+ if (XML_STREAM_XS_IDC_SEL(ctxt->comp)) {
1037
+ ERROR5(NULL, NULL, NULL,
1038
+ "Unexpected attribute axis in '%s'.\n", ctxt->base);
1039
+ ctxt->error = 1;
1040
+ return;
1041
+ }
1042
+ NEXT;
1043
+ xmlCompileAttributeTest(ctxt);
1044
+ if (ctxt->error != 0)
1045
+ goto error;
1046
+ return;
1047
+ }
1048
+ name = xmlPatScanNCName(ctxt);
1049
+ if (name == NULL) {
1050
+ if (CUR == '*') {
1051
+ NEXT;
1052
+ PUSH(XML_OP_ALL, NULL, NULL);
1053
+ return;
1054
+ } else {
1055
+ ERROR(NULL, NULL, NULL,
1056
+ "xmlCompileStepPattern : Name expected\n");
1057
+ ctxt->error = 1;
1058
+ return;
1059
+ }
1060
+ }
1061
+ if (IS_BLANK_CH(CUR)) {
1062
+ hasBlanks = 1;
1063
+ SKIP_BLANKS;
1064
+ }
1065
+ if (CUR == ':') {
1066
+ NEXT;
1067
+ if (CUR != ':') {
1068
+ xmlChar *prefix = name;
1069
+ int i;
1070
+
1071
+ if (hasBlanks || IS_BLANK_CH(CUR)) {
1072
+ ERROR5(NULL, NULL, NULL, "Invalid QName.\n", NULL);
1073
+ ctxt->error = 1;
1074
+ goto error;
1075
+ }
1076
+ /*
1077
+ * This is a namespace match
1078
+ */
1079
+ token = xmlPatScanName(ctxt);
1080
+ if ((prefix[0] == 'x') &&
1081
+ (prefix[1] == 'm') &&
1082
+ (prefix[2] == 'l') &&
1083
+ (prefix[3] == 0))
1084
+ {
1085
+ XML_PAT_COPY_NSNAME(ctxt, URL, XML_XML_NAMESPACE)
1086
+ } else {
1087
+ for (i = 0;i < ctxt->nb_namespaces;i++) {
1088
+ if (xmlStrEqual(ctxt->namespaces[2 * i + 1], prefix)) {
1089
+ XML_PAT_COPY_NSNAME(ctxt, URL, ctxt->namespaces[2 * i])
1090
+ break;
1091
+ }
1092
+ }
1093
+ if (i >= ctxt->nb_namespaces) {
1094
+ ERROR5(NULL, NULL, NULL,
1095
+ "xmlCompileStepPattern : no namespace bound to prefix %s\n",
1096
+ prefix);
1097
+ ctxt->error = 1;
1098
+ goto error;
1099
+ }
1100
+ }
1101
+ XML_PAT_FREE_STRING(ctxt, prefix);
1102
+ name = NULL;
1103
+ if (token == NULL) {
1104
+ if (CUR == '*') {
1105
+ NEXT;
1106
+ PUSH(XML_OP_NS, URL, NULL);
1107
+ } else {
1108
+ ERROR(NULL, NULL, NULL,
1109
+ "xmlCompileStepPattern : Name expected\n");
1110
+ ctxt->error = 1;
1111
+ goto error;
1112
+ }
1113
+ } else {
1114
+ PUSH(XML_OP_ELEM, token, URL);
1115
+ }
1116
+ } else {
1117
+ NEXT;
1118
+ if (xmlStrEqual(name, (const xmlChar *) "child")) {
1119
+ XML_PAT_FREE_STRING(ctxt, name);
1120
+ name = xmlPatScanName(ctxt);
1121
+ if (name == NULL) {
1122
+ if (CUR == '*') {
1123
+ NEXT;
1124
+ PUSH(XML_OP_ALL, NULL, NULL);
1125
+ return;
1126
+ } else {
1127
+ ERROR(NULL, NULL, NULL,
1128
+ "xmlCompileStepPattern : QName expected\n");
1129
+ ctxt->error = 1;
1130
+ goto error;
1131
+ }
1132
+ }
1133
+ if (CUR == ':') {
1134
+ xmlChar *prefix = name;
1135
+ int i;
1136
+
1137
+ NEXT;
1138
+ if (IS_BLANK_CH(CUR)) {
1139
+ ERROR5(NULL, NULL, NULL, "Invalid QName.\n", NULL);
1140
+ ctxt->error = 1;
1141
+ goto error;
1142
+ }
1143
+ /*
1144
+ * This is a namespace match
1145
+ */
1146
+ token = xmlPatScanName(ctxt);
1147
+ if ((prefix[0] == 'x') &&
1148
+ (prefix[1] == 'm') &&
1149
+ (prefix[2] == 'l') &&
1150
+ (prefix[3] == 0))
1151
+ {
1152
+ XML_PAT_COPY_NSNAME(ctxt, URL, XML_XML_NAMESPACE)
1153
+ } else {
1154
+ for (i = 0;i < ctxt->nb_namespaces;i++) {
1155
+ if (xmlStrEqual(ctxt->namespaces[2 * i + 1], prefix)) {
1156
+ XML_PAT_COPY_NSNAME(ctxt, URL, ctxt->namespaces[2 * i])
1157
+ break;
1158
+ }
1159
+ }
1160
+ if (i >= ctxt->nb_namespaces) {
1161
+ ERROR5(NULL, NULL, NULL,
1162
+ "xmlCompileStepPattern : no namespace bound "
1163
+ "to prefix %s\n", prefix);
1164
+ ctxt->error = 1;
1165
+ goto error;
1166
+ }
1167
+ }
1168
+ XML_PAT_FREE_STRING(ctxt, prefix);
1169
+ name = NULL;
1170
+ if (token == NULL) {
1171
+ if (CUR == '*') {
1172
+ NEXT;
1173
+ PUSH(XML_OP_NS, URL, NULL);
1174
+ } else {
1175
+ ERROR(NULL, NULL, NULL,
1176
+ "xmlCompileStepPattern : Name expected\n");
1177
+ ctxt->error = 1;
1178
+ goto error;
1179
+ }
1180
+ } else {
1181
+ PUSH(XML_OP_CHILD, token, URL);
1182
+ }
1183
+ } else
1184
+ PUSH(XML_OP_CHILD, name, NULL);
1185
+ return;
1186
+ } else if (xmlStrEqual(name, (const xmlChar *) "attribute")) {
1187
+ XML_PAT_FREE_STRING(ctxt, name)
1188
+ name = NULL;
1189
+ if (XML_STREAM_XS_IDC_SEL(ctxt->comp)) {
1190
+ ERROR5(NULL, NULL, NULL,
1191
+ "Unexpected attribute axis in '%s'.\n", ctxt->base);
1192
+ ctxt->error = 1;
1193
+ goto error;
1194
+ }
1195
+ xmlCompileAttributeTest(ctxt);
1196
+ if (ctxt->error != 0)
1197
+ goto error;
1198
+ return;
1199
+ } else {
1200
+ ERROR5(NULL, NULL, NULL,
1201
+ "The 'element' or 'attribute' axis is expected.\n", NULL);
1202
+ ctxt->error = 1;
1203
+ goto error;
1204
+ }
1205
+ }
1206
+ } else if (CUR == '*') {
1207
+ if (name != NULL) {
1208
+ ctxt->error = 1;
1209
+ goto error;
1210
+ }
1211
+ NEXT;
1212
+ PUSH(XML_OP_ALL, token, NULL);
1213
+ } else {
1214
+ PUSH(XML_OP_ELEM, name, NULL);
1215
+ }
1216
+ return;
1217
+ error:
1218
+ if (URL != NULL)
1219
+ XML_PAT_FREE_STRING(ctxt, URL)
1220
+ if (token != NULL)
1221
+ XML_PAT_FREE_STRING(ctxt, token)
1222
+ if (name != NULL)
1223
+ XML_PAT_FREE_STRING(ctxt, name)
1224
+ }
1225
+
1226
+ /**
1227
+ * xmlCompilePathPattern:
1228
+ * @ctxt: the compilation context
1229
+ *
1230
+ * Compile the Path Pattern and generates a precompiled
1231
+ * form suitable for fast matching.
1232
+ *
1233
+ * [5] Path ::= ('.//')? ( Step '/' )* ( Step | '@' NameTest )
1234
+ */
1235
+ static void
1236
+ xmlCompilePathPattern(xmlPatParserContextPtr ctxt) {
1237
+ SKIP_BLANKS;
1238
+ if (CUR == '/') {
1239
+ ctxt->comp->flags |= PAT_FROM_ROOT;
1240
+ } else if ((CUR == '.') || (ctxt->comp->flags & XML_PATTERN_NOTPATTERN)) {
1241
+ ctxt->comp->flags |= PAT_FROM_CUR;
1242
+ }
1243
+
1244
+ if ((CUR == '/') && (NXT(1) == '/')) {
1245
+ PUSH(XML_OP_ANCESTOR, NULL, NULL);
1246
+ NEXT;
1247
+ NEXT;
1248
+ } else if ((CUR == '.') && (NXT(1) == '/') && (NXT(2) == '/')) {
1249
+ PUSH(XML_OP_ANCESTOR, NULL, NULL);
1250
+ NEXT;
1251
+ NEXT;
1252
+ NEXT;
1253
+ /* Check for incompleteness. */
1254
+ SKIP_BLANKS;
1255
+ if (CUR == 0) {
1256
+ ERROR5(NULL, NULL, NULL,
1257
+ "Incomplete expression '%s'.\n", ctxt->base);
1258
+ ctxt->error = 1;
1259
+ goto error;
1260
+ }
1261
+ }
1262
+ if (CUR == '@') {
1263
+ NEXT;
1264
+ xmlCompileAttributeTest(ctxt);
1265
+ SKIP_BLANKS;
1266
+ /* TODO: check for incompleteness */
1267
+ if (CUR != 0) {
1268
+ xmlCompileStepPattern(ctxt);
1269
+ if (ctxt->error != 0)
1270
+ goto error;
1271
+ }
1272
+ } else {
1273
+ if (CUR == '/') {
1274
+ PUSH(XML_OP_ROOT, NULL, NULL);
1275
+ NEXT;
1276
+ /* Check for incompleteness. */
1277
+ SKIP_BLANKS;
1278
+ if (CUR == 0) {
1279
+ ERROR5(NULL, NULL, NULL,
1280
+ "Incomplete expression '%s'.\n", ctxt->base);
1281
+ ctxt->error = 1;
1282
+ goto error;
1283
+ }
1284
+ }
1285
+ xmlCompileStepPattern(ctxt);
1286
+ if (ctxt->error != 0)
1287
+ goto error;
1288
+ SKIP_BLANKS;
1289
+ while (CUR == '/') {
1290
+ if (NXT(1) == '/') {
1291
+ PUSH(XML_OP_ANCESTOR, NULL, NULL);
1292
+ NEXT;
1293
+ NEXT;
1294
+ SKIP_BLANKS;
1295
+ xmlCompileStepPattern(ctxt);
1296
+ if (ctxt->error != 0)
1297
+ goto error;
1298
+ } else {
1299
+ PUSH(XML_OP_PARENT, NULL, NULL);
1300
+ NEXT;
1301
+ SKIP_BLANKS;
1302
+ if (CUR == 0) {
1303
+ ERROR5(NULL, NULL, NULL,
1304
+ "Incomplete expression '%s'.\n", ctxt->base);
1305
+ ctxt->error = 1;
1306
+ goto error;
1307
+ }
1308
+ xmlCompileStepPattern(ctxt);
1309
+ if (ctxt->error != 0)
1310
+ goto error;
1311
+ }
1312
+ }
1313
+ }
1314
+ if (CUR != 0) {
1315
+ ERROR5(NULL, NULL, NULL,
1316
+ "Failed to compile pattern %s\n", ctxt->base);
1317
+ ctxt->error = 1;
1318
+ }
1319
+ error:
1320
+ return;
1321
+ }
1322
+
1323
+ /**
1324
+ * xmlCompileIDCXPathPath:
1325
+ * @ctxt: the compilation context
1326
+ *
1327
+ * Compile the Path Pattern and generates a precompiled
1328
+ * form suitable for fast matching.
1329
+ *
1330
+ * [5] Path ::= ('.//')? ( Step '/' )* ( Step | '@' NameTest )
1331
+ */
1332
+ static void
1333
+ xmlCompileIDCXPathPath(xmlPatParserContextPtr ctxt) {
1334
+ SKIP_BLANKS;
1335
+ if (CUR == '/') {
1336
+ ERROR5(NULL, NULL, NULL,
1337
+ "Unexpected selection of the document root in '%s'.\n",
1338
+ ctxt->base);
1339
+ goto error;
1340
+ }
1341
+ ctxt->comp->flags |= PAT_FROM_CUR;
1342
+
1343
+ if (CUR == '.') {
1344
+ /* "." - "self::node()" */
1345
+ NEXT;
1346
+ SKIP_BLANKS;
1347
+ if (CUR == 0) {
1348
+ /*
1349
+ * Selection of the context node.
1350
+ */
1351
+ PUSH(XML_OP_ELEM, NULL, NULL);
1352
+ return;
1353
+ }
1354
+ if (CUR != '/') {
1355
+ /* TODO: A more meaningful error message. */
1356
+ ERROR5(NULL, NULL, NULL,
1357
+ "Unexpected token after '.' in '%s'.\n", ctxt->base);
1358
+ goto error;
1359
+ }
1360
+ /* "./" - "self::node()/" */
1361
+ NEXT;
1362
+ SKIP_BLANKS;
1363
+ if (CUR == '/') {
1364
+ if (IS_BLANK_CH(PEEKPREV(1))) {
1365
+ /*
1366
+ * Disallow "./ /"
1367
+ */
1368
+ ERROR5(NULL, NULL, NULL,
1369
+ "Unexpected '/' token in '%s'.\n", ctxt->base);
1370
+ goto error;
1371
+ }
1372
+ /* ".//" - "self:node()/descendant-or-self::node()/" */
1373
+ PUSH(XML_OP_ANCESTOR, NULL, NULL);
1374
+ NEXT;
1375
+ SKIP_BLANKS;
1376
+ }
1377
+ if (CUR == 0)
1378
+ goto error_unfinished;
1379
+ }
1380
+ /*
1381
+ * Process steps.
1382
+ */
1383
+ do {
1384
+ xmlCompileStepPattern(ctxt);
1385
+ if (ctxt->error != 0)
1386
+ goto error;
1387
+ SKIP_BLANKS;
1388
+ if (CUR != '/')
1389
+ break;
1390
+ PUSH(XML_OP_PARENT, NULL, NULL);
1391
+ NEXT;
1392
+ SKIP_BLANKS;
1393
+ if (CUR == '/') {
1394
+ /*
1395
+ * Disallow subsequent '//'.
1396
+ */
1397
+ ERROR5(NULL, NULL, NULL,
1398
+ "Unexpected subsequent '//' in '%s'.\n",
1399
+ ctxt->base);
1400
+ goto error;
1401
+ }
1402
+ if (CUR == 0)
1403
+ goto error_unfinished;
1404
+
1405
+ } while (CUR != 0);
1406
+
1407
+ if (CUR != 0) {
1408
+ ERROR5(NULL, NULL, NULL,
1409
+ "Failed to compile expression '%s'.\n", ctxt->base);
1410
+ ctxt->error = 1;
1411
+ }
1412
+ return;
1413
+ error:
1414
+ ctxt->error = 1;
1415
+ return;
1416
+
1417
+ error_unfinished:
1418
+ ctxt->error = 1;
1419
+ ERROR5(NULL, NULL, NULL,
1420
+ "Unfinished expression '%s'.\n", ctxt->base);
1421
+ return;
1422
+ }
1423
+
1424
+ /************************************************************************
1425
+ * *
1426
+ * The streaming code *
1427
+ * *
1428
+ ************************************************************************/
1429
+
1430
+ #ifdef DEBUG_STREAMING
1431
+ static void
1432
+ xmlDebugStreamComp(xmlStreamCompPtr stream) {
1433
+ int i;
1434
+
1435
+ if (stream == NULL) {
1436
+ printf("Stream: NULL\n");
1437
+ return;
1438
+ }
1439
+ printf("Stream: %d steps\n", stream->nbStep);
1440
+ for (i = 0;i < stream->nbStep;i++) {
1441
+ if (stream->steps[i].ns != NULL) {
1442
+ printf("{%s}", stream->steps[i].ns);
1443
+ }
1444
+ if (stream->steps[i].name == NULL) {
1445
+ printf("* ");
1446
+ } else {
1447
+ printf("%s ", stream->steps[i].name);
1448
+ }
1449
+ if (stream->steps[i].flags & XML_STREAM_STEP_ROOT)
1450
+ printf("root ");
1451
+ if (stream->steps[i].flags & XML_STREAM_STEP_DESC)
1452
+ printf("// ");
1453
+ if (stream->steps[i].flags & XML_STREAM_STEP_FINAL)
1454
+ printf("final ");
1455
+ printf("\n");
1456
+ }
1457
+ }
1458
+ static void
1459
+ xmlDebugStreamCtxt(xmlStreamCtxtPtr ctxt, int match) {
1460
+ int i;
1461
+
1462
+ if (ctxt == NULL) {
1463
+ printf("Stream: NULL\n");
1464
+ return;
1465
+ }
1466
+ printf("Stream: level %d, %d states: ", ctxt->level, ctxt->nbState);
1467
+ if (match)
1468
+ printf("matches\n");
1469
+ else
1470
+ printf("\n");
1471
+ for (i = 0;i < ctxt->nbState;i++) {
1472
+ if (ctxt->states[2 * i] < 0)
1473
+ printf(" %d: free\n", i);
1474
+ else {
1475
+ printf(" %d: step %d, level %d", i, ctxt->states[2 * i],
1476
+ ctxt->states[(2 * i) + 1]);
1477
+ if (ctxt->comp->steps[ctxt->states[2 * i]].flags &
1478
+ XML_STREAM_STEP_DESC)
1479
+ printf(" //\n");
1480
+ else
1481
+ printf("\n");
1482
+ }
1483
+ }
1484
+ }
1485
+ #endif
1486
+ /**
1487
+ * xmlNewStreamComp:
1488
+ * @size: the number of expected steps
1489
+ *
1490
+ * build a new compiled pattern for streaming
1491
+ *
1492
+ * Returns the new structure or NULL in case of error.
1493
+ */
1494
+ static xmlStreamCompPtr
1495
+ xmlNewStreamComp(int size) {
1496
+ xmlStreamCompPtr cur;
1497
+
1498
+ if (size < 4)
1499
+ size = 4;
1500
+
1501
+ cur = (xmlStreamCompPtr) xmlMalloc(sizeof(xmlStreamComp));
1502
+ if (cur == NULL) {
1503
+ ERROR(NULL, NULL, NULL,
1504
+ "xmlNewStreamComp: malloc failed\n");
1505
+ return(NULL);
1506
+ }
1507
+ memset(cur, 0, sizeof(xmlStreamComp));
1508
+ cur->steps = (xmlStreamStepPtr) xmlMalloc(size * sizeof(xmlStreamStep));
1509
+ if (cur->steps == NULL) {
1510
+ xmlFree(cur);
1511
+ ERROR(NULL, NULL, NULL,
1512
+ "xmlNewStreamComp: malloc failed\n");
1513
+ return(NULL);
1514
+ }
1515
+ cur->nbStep = 0;
1516
+ cur->maxStep = size;
1517
+ return(cur);
1518
+ }
1519
+
1520
+ /**
1521
+ * xmlFreeStreamComp:
1522
+ * @comp: the compiled pattern for streaming
1523
+ *
1524
+ * Free the compiled pattern for streaming
1525
+ */
1526
+ static void
1527
+ xmlFreeStreamComp(xmlStreamCompPtr comp) {
1528
+ if (comp != NULL) {
1529
+ if (comp->steps != NULL)
1530
+ xmlFree(comp->steps);
1531
+ if (comp->dict != NULL)
1532
+ xmlDictFree(comp->dict);
1533
+ xmlFree(comp);
1534
+ }
1535
+ }
1536
+
1537
+ /**
1538
+ * xmlStreamCompAddStep:
1539
+ * @comp: the compiled pattern for streaming
1540
+ * @name: the first string, the name, or NULL for *
1541
+ * @ns: the second step, the namespace name
1542
+ * @flags: the flags for that step
1543
+ *
1544
+ * Add a new step to the compiled pattern
1545
+ *
1546
+ * Returns -1 in case of error or the step index if successful
1547
+ */
1548
+ static int
1549
+ xmlStreamCompAddStep(xmlStreamCompPtr comp, const xmlChar *name,
1550
+ const xmlChar *ns, int nodeType, int flags) {
1551
+ xmlStreamStepPtr cur;
1552
+
1553
+ if (comp->nbStep >= comp->maxStep) {
1554
+ cur = (xmlStreamStepPtr) xmlRealloc(comp->steps,
1555
+ comp->maxStep * 2 * sizeof(xmlStreamStep));
1556
+ if (cur == NULL) {
1557
+ ERROR(NULL, NULL, NULL,
1558
+ "xmlNewStreamComp: malloc failed\n");
1559
+ return(-1);
1560
+ }
1561
+ comp->steps = cur;
1562
+ comp->maxStep *= 2;
1563
+ }
1564
+ cur = &comp->steps[comp->nbStep++];
1565
+ cur->flags = flags;
1566
+ cur->name = name;
1567
+ cur->ns = ns;
1568
+ cur->nodeType = nodeType;
1569
+ return(comp->nbStep - 1);
1570
+ }
1571
+
1572
+ /**
1573
+ * xmlStreamCompile:
1574
+ * @comp: the precompiled pattern
1575
+ *
1576
+ * Tries to stream compile a pattern
1577
+ *
1578
+ * Returns -1 in case of failure and 0 in case of success.
1579
+ */
1580
+ static int
1581
+ xmlStreamCompile(xmlPatternPtr comp) {
1582
+ xmlStreamCompPtr stream;
1583
+ int i, s = 0, root = 0, flags = 0, prevs = -1;
1584
+ xmlStepOp step;
1585
+
1586
+ if ((comp == NULL) || (comp->steps == NULL))
1587
+ return(-1);
1588
+ /*
1589
+ * special case for .
1590
+ */
1591
+ if ((comp->nbStep == 1) &&
1592
+ (comp->steps[0].op == XML_OP_ELEM) &&
1593
+ (comp->steps[0].value == NULL) &&
1594
+ (comp->steps[0].value2 == NULL)) {
1595
+ stream = xmlNewStreamComp(0);
1596
+ if (stream == NULL)
1597
+ return(-1);
1598
+ /* Note that the stream will have no steps in this case. */
1599
+ stream->flags |= XML_STREAM_FINAL_IS_ANY_NODE;
1600
+ comp->stream = stream;
1601
+ return(0);
1602
+ }
1603
+
1604
+ stream = xmlNewStreamComp((comp->nbStep / 2) + 1);
1605
+ if (stream == NULL)
1606
+ return(-1);
1607
+ if (comp->dict != NULL) {
1608
+ stream->dict = comp->dict;
1609
+ xmlDictReference(stream->dict);
1610
+ }
1611
+
1612
+ i = 0;
1613
+ if (comp->flags & PAT_FROM_ROOT)
1614
+ stream->flags |= XML_STREAM_FROM_ROOT;
1615
+
1616
+ for (;i < comp->nbStep;i++) {
1617
+ step = comp->steps[i];
1618
+ switch (step.op) {
1619
+ case XML_OP_END:
1620
+ break;
1621
+ case XML_OP_ROOT:
1622
+ if (i != 0)
1623
+ goto error;
1624
+ root = 1;
1625
+ break;
1626
+ case XML_OP_NS:
1627
+ s = xmlStreamCompAddStep(stream, NULL, step.value,
1628
+ XML_ELEMENT_NODE, flags);
1629
+ if (s < 0)
1630
+ goto error;
1631
+ prevs = s;
1632
+ flags = 0;
1633
+ break;
1634
+ case XML_OP_ATTR:
1635
+ flags |= XML_STREAM_STEP_ATTR;
1636
+ prevs = -1;
1637
+ s = xmlStreamCompAddStep(stream,
1638
+ step.value, step.value2, XML_ATTRIBUTE_NODE, flags);
1639
+ flags = 0;
1640
+ if (s < 0)
1641
+ goto error;
1642
+ break;
1643
+ case XML_OP_ELEM:
1644
+ if ((step.value == NULL) && (step.value2 == NULL)) {
1645
+ /*
1646
+ * We have a "." or "self::node()" here.
1647
+ * Eliminate redundant self::node() tests like in "/./."
1648
+ * or "//./"
1649
+ * The only case we won't eliminate is "//.", i.e. if
1650
+ * self::node() is the last node test and we had
1651
+ * continuation somewhere beforehand.
1652
+ */
1653
+ if ((comp->nbStep == i + 1) &&
1654
+ (flags & XML_STREAM_STEP_DESC)) {
1655
+ /*
1656
+ * Mark the special case where the expression resolves
1657
+ * to any type of node.
1658
+ */
1659
+ if (comp->nbStep == i + 1) {
1660
+ stream->flags |= XML_STREAM_FINAL_IS_ANY_NODE;
1661
+ }
1662
+ flags |= XML_STREAM_STEP_NODE;
1663
+ s = xmlStreamCompAddStep(stream, NULL, NULL,
1664
+ XML_STREAM_ANY_NODE, flags);
1665
+ if (s < 0)
1666
+ goto error;
1667
+ flags = 0;
1668
+ /*
1669
+ * If there was a previous step, mark it to be added to
1670
+ * the result node-set; this is needed since only
1671
+ * the last step will be marked as "final" and only
1672
+ * "final" nodes are added to the resulting set.
1673
+ */
1674
+ if (prevs != -1) {
1675
+ stream->steps[prevs].flags |= XML_STREAM_STEP_IN_SET;
1676
+ prevs = -1;
1677
+ }
1678
+ break;
1679
+
1680
+ } else {
1681
+ /* Just skip this one. */
1682
+ continue;
1683
+ }
1684
+ }
1685
+ /* An element node. */
1686
+ s = xmlStreamCompAddStep(stream, step.value, step.value2,
1687
+ XML_ELEMENT_NODE, flags);
1688
+ if (s < 0)
1689
+ goto error;
1690
+ prevs = s;
1691
+ flags = 0;
1692
+ break;
1693
+ case XML_OP_CHILD:
1694
+ /* An element node child. */
1695
+ s = xmlStreamCompAddStep(stream, step.value, step.value2,
1696
+ XML_ELEMENT_NODE, flags);
1697
+ if (s < 0)
1698
+ goto error;
1699
+ prevs = s;
1700
+ flags = 0;
1701
+ break;
1702
+ case XML_OP_ALL:
1703
+ s = xmlStreamCompAddStep(stream, NULL, NULL,
1704
+ XML_ELEMENT_NODE, flags);
1705
+ if (s < 0)
1706
+ goto error;
1707
+ prevs = s;
1708
+ flags = 0;
1709
+ break;
1710
+ case XML_OP_PARENT:
1711
+ break;
1712
+ case XML_OP_ANCESTOR:
1713
+ /* Skip redundant continuations. */
1714
+ if (flags & XML_STREAM_STEP_DESC)
1715
+ break;
1716
+ flags |= XML_STREAM_STEP_DESC;
1717
+ /*
1718
+ * Mark the expression as having "//".
1719
+ */
1720
+ if ((stream->flags & XML_STREAM_DESC) == 0)
1721
+ stream->flags |= XML_STREAM_DESC;
1722
+ break;
1723
+ }
1724
+ }
1725
+ if ((! root) && (comp->flags & XML_PATTERN_NOTPATTERN) == 0) {
1726
+ /*
1727
+ * If this should behave like a real pattern, we will mark
1728
+ * the first step as having "//", to be reentrant on every
1729
+ * tree level.
1730
+ */
1731
+ if ((stream->flags & XML_STREAM_DESC) == 0)
1732
+ stream->flags |= XML_STREAM_DESC;
1733
+
1734
+ if (stream->nbStep > 0) {
1735
+ if ((stream->steps[0].flags & XML_STREAM_STEP_DESC) == 0)
1736
+ stream->steps[0].flags |= XML_STREAM_STEP_DESC;
1737
+ }
1738
+ }
1739
+ if (stream->nbStep <= s)
1740
+ goto error;
1741
+ stream->steps[s].flags |= XML_STREAM_STEP_FINAL;
1742
+ if (root)
1743
+ stream->steps[0].flags |= XML_STREAM_STEP_ROOT;
1744
+ #ifdef DEBUG_STREAMING
1745
+ xmlDebugStreamComp(stream);
1746
+ #endif
1747
+ comp->stream = stream;
1748
+ return(0);
1749
+ error:
1750
+ xmlFreeStreamComp(stream);
1751
+ return(0);
1752
+ }
1753
+
1754
+ /**
1755
+ * xmlNewStreamCtxt:
1756
+ * @size: the number of expected states
1757
+ *
1758
+ * build a new stream context
1759
+ *
1760
+ * Returns the new structure or NULL in case of error.
1761
+ */
1762
+ static xmlStreamCtxtPtr
1763
+ xmlNewStreamCtxt(xmlStreamCompPtr stream) {
1764
+ xmlStreamCtxtPtr cur;
1765
+
1766
+ cur = (xmlStreamCtxtPtr) xmlMalloc(sizeof(xmlStreamCtxt));
1767
+ if (cur == NULL) {
1768
+ ERROR(NULL, NULL, NULL,
1769
+ "xmlNewStreamCtxt: malloc failed\n");
1770
+ return(NULL);
1771
+ }
1772
+ memset(cur, 0, sizeof(xmlStreamCtxt));
1773
+ cur->states = (int *) xmlMalloc(4 * 2 * sizeof(int));
1774
+ if (cur->states == NULL) {
1775
+ xmlFree(cur);
1776
+ ERROR(NULL, NULL, NULL,
1777
+ "xmlNewStreamCtxt: malloc failed\n");
1778
+ return(NULL);
1779
+ }
1780
+ cur->nbState = 0;
1781
+ cur->maxState = 4;
1782
+ cur->level = 0;
1783
+ cur->comp = stream;
1784
+ cur->blockLevel = -1;
1785
+ return(cur);
1786
+ }
1787
+
1788
+ /**
1789
+ * xmlFreeStreamCtxt:
1790
+ * @stream: the stream context
1791
+ *
1792
+ * Free the stream context
1793
+ */
1794
+ void
1795
+ xmlFreeStreamCtxt(xmlStreamCtxtPtr stream) {
1796
+ xmlStreamCtxtPtr next;
1797
+
1798
+ while (stream != NULL) {
1799
+ next = stream->next;
1800
+ if (stream->states != NULL)
1801
+ xmlFree(stream->states);
1802
+ xmlFree(stream);
1803
+ stream = next;
1804
+ }
1805
+ }
1806
+
1807
+ /**
1808
+ * xmlStreamCtxtAddState:
1809
+ * @comp: the stream context
1810
+ * @idx: the step index for that streaming state
1811
+ *
1812
+ * Add a new state to the stream context
1813
+ *
1814
+ * Returns -1 in case of error or the state index if successful
1815
+ */
1816
+ static int
1817
+ xmlStreamCtxtAddState(xmlStreamCtxtPtr comp, int idx, int level) {
1818
+ int i;
1819
+ for (i = 0;i < comp->nbState;i++) {
1820
+ if (comp->states[2 * i] < 0) {
1821
+ comp->states[2 * i] = idx;
1822
+ comp->states[2 * i + 1] = level;
1823
+ return(i);
1824
+ }
1825
+ }
1826
+ if (comp->nbState >= comp->maxState) {
1827
+ int *cur;
1828
+
1829
+ cur = (int *) xmlRealloc(comp->states,
1830
+ comp->maxState * 4 * sizeof(int));
1831
+ if (cur == NULL) {
1832
+ ERROR(NULL, NULL, NULL,
1833
+ "xmlNewStreamCtxt: malloc failed\n");
1834
+ return(-1);
1835
+ }
1836
+ comp->states = cur;
1837
+ comp->maxState *= 2;
1838
+ }
1839
+ comp->states[2 * comp->nbState] = idx;
1840
+ comp->states[2 * comp->nbState++ + 1] = level;
1841
+ return(comp->nbState - 1);
1842
+ }
1843
+
1844
+ /**
1845
+ * xmlStreamPushInternal:
1846
+ * @stream: the stream context
1847
+ * @name: the current name
1848
+ * @ns: the namespace name
1849
+ * @nodeType: the type of the node
1850
+ *
1851
+ * Push new data onto the stream. NOTE: if the call xmlPatterncompile()
1852
+ * indicated a dictionary, then strings for name and ns will be expected
1853
+ * to come from the dictionary.
1854
+ * Both @name and @ns being NULL means the / i.e. the root of the document.
1855
+ * This can also act as a reset.
1856
+ *
1857
+ * Returns: -1 in case of error, 1 if the current state in the stream is a
1858
+ * match and 0 otherwise.
1859
+ */
1860
+ static int
1861
+ xmlStreamPushInternal(xmlStreamCtxtPtr stream,
1862
+ const xmlChar *name, const xmlChar *ns,
1863
+ int nodeType) {
1864
+ int ret = 0, err = 0, final = 0, tmp, i, m, match, stepNr, desc;
1865
+ xmlStreamCompPtr comp;
1866
+ xmlStreamStep step;
1867
+ #ifdef DEBUG_STREAMING
1868
+ xmlStreamCtxtPtr orig = stream;
1869
+ #endif
1870
+
1871
+ if ((stream == NULL) || (stream->nbState < 0))
1872
+ return(-1);
1873
+
1874
+ while (stream != NULL) {
1875
+ comp = stream->comp;
1876
+
1877
+ if ((nodeType == XML_ELEMENT_NODE) &&
1878
+ (name == NULL) && (ns == NULL)) {
1879
+ /* We have a document node here (or a reset). */
1880
+ stream->nbState = 0;
1881
+ stream->level = 0;
1882
+ stream->blockLevel = -1;
1883
+ if (comp->flags & XML_STREAM_FROM_ROOT) {
1884
+ if (comp->nbStep == 0) {
1885
+ /* TODO: We have a "/." here? */
1886
+ ret = 1;
1887
+ } else {
1888
+ if ((comp->nbStep == 1) &&
1889
+ (comp->steps[0].nodeType == XML_STREAM_ANY_NODE) &&
1890
+ (comp->steps[0].flags & XML_STREAM_STEP_DESC))
1891
+ {
1892
+ /*
1893
+ * In the case of "//." the document node will match
1894
+ * as well.
1895
+ */
1896
+ ret = 1;
1897
+ } else if (comp->steps[0].flags & XML_STREAM_STEP_ROOT) {
1898
+ /* TODO: Do we need this ? */
1899
+ tmp = xmlStreamCtxtAddState(stream, 0, 0);
1900
+ if (tmp < 0)
1901
+ err++;
1902
+ }
1903
+ }
1904
+ }
1905
+ stream = stream->next;
1906
+ continue; /* while */
1907
+ }
1908
+
1909
+ /*
1910
+ * Fast check for ".".
1911
+ */
1912
+ if (comp->nbStep == 0) {
1913
+ /*
1914
+ * / and . are handled at the XPath node set creation
1915
+ * level by checking min depth
1916
+ */
1917
+ if (stream->flags & XML_PATTERN_XPATH) {
1918
+ stream = stream->next;
1919
+ continue; /* while */
1920
+ }
1921
+ /*
1922
+ * For non-pattern like evaluation like XML Schema IDCs
1923
+ * or traditional XPath expressions, this will match if
1924
+ * we are at the first level only, otherwise on every level.
1925
+ */
1926
+ if ((nodeType != XML_ATTRIBUTE_NODE) &&
1927
+ (((stream->flags & XML_PATTERN_NOTPATTERN) == 0) ||
1928
+ (stream->level == 0))) {
1929
+ ret = 1;
1930
+ }
1931
+ stream->level++;
1932
+ goto stream_next;
1933
+ }
1934
+ if (stream->blockLevel != -1) {
1935
+ /*
1936
+ * Skip blocked expressions.
1937
+ */
1938
+ stream->level++;
1939
+ goto stream_next;
1940
+ }
1941
+
1942
+ if ((nodeType != XML_ELEMENT_NODE) &&
1943
+ (nodeType != XML_ATTRIBUTE_NODE) &&
1944
+ ((comp->flags & XML_STREAM_FINAL_IS_ANY_NODE) == 0)) {
1945
+ /*
1946
+ * No need to process nodes of other types if we don't
1947
+ * resolve to those types.
1948
+ * TODO: Do we need to block the context here?
1949
+ */
1950
+ stream->level++;
1951
+ goto stream_next;
1952
+ }
1953
+
1954
+ /*
1955
+ * Check evolution of existing states
1956
+ */
1957
+ i = 0;
1958
+ m = stream->nbState;
1959
+ while (i < m) {
1960
+ if ((comp->flags & XML_STREAM_DESC) == 0) {
1961
+ /*
1962
+ * If there is no "//", then only the last
1963
+ * added state is of interest.
1964
+ */
1965
+ stepNr = stream->states[2 * (stream->nbState -1)];
1966
+ /*
1967
+ * TODO: Security check, should not happen, remove it.
1968
+ */
1969
+ if (stream->states[(2 * (stream->nbState -1)) + 1] <
1970
+ stream->level) {
1971
+ return (-1);
1972
+ }
1973
+ desc = 0;
1974
+ /* loop-stopper */
1975
+ i = m;
1976
+ } else {
1977
+ /*
1978
+ * If there are "//", then we need to process every "//"
1979
+ * occurring in the states, plus any other state for this
1980
+ * level.
1981
+ */
1982
+ stepNr = stream->states[2 * i];
1983
+
1984
+ /* TODO: should not happen anymore: dead states */
1985
+ if (stepNr < 0)
1986
+ goto next_state;
1987
+
1988
+ tmp = stream->states[(2 * i) + 1];
1989
+
1990
+ /* skip new states just added */
1991
+ if (tmp > stream->level)
1992
+ goto next_state;
1993
+
1994
+ /* skip states at ancestor levels, except if "//" */
1995
+ desc = comp->steps[stepNr].flags & XML_STREAM_STEP_DESC;
1996
+ if ((tmp < stream->level) && (!desc))
1997
+ goto next_state;
1998
+ }
1999
+ /*
2000
+ * Check for correct node-type.
2001
+ */
2002
+ step = comp->steps[stepNr];
2003
+ if (step.nodeType != nodeType) {
2004
+ if (step.nodeType == XML_ATTRIBUTE_NODE) {
2005
+ /*
2006
+ * Block this expression for deeper evaluation.
2007
+ */
2008
+ if ((comp->flags & XML_STREAM_DESC) == 0)
2009
+ stream->blockLevel = stream->level +1;
2010
+ goto next_state;
2011
+ } else if (step.nodeType != XML_STREAM_ANY_NODE)
2012
+ goto next_state;
2013
+ }
2014
+ /*
2015
+ * Compare local/namespace-name.
2016
+ */
2017
+ match = 0;
2018
+ if (step.nodeType == XML_STREAM_ANY_NODE) {
2019
+ match = 1;
2020
+ } else if (step.name == NULL) {
2021
+ if (step.ns == NULL) {
2022
+ /*
2023
+ * This lets through all elements/attributes.
2024
+ */
2025
+ match = 1;
2026
+ } else if (ns != NULL)
2027
+ match = xmlStrEqual(step.ns, ns);
2028
+ } else if (((step.ns != NULL) == (ns != NULL)) &&
2029
+ (name != NULL) &&
2030
+ (step.name[0] == name[0]) &&
2031
+ xmlStrEqual(step.name, name) &&
2032
+ ((step.ns == ns) || xmlStrEqual(step.ns, ns)))
2033
+ {
2034
+ match = 1;
2035
+ }
2036
+ #if 0
2037
+ /*
2038
+ * TODO: Pointer comparison won't work, since not guaranteed that the given
2039
+ * values are in the same dict; especially if it's the namespace name,
2040
+ * normally coming from ns->href. We need a namespace dict mechanism !
2041
+ */
2042
+ } else if (comp->dict) {
2043
+ if (step.name == NULL) {
2044
+ if (step.ns == NULL)
2045
+ match = 1;
2046
+ else
2047
+ match = (step.ns == ns);
2048
+ } else {
2049
+ match = ((step.name == name) && (step.ns == ns));
2050
+ }
2051
+ #endif /* if 0 ------------------------------------------------------- */
2052
+ if (match) {
2053
+ final = step.flags & XML_STREAM_STEP_FINAL;
2054
+ if (desc) {
2055
+ if (final) {
2056
+ ret = 1;
2057
+ } else {
2058
+ /* descending match create a new state */
2059
+ xmlStreamCtxtAddState(stream, stepNr + 1,
2060
+ stream->level + 1);
2061
+ }
2062
+ } else {
2063
+ if (final) {
2064
+ ret = 1;
2065
+ } else {
2066
+ xmlStreamCtxtAddState(stream, stepNr + 1,
2067
+ stream->level + 1);
2068
+ }
2069
+ }
2070
+ if ((ret != 1) && (step.flags & XML_STREAM_STEP_IN_SET)) {
2071
+ /*
2072
+ * Check if we have a special case like "foo/bar//.", where
2073
+ * "foo" is selected as well.
2074
+ */
2075
+ ret = 1;
2076
+ }
2077
+ }
2078
+ if (((comp->flags & XML_STREAM_DESC) == 0) &&
2079
+ ((! match) || final)) {
2080
+ /*
2081
+ * Mark this expression as blocked for any evaluation at
2082
+ * deeper levels. Note that this includes "/foo"
2083
+ * expressions if the *pattern* behaviour is used.
2084
+ */
2085
+ stream->blockLevel = stream->level +1;
2086
+ }
2087
+ next_state:
2088
+ i++;
2089
+ }
2090
+
2091
+ stream->level++;
2092
+
2093
+ /*
2094
+ * Re/enter the expression.
2095
+ * Don't reenter if it's an absolute expression like "/foo",
2096
+ * except "//foo".
2097
+ */
2098
+ step = comp->steps[0];
2099
+ if (step.flags & XML_STREAM_STEP_ROOT)
2100
+ goto stream_next;
2101
+
2102
+ desc = step.flags & XML_STREAM_STEP_DESC;
2103
+ if (stream->flags & XML_PATTERN_NOTPATTERN) {
2104
+ /*
2105
+ * Re/enter the expression if it is a "descendant" one,
2106
+ * or if we are at the 1st level of evaluation.
2107
+ */
2108
+
2109
+ if (stream->level == 1) {
2110
+ if (XML_STREAM_XS_IDC(stream)) {
2111
+ /*
2112
+ * XS-IDC: The missing "self::node()" will always
2113
+ * match the first given node.
2114
+ */
2115
+ goto stream_next;
2116
+ } else
2117
+ goto compare;
2118
+ }
2119
+ /*
2120
+ * A "//" is always reentrant.
2121
+ */
2122
+ if (desc)
2123
+ goto compare;
2124
+
2125
+ /*
2126
+ * XS-IDC: Process the 2nd level, since the missing
2127
+ * "self::node()" is responsible for the 2nd level being
2128
+ * the real start level.
2129
+ */
2130
+ if ((stream->level == 2) && XML_STREAM_XS_IDC(stream))
2131
+ goto compare;
2132
+
2133
+ goto stream_next;
2134
+ }
2135
+
2136
+ compare:
2137
+ /*
2138
+ * Check expected node-type.
2139
+ */
2140
+ if (step.nodeType != nodeType) {
2141
+ if (nodeType == XML_ATTRIBUTE_NODE)
2142
+ goto stream_next;
2143
+ else if (step.nodeType != XML_STREAM_ANY_NODE)
2144
+ goto stream_next;
2145
+ }
2146
+ /*
2147
+ * Compare local/namespace-name.
2148
+ */
2149
+ match = 0;
2150
+ if (step.nodeType == XML_STREAM_ANY_NODE) {
2151
+ match = 1;
2152
+ } else if (step.name == NULL) {
2153
+ if (step.ns == NULL) {
2154
+ /*
2155
+ * This lets through all elements/attributes.
2156
+ */
2157
+ match = 1;
2158
+ } else if (ns != NULL)
2159
+ match = xmlStrEqual(step.ns, ns);
2160
+ } else if (((step.ns != NULL) == (ns != NULL)) &&
2161
+ (name != NULL) &&
2162
+ (step.name[0] == name[0]) &&
2163
+ xmlStrEqual(step.name, name) &&
2164
+ ((step.ns == ns) || xmlStrEqual(step.ns, ns)))
2165
+ {
2166
+ match = 1;
2167
+ }
2168
+ final = step.flags & XML_STREAM_STEP_FINAL;
2169
+ if (match) {
2170
+ if (final)
2171
+ ret = 1;
2172
+ else
2173
+ xmlStreamCtxtAddState(stream, 1, stream->level);
2174
+ if ((ret != 1) && (step.flags & XML_STREAM_STEP_IN_SET)) {
2175
+ /*
2176
+ * Check if we have a special case like "foo//.", where
2177
+ * "foo" is selected as well.
2178
+ */
2179
+ ret = 1;
2180
+ }
2181
+ }
2182
+ if (((comp->flags & XML_STREAM_DESC) == 0) &&
2183
+ ((! match) || final)) {
2184
+ /*
2185
+ * Mark this expression as blocked for any evaluation at
2186
+ * deeper levels.
2187
+ */
2188
+ stream->blockLevel = stream->level;
2189
+ }
2190
+
2191
+ stream_next:
2192
+ stream = stream->next;
2193
+ } /* while stream != NULL */
2194
+
2195
+ if (err > 0)
2196
+ ret = -1;
2197
+ #ifdef DEBUG_STREAMING
2198
+ xmlDebugStreamCtxt(orig, ret);
2199
+ #endif
2200
+ return(ret);
2201
+ }
2202
+
2203
+ /**
2204
+ * xmlStreamPush:
2205
+ * @stream: the stream context
2206
+ * @name: the current name
2207
+ * @ns: the namespace name
2208
+ *
2209
+ * Push new data onto the stream. NOTE: if the call xmlPatterncompile()
2210
+ * indicated a dictionary, then strings for name and ns will be expected
2211
+ * to come from the dictionary.
2212
+ * Both @name and @ns being NULL means the / i.e. the root of the document.
2213
+ * This can also act as a reset.
2214
+ * Otherwise the function will act as if it has been given an element-node.
2215
+ *
2216
+ * Returns: -1 in case of error, 1 if the current state in the stream is a
2217
+ * match and 0 otherwise.
2218
+ */
2219
+ int
2220
+ xmlStreamPush(xmlStreamCtxtPtr stream,
2221
+ const xmlChar *name, const xmlChar *ns) {
2222
+ return (xmlStreamPushInternal(stream, name, ns, (int) XML_ELEMENT_NODE));
2223
+ }
2224
+
2225
+ /**
2226
+ * xmlStreamPushNode:
2227
+ * @stream: the stream context
2228
+ * @name: the current name
2229
+ * @ns: the namespace name
2230
+ * @nodeType: the type of the node being pushed
2231
+ *
2232
+ * Push new data onto the stream. NOTE: if the call xmlPatterncompile()
2233
+ * indicated a dictionary, then strings for name and ns will be expected
2234
+ * to come from the dictionary.
2235
+ * Both @name and @ns being NULL means the / i.e. the root of the document.
2236
+ * This can also act as a reset.
2237
+ * Different from xmlStreamPush() this function can be fed with nodes of type:
2238
+ * element-, attribute-, text-, cdata-section-, comment- and
2239
+ * processing-instruction-node.
2240
+ *
2241
+ * Returns: -1 in case of error, 1 if the current state in the stream is a
2242
+ * match and 0 otherwise.
2243
+ */
2244
+ int
2245
+ xmlStreamPushNode(xmlStreamCtxtPtr stream,
2246
+ const xmlChar *name, const xmlChar *ns,
2247
+ int nodeType)
2248
+ {
2249
+ return (xmlStreamPushInternal(stream, name, ns,
2250
+ nodeType));
2251
+ }
2252
+
2253
+ /**
2254
+ * xmlStreamPushAttr:
2255
+ * @stream: the stream context
2256
+ * @name: the current name
2257
+ * @ns: the namespace name
2258
+ *
2259
+ * Push new attribute data onto the stream. NOTE: if the call xmlPatterncompile()
2260
+ * indicated a dictionary, then strings for name and ns will be expected
2261
+ * to come from the dictionary.
2262
+ * Both @name and @ns being NULL means the / i.e. the root of the document.
2263
+ * This can also act as a reset.
2264
+ * Otherwise the function will act as if it has been given an attribute-node.
2265
+ *
2266
+ * Returns: -1 in case of error, 1 if the current state in the stream is a
2267
+ * match and 0 otherwise.
2268
+ */
2269
+ int
2270
+ xmlStreamPushAttr(xmlStreamCtxtPtr stream,
2271
+ const xmlChar *name, const xmlChar *ns) {
2272
+ return (xmlStreamPushInternal(stream, name, ns, (int) XML_ATTRIBUTE_NODE));
2273
+ }
2274
+
2275
+ /**
2276
+ * xmlStreamPop:
2277
+ * @stream: the stream context
2278
+ *
2279
+ * push one level from the stream.
2280
+ *
2281
+ * Returns: -1 in case of error, 0 otherwise.
2282
+ */
2283
+ int
2284
+ xmlStreamPop(xmlStreamCtxtPtr stream) {
2285
+ int i, lev;
2286
+
2287
+ if (stream == NULL)
2288
+ return(-1);
2289
+ while (stream != NULL) {
2290
+ /*
2291
+ * Reset block-level.
2292
+ */
2293
+ if (stream->blockLevel == stream->level)
2294
+ stream->blockLevel = -1;
2295
+
2296
+ /*
2297
+ * stream->level can be zero when XML_FINAL_IS_ANY_NODE is set
2298
+ * (see the thread at
2299
+ * http://mail.gnome.org/archives/xslt/2008-July/msg00027.html)
2300
+ */
2301
+ if (stream->level)
2302
+ stream->level--;
2303
+ /*
2304
+ * Check evolution of existing states
2305
+ */
2306
+ for (i = stream->nbState -1; i >= 0; i--) {
2307
+ /* discard obsoleted states */
2308
+ lev = stream->states[(2 * i) + 1];
2309
+ if (lev > stream->level)
2310
+ stream->nbState--;
2311
+ if (lev <= stream->level)
2312
+ break;
2313
+ }
2314
+ stream = stream->next;
2315
+ }
2316
+ return(0);
2317
+ }
2318
+
2319
+ /**
2320
+ * xmlStreamWantsAnyNode:
2321
+ * @streamCtxt: the stream context
2322
+ *
2323
+ * Query if the streaming pattern additionally needs to be fed with
2324
+ * text-, cdata-section-, comment- and processing-instruction-nodes.
2325
+ * If the result is 0 then only element-nodes and attribute-nodes
2326
+ * need to be pushed.
2327
+ *
2328
+ * Returns: 1 in case of need of nodes of the above described types,
2329
+ * 0 otherwise. -1 on API errors.
2330
+ */
2331
+ int
2332
+ xmlStreamWantsAnyNode(xmlStreamCtxtPtr streamCtxt)
2333
+ {
2334
+ if (streamCtxt == NULL)
2335
+ return(-1);
2336
+ while (streamCtxt != NULL) {
2337
+ if (streamCtxt->comp->flags & XML_STREAM_FINAL_IS_ANY_NODE)
2338
+ return(1);
2339
+ streamCtxt = streamCtxt->next;
2340
+ }
2341
+ return(0);
2342
+ }
2343
+
2344
+ /************************************************************************
2345
+ * *
2346
+ * The public interfaces *
2347
+ * *
2348
+ ************************************************************************/
2349
+
2350
+ /**
2351
+ * xmlPatterncompile:
2352
+ * @pattern: the pattern to compile
2353
+ * @dict: an optional dictionary for interned strings
2354
+ * @flags: compilation flags, see xmlPatternFlags
2355
+ * @namespaces: the prefix definitions, array of [URI, prefix] or NULL
2356
+ *
2357
+ * Compile a pattern.
2358
+ *
2359
+ * Returns the compiled form of the pattern or NULL in case of error
2360
+ */
2361
+ xmlPatternPtr
2362
+ xmlPatterncompile(const xmlChar *pattern, xmlDict *dict, int flags,
2363
+ const xmlChar **namespaces) {
2364
+ xmlPatternPtr ret = NULL, cur;
2365
+ xmlPatParserContextPtr ctxt = NULL;
2366
+ const xmlChar *or, *start;
2367
+ xmlChar *tmp = NULL;
2368
+ int type = 0;
2369
+ int streamable = 1;
2370
+
2371
+ if (pattern == NULL)
2372
+ return(NULL);
2373
+
2374
+ start = pattern;
2375
+ or = start;
2376
+ while (*or != 0) {
2377
+ tmp = NULL;
2378
+ while ((*or != 0) && (*or != '|')) or++;
2379
+ if (*or == 0)
2380
+ ctxt = xmlNewPatParserContext(start, dict, namespaces);
2381
+ else {
2382
+ tmp = xmlStrndup(start, or - start);
2383
+ if (tmp != NULL) {
2384
+ ctxt = xmlNewPatParserContext(tmp, dict, namespaces);
2385
+ }
2386
+ or++;
2387
+ }
2388
+ if (ctxt == NULL) goto error;
2389
+ cur = xmlNewPattern();
2390
+ if (cur == NULL) goto error;
2391
+ /*
2392
+ * Assign string dict.
2393
+ */
2394
+ if (dict) {
2395
+ cur->dict = dict;
2396
+ xmlDictReference(dict);
2397
+ }
2398
+ if (ret == NULL)
2399
+ ret = cur;
2400
+ else {
2401
+ cur->next = ret->next;
2402
+ ret->next = cur;
2403
+ }
2404
+ cur->flags = flags;
2405
+ ctxt->comp = cur;
2406
+
2407
+ if (XML_STREAM_XS_IDC(cur))
2408
+ xmlCompileIDCXPathPath(ctxt);
2409
+ else
2410
+ xmlCompilePathPattern(ctxt);
2411
+ if (ctxt->error != 0)
2412
+ goto error;
2413
+ xmlFreePatParserContext(ctxt);
2414
+ ctxt = NULL;
2415
+
2416
+
2417
+ if (streamable) {
2418
+ if (type == 0) {
2419
+ type = cur->flags & (PAT_FROM_ROOT | PAT_FROM_CUR);
2420
+ } else if (type == PAT_FROM_ROOT) {
2421
+ if (cur->flags & PAT_FROM_CUR)
2422
+ streamable = 0;
2423
+ } else if (type == PAT_FROM_CUR) {
2424
+ if (cur->flags & PAT_FROM_ROOT)
2425
+ streamable = 0;
2426
+ }
2427
+ }
2428
+ if (streamable)
2429
+ xmlStreamCompile(cur);
2430
+ if (xmlReversePattern(cur) < 0)
2431
+ goto error;
2432
+ if (tmp != NULL) {
2433
+ xmlFree(tmp);
2434
+ tmp = NULL;
2435
+ }
2436
+ start = or;
2437
+ }
2438
+ if (streamable == 0) {
2439
+ cur = ret;
2440
+ while (cur != NULL) {
2441
+ if (cur->stream != NULL) {
2442
+ xmlFreeStreamComp(cur->stream);
2443
+ cur->stream = NULL;
2444
+ }
2445
+ cur = cur->next;
2446
+ }
2447
+ }
2448
+
2449
+ return(ret);
2450
+ error:
2451
+ if (ctxt != NULL) xmlFreePatParserContext(ctxt);
2452
+ if (ret != NULL) xmlFreePattern(ret);
2453
+ if (tmp != NULL) xmlFree(tmp);
2454
+ return(NULL);
2455
+ }
2456
+
2457
+ /**
2458
+ * xmlPatternMatch:
2459
+ * @comp: the precompiled pattern
2460
+ * @node: a node
2461
+ *
2462
+ * Test whether the node matches the pattern
2463
+ *
2464
+ * Returns 1 if it matches, 0 if it doesn't and -1 in case of failure
2465
+ */
2466
+ int
2467
+ xmlPatternMatch(xmlPatternPtr comp, xmlNodePtr node)
2468
+ {
2469
+ int ret = 0;
2470
+
2471
+ if ((comp == NULL) || (node == NULL))
2472
+ return(-1);
2473
+
2474
+ while (comp != NULL) {
2475
+ ret = xmlPatMatch(comp, node);
2476
+ if (ret != 0)
2477
+ return(ret);
2478
+ comp = comp->next;
2479
+ }
2480
+ return(ret);
2481
+ }
2482
+
2483
+ /**
2484
+ * xmlPatternGetStreamCtxt:
2485
+ * @comp: the precompiled pattern
2486
+ *
2487
+ * Get a streaming context for that pattern
2488
+ * Use xmlFreeStreamCtxt to free the context.
2489
+ *
2490
+ * Returns a pointer to the context or NULL in case of failure
2491
+ */
2492
+ xmlStreamCtxtPtr
2493
+ xmlPatternGetStreamCtxt(xmlPatternPtr comp)
2494
+ {
2495
+ xmlStreamCtxtPtr ret = NULL, cur;
2496
+
2497
+ if ((comp == NULL) || (comp->stream == NULL))
2498
+ return(NULL);
2499
+
2500
+ while (comp != NULL) {
2501
+ if (comp->stream == NULL)
2502
+ goto failed;
2503
+ cur = xmlNewStreamCtxt(comp->stream);
2504
+ if (cur == NULL)
2505
+ goto failed;
2506
+ if (ret == NULL)
2507
+ ret = cur;
2508
+ else {
2509
+ cur->next = ret->next;
2510
+ ret->next = cur;
2511
+ }
2512
+ cur->flags = comp->flags;
2513
+ comp = comp->next;
2514
+ }
2515
+ return(ret);
2516
+ failed:
2517
+ xmlFreeStreamCtxt(ret);
2518
+ return(NULL);
2519
+ }
2520
+
2521
+ /**
2522
+ * xmlPatternStreamable:
2523
+ * @comp: the precompiled pattern
2524
+ *
2525
+ * Check if the pattern is streamable i.e. xmlPatternGetStreamCtxt()
2526
+ * should work.
2527
+ *
2528
+ * Returns 1 if streamable, 0 if not and -1 in case of error.
2529
+ */
2530
+ int
2531
+ xmlPatternStreamable(xmlPatternPtr comp) {
2532
+ if (comp == NULL)
2533
+ return(-1);
2534
+ while (comp != NULL) {
2535
+ if (comp->stream == NULL)
2536
+ return(0);
2537
+ comp = comp->next;
2538
+ }
2539
+ return(1);
2540
+ }
2541
+
2542
+ /**
2543
+ * xmlPatternMaxDepth:
2544
+ * @comp: the precompiled pattern
2545
+ *
2546
+ * Check the maximum depth reachable by a pattern
2547
+ *
2548
+ * Returns -2 if no limit (using //), otherwise the depth,
2549
+ * and -1 in case of error
2550
+ */
2551
+ int
2552
+ xmlPatternMaxDepth(xmlPatternPtr comp) {
2553
+ int ret = 0, i;
2554
+ if (comp == NULL)
2555
+ return(-1);
2556
+ while (comp != NULL) {
2557
+ if (comp->stream == NULL)
2558
+ return(-1);
2559
+ for (i = 0;i < comp->stream->nbStep;i++)
2560
+ if (comp->stream->steps[i].flags & XML_STREAM_STEP_DESC)
2561
+ return(-2);
2562
+ if (comp->stream->nbStep > ret)
2563
+ ret = comp->stream->nbStep;
2564
+ comp = comp->next;
2565
+ }
2566
+ return(ret);
2567
+ }
2568
+
2569
+ /**
2570
+ * xmlPatternMinDepth:
2571
+ * @comp: the precompiled pattern
2572
+ *
2573
+ * Check the minimum depth reachable by a pattern, 0 mean the / or . are
2574
+ * part of the set.
2575
+ *
2576
+ * Returns -1 in case of error otherwise the depth,
2577
+ *
2578
+ */
2579
+ int
2580
+ xmlPatternMinDepth(xmlPatternPtr comp) {
2581
+ int ret = 12345678;
2582
+ if (comp == NULL)
2583
+ return(-1);
2584
+ while (comp != NULL) {
2585
+ if (comp->stream == NULL)
2586
+ return(-1);
2587
+ if (comp->stream->nbStep < ret)
2588
+ ret = comp->stream->nbStep;
2589
+ if (ret == 0)
2590
+ return(0);
2591
+ comp = comp->next;
2592
+ }
2593
+ return(ret);
2594
+ }
2595
+
2596
+ /**
2597
+ * xmlPatternFromRoot:
2598
+ * @comp: the precompiled pattern
2599
+ *
2600
+ * Check if the pattern must be looked at from the root.
2601
+ *
2602
+ * Returns 1 if true, 0 if false and -1 in case of error
2603
+ */
2604
+ int
2605
+ xmlPatternFromRoot(xmlPatternPtr comp) {
2606
+ if (comp == NULL)
2607
+ return(-1);
2608
+ while (comp != NULL) {
2609
+ if (comp->stream == NULL)
2610
+ return(-1);
2611
+ if (comp->flags & PAT_FROM_ROOT)
2612
+ return(1);
2613
+ comp = comp->next;
2614
+ }
2615
+ return(0);
2616
+
2617
+ }
2618
+
2619
+ #define bottom_pattern
2620
+ #include "elfgcchack.h"
2621
+ #endif /* LIBXML_PATTERN_ENABLED */