Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenpattern.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
1.7.6.1
|