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