ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

pattern.c
Go to the documentation of this file.
00001 /*
00002  * pattern.c: Implemetation of selectors for nodes
00003  *
00004  * Reference:
00005  *   http://www.w3.org/TR/2001/REC-xmlschema-1-20010502/
00006  *   to some extent 
00007  *   http://www.w3.org/TR/1999/REC-xml-19991116
00008  *
00009  * See Copyright for the status of this software.
00010  *
00011  * daniel@veillard.com
00012  */
00013 
00014 /*
00015  * TODO:
00016  * - compilation flags to check for specific syntaxes
00017  *   using flags of xmlPatterncompile()
00018  * - making clear how pattern starting with / or . need to be handled,
00019  *   currently push(NULL, NULL) means a reset of the streaming context
00020  *   and indicating we are on / (the document node), probably need
00021  *   something similar for .
00022  * - get rid of the "compile" starting with lowercase
00023  * - DONE (2006-05-16): get rid of the Strdup/Strndup in case of dictionary
00024  */
00025 
00026 #define IN_LIBXML
00027 #include "libxml.h"
00028 
00029 #include <string.h>
00030 #include <libxml/xmlmemory.h>
00031 #include <libxml/tree.h>
00032 #include <libxml/hash.h>
00033 #include <libxml/dict.h>
00034 #include <libxml/xmlerror.h>
00035 #include <libxml/parserInternals.h>
00036 #include <libxml/pattern.h>
00037 
00038 #ifdef LIBXML_PATTERN_ENABLED
00039 
00040 /* #define DEBUG_STREAMING */
00041 
00042 #define ERROR(a, b, c, d)
00043 #define ERROR5(a, b, c, d, e)
00044 
00045 #define XML_STREAM_STEP_DESC    1
00046 #define XML_STREAM_STEP_FINAL   2
00047 #define XML_STREAM_STEP_ROOT    4
00048 #define XML_STREAM_STEP_ATTR    8
00049 #define XML_STREAM_STEP_NODE    16
00050 #define XML_STREAM_STEP_IN_SET  32
00051 
00052 /*
00053 * NOTE: Those private flags (XML_STREAM_xxx) are used
00054 *   in _xmlStreamCtxt->flag. They extend the public
00055 *   xmlPatternFlags, so be carefull not to interfere with the
00056 *   reserved values for xmlPatternFlags. 
00057 */
00058 #define XML_STREAM_FINAL_IS_ANY_NODE 1<<14
00059 #define XML_STREAM_FROM_ROOT 1<<15
00060 #define XML_STREAM_DESC 1<<16
00061 
00062 /*
00063 * XML_STREAM_ANY_NODE is used for comparison against
00064 * xmlElementType enums, to indicate a node of any type.
00065 */
00066 #define XML_STREAM_ANY_NODE 100
00067 
00068 #define XML_PATTERN_NOTPATTERN  (XML_PATTERN_XPATH | \
00069                  XML_PATTERN_XSSEL | \
00070                  XML_PATTERN_XSFIELD)
00071 
00072 #define XML_STREAM_XS_IDC(c) ((c)->flags & \
00073     (XML_PATTERN_XSSEL | XML_PATTERN_XSFIELD))
00074 
00075 #define XML_STREAM_XS_IDC_SEL(c) ((c)->flags & XML_PATTERN_XSSEL)
00076 
00077 #define XML_STREAM_XS_IDC_FIELD(c) ((c)->flags & XML_PATTERN_XSFIELD)
00078 
00079 #define XML_PAT_COPY_NSNAME(c, r, nsname) \
00080     if ((c)->comp->dict) \
00081     r = (xmlChar *) xmlDictLookup((c)->comp->dict, BAD_CAST nsname, -1); \
00082     else r = xmlStrdup(BAD_CAST nsname);
00083 
00084 #define XML_PAT_FREE_STRING(c, r) if ((c)->comp->dict == NULL) xmlFree(r);
00085 
00086 typedef struct _xmlStreamStep xmlStreamStep;
00087 typedef xmlStreamStep *xmlStreamStepPtr;
00088 struct _xmlStreamStep {
00089     int flags;          /* properties of that step */
00090     const xmlChar *name;    /* first string value if NULL accept all */
00091     const xmlChar *ns;      /* second string value */
00092     int nodeType;       /* type of node */
00093 };
00094 
00095 typedef struct _xmlStreamComp xmlStreamComp;
00096 typedef xmlStreamComp *xmlStreamCompPtr;
00097 struct _xmlStreamComp {
00098     xmlDict *dict;      /* the dictionary if any */
00099     int nbStep;         /* number of steps in the automata */
00100     int maxStep;        /* allocated number of steps */
00101     xmlStreamStepPtr steps; /* the array of steps */
00102     int flags;
00103 };
00104 
00105 struct _xmlStreamCtxt {
00106     struct _xmlStreamCtxt *next;/* link to next sub pattern if | */
00107     xmlStreamCompPtr comp;  /* the compiled stream */
00108     int nbState;        /* number of states in the automata */
00109     int maxState;       /* allocated number of states */
00110     int level;          /* how deep are we ? */
00111     int *states;        /* the array of step indexes */
00112     int flags;          /* validation options */
00113     int blockLevel;
00114 };
00115 
00116 static void xmlFreeStreamComp(xmlStreamCompPtr comp);
00117 
00118 /*
00119  * Types are private:
00120  */
00121 
00122 typedef enum {
00123     XML_OP_END=0,
00124     XML_OP_ROOT,
00125     XML_OP_ELEM,
00126     XML_OP_CHILD,
00127     XML_OP_ATTR,
00128     XML_OP_PARENT,
00129     XML_OP_ANCESTOR,
00130     XML_OP_NS,
00131     XML_OP_ALL
00132 } xmlPatOp;
00133 
00134 
00135 typedef struct _xmlStepState xmlStepState;
00136 typedef xmlStepState *xmlStepStatePtr;
00137 struct _xmlStepState {
00138     int step;
00139     xmlNodePtr node;
00140 };
00141 
00142 typedef struct _xmlStepStates xmlStepStates;
00143 typedef xmlStepStates *xmlStepStatesPtr;
00144 struct _xmlStepStates {
00145     int nbstates;
00146     int maxstates;
00147     xmlStepStatePtr states;
00148 };
00149 
00150 typedef struct _xmlStepOp xmlStepOp;
00151 typedef xmlStepOp *xmlStepOpPtr;
00152 struct _xmlStepOp {
00153     xmlPatOp op;
00154     const xmlChar *value;
00155     const xmlChar *value2; /* The namespace name */
00156 };
00157 
00158 #define PAT_FROM_ROOT   (1<<8)
00159 #define PAT_FROM_CUR    (1<<9)
00160 
00161 struct _xmlPattern {
00162     void *data;         /* the associated template */
00163     xmlDictPtr dict;        /* the optional dictionary */
00164     struct _xmlPattern *next;   /* next pattern if | is used */
00165     const xmlChar *pattern; /* the pattern */
00166     int flags;          /* flags */
00167     int nbStep;
00168     int maxStep;
00169     xmlStepOpPtr steps;        /* ops for computation */
00170     xmlStreamCompPtr stream;    /* the streaming data if any */
00171 };
00172 
00173 typedef struct _xmlPatParserContext xmlPatParserContext;
00174 typedef xmlPatParserContext *xmlPatParserContextPtr;
00175 struct _xmlPatParserContext {
00176     const xmlChar *cur;         /* the current char being parsed */
00177     const xmlChar *base;        /* the full expression */
00178     int            error;       /* error code */
00179     xmlDictPtr     dict;        /* the dictionary if any */
00180     xmlPatternPtr  comp;        /* the result */
00181     xmlNodePtr     elem;        /* the current node if any */    
00182     const xmlChar **namespaces;     /* the namespaces definitions */
00183     int   nb_namespaces;        /* the number of namespaces */
00184 };
00185 
00186 /************************************************************************
00187  *                                  *
00188  *          Type functions                  *
00189  *                                  *
00190  ************************************************************************/
00191 
00199 static xmlPatternPtr
00200 xmlNewPattern(void) {
00201     xmlPatternPtr cur;
00202 
00203     cur = (xmlPatternPtr) xmlMalloc(sizeof(xmlPattern));
00204     if (cur == NULL) {
00205     ERROR(NULL, NULL, NULL,
00206         "xmlNewPattern : malloc failed\n");
00207     return(NULL);
00208     }
00209     memset(cur, 0, sizeof(xmlPattern));
00210     cur->maxStep = 10;
00211     cur->steps = (xmlStepOpPtr) xmlMalloc(cur->maxStep * sizeof(xmlStepOp));
00212     if (cur->steps == NULL) {
00213         xmlFree(cur);
00214     ERROR(NULL, NULL, NULL,
00215         "xmlNewPattern : malloc failed\n");
00216     return(NULL);
00217     }
00218     return(cur);
00219 }
00220 
00227 void
00228 xmlFreePattern(xmlPatternPtr comp) {
00229     xmlStepOpPtr op;
00230     int i;
00231 
00232     if (comp == NULL)
00233     return;
00234     if (comp->next != NULL)
00235         xmlFreePattern(comp->next);
00236     if (comp->stream != NULL)
00237         xmlFreeStreamComp(comp->stream);
00238     if (comp->pattern != NULL)
00239     xmlFree((xmlChar *)comp->pattern);
00240     if (comp->steps != NULL) {
00241         if (comp->dict == NULL) {
00242         for (i = 0;i < comp->nbStep;i++) {
00243         op = &comp->steps[i];
00244         if (op->value != NULL)
00245             xmlFree((xmlChar *) op->value);
00246         if (op->value2 != NULL)
00247             xmlFree((xmlChar *) op->value2);
00248         }
00249     }
00250     xmlFree(comp->steps);
00251     }
00252     if (comp->dict != NULL)
00253         xmlDictFree(comp->dict);
00254 
00255     memset(comp, -1, sizeof(xmlPattern));
00256     xmlFree(comp);
00257 }
00258 
00265 void
00266 xmlFreePatternList(xmlPatternPtr comp) {
00267     xmlPatternPtr cur;
00268 
00269     while (comp != NULL) {
00270     cur = comp;
00271     comp = comp->next;
00272     cur->next = NULL;
00273     xmlFreePattern(cur);
00274     }
00275 }
00276 
00288 static xmlPatParserContextPtr
00289 xmlNewPatParserContext(const xmlChar *pattern, xmlDictPtr dict,
00290                        const xmlChar **namespaces) {
00291     xmlPatParserContextPtr cur;
00292 
00293     if (pattern == NULL)
00294         return(NULL);
00295 
00296     cur = (xmlPatParserContextPtr) xmlMalloc(sizeof(xmlPatParserContext));
00297     if (cur == NULL) {
00298     ERROR(NULL, NULL, NULL,
00299         "xmlNewPatParserContext : malloc failed\n");
00300     return(NULL);
00301     }
00302     memset(cur, 0, sizeof(xmlPatParserContext));
00303     cur->dict = dict;
00304     cur->cur = pattern;
00305     cur->base = pattern;
00306     if (namespaces != NULL) {
00307         int i;
00308     for (i = 0;namespaces[2 * i] != NULL;i++);
00309         cur->nb_namespaces = i;
00310     } else {
00311         cur->nb_namespaces = 0;
00312     }
00313     cur->namespaces = namespaces;
00314     return(cur);
00315 }
00316 
00323 static void
00324 xmlFreePatParserContext(xmlPatParserContextPtr ctxt) {
00325     if (ctxt == NULL)
00326     return;    
00327     memset(ctxt, -1, sizeof(xmlPatParserContext));
00328     xmlFree(ctxt);
00329 }
00330 
00342 static int
00343 xmlPatternAdd(xmlPatParserContextPtr ctxt ATTRIBUTE_UNUSED,
00344                 xmlPatternPtr comp,
00345                 xmlPatOp op, xmlChar * value, xmlChar * value2)
00346 {
00347     if (comp->nbStep >= comp->maxStep) {
00348         xmlStepOpPtr temp;
00349     temp = (xmlStepOpPtr) xmlRealloc(comp->steps, comp->maxStep * 2 *
00350                                      sizeof(xmlStepOp));
00351         if (temp == NULL) {
00352         ERROR(ctxt, NULL, NULL,
00353                  "xmlPatternAdd: realloc failed\n");
00354         return (-1);
00355     }
00356     comp->steps = temp;
00357     comp->maxStep *= 2;
00358     }
00359     comp->steps[comp->nbStep].op = op;
00360     comp->steps[comp->nbStep].value = value;
00361     comp->steps[comp->nbStep].value2 = value2;
00362     comp->nbStep++;
00363     return (0);
00364 }
00365 
00366 #if 0
00367 
00373 static void
00374 xsltSwapTopPattern(xmlPatternPtr comp) {
00375     int i;
00376     int j = comp->nbStep - 1;
00377 
00378     if (j > 0) {
00379     register const xmlChar *tmp;
00380     register xmlPatOp op;
00381     i = j - 1;
00382     tmp = comp->steps[i].value;
00383     comp->steps[i].value = comp->steps[j].value;
00384     comp->steps[j].value = tmp;
00385     tmp = comp->steps[i].value2;
00386     comp->steps[i].value2 = comp->steps[j].value2;
00387     comp->steps[j].value2 = tmp;
00388     op = comp->steps[i].op;
00389     comp->steps[i].op = comp->steps[j].op;
00390     comp->steps[j].op = op;
00391     }
00392 }
00393 #endif
00394 
00403 static int
00404 xmlReversePattern(xmlPatternPtr comp) {
00405     int i, j;
00406 
00407     /*
00408      * remove the leading // for //a or .//a
00409      */
00410     if ((comp->nbStep > 0) && (comp->steps[0].op == XML_OP_ANCESTOR)) {
00411         for (i = 0, j = 1;j < comp->nbStep;i++,j++) {
00412         comp->steps[i].value = comp->steps[j].value;
00413         comp->steps[i].value2 = comp->steps[j].value2;
00414         comp->steps[i].op = comp->steps[j].op;
00415     }
00416     comp->nbStep--;
00417     }
00418     if (comp->nbStep >= comp->maxStep) {
00419         xmlStepOpPtr temp;
00420     temp = (xmlStepOpPtr) xmlRealloc(comp->steps, comp->maxStep * 2 *
00421                                      sizeof(xmlStepOp));
00422         if (temp == NULL) {
00423         ERROR(ctxt, NULL, NULL,
00424                  "xmlReversePattern: realloc failed\n");
00425         return (-1);
00426     }
00427     comp->steps = temp;
00428     comp->maxStep *= 2;
00429     }
00430     i = 0;
00431     j = comp->nbStep - 1;
00432     while (j > i) {
00433     register const xmlChar *tmp;
00434     register xmlPatOp op;
00435     tmp = comp->steps[i].value;
00436     comp->steps[i].value = comp->steps[j].value;
00437     comp->steps[j].value = tmp;
00438     tmp = comp->steps[i].value2;
00439     comp->steps[i].value2 = comp->steps[j].value2;
00440     comp->steps[j].value2 = tmp;
00441     op = comp->steps[i].op;
00442     comp->steps[i].op = comp->steps[j].op;
00443     comp->steps[j].op = op;
00444     j--;
00445     i++;
00446     }
00447     comp->steps[comp->nbStep].value = NULL;
00448     comp->steps[comp->nbStep].value2 = NULL;
00449     comp->steps[comp->nbStep++].op = XML_OP_END;
00450     return(0);
00451 }
00452 
00453 /************************************************************************
00454  *                                  *
00455  *      The interpreter for the precompiled patterns        *
00456  *                                  *
00457  ************************************************************************/
00458 
00459 static int
00460 xmlPatPushState(xmlStepStates *states, int step, xmlNodePtr node) {
00461     if ((states->states == NULL) || (states->maxstates <= 0)) {
00462         states->maxstates = 4;
00463     states->nbstates = 0;
00464     states->states = xmlMalloc(4 * sizeof(xmlStepState));
00465     }
00466     else if (states->maxstates <= states->nbstates) {
00467         xmlStepState *tmp;
00468 
00469     tmp = (xmlStepStatePtr) xmlRealloc(states->states,
00470                    2 * states->maxstates * sizeof(xmlStepState));
00471     if (tmp == NULL)
00472         return(-1);
00473     states->states = tmp;
00474     states->maxstates *= 2;
00475     }
00476     states->states[states->nbstates].step = step;
00477     states->states[states->nbstates++].node = node;
00478 #if 0
00479     fprintf(stderr, "Push: %d, %s\n", step, node->name);
00480 #endif
00481     return(0);
00482 }
00483 
00493 static int
00494 xmlPatMatch(xmlPatternPtr comp, xmlNodePtr node) {
00495     int i;
00496     xmlStepOpPtr step;
00497     xmlStepStates states = {0, 0, NULL}; /* // may require backtrack */
00498 
00499     if ((comp == NULL) || (node == NULL)) return(-1);
00500     i = 0;
00501 restart:
00502     for (;i < comp->nbStep;i++) {
00503     step = &comp->steps[i];
00504     switch (step->op) {
00505             case XML_OP_END:
00506         goto found;
00507             case XML_OP_ROOT:
00508         if (node->type == XML_NAMESPACE_DECL)
00509             goto rollback;
00510         node = node->parent;
00511         if ((node->type == XML_DOCUMENT_NODE) ||
00512 #ifdef LIBXML_DOCB_ENABLED
00513             (node->type == XML_DOCB_DOCUMENT_NODE) ||
00514 #endif
00515             (node->type == XML_HTML_DOCUMENT_NODE))
00516             continue;
00517         goto rollback;
00518             case XML_OP_ELEM:
00519         if (node->type != XML_ELEMENT_NODE)
00520             goto rollback;
00521         if (step->value == NULL)
00522             continue;
00523         if (step->value[0] != node->name[0])
00524             goto rollback;
00525         if (!xmlStrEqual(step->value, node->name))
00526             goto rollback;
00527 
00528         /* Namespace test */
00529         if (node->ns == NULL) {
00530             if (step->value2 != NULL)
00531             goto rollback;
00532         } else if (node->ns->href != NULL) {
00533             if (step->value2 == NULL)
00534             goto rollback;
00535             if (!xmlStrEqual(step->value2, node->ns->href))
00536             goto rollback;
00537         }
00538         continue;
00539             case XML_OP_CHILD: {
00540         xmlNodePtr lst;
00541 
00542         if ((node->type != XML_ELEMENT_NODE) &&
00543             (node->type != XML_DOCUMENT_NODE) &&
00544 #ifdef LIBXML_DOCB_ENABLED
00545             (node->type != XML_DOCB_DOCUMENT_NODE) &&
00546 #endif
00547             (node->type != XML_HTML_DOCUMENT_NODE))
00548             goto rollback;
00549 
00550         lst = node->children;
00551 
00552         if (step->value != NULL) {
00553             while (lst != NULL) {
00554             if ((lst->type == XML_ELEMENT_NODE) &&
00555                 (step->value[0] == lst->name[0]) &&
00556                 (xmlStrEqual(step->value, lst->name)))
00557                 break;
00558             lst = lst->next;
00559             }
00560             if (lst != NULL)
00561             continue;
00562         }
00563         goto rollback;
00564         }
00565             case XML_OP_ATTR:
00566         if (node->type != XML_ATTRIBUTE_NODE)
00567             goto rollback;
00568         if (step->value != NULL) {
00569             if (step->value[0] != node->name[0])
00570             goto rollback;
00571             if (!xmlStrEqual(step->value, node->name))
00572             goto rollback;
00573         }
00574         /* Namespace test */
00575         if (node->ns == NULL) {
00576             if (step->value2 != NULL)
00577             goto rollback;
00578         } else if (step->value2 != NULL) {
00579             if (!xmlStrEqual(step->value2, node->ns->href))
00580             goto rollback;
00581         }
00582         continue;
00583             case XML_OP_PARENT:
00584         if ((node->type == XML_DOCUMENT_NODE) ||
00585             (node->type == XML_HTML_DOCUMENT_NODE) ||
00586 #ifdef LIBXML_DOCB_ENABLED
00587             (node->type == XML_DOCB_DOCUMENT_NODE) ||
00588 #endif
00589             (node->type == XML_NAMESPACE_DECL))
00590             goto rollback;
00591         node = node->parent;
00592         if (node == NULL)
00593             goto rollback;
00594         if (step->value == NULL)
00595             continue;
00596         if (step->value[0] != node->name[0])
00597             goto rollback;
00598         if (!xmlStrEqual(step->value, node->name))
00599             goto rollback;
00600         /* Namespace test */
00601         if (node->ns == NULL) {
00602             if (step->value2 != NULL)
00603             goto rollback;
00604         } else if (node->ns->href != NULL) {
00605             if (step->value2 == NULL)
00606             goto rollback;
00607             if (!xmlStrEqual(step->value2, node->ns->href))
00608             goto rollback;
00609         }
00610         continue;
00611             case XML_OP_ANCESTOR:
00612         /* TODO: implement coalescing of ANCESTOR/NODE ops */
00613         if (step->value == NULL) {
00614             i++;
00615             step = &comp->steps[i];
00616             if (step->op == XML_OP_ROOT)
00617             goto found;
00618             if (step->op != XML_OP_ELEM)
00619             goto rollback;
00620             if (step->value == NULL)
00621             return(-1);
00622         }
00623         if (node == NULL)
00624             goto rollback;
00625         if ((node->type == XML_DOCUMENT_NODE) ||
00626             (node->type == XML_HTML_DOCUMENT_NODE) ||
00627 #ifdef LIBXML_DOCB_ENABLED
00628             (node->type == XML_DOCB_DOCUMENT_NODE) ||
00629 #endif
00630             (node->type == XML_NAMESPACE_DECL))
00631             goto rollback;
00632         node = node->parent;
00633         while (node != NULL) {
00634             if ((node->type == XML_ELEMENT_NODE) &&
00635             (step->value[0] == node->name[0]) &&
00636             (xmlStrEqual(step->value, node->name))) {
00637             /* Namespace test */
00638             if (node->ns == NULL) {
00639                 if (step->value2 == NULL)
00640                 break;
00641             } else if (node->ns->href != NULL) {
00642                 if ((step->value2 != NULL) &&
00643                     (xmlStrEqual(step->value2, node->ns->href)))
00644                 break;
00645             }
00646             }
00647             node = node->parent;
00648         }
00649         if (node == NULL)
00650             goto rollback;
00651         /*
00652          * prepare a potential rollback from here
00653          * for ancestors of that node.
00654          */
00655         if (step->op == XML_OP_ANCESTOR)
00656             xmlPatPushState(&states, i, node);
00657         else
00658             xmlPatPushState(&states, i - 1, node);
00659         continue;
00660             case XML_OP_NS:
00661         if (node->type != XML_ELEMENT_NODE)
00662             goto rollback;
00663         if (node->ns == NULL) {
00664             if (step->value != NULL)
00665             goto rollback;
00666         } else if (node->ns->href != NULL) {
00667             if (step->value == NULL)
00668             goto rollback;
00669             if (!xmlStrEqual(step->value, node->ns->href))
00670             goto rollback;
00671         }
00672         break;
00673             case XML_OP_ALL:
00674         if (node->type != XML_ELEMENT_NODE)
00675             goto rollback;
00676         break;
00677     }
00678     }
00679 found:
00680     if (states.states != NULL) {
00681         /* Free the rollback states */
00682     xmlFree(states.states);
00683     }
00684     return(1);
00685 rollback:
00686     /* got an error try to rollback */
00687     if (states.states == NULL)
00688     return(0);
00689     if (states.nbstates <= 0) {
00690     xmlFree(states.states);
00691     return(0);
00692     }
00693     states.nbstates--;
00694     i = states.states[states.nbstates].step;
00695     node = states.states[states.nbstates].node;
00696 #if 0
00697     fprintf(stderr, "Pop: %d, %s\n", i, node->name);
00698 #endif
00699     goto restart;
00700 }
00701 
00702 /************************************************************************
00703  *                                  *
00704  *          Dedicated parser for templates          *
00705  *                                  *
00706  ************************************************************************/
00707 
00708 #define TODO                                \
00709     xmlGenericError(xmlGenericErrorContext,             \
00710         "Unimplemented block at %s:%d\n",               \
00711             __FILE__, __LINE__);
00712 #define CUR (*ctxt->cur)
00713 #define SKIP(val) ctxt->cur += (val)
00714 #define NXT(val) ctxt->cur[(val)]
00715 #define PEEKPREV(val) ctxt->cur[-(val)]
00716 #define CUR_PTR ctxt->cur
00717 
00718 #define SKIP_BLANKS                             \
00719     while (IS_BLANK_CH(CUR)) NEXT
00720 
00721 #define CURRENT (*ctxt->cur)
00722 #define NEXT ((*ctxt->cur) ?  ctxt->cur++: ctxt->cur)
00723 
00724 
00725 #define PUSH(op, val, val2)                         \
00726     if (xmlPatternAdd(ctxt, ctxt->comp, (op), (val), (val2))) goto error;
00727 
00728 #define XSLT_ERROR(X)                           \
00729     { xsltError(ctxt, __FILE__, __LINE__, X);               \
00730       ctxt->error = (X); return; }
00731 
00732 #define XSLT_ERROR0(X)                          \
00733     { xsltError(ctxt, __FILE__, __LINE__, X);               \
00734       ctxt->error = (X); return(0); }
00735 
00736 #if 0
00737 
00749 static xmlChar *
00750 xmlPatScanLiteral(xmlPatParserContextPtr ctxt) {
00751     const xmlChar *q, *cur;
00752     xmlChar *ret = NULL;
00753     int val, len;
00754 
00755     SKIP_BLANKS;
00756     if (CUR == '"') {
00757         NEXT;
00758     cur = q = CUR_PTR;
00759     val = xmlStringCurrentChar(NULL, cur, &len);
00760     while ((IS_CHAR(val)) && (val != '"')) {
00761         cur += len;
00762         val = xmlStringCurrentChar(NULL, cur, &len);
00763     }
00764     if (!IS_CHAR(val)) {
00765         ctxt->error = 1;
00766         return(NULL);
00767     } else {
00768         if (ctxt->dict)
00769         ret = (xmlChar *) xmlDictLookup(ctxt->dict, q, cur - q);
00770         else
00771         ret = xmlStrndup(q, cur - q);       
00772         }
00773     cur += len;
00774     CUR_PTR = cur;
00775     } else if (CUR == '\'') {
00776         NEXT;
00777     cur = q = CUR_PTR;
00778     val = xmlStringCurrentChar(NULL, cur, &len);
00779     while ((IS_CHAR(val)) && (val != '\'')) {
00780         cur += len;
00781         val = xmlStringCurrentChar(NULL, cur, &len);
00782     }
00783     if (!IS_CHAR(val)) {
00784         ctxt->error = 1;
00785         return(NULL);
00786     } else {
00787         if (ctxt->dict)
00788         ret = (xmlChar *) xmlDictLookup(ctxt->dict, q, cur - q);
00789         else
00790         ret = xmlStrndup(q, cur - q);       
00791         }
00792     cur += len;
00793     CUR_PTR = cur;
00794     } else {
00795     /* XP_ERROR(XPATH_START_LITERAL_ERROR); */
00796     ctxt->error = 1;
00797     return(NULL);
00798     }
00799     return(ret);
00800 }
00801 #endif
00802 
00817 static xmlChar *
00818 xmlPatScanName(xmlPatParserContextPtr ctxt) {
00819     const xmlChar *q, *cur;
00820     xmlChar *ret = NULL;
00821     int val, len;
00822 
00823     SKIP_BLANKS;
00824 
00825     cur = q = CUR_PTR;
00826     val = xmlStringCurrentChar(NULL, cur, &len);
00827     if (!IS_LETTER(val) && (val != '_') && (val != ':'))
00828     return(NULL);
00829 
00830     while ((IS_LETTER(val)) || (IS_DIGIT(val)) ||
00831            (val == '.') || (val == '-') ||
00832        (val == '_') || 
00833        (IS_COMBINING(val)) ||
00834        (IS_EXTENDER(val))) {
00835     cur += len;
00836     val = xmlStringCurrentChar(NULL, cur, &len);
00837     }
00838     if (ctxt->dict)
00839     ret = (xmlChar *) xmlDictLookup(ctxt->dict, q, cur - q);
00840     else
00841     ret = xmlStrndup(q, cur - q);    
00842     CUR_PTR = cur;
00843     return(ret);
00844 }
00845 
00855 static xmlChar *
00856 xmlPatScanNCName(xmlPatParserContextPtr ctxt) {
00857     const xmlChar *q, *cur;
00858     xmlChar *ret = NULL;
00859     int val, len;
00860 
00861     SKIP_BLANKS;
00862 
00863     cur = q = CUR_PTR;
00864     val = xmlStringCurrentChar(NULL, cur, &len);
00865     if (!IS_LETTER(val) && (val != '_'))
00866     return(NULL);
00867 
00868     while ((IS_LETTER(val)) || (IS_DIGIT(val)) ||
00869            (val == '.') || (val == '-') ||
00870        (val == '_') ||
00871        (IS_COMBINING(val)) ||
00872        (IS_EXTENDER(val))) {
00873     cur += len;
00874     val = xmlStringCurrentChar(NULL, cur, &len);
00875     }
00876     if (ctxt->dict)
00877     ret = (xmlChar *) xmlDictLookup(ctxt->dict, q, cur - q);
00878     else
00879     ret = xmlStrndup(q, cur - q);
00880     CUR_PTR = cur;
00881     return(ret);
00882 }
00883 
00884 #if 0
00885 
00895 static xmlChar *
00896 xmlPatScanQName(xmlPatParserContextPtr ctxt, xmlChar **prefix) {
00897     xmlChar *ret = NULL;
00898 
00899     *prefix = NULL;
00900     ret = xmlPatScanNCName(ctxt);
00901     if (CUR == ':') {
00902         *prefix = ret;
00903     NEXT;
00904     ret = xmlPatScanNCName(ctxt);
00905     }
00906     return(ret);
00907 }
00908 #endif
00909 
00916 static void
00917 xmlCompileAttributeTest(xmlPatParserContextPtr ctxt) {
00918     xmlChar *token = NULL;
00919     xmlChar *name = NULL;
00920     xmlChar *URL = NULL;
00921     
00922     SKIP_BLANKS;
00923     name = xmlPatScanNCName(ctxt);
00924     if (name == NULL) {
00925     if (CUR == '*') {
00926         PUSH(XML_OP_ATTR, NULL, NULL);
00927         NEXT;
00928     } else {
00929         ERROR(NULL, NULL, NULL,
00930         "xmlCompileAttributeTest : Name expected\n");
00931         ctxt->error = 1;
00932     }
00933     return;
00934     }
00935     if (CUR == ':') {
00936     int i;
00937     xmlChar *prefix = name;
00938     
00939     NEXT;
00940 
00941     if (IS_BLANK_CH(CUR)) {     
00942         ERROR5(NULL, NULL, NULL, "Invalid QName.\n", NULL);
00943         XML_PAT_FREE_STRING(ctxt, prefix);
00944         ctxt->error = 1;
00945         goto error;
00946     }
00947     /*
00948     * This is a namespace match
00949     */
00950     token = xmlPatScanName(ctxt);
00951     if ((prefix[0] == 'x') &&
00952         (prefix[1] == 'm') &&
00953         (prefix[2] == 'l') &&
00954         (prefix[3] == 0))
00955     {
00956         XML_PAT_COPY_NSNAME(ctxt, URL, XML_XML_NAMESPACE);      
00957     } else {
00958         for (i = 0;i < ctxt->nb_namespaces;i++) {
00959         if (xmlStrEqual(ctxt->namespaces[2 * i + 1], prefix)) {
00960             XML_PAT_COPY_NSNAME(ctxt, URL, ctxt->namespaces[2 * i])         
00961             break;
00962         }
00963         }
00964         if (i >= ctxt->nb_namespaces) {
00965         ERROR5(NULL, NULL, NULL,
00966             "xmlCompileAttributeTest : no namespace bound to prefix %s\n",
00967             prefix);
00968         ctxt->error = 1;        
00969         goto error;
00970         }
00971     }
00972     XML_PAT_FREE_STRING(ctxt, prefix);
00973     if (token == NULL) {
00974         if (CUR == '*') {
00975         NEXT;
00976         PUSH(XML_OP_ATTR, NULL, URL);
00977         } else {
00978         ERROR(NULL, NULL, NULL,
00979             "xmlCompileAttributeTest : Name expected\n");
00980         ctxt->error = 1;
00981         goto error;
00982         }       
00983     } else {
00984         PUSH(XML_OP_ATTR, token, URL);
00985     }
00986     } else {
00987     PUSH(XML_OP_ATTR, name, NULL);
00988     }
00989     return;
00990 error:
00991     if (URL != NULL)
00992     XML_PAT_FREE_STRING(ctxt, URL)  
00993     if (token != NULL)
00994     XML_PAT_FREE_STRING(ctxt, token);
00995 }
00996 
01008 static void
01009 xmlCompileStepPattern(xmlPatParserContextPtr ctxt) {
01010     xmlChar *token = NULL;
01011     xmlChar *name = NULL;
01012     xmlChar *URL = NULL;
01013     int hasBlanks = 0;
01014 
01015     SKIP_BLANKS;
01016     if (CUR == '.') {
01017     /*
01018     * Context node.
01019     */
01020     NEXT;
01021     PUSH(XML_OP_ELEM, NULL, NULL);
01022     return;
01023     }
01024     if (CUR == '@') {
01025     /*
01026     * Attribute test.
01027     */
01028     if (XML_STREAM_XS_IDC_SEL(ctxt->comp)) {
01029         ERROR5(NULL, NULL, NULL,
01030         "Unexpected attribute axis in '%s'.\n", ctxt->base);
01031         ctxt->error = 1;
01032         return;
01033     }
01034     NEXT;
01035     xmlCompileAttributeTest(ctxt);
01036     if (ctxt->error != 0) 
01037         goto error;
01038     return;
01039     }
01040     name = xmlPatScanNCName(ctxt);
01041     if (name == NULL) {
01042     if (CUR == '*') {
01043         NEXT;
01044         PUSH(XML_OP_ALL, NULL, NULL);
01045         return;
01046     } else {
01047         ERROR(NULL, NULL, NULL,
01048             "xmlCompileStepPattern : Name expected\n");
01049         ctxt->error = 1;
01050         return;
01051     }
01052     }
01053     if (IS_BLANK_CH(CUR)) {
01054     hasBlanks = 1;
01055     SKIP_BLANKS;
01056     }
01057     if (CUR == ':') {
01058     NEXT;
01059     if (CUR != ':') {
01060         xmlChar *prefix = name;
01061         int i;      
01062 
01063         if (hasBlanks || IS_BLANK_CH(CUR)) {
01064         ERROR5(NULL, NULL, NULL, "Invalid QName.\n", NULL);
01065         ctxt->error = 1;
01066         goto error;
01067         }
01068         /*
01069          * This is a namespace match
01070          */
01071         token = xmlPatScanName(ctxt);
01072         if ((prefix[0] == 'x') &&
01073         (prefix[1] == 'm') &&
01074         (prefix[2] == 'l') &&
01075         (prefix[3] == 0))
01076         {
01077         XML_PAT_COPY_NSNAME(ctxt, URL, XML_XML_NAMESPACE)
01078         } else {
01079         for (i = 0;i < ctxt->nb_namespaces;i++) {
01080             if (xmlStrEqual(ctxt->namespaces[2 * i + 1], prefix)) {
01081             XML_PAT_COPY_NSNAME(ctxt, URL, ctxt->namespaces[2 * i])
01082             break;
01083             }
01084         }
01085         if (i >= ctxt->nb_namespaces) {
01086             ERROR5(NULL, NULL, NULL,
01087             "xmlCompileStepPattern : no namespace bound to prefix %s\n",
01088             prefix);
01089             ctxt->error = 1;
01090             goto error;
01091         }
01092         }
01093         XML_PAT_FREE_STRING(ctxt, prefix);
01094         name = NULL;
01095         if (token == NULL) {
01096         if (CUR == '*') {
01097             NEXT;
01098             PUSH(XML_OP_NS, URL, NULL);
01099         } else {
01100             ERROR(NULL, NULL, NULL,
01101                 "xmlCompileStepPattern : Name expected\n");
01102             ctxt->error = 1;
01103             goto error;
01104         }
01105         } else {
01106         PUSH(XML_OP_ELEM, token, URL);
01107         }
01108     } else {
01109         NEXT;
01110         if (xmlStrEqual(name, (const xmlChar *) "child")) {     
01111         XML_PAT_FREE_STRING(ctxt, name);
01112         name = xmlPatScanName(ctxt);
01113         if (name == NULL) {
01114             if (CUR == '*') {
01115             NEXT;
01116             PUSH(XML_OP_ALL, NULL, NULL);
01117             return;
01118             } else {
01119             ERROR(NULL, NULL, NULL,
01120                 "xmlCompileStepPattern : QName expected\n");
01121             ctxt->error = 1;
01122             goto error;
01123             }
01124         }
01125         if (CUR == ':') {
01126             xmlChar *prefix = name;
01127             int i;
01128             
01129             NEXT;
01130             if (IS_BLANK_CH(CUR)) {
01131             ERROR5(NULL, NULL, NULL, "Invalid QName.\n", NULL);
01132             ctxt->error = 1;
01133             goto error;
01134             }
01135             /*
01136             * This is a namespace match
01137             */
01138             token = xmlPatScanName(ctxt);
01139             if ((prefix[0] == 'x') &&
01140             (prefix[1] == 'm') &&
01141             (prefix[2] == 'l') &&
01142             (prefix[3] == 0))
01143             {
01144             XML_PAT_COPY_NSNAME(ctxt, URL, XML_XML_NAMESPACE)           
01145             } else {
01146             for (i = 0;i < ctxt->nb_namespaces;i++) {
01147                 if (xmlStrEqual(ctxt->namespaces[2 * i + 1], prefix)) {
01148                 XML_PAT_COPY_NSNAME(ctxt, URL, ctxt->namespaces[2 * i])             
01149                 break;
01150                 }
01151             }
01152             if (i >= ctxt->nb_namespaces) {
01153                 ERROR5(NULL, NULL, NULL,
01154                 "xmlCompileStepPattern : no namespace bound "
01155                 "to prefix %s\n", prefix);
01156                 ctxt->error = 1;
01157                 goto error;
01158             }
01159             }
01160             XML_PAT_FREE_STRING(ctxt, prefix);
01161             name = NULL;
01162             if (token == NULL) {
01163             if (CUR == '*') {
01164                 NEXT;
01165                 PUSH(XML_OP_NS, URL, NULL);
01166             } else {
01167                 ERROR(NULL, NULL, NULL,
01168                 "xmlCompileStepPattern : Name expected\n");
01169                 ctxt->error = 1;
01170                 goto error;
01171             }
01172             } else {
01173             PUSH(XML_OP_CHILD, token, URL);
01174             }
01175         } else
01176             PUSH(XML_OP_CHILD, name, NULL);
01177         return;
01178         } else if (xmlStrEqual(name, (const xmlChar *) "attribute")) {
01179         XML_PAT_FREE_STRING(ctxt, name)
01180         name = NULL;
01181         if (XML_STREAM_XS_IDC_SEL(ctxt->comp)) {
01182             ERROR5(NULL, NULL, NULL,
01183             "Unexpected attribute axis in '%s'.\n", ctxt->base);
01184             ctxt->error = 1;
01185             goto error;
01186         }
01187         xmlCompileAttributeTest(ctxt);
01188         if (ctxt->error != 0)
01189             goto error;
01190         return;
01191         } else {
01192         ERROR5(NULL, NULL, NULL,
01193             "The 'element' or 'attribute' axis is expected.\n", NULL);
01194         ctxt->error = 1;
01195         goto error;
01196         }       
01197     }
01198     } else if (CUR == '*') {
01199         if (name != NULL) {
01200         ctxt->error = 1;
01201         goto error;
01202     }
01203     NEXT;
01204     PUSH(XML_OP_ALL, token, NULL);
01205     } else {
01206     PUSH(XML_OP_ELEM, name, NULL);
01207     }
01208     return;
01209 error:
01210     if (URL != NULL)
01211     XML_PAT_FREE_STRING(ctxt, URL)  
01212     if (token != NULL)
01213     XML_PAT_FREE_STRING(ctxt, token)
01214     if (name != NULL)
01215     XML_PAT_FREE_STRING(ctxt, name)
01216 }
01217 
01227 static void
01228 xmlCompilePathPattern(xmlPatParserContextPtr ctxt) {
01229     SKIP_BLANKS;
01230     if (CUR == '/') {
01231         ctxt->comp->flags |= PAT_FROM_ROOT;
01232     } else if ((CUR == '.') || (ctxt->comp->flags & XML_PATTERN_NOTPATTERN)) {
01233         ctxt->comp->flags |= PAT_FROM_CUR;
01234     }
01235     
01236     if ((CUR == '/') && (NXT(1) == '/')) {
01237     PUSH(XML_OP_ANCESTOR, NULL, NULL);
01238     NEXT;
01239     NEXT;
01240     } else if ((CUR == '.') && (NXT(1) == '/') && (NXT(2) == '/')) {
01241     PUSH(XML_OP_ANCESTOR, NULL, NULL);
01242     NEXT;
01243     NEXT;
01244     NEXT;
01245     /* Check for incompleteness. */
01246     SKIP_BLANKS;
01247     if (CUR == 0) {
01248         ERROR5(NULL, NULL, NULL,
01249            "Incomplete expression '%s'.\n", ctxt->base);
01250         ctxt->error = 1;
01251         goto error;
01252     }
01253     }
01254     if (CUR == '@') {
01255     NEXT;
01256     xmlCompileAttributeTest(ctxt);
01257     SKIP_BLANKS;
01258     /* TODO: check for incompleteness */
01259     if (CUR != 0) {
01260         xmlCompileStepPattern(ctxt);
01261         if (ctxt->error != 0)
01262         goto error;
01263     }
01264     } else {
01265         if (CUR == '/') {
01266         PUSH(XML_OP_ROOT, NULL, NULL);
01267         NEXT;
01268         /* Check for incompleteness. */
01269         SKIP_BLANKS;
01270         if (CUR == 0) {
01271         ERROR5(NULL, NULL, NULL,
01272             "Incomplete expression '%s'.\n", ctxt->base);
01273         ctxt->error = 1;
01274         goto error;
01275         }
01276     }
01277     xmlCompileStepPattern(ctxt);
01278     if (ctxt->error != 0)
01279         goto error;
01280     SKIP_BLANKS;
01281     while (CUR == '/') {
01282         if (NXT(1) == '/') {
01283             PUSH(XML_OP_ANCESTOR, NULL, NULL);
01284         NEXT;
01285         NEXT;
01286         SKIP_BLANKS;
01287         xmlCompileStepPattern(ctxt);
01288         if (ctxt->error != 0)
01289             goto error;
01290         } else {
01291             PUSH(XML_OP_PARENT, NULL, NULL);
01292         NEXT;
01293         SKIP_BLANKS;
01294         if (CUR == 0) {
01295             ERROR5(NULL, NULL, NULL,
01296             "Incomplete expression '%s'.\n", ctxt->base);
01297             ctxt->error = 1;
01298             goto error;         
01299         }
01300         xmlCompileStepPattern(ctxt);
01301         if (ctxt->error != 0)
01302             goto error;
01303         }
01304     }
01305     }
01306     if (CUR != 0) {
01307     ERROR5(NULL, NULL, NULL,
01308            "Failed to compile pattern %s\n", ctxt->base);
01309     ctxt->error = 1;
01310     }
01311 error:
01312     return;
01313 }
01314 
01324 static void
01325 xmlCompileIDCXPathPath(xmlPatParserContextPtr ctxt) {
01326     SKIP_BLANKS;
01327     if (CUR == '/') {
01328     ERROR5(NULL, NULL, NULL,
01329         "Unexpected selection of the document root in '%s'.\n",
01330         ctxt->base);
01331     goto error;
01332     }
01333     ctxt->comp->flags |= PAT_FROM_CUR;
01334 
01335     if (CUR == '.') {
01336     /* "." - "self::node()" */
01337     NEXT;
01338     SKIP_BLANKS;
01339     if (CUR == 0) {
01340         /*
01341         * Selection of the context node.
01342         */
01343         PUSH(XML_OP_ELEM, NULL, NULL);
01344         return;
01345     }
01346     if (CUR != '/') {
01347         /* TODO: A more meaningful error message. */
01348         ERROR5(NULL, NULL, NULL,
01349         "Unexpected token after '.' in '%s'.\n", ctxt->base);
01350         goto error;
01351     }
01352     /* "./" - "self::node()/" */
01353     NEXT;
01354     SKIP_BLANKS;
01355     if (CUR == '/') {
01356         if (IS_BLANK_CH(PEEKPREV(1))) {
01357         /*
01358         * Disallow "./ /"
01359         */
01360         ERROR5(NULL, NULL, NULL,
01361             "Unexpected '/' token in '%s'.\n", ctxt->base);
01362         goto error;
01363         }
01364         /* ".//" - "self:node()/descendant-or-self::node()/" */
01365         PUSH(XML_OP_ANCESTOR, NULL, NULL);
01366         NEXT;
01367         SKIP_BLANKS;
01368     }
01369     if (CUR == 0)
01370         goto error_unfinished;
01371     }
01372     /*
01373     * Process steps.
01374     */
01375     do {
01376     xmlCompileStepPattern(ctxt);
01377     if (ctxt->error != 0) 
01378         goto error;
01379     SKIP_BLANKS;
01380     if (CUR != '/')
01381         break;
01382     PUSH(XML_OP_PARENT, NULL, NULL);
01383     NEXT;
01384     SKIP_BLANKS;
01385     if (CUR == '/') {
01386         /*
01387         * Disallow subsequent '//'.
01388         */
01389         ERROR5(NULL, NULL, NULL,
01390         "Unexpected subsequent '//' in '%s'.\n",
01391         ctxt->base);
01392         goto error;
01393     }
01394     if (CUR == 0)
01395         goto error_unfinished;
01396     
01397     } while (CUR != 0);
01398 
01399     if (CUR != 0) {
01400     ERROR5(NULL, NULL, NULL,
01401         "Failed to compile expression '%s'.\n", ctxt->base);
01402     ctxt->error = 1;
01403     }
01404     return;
01405 error:
01406     ctxt->error = 1;
01407     return;
01408 
01409 error_unfinished:
01410     ctxt->error = 1;
01411     ERROR5(NULL, NULL, NULL,
01412     "Unfinished expression '%s'.\n", ctxt->base);    
01413     return;
01414 }
01415 
01416 /************************************************************************
01417  *                                  *
01418  *          The streaming code              *
01419  *                                  *
01420  ************************************************************************/
01421 
01422 #ifdef DEBUG_STREAMING
01423 static void
01424 xmlDebugStreamComp(xmlStreamCompPtr stream) {
01425     int i;
01426 
01427     if (stream == NULL) {
01428         printf("Stream: NULL\n");
01429     return;
01430     }
01431     printf("Stream: %d steps\n", stream->nbStep);
01432     for (i = 0;i < stream->nbStep;i++) {
01433     if (stream->steps[i].ns != NULL) {
01434         printf("{%s}", stream->steps[i].ns);
01435     }
01436         if (stream->steps[i].name == NULL) {
01437         printf("* ");
01438     } else {
01439         printf("%s ", stream->steps[i].name);
01440     }
01441     if (stream->steps[i].flags & XML_STREAM_STEP_ROOT)
01442         printf("root ");
01443     if (stream->steps[i].flags & XML_STREAM_STEP_DESC)
01444         printf("// ");
01445     if (stream->steps[i].flags & XML_STREAM_STEP_FINAL)
01446         printf("final ");
01447     printf("\n");
01448     }
01449 }
01450 static void
01451 xmlDebugStreamCtxt(xmlStreamCtxtPtr ctxt, int match) {
01452     int i;
01453 
01454     if (ctxt == NULL) {
01455         printf("Stream: NULL\n");
01456     return;
01457     }
01458     printf("Stream: level %d, %d states: ", ctxt->level, ctxt->nbState);
01459     if (match)
01460         printf("matches\n");
01461     else
01462         printf("\n");
01463     for (i = 0;i < ctxt->nbState;i++) {
01464         if (ctxt->states[2 * i] < 0)
01465         printf(" %d: free\n", i);
01466     else {
01467         printf(" %d: step %d, level %d", i, ctxt->states[2 * i],
01468                ctxt->states[(2 * i) + 1]);
01469             if (ctxt->comp->steps[ctxt->states[2 * i]].flags &
01470             XML_STREAM_STEP_DESC)
01471             printf(" //\n");
01472         else
01473             printf("\n");
01474     }
01475     }
01476 }
01477 #endif
01478 
01486 static xmlStreamCompPtr
01487 xmlNewStreamComp(int size) {
01488     xmlStreamCompPtr cur;
01489 
01490     if (size < 4)
01491         size  = 4;
01492 
01493     cur = (xmlStreamCompPtr) xmlMalloc(sizeof(xmlStreamComp));
01494     if (cur == NULL) {
01495     ERROR(NULL, NULL, NULL,
01496         "xmlNewStreamComp: malloc failed\n");
01497     return(NULL);
01498     }
01499     memset(cur, 0, sizeof(xmlStreamComp));
01500     cur->steps = (xmlStreamStepPtr) xmlMalloc(size * sizeof(xmlStreamStep));
01501     if (cur->steps == NULL) {
01502     xmlFree(cur);
01503     ERROR(NULL, NULL, NULL,
01504           "xmlNewStreamComp: malloc failed\n");
01505     return(NULL);
01506     }
01507     cur->nbStep = 0;
01508     cur->maxStep = size;
01509     return(cur);
01510 }
01511 
01518 static void
01519 xmlFreeStreamComp(xmlStreamCompPtr comp) {
01520     if (comp != NULL) {
01521         if (comp->steps != NULL)
01522         xmlFree(comp->steps);
01523     if (comp->dict != NULL)
01524         xmlDictFree(comp->dict);
01525         xmlFree(comp);
01526     }
01527 }
01528 
01540 static int
01541 xmlStreamCompAddStep(xmlStreamCompPtr comp, const xmlChar *name,
01542                      const xmlChar *ns, int nodeType, int flags) {
01543     xmlStreamStepPtr cur;
01544 
01545     if (comp->nbStep >= comp->maxStep) {
01546     cur = (xmlStreamStepPtr) xmlRealloc(comp->steps,
01547                  comp->maxStep * 2 * sizeof(xmlStreamStep));
01548     if (cur == NULL) {
01549         ERROR(NULL, NULL, NULL,
01550           "xmlNewStreamComp: malloc failed\n");
01551         return(-1);
01552     }
01553     comp->steps = cur;
01554         comp->maxStep *= 2;
01555     }
01556     cur = &comp->steps[comp->nbStep++];
01557     cur->flags = flags;
01558     cur->name = name;
01559     cur->ns = ns;
01560     cur->nodeType = nodeType;
01561     return(comp->nbStep - 1);
01562 }
01563 
01572 static int
01573 xmlStreamCompile(xmlPatternPtr comp) {
01574     xmlStreamCompPtr stream;
01575     int i, s = 0, root = 0, flags = 0, prevs = -1;
01576     xmlStepOp step;
01577 
01578     if ((comp == NULL) || (comp->steps == NULL))
01579         return(-1);
01580     /*
01581      * special case for .
01582      */
01583     if ((comp->nbStep == 1) &&
01584         (comp->steps[0].op == XML_OP_ELEM) &&
01585     (comp->steps[0].value == NULL) &&
01586     (comp->steps[0].value2 == NULL)) {
01587     stream = xmlNewStreamComp(0);
01588     if (stream == NULL)
01589         return(-1);
01590     /* Note that the stream will have no steps in this case. */
01591     stream->flags |= XML_STREAM_FINAL_IS_ANY_NODE;
01592     comp->stream = stream;
01593     return(0);
01594     }
01595 
01596     stream = xmlNewStreamComp((comp->nbStep / 2) + 1);
01597     if (stream == NULL)
01598         return(-1);
01599     if (comp->dict != NULL) {
01600         stream->dict = comp->dict;
01601     xmlDictReference(stream->dict);
01602     }
01603 
01604     i = 0;        
01605     if (comp->flags & PAT_FROM_ROOT)
01606     stream->flags |= XML_STREAM_FROM_ROOT;
01607 
01608     for (;i < comp->nbStep;i++) {
01609     step = comp->steps[i];
01610         switch (step.op) {
01611         case XML_OP_END:
01612             break;
01613         case XML_OP_ROOT:
01614             if (i != 0)
01615             goto error;
01616         root = 1;
01617         break;
01618         case XML_OP_NS:
01619         s = xmlStreamCompAddStep(stream, NULL, step.value,
01620             XML_ELEMENT_NODE, flags);       
01621         if (s < 0)
01622             goto error;
01623         prevs = s;
01624         flags = 0;      
01625         break;      
01626         case XML_OP_ATTR:
01627         flags |= XML_STREAM_STEP_ATTR;
01628         prevs = -1;
01629         s = xmlStreamCompAddStep(stream,
01630             step.value, step.value2, XML_ATTRIBUTE_NODE, flags);
01631         flags = 0;
01632         if (s < 0)
01633             goto error;
01634         break;
01635         case XML_OP_ELEM:       
01636             if ((step.value == NULL) && (step.value2 == NULL)) {
01637             /*
01638             * We have a "." or "self::node()" here.
01639             * Eliminate redundant self::node() tests like in "/./."
01640             * or "//./"
01641             * The only case we won't eliminate is "//.", i.e. if
01642             * self::node() is the last node test and we had
01643             * continuation somewhere beforehand.
01644             */
01645             if ((comp->nbStep == i + 1) &&
01646             (flags & XML_STREAM_STEP_DESC)) {
01647             /*
01648             * Mark the special case where the expression resolves
01649             * to any type of node.
01650             */
01651             if (comp->nbStep == i + 1) {
01652                 stream->flags |= XML_STREAM_FINAL_IS_ANY_NODE;
01653             }
01654             flags |= XML_STREAM_STEP_NODE;          
01655             s = xmlStreamCompAddStep(stream, NULL, NULL,
01656                 XML_STREAM_ANY_NODE, flags);
01657             if (s < 0)
01658                 goto error;
01659             flags = 0;
01660             /*
01661             * If there was a previous step, mark it to be added to
01662             * the result node-set; this is needed since only
01663             * the last step will be marked as "final" and only
01664             * "final" nodes are added to the resulting set.
01665             */
01666             if (prevs != -1) {
01667                 stream->steps[prevs].flags |= XML_STREAM_STEP_IN_SET;
01668                 prevs = -1;
01669             }
01670             break;  
01671 
01672             } else {
01673             /* Just skip this one. */
01674             continue;
01675             }
01676         }
01677         /* An element node. */      
01678             s = xmlStreamCompAddStep(stream, step.value, step.value2,
01679             XML_ELEMENT_NODE, flags);       
01680         if (s < 0)
01681             goto error;
01682         prevs = s;
01683         flags = 0;      
01684         break;      
01685         case XML_OP_CHILD:
01686         /* An element node child. */
01687             s = xmlStreamCompAddStep(stream, step.value, step.value2,
01688             XML_ELEMENT_NODE, flags);       
01689         if (s < 0)
01690             goto error;
01691         prevs = s;
01692         flags = 0;
01693         break;      
01694         case XML_OP_ALL:
01695             s = xmlStreamCompAddStep(stream, NULL, NULL,
01696             XML_ELEMENT_NODE, flags);       
01697         if (s < 0)
01698             goto error;
01699         prevs = s;
01700         flags = 0;
01701         break;
01702         case XML_OP_PARENT: 
01703             break;
01704         case XML_OP_ANCESTOR:
01705         /* Skip redundant continuations. */
01706         if (flags & XML_STREAM_STEP_DESC)
01707             break;
01708             flags |= XML_STREAM_STEP_DESC;
01709         /*
01710         * Mark the expression as having "//".
01711         */
01712         if ((stream->flags & XML_STREAM_DESC) == 0)
01713             stream->flags |= XML_STREAM_DESC;
01714         break;
01715     }
01716     }    
01717     if ((! root) && (comp->flags & XML_PATTERN_NOTPATTERN) == 0) {
01718     /*
01719     * If this should behave like a real pattern, we will mark
01720     * the first step as having "//", to be reentrant on every
01721     * tree level.
01722     */
01723     if ((stream->flags & XML_STREAM_DESC) == 0)
01724         stream->flags |= XML_STREAM_DESC;
01725 
01726     if (stream->nbStep > 0) {
01727         if ((stream->steps[0].flags & XML_STREAM_STEP_DESC) == 0)
01728         stream->steps[0].flags |= XML_STREAM_STEP_DESC;     
01729     }
01730     }
01731     if (stream->nbStep <= s)
01732     goto error;
01733     stream->steps[s].flags |= XML_STREAM_STEP_FINAL;
01734     if (root)
01735     stream->steps[0].flags |= XML_STREAM_STEP_ROOT;
01736 #ifdef DEBUG_STREAMING
01737     xmlDebugStreamComp(stream);
01738 #endif
01739     comp->stream = stream;
01740     return(0);
01741 error:
01742     xmlFreeStreamComp(stream);
01743     return(0);
01744 }
01745 
01754 static xmlStreamCtxtPtr
01755 xmlNewStreamCtxt(xmlStreamCompPtr stream) {
01756     xmlStreamCtxtPtr cur;
01757 
01758     cur = (xmlStreamCtxtPtr) xmlMalloc(sizeof(xmlStreamCtxt));
01759     if (cur == NULL) {
01760     ERROR(NULL, NULL, NULL,
01761         "xmlNewStreamCtxt: malloc failed\n");
01762     return(NULL);
01763     }
01764     memset(cur, 0, sizeof(xmlStreamCtxt));
01765     cur->states = (int *) xmlMalloc(4 * 2 * sizeof(int));
01766     if (cur->states == NULL) {
01767     xmlFree(cur);
01768     ERROR(NULL, NULL, NULL,
01769           "xmlNewStreamCtxt: malloc failed\n");
01770     return(NULL);
01771     }
01772     cur->nbState = 0;
01773     cur->maxState = 4;
01774     cur->level = 0;
01775     cur->comp = stream;
01776     cur->blockLevel = -1;
01777     return(cur);
01778 }
01779 
01786 void
01787 xmlFreeStreamCtxt(xmlStreamCtxtPtr stream) {
01788     xmlStreamCtxtPtr next;
01789 
01790     while (stream != NULL) {
01791         next = stream->next;
01792         if (stream->states != NULL)
01793         xmlFree(stream->states);
01794         xmlFree(stream);
01795     stream = next;
01796     }
01797 }
01798 
01808 static int
01809 xmlStreamCtxtAddState(xmlStreamCtxtPtr comp, int idx, int level) {
01810     int i;
01811     for (i = 0;i < comp->nbState;i++) {
01812         if (comp->states[2 * i] < 0) {
01813         comp->states[2 * i] = idx;
01814         comp->states[2 * i + 1] = level;
01815         return(i);
01816     }
01817     }
01818     if (comp->nbState >= comp->maxState) {
01819         int *cur;
01820 
01821     cur = (int *) xmlRealloc(comp->states,
01822                  comp->maxState * 4 * sizeof(int));
01823     if (cur == NULL) {
01824         ERROR(NULL, NULL, NULL,
01825           "xmlNewStreamCtxt: malloc failed\n");
01826         return(-1);
01827     }
01828     comp->states = cur;
01829         comp->maxState *= 2;
01830     }
01831     comp->states[2 * comp->nbState] = idx;
01832     comp->states[2 * comp->nbState++ + 1] = level;
01833     return(comp->nbState - 1);
01834 }
01835 
01852 static int
01853 xmlStreamPushInternal(xmlStreamCtxtPtr stream,
01854               const xmlChar *name, const xmlChar *ns,
01855               int nodeType) {
01856     int ret = 0, err = 0, final = 0, tmp, i, m, match, stepNr, desc;
01857     xmlStreamCompPtr comp;
01858     xmlStreamStep step;
01859 #ifdef DEBUG_STREAMING
01860     xmlStreamCtxtPtr orig = stream;
01861 #endif
01862 
01863     if ((stream == NULL) || (stream->nbState < 0))
01864         return(-1);
01865 
01866     while (stream != NULL) {
01867     comp = stream->comp;
01868 
01869     if ((nodeType == XML_ELEMENT_NODE) &&
01870         (name == NULL) && (ns == NULL)) {
01871         /* We have a document node here (or a reset). */
01872         stream->nbState = 0;
01873         stream->level = 0;
01874         stream->blockLevel = -1;
01875         if (comp->flags & XML_STREAM_FROM_ROOT) {
01876         if (comp->nbStep == 0) {
01877             /* TODO: We have a "/." here? */
01878             ret = 1;
01879         } else {
01880             if ((comp->nbStep == 1) &&
01881             (comp->steps[0].nodeType == XML_STREAM_ANY_NODE) &&
01882             (comp->steps[0].flags & XML_STREAM_STEP_DESC))
01883             {
01884             /*
01885             * In the case of "//." the document node will match
01886             * as well.
01887             */
01888             ret = 1;
01889             } else if (comp->steps[0].flags & XML_STREAM_STEP_ROOT) {
01890             /* TODO: Do we need this ? */
01891             tmp = xmlStreamCtxtAddState(stream, 0, 0);
01892             if (tmp < 0)
01893                 err++;
01894             }
01895         }
01896         }
01897         stream = stream->next;
01898         continue; /* while */
01899     }
01900 
01901     /*
01902     * Fast check for ".".
01903     */
01904     if (comp->nbStep == 0) {
01905         /*
01906          * / and . are handled at the XPath node set creation
01907          * level by checking min depth
01908          */
01909         if (stream->flags & XML_PATTERN_XPATH) {
01910         stream = stream->next;
01911         continue; /* while */
01912         }
01913         /*
01914         * For non-pattern like evaluation like XML Schema IDCs
01915         * or traditional XPath expressions, this will match if
01916         * we are at the first level only, otherwise on every level.
01917         */
01918         if ((nodeType != XML_ATTRIBUTE_NODE) &&
01919         (((stream->flags & XML_PATTERN_NOTPATTERN) == 0) ||
01920         (stream->level == 0))) {
01921             ret = 1;        
01922         }
01923         stream->level++;
01924         goto stream_next;
01925     }
01926     if (stream->blockLevel != -1) {
01927         /*
01928         * Skip blocked expressions.
01929         */
01930             stream->level++;
01931         goto stream_next;
01932     }
01933 
01934     if ((nodeType != XML_ELEMENT_NODE) &&
01935         (nodeType != XML_ATTRIBUTE_NODE) &&
01936         ((comp->flags & XML_STREAM_FINAL_IS_ANY_NODE) == 0)) {
01937         /*
01938         * No need to process nodes of other types if we don't
01939         * resolve to those types.
01940         * TODO: Do we need to block the context here?
01941         */
01942         stream->level++;
01943         goto stream_next;
01944     }
01945 
01946     /*
01947      * Check evolution of existing states
01948      */
01949     i = 0;
01950     m = stream->nbState;
01951     while (i < m) {
01952         if ((comp->flags & XML_STREAM_DESC) == 0) {
01953         /*
01954         * If there is no "//", then only the last
01955         * added state is of interest.
01956         */
01957         stepNr = stream->states[2 * (stream->nbState -1)];
01958         /*
01959         * TODO: Security check, should not happen, remove it.
01960         */
01961         if (stream->states[(2 * (stream->nbState -1)) + 1] <
01962             stream->level) {
01963             return (-1);
01964         }
01965         desc = 0;
01966         /* loop-stopper */
01967         i = m;
01968         } else {
01969         /*
01970         * If there are "//", then we need to process every "//"
01971         * occuring in the states, plus any other state for this
01972         * level.
01973         */      
01974         stepNr = stream->states[2 * i];
01975 
01976         /* TODO: should not happen anymore: dead states */
01977         if (stepNr < 0)
01978             goto next_state;
01979 
01980         tmp = stream->states[(2 * i) + 1];
01981 
01982         /* skip new states just added */
01983         if (tmp > stream->level)
01984             goto next_state;
01985 
01986         /* skip states at ancestor levels, except if "//" */
01987         desc = comp->steps[stepNr].flags & XML_STREAM_STEP_DESC;
01988         if ((tmp < stream->level) && (!desc))
01989             goto next_state;
01990         }
01991         /* 
01992         * Check for correct node-type.
01993         */
01994         step = comp->steps[stepNr];
01995         if (step.nodeType != nodeType) {
01996         if (step.nodeType == XML_ATTRIBUTE_NODE) {
01997             /*
01998             * Block this expression for deeper evaluation.
01999             */
02000             if ((comp->flags & XML_STREAM_DESC) == 0)
02001             stream->blockLevel = stream->level +1;
02002             goto next_state;
02003         } else if (step.nodeType != XML_STREAM_ANY_NODE)
02004             goto next_state;
02005         }       
02006         /*
02007         * Compare local/namespace-name.
02008         */
02009         match = 0;
02010         if (step.nodeType == XML_STREAM_ANY_NODE) {
02011         match = 1;
02012         } else if (step.name == NULL) {
02013         if (step.ns == NULL) {
02014             /*
02015             * This lets through all elements/attributes.
02016             */
02017             match = 1;
02018         } else if (ns != NULL)
02019             match = xmlStrEqual(step.ns, ns);
02020         } else if (((step.ns != NULL) == (ns != NULL)) &&
02021         (name != NULL) &&
02022         (step.name[0] == name[0]) &&
02023         xmlStrEqual(step.name, name) &&
02024         ((step.ns == ns) || xmlStrEqual(step.ns, ns)))
02025         {
02026         match = 1;      
02027         }    
02028 #if 0 
02029 /*
02030 * TODO: Pointer comparison won't work, since not guaranteed that the given
02031 *  values are in the same dict; especially if it's the namespace name,
02032 *  normally coming from ns->href. We need a namespace dict mechanism !
02033 */
02034         } else if (comp->dict) {
02035         if (step.name == NULL) {
02036             if (step.ns == NULL)
02037             match = 1;
02038             else
02039             match = (step.ns == ns);
02040         } else {
02041             match = ((step.name == name) && (step.ns == ns));
02042         }
02043 #endif /* if 0 ------------------------------------------------------- */       
02044         if (match) {        
02045         final = step.flags & XML_STREAM_STEP_FINAL;
02046         if (desc) {
02047             if (final) {
02048             ret = 1;
02049             } else {
02050             /* descending match create a new state */
02051             xmlStreamCtxtAddState(stream, stepNr + 1,
02052                                   stream->level + 1);
02053             }
02054         } else {
02055             if (final) {
02056             ret = 1;
02057             } else {
02058             xmlStreamCtxtAddState(stream, stepNr + 1,
02059                                   stream->level + 1);
02060             }
02061         }
02062         if ((ret != 1) && (step.flags & XML_STREAM_STEP_IN_SET)) {
02063             /*
02064             * Check if we have a special case like "foo/bar//.", where
02065             * "foo" is selected as well.
02066             */
02067             ret = 1;
02068         }
02069         }       
02070         if (((comp->flags & XML_STREAM_DESC) == 0) &&
02071         ((! match) || final))  {
02072         /*
02073         * Mark this expression as blocked for any evaluation at
02074         * deeper levels. Note that this includes "/foo"
02075         * expressions if the *pattern* behaviour is used.
02076         */
02077         stream->blockLevel = stream->level +1;
02078         }
02079 next_state:
02080         i++;
02081     }
02082 
02083     stream->level++;
02084 
02085     /*
02086     * Re/enter the expression.
02087     * Don't reenter if it's an absolute expression like "/foo",
02088     *   except "//foo".
02089     */
02090     step = comp->steps[0];
02091     if (step.flags & XML_STREAM_STEP_ROOT)
02092         goto stream_next;
02093 
02094     desc = step.flags & XML_STREAM_STEP_DESC;
02095     if (stream->flags & XML_PATTERN_NOTPATTERN) {
02096         /*
02097         * Re/enter the expression if it is a "descendant" one,
02098         * or if we are at the 1st level of evaluation.
02099         */
02100         
02101         if (stream->level == 1) {
02102         if (XML_STREAM_XS_IDC(stream)) {
02103             /*
02104             * XS-IDC: The missing "self::node()" will always
02105             * match the first given node.
02106             */
02107             goto stream_next;
02108         } else
02109             goto compare;
02110         }       
02111         /*
02112         * A "//" is always reentrant.
02113         */
02114         if (desc)
02115         goto compare;
02116 
02117         /*
02118         * XS-IDC: Process the 2nd level, since the missing
02119         * "self::node()" is responsible for the 2nd level being
02120         * the real start level.     
02121         */      
02122         if ((stream->level == 2) && XML_STREAM_XS_IDC(stream))
02123         goto compare;
02124 
02125         goto stream_next;
02126     }
02127     
02128 compare:
02129     /*
02130     * Check expected node-type.
02131     */
02132     if (step.nodeType != nodeType) {
02133         if (nodeType == XML_ATTRIBUTE_NODE)
02134         goto stream_next;
02135         else if (step.nodeType != XML_STREAM_ANY_NODE)
02136         goto stream_next;        
02137     }
02138     /*
02139     * Compare local/namespace-name.
02140     */
02141     match = 0;
02142     if (step.nodeType == XML_STREAM_ANY_NODE) {
02143         match = 1;
02144     } else if (step.name == NULL) {
02145         if (step.ns == NULL) {
02146         /*
02147         * This lets through all elements/attributes.
02148         */
02149         match = 1;
02150         } else if (ns != NULL)
02151         match = xmlStrEqual(step.ns, ns);
02152     } else if (((step.ns != NULL) == (ns != NULL)) &&
02153         (name != NULL) &&
02154         (step.name[0] == name[0]) &&
02155         xmlStrEqual(step.name, name) &&
02156         ((step.ns == ns) || xmlStrEqual(step.ns, ns)))
02157     {
02158         match = 1;      
02159     }       
02160     final = step.flags & XML_STREAM_STEP_FINAL;
02161     if (match) {        
02162         if (final)
02163         ret = 1;
02164         else
02165         xmlStreamCtxtAddState(stream, 1, stream->level);
02166         if ((ret != 1) && (step.flags & XML_STREAM_STEP_IN_SET)) {
02167         /*
02168         * Check if we have a special case like "foo//.", where
02169         * "foo" is selected as well.
02170         */
02171         ret = 1;
02172         }
02173     }
02174     if (((comp->flags & XML_STREAM_DESC) == 0) &&
02175         ((! match) || final))  {
02176         /*
02177         * Mark this expression as blocked for any evaluation at
02178         * deeper levels.
02179         */
02180         stream->blockLevel = stream->level;
02181     }
02182 
02183 stream_next:
02184         stream = stream->next;
02185     } /* while stream != NULL */
02186  
02187     if (err > 0)
02188         ret = -1;
02189 #ifdef DEBUG_STREAMING
02190     xmlDebugStreamCtxt(orig, ret);
02191 #endif
02192     return(ret);
02193 }
02194 
02211 int
02212 xmlStreamPush(xmlStreamCtxtPtr stream,
02213               const xmlChar *name, const xmlChar *ns) {
02214     return (xmlStreamPushInternal(stream, name, ns, (int) XML_ELEMENT_NODE));
02215 }
02216 
02236 int
02237 xmlStreamPushNode(xmlStreamCtxtPtr stream,
02238           const xmlChar *name, const xmlChar *ns,
02239           int nodeType)
02240 {
02241     return (xmlStreamPushInternal(stream, name, ns,
02242     nodeType));
02243 }
02244 
02261 int
02262 xmlStreamPushAttr(xmlStreamCtxtPtr stream,
02263           const xmlChar *name, const xmlChar *ns) {
02264     return (xmlStreamPushInternal(stream, name, ns, (int) XML_ATTRIBUTE_NODE));
02265 }
02266 
02275 int
02276 xmlStreamPop(xmlStreamCtxtPtr stream) {
02277     int i, lev;
02278     
02279     if (stream == NULL)
02280         return(-1);
02281     while (stream != NULL) {
02282     /*
02283     * Reset block-level.
02284     */
02285     if (stream->blockLevel == stream->level)
02286         stream->blockLevel = -1;
02287 
02288     /*
02289      *  stream->level can be zero when XML_FINAL_IS_ANY_NODE is set
02290      *  (see the thread at
02291      *  http://mail.gnome.org/archives/xslt/2008-July/msg00027.html)
02292      */
02293     if (stream->level)
02294         stream->level--;
02295     /*
02296      * Check evolution of existing states
02297      */ 
02298     for (i = stream->nbState -1; i >= 0; i--) {
02299         /* discard obsoleted states */
02300         lev = stream->states[(2 * i) + 1];
02301         if (lev > stream->level)
02302         stream->nbState--;
02303         if (lev <= stream->level)
02304         break;
02305     }
02306     stream = stream->next;
02307     }
02308     return(0);
02309 }
02310 
02323 int
02324 xmlStreamWantsAnyNode(xmlStreamCtxtPtr streamCtxt)
02325 {    
02326     if (streamCtxt == NULL)
02327     return(-1);
02328     while (streamCtxt != NULL) {
02329     if (streamCtxt->comp->flags & XML_STREAM_FINAL_IS_ANY_NODE) 
02330         return(1);
02331     streamCtxt = streamCtxt->next;
02332     }
02333     return(0);
02334 }
02335 
02336 /************************************************************************
02337  *                                  *
02338  *          The public interfaces               *
02339  *                                  *
02340  ************************************************************************/
02341 
02353 xmlPatternPtr
02354 xmlPatterncompile(const xmlChar *pattern, xmlDict *dict, int flags,
02355                   const xmlChar **namespaces) {
02356     xmlPatternPtr ret = NULL, cur;
02357     xmlPatParserContextPtr ctxt = NULL;
02358     const xmlChar *or, *start;
02359     xmlChar *tmp = NULL;
02360     int type = 0;
02361     int streamable = 1;
02362 
02363     if (pattern == NULL)
02364         return(NULL);
02365 
02366     start = pattern;
02367     or = start;
02368     while (*or != 0) {
02369     tmp = NULL;
02370     while ((*or != 0) && (*or != '|')) or++;
02371         if (*or == 0)
02372         ctxt = xmlNewPatParserContext(start, dict, namespaces);
02373     else {
02374         tmp = xmlStrndup(start, or - start);
02375         if (tmp != NULL) {
02376         ctxt = xmlNewPatParserContext(tmp, dict, namespaces);
02377         }
02378         or++;
02379     }
02380     if (ctxt == NULL) goto error;   
02381     cur = xmlNewPattern();
02382     if (cur == NULL) goto error;
02383     /*
02384     * Assign string dict.
02385     */
02386     if (dict) {     
02387         cur->dict = dict;
02388         xmlDictReference(dict);
02389     }
02390     if (ret == NULL)
02391         ret = cur;
02392     else {
02393         cur->next = ret->next;
02394         ret->next = cur;
02395     }
02396     cur->flags = flags;
02397     ctxt->comp = cur;
02398 
02399     if (XML_STREAM_XS_IDC(cur))
02400         xmlCompileIDCXPathPath(ctxt);
02401     else
02402         xmlCompilePathPattern(ctxt);
02403     if (ctxt->error != 0)
02404         goto error;
02405     xmlFreePatParserContext(ctxt);
02406     ctxt = NULL;
02407 
02408 
02409         if (streamable) {
02410         if (type == 0) {
02411             type = cur->flags & (PAT_FROM_ROOT | PAT_FROM_CUR);
02412         } else if (type == PAT_FROM_ROOT) {
02413             if (cur->flags & PAT_FROM_CUR)
02414             streamable = 0;
02415         } else if (type == PAT_FROM_CUR) {
02416             if (cur->flags & PAT_FROM_ROOT)
02417             streamable = 0;
02418         }
02419     }
02420     if (streamable)
02421         xmlStreamCompile(cur);
02422     if (xmlReversePattern(cur) < 0)
02423         goto error;
02424     if (tmp != NULL) {
02425         xmlFree(tmp);
02426         tmp = NULL;
02427     }
02428     start = or;
02429     }
02430     if (streamable == 0) {
02431         cur = ret;
02432     while (cur != NULL) {
02433         if (cur->stream != NULL) {
02434         xmlFreeStreamComp(cur->stream);
02435         cur->stream = NULL;
02436         }
02437         cur = cur->next;
02438     }
02439     }
02440 
02441     return(ret);
02442 error:
02443     if (ctxt != NULL) xmlFreePatParserContext(ctxt);
02444     if (ret != NULL) xmlFreePattern(ret);
02445     if (tmp != NULL) xmlFree(tmp);
02446     return(NULL);
02447 }
02448 
02458 int
02459 xmlPatternMatch(xmlPatternPtr comp, xmlNodePtr node)
02460 {
02461     int ret = 0;
02462 
02463     if ((comp == NULL) || (node == NULL))
02464         return(-1);
02465 
02466     while (comp != NULL) {
02467         ret = xmlPatMatch(comp, node);
02468     if (ret != 0)
02469         return(ret);
02470     comp = comp->next;
02471     }
02472     return(ret);
02473 }
02474 
02484 xmlStreamCtxtPtr
02485 xmlPatternGetStreamCtxt(xmlPatternPtr comp)
02486 {
02487     xmlStreamCtxtPtr ret = NULL, cur;
02488 
02489     if ((comp == NULL) || (comp->stream == NULL))
02490         return(NULL);
02491 
02492     while (comp != NULL) {
02493         if (comp->stream == NULL)
02494         goto failed;
02495     cur = xmlNewStreamCtxt(comp->stream);
02496     if (cur == NULL)
02497         goto failed;
02498     if (ret == NULL)
02499         ret = cur;
02500     else {
02501         cur->next = ret->next;
02502         ret->next = cur;
02503     }
02504     cur->flags = comp->flags;
02505     comp = comp->next;
02506     }
02507     return(ret);
02508 failed:
02509     xmlFreeStreamCtxt(ret);
02510     return(NULL);
02511 }
02512 
02522 int
02523 xmlPatternStreamable(xmlPatternPtr comp) {
02524     if (comp == NULL)
02525         return(-1);
02526     while (comp != NULL) {
02527         if (comp->stream == NULL)
02528         return(0);
02529     comp = comp->next;
02530     }
02531     return(1);
02532 }
02533 
02543 int
02544 xmlPatternMaxDepth(xmlPatternPtr comp) {
02545     int ret = 0, i;
02546     if (comp == NULL)
02547         return(-1);
02548     while (comp != NULL) {
02549         if (comp->stream == NULL)
02550         return(-1);
02551     for (i = 0;i < comp->stream->nbStep;i++)
02552         if (comp->stream->steps[i].flags & XML_STREAM_STEP_DESC)
02553             return(-2);
02554     if (comp->stream->nbStep > ret)
02555         ret = comp->stream->nbStep;
02556     comp = comp->next;
02557     }
02558     return(ret);
02559 }
02560 
02571 int
02572 xmlPatternMinDepth(xmlPatternPtr comp) {
02573     int ret = 12345678;
02574     if (comp == NULL)
02575         return(-1);
02576     while (comp != NULL) {
02577         if (comp->stream == NULL)
02578         return(-1);
02579     if (comp->stream->nbStep < ret)
02580         ret = comp->stream->nbStep;
02581     if (ret == 0)
02582         return(0);
02583     comp = comp->next;
02584     }
02585     return(ret);
02586 }
02587 
02596 int
02597 xmlPatternFromRoot(xmlPatternPtr comp) {
02598     if (comp == NULL)
02599         return(-1);
02600     while (comp != NULL) {
02601         if (comp->stream == NULL)
02602         return(-1);
02603     if (comp->flags & PAT_FROM_ROOT)
02604         return(1);
02605     comp = comp->next;
02606     }
02607     return(0);
02608 
02609 }
02610 
02611 #define bottom_pattern
02612 #include "elfgcchack.h"
02613 #endif /* LIBXML_PATTERN_ENABLED */

Generated on Sun May 27 2012 04:19:38 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.