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

xsltutils.c
Go to the documentation of this file.
00001 /*
00002  * xsltutils.c: Utilities for the XSL Transformation 1.0 engine
00003  *
00004  * Reference:
00005  *   http://www.w3.org/TR/1999/REC-xslt-19991116
00006  *
00007  * See Copyright for the status of this software.
00008  *
00009  * daniel@veillard.com
00010  */
00011 
00012 #define IN_LIBXSLT
00013 #include "libxslt.h"
00014 
00015 #ifndef XSLT_NEED_TRIO
00016 #include <stdio.h>
00017 #else
00018 #include <trio.h>
00019 #endif
00020 
00021 #include <string.h>
00022 #ifdef HAVE_SYS_TIME_H
00023 #include <sys/time.h>
00024 #endif
00025 #ifdef HAVE_UNISTD_H
00026 #include <unistd.h>
00027 #endif
00028 #ifdef HAVE_STDLIB_H
00029 #include <stdlib.h>
00030 #endif
00031 #include <stdarg.h>
00032 
00033 #include <libxml/xmlmemory.h>
00034 #include <libxml/tree.h>
00035 #include <libxml/HTMLtree.h>
00036 #include <libxml/xmlerror.h>
00037 #include <libxml/xmlIO.h>
00038 #include "xsltutils.h"
00039 #include "templates.h"
00040 #include "xsltInternals.h"
00041 #include "imports.h"
00042 #include "transform.h"
00043 
00044 /* gettimeofday on Windows ??? */
00045 #if defined(WIN32) && !defined(__CYGWIN__)
00046 #ifdef _MSC_VER
00047 #include <winsock2.h>
00048 #pragma comment(lib, "ws2_32.lib")
00049 #define gettimeofday(p1,p2)
00050 #define HAVE_GETTIMEOFDAY
00051 #define XSLT_WIN32_PERFORMANCE_COUNTER
00052 #endif /* _MS_VER */
00053 #endif /* WIN32 */
00054 
00055 /************************************************************************
00056  *                                  *
00057  *          Convenience function                *
00058  *                                  *
00059  ************************************************************************/
00060 
00081 const xmlChar *
00082 xsltGetCNsProp(xsltStylesheetPtr style, xmlNodePtr node,
00083               const xmlChar *name, const xmlChar *nameSpace) {
00084     xmlAttrPtr prop;
00085     xmlDocPtr doc;
00086     xmlNsPtr ns;
00087     xmlChar *tmp;
00088     const xmlChar *ret;
00089 
00090     if ((node == NULL) || (style == NULL) || (style->dict == NULL))
00091     return(NULL);
00092 
00093     prop = node->properties;
00094     if (nameSpace == NULL) {
00095         return xmlGetProp(node, name);
00096     }
00097     while (prop != NULL) {
00098     /*
00099      * One need to have
00100      *   - same attribute names
00101      *   - and the attribute carrying that namespace
00102      */
00103         if ((xmlStrEqual(prop->name, name)) &&
00104         (((prop->ns == NULL) && (node->ns != NULL) &&
00105           (xmlStrEqual(node->ns->href, nameSpace))) ||
00106          ((prop->ns != NULL) &&
00107           (xmlStrEqual(prop->ns->href, nameSpace))))) {
00108 
00109         tmp = xmlNodeListGetString(node->doc, prop->children, 1);
00110         if (tmp == NULL)
00111             ret = xmlDictLookup(style->dict, BAD_CAST "", 0);
00112         else {
00113             ret = xmlDictLookup(style->dict, tmp, -1);
00114         xmlFree(tmp);
00115         }
00116         return ret;
00117         }
00118     prop = prop->next;
00119     }
00120     tmp = NULL;
00121     /*
00122      * Check if there is a default declaration in the internal
00123      * or external subsets
00124      */
00125     doc =  node->doc;
00126     if (doc != NULL) {
00127         if (doc->intSubset != NULL) {
00128         xmlAttributePtr attrDecl;
00129 
00130         attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
00131         if ((attrDecl == NULL) && (doc->extSubset != NULL))
00132         attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
00133         
00134         if ((attrDecl != NULL) && (attrDecl->prefix != NULL)) {
00135             /*
00136          * The DTD declaration only allows a prefix search
00137          */
00138         ns = xmlSearchNs(doc, node, attrDecl->prefix);
00139         if ((ns != NULL) && (xmlStrEqual(ns->href, nameSpace)))
00140             return(xmlDictLookup(style->dict,
00141                                  attrDecl->defaultValue, -1));
00142         }
00143     }
00144     }
00145     return(NULL);
00146 }
00166 xmlChar *
00167 xsltGetNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) {
00168     xmlAttrPtr prop;
00169     xmlDocPtr doc;
00170     xmlNsPtr ns;
00171 
00172     if (node == NULL)
00173     return(NULL);
00174 
00175     prop = node->properties;
00176     /*
00177     * TODO: Substitute xmlGetProp() for xmlGetNsProp(), since the former
00178     * is not namespace-aware and will return an attribute with equal
00179     * name regardless of its namespace.
00180     * Example:
00181     *   <xsl:element foo:name="myName"/>
00182     *   So this would return "myName" even if an attribute @name
00183     *   in the XSLT was requested.
00184     */
00185     if (nameSpace == NULL)
00186     return(xmlGetProp(node, name));
00187     while (prop != NULL) {
00188     /*
00189      * One need to have
00190      *   - same attribute names
00191      *   - and the attribute carrying that namespace
00192      */
00193         if ((xmlStrEqual(prop->name, name)) &&
00194         (((prop->ns == NULL) && (node->ns != NULL) &&
00195           (xmlStrEqual(node->ns->href, nameSpace))) ||
00196          ((prop->ns != NULL) &&
00197           (xmlStrEqual(prop->ns->href, nameSpace))))) {
00198         xmlChar *ret;
00199 
00200         ret = xmlNodeListGetString(node->doc, prop->children, 1);
00201         if (ret == NULL) return(xmlStrdup((xmlChar *)""));
00202         return(ret);
00203         }
00204     prop = prop->next;
00205     }
00206 
00207     /*
00208      * Check if there is a default declaration in the internal
00209      * or external subsets
00210      */
00211     doc =  node->doc;
00212     if (doc != NULL) {
00213         if (doc->intSubset != NULL) {
00214         xmlAttributePtr attrDecl;
00215 
00216         attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
00217         if ((attrDecl == NULL) && (doc->extSubset != NULL))
00218         attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
00219         
00220         if ((attrDecl != NULL) && (attrDecl->prefix != NULL)) {
00221             /*
00222          * The DTD declaration only allows a prefix search
00223          */
00224         ns = xmlSearchNs(doc, node, attrDecl->prefix);
00225         if ((ns != NULL) && (xmlStrEqual(ns->href, nameSpace)))
00226             return(xmlStrdup(attrDecl->defaultValue));
00227         }
00228     }
00229     }
00230     return(NULL);
00231 }
00232 
00245 int
00246 xsltGetUTF8Char(const unsigned char *utf, int *len) {
00247     unsigned int c;
00248 
00249     if (utf == NULL)
00250     goto error;
00251     if (len == NULL)
00252     goto error;
00253     if (*len < 1)
00254     goto error;
00255 
00256     c = utf[0];
00257     if (c & 0x80) {
00258     if (*len < 2)
00259         goto error;
00260     if ((utf[1] & 0xc0) != 0x80)
00261         goto error;
00262     if ((c & 0xe0) == 0xe0) {
00263         if (*len < 3)
00264         goto error;
00265         if ((utf[2] & 0xc0) != 0x80)
00266         goto error;
00267         if ((c & 0xf0) == 0xf0) {
00268         if (*len < 4)
00269             goto error;
00270         if ((c & 0xf8) != 0xf0 || (utf[3] & 0xc0) != 0x80)
00271             goto error;
00272         *len = 4;
00273         /* 4-byte code */
00274         c = (utf[0] & 0x7) << 18;
00275         c |= (utf[1] & 0x3f) << 12;
00276         c |= (utf[2] & 0x3f) << 6;
00277         c |= utf[3] & 0x3f;
00278         } else {
00279           /* 3-byte code */
00280         *len = 3;
00281         c = (utf[0] & 0xf) << 12;
00282         c |= (utf[1] & 0x3f) << 6;
00283         c |= utf[2] & 0x3f;
00284         }
00285     } else {
00286       /* 2-byte code */
00287         *len = 2;
00288         c = (utf[0] & 0x1f) << 6;
00289         c |= utf[1] & 0x3f;
00290     }
00291     } else {
00292     /* 1-byte code */
00293     *len = 1;
00294     }
00295     return(c);
00296 
00297 error:
00298     if (len != NULL)
00299     *len = 0;
00300     return(-1);
00301 }
00302 
00303 #ifdef XSLT_REFACTORED
00304 
00316 int
00317 xsltPointerListAddSize(xsltPointerListPtr list,            
00318                void *item,
00319                int initialSize)
00320 {
00321     if (list->items == NULL) {
00322     if (initialSize <= 0)
00323         initialSize = 1;
00324     list->items = (void **) xmlMalloc(
00325         initialSize * sizeof(void *));
00326     if (list->items == NULL) {
00327         xsltGenericError(xsltGenericErrorContext,
00328          "xsltPointerListAddSize: memory allocation failure.\n");
00329         return(-1);
00330     }
00331     list->number = 0;
00332     list->size = initialSize;
00333     } else if (list->size <= list->number) {
00334     list->size *= 2;
00335     list->items = (void **) xmlRealloc(list->items,
00336         list->size * sizeof(void *));
00337     if (list->items == NULL) {
00338         xsltGenericError(xsltGenericErrorContext,
00339          "xsltPointerListAddSize: memory re-allocation failure.\n");
00340         list->size = 0;
00341         return(-1);
00342     }
00343     }
00344     list->items[list->number++] = item;
00345     return(0);
00346 }
00347 
00356 xsltPointerListPtr
00357 xsltPointerListCreate(int initialSize)
00358 {
00359     xsltPointerListPtr ret;
00360 
00361     ret = xmlMalloc(sizeof(xsltPointerList));
00362     if (ret == NULL) {
00363     xsltGenericError(xsltGenericErrorContext,
00364          "xsltPointerListCreate: memory allocation failure.\n");
00365     return (NULL);
00366     }
00367     memset(ret, 0, sizeof(xsltPointerList));
00368     if (initialSize > 0) {
00369     xsltPointerListAddSize(ret, NULL, initialSize);
00370     ret->number = 0;
00371     }
00372     return (ret);
00373 }
00374 
00382 void
00383 xsltPointerListFree(xsltPointerListPtr list)
00384 {
00385     if (list == NULL)
00386     return;
00387     if (list->items != NULL)
00388     xmlFree(list->items);
00389     xmlFree(list);
00390 }
00391 
00399 void
00400 xsltPointerListClear(xsltPointerListPtr list)
00401 {
00402     if (list->items != NULL) {
00403     xmlFree(list->items);
00404     list->items = NULL;
00405     }
00406     list->number = 0;
00407     list->size = 0;
00408 }
00409 
00410 #endif /* XSLT_REFACTORED */
00411 
00412 /************************************************************************
00413  *                                  *
00414  *      Handling of XSLT stylesheets messages           *
00415  *                                  *
00416  ************************************************************************/
00417 
00426 void
00427 xsltMessage(xsltTransformContextPtr ctxt, xmlNodePtr node, xmlNodePtr inst) {
00428     xmlGenericErrorFunc error = xsltGenericError;
00429     void *errctx = xsltGenericErrorContext;
00430     xmlChar *prop, *message;
00431     int terminate = 0;
00432 
00433     if ((ctxt == NULL) || (inst == NULL))
00434     return;
00435 
00436     if (ctxt->error != NULL) {
00437     error = ctxt->error;
00438     errctx = ctxt->errctx;
00439     }
00440 
00441     prop = xmlGetNsProp(inst, (const xmlChar *)"terminate", NULL);
00442     if (prop != NULL) {
00443     if (xmlStrEqual(prop, (const xmlChar *)"yes")) {
00444         terminate = 1;
00445     } else if (xmlStrEqual(prop, (const xmlChar *)"no")) {
00446         terminate = 0;
00447     } else {
00448         error(errctx,
00449         "xsl:message : terminate expecting 'yes' or 'no'\n");
00450         ctxt->state = XSLT_STATE_ERROR;
00451     }
00452     xmlFree(prop);
00453     }
00454     message = xsltEvalTemplateString(ctxt, node, inst);
00455     if (message != NULL) {
00456     int len = xmlStrlen(message);
00457 
00458     error(errctx, "%s", (const char *)message);
00459     if ((len > 0) && (message[len - 1] != '\n'))
00460         error(errctx, "\n");
00461     xmlFree(message);
00462     }
00463     if (terminate)
00464     ctxt->state = XSLT_STATE_STOPPED;
00465 }
00466 
00467 /************************************************************************
00468  *                                  *
00469  *      Handling of out of context errors           *
00470  *                                  *
00471  ************************************************************************/
00472 
00473 #define XSLT_GET_VAR_STR(msg, str) {                \
00474     int       size;                     \
00475     int       chars;                        \
00476     char      *larger;                      \
00477     va_list   ap;                       \
00478                                 \
00479     str = (char *) xmlMalloc(150);              \
00480     if (str == NULL)                        \
00481     return;                         \
00482                                 \
00483     size = 150;                         \
00484                                 \
00485     while (size < 64000) {                  \
00486     va_start(ap, msg);                  \
00487     chars = vsnprintf(str, size, msg, ap);          \
00488     va_end(ap);                     \
00489     if ((chars > -1) && (chars < size))         \
00490         break;                      \
00491     if (chars > -1)                     \
00492         size += chars + 1;                  \
00493     else                            \
00494         size += 100;                    \
00495     if ((larger = (char *) xmlRealloc(str, size)) == NULL) {\
00496         xmlFree(str);                   \
00497         return;                     \
00498     }                           \
00499     str = larger;                       \
00500     }                               \
00501 }
00502 
00510 static void
00511 xsltGenericErrorDefaultFunc(void *ctx ATTRIBUTE_UNUSED, const char *msg, ...) {
00512     va_list args;
00513 
00514     if (xsltGenericErrorContext == NULL)
00515     xsltGenericErrorContext = (void *) stderr;
00516 
00517     va_start(args, msg);
00518     vfprintf((FILE *)xsltGenericErrorContext, msg, args);
00519     va_end(args);
00520 }
00521 
00522 xmlGenericErrorFunc xsltGenericError = xsltGenericErrorDefaultFunc;
00523 void *xsltGenericErrorContext = NULL;
00524 
00525 
00539 void
00540 xsltSetGenericErrorFunc(void *ctx, xmlGenericErrorFunc handler) {
00541     xsltGenericErrorContext = ctx;
00542     if (handler != NULL)
00543     xsltGenericError = handler;
00544     else
00545     xsltGenericError = xsltGenericErrorDefaultFunc;
00546 }
00547 
00556 static void
00557 xsltGenericDebugDefaultFunc(void *ctx ATTRIBUTE_UNUSED, const char *msg, ...) {
00558     va_list args;
00559 
00560     if (xsltGenericDebugContext == NULL)
00561     return;
00562 
00563     va_start(args, msg);
00564     vfprintf((FILE *)xsltGenericDebugContext, msg, args);
00565     va_end(args);
00566 }
00567 
00568 xmlGenericErrorFunc xsltGenericDebug = xsltGenericDebugDefaultFunc;
00569 void *xsltGenericDebugContext = NULL;
00570 
00571 
00585 void
00586 xsltSetGenericDebugFunc(void *ctx, xmlGenericErrorFunc handler) {
00587     xsltGenericDebugContext = ctx;
00588     if (handler != NULL)
00589     xsltGenericDebug = handler;
00590     else
00591     xsltGenericDebug = xsltGenericDebugDefaultFunc;
00592 }
00593 
00602 void
00603 xsltPrintErrorContext(xsltTransformContextPtr ctxt,
00604                   xsltStylesheetPtr style, xmlNodePtr node) {
00605     int line = 0;
00606     const xmlChar *file = NULL;
00607     const xmlChar *name = NULL;
00608     const char *type = "error";
00609     xmlGenericErrorFunc error = xsltGenericError;
00610     void *errctx = xsltGenericErrorContext;
00611 
00612     if (ctxt != NULL) {
00613     ctxt->state = XSLT_STATE_ERROR;
00614     if (ctxt->error != NULL) {
00615         error = ctxt->error;
00616         errctx = ctxt->errctx;
00617     }
00618     }
00619     if ((node == NULL) && (ctxt != NULL))
00620     node = ctxt->inst;
00621 
00622     if (node != NULL)  {
00623     if ((node->type == XML_DOCUMENT_NODE) ||
00624         (node->type == XML_HTML_DOCUMENT_NODE)) {
00625         xmlDocPtr doc = (xmlDocPtr) node;
00626 
00627         file = doc->URL;
00628     } else {
00629         line = xmlGetLineNo(node);
00630         if ((node->doc != NULL) && (node->doc->URL != NULL))
00631         file = node->doc->URL;
00632         if (node->name != NULL)
00633         name = node->name;
00634     }
00635     } 
00636     
00637     if (ctxt != NULL)
00638     type = "runtime error";
00639     else if (style != NULL) {
00640 #ifdef XSLT_REFACTORED
00641     if (XSLT_CCTXT(style)->errSeverity == XSLT_ERROR_SEVERITY_WARNING)
00642         type = "compilation warning";
00643     else
00644         type = "compilation error";
00645 #else
00646     type = "compilation error";
00647 #endif
00648     }
00649 
00650     if ((file != NULL) && (line != 0) && (name != NULL))
00651     error(errctx, "%s: file %s line %d element %s\n",
00652           type, file, line, name);
00653     else if ((file != NULL) && (name != NULL))
00654     error(errctx, "%s: file %s element %s\n", type, file, name);
00655     else if ((file != NULL) && (line != 0))
00656     error(errctx, "%s: file %s line %d\n", type, file, line);
00657     else if (file != NULL)
00658     error(errctx, "%s: file %s\n", type, file);
00659     else if (name != NULL)
00660     error(errctx, "%s: element %s\n", type, name);
00661     else
00662     error(errctx, "%s\n", type);
00663 }
00664 
00677 void
00678 xsltSetTransformErrorFunc(xsltTransformContextPtr ctxt,
00679                           void *ctx, xmlGenericErrorFunc handler)
00680 {
00681     ctxt->error = handler;
00682     ctxt->errctx = ctx;
00683 }
00684 
00696 void
00697 xsltTransformError(xsltTransformContextPtr ctxt,
00698            xsltStylesheetPtr style,
00699            xmlNodePtr node,
00700            const char *msg, ...) {
00701     xmlGenericErrorFunc error = xsltGenericError;
00702     void *errctx = xsltGenericErrorContext;
00703     char * str;
00704 
00705     if (ctxt != NULL) {
00706     ctxt->state = XSLT_STATE_ERROR;
00707     if (ctxt->error != NULL) {
00708         error = ctxt->error;
00709         errctx = ctxt->errctx;
00710     }
00711     }
00712     if ((node == NULL) && (ctxt != NULL))
00713     node = ctxt->inst;
00714     xsltPrintErrorContext(ctxt, style, node);
00715     XSLT_GET_VAR_STR(msg, str);
00716     error(errctx, "%s", str);
00717     if (str != NULL)
00718     xmlFree(str);
00719 }
00720 
00721 /************************************************************************
00722  *                                  *
00723  *              QNames                  *
00724  *                                  *
00725  ************************************************************************/
00726 
00737 const xmlChar *
00738 xsltSplitQName(xmlDictPtr dict, const xmlChar *name, const xmlChar **prefix) {
00739     int len = 0;
00740     const xmlChar *ret = NULL;
00741 
00742     *prefix = NULL;
00743     if ((name == NULL) || (dict == NULL)) return(NULL);
00744     if (name[0] == ':')
00745         return(xmlDictLookup(dict, name, -1));
00746     while ((name[len] != 0) && (name[len] != ':')) len++;
00747     if (name[len] == 0) return(xmlDictLookup(dict, name, -1));
00748     *prefix = xmlDictLookup(dict, name, len);
00749     ret = xmlDictLookup(dict, &name[len + 1], -1);
00750     return(ret);
00751 }
00752 
00770 const xmlChar *
00771 xsltGetQNameURI(xmlNodePtr node, xmlChar ** name)
00772 {
00773     int len = 0;
00774     xmlChar *qname;
00775     xmlNsPtr ns;
00776 
00777     if (name == NULL)
00778     return(NULL);
00779     qname = *name;
00780     if ((qname == NULL) || (*qname == 0))
00781     return(NULL);
00782     if (node == NULL) {
00783     xsltGenericError(xsltGenericErrorContext,
00784                  "QName: no element for namespace lookup %s\n",
00785              qname);
00786     xmlFree(qname);
00787     *name = NULL;
00788     return(NULL);
00789     }
00790 
00791     /* nasty but valid */
00792     if (qname[0] == ':')
00793     return(NULL);
00794 
00795     /*
00796      * we are not trying to validate but just to cut, and yes it will
00797      * work even if this is a set of UTF-8 encoded chars
00798      */
00799     while ((qname[len] != 0) && (qname[len] != ':')) 
00800     len++;
00801     
00802     if (qname[len] == 0)
00803     return(NULL);
00804 
00805     /*
00806      * handle xml: separately, this one is magical
00807      */
00808     if ((qname[0] == 'x') && (qname[1] == 'm') &&
00809         (qname[2] == 'l') && (qname[3] == ':')) {
00810     if (qname[4] == 0)
00811         return(NULL);
00812         *name = xmlStrdup(&qname[4]);
00813     xmlFree(qname);
00814     return(XML_XML_NAMESPACE);
00815     }
00816 
00817     qname[len] = 0;
00818     ns = xmlSearchNs(node->doc, node, qname);
00819     if (ns == NULL) {
00820     xsltGenericError(xsltGenericErrorContext,
00821         "%s:%s : no namespace bound to prefix %s\n",
00822                  qname, &qname[len + 1], qname);
00823     *name = NULL;
00824     xmlFree(qname);
00825     return(NULL);
00826     }
00827     *name = xmlStrdup(&qname[len + 1]);
00828     xmlFree(qname);
00829     return(ns->href);
00830 }
00831 
00844 const xmlChar *
00845 xsltGetQNameURI2(xsltStylesheetPtr style, xmlNodePtr node,
00846          const xmlChar **name) {
00847     int len = 0;
00848     xmlChar *qname;
00849     xmlNsPtr ns;
00850 
00851     if (name == NULL)
00852         return(NULL);
00853     qname = (xmlChar *)*name;
00854     if ((qname == NULL) || (*qname == 0))
00855         return(NULL);
00856     if (node == NULL) {
00857         xsltGenericError(xsltGenericErrorContext,
00858                          "QName: no element for namespace lookup %s\n",
00859                           qname);
00860     *name = NULL;
00861     return(NULL);
00862     }
00863 
00864     /*
00865      * we are not trying to validate but just to cut, and yes it will
00866      * work even if this is a set of UTF-8 encoded chars
00867      */
00868     while ((qname[len] != 0) && (qname[len] != ':'))
00869         len++;
00870 
00871     if (qname[len] == 0)
00872         return(NULL);
00873 
00874     /*
00875      * handle xml: separately, this one is magical
00876      */
00877     if ((qname[0] == 'x') && (qname[1] == 'm') &&
00878         (qname[2] == 'l') && (qname[3] == ':')) {
00879         if (qname[4] == 0)
00880             return(NULL);
00881         *name = xmlDictLookup(style->dict, &qname[4], -1);
00882         return(XML_XML_NAMESPACE);
00883     }
00884 
00885     qname = xmlStrndup(*name, len);
00886     ns = xmlSearchNs(node->doc, node, qname);
00887     if (ns == NULL) {
00888     if (style) {
00889         xsltTransformError(NULL, style, node,
00890         "No namespace bound to prefix '%s'.\n",
00891         qname);
00892         style->errors++;
00893     } else {
00894         xsltGenericError(xsltGenericErrorContext,
00895                 "%s : no namespace bound to prefix %s\n",
00896         *name, qname);
00897     }
00898         *name = NULL;
00899         xmlFree(qname);
00900         return(NULL);
00901     }
00902     *name = xmlDictLookup(style->dict, (*name)+len+1, -1);
00903     xmlFree(qname);
00904     return(ns->href);
00905 }
00906                                               
00907 /************************************************************************
00908  *                                  *
00909  *              Sorting                 *
00910  *                                  *
00911  ************************************************************************/
00912 
00920 void
00921 xsltDocumentSortFunction(xmlNodeSetPtr list) {
00922     int i, j;
00923     int len, tst;
00924     xmlNodePtr node;
00925 
00926     if (list == NULL)
00927     return;
00928     len = list->nodeNr;
00929     if (len <= 1)
00930     return;
00931     /* TODO: sort is really not optimized, does it needs to ? */
00932     for (i = 0;i < len -1;i++) {
00933     for (j = i + 1; j < len; j++) {
00934         tst = xmlXPathCmpNodes(list->nodeTab[i], list->nodeTab[j]);
00935         if (tst == -1) {
00936         node = list->nodeTab[i];
00937         list->nodeTab[i] = list->nodeTab[j];
00938         list->nodeTab[j] = node;
00939         }
00940     }
00941     }
00942 }
00943 
00954 xmlXPathObjectPtr *
00955 xsltComputeSortResult(xsltTransformContextPtr ctxt, xmlNodePtr sort) {
00956 #ifdef XSLT_REFACTORED
00957     xsltStyleItemSortPtr comp;
00958 #else
00959     xsltStylePreCompPtr comp;
00960 #endif
00961     xmlXPathObjectPtr *results = NULL;
00962     xmlNodeSetPtr list = NULL;
00963     xmlXPathObjectPtr res;
00964     int len = 0;
00965     int i;    
00966     xmlNodePtr oldNode;
00967     xmlNodePtr oldInst;
00968     int oldPos, oldSize ;
00969     int oldNsNr;
00970     xmlNsPtr *oldNamespaces;
00971 
00972     comp = sort->psvi;
00973     if (comp == NULL) {
00974     xsltGenericError(xsltGenericErrorContext,
00975          "xsl:sort : compilation failed\n");
00976     return(NULL);
00977     }
00978 
00979     if ((comp->select == NULL) || (comp->comp == NULL))
00980     return(NULL);
00981 
00982     list = ctxt->nodeList;
00983     if ((list == NULL) || (list->nodeNr <= 1))
00984     return(NULL);
00985 
00986     len = list->nodeNr;
00987 
00988     /* TODO: xsl:sort lang attribute */
00989     /* TODO: xsl:sort case-order attribute */
00990 
00991 
00992     results = xmlMalloc(len * sizeof(xmlXPathObjectPtr));
00993     if (results == NULL) {
00994     xsltGenericError(xsltGenericErrorContext,
00995          "xsltComputeSortResult: memory allocation failure\n");
00996     return(NULL);
00997     }
00998 
00999     oldNode = ctxt->node;
01000     oldInst = ctxt->inst;
01001     oldPos = ctxt->xpathCtxt->proximityPosition;
01002     oldSize = ctxt->xpathCtxt->contextSize;
01003     oldNsNr = ctxt->xpathCtxt->nsNr;
01004     oldNamespaces = ctxt->xpathCtxt->namespaces;
01005     for (i = 0;i < len;i++) {
01006     ctxt->inst = sort;
01007     ctxt->xpathCtxt->contextSize = len;
01008     ctxt->xpathCtxt->proximityPosition = i + 1;
01009     ctxt->node = list->nodeTab[i];
01010     ctxt->xpathCtxt->node = ctxt->node;
01011 #ifdef XSLT_REFACTORED
01012     if (comp->inScopeNs != NULL) {
01013         ctxt->xpathCtxt->namespaces = comp->inScopeNs->list;
01014         ctxt->xpathCtxt->nsNr = comp->inScopeNs->xpathNumber;
01015     } else {
01016         ctxt->xpathCtxt->namespaces = NULL;
01017         ctxt->xpathCtxt->nsNr = 0;
01018     }
01019 #else
01020     ctxt->xpathCtxt->namespaces = comp->nsList;
01021     ctxt->xpathCtxt->nsNr = comp->nsNr;
01022 #endif
01023     res = xmlXPathCompiledEval(comp->comp, ctxt->xpathCtxt);
01024     if (res != NULL) {
01025         if (res->type != XPATH_STRING)
01026         res = xmlXPathConvertString(res);
01027         if (comp->number)
01028         res = xmlXPathConvertNumber(res);
01029         res->index = i; /* Save original pos for dupl resolv */
01030         if (comp->number) {
01031         if (res->type == XPATH_NUMBER) {
01032             results[i] = res;
01033         } else {
01034 #ifdef WITH_XSLT_DEBUG_PROCESS
01035             xsltGenericDebug(xsltGenericDebugContext,
01036             "xsltComputeSortResult: select didn't evaluate to a number\n");
01037 #endif
01038             results[i] = NULL;
01039         }
01040         } else {
01041         if (res->type == XPATH_STRING) {
01042             if (comp->locale != (xsltLocale)0) {
01043             xmlChar *str = res->stringval;
01044             res->stringval = (xmlChar *) xsltStrxfrm(comp->locale, str);
01045             xmlFree(str);
01046             }
01047 
01048             results[i] = res;
01049         } else {
01050 #ifdef WITH_XSLT_DEBUG_PROCESS
01051             xsltGenericDebug(xsltGenericDebugContext,
01052             "xsltComputeSortResult: select didn't evaluate to a string\n");
01053 #endif
01054             results[i] = NULL;
01055         }
01056         }
01057     } else {
01058         ctxt->state = XSLT_STATE_STOPPED;
01059         results[i] = NULL;
01060     }
01061     }
01062     ctxt->node = oldNode;
01063     ctxt->inst = oldInst;
01064     ctxt->xpathCtxt->contextSize = oldSize;
01065     ctxt->xpathCtxt->proximityPosition = oldPos;
01066     ctxt->xpathCtxt->nsNr = oldNsNr;
01067     ctxt->xpathCtxt->namespaces = oldNamespaces;
01068 
01069     return(results);
01070 }
01071 
01081 void    
01082 xsltDefaultSortFunction(xsltTransformContextPtr ctxt, xmlNodePtr *sorts,
01083                int nbsorts) {
01084 #ifdef XSLT_REFACTORED
01085     xsltStyleItemSortPtr comp;
01086 #else
01087     xsltStylePreCompPtr comp;
01088 #endif
01089     xmlXPathObjectPtr *resultsTab[XSLT_MAX_SORT];
01090     xmlXPathObjectPtr *results = NULL, *res;
01091     xmlNodeSetPtr list = NULL;
01092     int descending, number, desc, numb;
01093     int len = 0;
01094     int i, j, incr;
01095     int tst;
01096     int depth;
01097     xmlNodePtr node;
01098     xmlXPathObjectPtr tmp;    
01099     int tempstype[XSLT_MAX_SORT], temporder[XSLT_MAX_SORT];
01100 
01101     if ((ctxt == NULL) || (sorts == NULL) || (nbsorts <= 0) ||
01102     (nbsorts >= XSLT_MAX_SORT))
01103     return;
01104     if (sorts[0] == NULL)
01105     return;
01106     comp = sorts[0]->psvi;
01107     if (comp == NULL)
01108     return;
01109 
01110     list = ctxt->nodeList;
01111     if ((list == NULL) || (list->nodeNr <= 1))
01112     return; /* nothing to do */
01113 
01114     for (j = 0; j < nbsorts; j++) {
01115     comp = sorts[j]->psvi;
01116     tempstype[j] = 0;
01117     if ((comp->stype == NULL) && (comp->has_stype != 0)) {
01118         comp->stype =
01119         xsltEvalAttrValueTemplate(ctxt, sorts[j],
01120                       (const xmlChar *) "data-type",
01121                       XSLT_NAMESPACE);
01122         if (comp->stype != NULL) {
01123         tempstype[j] = 1;
01124         if (xmlStrEqual(comp->stype, (const xmlChar *) "text"))
01125             comp->number = 0;
01126         else if (xmlStrEqual(comp->stype, (const xmlChar *) "number"))
01127             comp->number = 1;
01128         else {
01129             xsltTransformError(ctxt, NULL, sorts[j],
01130               "xsltDoSortFunction: no support for data-type = %s\n",
01131                      comp->stype);
01132             comp->number = 0; /* use default */
01133         }
01134         }
01135     }
01136     temporder[j] = 0;
01137     if ((comp->order == NULL) && (comp->has_order != 0)) {
01138         comp->order = xsltEvalAttrValueTemplate(ctxt, sorts[j],
01139                             (const xmlChar *) "order",
01140                             XSLT_NAMESPACE);
01141         if (comp->order != NULL) {
01142         temporder[j] = 1;
01143         if (xmlStrEqual(comp->order, (const xmlChar *) "ascending"))
01144             comp->descending = 0;
01145         else if (xmlStrEqual(comp->order,
01146                      (const xmlChar *) "descending"))
01147             comp->descending = 1;
01148         else {
01149             xsltTransformError(ctxt, NULL, sorts[j],
01150                  "xsltDoSortFunction: invalid value %s for order\n",
01151                      comp->order);
01152             comp->descending = 0; /* use default */
01153         }
01154         }
01155     }
01156     }
01157 
01158     len = list->nodeNr;
01159 
01160     resultsTab[0] = xsltComputeSortResult(ctxt, sorts[0]);
01161     for (i = 1;i < XSLT_MAX_SORT;i++)
01162     resultsTab[i] = NULL;
01163 
01164     results = resultsTab[0];
01165 
01166     comp = sorts[0]->psvi;
01167     descending = comp->descending;
01168     number = comp->number;
01169     if (results == NULL)
01170     return;
01171 
01172     /* Shell's sort of node-set */
01173     for (incr = len / 2; incr > 0; incr /= 2) {
01174     for (i = incr; i < len; i++) {
01175         j = i - incr;
01176         if (results[i] == NULL)
01177         continue;
01178         
01179         while (j >= 0) {
01180         if (results[j] == NULL)
01181             tst = 1;
01182         else {
01183             if (number) {
01184             /* We make NaN smaller than number in accordance
01185                with XSLT spec */
01186             if (xmlXPathIsNaN(results[j]->floatval)) {
01187                 if (xmlXPathIsNaN(results[j + incr]->floatval))
01188                 tst = 0;
01189                 else
01190                 tst = -1;
01191             } else if (xmlXPathIsNaN(results[j + incr]->floatval))
01192                 tst = 1;
01193             else if (results[j]->floatval ==
01194                 results[j + incr]->floatval)
01195                 tst = 0;
01196             else if (results[j]->floatval > 
01197                 results[j + incr]->floatval)
01198                 tst = 1;
01199             else tst = -1;
01200             } else if(comp->locale != (xsltLocale)0) {
01201             tst = xsltLocaleStrcmp(
01202                 comp->locale,
01203                 (xsltLocaleChar *) results[j]->stringval,
01204                 (xsltLocaleChar *) results[j + incr]->stringval); 
01205             } else {
01206             tst = xmlStrcmp(results[j]->stringval,
01207                      results[j + incr]->stringval); 
01208             }
01209             if (descending)
01210             tst = -tst;
01211         }
01212         if (tst == 0) {
01213             /*
01214              * Okay we need to use multi level sorts
01215              */
01216             depth = 1;
01217             while (depth < nbsorts) {
01218             if (sorts[depth] == NULL)
01219                 break;
01220             comp = sorts[depth]->psvi;
01221             if (comp == NULL)
01222                 break;
01223             desc = comp->descending;
01224             numb = comp->number;
01225 
01226             /*
01227              * Compute the result of the next level for the
01228              * full set, this might be optimized ... or not
01229              */
01230             if (resultsTab[depth] == NULL) 
01231                 resultsTab[depth] = xsltComputeSortResult(ctxt,
01232                                         sorts[depth]);
01233             res = resultsTab[depth];
01234             if (res == NULL) 
01235                 break;
01236             if (res[j] == NULL) {
01237                 if (res[j+incr] != NULL)
01238                 tst = 1;
01239             } else {
01240                 if (numb) {
01241                 /* We make NaN smaller than number in
01242                    accordance with XSLT spec */
01243                 if (xmlXPathIsNaN(res[j]->floatval)) {
01244                     if (xmlXPathIsNaN(res[j +
01245                             incr]->floatval))
01246                     tst = 0;
01247                     else
01248                         tst = -1;
01249                 } else if (xmlXPathIsNaN(res[j + incr]->
01250                         floatval))
01251                     tst = 1;
01252                 else if (res[j]->floatval == res[j + incr]->
01253                         floatval)
01254                     tst = 0;
01255                 else if (res[j]->floatval > 
01256                     res[j + incr]->floatval)
01257                     tst = 1;
01258                 else tst = -1;
01259                 } else if(comp->locale != (xsltLocale)0) {
01260                 tst = xsltLocaleStrcmp(
01261                     comp->locale,
01262                     (xsltLocaleChar *) res[j]->stringval,
01263                     (xsltLocaleChar *) res[j + incr]->stringval); 
01264                 } else {
01265                 tst = xmlStrcmp(res[j]->stringval,
01266                          res[j + incr]->stringval); 
01267                 }
01268                 if (desc)
01269                 tst = -tst;
01270             }
01271 
01272             /*
01273              * if we still can't differenciate at this level
01274              * try one level deeper.
01275              */
01276             if (tst != 0)
01277                 break;
01278             depth++;
01279             }
01280         }
01281         if (tst == 0) {
01282             tst = results[j]->index > results[j + incr]->index;
01283         }
01284         if (tst > 0) {
01285             tmp = results[j];
01286             results[j] = results[j + incr];
01287             results[j + incr] = tmp;
01288             node = list->nodeTab[j];
01289             list->nodeTab[j] = list->nodeTab[j + incr];
01290             list->nodeTab[j + incr] = node;
01291             depth = 1;
01292             while (depth < nbsorts) {
01293             if (sorts[depth] == NULL)
01294                 break;
01295             if (resultsTab[depth] == NULL)
01296                 break;
01297             res = resultsTab[depth];
01298             tmp = res[j];
01299             res[j] = res[j + incr];
01300             res[j + incr] = tmp;
01301             depth++;
01302             }
01303             j -= incr;
01304         } else
01305             break;
01306         }
01307     }
01308     }
01309 
01310     for (j = 0; j < nbsorts; j++) {
01311     comp = sorts[j]->psvi;
01312     if (tempstype[j] == 1) {
01313         /* The data-type needs to be recomputed each time */
01314         xmlFree((void *)(comp->stype));
01315         comp->stype = NULL;
01316     }
01317     if (temporder[j] == 1) {
01318         /* The order needs to be recomputed each time */
01319         xmlFree((void *)(comp->order));
01320         comp->order = NULL;
01321     }
01322     if (resultsTab[j] != NULL) {
01323         for (i = 0;i < len;i++)
01324         xmlXPathFreeObject(resultsTab[j][i]);
01325         xmlFree(resultsTab[j]);
01326     }
01327     }
01328 }
01329 
01330 
01331 static xsltSortFunc xsltSortFunction = xsltDefaultSortFunction;
01332 
01347 void
01348 xsltDoSortFunction(xsltTransformContextPtr ctxt, xmlNodePtr * sorts,
01349                    int nbsorts)
01350 {
01351     if (ctxt->sortfunc != NULL)
01352     (ctxt->sortfunc)(ctxt, sorts, nbsorts);
01353     else if (xsltSortFunction != NULL)
01354         xsltSortFunction(ctxt, sorts, nbsorts);
01355 }
01356 
01364 void
01365 xsltSetSortFunc(xsltSortFunc handler) {
01366     if (handler != NULL)
01367     xsltSortFunction = handler;
01368     else
01369     xsltSortFunction = xsltDefaultSortFunction;
01370 }
01371 
01382 void 
01383 xsltSetCtxtSortFunc(xsltTransformContextPtr ctxt, xsltSortFunc handler) {
01384     ctxt->sortfunc = handler;
01385 }
01386 
01387 /************************************************************************
01388  *                                  *
01389  *              Parsing options             *
01390  *                                  *
01391  ************************************************************************/
01392 
01403 int 
01404 xsltSetCtxtParseOptions(xsltTransformContextPtr ctxt, int options)
01405 {
01406     int oldopts;
01407 
01408     if (ctxt == NULL)
01409         return(-1);
01410     oldopts = ctxt->parserOptions;
01411     if (ctxt->xinclude)
01412         oldopts |= XML_PARSE_XINCLUDE;
01413     ctxt->parserOptions = options;
01414     if (options & XML_PARSE_XINCLUDE)
01415         ctxt->xinclude = 1;
01416     else
01417         ctxt->xinclude = 0;
01418     return(oldopts);
01419 }
01420 
01421 /************************************************************************
01422  *                                  *
01423  *              Output                  *
01424  *                                  *
01425  ************************************************************************/
01426 
01438 int
01439 xsltSaveResultTo(xmlOutputBufferPtr buf, xmlDocPtr result,
01440            xsltStylesheetPtr style) {
01441     const xmlChar *encoding;
01442     int base;
01443     const xmlChar *method;
01444     int indent;
01445 
01446     if ((buf == NULL) || (result == NULL) || (style == NULL))
01447     return(-1);
01448     if ((result->children == NULL) ||
01449     ((result->children->type == XML_DTD_NODE) &&
01450      (result->children->next == NULL)))
01451     return(0);
01452 
01453     if ((style->methodURI != NULL) &&
01454     ((style->method == NULL) ||
01455      (!xmlStrEqual(style->method, (const xmlChar *) "xhtml")))) {
01456         xsltGenericError(xsltGenericErrorContext,
01457         "xsltSaveResultTo : unknown ouput method\n");
01458         return(-1);
01459     }
01460 
01461     base = buf->written;
01462 
01463     XSLT_GET_IMPORT_PTR(method, style, method)
01464     XSLT_GET_IMPORT_PTR(encoding, style, encoding)
01465     XSLT_GET_IMPORT_INT(indent, style, indent);
01466 
01467     if ((method == NULL) && (result->type == XML_HTML_DOCUMENT_NODE))
01468     method = (const xmlChar *) "html";
01469 
01470     if ((method != NULL) &&
01471     (xmlStrEqual(method, (const xmlChar *) "html"))) {
01472     if (encoding != NULL) {
01473         htmlSetMetaEncoding(result, (const xmlChar *) encoding);
01474     } else {
01475         htmlSetMetaEncoding(result, (const xmlChar *) "UTF-8");
01476     }
01477     if (indent == -1)
01478         indent = 1;
01479     htmlDocContentDumpFormatOutput(buf, result, (const char *) encoding,
01480                                indent);
01481     xmlOutputBufferFlush(buf);
01482     } else if ((method != NULL) &&
01483     (xmlStrEqual(method, (const xmlChar *) "xhtml"))) {
01484     if (encoding != NULL) {
01485         htmlSetMetaEncoding(result, (const xmlChar *) encoding);
01486     } else {
01487         htmlSetMetaEncoding(result, (const xmlChar *) "UTF-8");
01488     }
01489     htmlDocContentDumpOutput(buf, result, (const char *) encoding);
01490     xmlOutputBufferFlush(buf);
01491     } else if ((method != NULL) &&
01492            (xmlStrEqual(method, (const xmlChar *) "text"))) {
01493     xmlNodePtr cur;
01494 
01495     cur = result->children;
01496     while (cur != NULL) {
01497         if (cur->type == XML_TEXT_NODE)
01498         xmlOutputBufferWriteString(buf, (const char *) cur->content);
01499 
01500         /*
01501          * Skip to next node
01502          */
01503         if (cur->children != NULL) {
01504         if ((cur->children->type != XML_ENTITY_DECL) &&
01505             (cur->children->type != XML_ENTITY_REF_NODE) &&
01506             (cur->children->type != XML_ENTITY_NODE)) {
01507             cur = cur->children;
01508             continue;
01509         }
01510         }
01511         if (cur->next != NULL) {
01512         cur = cur->next;
01513         continue;
01514         }
01515         
01516         do {
01517         cur = cur->parent;
01518         if (cur == NULL)
01519             break;
01520         if (cur == (xmlNodePtr) style->doc) {
01521             cur = NULL;
01522             break;
01523         }
01524         if (cur->next != NULL) {
01525             cur = cur->next;
01526             break;
01527         }
01528         } while (cur != NULL);
01529     }
01530     xmlOutputBufferFlush(buf);
01531     } else {
01532     int omitXmlDecl;
01533     int standalone;
01534 
01535     XSLT_GET_IMPORT_INT(omitXmlDecl, style, omitXmlDeclaration);
01536     XSLT_GET_IMPORT_INT(standalone, style, standalone);
01537 
01538     if (omitXmlDecl != 1) {
01539         xmlOutputBufferWriteString(buf, "<?xml version=");
01540         if (result->version != NULL) 
01541         xmlBufferWriteQuotedString(buf->buffer, result->version);
01542         else
01543         xmlOutputBufferWriteString(buf, "\"1.0\"");
01544         if (encoding == NULL) {
01545         if (result->encoding != NULL)
01546             encoding = result->encoding;
01547         else if (result->charset != XML_CHAR_ENCODING_UTF8)
01548             encoding = (const xmlChar *)
01549                    xmlGetCharEncodingName((xmlCharEncoding)
01550                                           result->charset);
01551         }
01552         if (encoding != NULL) {
01553         xmlOutputBufferWriteString(buf, " encoding=");
01554         xmlBufferWriteQuotedString(buf->buffer, (xmlChar *) encoding);
01555         }
01556         switch (standalone) {
01557         case 0:
01558             xmlOutputBufferWriteString(buf, " standalone=\"no\"");
01559             break;
01560         case 1:
01561             xmlOutputBufferWriteString(buf, " standalone=\"yes\"");
01562             break;
01563         default:
01564             break;
01565         }
01566         xmlOutputBufferWriteString(buf, "?>\n");
01567     }
01568     if (result->children != NULL) {
01569         xmlNodePtr child = result->children;
01570 
01571         while (child != NULL) {
01572         xmlNodeDumpOutput(buf, result, child, 0, (indent == 1),
01573                       (const char *) encoding);
01574         if ((child->type == XML_DTD_NODE) ||
01575             ((child->type == XML_COMMENT_NODE) &&
01576              (child->next != NULL)))
01577             xmlOutputBufferWriteString(buf, "\n");
01578         child = child->next;
01579         }
01580         xmlOutputBufferWriteString(buf, "\n");
01581     }
01582     xmlOutputBufferFlush(buf);
01583     }
01584     return(buf->written - base);
01585 }
01586 
01599 int
01600 xsltSaveResultToFilename(const char *URL, xmlDocPtr result,
01601              xsltStylesheetPtr style, int compression) {
01602     xmlOutputBufferPtr buf;
01603     const xmlChar *encoding;
01604     int ret;
01605 
01606     if ((URL == NULL) || (result == NULL) || (style == NULL))
01607     return(-1);
01608     if (result->children == NULL)
01609     return(0);
01610 
01611     XSLT_GET_IMPORT_PTR(encoding, style, encoding)
01612     if (encoding != NULL) {
01613     xmlCharEncodingHandlerPtr encoder;
01614 
01615     encoder = xmlFindCharEncodingHandler((char *)encoding);
01616     if ((encoder != NULL) &&
01617         (xmlStrEqual((const xmlChar *)encoder->name,
01618              (const xmlChar *) "UTF-8")))
01619         encoder = NULL;
01620     buf = xmlOutputBufferCreateFilename(URL, encoder, compression);
01621     } else {
01622     buf = xmlOutputBufferCreateFilename(URL, NULL, compression);
01623     }
01624     if (buf == NULL)
01625     return(-1);
01626     xsltSaveResultTo(buf, result, style);
01627     ret = xmlOutputBufferClose(buf);
01628     return(ret);
01629 }
01630 
01643 int
01644 xsltSaveResultToFile(FILE *file, xmlDocPtr result, xsltStylesheetPtr style) {
01645     xmlOutputBufferPtr buf;
01646     const xmlChar *encoding;
01647     int ret;
01648 
01649     if ((file == NULL) || (result == NULL) || (style == NULL))
01650     return(-1);
01651     if (result->children == NULL)
01652     return(0);
01653 
01654     XSLT_GET_IMPORT_PTR(encoding, style, encoding)
01655     if (encoding != NULL) {
01656     xmlCharEncodingHandlerPtr encoder;
01657 
01658     encoder = xmlFindCharEncodingHandler((char *)encoding);
01659     if ((encoder != NULL) &&
01660         (xmlStrEqual((const xmlChar *)encoder->name,
01661              (const xmlChar *) "UTF-8")))
01662         encoder = NULL;
01663     buf = xmlOutputBufferCreateFile(file, encoder);
01664     } else {
01665     buf = xmlOutputBufferCreateFile(file, NULL);
01666     }
01667 
01668     if (buf == NULL)
01669     return(-1);
01670     xsltSaveResultTo(buf, result, style);
01671     ret = xmlOutputBufferClose(buf);
01672     return(ret);
01673 }
01674 
01687 int
01688 xsltSaveResultToFd(int fd, xmlDocPtr result, xsltStylesheetPtr style) {
01689     xmlOutputBufferPtr buf;
01690     const xmlChar *encoding;
01691     int ret;
01692 
01693     if ((fd < 0) || (result == NULL) || (style == NULL))
01694     return(-1);
01695     if (result->children == NULL)
01696     return(0);
01697 
01698     XSLT_GET_IMPORT_PTR(encoding, style, encoding)
01699     if (encoding != NULL) {
01700     xmlCharEncodingHandlerPtr encoder;
01701 
01702     encoder = xmlFindCharEncodingHandler((char *)encoding);
01703     if ((encoder != NULL) &&
01704         (xmlStrEqual((const xmlChar *)encoder->name,
01705              (const xmlChar *) "UTF-8")))
01706         encoder = NULL;
01707     buf = xmlOutputBufferCreateFd(fd, encoder);
01708     } else {
01709     buf = xmlOutputBufferCreateFd(fd, NULL);
01710     }
01711     if (buf == NULL)
01712     return(-1);
01713     xsltSaveResultTo(buf, result, style);
01714     ret = xmlOutputBufferClose(buf);
01715     return(ret);
01716 }
01717 
01730 int
01731 xsltSaveResultToString(xmlChar **doc_txt_ptr, int * doc_txt_len, 
01732                xmlDocPtr result, xsltStylesheetPtr style) {
01733     xmlOutputBufferPtr buf;
01734     const xmlChar *encoding;
01735 
01736     *doc_txt_ptr = NULL;
01737     *doc_txt_len = 0;
01738     if (result->children == NULL)
01739     return(0);
01740 
01741     XSLT_GET_IMPORT_PTR(encoding, style, encoding)
01742     if (encoding != NULL) {
01743     xmlCharEncodingHandlerPtr encoder;
01744 
01745     encoder = xmlFindCharEncodingHandler((char *)encoding);
01746     if ((encoder != NULL) &&
01747         (xmlStrEqual((const xmlChar *)encoder->name,
01748              (const xmlChar *) "UTF-8")))
01749         encoder = NULL;
01750     buf = xmlAllocOutputBuffer(encoder);
01751     } else {
01752     buf = xmlAllocOutputBuffer(NULL);
01753     }
01754     if (buf == NULL)
01755     return(-1);
01756     xsltSaveResultTo(buf, result, style);
01757     if (buf->conv != NULL) {
01758     *doc_txt_len = buf->conv->use;
01759     *doc_txt_ptr = xmlStrndup(buf->conv->content, *doc_txt_len);
01760     } else {
01761     *doc_txt_len = buf->buffer->use;
01762     *doc_txt_ptr = xmlStrndup(buf->buffer->content, *doc_txt_len);
01763     }
01764     (void)xmlOutputBufferClose(buf);
01765     return 0;
01766 }
01767 
01768 /************************************************************************
01769  *                                  *
01770  *      Generating profiling informations           *
01771  *                                  *
01772  ************************************************************************/
01773 
01774 static long calibration = -1;
01775 
01784 static long
01785 xsltCalibrateTimestamps(void) {
01786     register int i;
01787 
01788     for (i = 0;i < 999;i++)
01789     xsltTimestamp();
01790     return(xsltTimestamp() / 1000);
01791 }
01792 
01799 void
01800 xsltCalibrateAdjust(long delta) {
01801     calibration += delta;
01802 }
01803 
01812 long
01813 xsltTimestamp(void)
01814 {
01815 #ifdef XSLT_WIN32_PERFORMANCE_COUNTER
01816     BOOL ok;
01817     LARGE_INTEGER performanceCount;
01818     LARGE_INTEGER performanceFrequency;
01819     LONGLONG quadCount;
01820     double seconds;
01821     static LONGLONG startupQuadCount = 0;
01822     static LONGLONG startupQuadFreq = 0;
01823 
01824     ok = QueryPerformanceCounter(&performanceCount);
01825     if (!ok)
01826         return 0;
01827     quadCount = performanceCount.QuadPart;
01828     if (calibration < 0) {
01829         calibration = 0;
01830         ok = QueryPerformanceFrequency(&performanceFrequency);
01831         if (!ok)
01832             return 0;
01833         startupQuadFreq = performanceFrequency.QuadPart;
01834         startupQuadCount = quadCount;
01835         return (0);
01836     }
01837     if (startupQuadFreq == 0)
01838         return 0;
01839     seconds = (quadCount - startupQuadCount) / (double) startupQuadFreq;
01840     return (long) (seconds * XSLT_TIMESTAMP_TICS_PER_SEC);
01841 
01842 #else /* XSLT_WIN32_PERFORMANCE_COUNTER */
01843 #ifdef HAVE_GETTIMEOFDAY
01844     static struct timeval startup;
01845     struct timeval cur;
01846     long tics;
01847 
01848     if (calibration < 0) {
01849         gettimeofday(&startup, NULL);
01850         calibration = 0;
01851         calibration = xsltCalibrateTimestamps();
01852         gettimeofday(&startup, NULL);
01853         return (0);
01854     }
01855 
01856     gettimeofday(&cur, NULL);
01857     tics = (cur.tv_sec - startup.tv_sec) * XSLT_TIMESTAMP_TICS_PER_SEC;
01858     tics += (cur.tv_usec - startup.tv_usec) /
01859                           (1000000l / XSLT_TIMESTAMP_TICS_PER_SEC);
01860     
01861     tics -= calibration;
01862     return(tics);
01863 #else
01864 
01865     /* Neither gettimeofday() nor Win32 performance counter available */
01866 
01867     return (0);
01868 
01869 #endif /* HAVE_GETTIMEOFDAY */
01870 #endif /* XSLT_WIN32_PERFORMANCE_COUNTER */
01871 }
01872 
01873 #define MAX_TEMPLATES 10000
01874 
01882 void
01883 xsltSaveProfiling(xsltTransformContextPtr ctxt, FILE *output) {
01884     int nb, i,j;
01885     int max;
01886     int total;
01887     long totalt;
01888     xsltTemplatePtr *templates;
01889     xsltStylesheetPtr style;
01890     xsltTemplatePtr template;
01891 
01892     if ((output == NULL) || (ctxt == NULL))
01893     return;
01894     if (ctxt->profile == 0)
01895     return;
01896 
01897     nb = 0;
01898     max = MAX_TEMPLATES;
01899     templates = xmlMalloc(max * sizeof(xsltTemplatePtr));
01900     if (templates == NULL)
01901     return;
01902 
01903     style = ctxt->style;
01904     while (style != NULL) {
01905     template = style->templates;
01906     while (template != NULL) {
01907         if (nb >= max)
01908         break;
01909 
01910         if (template->nbCalls > 0)
01911         templates[nb++] = template;
01912         template = template->next;
01913     }
01914 
01915     style = xsltNextImport(style);
01916     }
01917 
01918     for (i = 0;i < nb -1;i++) {
01919     for (j = i + 1; j < nb; j++) {
01920         if ((templates[i]->time <= templates[j]->time) ||
01921         ((templates[i]->time == templates[j]->time) &&
01922              (templates[i]->nbCalls <= templates[j]->nbCalls))) {
01923         template = templates[j];
01924         templates[j] = templates[i];
01925         templates[i] = template;
01926         }
01927     }
01928     }
01929 
01930     fprintf(output, "%6s%20s%20s%10s  Calls Tot 100us Avg\n\n",
01931         "number", "match", "name", "mode");
01932     total = 0;
01933     totalt = 0;
01934     for (i = 0;i < nb;i++) {
01935     fprintf(output, "%5d ", i);
01936     if (templates[i]->match != NULL) {
01937         if (xmlStrlen(templates[i]->match) > 20)
01938         fprintf(output, "%s\n%26s", templates[i]->match, "");
01939         else
01940         fprintf(output, "%20s", templates[i]->match);
01941     } else {
01942         fprintf(output, "%20s", "");
01943     }
01944     if (templates[i]->name != NULL) {
01945         if (xmlStrlen(templates[i]->name) > 20)
01946         fprintf(output, "%s\n%46s", templates[i]->name, "");
01947         else
01948         fprintf(output, "%20s", templates[i]->name);
01949     } else {
01950         fprintf(output, "%20s", "");
01951     }
01952     if (templates[i]->mode != NULL) {
01953         if (xmlStrlen(templates[i]->mode) > 10)
01954         fprintf(output, "%s\n%56s", templates[i]->mode, "");
01955         else
01956         fprintf(output, "%10s", templates[i]->mode);
01957     } else {
01958         fprintf(output, "%10s", "");
01959     }
01960     fprintf(output, " %6d", templates[i]->nbCalls);
01961     fprintf(output, " %6ld %6ld\n", templates[i]->time,
01962         templates[i]->time / templates[i]->nbCalls);
01963     total += templates[i]->nbCalls;
01964     totalt += templates[i]->time;
01965     }
01966     fprintf(output, "\n%30s%26s %6d %6ld\n", "Total", "", total, totalt);
01967 
01968     xmlFree(templates);
01969 }
01970 
01971 /************************************************************************
01972  *                                  *
01973  *      Fetching profiling informations             *
01974  *                                  *
01975  ************************************************************************/
01976 
01998 xmlDocPtr
01999 xsltGetProfileInformation(xsltTransformContextPtr ctxt)
02000 {
02001     xmlDocPtr ret = NULL;
02002     xmlNodePtr root, child;
02003     char buf[100];
02004 
02005     xsltStylesheetPtr style;
02006     xsltTemplatePtr *templates;
02007     xsltTemplatePtr templ;
02008     int nb = 0, max = 0, i, j;
02009 
02010     if (!ctxt)
02011         return NULL;
02012 
02013     if (!ctxt->profile)
02014         return NULL;
02015 
02016     nb = 0;
02017     max = 10000;
02018     templates =
02019         (xsltTemplatePtr *) xmlMalloc(max * sizeof(xsltTemplatePtr));
02020     if (templates == NULL)
02021         return NULL;
02022 
02023     /*
02024      * collect all the templates in an array
02025      */
02026     style = ctxt->style;
02027     while (style != NULL) {
02028         templ = style->templates;
02029         while (templ != NULL) {
02030             if (nb >= max)
02031                 break;
02032 
02033             if (templ->nbCalls > 0)
02034                 templates[nb++] = templ;
02035             templ = templ->next;
02036         }
02037 
02038         style = (xsltStylesheetPtr) xsltNextImport(style);
02039     }
02040 
02041     /*
02042      * Sort the array by time spent
02043      */
02044     for (i = 0; i < nb - 1; i++) {
02045         for (j = i + 1; j < nb; j++) {
02046             if ((templates[i]->time <= templates[j]->time) ||
02047                 ((templates[i]->time == templates[j]->time) &&
02048                  (templates[i]->nbCalls <= templates[j]->nbCalls))) {
02049                 templ = templates[j];
02050                 templates[j] = templates[i];
02051                 templates[i] = templ;
02052             }
02053         }
02054     }
02055 
02056     /*
02057      * Generate a document corresponding to the results.
02058      */
02059     ret = xmlNewDoc(BAD_CAST "1.0");
02060     root = xmlNewDocNode(ret, NULL, BAD_CAST "profile", NULL);
02061     xmlDocSetRootElement(ret, root);
02062 
02063     for (i = 0; i < nb; i++) {
02064         child = xmlNewChild(root, NULL, BAD_CAST "template", NULL);
02065         sprintf(buf, "%d", i + 1);
02066         xmlSetProp(child, BAD_CAST "rank", BAD_CAST buf);
02067         xmlSetProp(child, BAD_CAST "match", BAD_CAST templates[i]->match);
02068         xmlSetProp(child, BAD_CAST "name", BAD_CAST templates[i]->name);
02069         xmlSetProp(child, BAD_CAST "mode", BAD_CAST templates[i]->mode);
02070 
02071         sprintf(buf, "%d", templates[i]->nbCalls);
02072         xmlSetProp(child, BAD_CAST "calls", BAD_CAST buf);
02073 
02074         sprintf(buf, "%ld", templates[i]->time);
02075         xmlSetProp(child, BAD_CAST "time", BAD_CAST buf);
02076 
02077         sprintf(buf, "%ld", templates[i]->time / templates[i]->nbCalls);
02078         xmlSetProp(child, BAD_CAST "average", BAD_CAST buf);
02079     };
02080 
02081     xmlFree(templates);
02082 
02083     return ret;
02084 }
02085 
02086 /************************************************************************
02087  *                                  *
02088  *      Hooks for libxml2 XPath                 *
02089  *                                  *
02090  ************************************************************************/
02091 
02102 xmlXPathCompExprPtr
02103 xsltXPathCompile(xsltStylesheetPtr style, const xmlChar *str) {
02104     xmlXPathContextPtr xpathCtxt;
02105     xmlXPathCompExprPtr ret;
02106 
02107     if (style != NULL) {
02108 #ifdef XSLT_REFACTORED_XPATHCOMP
02109     if (XSLT_CCTXT(style)) {
02110         /*
02111         * Proposed by Jerome Pesenti
02112         * --------------------------
02113         * For better efficiency we'll reuse the compilation
02114         * context's XPath context. For the common stylesheet using
02115         * XPath expressions this will reduce compilation time to
02116         * about 50%.
02117         *
02118         * See http://mail.gnome.org/archives/xslt/2006-April/msg00037.html
02119         */
02120         xpathCtxt = XSLT_CCTXT(style)->xpathCtxt;
02121         xpathCtxt->doc = style->doc;
02122     } else
02123         xpathCtxt = xmlXPathNewContext(style->doc);
02124 #else
02125     xpathCtxt = xmlXPathNewContext(style->doc);
02126 #endif
02127     if (xpathCtxt == NULL)
02128         return NULL;
02129     xpathCtxt->dict = style->dict;
02130     } else {
02131     xpathCtxt = xmlXPathNewContext(NULL);
02132     if (xpathCtxt == NULL)
02133         return NULL;
02134     }
02135     /*
02136     * Compile the expression.
02137     */
02138     ret = xmlXPathCtxtCompile(xpathCtxt, str);
02139 
02140 #ifdef XSLT_REFACTORED_XPATHCOMP
02141     if ((style == NULL) || (! XSLT_CCTXT(style))) {
02142     xmlXPathFreeContext(xpathCtxt);
02143     }
02144 #else
02145     xmlXPathFreeContext(xpathCtxt);
02146 #endif
02147     /*
02148      * TODO: there is a lot of optimizations which should be possible
02149      *       like variable slot precomputations, function precomputations, etc.
02150      */
02151 
02152     return(ret);
02153 }
02154 
02155 /************************************************************************
02156  *                                  *
02157  *      Hooks for the debugger                  *
02158  *                                  *
02159  ************************************************************************/
02160 
02161 /*
02162  * There is currently only 3 debugging callback defined
02163  * Debugger callbacks are disabled by default
02164  */
02165 #define XSLT_CALLBACK_NUMBER 3
02166 
02167 typedef struct _xsltDebuggerCallbacks xsltDebuggerCallbacks;
02168 typedef xsltDebuggerCallbacks *xsltDebuggerCallbacksPtr;
02169 struct _xsltDebuggerCallbacks {
02170     xsltHandleDebuggerCallback handler;
02171     xsltAddCallCallback add;
02172     xsltDropCallCallback drop;
02173 };
02174 
02175 static xsltDebuggerCallbacks xsltDebuggerCurrentCallbacks = {
02176     NULL, /* handler */
02177     NULL, /* add */
02178     NULL  /* drop */
02179 };
02180 
02181 int xslDebugStatus;
02182 
02189 void
02190 xsltSetDebuggerStatus(int value)
02191 {
02192     xslDebugStatus = value; 
02193 }
02194 
02202 int
02203 xsltGetDebuggerStatus(void)
02204 {
02205     return(xslDebugStatus); 
02206 }
02207 
02219 int
02220 xsltSetDebuggerCallbacks(int no, void *block)
02221 {
02222     xsltDebuggerCallbacksPtr callbacks;
02223 
02224     if ((block == NULL) || (no != XSLT_CALLBACK_NUMBER))
02225     return(-1);
02226 
02227     callbacks = (xsltDebuggerCallbacksPtr) block;
02228     xsltDebuggerCurrentCallbacks.handler = callbacks->handler;
02229     xsltDebuggerCurrentCallbacks.add  = callbacks->add;
02230     xsltDebuggerCurrentCallbacks.drop  = callbacks->drop;
02231     return(0);
02232 }
02233 
02245 void
02246 xslHandleDebugger(xmlNodePtr cur, xmlNodePtr node, xsltTemplatePtr templ,
02247               xsltTransformContextPtr ctxt)
02248 {
02249     if (xsltDebuggerCurrentCallbacks.handler != NULL)
02250     xsltDebuggerCurrentCallbacks.handler(cur, node, templ, ctxt);
02251 }
02252 
02262 int
02263 xslAddCall(xsltTemplatePtr templ, xmlNodePtr source)
02264 {
02265     if (xsltDebuggerCurrentCallbacks.add != NULL)
02266     return(xsltDebuggerCurrentCallbacks.add(templ, source));
02267     return(0);
02268 }
02269 
02275 void
02276 xslDropCall(void)
02277 {
02278     if (xsltDebuggerCurrentCallbacks.drop != NULL)
02279     xsltDebuggerCurrentCallbacks.drop();
02280 }
02281 

Generated on Sun May 27 2012 04:19:43 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.