Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
wine-mirror
GitHub Repository: wine-mirror/wine
Path: blob/master/libs/xslt/libxslt/attrvt.c
4389 views
1
/*
2
* attrvt.c: Implementation of the XSL Transformation 1.0 engine
3
* attribute value template handling part.
4
*
5
* References:
6
* http://www.w3.org/TR/1999/REC-xslt-19991116
7
*
8
* Michael Kay "XSLT Programmer's Reference" pp 637-643
9
* Writing Multiple Output Files
10
*
11
* See Copyright for the status of this software.
12
*
13
* [email protected]
14
*/
15
16
#define IN_LIBXSLT
17
#include "libxslt.h"
18
19
#include <string.h>
20
21
#include <libxml/xmlmemory.h>
22
#include <libxml/tree.h>
23
#include <libxml/xpath.h>
24
#include <libxml/xpathInternals.h>
25
#include "xslt.h"
26
#include "xsltutils.h"
27
#include "xsltInternals.h"
28
#include "templates.h"
29
30
#ifdef WITH_XSLT_DEBUG
31
#define WITH_XSLT_DEBUG_AVT
32
#endif
33
34
#define MAX_AVT_SEG 10
35
36
typedef struct _xsltAttrVT xsltAttrVT;
37
typedef xsltAttrVT *xsltAttrVTPtr;
38
struct _xsltAttrVT {
39
struct _xsltAttrVT *next; /* next xsltAttrVT */
40
int nb_seg; /* Number of segments */
41
int max_seg; /* max capacity before re-alloc needed */
42
int strstart; /* is the start a string */
43
/*
44
* the namespaces in scope
45
*/
46
xmlNsPtr *nsList;
47
int nsNr;
48
/*
49
* the content is an alternate of string and xmlXPathCompExprPtr
50
*/
51
#if __STDC_VERSION__ >= 199901L
52
/* Using a C99 flexible array member avoids false positives under UBSan */
53
void *segments[];
54
#else
55
void *segments[1];
56
#endif
57
};
58
59
/**
60
* xsltNewAttrVT:
61
* @style: a XSLT process context
62
*
63
* Build a new xsltAttrVT structure
64
*
65
* Returns the structure or NULL in case of error
66
*/
67
static xsltAttrVTPtr
68
xsltNewAttrVT(xsltStylesheetPtr style) {
69
xsltAttrVTPtr cur;
70
size_t size = sizeof(xsltAttrVT) + MAX_AVT_SEG * sizeof(void*);
71
72
cur = (xsltAttrVTPtr) xmlMalloc(size);
73
if (cur == NULL) {
74
xsltTransformError(NULL, style, NULL,
75
"xsltNewAttrVTPtr : malloc failed\n");
76
if (style != NULL) style->errors++;
77
return(NULL);
78
}
79
memset(cur, 0, size);
80
81
cur->nb_seg = 0;
82
cur->max_seg = MAX_AVT_SEG;
83
cur->strstart = 0;
84
cur->next = style->attVTs;
85
/*
86
* Note: this pointer may be changed by a re-alloc within xsltCompileAttr,
87
* so that code may change the stylesheet pointer also!
88
*/
89
style->attVTs = (xsltAttrVTPtr) cur;
90
91
return(cur);
92
}
93
94
/**
95
* xsltFreeAttrVT:
96
* @avt: pointer to an xsltAttrVT structure
97
*
98
* Free up the memory associated to the attribute value template
99
*/
100
static void
101
xsltFreeAttrVT(xsltAttrVTPtr avt) {
102
int i;
103
104
if (avt == NULL) return;
105
106
if (avt->strstart == 1) {
107
for (i = 0;i < avt->nb_seg; i += 2)
108
if (avt->segments[i] != NULL)
109
xmlFree((xmlChar *) avt->segments[i]);
110
for (i = 1;i < avt->nb_seg; i += 2)
111
xmlXPathFreeCompExpr((xmlXPathCompExprPtr) avt->segments[i]);
112
} else {
113
for (i = 0;i < avt->nb_seg; i += 2)
114
xmlXPathFreeCompExpr((xmlXPathCompExprPtr) avt->segments[i]);
115
for (i = 1;i < avt->nb_seg; i += 2)
116
if (avt->segments[i] != NULL)
117
xmlFree((xmlChar *) avt->segments[i]);
118
}
119
if (avt->nsList != NULL)
120
xmlFree(avt->nsList);
121
xmlFree(avt);
122
}
123
124
/**
125
* xsltFreeAVTList:
126
* @avt: pointer to an list of AVT structures
127
*
128
* Free up the memory associated to the attribute value templates
129
*/
130
void
131
xsltFreeAVTList(void *avt) {
132
xsltAttrVTPtr cur = (xsltAttrVTPtr) avt, next;
133
134
while (cur != NULL) {
135
next = cur->next;
136
xsltFreeAttrVT(cur);
137
cur = next;
138
}
139
}
140
/**
141
* xsltSetAttrVTsegment:
142
* @ avt: pointer to an xsltAttrVT structure
143
* @ val: the value to be set to the next available segment
144
*
145
* Within xsltCompileAttr there are several places where a value
146
* needs to be added to the 'segments' array within the xsltAttrVT
147
* structure, and at each place the allocated size may have to be
148
* re-allocated. This routine takes care of that situation.
149
*
150
* Returns the avt pointer, which may have been changed by a re-alloc
151
*/
152
static xsltAttrVTPtr
153
xsltSetAttrVTsegment(xsltAttrVTPtr avt, void *val) {
154
if (avt->nb_seg >= avt->max_seg) {
155
size_t size = sizeof(xsltAttrVT) +
156
(avt->max_seg + MAX_AVT_SEG) * sizeof(void *);
157
avt = (xsltAttrVTPtr) xmlRealloc(avt, size);
158
if (avt == NULL)
159
return NULL;
160
memset(&avt->segments[avt->nb_seg], 0, MAX_AVT_SEG*sizeof(void *));
161
avt->max_seg += MAX_AVT_SEG;
162
}
163
avt->segments[avt->nb_seg++] = val;
164
return avt;
165
}
166
167
/**
168
* xsltCompileAttr:
169
* @style: a XSLT process context
170
* @attr: the attribute coming from the stylesheet.
171
*
172
* Precompile an attribute in a stylesheet, basically it checks if it is
173
* an attribute value template, and if yes, establish some structures needed
174
* to process it at transformation time.
175
*/
176
void
177
xsltCompileAttr(xsltStylesheetPtr style, xmlAttrPtr attr) {
178
const xmlChar *str;
179
const xmlChar *cur;
180
xmlChar *ret = NULL;
181
xmlChar *expr = NULL;
182
xmlXPathCompExprPtr comp = NULL;
183
xsltAttrVTPtr avt, tmp;
184
int i = 0, lastavt = 0;
185
186
if ((style == NULL) || (attr == NULL) || (attr->children == NULL))
187
return;
188
if ((attr->children->type != XML_TEXT_NODE) ||
189
(attr->children->next != NULL)) {
190
xsltTransformError(NULL, style, attr->parent,
191
"Attribute '%s': The content is expected to be a single text "
192
"node when compiling an AVT.\n", attr->name);
193
style->errors++;
194
return;
195
}
196
str = attr->children->content;
197
if ((xmlStrchr(str, '{') == NULL) &&
198
(xmlStrchr(str, '}') == NULL)) return;
199
200
#ifdef WITH_XSLT_DEBUG_AVT
201
xsltGenericDebug(xsltGenericDebugContext,
202
"Found AVT %s: %s\n", attr->name, str);
203
#endif
204
if (attr->psvi != NULL) {
205
#ifdef WITH_XSLT_DEBUG_AVT
206
xsltGenericDebug(xsltGenericDebugContext,
207
"AVT %s: already compiled\n", attr->name);
208
#endif
209
return;
210
}
211
/*
212
* Create a new AVT object.
213
*/
214
avt = xsltNewAttrVT(style);
215
if (avt == NULL)
216
return;
217
attr->psvi = avt;
218
219
avt->nsList = xmlGetNsList(attr->doc, attr->parent);
220
if (avt->nsList != NULL) {
221
while (avt->nsList[i] != NULL)
222
i++;
223
}
224
avt->nsNr = i;
225
226
cur = str;
227
while (*cur != 0) {
228
if (*cur == '{') {
229
if (*(cur+1) == '{') { /* escaped '{' */
230
cur++;
231
ret = xmlStrncat(ret, str, cur - str);
232
cur++;
233
str = cur;
234
continue;
235
}
236
if (*(cur+1) == '}') { /* skip empty AVT */
237
ret = xmlStrncat(ret, str, cur - str);
238
cur += 2;
239
str = cur;
240
continue;
241
}
242
if ((ret != NULL) || (cur - str > 0)) {
243
ret = xmlStrncat(ret, str, cur - str);
244
str = cur;
245
if (avt->nb_seg == 0)
246
avt->strstart = 1;
247
if ((tmp = xsltSetAttrVTsegment(avt, (void *) ret)) == NULL)
248
goto error;
249
avt = tmp;
250
ret = NULL;
251
lastavt = 0;
252
}
253
254
cur++;
255
while ((*cur != 0) && (*cur != '}')) {
256
/* Need to check for literal (bug539741) */
257
if ((*cur == '\'') || (*cur == '"')) {
258
char delim = *(cur++);
259
while ((*cur != 0) && (*cur != delim))
260
cur++;
261
if (*cur != 0)
262
cur++; /* skip the ending delimiter */
263
} else
264
cur++;
265
}
266
if (*cur == 0) {
267
xsltTransformError(NULL, style, attr->parent,
268
"Attribute '%s': The AVT has an unmatched '{'.\n",
269
attr->name);
270
style->errors++;
271
goto error;
272
}
273
str++;
274
expr = xmlStrndup(str, cur - str);
275
if (expr == NULL) {
276
/*
277
* TODO: What needs to be done here?
278
*/
279
XSLT_TODO
280
goto error;
281
} else {
282
comp = xsltXPathCompile(style, expr);
283
if (comp == NULL) {
284
xsltTransformError(NULL, style, attr->parent,
285
"Attribute '%s': Failed to compile the expression "
286
"'%s' in the AVT.\n", attr->name, expr);
287
style->errors++;
288
goto error;
289
}
290
if (avt->nb_seg == 0)
291
avt->strstart = 0;
292
if (lastavt == 1) {
293
if ((tmp = xsltSetAttrVTsegment(avt, NULL)) == NULL) {
294
xsltTransformError(NULL, style, attr->parent,
295
"out of memory\n");
296
goto error;
297
}
298
avt = tmp;
299
}
300
if ((tmp = xsltSetAttrVTsegment(avt, (void *) comp)) == NULL) {
301
xsltTransformError(NULL, style, attr->parent,
302
"out of memory\n");
303
goto error;
304
}
305
avt = tmp;
306
lastavt = 1;
307
xmlFree(expr);
308
expr = NULL;
309
comp = NULL;
310
}
311
cur++;
312
str = cur;
313
} else if (*cur == '}') {
314
cur++;
315
if (*cur == '}') { /* escaped '}' */
316
ret = xmlStrncat(ret, str, cur - str);
317
cur++;
318
str = cur;
319
continue;
320
} else {
321
xsltTransformError(NULL, style, attr->parent,
322
"Attribute '%s': The AVT has an unmatched '}'.\n",
323
attr->name);
324
goto error;
325
}
326
} else
327
cur++;
328
}
329
if ((ret != NULL) || (cur - str > 0)) {
330
ret = xmlStrncat(ret, str, cur - str);
331
str = cur;
332
if (avt->nb_seg == 0)
333
avt->strstart = 1;
334
if ((tmp = xsltSetAttrVTsegment(avt, (void *) ret)) == NULL)
335
goto error;
336
avt = tmp;
337
ret = NULL;
338
}
339
340
error:
341
if (avt == NULL) {
342
xsltTransformError(NULL, style, attr->parent,
343
"xsltCompileAttr: malloc problem\n");
344
} else {
345
if (attr->psvi != avt) { /* may have changed from realloc */
346
attr->psvi = avt;
347
/*
348
* This is a "hack", but I can't see any clean method of
349
* doing it. If a re-alloc has taken place, then the pointer
350
* for this AVT may have changed. style->attVTs was set by
351
* xsltNewAttrVT, so it needs to be re-set to the new value!
352
*/
353
style->attVTs = avt;
354
}
355
}
356
if (ret != NULL)
357
xmlFree(ret);
358
if (expr != NULL)
359
xmlFree(expr);
360
if (comp != NULL)
361
xmlXPathFreeCompExpr(comp);
362
}
363
364
365
/**
366
* xsltEvalAVT:
367
* @ctxt: the XSLT transformation context
368
* @avt: the prevompiled attribute value template info
369
* @node: the node hosting the attribute
370
*
371
* Process the given AVT, and return the new string value.
372
*
373
* Returns the computed string value or NULL, must be deallocated by the
374
* caller.
375
*/
376
xmlChar *
377
xsltEvalAVT(xsltTransformContextPtr ctxt, void *avt, xmlNodePtr node) {
378
xmlChar *ret = NULL, *tmp;
379
xmlXPathCompExprPtr comp;
380
xsltAttrVTPtr cur = (xsltAttrVTPtr) avt;
381
int i;
382
int str;
383
384
if ((ctxt == NULL) || (avt == NULL) || (node == NULL))
385
return(NULL);
386
str = cur->strstart;
387
for (i = 0;i < cur->nb_seg;i++) {
388
if (str) {
389
ret = xmlStrcat(ret, (const xmlChar *) cur->segments[i]);
390
} else {
391
comp = (xmlXPathCompExprPtr) cur->segments[i];
392
tmp = xsltEvalXPathStringNs(ctxt, comp, cur->nsNr, cur->nsList);
393
if (tmp != NULL) {
394
if (ret != NULL) {
395
ret = xmlStrcat(ret, tmp);
396
xmlFree(tmp);
397
} else {
398
ret = tmp;
399
}
400
}
401
}
402
str = !str;
403
}
404
return(ret);
405
}
406
407