123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396 |
- /*
- * attrvt.c: Implementation of the XSL Transformation 1.0 engine
- * attribute value template handling part.
- *
- * References:
- * http://www.w3.org/TR/1999/REC-xslt-19991116
- *
- * Michael Kay "XSLT Programmer's Reference" pp 637-643
- * Writing Multiple Output Files
- *
- * See Copyright for the status of this software.
- *
- * daniel@veillard.com
- */
- #define IN_LIBXSLT
- #include "libxslt.h"
- #include <string.h>
- #include <libxml/xmlmemory.h>
- #include <libxml/tree.h>
- #include <libxml/xpath.h>
- #include <libxml/xpathInternals.h>
- #include "xslt.h"
- #include "xsltutils.h"
- #include "xsltInternals.h"
- #include "templates.h"
- #ifdef WITH_XSLT_DEBUG
- #define WITH_XSLT_DEBUG_AVT
- #endif
- #define MAX_AVT_SEG 10
- typedef struct _xsltAttrVT xsltAttrVT;
- typedef xsltAttrVT *xsltAttrVTPtr;
- struct _xsltAttrVT {
- struct _xsltAttrVT *next; /* next xsltAttrVT */
- int nb_seg; /* Number of segments */
- int max_seg; /* max capacity before re-alloc needed */
- int strstart; /* is the start a string */
- /*
- * the namespaces in scope
- */
- xmlNsPtr *nsList;
- int nsNr;
- /*
- * the content is an alternate of string and xmlXPathCompExprPtr
- */
- #if __STDC_VERSION__ >= 199901L
- /* Using a C99 flexible array member avoids false positives under UBSan */
- void *segments[];
- #else
- void *segments[1];
- #endif
- };
- /**
- * xsltNewAttrVT:
- * @style: a XSLT process context
- *
- * Build a new xsltAttrVT structure
- *
- * Returns the structure or NULL in case of error
- */
- static xsltAttrVTPtr
- xsltNewAttrVT(xsltStylesheetPtr style) {
- xsltAttrVTPtr cur;
- size_t size = sizeof(xsltAttrVT) + MAX_AVT_SEG * sizeof(void*);
- cur = (xsltAttrVTPtr) xmlMalloc(size);
- if (cur == NULL) {
- xsltTransformError(NULL, style, NULL,
- "xsltNewAttrVTPtr : malloc failed\n");
- if (style != NULL) style->errors++;
- return(NULL);
- }
- memset(cur, 0, size);
- cur->nb_seg = 0;
- cur->max_seg = MAX_AVT_SEG;
- cur->strstart = 0;
- cur->next = style->attVTs;
- /*
- * Note: this pointer may be changed by a re-alloc within xsltCompileAttr,
- * so that code may change the stylesheet pointer also!
- */
- style->attVTs = (xsltAttrVTPtr) cur;
- return(cur);
- }
- /**
- * xsltFreeAttrVT:
- * @avt: pointer to an xsltAttrVT structure
- *
- * Free up the memory associated to the attribute value template
- */
- static void
- xsltFreeAttrVT(xsltAttrVTPtr avt) {
- int i;
- if (avt == NULL) return;
- if (avt->strstart == 1) {
- for (i = 0;i < avt->nb_seg; i += 2)
- if (avt->segments[i] != NULL)
- xmlFree((xmlChar *) avt->segments[i]);
- for (i = 1;i < avt->nb_seg; i += 2)
- xmlXPathFreeCompExpr((xmlXPathCompExprPtr) avt->segments[i]);
- } else {
- for (i = 0;i < avt->nb_seg; i += 2)
- xmlXPathFreeCompExpr((xmlXPathCompExprPtr) avt->segments[i]);
- for (i = 1;i < avt->nb_seg; i += 2)
- if (avt->segments[i] != NULL)
- xmlFree((xmlChar *) avt->segments[i]);
- }
- if (avt->nsList != NULL)
- xmlFree(avt->nsList);
- xmlFree(avt);
- }
- /**
- * xsltFreeAVTList:
- * @avt: pointer to an list of AVT structures
- *
- * Free up the memory associated to the attribute value templates
- */
- void
- xsltFreeAVTList(void *avt) {
- xsltAttrVTPtr cur = (xsltAttrVTPtr) avt, next;
- while (cur != NULL) {
- next = cur->next;
- xsltFreeAttrVT(cur);
- cur = next;
- }
- }
- /**
- * xsltSetAttrVTsegment:
- * @ avt: pointer to an xsltAttrVT structure
- * @ val: the value to be set to the next available segment
- *
- * Within xsltCompileAttr there are several places where a value
- * needs to be added to the 'segments' array within the xsltAttrVT
- * structure, and at each place the allocated size may have to be
- * re-allocated. This routine takes care of that situation.
- *
- * Returns the avt pointer, which may have been changed by a re-alloc
- */
- static xsltAttrVTPtr
- xsltSetAttrVTsegment(xsltAttrVTPtr avt, void *val) {
- if (avt->nb_seg >= avt->max_seg) {
- size_t size = sizeof(xsltAttrVT) +
- (avt->max_seg + MAX_AVT_SEG) * sizeof(void *);
- xsltAttrVTPtr tmp = (xsltAttrVTPtr) xmlRealloc(avt, size);
- if (tmp == NULL) {
- xsltFreeAttrVT(avt);
- return NULL;
- }
- avt = tmp;
- memset(&avt->segments[avt->nb_seg], 0, MAX_AVT_SEG*sizeof(void *));
- avt->max_seg += MAX_AVT_SEG;
- }
- avt->segments[avt->nb_seg++] = val;
- return avt;
- }
- /**
- * xsltCompileAttr:
- * @style: a XSLT process context
- * @attr: the attribute coming from the stylesheet.
- *
- * Precompile an attribute in a stylesheet, basically it checks if it is
- * an attribute value template, and if yes, establish some structures needed
- * to process it at transformation time.
- */
- void
- xsltCompileAttr(xsltStylesheetPtr style, xmlAttrPtr attr) {
- const xmlChar *str;
- const xmlChar *cur;
- xmlChar *ret = NULL;
- xmlChar *expr = NULL;
- xsltAttrVTPtr avt;
- int i = 0, lastavt = 0;
- if ((style == NULL) || (attr == NULL) || (attr->children == NULL))
- return;
- if ((attr->children->type != XML_TEXT_NODE) ||
- (attr->children->next != NULL)) {
- xsltTransformError(NULL, style, attr->parent,
- "Attribute '%s': The content is expected to be a single text "
- "node when compiling an AVT.\n", attr->name);
- style->errors++;
- return;
- }
- str = attr->children->content;
- if ((xmlStrchr(str, '{') == NULL) &&
- (xmlStrchr(str, '}') == NULL)) return;
- #ifdef WITH_XSLT_DEBUG_AVT
- xsltGenericDebug(xsltGenericDebugContext,
- "Found AVT %s: %s\n", attr->name, str);
- #endif
- if (attr->psvi != NULL) {
- #ifdef WITH_XSLT_DEBUG_AVT
- xsltGenericDebug(xsltGenericDebugContext,
- "AVT %s: already compiled\n", attr->name);
- #endif
- return;
- }
- /*
- * Create a new AVT object.
- */
- avt = xsltNewAttrVT(style);
- if (avt == NULL)
- return;
- attr->psvi = avt;
- avt->nsList = xmlGetNsList(attr->doc, attr->parent);
- if (avt->nsList != NULL) {
- while (avt->nsList[i] != NULL)
- i++;
- }
- avt->nsNr = i;
- cur = str;
- while (*cur != 0) {
- if (*cur == '{') {
- if (*(cur+1) == '{') { /* escaped '{' */
- cur++;
- ret = xmlStrncat(ret, str, cur - str);
- cur++;
- str = cur;
- continue;
- }
- if (*(cur+1) == '}') { /* skip empty AVT */
- ret = xmlStrncat(ret, str, cur - str);
- cur += 2;
- str = cur;
- continue;
- }
- if ((ret != NULL) || (cur - str > 0)) {
- ret = xmlStrncat(ret, str, cur - str);
- str = cur;
- if (avt->nb_seg == 0)
- avt->strstart = 1;
- if ((avt = xsltSetAttrVTsegment(avt, (void *) ret)) == NULL)
- goto error;
- ret = NULL;
- lastavt = 0;
- }
- cur++;
- while ((*cur != 0) && (*cur != '}')) {
- /* Need to check for literal (bug539741) */
- if ((*cur == '\'') || (*cur == '"')) {
- char delim = *(cur++);
- while ((*cur != 0) && (*cur != delim))
- cur++;
- if (*cur != 0)
- cur++; /* skip the ending delimiter */
- } else
- cur++;
- }
- if (*cur == 0) {
- xsltTransformError(NULL, style, attr->parent,
- "Attribute '%s': The AVT has an unmatched '{'.\n",
- attr->name);
- style->errors++;
- goto error;
- }
- str++;
- expr = xmlStrndup(str, cur - str);
- if (expr == NULL) {
- /*
- * TODO: What needs to be done here?
- */
- XSLT_TODO
- goto error;
- } else {
- xmlXPathCompExprPtr comp;
- comp = xsltXPathCompile(style, expr);
- if (comp == NULL) {
- xsltTransformError(NULL, style, attr->parent,
- "Attribute '%s': Failed to compile the expression "
- "'%s' in the AVT.\n", attr->name, expr);
- style->errors++;
- goto error;
- }
- if (avt->nb_seg == 0)
- avt->strstart = 0;
- if (lastavt == 1) {
- if ((avt = xsltSetAttrVTsegment(avt, NULL)) == NULL)
- goto error;
- }
- if ((avt = xsltSetAttrVTsegment(avt, (void *) comp)) == NULL)
- goto error;
- lastavt = 1;
- xmlFree(expr);
- expr = NULL;
- }
- cur++;
- str = cur;
- } else if (*cur == '}') {
- cur++;
- if (*cur == '}') { /* escaped '}' */
- ret = xmlStrncat(ret, str, cur - str);
- cur++;
- str = cur;
- continue;
- } else {
- xsltTransformError(NULL, style, attr->parent,
- "Attribute '%s': The AVT has an unmatched '}'.\n",
- attr->name);
- goto error;
- }
- } else
- cur++;
- }
- if ((ret != NULL) || (cur - str > 0)) {
- ret = xmlStrncat(ret, str, cur - str);
- str = cur;
- if (avt->nb_seg == 0)
- avt->strstart = 1;
- if ((avt = xsltSetAttrVTsegment(avt, (void *) ret)) == NULL)
- goto error;
- ret = NULL;
- }
- error:
- if (avt == NULL) {
- xsltTransformError(NULL, style, attr->parent,
- "xsltCompileAttr: malloc problem\n");
- } else {
- if (attr->psvi != avt) { /* may have changed from realloc */
- attr->psvi = avt;
- /*
- * This is a "hack", but I can't see any clean method of
- * doing it. If a re-alloc has taken place, then the pointer
- * for this AVT may have changed. style->attVTs was set by
- * xsltNewAttrVT, so it needs to be re-set to the new value!
- */
- style->attVTs = avt;
- }
- }
- if (ret != NULL)
- xmlFree(ret);
- if (expr != NULL)
- xmlFree(expr);
- }
- /**
- * xsltEvalAVT:
- * @ctxt: the XSLT transformation context
- * @avt: the prevompiled attribute value template info
- * @node: the node hosting the attribute
- *
- * Process the given AVT, and return the new string value.
- *
- * Returns the computed string value or NULL, must be deallocated by the
- * caller.
- */
- xmlChar *
- xsltEvalAVT(xsltTransformContextPtr ctxt, void *avt, xmlNodePtr node) {
- xmlChar *ret = NULL, *tmp;
- xmlXPathCompExprPtr comp;
- xsltAttrVTPtr cur = (xsltAttrVTPtr) avt;
- int i;
- int str;
- if ((ctxt == NULL) || (avt == NULL) || (node == NULL))
- return(NULL);
- str = cur->strstart;
- for (i = 0;i < cur->nb_seg;i++) {
- if (str) {
- ret = xmlStrcat(ret, (const xmlChar *) cur->segments[i]);
- } else {
- comp = (xmlXPathCompExprPtr) cur->segments[i];
- tmp = xsltEvalXPathStringNs(ctxt, comp, cur->nsNr, cur->nsList);
- if (tmp != NULL) {
- if (ret != NULL) {
- ret = xmlStrcat(ret, tmp);
- xmlFree(tmp);
- } else {
- ret = tmp;
- }
- }
- }
- str = !str;
- }
- return(ret);
- }
|