/src/libxml2-2.11.5/relaxng.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * relaxng.c : implementation of the Relax-NG handling and validity checking |
3 | | * |
4 | | * See Copyright for the status of this software. |
5 | | * |
6 | | * Daniel Veillard <veillard@redhat.com> |
7 | | */ |
8 | | |
9 | | /** |
10 | | * TODO: |
11 | | * - add support for DTD compatibility spec |
12 | | * http://www.oasis-open.org/committees/relax-ng/compatibility-20011203.html |
13 | | * - report better mem allocations pbms at runtime and abort immediately. |
14 | | */ |
15 | | |
16 | | #define IN_LIBXML |
17 | | #include "libxml.h" |
18 | | |
19 | | #ifdef LIBXML_SCHEMAS_ENABLED |
20 | | |
21 | | #include <string.h> |
22 | | #include <stdio.h> |
23 | | #include <stddef.h> |
24 | | #include <libxml/xmlmemory.h> |
25 | | #include <libxml/parser.h> |
26 | | #include <libxml/parserInternals.h> |
27 | | #include <libxml/hash.h> |
28 | | #include <libxml/uri.h> |
29 | | |
30 | | #include <libxml/relaxng.h> |
31 | | |
32 | | #include <libxml/xmlschemastypes.h> |
33 | | #include <libxml/xmlautomata.h> |
34 | | #include <libxml/xmlregexp.h> |
35 | | #include <libxml/xmlschemastypes.h> |
36 | | |
37 | | #include "private/error.h" |
38 | | #include "private/regexp.h" |
39 | | #include "private/string.h" |
40 | | |
41 | | /* |
42 | | * The Relax-NG namespace |
43 | | */ |
44 | | static const xmlChar *xmlRelaxNGNs = (const xmlChar *) |
45 | | "http://relaxng.org/ns/structure/1.0"; |
46 | | |
47 | | #define IS_RELAXNG(node, typ) \ |
48 | 0 | ((node != NULL) && (node->ns != NULL) && \ |
49 | 0 | (node->type == XML_ELEMENT_NODE) && \ |
50 | 0 | (xmlStrEqual(node->name, (const xmlChar *) typ)) && \ |
51 | 0 | (xmlStrEqual(node->ns->href, xmlRelaxNGNs))) |
52 | | |
53 | | |
54 | | #if 0 |
55 | | #define DEBUG 1 |
56 | | |
57 | | #define DEBUG_GRAMMAR 1 |
58 | | |
59 | | #define DEBUG_CONTENT 1 |
60 | | |
61 | | #define DEBUG_TYPE 1 |
62 | | |
63 | | #define DEBUG_VALID 1 |
64 | | |
65 | | #define DEBUG_INTERLEAVE 1 |
66 | | |
67 | | #define DEBUG_LIST 1 |
68 | | |
69 | | #define DEBUG_INCLUDE 1 |
70 | | |
71 | | #define DEBUG_ERROR 1 |
72 | | |
73 | | #define DEBUG_COMPILE 1 |
74 | | |
75 | | #define DEBUG_PROGRESSIVE 1 |
76 | | #endif |
77 | | |
78 | 0 | #define MAX_ERROR 5 |
79 | | |
80 | | #define TODO \ |
81 | 0 | xmlGenericError(xmlGenericErrorContext, \ |
82 | 0 | "Unimplemented block at %s:%d\n", \ |
83 | 0 | __FILE__, __LINE__); |
84 | | |
85 | | typedef struct _xmlRelaxNGSchema xmlRelaxNGSchema; |
86 | | typedef xmlRelaxNGSchema *xmlRelaxNGSchemaPtr; |
87 | | |
88 | | typedef struct _xmlRelaxNGDefine xmlRelaxNGDefine; |
89 | | typedef xmlRelaxNGDefine *xmlRelaxNGDefinePtr; |
90 | | |
91 | | typedef struct _xmlRelaxNGDocument xmlRelaxNGDocument; |
92 | | typedef xmlRelaxNGDocument *xmlRelaxNGDocumentPtr; |
93 | | |
94 | | typedef struct _xmlRelaxNGInclude xmlRelaxNGInclude; |
95 | | typedef xmlRelaxNGInclude *xmlRelaxNGIncludePtr; |
96 | | |
97 | | typedef enum { |
98 | | XML_RELAXNG_COMBINE_UNDEFINED = 0, /* undefined */ |
99 | | XML_RELAXNG_COMBINE_CHOICE, /* choice */ |
100 | | XML_RELAXNG_COMBINE_INTERLEAVE /* interleave */ |
101 | | } xmlRelaxNGCombine; |
102 | | |
103 | | typedef enum { |
104 | | XML_RELAXNG_CONTENT_ERROR = -1, |
105 | | XML_RELAXNG_CONTENT_EMPTY = 0, |
106 | | XML_RELAXNG_CONTENT_SIMPLE, |
107 | | XML_RELAXNG_CONTENT_COMPLEX |
108 | | } xmlRelaxNGContentType; |
109 | | |
110 | | typedef struct _xmlRelaxNGGrammar xmlRelaxNGGrammar; |
111 | | typedef xmlRelaxNGGrammar *xmlRelaxNGGrammarPtr; |
112 | | |
113 | | struct _xmlRelaxNGGrammar { |
114 | | xmlRelaxNGGrammarPtr parent; /* the parent grammar if any */ |
115 | | xmlRelaxNGGrammarPtr children; /* the children grammar if any */ |
116 | | xmlRelaxNGGrammarPtr next; /* the next grammar if any */ |
117 | | xmlRelaxNGDefinePtr start; /* <start> content */ |
118 | | xmlRelaxNGCombine combine; /* the default combine value */ |
119 | | xmlRelaxNGDefinePtr startList; /* list of <start> definitions */ |
120 | | xmlHashTablePtr defs; /* define* */ |
121 | | xmlHashTablePtr refs; /* references */ |
122 | | }; |
123 | | |
124 | | |
125 | | typedef enum { |
126 | | XML_RELAXNG_NOOP = -1, /* a no operation from simplification */ |
127 | | XML_RELAXNG_EMPTY = 0, /* an empty pattern */ |
128 | | XML_RELAXNG_NOT_ALLOWED, /* not allowed top */ |
129 | | XML_RELAXNG_EXCEPT, /* except present in nameclass defs */ |
130 | | XML_RELAXNG_TEXT, /* textual content */ |
131 | | XML_RELAXNG_ELEMENT, /* an element */ |
132 | | XML_RELAXNG_DATATYPE, /* external data type definition */ |
133 | | XML_RELAXNG_PARAM, /* external data type parameter */ |
134 | | XML_RELAXNG_VALUE, /* value from an external data type definition */ |
135 | | XML_RELAXNG_LIST, /* a list of patterns */ |
136 | | XML_RELAXNG_ATTRIBUTE, /* an attribute following a pattern */ |
137 | | XML_RELAXNG_DEF, /* a definition */ |
138 | | XML_RELAXNG_REF, /* reference to a definition */ |
139 | | XML_RELAXNG_EXTERNALREF, /* reference to an external def */ |
140 | | XML_RELAXNG_PARENTREF, /* reference to a def in the parent grammar */ |
141 | | XML_RELAXNG_OPTIONAL, /* optional patterns */ |
142 | | XML_RELAXNG_ZEROORMORE, /* zero or more non empty patterns */ |
143 | | XML_RELAXNG_ONEORMORE, /* one or more non empty patterns */ |
144 | | XML_RELAXNG_CHOICE, /* a choice between non empty patterns */ |
145 | | XML_RELAXNG_GROUP, /* a pair/group of non empty patterns */ |
146 | | XML_RELAXNG_INTERLEAVE, /* interleaving choice of non-empty patterns */ |
147 | | XML_RELAXNG_START /* Used to keep track of starts on grammars */ |
148 | | } xmlRelaxNGType; |
149 | | |
150 | 0 | #define IS_NULLABLE (1 << 0) |
151 | 0 | #define IS_NOT_NULLABLE (1 << 1) |
152 | 0 | #define IS_INDETERMINIST (1 << 2) |
153 | 0 | #define IS_MIXED (1 << 3) |
154 | 0 | #define IS_TRIABLE (1 << 4) |
155 | 0 | #define IS_PROCESSED (1 << 5) |
156 | 0 | #define IS_COMPILABLE (1 << 6) |
157 | 0 | #define IS_NOT_COMPILABLE (1 << 7) |
158 | 0 | #define IS_EXTERNAL_REF (1 << 8) |
159 | | |
160 | | struct _xmlRelaxNGDefine { |
161 | | xmlRelaxNGType type; /* the type of definition */ |
162 | | xmlNodePtr node; /* the node in the source */ |
163 | | xmlChar *name; /* the element local name if present */ |
164 | | xmlChar *ns; /* the namespace local name if present */ |
165 | | xmlChar *value; /* value when available */ |
166 | | void *data; /* data lib or specific pointer */ |
167 | | xmlRelaxNGDefinePtr content; /* the expected content */ |
168 | | xmlRelaxNGDefinePtr parent; /* the parent definition, if any */ |
169 | | xmlRelaxNGDefinePtr next; /* list within grouping sequences */ |
170 | | xmlRelaxNGDefinePtr attrs; /* list of attributes for elements */ |
171 | | xmlRelaxNGDefinePtr nameClass; /* the nameClass definition if any */ |
172 | | xmlRelaxNGDefinePtr nextHash; /* next define in defs/refs hash tables */ |
173 | | short depth; /* used for the cycle detection */ |
174 | | short dflags; /* define related flags */ |
175 | | xmlRegexpPtr contModel; /* a compiled content model if available */ |
176 | | }; |
177 | | |
178 | | /** |
179 | | * _xmlRelaxNG: |
180 | | * |
181 | | * A RelaxNGs definition |
182 | | */ |
183 | | struct _xmlRelaxNG { |
184 | | void *_private; /* unused by the library for users or bindings */ |
185 | | xmlRelaxNGGrammarPtr topgrammar; |
186 | | xmlDocPtr doc; |
187 | | |
188 | | int idref; /* requires idref checking */ |
189 | | |
190 | | xmlHashTablePtr defs; /* define */ |
191 | | xmlHashTablePtr refs; /* references */ |
192 | | xmlRelaxNGDocumentPtr documents; /* all the documents loaded */ |
193 | | xmlRelaxNGIncludePtr includes; /* all the includes loaded */ |
194 | | int defNr; /* number of defines used */ |
195 | | xmlRelaxNGDefinePtr *defTab; /* pointer to the allocated definitions */ |
196 | | |
197 | | }; |
198 | | |
199 | 0 | #define XML_RELAXNG_IN_ATTRIBUTE (1 << 0) |
200 | 0 | #define XML_RELAXNG_IN_ONEORMORE (1 << 1) |
201 | 0 | #define XML_RELAXNG_IN_LIST (1 << 2) |
202 | 0 | #define XML_RELAXNG_IN_DATAEXCEPT (1 << 3) |
203 | 0 | #define XML_RELAXNG_IN_START (1 << 4) |
204 | 0 | #define XML_RELAXNG_IN_OOMGROUP (1 << 5) |
205 | 0 | #define XML_RELAXNG_IN_OOMINTERLEAVE (1 << 6) |
206 | 0 | #define XML_RELAXNG_IN_EXTERNALREF (1 << 7) |
207 | 0 | #define XML_RELAXNG_IN_ANYEXCEPT (1 << 8) |
208 | 0 | #define XML_RELAXNG_IN_NSEXCEPT (1 << 9) |
209 | | |
210 | | struct _xmlRelaxNGParserCtxt { |
211 | | void *userData; /* user specific data block */ |
212 | | xmlRelaxNGValidityErrorFunc error; /* the callback in case of errors */ |
213 | | xmlRelaxNGValidityWarningFunc warning; /* the callback in case of warning */ |
214 | | xmlStructuredErrorFunc serror; |
215 | | xmlRelaxNGValidErr err; |
216 | | |
217 | | xmlRelaxNGPtr schema; /* The schema in use */ |
218 | | xmlRelaxNGGrammarPtr grammar; /* the current grammar */ |
219 | | xmlRelaxNGGrammarPtr parentgrammar; /* the parent grammar */ |
220 | | int flags; /* parser flags */ |
221 | | int nbErrors; /* number of errors at parse time */ |
222 | | int nbWarnings; /* number of warnings at parse time */ |
223 | | const xmlChar *define; /* the current define scope */ |
224 | | xmlRelaxNGDefinePtr def; /* the current define */ |
225 | | |
226 | | int nbInterleaves; |
227 | | xmlHashTablePtr interleaves; /* keep track of all the interleaves */ |
228 | | |
229 | | xmlRelaxNGDocumentPtr documents; /* all the documents loaded */ |
230 | | xmlRelaxNGIncludePtr includes; /* all the includes loaded */ |
231 | | xmlChar *URL; |
232 | | xmlDocPtr document; |
233 | | |
234 | | int defNr; /* number of defines used */ |
235 | | int defMax; /* number of defines allocated */ |
236 | | xmlRelaxNGDefinePtr *defTab; /* pointer to the allocated definitions */ |
237 | | |
238 | | const char *buffer; |
239 | | int size; |
240 | | |
241 | | /* the document stack */ |
242 | | xmlRelaxNGDocumentPtr doc; /* Current parsed external ref */ |
243 | | int docNr; /* Depth of the parsing stack */ |
244 | | int docMax; /* Max depth of the parsing stack */ |
245 | | xmlRelaxNGDocumentPtr *docTab; /* array of docs */ |
246 | | |
247 | | /* the include stack */ |
248 | | xmlRelaxNGIncludePtr inc; /* Current parsed include */ |
249 | | int incNr; /* Depth of the include parsing stack */ |
250 | | int incMax; /* Max depth of the parsing stack */ |
251 | | xmlRelaxNGIncludePtr *incTab; /* array of incs */ |
252 | | |
253 | | int idref; /* requires idref checking */ |
254 | | |
255 | | /* used to compile content models */ |
256 | | xmlAutomataPtr am; /* the automata */ |
257 | | xmlAutomataStatePtr state; /* used to build the automata */ |
258 | | |
259 | | int crng; /* compact syntax and other flags */ |
260 | | int freedoc; /* need to free the document */ |
261 | | }; |
262 | | |
263 | 0 | #define FLAGS_IGNORABLE 1 |
264 | 0 | #define FLAGS_NEGATIVE 2 |
265 | 0 | #define FLAGS_MIXED_CONTENT 4 |
266 | 0 | #define FLAGS_NOERROR 8 |
267 | | |
268 | | /** |
269 | | * xmlRelaxNGInterleaveGroup: |
270 | | * |
271 | | * A RelaxNGs partition set associated to lists of definitions |
272 | | */ |
273 | | typedef struct _xmlRelaxNGInterleaveGroup xmlRelaxNGInterleaveGroup; |
274 | | typedef xmlRelaxNGInterleaveGroup *xmlRelaxNGInterleaveGroupPtr; |
275 | | struct _xmlRelaxNGInterleaveGroup { |
276 | | xmlRelaxNGDefinePtr rule; /* the rule to satisfy */ |
277 | | xmlRelaxNGDefinePtr *defs; /* the array of element definitions */ |
278 | | xmlRelaxNGDefinePtr *attrs; /* the array of attributes definitions */ |
279 | | }; |
280 | | |
281 | 0 | #define IS_DETERMINIST 1 |
282 | 0 | #define IS_NEEDCHECK 2 |
283 | | |
284 | | /** |
285 | | * xmlRelaxNGPartitions: |
286 | | * |
287 | | * A RelaxNGs partition associated to an interleave group |
288 | | */ |
289 | | typedef struct _xmlRelaxNGPartition xmlRelaxNGPartition; |
290 | | typedef xmlRelaxNGPartition *xmlRelaxNGPartitionPtr; |
291 | | struct _xmlRelaxNGPartition { |
292 | | int nbgroups; /* number of groups in the partitions */ |
293 | | xmlHashTablePtr triage; /* hash table used to direct nodes to the |
294 | | * right group when possible */ |
295 | | int flags; /* determinist ? */ |
296 | | xmlRelaxNGInterleaveGroupPtr *groups; |
297 | | }; |
298 | | |
299 | | /** |
300 | | * xmlRelaxNGValidState: |
301 | | * |
302 | | * A RelaxNGs validation state |
303 | | */ |
304 | 0 | #define MAX_ATTR 20 |
305 | | typedef struct _xmlRelaxNGValidState xmlRelaxNGValidState; |
306 | | typedef xmlRelaxNGValidState *xmlRelaxNGValidStatePtr; |
307 | | struct _xmlRelaxNGValidState { |
308 | | xmlNodePtr node; /* the current node */ |
309 | | xmlNodePtr seq; /* the sequence of children left to validate */ |
310 | | int nbAttrs; /* the number of attributes */ |
311 | | int maxAttrs; /* the size of attrs */ |
312 | | int nbAttrLeft; /* the number of attributes left to validate */ |
313 | | xmlChar *value; /* the value when operating on string */ |
314 | | xmlChar *endvalue; /* the end value when operating on string */ |
315 | | xmlAttrPtr *attrs; /* the array of attributes */ |
316 | | }; |
317 | | |
318 | | /** |
319 | | * xmlRelaxNGStates: |
320 | | * |
321 | | * A RelaxNGs container for validation state |
322 | | */ |
323 | | typedef struct _xmlRelaxNGStates xmlRelaxNGStates; |
324 | | typedef xmlRelaxNGStates *xmlRelaxNGStatesPtr; |
325 | | struct _xmlRelaxNGStates { |
326 | | int nbState; /* the number of states */ |
327 | | int maxState; /* the size of the array */ |
328 | | xmlRelaxNGValidStatePtr *tabState; |
329 | | }; |
330 | | |
331 | 0 | #define ERROR_IS_DUP 1 |
332 | | |
333 | | /** |
334 | | * xmlRelaxNGValidError: |
335 | | * |
336 | | * A RelaxNGs validation error |
337 | | */ |
338 | | typedef struct _xmlRelaxNGValidError xmlRelaxNGValidError; |
339 | | typedef xmlRelaxNGValidError *xmlRelaxNGValidErrorPtr; |
340 | | struct _xmlRelaxNGValidError { |
341 | | xmlRelaxNGValidErr err; /* the error number */ |
342 | | int flags; /* flags */ |
343 | | xmlNodePtr node; /* the current node */ |
344 | | xmlNodePtr seq; /* the current child */ |
345 | | const xmlChar *arg1; /* first arg */ |
346 | | const xmlChar *arg2; /* second arg */ |
347 | | }; |
348 | | |
349 | | /** |
350 | | * xmlRelaxNGValidCtxt: |
351 | | * |
352 | | * A RelaxNGs validation context |
353 | | */ |
354 | | |
355 | | struct _xmlRelaxNGValidCtxt { |
356 | | void *userData; /* user specific data block */ |
357 | | xmlRelaxNGValidityErrorFunc error; /* the callback in case of errors */ |
358 | | xmlRelaxNGValidityWarningFunc warning; /* the callback in case of warning */ |
359 | | xmlStructuredErrorFunc serror; |
360 | | int nbErrors; /* number of errors in validation */ |
361 | | |
362 | | xmlRelaxNGPtr schema; /* The schema in use */ |
363 | | xmlDocPtr doc; /* the document being validated */ |
364 | | int flags; /* validation flags */ |
365 | | int depth; /* validation depth */ |
366 | | int idref; /* requires idref checking */ |
367 | | int errNo; /* the first error found */ |
368 | | |
369 | | /* |
370 | | * Errors accumulated in branches may have to be stacked to be |
371 | | * provided back when it's sure they affect validation. |
372 | | */ |
373 | | xmlRelaxNGValidErrorPtr err; /* Last error */ |
374 | | int errNr; /* Depth of the error stack */ |
375 | | int errMax; /* Max depth of the error stack */ |
376 | | xmlRelaxNGValidErrorPtr errTab; /* stack of errors */ |
377 | | |
378 | | xmlRelaxNGValidStatePtr state; /* the current validation state */ |
379 | | xmlRelaxNGStatesPtr states; /* the accumulated state list */ |
380 | | |
381 | | xmlRelaxNGStatesPtr freeState; /* the pool of free valid states */ |
382 | | int freeStatesNr; |
383 | | int freeStatesMax; |
384 | | xmlRelaxNGStatesPtr *freeStates; /* the pool of free state groups */ |
385 | | |
386 | | /* |
387 | | * This is used for "progressive" validation |
388 | | */ |
389 | | xmlRegExecCtxtPtr elem; /* the current element regexp */ |
390 | | int elemNr; /* the number of element validated */ |
391 | | int elemMax; /* the max depth of elements */ |
392 | | xmlRegExecCtxtPtr *elemTab; /* the stack of regexp runtime */ |
393 | | int pstate; /* progressive state */ |
394 | | xmlNodePtr pnode; /* the current node */ |
395 | | xmlRelaxNGDefinePtr pdef; /* the non-streamable definition */ |
396 | | int perr; /* signal error in content model |
397 | | * outside the regexp */ |
398 | | }; |
399 | | |
400 | | /** |
401 | | * xmlRelaxNGInclude: |
402 | | * |
403 | | * Structure associated to a RelaxNGs document element |
404 | | */ |
405 | | struct _xmlRelaxNGInclude { |
406 | | xmlRelaxNGIncludePtr next; /* keep a chain of includes */ |
407 | | xmlChar *href; /* the normalized href value */ |
408 | | xmlDocPtr doc; /* the associated XML document */ |
409 | | xmlRelaxNGDefinePtr content; /* the definitions */ |
410 | | xmlRelaxNGPtr schema; /* the schema */ |
411 | | }; |
412 | | |
413 | | /** |
414 | | * xmlRelaxNGDocument: |
415 | | * |
416 | | * Structure associated to a RelaxNGs document element |
417 | | */ |
418 | | struct _xmlRelaxNGDocument { |
419 | | xmlRelaxNGDocumentPtr next; /* keep a chain of documents */ |
420 | | xmlChar *href; /* the normalized href value */ |
421 | | xmlDocPtr doc; /* the associated XML document */ |
422 | | xmlRelaxNGDefinePtr content; /* the definitions */ |
423 | | xmlRelaxNGPtr schema; /* the schema */ |
424 | | int externalRef; /* 1 if an external ref */ |
425 | | }; |
426 | | |
427 | | |
428 | | /************************************************************************ |
429 | | * * |
430 | | * Some factorized error routines * |
431 | | * * |
432 | | ************************************************************************/ |
433 | | |
434 | | /** |
435 | | * xmlRngPErrMemory: |
436 | | * @ctxt: an Relax-NG parser context |
437 | | * @extra: extra information |
438 | | * |
439 | | * Handle a redefinition of attribute error |
440 | | */ |
441 | | static void |
442 | | xmlRngPErrMemory(xmlRelaxNGParserCtxtPtr ctxt, const char *extra) |
443 | 0 | { |
444 | 0 | xmlStructuredErrorFunc schannel = NULL; |
445 | 0 | xmlGenericErrorFunc channel = NULL; |
446 | 0 | void *data = NULL; |
447 | |
|
448 | 0 | if (ctxt != NULL) { |
449 | 0 | if (ctxt->serror != NULL) |
450 | 0 | schannel = ctxt->serror; |
451 | 0 | else |
452 | 0 | channel = ctxt->error; |
453 | 0 | data = ctxt->userData; |
454 | 0 | ctxt->nbErrors++; |
455 | 0 | } |
456 | 0 | if (extra) |
457 | 0 | __xmlRaiseError(schannel, channel, data, |
458 | 0 | NULL, NULL, XML_FROM_RELAXNGP, |
459 | 0 | XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, extra, |
460 | 0 | NULL, NULL, 0, 0, |
461 | 0 | "Memory allocation failed : %s\n", extra); |
462 | 0 | else |
463 | 0 | __xmlRaiseError(schannel, channel, data, |
464 | 0 | NULL, NULL, XML_FROM_RELAXNGP, |
465 | 0 | XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, NULL, |
466 | 0 | NULL, NULL, 0, 0, "Memory allocation failed\n"); |
467 | 0 | } |
468 | | |
469 | | /** |
470 | | * xmlRngVErrMemory: |
471 | | * @ctxt: a Relax-NG validation context |
472 | | * @extra: extra information |
473 | | * |
474 | | * Handle a redefinition of attribute error |
475 | | */ |
476 | | static void |
477 | | xmlRngVErrMemory(xmlRelaxNGValidCtxtPtr ctxt, const char *extra) |
478 | 0 | { |
479 | 0 | xmlStructuredErrorFunc schannel = NULL; |
480 | 0 | xmlGenericErrorFunc channel = NULL; |
481 | 0 | void *data = NULL; |
482 | |
|
483 | 0 | if (ctxt != NULL) { |
484 | 0 | if (ctxt->serror != NULL) |
485 | 0 | schannel = ctxt->serror; |
486 | 0 | else |
487 | 0 | channel = ctxt->error; |
488 | 0 | data = ctxt->userData; |
489 | 0 | ctxt->nbErrors++; |
490 | 0 | } |
491 | 0 | if (extra) |
492 | 0 | __xmlRaiseError(schannel, channel, data, |
493 | 0 | NULL, NULL, XML_FROM_RELAXNGV, |
494 | 0 | XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, extra, |
495 | 0 | NULL, NULL, 0, 0, |
496 | 0 | "Memory allocation failed : %s\n", extra); |
497 | 0 | else |
498 | 0 | __xmlRaiseError(schannel, channel, data, |
499 | 0 | NULL, NULL, XML_FROM_RELAXNGV, |
500 | 0 | XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, NULL, |
501 | 0 | NULL, NULL, 0, 0, "Memory allocation failed\n"); |
502 | 0 | } |
503 | | |
504 | | /** |
505 | | * xmlRngPErr: |
506 | | * @ctxt: a Relax-NG parser context |
507 | | * @node: the node raising the error |
508 | | * @error: the error code |
509 | | * @msg: message |
510 | | * @str1: extra info |
511 | | * @str2: extra info |
512 | | * |
513 | | * Handle a Relax NG Parsing error |
514 | | */ |
515 | | static void LIBXML_ATTR_FORMAT(4,0) |
516 | | xmlRngPErr(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node, int error, |
517 | | const char *msg, const xmlChar * str1, const xmlChar * str2) |
518 | 0 | { |
519 | 0 | xmlStructuredErrorFunc schannel = NULL; |
520 | 0 | xmlGenericErrorFunc channel = NULL; |
521 | 0 | void *data = NULL; |
522 | |
|
523 | 0 | if (ctxt != NULL) { |
524 | 0 | if (ctxt->serror != NULL) |
525 | 0 | schannel = ctxt->serror; |
526 | 0 | else |
527 | 0 | channel = ctxt->error; |
528 | 0 | data = ctxt->userData; |
529 | 0 | ctxt->nbErrors++; |
530 | 0 | } |
531 | 0 | __xmlRaiseError(schannel, channel, data, |
532 | 0 | NULL, node, XML_FROM_RELAXNGP, |
533 | 0 | error, XML_ERR_ERROR, NULL, 0, |
534 | 0 | (const char *) str1, (const char *) str2, NULL, 0, 0, |
535 | 0 | msg, str1, str2); |
536 | 0 | } |
537 | | |
538 | | /** |
539 | | * xmlRngVErr: |
540 | | * @ctxt: a Relax-NG validation context |
541 | | * @node: the node raising the error |
542 | | * @error: the error code |
543 | | * @msg: message |
544 | | * @str1: extra info |
545 | | * @str2: extra info |
546 | | * |
547 | | * Handle a Relax NG Validation error |
548 | | */ |
549 | | static void LIBXML_ATTR_FORMAT(4,0) |
550 | | xmlRngVErr(xmlRelaxNGValidCtxtPtr ctxt, xmlNodePtr node, int error, |
551 | | const char *msg, const xmlChar * str1, const xmlChar * str2) |
552 | 0 | { |
553 | 0 | xmlStructuredErrorFunc schannel = NULL; |
554 | 0 | xmlGenericErrorFunc channel = NULL; |
555 | 0 | void *data = NULL; |
556 | |
|
557 | 0 | if (ctxt != NULL) { |
558 | 0 | if (ctxt->serror != NULL) |
559 | 0 | schannel = ctxt->serror; |
560 | 0 | else |
561 | 0 | channel = ctxt->error; |
562 | 0 | data = ctxt->userData; |
563 | 0 | ctxt->nbErrors++; |
564 | 0 | } |
565 | 0 | __xmlRaiseError(schannel, channel, data, |
566 | 0 | NULL, node, XML_FROM_RELAXNGV, |
567 | 0 | error, XML_ERR_ERROR, NULL, 0, |
568 | 0 | (const char *) str1, (const char *) str2, NULL, 0, 0, |
569 | 0 | msg, str1, str2); |
570 | 0 | } |
571 | | |
572 | | /************************************************************************ |
573 | | * * |
574 | | * Preliminary type checking interfaces * |
575 | | * * |
576 | | ************************************************************************/ |
577 | | |
578 | | /** |
579 | | * xmlRelaxNGTypeHave: |
580 | | * @data: data needed for the library |
581 | | * @type: the type name |
582 | | * @value: the value to check |
583 | | * |
584 | | * Function provided by a type library to check if a type is exported |
585 | | * |
586 | | * Returns 1 if yes, 0 if no and -1 in case of error. |
587 | | */ |
588 | | typedef int (*xmlRelaxNGTypeHave) (void *data, const xmlChar * type); |
589 | | |
590 | | /** |
591 | | * xmlRelaxNGTypeCheck: |
592 | | * @data: data needed for the library |
593 | | * @type: the type name |
594 | | * @value: the value to check |
595 | | * @result: place to store the result if needed |
596 | | * |
597 | | * Function provided by a type library to check if a value match a type |
598 | | * |
599 | | * Returns 1 if yes, 0 if no and -1 in case of error. |
600 | | */ |
601 | | typedef int (*xmlRelaxNGTypeCheck) (void *data, const xmlChar * type, |
602 | | const xmlChar * value, void **result, |
603 | | xmlNodePtr node); |
604 | | |
605 | | /** |
606 | | * xmlRelaxNGFacetCheck: |
607 | | * @data: data needed for the library |
608 | | * @type: the type name |
609 | | * @facet: the facet name |
610 | | * @val: the facet value |
611 | | * @strval: the string value |
612 | | * @value: the value to check |
613 | | * |
614 | | * Function provided by a type library to check a value facet |
615 | | * |
616 | | * Returns 1 if yes, 0 if no and -1 in case of error. |
617 | | */ |
618 | | typedef int (*xmlRelaxNGFacetCheck) (void *data, const xmlChar * type, |
619 | | const xmlChar * facet, |
620 | | const xmlChar * val, |
621 | | const xmlChar * strval, void *value); |
622 | | |
623 | | /** |
624 | | * xmlRelaxNGTypeFree: |
625 | | * @data: data needed for the library |
626 | | * @result: the value to free |
627 | | * |
628 | | * Function provided by a type library to free a returned result |
629 | | */ |
630 | | typedef void (*xmlRelaxNGTypeFree) (void *data, void *result); |
631 | | |
632 | | /** |
633 | | * xmlRelaxNGTypeCompare: |
634 | | * @data: data needed for the library |
635 | | * @type: the type name |
636 | | * @value1: the first value |
637 | | * @value2: the second value |
638 | | * |
639 | | * Function provided by a type library to compare two values accordingly |
640 | | * to a type. |
641 | | * |
642 | | * Returns 1 if yes, 0 if no and -1 in case of error. |
643 | | */ |
644 | | typedef int (*xmlRelaxNGTypeCompare) (void *data, const xmlChar * type, |
645 | | const xmlChar * value1, |
646 | | xmlNodePtr ctxt1, |
647 | | void *comp1, |
648 | | const xmlChar * value2, |
649 | | xmlNodePtr ctxt2); |
650 | | typedef struct _xmlRelaxNGTypeLibrary xmlRelaxNGTypeLibrary; |
651 | | typedef xmlRelaxNGTypeLibrary *xmlRelaxNGTypeLibraryPtr; |
652 | | struct _xmlRelaxNGTypeLibrary { |
653 | | const xmlChar *namespace; /* the datatypeLibrary value */ |
654 | | void *data; /* data needed for the library */ |
655 | | xmlRelaxNGTypeHave have; /* the export function */ |
656 | | xmlRelaxNGTypeCheck check; /* the checking function */ |
657 | | xmlRelaxNGTypeCompare comp; /* the compare function */ |
658 | | xmlRelaxNGFacetCheck facet; /* the facet check function */ |
659 | | xmlRelaxNGTypeFree freef; /* the freeing function */ |
660 | | }; |
661 | | |
662 | | /************************************************************************ |
663 | | * * |
664 | | * Allocation functions * |
665 | | * * |
666 | | ************************************************************************/ |
667 | | static void xmlRelaxNGFreeGrammar(xmlRelaxNGGrammarPtr grammar); |
668 | | static void xmlRelaxNGFreeDefine(xmlRelaxNGDefinePtr define); |
669 | | static void xmlRelaxNGNormExtSpace(xmlChar * value); |
670 | | static void xmlRelaxNGFreeInnerSchema(xmlRelaxNGPtr schema); |
671 | | static int xmlRelaxNGEqualValidState(xmlRelaxNGValidCtxtPtr ctxt |
672 | | ATTRIBUTE_UNUSED, |
673 | | xmlRelaxNGValidStatePtr state1, |
674 | | xmlRelaxNGValidStatePtr state2); |
675 | | static void xmlRelaxNGFreeValidState(xmlRelaxNGValidCtxtPtr ctxt, |
676 | | xmlRelaxNGValidStatePtr state); |
677 | | |
678 | | /** |
679 | | * xmlRelaxNGFreeDocument: |
680 | | * @docu: a document structure |
681 | | * |
682 | | * Deallocate a RelaxNG document structure. |
683 | | */ |
684 | | static void |
685 | | xmlRelaxNGFreeDocument(xmlRelaxNGDocumentPtr docu) |
686 | 0 | { |
687 | 0 | if (docu == NULL) |
688 | 0 | return; |
689 | | |
690 | 0 | if (docu->href != NULL) |
691 | 0 | xmlFree(docu->href); |
692 | 0 | if (docu->doc != NULL) |
693 | 0 | xmlFreeDoc(docu->doc); |
694 | 0 | if (docu->schema != NULL) |
695 | 0 | xmlRelaxNGFreeInnerSchema(docu->schema); |
696 | 0 | xmlFree(docu); |
697 | 0 | } |
698 | | |
699 | | /** |
700 | | * xmlRelaxNGFreeDocumentList: |
701 | | * @docu: a list of document structure |
702 | | * |
703 | | * Deallocate a RelaxNG document structures. |
704 | | */ |
705 | | static void |
706 | | xmlRelaxNGFreeDocumentList(xmlRelaxNGDocumentPtr docu) |
707 | 0 | { |
708 | 0 | xmlRelaxNGDocumentPtr next; |
709 | |
|
710 | 0 | while (docu != NULL) { |
711 | 0 | next = docu->next; |
712 | 0 | xmlRelaxNGFreeDocument(docu); |
713 | 0 | docu = next; |
714 | 0 | } |
715 | 0 | } |
716 | | |
717 | | /** |
718 | | * xmlRelaxNGFreeInclude: |
719 | | * @incl: a include structure |
720 | | * |
721 | | * Deallocate a RelaxNG include structure. |
722 | | */ |
723 | | static void |
724 | | xmlRelaxNGFreeInclude(xmlRelaxNGIncludePtr incl) |
725 | 0 | { |
726 | 0 | if (incl == NULL) |
727 | 0 | return; |
728 | | |
729 | 0 | if (incl->href != NULL) |
730 | 0 | xmlFree(incl->href); |
731 | 0 | if (incl->doc != NULL) |
732 | 0 | xmlFreeDoc(incl->doc); |
733 | 0 | if (incl->schema != NULL) |
734 | 0 | xmlRelaxNGFree(incl->schema); |
735 | 0 | xmlFree(incl); |
736 | 0 | } |
737 | | |
738 | | /** |
739 | | * xmlRelaxNGFreeIncludeList: |
740 | | * @incl: a include structure list |
741 | | * |
742 | | * Deallocate a RelaxNG include structure. |
743 | | */ |
744 | | static void |
745 | | xmlRelaxNGFreeIncludeList(xmlRelaxNGIncludePtr incl) |
746 | 0 | { |
747 | 0 | xmlRelaxNGIncludePtr next; |
748 | |
|
749 | 0 | while (incl != NULL) { |
750 | 0 | next = incl->next; |
751 | 0 | xmlRelaxNGFreeInclude(incl); |
752 | 0 | incl = next; |
753 | 0 | } |
754 | 0 | } |
755 | | |
756 | | /** |
757 | | * xmlRelaxNGNewRelaxNG: |
758 | | * @ctxt: a Relax-NG validation context (optional) |
759 | | * |
760 | | * Allocate a new RelaxNG structure. |
761 | | * |
762 | | * Returns the newly allocated structure or NULL in case or error |
763 | | */ |
764 | | static xmlRelaxNGPtr |
765 | | xmlRelaxNGNewRelaxNG(xmlRelaxNGParserCtxtPtr ctxt) |
766 | 0 | { |
767 | 0 | xmlRelaxNGPtr ret; |
768 | |
|
769 | 0 | ret = (xmlRelaxNGPtr) xmlMalloc(sizeof(xmlRelaxNG)); |
770 | 0 | if (ret == NULL) { |
771 | 0 | xmlRngPErrMemory(ctxt, NULL); |
772 | 0 | return (NULL); |
773 | 0 | } |
774 | 0 | memset(ret, 0, sizeof(xmlRelaxNG)); |
775 | |
|
776 | 0 | return (ret); |
777 | 0 | } |
778 | | |
779 | | /** |
780 | | * xmlRelaxNGFreeInnerSchema: |
781 | | * @schema: a schema structure |
782 | | * |
783 | | * Deallocate a RelaxNG schema structure. |
784 | | */ |
785 | | static void |
786 | | xmlRelaxNGFreeInnerSchema(xmlRelaxNGPtr schema) |
787 | 0 | { |
788 | 0 | if (schema == NULL) |
789 | 0 | return; |
790 | | |
791 | 0 | if (schema->doc != NULL) |
792 | 0 | xmlFreeDoc(schema->doc); |
793 | 0 | if (schema->defTab != NULL) { |
794 | 0 | int i; |
795 | |
|
796 | 0 | for (i = 0; i < schema->defNr; i++) |
797 | 0 | xmlRelaxNGFreeDefine(schema->defTab[i]); |
798 | 0 | xmlFree(schema->defTab); |
799 | 0 | } |
800 | |
|
801 | 0 | xmlFree(schema); |
802 | 0 | } |
803 | | |
804 | | /** |
805 | | * xmlRelaxNGFree: |
806 | | * @schema: a schema structure |
807 | | * |
808 | | * Deallocate a RelaxNG structure. |
809 | | */ |
810 | | void |
811 | | xmlRelaxNGFree(xmlRelaxNGPtr schema) |
812 | 0 | { |
813 | 0 | if (schema == NULL) |
814 | 0 | return; |
815 | | |
816 | 0 | if (schema->topgrammar != NULL) |
817 | 0 | xmlRelaxNGFreeGrammar(schema->topgrammar); |
818 | 0 | if (schema->doc != NULL) |
819 | 0 | xmlFreeDoc(schema->doc); |
820 | 0 | if (schema->documents != NULL) |
821 | 0 | xmlRelaxNGFreeDocumentList(schema->documents); |
822 | 0 | if (schema->includes != NULL) |
823 | 0 | xmlRelaxNGFreeIncludeList(schema->includes); |
824 | 0 | if (schema->defTab != NULL) { |
825 | 0 | int i; |
826 | |
|
827 | 0 | for (i = 0; i < schema->defNr; i++) |
828 | 0 | xmlRelaxNGFreeDefine(schema->defTab[i]); |
829 | 0 | xmlFree(schema->defTab); |
830 | 0 | } |
831 | |
|
832 | 0 | xmlFree(schema); |
833 | 0 | } |
834 | | |
835 | | /** |
836 | | * xmlRelaxNGNewGrammar: |
837 | | * @ctxt: a Relax-NG validation context (optional) |
838 | | * |
839 | | * Allocate a new RelaxNG grammar. |
840 | | * |
841 | | * Returns the newly allocated structure or NULL in case or error |
842 | | */ |
843 | | static xmlRelaxNGGrammarPtr |
844 | | xmlRelaxNGNewGrammar(xmlRelaxNGParserCtxtPtr ctxt) |
845 | 0 | { |
846 | 0 | xmlRelaxNGGrammarPtr ret; |
847 | |
|
848 | 0 | ret = (xmlRelaxNGGrammarPtr) xmlMalloc(sizeof(xmlRelaxNGGrammar)); |
849 | 0 | if (ret == NULL) { |
850 | 0 | xmlRngPErrMemory(ctxt, NULL); |
851 | 0 | return (NULL); |
852 | 0 | } |
853 | 0 | memset(ret, 0, sizeof(xmlRelaxNGGrammar)); |
854 | |
|
855 | 0 | return (ret); |
856 | 0 | } |
857 | | |
858 | | /** |
859 | | * xmlRelaxNGFreeGrammar: |
860 | | * @grammar: a grammar structure |
861 | | * |
862 | | * Deallocate a RelaxNG grammar structure. |
863 | | */ |
864 | | static void |
865 | | xmlRelaxNGFreeGrammar(xmlRelaxNGGrammarPtr grammar) |
866 | 0 | { |
867 | 0 | if (grammar == NULL) |
868 | 0 | return; |
869 | | |
870 | 0 | if (grammar->children != NULL) { |
871 | 0 | xmlRelaxNGFreeGrammar(grammar->children); |
872 | 0 | } |
873 | 0 | if (grammar->next != NULL) { |
874 | 0 | xmlRelaxNGFreeGrammar(grammar->next); |
875 | 0 | } |
876 | 0 | if (grammar->refs != NULL) { |
877 | 0 | xmlHashFree(grammar->refs, NULL); |
878 | 0 | } |
879 | 0 | if (grammar->defs != NULL) { |
880 | 0 | xmlHashFree(grammar->defs, NULL); |
881 | 0 | } |
882 | |
|
883 | 0 | xmlFree(grammar); |
884 | 0 | } |
885 | | |
886 | | /** |
887 | | * xmlRelaxNGNewDefine: |
888 | | * @ctxt: a Relax-NG validation context |
889 | | * @node: the node in the input document. |
890 | | * |
891 | | * Allocate a new RelaxNG define. |
892 | | * |
893 | | * Returns the newly allocated structure or NULL in case or error |
894 | | */ |
895 | | static xmlRelaxNGDefinePtr |
896 | | xmlRelaxNGNewDefine(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) |
897 | 0 | { |
898 | 0 | xmlRelaxNGDefinePtr ret; |
899 | |
|
900 | 0 | if (ctxt->defMax == 0) { |
901 | 0 | ctxt->defMax = 16; |
902 | 0 | ctxt->defNr = 0; |
903 | 0 | ctxt->defTab = (xmlRelaxNGDefinePtr *) |
904 | 0 | xmlMalloc(ctxt->defMax * sizeof(xmlRelaxNGDefinePtr)); |
905 | 0 | if (ctxt->defTab == NULL) { |
906 | 0 | xmlRngPErrMemory(ctxt, "allocating define\n"); |
907 | 0 | return (NULL); |
908 | 0 | } |
909 | 0 | } else if (ctxt->defMax <= ctxt->defNr) { |
910 | 0 | xmlRelaxNGDefinePtr *tmp; |
911 | |
|
912 | 0 | ctxt->defMax *= 2; |
913 | 0 | tmp = (xmlRelaxNGDefinePtr *) xmlRealloc(ctxt->defTab, |
914 | 0 | ctxt->defMax * |
915 | 0 | sizeof |
916 | 0 | (xmlRelaxNGDefinePtr)); |
917 | 0 | if (tmp == NULL) { |
918 | 0 | xmlRngPErrMemory(ctxt, "allocating define\n"); |
919 | 0 | return (NULL); |
920 | 0 | } |
921 | 0 | ctxt->defTab = tmp; |
922 | 0 | } |
923 | 0 | ret = (xmlRelaxNGDefinePtr) xmlMalloc(sizeof(xmlRelaxNGDefine)); |
924 | 0 | if (ret == NULL) { |
925 | 0 | xmlRngPErrMemory(ctxt, "allocating define\n"); |
926 | 0 | return (NULL); |
927 | 0 | } |
928 | 0 | memset(ret, 0, sizeof(xmlRelaxNGDefine)); |
929 | 0 | ctxt->defTab[ctxt->defNr++] = ret; |
930 | 0 | ret->node = node; |
931 | 0 | ret->depth = -1; |
932 | 0 | return (ret); |
933 | 0 | } |
934 | | |
935 | | /** |
936 | | * xmlRelaxNGFreePartition: |
937 | | * @partitions: a partition set structure |
938 | | * |
939 | | * Deallocate RelaxNG partition set structures. |
940 | | */ |
941 | | static void |
942 | | xmlRelaxNGFreePartition(xmlRelaxNGPartitionPtr partitions) |
943 | 0 | { |
944 | 0 | xmlRelaxNGInterleaveGroupPtr group; |
945 | 0 | int j; |
946 | |
|
947 | 0 | if (partitions != NULL) { |
948 | 0 | if (partitions->groups != NULL) { |
949 | 0 | for (j = 0; j < partitions->nbgroups; j++) { |
950 | 0 | group = partitions->groups[j]; |
951 | 0 | if (group != NULL) { |
952 | 0 | if (group->defs != NULL) |
953 | 0 | xmlFree(group->defs); |
954 | 0 | if (group->attrs != NULL) |
955 | 0 | xmlFree(group->attrs); |
956 | 0 | xmlFree(group); |
957 | 0 | } |
958 | 0 | } |
959 | 0 | xmlFree(partitions->groups); |
960 | 0 | } |
961 | 0 | if (partitions->triage != NULL) { |
962 | 0 | xmlHashFree(partitions->triage, NULL); |
963 | 0 | } |
964 | 0 | xmlFree(partitions); |
965 | 0 | } |
966 | 0 | } |
967 | | |
968 | | /** |
969 | | * xmlRelaxNGFreeDefine: |
970 | | * @define: a define structure |
971 | | * |
972 | | * Deallocate a RelaxNG define structure. |
973 | | */ |
974 | | static void |
975 | | xmlRelaxNGFreeDefine(xmlRelaxNGDefinePtr define) |
976 | 0 | { |
977 | 0 | if (define == NULL) |
978 | 0 | return; |
979 | | |
980 | 0 | if ((define->type == XML_RELAXNG_VALUE) && (define->attrs != NULL)) { |
981 | 0 | xmlRelaxNGTypeLibraryPtr lib; |
982 | |
|
983 | 0 | lib = (xmlRelaxNGTypeLibraryPtr) define->data; |
984 | 0 | if ((lib != NULL) && (lib->freef != NULL)) |
985 | 0 | lib->freef(lib->data, (void *) define->attrs); |
986 | 0 | } |
987 | 0 | if ((define->data != NULL) && (define->type == XML_RELAXNG_INTERLEAVE)) |
988 | 0 | xmlRelaxNGFreePartition((xmlRelaxNGPartitionPtr) define->data); |
989 | 0 | if ((define->data != NULL) && (define->type == XML_RELAXNG_CHOICE)) |
990 | 0 | xmlHashFree((xmlHashTablePtr) define->data, NULL); |
991 | 0 | if (define->name != NULL) |
992 | 0 | xmlFree(define->name); |
993 | 0 | if (define->ns != NULL) |
994 | 0 | xmlFree(define->ns); |
995 | 0 | if (define->value != NULL) |
996 | 0 | xmlFree(define->value); |
997 | 0 | if (define->contModel != NULL) |
998 | 0 | xmlRegFreeRegexp(define->contModel); |
999 | 0 | xmlFree(define); |
1000 | 0 | } |
1001 | | |
1002 | | /** |
1003 | | * xmlRelaxNGNewStates: |
1004 | | * @ctxt: a Relax-NG validation context |
1005 | | * @size: the default size for the container |
1006 | | * |
1007 | | * Allocate a new RelaxNG validation state container |
1008 | | * |
1009 | | * Returns the newly allocated structure or NULL in case or error |
1010 | | */ |
1011 | | static xmlRelaxNGStatesPtr |
1012 | | xmlRelaxNGNewStates(xmlRelaxNGValidCtxtPtr ctxt, int size) |
1013 | 0 | { |
1014 | 0 | xmlRelaxNGStatesPtr ret; |
1015 | |
|
1016 | 0 | if ((ctxt != NULL) && |
1017 | 0 | (ctxt->freeStates != NULL) && (ctxt->freeStatesNr > 0)) { |
1018 | 0 | ctxt->freeStatesNr--; |
1019 | 0 | ret = ctxt->freeStates[ctxt->freeStatesNr]; |
1020 | 0 | ret->nbState = 0; |
1021 | 0 | return (ret); |
1022 | 0 | } |
1023 | 0 | if (size < 16) |
1024 | 0 | size = 16; |
1025 | |
|
1026 | 0 | ret = (xmlRelaxNGStatesPtr) xmlMalloc(sizeof(xmlRelaxNGStates) + |
1027 | 0 | (size - |
1028 | 0 | 1) * |
1029 | 0 | sizeof(xmlRelaxNGValidStatePtr)); |
1030 | 0 | if (ret == NULL) { |
1031 | 0 | xmlRngVErrMemory(ctxt, "allocating states\n"); |
1032 | 0 | return (NULL); |
1033 | 0 | } |
1034 | 0 | ret->nbState = 0; |
1035 | 0 | ret->maxState = size; |
1036 | 0 | ret->tabState = (xmlRelaxNGValidStatePtr *) xmlMalloc((size) * |
1037 | 0 | sizeof |
1038 | 0 | (xmlRelaxNGValidStatePtr)); |
1039 | 0 | if (ret->tabState == NULL) { |
1040 | 0 | xmlRngVErrMemory(ctxt, "allocating states\n"); |
1041 | 0 | xmlFree(ret); |
1042 | 0 | return (NULL); |
1043 | 0 | } |
1044 | 0 | return (ret); |
1045 | 0 | } |
1046 | | |
1047 | | /** |
1048 | | * xmlRelaxNGAddStateUniq: |
1049 | | * @ctxt: a Relax-NG validation context |
1050 | | * @states: the states container |
1051 | | * @state: the validation state |
1052 | | * |
1053 | | * Add a RelaxNG validation state to the container without checking |
1054 | | * for unicity. |
1055 | | * |
1056 | | * Return 1 in case of success and 0 if this is a duplicate and -1 on error |
1057 | | */ |
1058 | | static int |
1059 | | xmlRelaxNGAddStatesUniq(xmlRelaxNGValidCtxtPtr ctxt, |
1060 | | xmlRelaxNGStatesPtr states, |
1061 | | xmlRelaxNGValidStatePtr state) |
1062 | 0 | { |
1063 | 0 | if (state == NULL) { |
1064 | 0 | return (-1); |
1065 | 0 | } |
1066 | 0 | if (states->nbState >= states->maxState) { |
1067 | 0 | xmlRelaxNGValidStatePtr *tmp; |
1068 | 0 | int size; |
1069 | |
|
1070 | 0 | size = states->maxState * 2; |
1071 | 0 | tmp = (xmlRelaxNGValidStatePtr *) xmlRealloc(states->tabState, |
1072 | 0 | (size) * |
1073 | 0 | sizeof |
1074 | 0 | (xmlRelaxNGValidStatePtr)); |
1075 | 0 | if (tmp == NULL) { |
1076 | 0 | xmlRngVErrMemory(ctxt, "adding states\n"); |
1077 | 0 | return (-1); |
1078 | 0 | } |
1079 | 0 | states->tabState = tmp; |
1080 | 0 | states->maxState = size; |
1081 | 0 | } |
1082 | 0 | states->tabState[states->nbState++] = state; |
1083 | 0 | return (1); |
1084 | 0 | } |
1085 | | |
1086 | | /** |
1087 | | * xmlRelaxNGAddState: |
1088 | | * @ctxt: a Relax-NG validation context |
1089 | | * @states: the states container |
1090 | | * @state: the validation state |
1091 | | * |
1092 | | * Add a RelaxNG validation state to the container |
1093 | | * |
1094 | | * Return 1 in case of success and 0 if this is a duplicate and -1 on error |
1095 | | */ |
1096 | | static int |
1097 | | xmlRelaxNGAddStates(xmlRelaxNGValidCtxtPtr ctxt, |
1098 | | xmlRelaxNGStatesPtr states, |
1099 | | xmlRelaxNGValidStatePtr state) |
1100 | 0 | { |
1101 | 0 | int i; |
1102 | |
|
1103 | 0 | if (state == NULL || states == NULL) { |
1104 | 0 | return (-1); |
1105 | 0 | } |
1106 | 0 | if (states->nbState >= states->maxState) { |
1107 | 0 | xmlRelaxNGValidStatePtr *tmp; |
1108 | 0 | int size; |
1109 | |
|
1110 | 0 | size = states->maxState * 2; |
1111 | 0 | tmp = (xmlRelaxNGValidStatePtr *) xmlRealloc(states->tabState, |
1112 | 0 | (size) * |
1113 | 0 | sizeof |
1114 | 0 | (xmlRelaxNGValidStatePtr)); |
1115 | 0 | if (tmp == NULL) { |
1116 | 0 | xmlRngVErrMemory(ctxt, "adding states\n"); |
1117 | 0 | return (-1); |
1118 | 0 | } |
1119 | 0 | states->tabState = tmp; |
1120 | 0 | states->maxState = size; |
1121 | 0 | } |
1122 | 0 | for (i = 0; i < states->nbState; i++) { |
1123 | 0 | if (xmlRelaxNGEqualValidState(ctxt, state, states->tabState[i])) { |
1124 | 0 | xmlRelaxNGFreeValidState(ctxt, state); |
1125 | 0 | return (0); |
1126 | 0 | } |
1127 | 0 | } |
1128 | 0 | states->tabState[states->nbState++] = state; |
1129 | 0 | return (1); |
1130 | 0 | } |
1131 | | |
1132 | | /** |
1133 | | * xmlRelaxNGFreeStates: |
1134 | | * @ctxt: a Relax-NG validation context |
1135 | | * @states: the container |
1136 | | * |
1137 | | * Free a RelaxNG validation state container |
1138 | | */ |
1139 | | static void |
1140 | | xmlRelaxNGFreeStates(xmlRelaxNGValidCtxtPtr ctxt, |
1141 | | xmlRelaxNGStatesPtr states) |
1142 | 0 | { |
1143 | 0 | if (states == NULL) |
1144 | 0 | return; |
1145 | 0 | if ((ctxt != NULL) && (ctxt->freeStates == NULL)) { |
1146 | 0 | ctxt->freeStatesMax = 40; |
1147 | 0 | ctxt->freeStatesNr = 0; |
1148 | 0 | ctxt->freeStates = (xmlRelaxNGStatesPtr *) |
1149 | 0 | xmlMalloc(ctxt->freeStatesMax * sizeof(xmlRelaxNGStatesPtr)); |
1150 | 0 | if (ctxt->freeStates == NULL) { |
1151 | 0 | xmlRngVErrMemory(ctxt, "storing states\n"); |
1152 | 0 | } |
1153 | 0 | } else if ((ctxt != NULL) |
1154 | 0 | && (ctxt->freeStatesNr >= ctxt->freeStatesMax)) { |
1155 | 0 | xmlRelaxNGStatesPtr *tmp; |
1156 | |
|
1157 | 0 | tmp = (xmlRelaxNGStatesPtr *) xmlRealloc(ctxt->freeStates, |
1158 | 0 | 2 * ctxt->freeStatesMax * |
1159 | 0 | sizeof |
1160 | 0 | (xmlRelaxNGStatesPtr)); |
1161 | 0 | if (tmp == NULL) { |
1162 | 0 | xmlRngVErrMemory(ctxt, "storing states\n"); |
1163 | 0 | xmlFree(states->tabState); |
1164 | 0 | xmlFree(states); |
1165 | 0 | return; |
1166 | 0 | } |
1167 | 0 | ctxt->freeStates = tmp; |
1168 | 0 | ctxt->freeStatesMax *= 2; |
1169 | 0 | } |
1170 | 0 | if ((ctxt == NULL) || (ctxt->freeStates == NULL)) { |
1171 | 0 | xmlFree(states->tabState); |
1172 | 0 | xmlFree(states); |
1173 | 0 | } else { |
1174 | 0 | ctxt->freeStates[ctxt->freeStatesNr++] = states; |
1175 | 0 | } |
1176 | 0 | } |
1177 | | |
1178 | | /** |
1179 | | * xmlRelaxNGNewValidState: |
1180 | | * @ctxt: a Relax-NG validation context |
1181 | | * @node: the current node or NULL for the document |
1182 | | * |
1183 | | * Allocate a new RelaxNG validation state |
1184 | | * |
1185 | | * Returns the newly allocated structure or NULL in case or error |
1186 | | */ |
1187 | | static xmlRelaxNGValidStatePtr |
1188 | | xmlRelaxNGNewValidState(xmlRelaxNGValidCtxtPtr ctxt, xmlNodePtr node) |
1189 | 0 | { |
1190 | 0 | xmlRelaxNGValidStatePtr ret; |
1191 | 0 | xmlAttrPtr attr; |
1192 | 0 | xmlAttrPtr attrs[MAX_ATTR]; |
1193 | 0 | int nbAttrs = 0; |
1194 | 0 | xmlNodePtr root = NULL; |
1195 | |
|
1196 | 0 | if (node == NULL) { |
1197 | 0 | root = xmlDocGetRootElement(ctxt->doc); |
1198 | 0 | if (root == NULL) |
1199 | 0 | return (NULL); |
1200 | 0 | } else { |
1201 | 0 | attr = node->properties; |
1202 | 0 | while (attr != NULL) { |
1203 | 0 | if (nbAttrs < MAX_ATTR) |
1204 | 0 | attrs[nbAttrs++] = attr; |
1205 | 0 | else |
1206 | 0 | nbAttrs++; |
1207 | 0 | attr = attr->next; |
1208 | 0 | } |
1209 | 0 | } |
1210 | 0 | if ((ctxt->freeState != NULL) && (ctxt->freeState->nbState > 0)) { |
1211 | 0 | ctxt->freeState->nbState--; |
1212 | 0 | ret = ctxt->freeState->tabState[ctxt->freeState->nbState]; |
1213 | 0 | } else { |
1214 | 0 | ret = |
1215 | 0 | (xmlRelaxNGValidStatePtr) |
1216 | 0 | xmlMalloc(sizeof(xmlRelaxNGValidState)); |
1217 | 0 | if (ret == NULL) { |
1218 | 0 | xmlRngVErrMemory(ctxt, "allocating states\n"); |
1219 | 0 | return (NULL); |
1220 | 0 | } |
1221 | 0 | memset(ret, 0, sizeof(xmlRelaxNGValidState)); |
1222 | 0 | } |
1223 | 0 | ret->value = NULL; |
1224 | 0 | ret->endvalue = NULL; |
1225 | 0 | if (node == NULL) { |
1226 | 0 | ret->node = (xmlNodePtr) ctxt->doc; |
1227 | 0 | ret->seq = root; |
1228 | 0 | } else { |
1229 | 0 | ret->node = node; |
1230 | 0 | ret->seq = node->children; |
1231 | 0 | } |
1232 | 0 | ret->nbAttrs = 0; |
1233 | 0 | if (nbAttrs > 0) { |
1234 | 0 | if (ret->attrs == NULL) { |
1235 | 0 | if (nbAttrs < 4) |
1236 | 0 | ret->maxAttrs = 4; |
1237 | 0 | else |
1238 | 0 | ret->maxAttrs = nbAttrs; |
1239 | 0 | ret->attrs = (xmlAttrPtr *) xmlMalloc(ret->maxAttrs * |
1240 | 0 | sizeof(xmlAttrPtr)); |
1241 | 0 | if (ret->attrs == NULL) { |
1242 | 0 | xmlRngVErrMemory(ctxt, "allocating states\n"); |
1243 | 0 | return (ret); |
1244 | 0 | } |
1245 | 0 | } else if (ret->maxAttrs < nbAttrs) { |
1246 | 0 | xmlAttrPtr *tmp; |
1247 | |
|
1248 | 0 | tmp = (xmlAttrPtr *) xmlRealloc(ret->attrs, nbAttrs * |
1249 | 0 | sizeof(xmlAttrPtr)); |
1250 | 0 | if (tmp == NULL) { |
1251 | 0 | xmlRngVErrMemory(ctxt, "allocating states\n"); |
1252 | 0 | return (ret); |
1253 | 0 | } |
1254 | 0 | ret->attrs = tmp; |
1255 | 0 | ret->maxAttrs = nbAttrs; |
1256 | 0 | } |
1257 | 0 | ret->nbAttrs = nbAttrs; |
1258 | 0 | if (nbAttrs < MAX_ATTR) { |
1259 | 0 | memcpy(ret->attrs, attrs, sizeof(xmlAttrPtr) * nbAttrs); |
1260 | 0 | } else { |
1261 | 0 | attr = node->properties; |
1262 | 0 | nbAttrs = 0; |
1263 | 0 | while (attr != NULL) { |
1264 | 0 | ret->attrs[nbAttrs++] = attr; |
1265 | 0 | attr = attr->next; |
1266 | 0 | } |
1267 | 0 | } |
1268 | 0 | } |
1269 | 0 | ret->nbAttrLeft = ret->nbAttrs; |
1270 | 0 | return (ret); |
1271 | 0 | } |
1272 | | |
1273 | | /** |
1274 | | * xmlRelaxNGCopyValidState: |
1275 | | * @ctxt: a Relax-NG validation context |
1276 | | * @state: a validation state |
1277 | | * |
1278 | | * Copy the validation state |
1279 | | * |
1280 | | * Returns the newly allocated structure or NULL in case or error |
1281 | | */ |
1282 | | static xmlRelaxNGValidStatePtr |
1283 | | xmlRelaxNGCopyValidState(xmlRelaxNGValidCtxtPtr ctxt, |
1284 | | xmlRelaxNGValidStatePtr state) |
1285 | 0 | { |
1286 | 0 | xmlRelaxNGValidStatePtr ret; |
1287 | 0 | unsigned int maxAttrs; |
1288 | 0 | xmlAttrPtr *attrs; |
1289 | |
|
1290 | 0 | if (state == NULL) |
1291 | 0 | return (NULL); |
1292 | 0 | if ((ctxt->freeState != NULL) && (ctxt->freeState->nbState > 0)) { |
1293 | 0 | ctxt->freeState->nbState--; |
1294 | 0 | ret = ctxt->freeState->tabState[ctxt->freeState->nbState]; |
1295 | 0 | } else { |
1296 | 0 | ret = |
1297 | 0 | (xmlRelaxNGValidStatePtr) |
1298 | 0 | xmlMalloc(sizeof(xmlRelaxNGValidState)); |
1299 | 0 | if (ret == NULL) { |
1300 | 0 | xmlRngVErrMemory(ctxt, "allocating states\n"); |
1301 | 0 | return (NULL); |
1302 | 0 | } |
1303 | 0 | memset(ret, 0, sizeof(xmlRelaxNGValidState)); |
1304 | 0 | } |
1305 | 0 | attrs = ret->attrs; |
1306 | 0 | maxAttrs = ret->maxAttrs; |
1307 | 0 | memcpy(ret, state, sizeof(xmlRelaxNGValidState)); |
1308 | 0 | ret->attrs = attrs; |
1309 | 0 | ret->maxAttrs = maxAttrs; |
1310 | 0 | if (state->nbAttrs > 0) { |
1311 | 0 | if (ret->attrs == NULL) { |
1312 | 0 | ret->maxAttrs = state->maxAttrs; |
1313 | 0 | ret->attrs = (xmlAttrPtr *) xmlMalloc(ret->maxAttrs * |
1314 | 0 | sizeof(xmlAttrPtr)); |
1315 | 0 | if (ret->attrs == NULL) { |
1316 | 0 | xmlRngVErrMemory(ctxt, "allocating states\n"); |
1317 | 0 | ret->nbAttrs = 0; |
1318 | 0 | return (ret); |
1319 | 0 | } |
1320 | 0 | } else if (ret->maxAttrs < state->nbAttrs) { |
1321 | 0 | xmlAttrPtr *tmp; |
1322 | |
|
1323 | 0 | tmp = (xmlAttrPtr *) xmlRealloc(ret->attrs, state->maxAttrs * |
1324 | 0 | sizeof(xmlAttrPtr)); |
1325 | 0 | if (tmp == NULL) { |
1326 | 0 | xmlRngVErrMemory(ctxt, "allocating states\n"); |
1327 | 0 | ret->nbAttrs = 0; |
1328 | 0 | return (ret); |
1329 | 0 | } |
1330 | 0 | ret->maxAttrs = state->maxAttrs; |
1331 | 0 | ret->attrs = tmp; |
1332 | 0 | } |
1333 | 0 | memcpy(ret->attrs, state->attrs, |
1334 | 0 | state->nbAttrs * sizeof(xmlAttrPtr)); |
1335 | 0 | } |
1336 | 0 | return (ret); |
1337 | 0 | } |
1338 | | |
1339 | | /** |
1340 | | * xmlRelaxNGEqualValidState: |
1341 | | * @ctxt: a Relax-NG validation context |
1342 | | * @state1: a validation state |
1343 | | * @state2: a validation state |
1344 | | * |
1345 | | * Compare the validation states for equality |
1346 | | * |
1347 | | * Returns 1 if equal, 0 otherwise |
1348 | | */ |
1349 | | static int |
1350 | | xmlRelaxNGEqualValidState(xmlRelaxNGValidCtxtPtr ctxt ATTRIBUTE_UNUSED, |
1351 | | xmlRelaxNGValidStatePtr state1, |
1352 | | xmlRelaxNGValidStatePtr state2) |
1353 | 0 | { |
1354 | 0 | int i; |
1355 | |
|
1356 | 0 | if ((state1 == NULL) || (state2 == NULL)) |
1357 | 0 | return (0); |
1358 | 0 | if (state1 == state2) |
1359 | 0 | return (1); |
1360 | 0 | if (state1->node != state2->node) |
1361 | 0 | return (0); |
1362 | 0 | if (state1->seq != state2->seq) |
1363 | 0 | return (0); |
1364 | 0 | if (state1->nbAttrLeft != state2->nbAttrLeft) |
1365 | 0 | return (0); |
1366 | 0 | if (state1->nbAttrs != state2->nbAttrs) |
1367 | 0 | return (0); |
1368 | 0 | if (state1->endvalue != state2->endvalue) |
1369 | 0 | return (0); |
1370 | 0 | if ((state1->value != state2->value) && |
1371 | 0 | (!xmlStrEqual(state1->value, state2->value))) |
1372 | 0 | return (0); |
1373 | 0 | for (i = 0; i < state1->nbAttrs; i++) { |
1374 | 0 | if (state1->attrs[i] != state2->attrs[i]) |
1375 | 0 | return (0); |
1376 | 0 | } |
1377 | 0 | return (1); |
1378 | 0 | } |
1379 | | |
1380 | | /** |
1381 | | * xmlRelaxNGFreeValidState: |
1382 | | * @state: a validation state structure |
1383 | | * |
1384 | | * Deallocate a RelaxNG validation state structure. |
1385 | | */ |
1386 | | static void |
1387 | | xmlRelaxNGFreeValidState(xmlRelaxNGValidCtxtPtr ctxt, |
1388 | | xmlRelaxNGValidStatePtr state) |
1389 | 0 | { |
1390 | 0 | if (state == NULL) |
1391 | 0 | return; |
1392 | | |
1393 | 0 | if ((ctxt != NULL) && (ctxt->freeState == NULL)) { |
1394 | 0 | ctxt->freeState = xmlRelaxNGNewStates(ctxt, 40); |
1395 | 0 | } |
1396 | 0 | if ((ctxt == NULL) || (ctxt->freeState == NULL)) { |
1397 | 0 | if (state->attrs != NULL) |
1398 | 0 | xmlFree(state->attrs); |
1399 | 0 | xmlFree(state); |
1400 | 0 | } else { |
1401 | 0 | xmlRelaxNGAddStatesUniq(ctxt, ctxt->freeState, state); |
1402 | 0 | } |
1403 | 0 | } |
1404 | | |
1405 | | /************************************************************************ |
1406 | | * * |
1407 | | * Semi internal functions * |
1408 | | * * |
1409 | | ************************************************************************/ |
1410 | | |
1411 | | /** |
1412 | | * xmlRelaxParserSetFlag: |
1413 | | * @ctxt: a RelaxNG parser context |
1414 | | * @flags: a set of flags values |
1415 | | * |
1416 | | * Semi private function used to pass information to a parser context |
1417 | | * which are a combination of xmlRelaxNGParserFlag . |
1418 | | * |
1419 | | * Returns 0 if success and -1 in case of error |
1420 | | */ |
1421 | | int |
1422 | | xmlRelaxParserSetFlag(xmlRelaxNGParserCtxtPtr ctxt, int flags) |
1423 | 0 | { |
1424 | 0 | if (ctxt == NULL) return(-1); |
1425 | 0 | if (flags & XML_RELAXNGP_FREE_DOC) { |
1426 | 0 | ctxt->crng |= XML_RELAXNGP_FREE_DOC; |
1427 | 0 | flags -= XML_RELAXNGP_FREE_DOC; |
1428 | 0 | } |
1429 | 0 | if (flags & XML_RELAXNGP_CRNG) { |
1430 | 0 | ctxt->crng |= XML_RELAXNGP_CRNG; |
1431 | 0 | flags -= XML_RELAXNGP_CRNG; |
1432 | 0 | } |
1433 | 0 | if (flags != 0) return(-1); |
1434 | 0 | return(0); |
1435 | 0 | } |
1436 | | |
1437 | | /************************************************************************ |
1438 | | * * |
1439 | | * Document functions * |
1440 | | * * |
1441 | | ************************************************************************/ |
1442 | | static xmlDocPtr xmlRelaxNGCleanupDoc(xmlRelaxNGParserCtxtPtr ctxt, |
1443 | | xmlDocPtr doc); |
1444 | | |
1445 | | /** |
1446 | | * xmlRelaxNGIncludePush: |
1447 | | * @ctxt: the parser context |
1448 | | * @value: the element doc |
1449 | | * |
1450 | | * Pushes a new include on top of the include stack |
1451 | | * |
1452 | | * Returns 0 in case of error, the index in the stack otherwise |
1453 | | */ |
1454 | | static int |
1455 | | xmlRelaxNGIncludePush(xmlRelaxNGParserCtxtPtr ctxt, |
1456 | | xmlRelaxNGIncludePtr value) |
1457 | 0 | { |
1458 | 0 | if (ctxt->incTab == NULL) { |
1459 | 0 | ctxt->incMax = 4; |
1460 | 0 | ctxt->incNr = 0; |
1461 | 0 | ctxt->incTab = |
1462 | 0 | (xmlRelaxNGIncludePtr *) xmlMalloc(ctxt->incMax * |
1463 | 0 | sizeof(ctxt->incTab[0])); |
1464 | 0 | if (ctxt->incTab == NULL) { |
1465 | 0 | xmlRngPErrMemory(ctxt, "allocating include\n"); |
1466 | 0 | return (0); |
1467 | 0 | } |
1468 | 0 | } |
1469 | 0 | if (ctxt->incNr >= ctxt->incMax) { |
1470 | 0 | ctxt->incMax *= 2; |
1471 | 0 | ctxt->incTab = |
1472 | 0 | (xmlRelaxNGIncludePtr *) xmlRealloc(ctxt->incTab, |
1473 | 0 | ctxt->incMax * |
1474 | 0 | sizeof(ctxt->incTab[0])); |
1475 | 0 | if (ctxt->incTab == NULL) { |
1476 | 0 | xmlRngPErrMemory(ctxt, "allocating include\n"); |
1477 | 0 | return (0); |
1478 | 0 | } |
1479 | 0 | } |
1480 | 0 | ctxt->incTab[ctxt->incNr] = value; |
1481 | 0 | ctxt->inc = value; |
1482 | 0 | return (ctxt->incNr++); |
1483 | 0 | } |
1484 | | |
1485 | | /** |
1486 | | * xmlRelaxNGIncludePop: |
1487 | | * @ctxt: the parser context |
1488 | | * |
1489 | | * Pops the top include from the include stack |
1490 | | * |
1491 | | * Returns the include just removed |
1492 | | */ |
1493 | | static xmlRelaxNGIncludePtr |
1494 | | xmlRelaxNGIncludePop(xmlRelaxNGParserCtxtPtr ctxt) |
1495 | 0 | { |
1496 | 0 | xmlRelaxNGIncludePtr ret; |
1497 | |
|
1498 | 0 | if (ctxt->incNr <= 0) |
1499 | 0 | return (NULL); |
1500 | 0 | ctxt->incNr--; |
1501 | 0 | if (ctxt->incNr > 0) |
1502 | 0 | ctxt->inc = ctxt->incTab[ctxt->incNr - 1]; |
1503 | 0 | else |
1504 | 0 | ctxt->inc = NULL; |
1505 | 0 | ret = ctxt->incTab[ctxt->incNr]; |
1506 | 0 | ctxt->incTab[ctxt->incNr] = NULL; |
1507 | 0 | return (ret); |
1508 | 0 | } |
1509 | | |
1510 | | /** |
1511 | | * xmlRelaxNGRemoveRedefine: |
1512 | | * @ctxt: the parser context |
1513 | | * @URL: the normalized URL |
1514 | | * @target: the included target |
1515 | | * @name: the define name to eliminate |
1516 | | * |
1517 | | * Applies the elimination algorithm of 4.7 |
1518 | | * |
1519 | | * Returns 0 in case of error, 1 in case of success. |
1520 | | */ |
1521 | | static int |
1522 | | xmlRelaxNGRemoveRedefine(xmlRelaxNGParserCtxtPtr ctxt, |
1523 | | const xmlChar * URL ATTRIBUTE_UNUSED, |
1524 | | xmlNodePtr target, const xmlChar * name) |
1525 | 0 | { |
1526 | 0 | int found = 0; |
1527 | 0 | xmlNodePtr tmp, tmp2; |
1528 | 0 | xmlChar *name2; |
1529 | |
|
1530 | | #ifdef DEBUG_INCLUDE |
1531 | | if (name == NULL) |
1532 | | xmlGenericError(xmlGenericErrorContext, |
1533 | | "Elimination of <include> start from %s\n", URL); |
1534 | | else |
1535 | | xmlGenericError(xmlGenericErrorContext, |
1536 | | "Elimination of <include> define %s from %s\n", |
1537 | | name, URL); |
1538 | | #endif |
1539 | 0 | tmp = target; |
1540 | 0 | while (tmp != NULL) { |
1541 | 0 | tmp2 = tmp->next; |
1542 | 0 | if ((name == NULL) && (IS_RELAXNG(tmp, "start"))) { |
1543 | 0 | found = 1; |
1544 | 0 | xmlUnlinkNode(tmp); |
1545 | 0 | xmlFreeNode(tmp); |
1546 | 0 | } else if ((name != NULL) && (IS_RELAXNG(tmp, "define"))) { |
1547 | 0 | name2 = xmlGetProp(tmp, BAD_CAST "name"); |
1548 | 0 | xmlRelaxNGNormExtSpace(name2); |
1549 | 0 | if (name2 != NULL) { |
1550 | 0 | if (xmlStrEqual(name, name2)) { |
1551 | 0 | found = 1; |
1552 | 0 | xmlUnlinkNode(tmp); |
1553 | 0 | xmlFreeNode(tmp); |
1554 | 0 | } |
1555 | 0 | xmlFree(name2); |
1556 | 0 | } |
1557 | 0 | } else if (IS_RELAXNG(tmp, "include")) { |
1558 | 0 | xmlChar *href = NULL; |
1559 | 0 | xmlRelaxNGDocumentPtr inc = tmp->psvi; |
1560 | |
|
1561 | 0 | if ((inc != NULL) && (inc->doc != NULL) && |
1562 | 0 | (inc->doc->children != NULL)) { |
1563 | |
|
1564 | 0 | if (xmlStrEqual |
1565 | 0 | (inc->doc->children->name, BAD_CAST "grammar")) { |
1566 | | #ifdef DEBUG_INCLUDE |
1567 | | href = xmlGetProp(tmp, BAD_CAST "href"); |
1568 | | #endif |
1569 | 0 | if (xmlRelaxNGRemoveRedefine(ctxt, href, |
1570 | 0 | xmlDocGetRootElement(inc->doc)->children, |
1571 | 0 | name) == 1) { |
1572 | 0 | found = 1; |
1573 | 0 | } |
1574 | | #ifdef DEBUG_INCLUDE |
1575 | | if (href != NULL) |
1576 | | xmlFree(href); |
1577 | | #endif |
1578 | 0 | } |
1579 | 0 | } |
1580 | 0 | if (xmlRelaxNGRemoveRedefine(ctxt, URL, tmp->children, name) == 1) { |
1581 | 0 | found = 1; |
1582 | 0 | } |
1583 | 0 | } |
1584 | 0 | tmp = tmp2; |
1585 | 0 | } |
1586 | 0 | return (found); |
1587 | 0 | } |
1588 | | |
1589 | | /** |
1590 | | * xmlRelaxNGLoadInclude: |
1591 | | * @ctxt: the parser context |
1592 | | * @URL: the normalized URL |
1593 | | * @node: the include node. |
1594 | | * @ns: the namespace passed from the context. |
1595 | | * |
1596 | | * First lookup if the document is already loaded into the parser context, |
1597 | | * check against recursion. If not found the resource is loaded and |
1598 | | * the content is preprocessed before being returned back to the caller. |
1599 | | * |
1600 | | * Returns the xmlRelaxNGIncludePtr or NULL in case of error |
1601 | | */ |
1602 | | static xmlRelaxNGIncludePtr |
1603 | | xmlRelaxNGLoadInclude(xmlRelaxNGParserCtxtPtr ctxt, const xmlChar * URL, |
1604 | | xmlNodePtr node, const xmlChar * ns) |
1605 | 0 | { |
1606 | 0 | xmlRelaxNGIncludePtr ret = NULL; |
1607 | 0 | xmlDocPtr doc; |
1608 | 0 | int i; |
1609 | 0 | xmlNodePtr root, cur; |
1610 | |
|
1611 | | #ifdef DEBUG_INCLUDE |
1612 | | xmlGenericError(xmlGenericErrorContext, |
1613 | | "xmlRelaxNGLoadInclude(%s)\n", URL); |
1614 | | #endif |
1615 | | |
1616 | | /* |
1617 | | * check against recursion in the stack |
1618 | | */ |
1619 | 0 | for (i = 0; i < ctxt->incNr; i++) { |
1620 | 0 | if (xmlStrEqual(ctxt->incTab[i]->href, URL)) { |
1621 | 0 | xmlRngPErr(ctxt, NULL, XML_RNGP_INCLUDE_RECURSE, |
1622 | 0 | "Detected an Include recursion for %s\n", URL, |
1623 | 0 | NULL); |
1624 | 0 | return (NULL); |
1625 | 0 | } |
1626 | 0 | } |
1627 | | |
1628 | | /* |
1629 | | * load the document |
1630 | | */ |
1631 | 0 | doc = xmlReadFile((const char *) URL,NULL,0); |
1632 | 0 | if (doc == NULL) { |
1633 | 0 | xmlRngPErr(ctxt, node, XML_RNGP_PARSE_ERROR, |
1634 | 0 | "xmlRelaxNG: could not load %s\n", URL, NULL); |
1635 | 0 | return (NULL); |
1636 | 0 | } |
1637 | | #ifdef DEBUG_INCLUDE |
1638 | | xmlGenericError(xmlGenericErrorContext, "Parsed %s Okay\n", URL); |
1639 | | #endif |
1640 | | |
1641 | | /* |
1642 | | * Allocate the document structures and register it first. |
1643 | | */ |
1644 | 0 | ret = (xmlRelaxNGIncludePtr) xmlMalloc(sizeof(xmlRelaxNGInclude)); |
1645 | 0 | if (ret == NULL) { |
1646 | 0 | xmlRngPErrMemory(ctxt, "allocating include\n"); |
1647 | 0 | xmlFreeDoc(doc); |
1648 | 0 | return (NULL); |
1649 | 0 | } |
1650 | 0 | memset(ret, 0, sizeof(xmlRelaxNGInclude)); |
1651 | 0 | ret->doc = doc; |
1652 | 0 | ret->href = xmlStrdup(URL); |
1653 | 0 | ret->next = ctxt->includes; |
1654 | 0 | ctxt->includes = ret; |
1655 | | |
1656 | | /* |
1657 | | * transmit the ns if needed |
1658 | | */ |
1659 | 0 | if (ns != NULL) { |
1660 | 0 | root = xmlDocGetRootElement(doc); |
1661 | 0 | if (root != NULL) { |
1662 | 0 | if (xmlHasProp(root, BAD_CAST "ns") == NULL) { |
1663 | 0 | xmlSetProp(root, BAD_CAST "ns", ns); |
1664 | 0 | } |
1665 | 0 | } |
1666 | 0 | } |
1667 | | |
1668 | | /* |
1669 | | * push it on the stack |
1670 | | */ |
1671 | 0 | xmlRelaxNGIncludePush(ctxt, ret); |
1672 | | |
1673 | | /* |
1674 | | * Some preprocessing of the document content, this include recursing |
1675 | | * in the include stack. |
1676 | | */ |
1677 | | #ifdef DEBUG_INCLUDE |
1678 | | xmlGenericError(xmlGenericErrorContext, "cleanup of %s\n", URL); |
1679 | | #endif |
1680 | |
|
1681 | 0 | doc = xmlRelaxNGCleanupDoc(ctxt, doc); |
1682 | 0 | if (doc == NULL) { |
1683 | 0 | ctxt->inc = NULL; |
1684 | 0 | return (NULL); |
1685 | 0 | } |
1686 | | |
1687 | | /* |
1688 | | * Pop up the include from the stack |
1689 | | */ |
1690 | 0 | xmlRelaxNGIncludePop(ctxt); |
1691 | |
|
1692 | | #ifdef DEBUG_INCLUDE |
1693 | | xmlGenericError(xmlGenericErrorContext, "Checking of %s\n", URL); |
1694 | | #endif |
1695 | | /* |
1696 | | * Check that the top element is a grammar |
1697 | | */ |
1698 | 0 | root = xmlDocGetRootElement(doc); |
1699 | 0 | if (root == NULL) { |
1700 | 0 | xmlRngPErr(ctxt, node, XML_RNGP_EMPTY, |
1701 | 0 | "xmlRelaxNG: included document is empty %s\n", URL, |
1702 | 0 | NULL); |
1703 | 0 | return (NULL); |
1704 | 0 | } |
1705 | 0 | if (!IS_RELAXNG(root, "grammar")) { |
1706 | 0 | xmlRngPErr(ctxt, node, XML_RNGP_GRAMMAR_MISSING, |
1707 | 0 | "xmlRelaxNG: included document %s root is not a grammar\n", |
1708 | 0 | URL, NULL); |
1709 | 0 | return (NULL); |
1710 | 0 | } |
1711 | | |
1712 | | /* |
1713 | | * Elimination of redefined rules in the include. |
1714 | | */ |
1715 | 0 | cur = node->children; |
1716 | 0 | while (cur != NULL) { |
1717 | 0 | if (IS_RELAXNG(cur, "start")) { |
1718 | 0 | int found = 0; |
1719 | |
|
1720 | 0 | found = |
1721 | 0 | xmlRelaxNGRemoveRedefine(ctxt, URL, root->children, NULL); |
1722 | 0 | if (!found) { |
1723 | 0 | xmlRngPErr(ctxt, node, XML_RNGP_START_MISSING, |
1724 | 0 | "xmlRelaxNG: include %s has a start but not the included grammar\n", |
1725 | 0 | URL, NULL); |
1726 | 0 | } |
1727 | 0 | } else if (IS_RELAXNG(cur, "define")) { |
1728 | 0 | xmlChar *name; |
1729 | |
|
1730 | 0 | name = xmlGetProp(cur, BAD_CAST "name"); |
1731 | 0 | if (name == NULL) { |
1732 | 0 | xmlRngPErr(ctxt, node, XML_RNGP_NAME_MISSING, |
1733 | 0 | "xmlRelaxNG: include %s has define without name\n", |
1734 | 0 | URL, NULL); |
1735 | 0 | } else { |
1736 | 0 | int found; |
1737 | |
|
1738 | 0 | xmlRelaxNGNormExtSpace(name); |
1739 | 0 | found = xmlRelaxNGRemoveRedefine(ctxt, URL, |
1740 | 0 | root->children, name); |
1741 | 0 | if (!found) { |
1742 | 0 | xmlRngPErr(ctxt, node, XML_RNGP_DEFINE_MISSING, |
1743 | 0 | "xmlRelaxNG: include %s has a define %s but not the included grammar\n", |
1744 | 0 | URL, name); |
1745 | 0 | } |
1746 | 0 | xmlFree(name); |
1747 | 0 | } |
1748 | 0 | } |
1749 | 0 | if (IS_RELAXNG(cur, "div") && cur->children != NULL) { |
1750 | 0 | cur = cur->children; |
1751 | 0 | } else { |
1752 | 0 | if (cur->next != NULL) { |
1753 | 0 | cur = cur->next; |
1754 | 0 | } else { |
1755 | 0 | while (cur->parent != node && cur->parent->next == NULL) { |
1756 | 0 | cur = cur->parent; |
1757 | 0 | } |
1758 | 0 | cur = cur->parent != node ? cur->parent->next : NULL; |
1759 | 0 | } |
1760 | 0 | } |
1761 | 0 | } |
1762 | | |
1763 | |
|
1764 | 0 | return (ret); |
1765 | 0 | } |
1766 | | |
1767 | | /** |
1768 | | * xmlRelaxNGValidErrorPush: |
1769 | | * @ctxt: the validation context |
1770 | | * @err: the error code |
1771 | | * @arg1: the first string argument |
1772 | | * @arg2: the second string argument |
1773 | | * @dup: arg need to be duplicated |
1774 | | * |
1775 | | * Pushes a new error on top of the error stack |
1776 | | * |
1777 | | * Returns 0 in case of error, the index in the stack otherwise |
1778 | | */ |
1779 | | static int |
1780 | | xmlRelaxNGValidErrorPush(xmlRelaxNGValidCtxtPtr ctxt, |
1781 | | xmlRelaxNGValidErr err, const xmlChar * arg1, |
1782 | | const xmlChar * arg2, int dup) |
1783 | 0 | { |
1784 | 0 | xmlRelaxNGValidErrorPtr cur; |
1785 | |
|
1786 | | #ifdef DEBUG_ERROR |
1787 | | xmlGenericError(xmlGenericErrorContext, |
1788 | | "Pushing error %d at %d on stack\n", err, ctxt->errNr); |
1789 | | #endif |
1790 | 0 | if (ctxt->errTab == NULL) { |
1791 | 0 | ctxt->errMax = 8; |
1792 | 0 | ctxt->errNr = 0; |
1793 | 0 | ctxt->errTab = |
1794 | 0 | (xmlRelaxNGValidErrorPtr) xmlMalloc(ctxt->errMax * |
1795 | 0 | sizeof |
1796 | 0 | (xmlRelaxNGValidError)); |
1797 | 0 | if (ctxt->errTab == NULL) { |
1798 | 0 | xmlRngVErrMemory(ctxt, "pushing error\n"); |
1799 | 0 | return (0); |
1800 | 0 | } |
1801 | 0 | ctxt->err = NULL; |
1802 | 0 | } |
1803 | 0 | if (ctxt->errNr >= ctxt->errMax) { |
1804 | 0 | ctxt->errMax *= 2; |
1805 | 0 | ctxt->errTab = |
1806 | 0 | (xmlRelaxNGValidErrorPtr) xmlRealloc(ctxt->errTab, |
1807 | 0 | ctxt->errMax * |
1808 | 0 | sizeof |
1809 | 0 | (xmlRelaxNGValidError)); |
1810 | 0 | if (ctxt->errTab == NULL) { |
1811 | 0 | xmlRngVErrMemory(ctxt, "pushing error\n"); |
1812 | 0 | return (0); |
1813 | 0 | } |
1814 | 0 | ctxt->err = &ctxt->errTab[ctxt->errNr - 1]; |
1815 | 0 | } |
1816 | 0 | if ((ctxt->err != NULL) && (ctxt->state != NULL) && |
1817 | 0 | (ctxt->err->node == ctxt->state->node) && (ctxt->err->err == err)) |
1818 | 0 | return (ctxt->errNr); |
1819 | 0 | cur = &ctxt->errTab[ctxt->errNr]; |
1820 | 0 | cur->err = err; |
1821 | 0 | if (dup) { |
1822 | 0 | cur->arg1 = xmlStrdup(arg1); |
1823 | 0 | cur->arg2 = xmlStrdup(arg2); |
1824 | 0 | cur->flags = ERROR_IS_DUP; |
1825 | 0 | } else { |
1826 | 0 | cur->arg1 = arg1; |
1827 | 0 | cur->arg2 = arg2; |
1828 | 0 | cur->flags = 0; |
1829 | 0 | } |
1830 | 0 | if (ctxt->state != NULL) { |
1831 | 0 | cur->node = ctxt->state->node; |
1832 | 0 | cur->seq = ctxt->state->seq; |
1833 | 0 | } else { |
1834 | 0 | cur->node = NULL; |
1835 | 0 | cur->seq = NULL; |
1836 | 0 | } |
1837 | 0 | ctxt->err = cur; |
1838 | 0 | return (ctxt->errNr++); |
1839 | 0 | } |
1840 | | |
1841 | | /** |
1842 | | * xmlRelaxNGValidErrorPop: |
1843 | | * @ctxt: the validation context |
1844 | | * |
1845 | | * Pops the top error from the error stack |
1846 | | */ |
1847 | | static void |
1848 | | xmlRelaxNGValidErrorPop(xmlRelaxNGValidCtxtPtr ctxt) |
1849 | 0 | { |
1850 | 0 | xmlRelaxNGValidErrorPtr cur; |
1851 | |
|
1852 | 0 | if (ctxt->errNr <= 0) { |
1853 | 0 | ctxt->err = NULL; |
1854 | 0 | return; |
1855 | 0 | } |
1856 | 0 | ctxt->errNr--; |
1857 | 0 | if (ctxt->errNr > 0) |
1858 | 0 | ctxt->err = &ctxt->errTab[ctxt->errNr - 1]; |
1859 | 0 | else |
1860 | 0 | ctxt->err = NULL; |
1861 | 0 | cur = &ctxt->errTab[ctxt->errNr]; |
1862 | 0 | if (cur->flags & ERROR_IS_DUP) { |
1863 | 0 | if (cur->arg1 != NULL) |
1864 | 0 | xmlFree((xmlChar *) cur->arg1); |
1865 | 0 | cur->arg1 = NULL; |
1866 | 0 | if (cur->arg2 != NULL) |
1867 | 0 | xmlFree((xmlChar *) cur->arg2); |
1868 | 0 | cur->arg2 = NULL; |
1869 | 0 | cur->flags = 0; |
1870 | 0 | } |
1871 | 0 | } |
1872 | | |
1873 | | /** |
1874 | | * xmlRelaxNGDocumentPush: |
1875 | | * @ctxt: the parser context |
1876 | | * @value: the element doc |
1877 | | * |
1878 | | * Pushes a new doc on top of the doc stack |
1879 | | * |
1880 | | * Returns 0 in case of error, the index in the stack otherwise |
1881 | | */ |
1882 | | static int |
1883 | | xmlRelaxNGDocumentPush(xmlRelaxNGParserCtxtPtr ctxt, |
1884 | | xmlRelaxNGDocumentPtr value) |
1885 | 0 | { |
1886 | 0 | if (ctxt->docTab == NULL) { |
1887 | 0 | ctxt->docMax = 4; |
1888 | 0 | ctxt->docNr = 0; |
1889 | 0 | ctxt->docTab = |
1890 | 0 | (xmlRelaxNGDocumentPtr *) xmlMalloc(ctxt->docMax * |
1891 | 0 | sizeof(ctxt->docTab[0])); |
1892 | 0 | if (ctxt->docTab == NULL) { |
1893 | 0 | xmlRngPErrMemory(ctxt, "adding document\n"); |
1894 | 0 | return (0); |
1895 | 0 | } |
1896 | 0 | } |
1897 | 0 | if (ctxt->docNr >= ctxt->docMax) { |
1898 | 0 | ctxt->docMax *= 2; |
1899 | 0 | ctxt->docTab = |
1900 | 0 | (xmlRelaxNGDocumentPtr *) xmlRealloc(ctxt->docTab, |
1901 | 0 | ctxt->docMax * |
1902 | 0 | sizeof(ctxt->docTab[0])); |
1903 | 0 | if (ctxt->docTab == NULL) { |
1904 | 0 | xmlRngPErrMemory(ctxt, "adding document\n"); |
1905 | 0 | return (0); |
1906 | 0 | } |
1907 | 0 | } |
1908 | 0 | ctxt->docTab[ctxt->docNr] = value; |
1909 | 0 | ctxt->doc = value; |
1910 | 0 | return (ctxt->docNr++); |
1911 | 0 | } |
1912 | | |
1913 | | /** |
1914 | | * xmlRelaxNGDocumentPop: |
1915 | | * @ctxt: the parser context |
1916 | | * |
1917 | | * Pops the top doc from the doc stack |
1918 | | * |
1919 | | * Returns the doc just removed |
1920 | | */ |
1921 | | static xmlRelaxNGDocumentPtr |
1922 | | xmlRelaxNGDocumentPop(xmlRelaxNGParserCtxtPtr ctxt) |
1923 | 0 | { |
1924 | 0 | xmlRelaxNGDocumentPtr ret; |
1925 | |
|
1926 | 0 | if (ctxt->docNr <= 0) |
1927 | 0 | return (NULL); |
1928 | 0 | ctxt->docNr--; |
1929 | 0 | if (ctxt->docNr > 0) |
1930 | 0 | ctxt->doc = ctxt->docTab[ctxt->docNr - 1]; |
1931 | 0 | else |
1932 | 0 | ctxt->doc = NULL; |
1933 | 0 | ret = ctxt->docTab[ctxt->docNr]; |
1934 | 0 | ctxt->docTab[ctxt->docNr] = NULL; |
1935 | 0 | return (ret); |
1936 | 0 | } |
1937 | | |
1938 | | /** |
1939 | | * xmlRelaxNGLoadExternalRef: |
1940 | | * @ctxt: the parser context |
1941 | | * @URL: the normalized URL |
1942 | | * @ns: the inherited ns if any |
1943 | | * |
1944 | | * First lookup if the document is already loaded into the parser context, |
1945 | | * check against recursion. If not found the resource is loaded and |
1946 | | * the content is preprocessed before being returned back to the caller. |
1947 | | * |
1948 | | * Returns the xmlRelaxNGDocumentPtr or NULL in case of error |
1949 | | */ |
1950 | | static xmlRelaxNGDocumentPtr |
1951 | | xmlRelaxNGLoadExternalRef(xmlRelaxNGParserCtxtPtr ctxt, |
1952 | | const xmlChar * URL, const xmlChar * ns) |
1953 | 0 | { |
1954 | 0 | xmlRelaxNGDocumentPtr ret = NULL; |
1955 | 0 | xmlDocPtr doc; |
1956 | 0 | xmlNodePtr root; |
1957 | 0 | int i; |
1958 | | |
1959 | | /* |
1960 | | * check against recursion in the stack |
1961 | | */ |
1962 | 0 | for (i = 0; i < ctxt->docNr; i++) { |
1963 | 0 | if (xmlStrEqual(ctxt->docTab[i]->href, URL)) { |
1964 | 0 | xmlRngPErr(ctxt, NULL, XML_RNGP_EXTERNALREF_RECURSE, |
1965 | 0 | "Detected an externalRef recursion for %s\n", URL, |
1966 | 0 | NULL); |
1967 | 0 | return (NULL); |
1968 | 0 | } |
1969 | 0 | } |
1970 | | |
1971 | | /* |
1972 | | * load the document |
1973 | | */ |
1974 | 0 | doc = xmlReadFile((const char *) URL,NULL,0); |
1975 | 0 | if (doc == NULL) { |
1976 | 0 | xmlRngPErr(ctxt, NULL, XML_RNGP_PARSE_ERROR, |
1977 | 0 | "xmlRelaxNG: could not load %s\n", URL, NULL); |
1978 | 0 | return (NULL); |
1979 | 0 | } |
1980 | | |
1981 | | /* |
1982 | | * Allocate the document structures and register it first. |
1983 | | */ |
1984 | 0 | ret = (xmlRelaxNGDocumentPtr) xmlMalloc(sizeof(xmlRelaxNGDocument)); |
1985 | 0 | if (ret == NULL) { |
1986 | 0 | xmlRngPErr(ctxt, (xmlNodePtr) doc, XML_ERR_NO_MEMORY, |
1987 | 0 | "xmlRelaxNG: allocate memory for doc %s\n", URL, NULL); |
1988 | 0 | xmlFreeDoc(doc); |
1989 | 0 | return (NULL); |
1990 | 0 | } |
1991 | 0 | memset(ret, 0, sizeof(xmlRelaxNGDocument)); |
1992 | 0 | ret->doc = doc; |
1993 | 0 | ret->href = xmlStrdup(URL); |
1994 | 0 | ret->next = ctxt->documents; |
1995 | 0 | ret->externalRef = 1; |
1996 | 0 | ctxt->documents = ret; |
1997 | | |
1998 | | /* |
1999 | | * transmit the ns if needed |
2000 | | */ |
2001 | 0 | if (ns != NULL) { |
2002 | 0 | root = xmlDocGetRootElement(doc); |
2003 | 0 | if (root != NULL) { |
2004 | 0 | if (xmlHasProp(root, BAD_CAST "ns") == NULL) { |
2005 | 0 | xmlSetProp(root, BAD_CAST "ns", ns); |
2006 | 0 | } |
2007 | 0 | } |
2008 | 0 | } |
2009 | | |
2010 | | /* |
2011 | | * push it on the stack and register it in the hash table |
2012 | | */ |
2013 | 0 | xmlRelaxNGDocumentPush(ctxt, ret); |
2014 | | |
2015 | | /* |
2016 | | * Some preprocessing of the document content |
2017 | | */ |
2018 | 0 | doc = xmlRelaxNGCleanupDoc(ctxt, doc); |
2019 | 0 | if (doc == NULL) { |
2020 | 0 | ctxt->doc = NULL; |
2021 | 0 | return (NULL); |
2022 | 0 | } |
2023 | | |
2024 | 0 | xmlRelaxNGDocumentPop(ctxt); |
2025 | |
|
2026 | 0 | return (ret); |
2027 | 0 | } |
2028 | | |
2029 | | /************************************************************************ |
2030 | | * * |
2031 | | * Error functions * |
2032 | | * * |
2033 | | ************************************************************************/ |
2034 | | |
2035 | 0 | #define VALID_ERR(a) xmlRelaxNGAddValidError(ctxt, a, NULL, NULL, 0); |
2036 | 0 | #define VALID_ERR2(a, b) xmlRelaxNGAddValidError(ctxt, a, b, NULL, 0); |
2037 | 0 | #define VALID_ERR3(a, b, c) xmlRelaxNGAddValidError(ctxt, a, b, c, 0); |
2038 | 0 | #define VALID_ERR2P(a, b) xmlRelaxNGAddValidError(ctxt, a, b, NULL, 1); |
2039 | 0 | #define VALID_ERR3P(a, b, c) xmlRelaxNGAddValidError(ctxt, a, b, c, 1); |
2040 | | |
2041 | | static const char * |
2042 | | xmlRelaxNGDefName(xmlRelaxNGDefinePtr def) |
2043 | 0 | { |
2044 | 0 | if (def == NULL) |
2045 | 0 | return ("none"); |
2046 | 0 | switch (def->type) { |
2047 | 0 | case XML_RELAXNG_EMPTY: |
2048 | 0 | return ("empty"); |
2049 | 0 | case XML_RELAXNG_NOT_ALLOWED: |
2050 | 0 | return ("notAllowed"); |
2051 | 0 | case XML_RELAXNG_EXCEPT: |
2052 | 0 | return ("except"); |
2053 | 0 | case XML_RELAXNG_TEXT: |
2054 | 0 | return ("text"); |
2055 | 0 | case XML_RELAXNG_ELEMENT: |
2056 | 0 | return ("element"); |
2057 | 0 | case XML_RELAXNG_DATATYPE: |
2058 | 0 | return ("datatype"); |
2059 | 0 | case XML_RELAXNG_VALUE: |
2060 | 0 | return ("value"); |
2061 | 0 | case XML_RELAXNG_LIST: |
2062 | 0 | return ("list"); |
2063 | 0 | case XML_RELAXNG_ATTRIBUTE: |
2064 | 0 | return ("attribute"); |
2065 | 0 | case XML_RELAXNG_DEF: |
2066 | 0 | return ("def"); |
2067 | 0 | case XML_RELAXNG_REF: |
2068 | 0 | return ("ref"); |
2069 | 0 | case XML_RELAXNG_EXTERNALREF: |
2070 | 0 | return ("externalRef"); |
2071 | 0 | case XML_RELAXNG_PARENTREF: |
2072 | 0 | return ("parentRef"); |
2073 | 0 | case XML_RELAXNG_OPTIONAL: |
2074 | 0 | return ("optional"); |
2075 | 0 | case XML_RELAXNG_ZEROORMORE: |
2076 | 0 | return ("zeroOrMore"); |
2077 | 0 | case XML_RELAXNG_ONEORMORE: |
2078 | 0 | return ("oneOrMore"); |
2079 | 0 | case XML_RELAXNG_CHOICE: |
2080 | 0 | return ("choice"); |
2081 | 0 | case XML_RELAXNG_GROUP: |
2082 | 0 | return ("group"); |
2083 | 0 | case XML_RELAXNG_INTERLEAVE: |
2084 | 0 | return ("interleave"); |
2085 | 0 | case XML_RELAXNG_START: |
2086 | 0 | return ("start"); |
2087 | 0 | case XML_RELAXNG_NOOP: |
2088 | 0 | return ("noop"); |
2089 | 0 | case XML_RELAXNG_PARAM: |
2090 | 0 | return ("param"); |
2091 | 0 | } |
2092 | 0 | return ("unknown"); |
2093 | 0 | } |
2094 | | |
2095 | | /** |
2096 | | * xmlRelaxNGGetErrorString: |
2097 | | * @err: the error code |
2098 | | * @arg1: the first string argument |
2099 | | * @arg2: the second string argument |
2100 | | * |
2101 | | * computes a formatted error string for the given error code and args |
2102 | | * |
2103 | | * Returns the error string, it must be deallocated by the caller |
2104 | | */ |
2105 | | static xmlChar * |
2106 | | xmlRelaxNGGetErrorString(xmlRelaxNGValidErr err, const xmlChar * arg1, |
2107 | | const xmlChar * arg2) |
2108 | 0 | { |
2109 | 0 | char msg[1000]; |
2110 | 0 | xmlChar *result; |
2111 | |
|
2112 | 0 | if (arg1 == NULL) |
2113 | 0 | arg1 = BAD_CAST ""; |
2114 | 0 | if (arg2 == NULL) |
2115 | 0 | arg2 = BAD_CAST ""; |
2116 | |
|
2117 | 0 | msg[0] = 0; |
2118 | 0 | switch (err) { |
2119 | 0 | case XML_RELAXNG_OK: |
2120 | 0 | return (NULL); |
2121 | 0 | case XML_RELAXNG_ERR_MEMORY: |
2122 | 0 | return (xmlCharStrdup("out of memory\n")); |
2123 | 0 | case XML_RELAXNG_ERR_TYPE: |
2124 | 0 | snprintf(msg, 1000, "failed to validate type %s\n", arg1); |
2125 | 0 | break; |
2126 | 0 | case XML_RELAXNG_ERR_TYPEVAL: |
2127 | 0 | snprintf(msg, 1000, "Type %s doesn't allow value '%s'\n", arg1, |
2128 | 0 | arg2); |
2129 | 0 | break; |
2130 | 0 | case XML_RELAXNG_ERR_DUPID: |
2131 | 0 | snprintf(msg, 1000, "ID %s redefined\n", arg1); |
2132 | 0 | break; |
2133 | 0 | case XML_RELAXNG_ERR_TYPECMP: |
2134 | 0 | snprintf(msg, 1000, "failed to compare type %s\n", arg1); |
2135 | 0 | break; |
2136 | 0 | case XML_RELAXNG_ERR_NOSTATE: |
2137 | 0 | return (xmlCharStrdup("Internal error: no state\n")); |
2138 | 0 | case XML_RELAXNG_ERR_NODEFINE: |
2139 | 0 | return (xmlCharStrdup("Internal error: no define\n")); |
2140 | 0 | case XML_RELAXNG_ERR_INTERNAL: |
2141 | 0 | snprintf(msg, 1000, "Internal error: %s\n", arg1); |
2142 | 0 | break; |
2143 | 0 | case XML_RELAXNG_ERR_LISTEXTRA: |
2144 | 0 | snprintf(msg, 1000, "Extra data in list: %s\n", arg1); |
2145 | 0 | break; |
2146 | 0 | case XML_RELAXNG_ERR_INTERNODATA: |
2147 | 0 | return (xmlCharStrdup |
2148 | 0 | ("Internal: interleave block has no data\n")); |
2149 | 0 | case XML_RELAXNG_ERR_INTERSEQ: |
2150 | 0 | return (xmlCharStrdup("Invalid sequence in interleave\n")); |
2151 | 0 | case XML_RELAXNG_ERR_INTEREXTRA: |
2152 | 0 | snprintf(msg, 1000, "Extra element %s in interleave\n", arg1); |
2153 | 0 | break; |
2154 | 0 | case XML_RELAXNG_ERR_ELEMNAME: |
2155 | 0 | snprintf(msg, 1000, "Expecting element %s, got %s\n", arg1, |
2156 | 0 | arg2); |
2157 | 0 | break; |
2158 | 0 | case XML_RELAXNG_ERR_ELEMNONS: |
2159 | 0 | snprintf(msg, 1000, "Expecting a namespace for element %s\n", |
2160 | 0 | arg1); |
2161 | 0 | break; |
2162 | 0 | case XML_RELAXNG_ERR_ELEMWRONGNS: |
2163 | 0 | snprintf(msg, 1000, |
2164 | 0 | "Element %s has wrong namespace: expecting %s\n", arg1, |
2165 | 0 | arg2); |
2166 | 0 | break; |
2167 | 0 | case XML_RELAXNG_ERR_ELEMWRONG: |
2168 | 0 | snprintf(msg, 1000, "Did not expect element %s there\n", arg1); |
2169 | 0 | break; |
2170 | 0 | case XML_RELAXNG_ERR_TEXTWRONG: |
2171 | 0 | snprintf(msg, 1000, |
2172 | 0 | "Did not expect text in element %s content\n", arg1); |
2173 | 0 | break; |
2174 | 0 | case XML_RELAXNG_ERR_ELEMEXTRANS: |
2175 | 0 | snprintf(msg, 1000, "Expecting no namespace for element %s\n", |
2176 | 0 | arg1); |
2177 | 0 | break; |
2178 | 0 | case XML_RELAXNG_ERR_ELEMNOTEMPTY: |
2179 | 0 | snprintf(msg, 1000, "Expecting element %s to be empty\n", arg1); |
2180 | 0 | break; |
2181 | 0 | case XML_RELAXNG_ERR_NOELEM: |
2182 | 0 | snprintf(msg, 1000, "Expecting an element %s, got nothing\n", |
2183 | 0 | arg1); |
2184 | 0 | break; |
2185 | 0 | case XML_RELAXNG_ERR_NOTELEM: |
2186 | 0 | return (xmlCharStrdup("Expecting an element got text\n")); |
2187 | 0 | case XML_RELAXNG_ERR_ATTRVALID: |
2188 | 0 | snprintf(msg, 1000, "Element %s failed to validate attributes\n", |
2189 | 0 | arg1); |
2190 | 0 | break; |
2191 | 0 | case XML_RELAXNG_ERR_CONTENTVALID: |
2192 | 0 | snprintf(msg, 1000, "Element %s failed to validate content\n", |
2193 | 0 | arg1); |
2194 | 0 | break; |
2195 | 0 | case XML_RELAXNG_ERR_EXTRACONTENT: |
2196 | 0 | snprintf(msg, 1000, "Element %s has extra content: %s\n", |
2197 | 0 | arg1, arg2); |
2198 | 0 | break; |
2199 | 0 | case XML_RELAXNG_ERR_INVALIDATTR: |
2200 | 0 | snprintf(msg, 1000, "Invalid attribute %s for element %s\n", |
2201 | 0 | arg1, arg2); |
2202 | 0 | break; |
2203 | 0 | case XML_RELAXNG_ERR_LACKDATA: |
2204 | 0 | snprintf(msg, 1000, "Datatype element %s contains no data\n", |
2205 | 0 | arg1); |
2206 | 0 | break; |
2207 | 0 | case XML_RELAXNG_ERR_DATAELEM: |
2208 | 0 | snprintf(msg, 1000, "Datatype element %s has child elements\n", |
2209 | 0 | arg1); |
2210 | 0 | break; |
2211 | 0 | case XML_RELAXNG_ERR_VALELEM: |
2212 | 0 | snprintf(msg, 1000, "Value element %s has child elements\n", |
2213 | 0 | arg1); |
2214 | 0 | break; |
2215 | 0 | case XML_RELAXNG_ERR_LISTELEM: |
2216 | 0 | snprintf(msg, 1000, "List element %s has child elements\n", |
2217 | 0 | arg1); |
2218 | 0 | break; |
2219 | 0 | case XML_RELAXNG_ERR_DATATYPE: |
2220 | 0 | snprintf(msg, 1000, "Error validating datatype %s\n", arg1); |
2221 | 0 | break; |
2222 | 0 | case XML_RELAXNG_ERR_VALUE: |
2223 | 0 | snprintf(msg, 1000, "Error validating value %s\n", arg1); |
2224 | 0 | break; |
2225 | 0 | case XML_RELAXNG_ERR_LIST: |
2226 | 0 | return (xmlCharStrdup("Error validating list\n")); |
2227 | 0 | case XML_RELAXNG_ERR_NOGRAMMAR: |
2228 | 0 | return (xmlCharStrdup("No top grammar defined\n")); |
2229 | 0 | case XML_RELAXNG_ERR_EXTRADATA: |
2230 | 0 | return (xmlCharStrdup("Extra data in the document\n")); |
2231 | 0 | default: |
2232 | 0 | return (xmlCharStrdup("Unknown error !\n")); |
2233 | 0 | } |
2234 | 0 | if (msg[0] == 0) { |
2235 | 0 | snprintf(msg, 1000, "Unknown error code %d\n", err); |
2236 | 0 | } |
2237 | 0 | msg[1000 - 1] = 0; |
2238 | 0 | result = xmlCharStrdup(msg); |
2239 | 0 | return (xmlEscapeFormatString(&result)); |
2240 | 0 | } |
2241 | | |
2242 | | /** |
2243 | | * xmlRelaxNGShowValidError: |
2244 | | * @ctxt: the validation context |
2245 | | * @err: the error number |
2246 | | * @node: the node |
2247 | | * @child: the node child generating the problem. |
2248 | | * @arg1: the first argument |
2249 | | * @arg2: the second argument |
2250 | | * |
2251 | | * Show a validation error. |
2252 | | */ |
2253 | | static void |
2254 | | xmlRelaxNGShowValidError(xmlRelaxNGValidCtxtPtr ctxt, |
2255 | | xmlRelaxNGValidErr err, xmlNodePtr node, |
2256 | | xmlNodePtr child, const xmlChar * arg1, |
2257 | | const xmlChar * arg2) |
2258 | 0 | { |
2259 | 0 | xmlChar *msg; |
2260 | |
|
2261 | 0 | if (ctxt->flags & FLAGS_NOERROR) |
2262 | 0 | return; |
2263 | | |
2264 | | #ifdef DEBUG_ERROR |
2265 | | xmlGenericError(xmlGenericErrorContext, "Show error %d\n", err); |
2266 | | #endif |
2267 | 0 | msg = xmlRelaxNGGetErrorString(err, arg1, arg2); |
2268 | 0 | if (msg == NULL) |
2269 | 0 | return; |
2270 | | |
2271 | 0 | if (ctxt->errNo == XML_RELAXNG_OK) |
2272 | 0 | ctxt->errNo = err; |
2273 | 0 | xmlRngVErr(ctxt, (child == NULL ? node : child), err, |
2274 | 0 | (const char *) msg, arg1, arg2); |
2275 | 0 | xmlFree(msg); |
2276 | 0 | } |
2277 | | |
2278 | | /** |
2279 | | * xmlRelaxNGPopErrors: |
2280 | | * @ctxt: the validation context |
2281 | | * @level: the error level in the stack |
2282 | | * |
2283 | | * pop and discard all errors until the given level is reached |
2284 | | */ |
2285 | | static void |
2286 | | xmlRelaxNGPopErrors(xmlRelaxNGValidCtxtPtr ctxt, int level) |
2287 | 0 | { |
2288 | 0 | int i; |
2289 | 0 | xmlRelaxNGValidErrorPtr err; |
2290 | |
|
2291 | | #ifdef DEBUG_ERROR |
2292 | | xmlGenericError(xmlGenericErrorContext, |
2293 | | "Pop errors till level %d\n", level); |
2294 | | #endif |
2295 | 0 | for (i = level; i < ctxt->errNr; i++) { |
2296 | 0 | err = &ctxt->errTab[i]; |
2297 | 0 | if (err->flags & ERROR_IS_DUP) { |
2298 | 0 | if (err->arg1 != NULL) |
2299 | 0 | xmlFree((xmlChar *) err->arg1); |
2300 | 0 | err->arg1 = NULL; |
2301 | 0 | if (err->arg2 != NULL) |
2302 | 0 | xmlFree((xmlChar *) err->arg2); |
2303 | 0 | err->arg2 = NULL; |
2304 | 0 | err->flags = 0; |
2305 | 0 | } |
2306 | 0 | } |
2307 | 0 | ctxt->errNr = level; |
2308 | 0 | if (ctxt->errNr <= 0) |
2309 | 0 | ctxt->err = NULL; |
2310 | 0 | } |
2311 | | |
2312 | | /** |
2313 | | * xmlRelaxNGDumpValidError: |
2314 | | * @ctxt: the validation context |
2315 | | * |
2316 | | * Show all validation error over a given index. |
2317 | | */ |
2318 | | static void |
2319 | | xmlRelaxNGDumpValidError(xmlRelaxNGValidCtxtPtr ctxt) |
2320 | 0 | { |
2321 | 0 | int i, j, k; |
2322 | 0 | xmlRelaxNGValidErrorPtr err, dup; |
2323 | |
|
2324 | | #ifdef DEBUG_ERROR |
2325 | | xmlGenericError(xmlGenericErrorContext, |
2326 | | "Dumping error stack %d errors\n", ctxt->errNr); |
2327 | | #endif |
2328 | 0 | for (i = 0, k = 0; i < ctxt->errNr; i++) { |
2329 | 0 | err = &ctxt->errTab[i]; |
2330 | 0 | if (k < MAX_ERROR) { |
2331 | 0 | for (j = 0; j < i; j++) { |
2332 | 0 | dup = &ctxt->errTab[j]; |
2333 | 0 | if ((err->err == dup->err) && (err->node == dup->node) && |
2334 | 0 | (xmlStrEqual(err->arg1, dup->arg1)) && |
2335 | 0 | (xmlStrEqual(err->arg2, dup->arg2))) { |
2336 | 0 | goto skip; |
2337 | 0 | } |
2338 | 0 | } |
2339 | 0 | xmlRelaxNGShowValidError(ctxt, err->err, err->node, err->seq, |
2340 | 0 | err->arg1, err->arg2); |
2341 | 0 | k++; |
2342 | 0 | } |
2343 | 0 | skip: |
2344 | 0 | if (err->flags & ERROR_IS_DUP) { |
2345 | 0 | if (err->arg1 != NULL) |
2346 | 0 | xmlFree((xmlChar *) err->arg1); |
2347 | 0 | err->arg1 = NULL; |
2348 | 0 | if (err->arg2 != NULL) |
2349 | 0 | xmlFree((xmlChar *) err->arg2); |
2350 | 0 | err->arg2 = NULL; |
2351 | 0 | err->flags = 0; |
2352 | 0 | } |
2353 | 0 | } |
2354 | 0 | ctxt->errNr = 0; |
2355 | 0 | } |
2356 | | |
2357 | | /** |
2358 | | * xmlRelaxNGAddValidError: |
2359 | | * @ctxt: the validation context |
2360 | | * @err: the error number |
2361 | | * @arg1: the first argument |
2362 | | * @arg2: the second argument |
2363 | | * @dup: need to dup the args |
2364 | | * |
2365 | | * Register a validation error, either generating it if it's sure |
2366 | | * or stacking it for later handling if unsure. |
2367 | | */ |
2368 | | static void |
2369 | | xmlRelaxNGAddValidError(xmlRelaxNGValidCtxtPtr ctxt, |
2370 | | xmlRelaxNGValidErr err, const xmlChar * arg1, |
2371 | | const xmlChar * arg2, int dup) |
2372 | 0 | { |
2373 | 0 | if (ctxt == NULL) |
2374 | 0 | return; |
2375 | 0 | if (ctxt->flags & FLAGS_NOERROR) |
2376 | 0 | return; |
2377 | | |
2378 | | #ifdef DEBUG_ERROR |
2379 | | xmlGenericError(xmlGenericErrorContext, "Adding error %d\n", err); |
2380 | | #endif |
2381 | | /* |
2382 | | * generate the error directly |
2383 | | */ |
2384 | 0 | if (((ctxt->flags & FLAGS_IGNORABLE) == 0) || |
2385 | 0 | (ctxt->flags & FLAGS_NEGATIVE)) { |
2386 | 0 | xmlNodePtr node, seq; |
2387 | | |
2388 | | /* |
2389 | | * Flush first any stacked error which might be the |
2390 | | * real cause of the problem. |
2391 | | */ |
2392 | 0 | if (ctxt->errNr != 0) |
2393 | 0 | xmlRelaxNGDumpValidError(ctxt); |
2394 | 0 | if (ctxt->state != NULL) { |
2395 | 0 | node = ctxt->state->node; |
2396 | 0 | seq = ctxt->state->seq; |
2397 | 0 | } else { |
2398 | 0 | node = seq = NULL; |
2399 | 0 | } |
2400 | 0 | if ((node == NULL) && (seq == NULL)) { |
2401 | 0 | node = ctxt->pnode; |
2402 | 0 | } |
2403 | 0 | xmlRelaxNGShowValidError(ctxt, err, node, seq, arg1, arg2); |
2404 | 0 | } |
2405 | | /* |
2406 | | * Stack the error for later processing if needed |
2407 | | */ |
2408 | 0 | else { |
2409 | 0 | xmlRelaxNGValidErrorPush(ctxt, err, arg1, arg2, dup); |
2410 | 0 | } |
2411 | 0 | } |
2412 | | |
2413 | | |
2414 | | /************************************************************************ |
2415 | | * * |
2416 | | * Type library hooks * |
2417 | | * * |
2418 | | ************************************************************************/ |
2419 | | static xmlChar *xmlRelaxNGNormalize(xmlRelaxNGValidCtxtPtr ctxt, |
2420 | | const xmlChar * str); |
2421 | | |
2422 | | /** |
2423 | | * xmlRelaxNGSchemaTypeHave: |
2424 | | * @data: data needed for the library |
2425 | | * @type: the type name |
2426 | | * |
2427 | | * Check if the given type is provided by |
2428 | | * the W3C XMLSchema Datatype library. |
2429 | | * |
2430 | | * Returns 1 if yes, 0 if no and -1 in case of error. |
2431 | | */ |
2432 | | static int |
2433 | | xmlRelaxNGSchemaTypeHave(void *data ATTRIBUTE_UNUSED, const xmlChar * type) |
2434 | 0 | { |
2435 | 0 | xmlSchemaTypePtr typ; |
2436 | |
|
2437 | 0 | if (type == NULL) |
2438 | 0 | return (-1); |
2439 | 0 | typ = xmlSchemaGetPredefinedType(type, |
2440 | 0 | BAD_CAST |
2441 | 0 | "http://www.w3.org/2001/XMLSchema"); |
2442 | 0 | if (typ == NULL) |
2443 | 0 | return (0); |
2444 | 0 | return (1); |
2445 | 0 | } |
2446 | | |
2447 | | /** |
2448 | | * xmlRelaxNGSchemaTypeCheck: |
2449 | | * @data: data needed for the library |
2450 | | * @type: the type name |
2451 | | * @value: the value to check |
2452 | | * @node: the node |
2453 | | * |
2454 | | * Check if the given type and value are validated by |
2455 | | * the W3C XMLSchema Datatype library. |
2456 | | * |
2457 | | * Returns 1 if yes, 0 if no and -1 in case of error. |
2458 | | */ |
2459 | | static int |
2460 | | xmlRelaxNGSchemaTypeCheck(void *data ATTRIBUTE_UNUSED, |
2461 | | const xmlChar * type, |
2462 | | const xmlChar * value, |
2463 | | void **result, xmlNodePtr node) |
2464 | 0 | { |
2465 | 0 | xmlSchemaTypePtr typ; |
2466 | 0 | int ret; |
2467 | |
|
2468 | 0 | if ((type == NULL) || (value == NULL)) |
2469 | 0 | return (-1); |
2470 | 0 | typ = xmlSchemaGetPredefinedType(type, |
2471 | 0 | BAD_CAST |
2472 | 0 | "http://www.w3.org/2001/XMLSchema"); |
2473 | 0 | if (typ == NULL) |
2474 | 0 | return (-1); |
2475 | 0 | ret = xmlSchemaValPredefTypeNode(typ, value, |
2476 | 0 | (xmlSchemaValPtr *) result, node); |
2477 | 0 | if (ret == 2) /* special ID error code */ |
2478 | 0 | return (2); |
2479 | 0 | if (ret == 0) |
2480 | 0 | return (1); |
2481 | 0 | if (ret > 0) |
2482 | 0 | return (0); |
2483 | 0 | return (-1); |
2484 | 0 | } |
2485 | | |
2486 | | /** |
2487 | | * xmlRelaxNGSchemaFacetCheck: |
2488 | | * @data: data needed for the library |
2489 | | * @type: the type name |
2490 | | * @facet: the facet name |
2491 | | * @val: the facet value |
2492 | | * @strval: the string value |
2493 | | * @value: the value to check |
2494 | | * |
2495 | | * Function provided by a type library to check a value facet |
2496 | | * |
2497 | | * Returns 1 if yes, 0 if no and -1 in case of error. |
2498 | | */ |
2499 | | static int |
2500 | | xmlRelaxNGSchemaFacetCheck(void *data ATTRIBUTE_UNUSED, |
2501 | | const xmlChar * type, const xmlChar * facetname, |
2502 | | const xmlChar * val, const xmlChar * strval, |
2503 | | void *value) |
2504 | 0 | { |
2505 | 0 | xmlSchemaFacetPtr facet; |
2506 | 0 | xmlSchemaTypePtr typ; |
2507 | 0 | int ret; |
2508 | |
|
2509 | 0 | if ((type == NULL) || (strval == NULL)) |
2510 | 0 | return (-1); |
2511 | 0 | typ = xmlSchemaGetPredefinedType(type, |
2512 | 0 | BAD_CAST |
2513 | 0 | "http://www.w3.org/2001/XMLSchema"); |
2514 | 0 | if (typ == NULL) |
2515 | 0 | return (-1); |
2516 | | |
2517 | 0 | facet = xmlSchemaNewFacet(); |
2518 | 0 | if (facet == NULL) |
2519 | 0 | return (-1); |
2520 | | |
2521 | 0 | if (xmlStrEqual(facetname, BAD_CAST "minInclusive")) { |
2522 | 0 | facet->type = XML_SCHEMA_FACET_MININCLUSIVE; |
2523 | 0 | } else if (xmlStrEqual(facetname, BAD_CAST "minExclusive")) { |
2524 | 0 | facet->type = XML_SCHEMA_FACET_MINEXCLUSIVE; |
2525 | 0 | } else if (xmlStrEqual(facetname, BAD_CAST "maxInclusive")) { |
2526 | 0 | facet->type = XML_SCHEMA_FACET_MAXINCLUSIVE; |
2527 | 0 | } else if (xmlStrEqual(facetname, BAD_CAST "maxExclusive")) { |
2528 | 0 | facet->type = XML_SCHEMA_FACET_MAXEXCLUSIVE; |
2529 | 0 | } else if (xmlStrEqual(facetname, BAD_CAST "totalDigits")) { |
2530 | 0 | facet->type = XML_SCHEMA_FACET_TOTALDIGITS; |
2531 | 0 | } else if (xmlStrEqual(facetname, BAD_CAST "fractionDigits")) { |
2532 | 0 | facet->type = XML_SCHEMA_FACET_FRACTIONDIGITS; |
2533 | 0 | } else if (xmlStrEqual(facetname, BAD_CAST "pattern")) { |
2534 | 0 | facet->type = XML_SCHEMA_FACET_PATTERN; |
2535 | 0 | } else if (xmlStrEqual(facetname, BAD_CAST "enumeration")) { |
2536 | 0 | facet->type = XML_SCHEMA_FACET_ENUMERATION; |
2537 | 0 | } else if (xmlStrEqual(facetname, BAD_CAST "whiteSpace")) { |
2538 | 0 | facet->type = XML_SCHEMA_FACET_WHITESPACE; |
2539 | 0 | } else if (xmlStrEqual(facetname, BAD_CAST "length")) { |
2540 | 0 | facet->type = XML_SCHEMA_FACET_LENGTH; |
2541 | 0 | } else if (xmlStrEqual(facetname, BAD_CAST "maxLength")) { |
2542 | 0 | facet->type = XML_SCHEMA_FACET_MAXLENGTH; |
2543 | 0 | } else if (xmlStrEqual(facetname, BAD_CAST "minLength")) { |
2544 | 0 | facet->type = XML_SCHEMA_FACET_MINLENGTH; |
2545 | 0 | } else { |
2546 | 0 | xmlSchemaFreeFacet(facet); |
2547 | 0 | return (-1); |
2548 | 0 | } |
2549 | 0 | facet->value = val; |
2550 | 0 | ret = xmlSchemaCheckFacet(facet, typ, NULL, type); |
2551 | 0 | if (ret != 0) { |
2552 | 0 | xmlSchemaFreeFacet(facet); |
2553 | 0 | return (-1); |
2554 | 0 | } |
2555 | 0 | ret = xmlSchemaValidateFacet(typ, facet, strval, value); |
2556 | 0 | xmlSchemaFreeFacet(facet); |
2557 | 0 | if (ret != 0) |
2558 | 0 | return (-1); |
2559 | 0 | return (0); |
2560 | 0 | } |
2561 | | |
2562 | | /** |
2563 | | * xmlRelaxNGSchemaFreeValue: |
2564 | | * @data: data needed for the library |
2565 | | * @value: the value to free |
2566 | | * |
2567 | | * Function provided by a type library to free a Schemas value |
2568 | | * |
2569 | | * Returns 1 if yes, 0 if no and -1 in case of error. |
2570 | | */ |
2571 | | static void |
2572 | | xmlRelaxNGSchemaFreeValue(void *data ATTRIBUTE_UNUSED, void *value) |
2573 | 0 | { |
2574 | 0 | xmlSchemaFreeValue(value); |
2575 | 0 | } |
2576 | | |
2577 | | /** |
2578 | | * xmlRelaxNGSchemaTypeCompare: |
2579 | | * @data: data needed for the library |
2580 | | * @type: the type name |
2581 | | * @value1: the first value |
2582 | | * @value2: the second value |
2583 | | * |
2584 | | * Compare two values for equality accordingly a type from the W3C XMLSchema |
2585 | | * Datatype library. |
2586 | | * |
2587 | | * Returns 1 if equal, 0 if no and -1 in case of error. |
2588 | | */ |
2589 | | static int |
2590 | | xmlRelaxNGSchemaTypeCompare(void *data ATTRIBUTE_UNUSED, |
2591 | | const xmlChar * type, |
2592 | | const xmlChar * value1, |
2593 | | xmlNodePtr ctxt1, |
2594 | | void *comp1, |
2595 | | const xmlChar * value2, xmlNodePtr ctxt2) |
2596 | 0 | { |
2597 | 0 | int ret; |
2598 | 0 | xmlSchemaTypePtr typ; |
2599 | 0 | xmlSchemaValPtr res1 = NULL, res2 = NULL; |
2600 | |
|
2601 | 0 | if ((type == NULL) || (value1 == NULL) || (value2 == NULL)) |
2602 | 0 | return (-1); |
2603 | 0 | typ = xmlSchemaGetPredefinedType(type, |
2604 | 0 | BAD_CAST |
2605 | 0 | "http://www.w3.org/2001/XMLSchema"); |
2606 | 0 | if (typ == NULL) |
2607 | 0 | return (-1); |
2608 | 0 | if (comp1 == NULL) { |
2609 | 0 | ret = xmlSchemaValPredefTypeNode(typ, value1, &res1, ctxt1); |
2610 | 0 | if (ret != 0) |
2611 | 0 | return (-1); |
2612 | 0 | if (res1 == NULL) |
2613 | 0 | return (-1); |
2614 | 0 | } else { |
2615 | 0 | res1 = (xmlSchemaValPtr) comp1; |
2616 | 0 | } |
2617 | 0 | ret = xmlSchemaValPredefTypeNode(typ, value2, &res2, ctxt2); |
2618 | 0 | if (ret != 0) { |
2619 | 0 | if (res1 != (xmlSchemaValPtr) comp1) |
2620 | 0 | xmlSchemaFreeValue(res1); |
2621 | 0 | return (-1); |
2622 | 0 | } |
2623 | 0 | ret = xmlSchemaCompareValues(res1, res2); |
2624 | 0 | if (res1 != (xmlSchemaValPtr) comp1) |
2625 | 0 | xmlSchemaFreeValue(res1); |
2626 | 0 | xmlSchemaFreeValue(res2); |
2627 | 0 | if (ret == -2) |
2628 | 0 | return (-1); |
2629 | 0 | if (ret == 0) |
2630 | 0 | return (1); |
2631 | 0 | return (0); |
2632 | 0 | } |
2633 | | |
2634 | | /** |
2635 | | * xmlRelaxNGDefaultTypeHave: |
2636 | | * @data: data needed for the library |
2637 | | * @type: the type name |
2638 | | * |
2639 | | * Check if the given type is provided by |
2640 | | * the default datatype library. |
2641 | | * |
2642 | | * Returns 1 if yes, 0 if no and -1 in case of error. |
2643 | | */ |
2644 | | static int |
2645 | | xmlRelaxNGDefaultTypeHave(void *data ATTRIBUTE_UNUSED, |
2646 | | const xmlChar * type) |
2647 | 0 | { |
2648 | 0 | if (type == NULL) |
2649 | 0 | return (-1); |
2650 | 0 | if (xmlStrEqual(type, BAD_CAST "string")) |
2651 | 0 | return (1); |
2652 | 0 | if (xmlStrEqual(type, BAD_CAST "token")) |
2653 | 0 | return (1); |
2654 | 0 | return (0); |
2655 | 0 | } |
2656 | | |
2657 | | /** |
2658 | | * xmlRelaxNGDefaultTypeCheck: |
2659 | | * @data: data needed for the library |
2660 | | * @type: the type name |
2661 | | * @value: the value to check |
2662 | | * @node: the node |
2663 | | * |
2664 | | * Check if the given type and value are validated by |
2665 | | * the default datatype library. |
2666 | | * |
2667 | | * Returns 1 if yes, 0 if no and -1 in case of error. |
2668 | | */ |
2669 | | static int |
2670 | | xmlRelaxNGDefaultTypeCheck(void *data ATTRIBUTE_UNUSED, |
2671 | | const xmlChar * type ATTRIBUTE_UNUSED, |
2672 | | const xmlChar * value ATTRIBUTE_UNUSED, |
2673 | | void **result ATTRIBUTE_UNUSED, |
2674 | | xmlNodePtr node ATTRIBUTE_UNUSED) |
2675 | 0 | { |
2676 | 0 | if (value == NULL) |
2677 | 0 | return (-1); |
2678 | 0 | if (xmlStrEqual(type, BAD_CAST "string")) |
2679 | 0 | return (1); |
2680 | 0 | if (xmlStrEqual(type, BAD_CAST "token")) { |
2681 | 0 | return (1); |
2682 | 0 | } |
2683 | | |
2684 | 0 | return (0); |
2685 | 0 | } |
2686 | | |
2687 | | /** |
2688 | | * xmlRelaxNGDefaultTypeCompare: |
2689 | | * @data: data needed for the library |
2690 | | * @type: the type name |
2691 | | * @value1: the first value |
2692 | | * @value2: the second value |
2693 | | * |
2694 | | * Compare two values accordingly a type from the default |
2695 | | * datatype library. |
2696 | | * |
2697 | | * Returns 1 if yes, 0 if no and -1 in case of error. |
2698 | | */ |
2699 | | static int |
2700 | | xmlRelaxNGDefaultTypeCompare(void *data ATTRIBUTE_UNUSED, |
2701 | | const xmlChar * type, |
2702 | | const xmlChar * value1, |
2703 | | xmlNodePtr ctxt1 ATTRIBUTE_UNUSED, |
2704 | | void *comp1 ATTRIBUTE_UNUSED, |
2705 | | const xmlChar * value2, |
2706 | | xmlNodePtr ctxt2 ATTRIBUTE_UNUSED) |
2707 | 0 | { |
2708 | 0 | int ret = -1; |
2709 | |
|
2710 | 0 | if (xmlStrEqual(type, BAD_CAST "string")) { |
2711 | 0 | ret = xmlStrEqual(value1, value2); |
2712 | 0 | } else if (xmlStrEqual(type, BAD_CAST "token")) { |
2713 | 0 | if (!xmlStrEqual(value1, value2)) { |
2714 | 0 | xmlChar *nval, *nvalue; |
2715 | | |
2716 | | /* |
2717 | | * TODO: trivial optimizations are possible by |
2718 | | * computing at compile-time |
2719 | | */ |
2720 | 0 | nval = xmlRelaxNGNormalize(NULL, value1); |
2721 | 0 | nvalue = xmlRelaxNGNormalize(NULL, value2); |
2722 | |
|
2723 | 0 | if ((nval == NULL) || (nvalue == NULL)) |
2724 | 0 | ret = -1; |
2725 | 0 | else if (xmlStrEqual(nval, nvalue)) |
2726 | 0 | ret = 1; |
2727 | 0 | else |
2728 | 0 | ret = 0; |
2729 | 0 | if (nval != NULL) |
2730 | 0 | xmlFree(nval); |
2731 | 0 | if (nvalue != NULL) |
2732 | 0 | xmlFree(nvalue); |
2733 | 0 | } else |
2734 | 0 | ret = 1; |
2735 | 0 | } |
2736 | 0 | return (ret); |
2737 | 0 | } |
2738 | | |
2739 | | static int xmlRelaxNGTypeInitialized = 0; |
2740 | | static xmlHashTablePtr xmlRelaxNGRegisteredTypes = NULL; |
2741 | | |
2742 | | /** |
2743 | | * xmlRelaxNGFreeTypeLibrary: |
2744 | | * @lib: the type library structure |
2745 | | * @namespace: the URI bound to the library |
2746 | | * |
2747 | | * Free the structure associated to the type library |
2748 | | */ |
2749 | | static void |
2750 | | xmlRelaxNGFreeTypeLibrary(void *payload, |
2751 | | const xmlChar * namespace ATTRIBUTE_UNUSED) |
2752 | 0 | { |
2753 | 0 | xmlRelaxNGTypeLibraryPtr lib = (xmlRelaxNGTypeLibraryPtr) payload; |
2754 | 0 | if (lib == NULL) |
2755 | 0 | return; |
2756 | 0 | if (lib->namespace != NULL) |
2757 | 0 | xmlFree((xmlChar *) lib->namespace); |
2758 | 0 | xmlFree(lib); |
2759 | 0 | } |
2760 | | |
2761 | | /** |
2762 | | * xmlRelaxNGRegisterTypeLibrary: |
2763 | | * @namespace: the URI bound to the library |
2764 | | * @data: data associated to the library |
2765 | | * @have: the provide function |
2766 | | * @check: the checking function |
2767 | | * @comp: the comparison function |
2768 | | * |
2769 | | * Register a new type library |
2770 | | * |
2771 | | * Returns 0 in case of success and -1 in case of error. |
2772 | | */ |
2773 | | static int |
2774 | | xmlRelaxNGRegisterTypeLibrary(const xmlChar * namespace, void *data, |
2775 | | xmlRelaxNGTypeHave have, |
2776 | | xmlRelaxNGTypeCheck check, |
2777 | | xmlRelaxNGTypeCompare comp, |
2778 | | xmlRelaxNGFacetCheck facet, |
2779 | | xmlRelaxNGTypeFree freef) |
2780 | 0 | { |
2781 | 0 | xmlRelaxNGTypeLibraryPtr lib; |
2782 | 0 | int ret; |
2783 | |
|
2784 | 0 | if ((xmlRelaxNGRegisteredTypes == NULL) || (namespace == NULL) || |
2785 | 0 | (check == NULL) || (comp == NULL)) |
2786 | 0 | return (-1); |
2787 | 0 | if (xmlHashLookup(xmlRelaxNGRegisteredTypes, namespace) != NULL) { |
2788 | 0 | xmlGenericError(xmlGenericErrorContext, |
2789 | 0 | "Relax-NG types library '%s' already registered\n", |
2790 | 0 | namespace); |
2791 | 0 | return (-1); |
2792 | 0 | } |
2793 | 0 | lib = |
2794 | 0 | (xmlRelaxNGTypeLibraryPtr) |
2795 | 0 | xmlMalloc(sizeof(xmlRelaxNGTypeLibrary)); |
2796 | 0 | if (lib == NULL) { |
2797 | 0 | xmlRngVErrMemory(NULL, "adding types library\n"); |
2798 | 0 | return (-1); |
2799 | 0 | } |
2800 | 0 | memset(lib, 0, sizeof(xmlRelaxNGTypeLibrary)); |
2801 | 0 | lib->namespace = xmlStrdup(namespace); |
2802 | 0 | lib->data = data; |
2803 | 0 | lib->have = have; |
2804 | 0 | lib->comp = comp; |
2805 | 0 | lib->check = check; |
2806 | 0 | lib->facet = facet; |
2807 | 0 | lib->freef = freef; |
2808 | 0 | ret = xmlHashAddEntry(xmlRelaxNGRegisteredTypes, namespace, lib); |
2809 | 0 | if (ret < 0) { |
2810 | 0 | xmlGenericError(xmlGenericErrorContext, |
2811 | 0 | "Relax-NG types library failed to register '%s'\n", |
2812 | 0 | namespace); |
2813 | 0 | xmlRelaxNGFreeTypeLibrary(lib, namespace); |
2814 | 0 | return (-1); |
2815 | 0 | } |
2816 | 0 | return (0); |
2817 | 0 | } |
2818 | | |
2819 | | /** |
2820 | | * xmlRelaxNGInitTypes: |
2821 | | * |
2822 | | * Initialize the default type libraries. |
2823 | | * |
2824 | | * Returns 0 in case of success and -1 in case of error. |
2825 | | */ |
2826 | | int |
2827 | | xmlRelaxNGInitTypes(void) |
2828 | 0 | { |
2829 | 0 | if (xmlRelaxNGTypeInitialized != 0) |
2830 | 0 | return (0); |
2831 | 0 | xmlRelaxNGRegisteredTypes = xmlHashCreate(10); |
2832 | 0 | if (xmlRelaxNGRegisteredTypes == NULL) { |
2833 | 0 | xmlGenericError(xmlGenericErrorContext, |
2834 | 0 | "Failed to allocate sh table for Relax-NG types\n"); |
2835 | 0 | return (-1); |
2836 | 0 | } |
2837 | 0 | xmlRelaxNGRegisterTypeLibrary(BAD_CAST |
2838 | 0 | "http://www.w3.org/2001/XMLSchema-datatypes", |
2839 | 0 | NULL, xmlRelaxNGSchemaTypeHave, |
2840 | 0 | xmlRelaxNGSchemaTypeCheck, |
2841 | 0 | xmlRelaxNGSchemaTypeCompare, |
2842 | 0 | xmlRelaxNGSchemaFacetCheck, |
2843 | 0 | xmlRelaxNGSchemaFreeValue); |
2844 | 0 | xmlRelaxNGRegisterTypeLibrary(xmlRelaxNGNs, NULL, |
2845 | 0 | xmlRelaxNGDefaultTypeHave, |
2846 | 0 | xmlRelaxNGDefaultTypeCheck, |
2847 | 0 | xmlRelaxNGDefaultTypeCompare, NULL, |
2848 | 0 | NULL); |
2849 | 0 | xmlRelaxNGTypeInitialized = 1; |
2850 | 0 | return (0); |
2851 | 0 | } |
2852 | | |
2853 | | /** |
2854 | | * xmlRelaxNGCleanupTypes: |
2855 | | * |
2856 | | * DEPRECATED: This function will be made private. Call xmlCleanupParser |
2857 | | * to free global state but see the warnings there. xmlCleanupParser |
2858 | | * should be only called once at program exit. In most cases, you don't |
2859 | | * have call cleanup functions at all. |
2860 | | * |
2861 | | * Cleanup the default Schemas type library associated to RelaxNG |
2862 | | */ |
2863 | | void |
2864 | | xmlRelaxNGCleanupTypes(void) |
2865 | 0 | { |
2866 | 0 | xmlSchemaCleanupTypes(); |
2867 | 0 | if (xmlRelaxNGTypeInitialized == 0) |
2868 | 0 | return; |
2869 | 0 | xmlHashFree(xmlRelaxNGRegisteredTypes, xmlRelaxNGFreeTypeLibrary); |
2870 | 0 | xmlRelaxNGTypeInitialized = 0; |
2871 | 0 | } |
2872 | | |
2873 | | /************************************************************************ |
2874 | | * * |
2875 | | * Compiling element content into regexp * |
2876 | | * * |
2877 | | * Sometime the element content can be compiled into a pure regexp, * |
2878 | | * This allows a faster execution and streamability at that level * |
2879 | | * * |
2880 | | ************************************************************************/ |
2881 | | |
2882 | | static int xmlRelaxNGTryCompile(xmlRelaxNGParserCtxtPtr ctxt, |
2883 | | xmlRelaxNGDefinePtr def); |
2884 | | |
2885 | | /** |
2886 | | * xmlRelaxNGIsCompilable: |
2887 | | * @define: the definition to check |
2888 | | * |
2889 | | * Check if a definition is nullable. |
2890 | | * |
2891 | | * Returns 1 if yes, 0 if no and -1 in case of error |
2892 | | */ |
2893 | | static int |
2894 | | xmlRelaxNGIsCompilable(xmlRelaxNGDefinePtr def) |
2895 | 0 | { |
2896 | 0 | int ret = -1; |
2897 | |
|
2898 | 0 | if (def == NULL) { |
2899 | 0 | return (-1); |
2900 | 0 | } |
2901 | 0 | if ((def->type != XML_RELAXNG_ELEMENT) && |
2902 | 0 | (def->dflags & IS_COMPILABLE)) |
2903 | 0 | return (1); |
2904 | 0 | if ((def->type != XML_RELAXNG_ELEMENT) && |
2905 | 0 | (def->dflags & IS_NOT_COMPILABLE)) |
2906 | 0 | return (0); |
2907 | 0 | switch (def->type) { |
2908 | 0 | case XML_RELAXNG_NOOP: |
2909 | 0 | ret = xmlRelaxNGIsCompilable(def->content); |
2910 | 0 | break; |
2911 | 0 | case XML_RELAXNG_TEXT: |
2912 | 0 | case XML_RELAXNG_EMPTY: |
2913 | 0 | ret = 1; |
2914 | 0 | break; |
2915 | 0 | case XML_RELAXNG_ELEMENT: |
2916 | | /* |
2917 | | * Check if the element content is compilable |
2918 | | */ |
2919 | 0 | if (((def->dflags & IS_NOT_COMPILABLE) == 0) && |
2920 | 0 | ((def->dflags & IS_COMPILABLE) == 0)) { |
2921 | 0 | xmlRelaxNGDefinePtr list; |
2922 | |
|
2923 | 0 | list = def->content; |
2924 | 0 | while (list != NULL) { |
2925 | 0 | ret = xmlRelaxNGIsCompilable(list); |
2926 | 0 | if (ret != 1) |
2927 | 0 | break; |
2928 | 0 | list = list->next; |
2929 | 0 | } |
2930 | | /* |
2931 | | * Because the routine is recursive, we must guard against |
2932 | | * discovering both COMPILABLE and NOT_COMPILABLE |
2933 | | */ |
2934 | 0 | if (ret == 0) { |
2935 | 0 | def->dflags &= ~IS_COMPILABLE; |
2936 | 0 | def->dflags |= IS_NOT_COMPILABLE; |
2937 | 0 | } |
2938 | 0 | if ((ret == 1) && !(def->dflags &= IS_NOT_COMPILABLE)) |
2939 | 0 | def->dflags |= IS_COMPILABLE; |
2940 | | #ifdef DEBUG_COMPILE |
2941 | | if (ret == 1) { |
2942 | | xmlGenericError(xmlGenericErrorContext, |
2943 | | "element content for %s is compilable\n", |
2944 | | def->name); |
2945 | | } else if (ret == 0) { |
2946 | | xmlGenericError(xmlGenericErrorContext, |
2947 | | "element content for %s is not compilable\n", |
2948 | | def->name); |
2949 | | } else { |
2950 | | xmlGenericError(xmlGenericErrorContext, |
2951 | | "Problem in RelaxNGIsCompilable for element %s\n", |
2952 | | def->name); |
2953 | | } |
2954 | | #endif |
2955 | 0 | } |
2956 | | /* |
2957 | | * All elements return a compilable status unless they |
2958 | | * are generic like anyName |
2959 | | */ |
2960 | 0 | if ((def->nameClass != NULL) || (def->name == NULL)) |
2961 | 0 | ret = 0; |
2962 | 0 | else |
2963 | 0 | ret = 1; |
2964 | 0 | return (ret); |
2965 | 0 | case XML_RELAXNG_REF: |
2966 | 0 | case XML_RELAXNG_EXTERNALREF: |
2967 | 0 | case XML_RELAXNG_PARENTREF: |
2968 | 0 | if (def->depth == -20) { |
2969 | 0 | return (1); |
2970 | 0 | } else { |
2971 | 0 | xmlRelaxNGDefinePtr list; |
2972 | |
|
2973 | 0 | def->depth = -20; |
2974 | 0 | list = def->content; |
2975 | 0 | while (list != NULL) { |
2976 | 0 | ret = xmlRelaxNGIsCompilable(list); |
2977 | 0 | if (ret != 1) |
2978 | 0 | break; |
2979 | 0 | list = list->next; |
2980 | 0 | } |
2981 | 0 | } |
2982 | 0 | break; |
2983 | 0 | case XML_RELAXNG_START: |
2984 | 0 | case XML_RELAXNG_OPTIONAL: |
2985 | 0 | case XML_RELAXNG_ZEROORMORE: |
2986 | 0 | case XML_RELAXNG_ONEORMORE: |
2987 | 0 | case XML_RELAXNG_CHOICE: |
2988 | 0 | case XML_RELAXNG_GROUP: |
2989 | 0 | case XML_RELAXNG_DEF:{ |
2990 | 0 | xmlRelaxNGDefinePtr list; |
2991 | |
|
2992 | 0 | list = def->content; |
2993 | 0 | while (list != NULL) { |
2994 | 0 | ret = xmlRelaxNGIsCompilable(list); |
2995 | 0 | if (ret != 1) |
2996 | 0 | break; |
2997 | 0 | list = list->next; |
2998 | 0 | } |
2999 | 0 | break; |
3000 | 0 | } |
3001 | 0 | case XML_RELAXNG_EXCEPT: |
3002 | 0 | case XML_RELAXNG_ATTRIBUTE: |
3003 | 0 | case XML_RELAXNG_INTERLEAVE: |
3004 | 0 | case XML_RELAXNG_DATATYPE: |
3005 | 0 | case XML_RELAXNG_LIST: |
3006 | 0 | case XML_RELAXNG_PARAM: |
3007 | 0 | case XML_RELAXNG_VALUE: |
3008 | 0 | case XML_RELAXNG_NOT_ALLOWED: |
3009 | 0 | ret = 0; |
3010 | 0 | break; |
3011 | 0 | } |
3012 | 0 | if (ret == 0) |
3013 | 0 | def->dflags |= IS_NOT_COMPILABLE; |
3014 | 0 | if (ret == 1) |
3015 | 0 | def->dflags |= IS_COMPILABLE; |
3016 | | #ifdef DEBUG_COMPILE |
3017 | | if (ret == 1) { |
3018 | | xmlGenericError(xmlGenericErrorContext, |
3019 | | "RelaxNGIsCompilable %s : true\n", |
3020 | | xmlRelaxNGDefName(def)); |
3021 | | } else if (ret == 0) { |
3022 | | xmlGenericError(xmlGenericErrorContext, |
3023 | | "RelaxNGIsCompilable %s : false\n", |
3024 | | xmlRelaxNGDefName(def)); |
3025 | | } else { |
3026 | | xmlGenericError(xmlGenericErrorContext, |
3027 | | "Problem in RelaxNGIsCompilable %s\n", |
3028 | | xmlRelaxNGDefName(def)); |
3029 | | } |
3030 | | #endif |
3031 | 0 | return (ret); |
3032 | 0 | } |
3033 | | |
3034 | | /** |
3035 | | * xmlRelaxNGCompile: |
3036 | | * ctxt: the RelaxNG parser context |
3037 | | * @define: the definition tree to compile |
3038 | | * |
3039 | | * Compile the set of definitions, it works recursively, till the |
3040 | | * element boundaries, where it tries to compile the content if possible |
3041 | | * |
3042 | | * Returns 0 if success and -1 in case of error |
3043 | | */ |
3044 | | static int |
3045 | | xmlRelaxNGCompile(xmlRelaxNGParserCtxtPtr ctxt, xmlRelaxNGDefinePtr def) |
3046 | 0 | { |
3047 | 0 | int ret = 0; |
3048 | 0 | xmlRelaxNGDefinePtr list; |
3049 | |
|
3050 | 0 | if ((ctxt == NULL) || (def == NULL)) |
3051 | 0 | return (-1); |
3052 | | |
3053 | 0 | switch (def->type) { |
3054 | 0 | case XML_RELAXNG_START: |
3055 | 0 | if ((xmlRelaxNGIsCompilable(def) == 1) && (def->depth != -25)) { |
3056 | 0 | xmlAutomataPtr oldam = ctxt->am; |
3057 | 0 | xmlAutomataStatePtr oldstate = ctxt->state; |
3058 | |
|
3059 | 0 | def->depth = -25; |
3060 | |
|
3061 | 0 | list = def->content; |
3062 | 0 | ctxt->am = xmlNewAutomata(); |
3063 | 0 | if (ctxt->am == NULL) |
3064 | 0 | return (-1); |
3065 | | |
3066 | | /* |
3067 | | * assume identical strings but not same pointer are different |
3068 | | * atoms, needed for non-determinism detection |
3069 | | * That way if 2 elements with the same name are in a choice |
3070 | | * branch the automata is found non-deterministic and |
3071 | | * we fallback to the normal validation which does the right |
3072 | | * thing of exploring both choices. |
3073 | | */ |
3074 | 0 | xmlAutomataSetFlags(ctxt->am, 1); |
3075 | |
|
3076 | 0 | ctxt->state = xmlAutomataGetInitState(ctxt->am); |
3077 | 0 | while (list != NULL) { |
3078 | 0 | xmlRelaxNGCompile(ctxt, list); |
3079 | 0 | list = list->next; |
3080 | 0 | } |
3081 | 0 | xmlAutomataSetFinalState(ctxt->am, ctxt->state); |
3082 | 0 | if (xmlAutomataIsDeterminist(ctxt->am)) |
3083 | 0 | def->contModel = xmlAutomataCompile(ctxt->am); |
3084 | |
|
3085 | 0 | xmlFreeAutomata(ctxt->am); |
3086 | 0 | ctxt->state = oldstate; |
3087 | 0 | ctxt->am = oldam; |
3088 | 0 | } |
3089 | 0 | break; |
3090 | 0 | case XML_RELAXNG_ELEMENT: |
3091 | 0 | if ((ctxt->am != NULL) && (def->name != NULL)) { |
3092 | 0 | ctxt->state = xmlAutomataNewTransition2(ctxt->am, |
3093 | 0 | ctxt->state, NULL, |
3094 | 0 | def->name, def->ns, |
3095 | 0 | def); |
3096 | 0 | } |
3097 | 0 | if ((def->dflags & IS_COMPILABLE) && (def->depth != -25)) { |
3098 | 0 | xmlAutomataPtr oldam = ctxt->am; |
3099 | 0 | xmlAutomataStatePtr oldstate = ctxt->state; |
3100 | |
|
3101 | 0 | def->depth = -25; |
3102 | |
|
3103 | 0 | list = def->content; |
3104 | 0 | ctxt->am = xmlNewAutomata(); |
3105 | 0 | if (ctxt->am == NULL) |
3106 | 0 | return (-1); |
3107 | 0 | xmlAutomataSetFlags(ctxt->am, 1); |
3108 | 0 | ctxt->state = xmlAutomataGetInitState(ctxt->am); |
3109 | 0 | while (list != NULL) { |
3110 | 0 | xmlRelaxNGCompile(ctxt, list); |
3111 | 0 | list = list->next; |
3112 | 0 | } |
3113 | 0 | xmlAutomataSetFinalState(ctxt->am, ctxt->state); |
3114 | 0 | def->contModel = xmlAutomataCompile(ctxt->am); |
3115 | 0 | if (!xmlRegexpIsDeterminist(def->contModel)) { |
3116 | | #ifdef DEBUG_COMPILE |
3117 | | xmlGenericError(xmlGenericErrorContext, |
3118 | | "Content model not determinist %s\n", |
3119 | | def->name); |
3120 | | #endif |
3121 | | /* |
3122 | | * we can only use the automata if it is determinist |
3123 | | */ |
3124 | 0 | xmlRegFreeRegexp(def->contModel); |
3125 | 0 | def->contModel = NULL; |
3126 | 0 | } |
3127 | 0 | xmlFreeAutomata(ctxt->am); |
3128 | 0 | ctxt->state = oldstate; |
3129 | 0 | ctxt->am = oldam; |
3130 | 0 | } else { |
3131 | 0 | xmlAutomataPtr oldam = ctxt->am; |
3132 | | |
3133 | | /* |
3134 | | * we can't build the content model for this element content |
3135 | | * but it still might be possible to build it for some of its |
3136 | | * children, recurse. |
3137 | | */ |
3138 | 0 | ret = xmlRelaxNGTryCompile(ctxt, def); |
3139 | 0 | ctxt->am = oldam; |
3140 | 0 | } |
3141 | 0 | break; |
3142 | 0 | case XML_RELAXNG_NOOP: |
3143 | 0 | ret = xmlRelaxNGCompile(ctxt, def->content); |
3144 | 0 | break; |
3145 | 0 | case XML_RELAXNG_OPTIONAL:{ |
3146 | 0 | xmlAutomataStatePtr oldstate = ctxt->state; |
3147 | |
|
3148 | 0 | list = def->content; |
3149 | 0 | while (list != NULL) { |
3150 | 0 | xmlRelaxNGCompile(ctxt, list); |
3151 | 0 | list = list->next; |
3152 | 0 | } |
3153 | 0 | xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state); |
3154 | 0 | break; |
3155 | 0 | } |
3156 | 0 | case XML_RELAXNG_ZEROORMORE:{ |
3157 | 0 | xmlAutomataStatePtr oldstate; |
3158 | |
|
3159 | 0 | ctxt->state = |
3160 | 0 | xmlAutomataNewEpsilon(ctxt->am, ctxt->state, NULL); |
3161 | 0 | oldstate = ctxt->state; |
3162 | 0 | list = def->content; |
3163 | 0 | while (list != NULL) { |
3164 | 0 | xmlRelaxNGCompile(ctxt, list); |
3165 | 0 | list = list->next; |
3166 | 0 | } |
3167 | 0 | xmlAutomataNewEpsilon(ctxt->am, ctxt->state, oldstate); |
3168 | 0 | ctxt->state = |
3169 | 0 | xmlAutomataNewEpsilon(ctxt->am, oldstate, NULL); |
3170 | 0 | break; |
3171 | 0 | } |
3172 | 0 | case XML_RELAXNG_ONEORMORE:{ |
3173 | 0 | xmlAutomataStatePtr oldstate; |
3174 | |
|
3175 | 0 | list = def->content; |
3176 | 0 | while (list != NULL) { |
3177 | 0 | xmlRelaxNGCompile(ctxt, list); |
3178 | 0 | list = list->next; |
3179 | 0 | } |
3180 | 0 | oldstate = ctxt->state; |
3181 | 0 | list = def->content; |
3182 | 0 | while (list != NULL) { |
3183 | 0 | xmlRelaxNGCompile(ctxt, list); |
3184 | 0 | list = list->next; |
3185 | 0 | } |
3186 | 0 | xmlAutomataNewEpsilon(ctxt->am, ctxt->state, oldstate); |
3187 | 0 | ctxt->state = |
3188 | 0 | xmlAutomataNewEpsilon(ctxt->am, oldstate, NULL); |
3189 | 0 | break; |
3190 | 0 | } |
3191 | 0 | case XML_RELAXNG_CHOICE:{ |
3192 | 0 | xmlAutomataStatePtr target = NULL; |
3193 | 0 | xmlAutomataStatePtr oldstate = ctxt->state; |
3194 | |
|
3195 | 0 | list = def->content; |
3196 | 0 | while (list != NULL) { |
3197 | 0 | ctxt->state = oldstate; |
3198 | 0 | ret = xmlRelaxNGCompile(ctxt, list); |
3199 | 0 | if (ret != 0) |
3200 | 0 | break; |
3201 | 0 | if (target == NULL) |
3202 | 0 | target = ctxt->state; |
3203 | 0 | else { |
3204 | 0 | xmlAutomataNewEpsilon(ctxt->am, ctxt->state, |
3205 | 0 | target); |
3206 | 0 | } |
3207 | 0 | list = list->next; |
3208 | 0 | } |
3209 | 0 | ctxt->state = target; |
3210 | |
|
3211 | 0 | break; |
3212 | 0 | } |
3213 | 0 | case XML_RELAXNG_REF: |
3214 | 0 | case XML_RELAXNG_EXTERNALREF: |
3215 | 0 | case XML_RELAXNG_PARENTREF: |
3216 | 0 | case XML_RELAXNG_GROUP: |
3217 | 0 | case XML_RELAXNG_DEF: |
3218 | 0 | list = def->content; |
3219 | 0 | while (list != NULL) { |
3220 | 0 | ret = xmlRelaxNGCompile(ctxt, list); |
3221 | 0 | if (ret != 0) |
3222 | 0 | break; |
3223 | 0 | list = list->next; |
3224 | 0 | } |
3225 | 0 | break; |
3226 | 0 | case XML_RELAXNG_TEXT:{ |
3227 | 0 | xmlAutomataStatePtr oldstate; |
3228 | |
|
3229 | 0 | ctxt->state = |
3230 | 0 | xmlAutomataNewEpsilon(ctxt->am, ctxt->state, NULL); |
3231 | 0 | oldstate = ctxt->state; |
3232 | 0 | xmlRelaxNGCompile(ctxt, def->content); |
3233 | 0 | xmlAutomataNewTransition(ctxt->am, ctxt->state, |
3234 | 0 | ctxt->state, BAD_CAST "#text", |
3235 | 0 | NULL); |
3236 | 0 | ctxt->state = |
3237 | 0 | xmlAutomataNewEpsilon(ctxt->am, oldstate, NULL); |
3238 | 0 | break; |
3239 | 0 | } |
3240 | 0 | case XML_RELAXNG_EMPTY: |
3241 | 0 | ctxt->state = |
3242 | 0 | xmlAutomataNewEpsilon(ctxt->am, ctxt->state, NULL); |
3243 | 0 | break; |
3244 | 0 | case XML_RELAXNG_EXCEPT: |
3245 | 0 | case XML_RELAXNG_ATTRIBUTE: |
3246 | 0 | case XML_RELAXNG_INTERLEAVE: |
3247 | 0 | case XML_RELAXNG_NOT_ALLOWED: |
3248 | 0 | case XML_RELAXNG_DATATYPE: |
3249 | 0 | case XML_RELAXNG_LIST: |
3250 | 0 | case XML_RELAXNG_PARAM: |
3251 | 0 | case XML_RELAXNG_VALUE: |
3252 | | /* This should not happen and generate an internal error */ |
3253 | 0 | fprintf(stderr, "RNG internal error trying to compile %s\n", |
3254 | 0 | xmlRelaxNGDefName(def)); |
3255 | 0 | break; |
3256 | 0 | } |
3257 | 0 | return (ret); |
3258 | 0 | } |
3259 | | |
3260 | | /** |
3261 | | * xmlRelaxNGTryCompile: |
3262 | | * ctxt: the RelaxNG parser context |
3263 | | * @define: the definition tree to compile |
3264 | | * |
3265 | | * Try to compile the set of definitions, it works recursively, |
3266 | | * possibly ignoring parts which cannot be compiled. |
3267 | | * |
3268 | | * Returns 0 if success and -1 in case of error |
3269 | | */ |
3270 | | static int |
3271 | | xmlRelaxNGTryCompile(xmlRelaxNGParserCtxtPtr ctxt, xmlRelaxNGDefinePtr def) |
3272 | 0 | { |
3273 | 0 | int ret = 0; |
3274 | 0 | xmlRelaxNGDefinePtr list; |
3275 | |
|
3276 | 0 | if ((ctxt == NULL) || (def == NULL)) |
3277 | 0 | return (-1); |
3278 | | |
3279 | 0 | if ((def->type == XML_RELAXNG_START) || |
3280 | 0 | (def->type == XML_RELAXNG_ELEMENT)) { |
3281 | 0 | ret = xmlRelaxNGIsCompilable(def); |
3282 | 0 | if ((def->dflags & IS_COMPILABLE) && (def->depth != -25)) { |
3283 | 0 | ctxt->am = NULL; |
3284 | 0 | ret = xmlRelaxNGCompile(ctxt, def); |
3285 | | #ifdef DEBUG_PROGRESSIVE |
3286 | | if (ret == 0) { |
3287 | | if (def->type == XML_RELAXNG_START) |
3288 | | xmlGenericError(xmlGenericErrorContext, |
3289 | | "compiled the start\n"); |
3290 | | else |
3291 | | xmlGenericError(xmlGenericErrorContext, |
3292 | | "compiled element %s\n", def->name); |
3293 | | } else { |
3294 | | if (def->type == XML_RELAXNG_START) |
3295 | | xmlGenericError(xmlGenericErrorContext, |
3296 | | "failed to compile the start\n"); |
3297 | | else |
3298 | | xmlGenericError(xmlGenericErrorContext, |
3299 | | "failed to compile element %s\n", |
3300 | | def->name); |
3301 | | } |
3302 | | #endif |
3303 | 0 | return (ret); |
3304 | 0 | } |
3305 | 0 | } |
3306 | 0 | switch (def->type) { |
3307 | 0 | case XML_RELAXNG_NOOP: |
3308 | 0 | ret = xmlRelaxNGTryCompile(ctxt, def->content); |
3309 | 0 | break; |
3310 | 0 | case XML_RELAXNG_TEXT: |
3311 | 0 | case XML_RELAXNG_DATATYPE: |
3312 | 0 | case XML_RELAXNG_LIST: |
3313 | 0 | case XML_RELAXNG_PARAM: |
3314 | 0 | case XML_RELAXNG_VALUE: |
3315 | 0 | case XML_RELAXNG_EMPTY: |
3316 | 0 | case XML_RELAXNG_ELEMENT: |
3317 | 0 | ret = 0; |
3318 | 0 | break; |
3319 | 0 | case XML_RELAXNG_OPTIONAL: |
3320 | 0 | case XML_RELAXNG_ZEROORMORE: |
3321 | 0 | case XML_RELAXNG_ONEORMORE: |
3322 | 0 | case XML_RELAXNG_CHOICE: |
3323 | 0 | case XML_RELAXNG_GROUP: |
3324 | 0 | case XML_RELAXNG_DEF: |
3325 | 0 | case XML_RELAXNG_START: |
3326 | 0 | case XML_RELAXNG_REF: |
3327 | 0 | case XML_RELAXNG_EXTERNALREF: |
3328 | 0 | case XML_RELAXNG_PARENTREF: |
3329 | 0 | list = def->content; |
3330 | 0 | while (list != NULL) { |
3331 | 0 | ret = xmlRelaxNGTryCompile(ctxt, list); |
3332 | 0 | if (ret != 0) |
3333 | 0 | break; |
3334 | 0 | list = list->next; |
3335 | 0 | } |
3336 | 0 | break; |
3337 | 0 | case XML_RELAXNG_EXCEPT: |
3338 | 0 | case XML_RELAXNG_ATTRIBUTE: |
3339 | 0 | case XML_RELAXNG_INTERLEAVE: |
3340 | 0 | case XML_RELAXNG_NOT_ALLOWED: |
3341 | 0 | ret = 0; |
3342 | 0 | break; |
3343 | 0 | } |
3344 | 0 | return (ret); |
3345 | 0 | } |
3346 | | |
3347 | | /************************************************************************ |
3348 | | * * |
3349 | | * Parsing functions * |
3350 | | * * |
3351 | | ************************************************************************/ |
3352 | | |
3353 | | static xmlRelaxNGDefinePtr xmlRelaxNGParseAttribute(xmlRelaxNGParserCtxtPtr |
3354 | | ctxt, xmlNodePtr node); |
3355 | | static xmlRelaxNGDefinePtr xmlRelaxNGParseElement(xmlRelaxNGParserCtxtPtr |
3356 | | ctxt, xmlNodePtr node); |
3357 | | static xmlRelaxNGDefinePtr xmlRelaxNGParsePatterns(xmlRelaxNGParserCtxtPtr |
3358 | | ctxt, xmlNodePtr nodes, |
3359 | | int group); |
3360 | | static xmlRelaxNGDefinePtr xmlRelaxNGParsePattern(xmlRelaxNGParserCtxtPtr |
3361 | | ctxt, xmlNodePtr node); |
3362 | | static xmlRelaxNGPtr xmlRelaxNGParseDocument(xmlRelaxNGParserCtxtPtr ctxt, |
3363 | | xmlNodePtr node); |
3364 | | static int xmlRelaxNGParseGrammarContent(xmlRelaxNGParserCtxtPtr ctxt, |
3365 | | xmlNodePtr nodes); |
3366 | | static xmlRelaxNGDefinePtr xmlRelaxNGParseNameClass(xmlRelaxNGParserCtxtPtr |
3367 | | ctxt, xmlNodePtr node, |
3368 | | xmlRelaxNGDefinePtr |
3369 | | def); |
3370 | | static xmlRelaxNGGrammarPtr xmlRelaxNGParseGrammar(xmlRelaxNGParserCtxtPtr |
3371 | | ctxt, xmlNodePtr nodes); |
3372 | | static int xmlRelaxNGElementMatch(xmlRelaxNGValidCtxtPtr ctxt, |
3373 | | xmlRelaxNGDefinePtr define, |
3374 | | xmlNodePtr elem); |
3375 | | |
3376 | | |
3377 | 0 | #define IS_BLANK_NODE(n) (xmlRelaxNGIsBlank((n)->content)) |
3378 | | |
3379 | | /** |
3380 | | * xmlRelaxNGIsNullable: |
3381 | | * @define: the definition to verify |
3382 | | * |
3383 | | * Check if a definition is nullable. |
3384 | | * |
3385 | | * Returns 1 if yes, 0 if no and -1 in case of error |
3386 | | */ |
3387 | | static int |
3388 | | xmlRelaxNGIsNullable(xmlRelaxNGDefinePtr define) |
3389 | 0 | { |
3390 | 0 | int ret; |
3391 | |
|
3392 | 0 | if (define == NULL) |
3393 | 0 | return (-1); |
3394 | | |
3395 | 0 | if (define->dflags & IS_NULLABLE) |
3396 | 0 | return (1); |
3397 | 0 | if (define->dflags & IS_NOT_NULLABLE) |
3398 | 0 | return (0); |
3399 | 0 | switch (define->type) { |
3400 | 0 | case XML_RELAXNG_EMPTY: |
3401 | 0 | case XML_RELAXNG_TEXT: |
3402 | 0 | ret = 1; |
3403 | 0 | break; |
3404 | 0 | case XML_RELAXNG_NOOP: |
3405 | 0 | case XML_RELAXNG_DEF: |
3406 | 0 | case XML_RELAXNG_REF: |
3407 | 0 | case XML_RELAXNG_EXTERNALREF: |
3408 | 0 | case XML_RELAXNG_PARENTREF: |
3409 | 0 | case XML_RELAXNG_ONEORMORE: |
3410 | 0 | ret = xmlRelaxNGIsNullable(define->content); |
3411 | 0 | break; |
3412 | 0 | case XML_RELAXNG_EXCEPT: |
3413 | 0 | case XML_RELAXNG_NOT_ALLOWED: |
3414 | 0 | case XML_RELAXNG_ELEMENT: |
3415 | 0 | case XML_RELAXNG_DATATYPE: |
3416 | 0 | case XML_RELAXNG_PARAM: |
3417 | 0 | case XML_RELAXNG_VALUE: |
3418 | 0 | case XML_RELAXNG_LIST: |
3419 | 0 | case XML_RELAXNG_ATTRIBUTE: |
3420 | 0 | ret = 0; |
3421 | 0 | break; |
3422 | 0 | case XML_RELAXNG_CHOICE:{ |
3423 | 0 | xmlRelaxNGDefinePtr list = define->content; |
3424 | |
|
3425 | 0 | while (list != NULL) { |
3426 | 0 | ret = xmlRelaxNGIsNullable(list); |
3427 | 0 | if (ret != 0) |
3428 | 0 | goto done; |
3429 | 0 | list = list->next; |
3430 | 0 | } |
3431 | 0 | ret = 0; |
3432 | 0 | break; |
3433 | 0 | } |
3434 | 0 | case XML_RELAXNG_START: |
3435 | 0 | case XML_RELAXNG_INTERLEAVE: |
3436 | 0 | case XML_RELAXNG_GROUP:{ |
3437 | 0 | xmlRelaxNGDefinePtr list = define->content; |
3438 | |
|
3439 | 0 | while (list != NULL) { |
3440 | 0 | ret = xmlRelaxNGIsNullable(list); |
3441 | 0 | if (ret != 1) |
3442 | 0 | goto done; |
3443 | 0 | list = list->next; |
3444 | 0 | } |
3445 | 0 | return (1); |
3446 | 0 | } |
3447 | 0 | default: |
3448 | 0 | return (-1); |
3449 | 0 | } |
3450 | 0 | done: |
3451 | 0 | if (ret == 0) |
3452 | 0 | define->dflags |= IS_NOT_NULLABLE; |
3453 | 0 | if (ret == 1) |
3454 | 0 | define->dflags |= IS_NULLABLE; |
3455 | 0 | return (ret); |
3456 | 0 | } |
3457 | | |
3458 | | /** |
3459 | | * xmlRelaxNGIsBlank: |
3460 | | * @str: a string |
3461 | | * |
3462 | | * Check if a string is ignorable c.f. 4.2. Whitespace |
3463 | | * |
3464 | | * Returns 1 if the string is NULL or made of blanks chars, 0 otherwise |
3465 | | */ |
3466 | | static int |
3467 | | xmlRelaxNGIsBlank(xmlChar * str) |
3468 | 0 | { |
3469 | 0 | if (str == NULL) |
3470 | 0 | return (1); |
3471 | 0 | while (*str != 0) { |
3472 | 0 | if (!(IS_BLANK_CH(*str))) |
3473 | 0 | return (0); |
3474 | 0 | str++; |
3475 | 0 | } |
3476 | 0 | return (1); |
3477 | 0 | } |
3478 | | |
3479 | | /** |
3480 | | * xmlRelaxNGGetDataTypeLibrary: |
3481 | | * @ctxt: a Relax-NG parser context |
3482 | | * @node: the current data or value element |
3483 | | * |
3484 | | * Applies algorithm from 4.3. datatypeLibrary attribute |
3485 | | * |
3486 | | * Returns the datatypeLibrary value or NULL if not found |
3487 | | */ |
3488 | | static xmlChar * |
3489 | | xmlRelaxNGGetDataTypeLibrary(xmlRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED, |
3490 | | xmlNodePtr node) |
3491 | 0 | { |
3492 | 0 | xmlChar *ret, *escape; |
3493 | |
|
3494 | 0 | if (node == NULL) |
3495 | 0 | return(NULL); |
3496 | | |
3497 | 0 | if ((IS_RELAXNG(node, "data")) || (IS_RELAXNG(node, "value"))) { |
3498 | 0 | ret = xmlGetProp(node, BAD_CAST "datatypeLibrary"); |
3499 | 0 | if (ret != NULL) { |
3500 | 0 | if (ret[0] == 0) { |
3501 | 0 | xmlFree(ret); |
3502 | 0 | return (NULL); |
3503 | 0 | } |
3504 | 0 | escape = xmlURIEscapeStr(ret, BAD_CAST ":/#?"); |
3505 | 0 | if (escape == NULL) { |
3506 | 0 | return (ret); |
3507 | 0 | } |
3508 | 0 | xmlFree(ret); |
3509 | 0 | return (escape); |
3510 | 0 | } |
3511 | 0 | } |
3512 | 0 | node = node->parent; |
3513 | 0 | while ((node != NULL) && (node->type == XML_ELEMENT_NODE)) { |
3514 | 0 | ret = xmlGetProp(node, BAD_CAST "datatypeLibrary"); |
3515 | 0 | if (ret != NULL) { |
3516 | 0 | if (ret[0] == 0) { |
3517 | 0 | xmlFree(ret); |
3518 | 0 | return (NULL); |
3519 | 0 | } |
3520 | 0 | escape = xmlURIEscapeStr(ret, BAD_CAST ":/#?"); |
3521 | 0 | if (escape == NULL) { |
3522 | 0 | return (ret); |
3523 | 0 | } |
3524 | 0 | xmlFree(ret); |
3525 | 0 | return (escape); |
3526 | 0 | } |
3527 | 0 | node = node->parent; |
3528 | 0 | } |
3529 | 0 | return (NULL); |
3530 | 0 | } |
3531 | | |
3532 | | /** |
3533 | | * xmlRelaxNGParseValue: |
3534 | | * @ctxt: a Relax-NG parser context |
3535 | | * @node: the data node. |
3536 | | * |
3537 | | * parse the content of a RelaxNG value node. |
3538 | | * |
3539 | | * Returns the definition pointer or NULL in case of error |
3540 | | */ |
3541 | | static xmlRelaxNGDefinePtr |
3542 | | xmlRelaxNGParseValue(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) |
3543 | 0 | { |
3544 | 0 | xmlRelaxNGDefinePtr def = NULL; |
3545 | 0 | xmlRelaxNGTypeLibraryPtr lib = NULL; |
3546 | 0 | xmlChar *type; |
3547 | 0 | xmlChar *library; |
3548 | 0 | int success = 0; |
3549 | |
|
3550 | 0 | def = xmlRelaxNGNewDefine(ctxt, node); |
3551 | 0 | if (def == NULL) |
3552 | 0 | return (NULL); |
3553 | 0 | def->type = XML_RELAXNG_VALUE; |
3554 | |
|
3555 | 0 | type = xmlGetProp(node, BAD_CAST "type"); |
3556 | 0 | if (type != NULL) { |
3557 | 0 | xmlRelaxNGNormExtSpace(type); |
3558 | 0 | if (xmlValidateNCName(type, 0)) { |
3559 | 0 | xmlRngPErr(ctxt, node, XML_RNGP_TYPE_VALUE, |
3560 | 0 | "value type '%s' is not an NCName\n", type, NULL); |
3561 | 0 | } |
3562 | 0 | library = xmlRelaxNGGetDataTypeLibrary(ctxt, node); |
3563 | 0 | if (library == NULL) |
3564 | 0 | library = |
3565 | 0 | xmlStrdup(BAD_CAST "http://relaxng.org/ns/structure/1.0"); |
3566 | |
|
3567 | 0 | def->name = type; |
3568 | 0 | def->ns = library; |
3569 | |
|
3570 | 0 | lib = (xmlRelaxNGTypeLibraryPtr) |
3571 | 0 | xmlHashLookup(xmlRelaxNGRegisteredTypes, library); |
3572 | 0 | if (lib == NULL) { |
3573 | 0 | xmlRngPErr(ctxt, node, XML_RNGP_UNKNOWN_TYPE_LIB, |
3574 | 0 | "Use of unregistered type library '%s'\n", library, |
3575 | 0 | NULL); |
3576 | 0 | def->data = NULL; |
3577 | 0 | } else { |
3578 | 0 | def->data = lib; |
3579 | 0 | if (lib->have == NULL) { |
3580 | 0 | xmlRngPErr(ctxt, node, XML_RNGP_ERROR_TYPE_LIB, |
3581 | 0 | "Internal error with type library '%s': no 'have'\n", |
3582 | 0 | library, NULL); |
3583 | 0 | } else { |
3584 | 0 | success = lib->have(lib->data, def->name); |
3585 | 0 | if (success != 1) { |
3586 | 0 | xmlRngPErr(ctxt, node, XML_RNGP_TYPE_NOT_FOUND, |
3587 | 0 | "Error type '%s' is not exported by type library '%s'\n", |
3588 | 0 | def->name, library); |
3589 | 0 | } |
3590 | 0 | } |
3591 | 0 | } |
3592 | 0 | } |
3593 | 0 | if (node->children == NULL) { |
3594 | 0 | def->value = xmlStrdup(BAD_CAST ""); |
3595 | 0 | } else if (((node->children->type != XML_TEXT_NODE) && |
3596 | 0 | (node->children->type != XML_CDATA_SECTION_NODE)) || |
3597 | 0 | (node->children->next != NULL)) { |
3598 | 0 | xmlRngPErr(ctxt, node, XML_RNGP_TEXT_EXPECTED, |
3599 | 0 | "Expecting a single text value for <value>content\n", |
3600 | 0 | NULL, NULL); |
3601 | 0 | } else if (def != NULL) { |
3602 | 0 | def->value = xmlNodeGetContent(node); |
3603 | 0 | if (def->value == NULL) { |
3604 | 0 | xmlRngPErr(ctxt, node, XML_RNGP_VALUE_NO_CONTENT, |
3605 | 0 | "Element <value> has no content\n", NULL, NULL); |
3606 | 0 | } else if ((lib != NULL) && (lib->check != NULL) && (success == 1)) { |
3607 | 0 | void *val = NULL; |
3608 | |
|
3609 | 0 | success = |
3610 | 0 | lib->check(lib->data, def->name, def->value, &val, node); |
3611 | 0 | if (success != 1) { |
3612 | 0 | xmlRngPErr(ctxt, node, XML_RNGP_INVALID_VALUE, |
3613 | 0 | "Value '%s' is not acceptable for type '%s'\n", |
3614 | 0 | def->value, def->name); |
3615 | 0 | } else { |
3616 | 0 | if (val != NULL) |
3617 | 0 | def->attrs = val; |
3618 | 0 | } |
3619 | 0 | } |
3620 | 0 | } |
3621 | 0 | return (def); |
3622 | 0 | } |
3623 | | |
3624 | | /** |
3625 | | * xmlRelaxNGParseData: |
3626 | | * @ctxt: a Relax-NG parser context |
3627 | | * @node: the data node. |
3628 | | * |
3629 | | * parse the content of a RelaxNG data node. |
3630 | | * |
3631 | | * Returns the definition pointer or NULL in case of error |
3632 | | */ |
3633 | | static xmlRelaxNGDefinePtr |
3634 | | xmlRelaxNGParseData(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) |
3635 | 0 | { |
3636 | 0 | xmlRelaxNGDefinePtr def = NULL, except; |
3637 | 0 | xmlRelaxNGDefinePtr param, lastparam = NULL; |
3638 | 0 | xmlRelaxNGTypeLibraryPtr lib; |
3639 | 0 | xmlChar *type; |
3640 | 0 | xmlChar *library; |
3641 | 0 | xmlNodePtr content; |
3642 | 0 | int tmp; |
3643 | |
|
3644 | 0 | type = xmlGetProp(node, BAD_CAST "type"); |
3645 | 0 | if (type == NULL) { |
3646 | 0 | xmlRngPErr(ctxt, node, XML_RNGP_TYPE_MISSING, "data has no type\n", NULL, |
3647 | 0 | NULL); |
3648 | 0 | return (NULL); |
3649 | 0 | } |
3650 | 0 | xmlRelaxNGNormExtSpace(type); |
3651 | 0 | if (xmlValidateNCName(type, 0)) { |
3652 | 0 | xmlRngPErr(ctxt, node, XML_RNGP_TYPE_VALUE, |
3653 | 0 | "data type '%s' is not an NCName\n", type, NULL); |
3654 | 0 | } |
3655 | 0 | library = xmlRelaxNGGetDataTypeLibrary(ctxt, node); |
3656 | 0 | if (library == NULL) |
3657 | 0 | library = |
3658 | 0 | xmlStrdup(BAD_CAST "http://relaxng.org/ns/structure/1.0"); |
3659 | |
|
3660 | 0 | def = xmlRelaxNGNewDefine(ctxt, node); |
3661 | 0 | if (def == NULL) { |
3662 | 0 | xmlFree(library); |
3663 | 0 | xmlFree(type); |
3664 | 0 | return (NULL); |
3665 | 0 | } |
3666 | 0 | def->type = XML_RELAXNG_DATATYPE; |
3667 | 0 | def->name = type; |
3668 | 0 | def->ns = library; |
3669 | |
|
3670 | 0 | lib = (xmlRelaxNGTypeLibraryPtr) |
3671 | 0 | xmlHashLookup(xmlRelaxNGRegisteredTypes, library); |
3672 | 0 | if (lib == NULL) { |
3673 | 0 | xmlRngPErr(ctxt, node, XML_RNGP_UNKNOWN_TYPE_LIB, |
3674 | 0 | "Use of unregistered type library '%s'\n", library, |
3675 | 0 | NULL); |
3676 | 0 | def->data = NULL; |
3677 | 0 | } else { |
3678 | 0 | def->data = lib; |
3679 | 0 | if (lib->have == NULL) { |
3680 | 0 | xmlRngPErr(ctxt, node, XML_RNGP_ERROR_TYPE_LIB, |
3681 | 0 | "Internal error with type library '%s': no 'have'\n", |
3682 | 0 | library, NULL); |
3683 | 0 | } else { |
3684 | 0 | tmp = lib->have(lib->data, def->name); |
3685 | 0 | if (tmp != 1) { |
3686 | 0 | xmlRngPErr(ctxt, node, XML_RNGP_TYPE_NOT_FOUND, |
3687 | 0 | "Error type '%s' is not exported by type library '%s'\n", |
3688 | 0 | def->name, library); |
3689 | 0 | } else |
3690 | 0 | if ((xmlStrEqual |
3691 | 0 | (library, |
3692 | 0 | BAD_CAST |
3693 | 0 | "http://www.w3.org/2001/XMLSchema-datatypes")) |
3694 | 0 | && ((xmlStrEqual(def->name, BAD_CAST "IDREF")) |
3695 | 0 | || (xmlStrEqual(def->name, BAD_CAST "IDREFS")))) { |
3696 | 0 | ctxt->idref = 1; |
3697 | 0 | } |
3698 | 0 | } |
3699 | 0 | } |
3700 | 0 | content = node->children; |
3701 | | |
3702 | | /* |
3703 | | * Handle optional params |
3704 | | */ |
3705 | 0 | while (content != NULL) { |
3706 | 0 | if (!xmlStrEqual(content->name, BAD_CAST "param")) |
3707 | 0 | break; |
3708 | 0 | if (xmlStrEqual(library, |
3709 | 0 | BAD_CAST "http://relaxng.org/ns/structure/1.0")) { |
3710 | 0 | xmlRngPErr(ctxt, node, XML_RNGP_PARAM_FORBIDDEN, |
3711 | 0 | "Type library '%s' does not allow type parameters\n", |
3712 | 0 | library, NULL); |
3713 | 0 | content = content->next; |
3714 | 0 | while ((content != NULL) && |
3715 | 0 | (xmlStrEqual(content->name, BAD_CAST "param"))) |
3716 | 0 | content = content->next; |
3717 | 0 | } else { |
3718 | 0 | param = xmlRelaxNGNewDefine(ctxt, node); |
3719 | 0 | if (param != NULL) { |
3720 | 0 | param->type = XML_RELAXNG_PARAM; |
3721 | 0 | param->name = xmlGetProp(content, BAD_CAST "name"); |
3722 | 0 | if (param->name == NULL) { |
3723 | 0 | xmlRngPErr(ctxt, node, XML_RNGP_PARAM_NAME_MISSING, |
3724 | 0 | "param has no name\n", NULL, NULL); |
3725 | 0 | } |
3726 | 0 | param->value = xmlNodeGetContent(content); |
3727 | 0 | if (lastparam == NULL) { |
3728 | 0 | def->attrs = lastparam = param; |
3729 | 0 | } else { |
3730 | 0 | lastparam->next = param; |
3731 | 0 | lastparam = param; |
3732 | 0 | } |
3733 | 0 | if (lib != NULL) { |
3734 | 0 | } |
3735 | 0 | } |
3736 | 0 | content = content->next; |
3737 | 0 | } |
3738 | 0 | } |
3739 | | /* |
3740 | | * Handle optional except |
3741 | | */ |
3742 | 0 | if ((content != NULL) |
3743 | 0 | && (xmlStrEqual(content->name, BAD_CAST "except"))) { |
3744 | 0 | xmlNodePtr child; |
3745 | 0 | xmlRelaxNGDefinePtr tmp2, last = NULL; |
3746 | |
|
3747 | 0 | except = xmlRelaxNGNewDefine(ctxt, node); |
3748 | 0 | if (except == NULL) { |
3749 | 0 | return (def); |
3750 | 0 | } |
3751 | 0 | except->type = XML_RELAXNG_EXCEPT; |
3752 | 0 | child = content->children; |
3753 | 0 | def->content = except; |
3754 | 0 | if (child == NULL) { |
3755 | 0 | xmlRngPErr(ctxt, content, XML_RNGP_EXCEPT_NO_CONTENT, |
3756 | 0 | "except has no content\n", NULL, NULL); |
3757 | 0 | } |
3758 | 0 | while (child != NULL) { |
3759 | 0 | tmp2 = xmlRelaxNGParsePattern(ctxt, child); |
3760 | 0 | if (tmp2 != NULL) { |
3761 | 0 | if (last == NULL) { |
3762 | 0 | except->content = last = tmp2; |
3763 | 0 | } else { |
3764 | 0 | last->next = tmp2; |
3765 | 0 | last = tmp2; |
3766 | 0 | } |
3767 | 0 | } |
3768 | 0 | child = child->next; |
3769 | 0 | } |
3770 | 0 | content = content->next; |
3771 | 0 | } |
3772 | | /* |
3773 | | * Check there is no unhandled data |
3774 | | */ |
3775 | 0 | if (content != NULL) { |
3776 | 0 | xmlRngPErr(ctxt, content, XML_RNGP_DATA_CONTENT, |
3777 | 0 | "Element data has unexpected content %s\n", |
3778 | 0 | content->name, NULL); |
3779 | 0 | } |
3780 | |
|
3781 | 0 | return (def); |
3782 | 0 | } |
3783 | | |
3784 | | static const xmlChar *invalidName = BAD_CAST "\1"; |
3785 | | |
3786 | | /** |
3787 | | * xmlRelaxNGCompareNameClasses: |
3788 | | * @defs1: the first element/attribute defs |
3789 | | * @defs2: the second element/attribute defs |
3790 | | * @name: the restriction on the name |
3791 | | * @ns: the restriction on the namespace |
3792 | | * |
3793 | | * Compare the 2 lists of element definitions. The comparison is |
3794 | | * that if both lists do not accept the same QNames, it returns 1 |
3795 | | * If the 2 lists can accept the same QName the comparison returns 0 |
3796 | | * |
3797 | | * Returns 1 distinct, 0 if equal |
3798 | | */ |
3799 | | static int |
3800 | | xmlRelaxNGCompareNameClasses(xmlRelaxNGDefinePtr def1, |
3801 | | xmlRelaxNGDefinePtr def2) |
3802 | 0 | { |
3803 | 0 | int ret = 1; |
3804 | 0 | xmlNode node; |
3805 | 0 | xmlNs ns; |
3806 | 0 | xmlRelaxNGValidCtxt ctxt; |
3807 | |
|
3808 | 0 | memset(&ctxt, 0, sizeof(xmlRelaxNGValidCtxt)); |
3809 | |
|
3810 | 0 | ctxt.flags = FLAGS_IGNORABLE | FLAGS_NOERROR; |
3811 | |
|
3812 | 0 | if ((def1->type == XML_RELAXNG_ELEMENT) || |
3813 | 0 | (def1->type == XML_RELAXNG_ATTRIBUTE)) { |
3814 | 0 | if (def2->type == XML_RELAXNG_TEXT) |
3815 | 0 | return (1); |
3816 | 0 | if (def1->name != NULL) { |
3817 | 0 | node.name = def1->name; |
3818 | 0 | } else { |
3819 | 0 | node.name = invalidName; |
3820 | 0 | } |
3821 | 0 | if (def1->ns != NULL) { |
3822 | 0 | if (def1->ns[0] == 0) { |
3823 | 0 | node.ns = NULL; |
3824 | 0 | } else { |
3825 | 0 | node.ns = &ns; |
3826 | 0 | ns.href = def1->ns; |
3827 | 0 | } |
3828 | 0 | } else { |
3829 | 0 | node.ns = NULL; |
3830 | 0 | } |
3831 | 0 | if (xmlRelaxNGElementMatch(&ctxt, def2, &node)) { |
3832 | 0 | if (def1->nameClass != NULL) { |
3833 | 0 | ret = xmlRelaxNGCompareNameClasses(def1->nameClass, def2); |
3834 | 0 | } else { |
3835 | 0 | ret = 0; |
3836 | 0 | } |
3837 | 0 | } else { |
3838 | 0 | ret = 1; |
3839 | 0 | } |
3840 | 0 | } else if (def1->type == XML_RELAXNG_TEXT) { |
3841 | 0 | if (def2->type == XML_RELAXNG_TEXT) |
3842 | 0 | return (0); |
3843 | 0 | return (1); |
3844 | 0 | } else if (def1->type == XML_RELAXNG_EXCEPT) { |
3845 | 0 | ret = xmlRelaxNGCompareNameClasses(def1->content, def2); |
3846 | 0 | if (ret == 0) |
3847 | 0 | ret = 1; |
3848 | 0 | else if (ret == 1) |
3849 | 0 | ret = 0; |
3850 | 0 | } else { |
3851 | 0 | TODO ret = 0; |
3852 | 0 | } |
3853 | 0 | if (ret == 0) |
3854 | 0 | return (ret); |
3855 | 0 | if ((def2->type == XML_RELAXNG_ELEMENT) || |
3856 | 0 | (def2->type == XML_RELAXNG_ATTRIBUTE)) { |
3857 | 0 | if (def2->name != NULL) { |
3858 | 0 | node.name = def2->name; |
3859 | 0 | } else { |
3860 | 0 | node.name = invalidName; |
3861 | 0 | } |
3862 | 0 | node.ns = &ns; |
3863 | 0 | if (def2->ns != NULL) { |
3864 | 0 | if (def2->ns[0] == 0) { |
3865 | 0 | node.ns = NULL; |
3866 | 0 | } else { |
3867 | 0 | ns.href = def2->ns; |
3868 | 0 | } |
3869 | 0 | } else { |
3870 | 0 | ns.href = invalidName; |
3871 | 0 | } |
3872 | 0 | if (xmlRelaxNGElementMatch(&ctxt, def1, &node)) { |
3873 | 0 | if (def2->nameClass != NULL) { |
3874 | 0 | ret = xmlRelaxNGCompareNameClasses(def2->nameClass, def1); |
3875 | 0 | } else { |
3876 | 0 | ret = 0; |
3877 | 0 | } |
3878 | 0 | } else { |
3879 | 0 | ret = 1; |
3880 | 0 | } |
3881 | 0 | } else { |
3882 | 0 | TODO ret = 0; |
3883 | 0 | } |
3884 | |
|
3885 | 0 | return (ret); |
3886 | 0 | } |
3887 | | |
3888 | | /** |
3889 | | * xmlRelaxNGCompareElemDefLists: |
3890 | | * @ctxt: a Relax-NG parser context |
3891 | | * @defs1: the first list of element/attribute defs |
3892 | | * @defs2: the second list of element/attribute defs |
3893 | | * |
3894 | | * Compare the 2 lists of element or attribute definitions. The comparison |
3895 | | * is that if both lists do not accept the same QNames, it returns 1 |
3896 | | * If the 2 lists can accept the same QName the comparison returns 0 |
3897 | | * |
3898 | | * Returns 1 distinct, 0 if equal |
3899 | | */ |
3900 | | static int |
3901 | | xmlRelaxNGCompareElemDefLists(xmlRelaxNGParserCtxtPtr ctxt |
3902 | | ATTRIBUTE_UNUSED, xmlRelaxNGDefinePtr * def1, |
3903 | | xmlRelaxNGDefinePtr * def2) |
3904 | 0 | { |
3905 | 0 | xmlRelaxNGDefinePtr *basedef2 = def2; |
3906 | |
|
3907 | 0 | if ((def1 == NULL) || (def2 == NULL)) |
3908 | 0 | return (1); |
3909 | 0 | if ((*def1 == NULL) || (*def2 == NULL)) |
3910 | 0 | return (1); |
3911 | 0 | while (*def1 != NULL) { |
3912 | 0 | while ((*def2) != NULL) { |
3913 | 0 | if (xmlRelaxNGCompareNameClasses(*def1, *def2) == 0) |
3914 | 0 | return (0); |
3915 | 0 | def2++; |
3916 | 0 | } |
3917 | 0 | def2 = basedef2; |
3918 | 0 | def1++; |
3919 | 0 | } |
3920 | 0 | return (1); |
3921 | 0 | } |
3922 | | |
3923 | | /** |
3924 | | * xmlRelaxNGGenerateAttributes: |
3925 | | * @ctxt: a Relax-NG parser context |
3926 | | * @def: the definition definition |
3927 | | * |
3928 | | * Check if the definition can only generate attributes |
3929 | | * |
3930 | | * Returns 1 if yes, 0 if no and -1 in case of error. |
3931 | | */ |
3932 | | static int |
3933 | | xmlRelaxNGGenerateAttributes(xmlRelaxNGParserCtxtPtr ctxt, |
3934 | | xmlRelaxNGDefinePtr def) |
3935 | 0 | { |
3936 | 0 | xmlRelaxNGDefinePtr parent, cur, tmp; |
3937 | | |
3938 | | /* |
3939 | | * Don't run that check in case of error. Infinite recursion |
3940 | | * becomes possible. |
3941 | | */ |
3942 | 0 | if (ctxt->nbErrors != 0) |
3943 | 0 | return (-1); |
3944 | | |
3945 | 0 | parent = NULL; |
3946 | 0 | cur = def; |
3947 | 0 | while (cur != NULL) { |
3948 | 0 | if ((cur->type == XML_RELAXNG_ELEMENT) || |
3949 | 0 | (cur->type == XML_RELAXNG_TEXT) || |
3950 | 0 | (cur->type == XML_RELAXNG_DATATYPE) || |
3951 | 0 | (cur->type == XML_RELAXNG_PARAM) || |
3952 | 0 | (cur->type == XML_RELAXNG_LIST) || |
3953 | 0 | (cur->type == XML_RELAXNG_VALUE) || |
3954 | 0 | (cur->type == XML_RELAXNG_EMPTY)) |
3955 | 0 | return (0); |
3956 | 0 | if ((cur->type == XML_RELAXNG_CHOICE) || |
3957 | 0 | (cur->type == XML_RELAXNG_INTERLEAVE) || |
3958 | 0 | (cur->type == XML_RELAXNG_GROUP) || |
3959 | 0 | (cur->type == XML_RELAXNG_ONEORMORE) || |
3960 | 0 | (cur->type == XML_RELAXNG_ZEROORMORE) || |
3961 | 0 | (cur->type == XML_RELAXNG_OPTIONAL) || |
3962 | 0 | (cur->type == XML_RELAXNG_PARENTREF) || |
3963 | 0 | (cur->type == XML_RELAXNG_EXTERNALREF) || |
3964 | 0 | (cur->type == XML_RELAXNG_REF) || |
3965 | 0 | (cur->type == XML_RELAXNG_DEF)) { |
3966 | 0 | if (cur->content != NULL) { |
3967 | 0 | parent = cur; |
3968 | 0 | cur = cur->content; |
3969 | 0 | tmp = cur; |
3970 | 0 | while (tmp != NULL) { |
3971 | 0 | tmp->parent = parent; |
3972 | 0 | tmp = tmp->next; |
3973 | 0 | } |
3974 | 0 | continue; |
3975 | 0 | } |
3976 | 0 | } |
3977 | 0 | if (cur == def) |
3978 | 0 | break; |
3979 | 0 | if (cur->next != NULL) { |
3980 | 0 | cur = cur->next; |
3981 | 0 | continue; |
3982 | 0 | } |
3983 | 0 | do { |
3984 | 0 | cur = cur->parent; |
3985 | 0 | if (cur == NULL) |
3986 | 0 | break; |
3987 | 0 | if (cur == def) |
3988 | 0 | return (1); |
3989 | 0 | if (cur->next != NULL) { |
3990 | 0 | cur = cur->next; |
3991 | 0 | break; |
3992 | 0 | } |
3993 | 0 | } while (cur != NULL); |
3994 | 0 | } |
3995 | 0 | return (1); |
3996 | 0 | } |
3997 | | |
3998 | | /** |
3999 | | * xmlRelaxNGGetElements: |
4000 | | * @ctxt: a Relax-NG parser context |
4001 | | * @def: the definition definition |
4002 | | * @eora: gather elements (0), attributes (1) or elements and text (2) |
4003 | | * |
4004 | | * Compute the list of top elements a definition can generate |
4005 | | * |
4006 | | * Returns a list of elements or NULL if none was found. |
4007 | | */ |
4008 | | static xmlRelaxNGDefinePtr * |
4009 | | xmlRelaxNGGetElements(xmlRelaxNGParserCtxtPtr ctxt, |
4010 | | xmlRelaxNGDefinePtr def, int eora) |
4011 | 0 | { |
4012 | 0 | xmlRelaxNGDefinePtr *ret = NULL, parent, cur, tmp; |
4013 | 0 | int len = 0; |
4014 | 0 | int max = 0; |
4015 | | |
4016 | | /* |
4017 | | * Don't run that check in case of error. Infinite recursion |
4018 | | * becomes possible. |
4019 | | */ |
4020 | 0 | if (ctxt->nbErrors != 0) |
4021 | 0 | return (NULL); |
4022 | | |
4023 | 0 | parent = NULL; |
4024 | 0 | cur = def; |
4025 | 0 | while (cur != NULL) { |
4026 | 0 | if (((eora == 0) && ((cur->type == XML_RELAXNG_ELEMENT) || |
4027 | 0 | (cur->type == XML_RELAXNG_TEXT))) || |
4028 | 0 | ((eora == 1) && (cur->type == XML_RELAXNG_ATTRIBUTE)) || |
4029 | 0 | ((eora == 2) && ((cur->type == XML_RELAXNG_DATATYPE) || |
4030 | 0 | (cur->type == XML_RELAXNG_ELEMENT) || |
4031 | 0 | (cur->type == XML_RELAXNG_LIST) || |
4032 | 0 | (cur->type == XML_RELAXNG_TEXT) || |
4033 | 0 | (cur->type == XML_RELAXNG_VALUE)))) { |
4034 | 0 | if (ret == NULL) { |
4035 | 0 | max = 10; |
4036 | 0 | ret = (xmlRelaxNGDefinePtr *) |
4037 | 0 | xmlMalloc((max + 1) * sizeof(xmlRelaxNGDefinePtr)); |
4038 | 0 | if (ret == NULL) { |
4039 | 0 | xmlRngPErrMemory(ctxt, "getting element list\n"); |
4040 | 0 | return (NULL); |
4041 | 0 | } |
4042 | 0 | } else if (max <= len) { |
4043 | 0 | xmlRelaxNGDefinePtr *temp; |
4044 | |
|
4045 | 0 | max *= 2; |
4046 | 0 | temp = xmlRealloc(ret, |
4047 | 0 | (max + 1) * sizeof(xmlRelaxNGDefinePtr)); |
4048 | 0 | if (temp == NULL) { |
4049 | 0 | xmlRngPErrMemory(ctxt, "getting element list\n"); |
4050 | 0 | xmlFree(ret); |
4051 | 0 | return (NULL); |
4052 | 0 | } |
4053 | 0 | ret = temp; |
4054 | 0 | } |
4055 | 0 | ret[len++] = cur; |
4056 | 0 | ret[len] = NULL; |
4057 | 0 | } else if ((cur->type == XML_RELAXNG_CHOICE) || |
4058 | 0 | (cur->type == XML_RELAXNG_INTERLEAVE) || |
4059 | 0 | (cur->type == XML_RELAXNG_GROUP) || |
4060 | 0 | (cur->type == XML_RELAXNG_ONEORMORE) || |
4061 | 0 | (cur->type == XML_RELAXNG_ZEROORMORE) || |
4062 | 0 | (cur->type == XML_RELAXNG_OPTIONAL) || |
4063 | 0 | (cur->type == XML_RELAXNG_PARENTREF) || |
4064 | 0 | (cur->type == XML_RELAXNG_REF) || |
4065 | 0 | (cur->type == XML_RELAXNG_DEF) || |
4066 | 0 | (cur->type == XML_RELAXNG_EXTERNALREF)) { |
4067 | | /* |
4068 | | * Don't go within elements or attributes or string values. |
4069 | | * Just gather the element top list |
4070 | | */ |
4071 | 0 | if (cur->content != NULL) { |
4072 | 0 | parent = cur; |
4073 | 0 | cur = cur->content; |
4074 | 0 | tmp = cur; |
4075 | 0 | while (tmp != NULL) { |
4076 | 0 | tmp->parent = parent; |
4077 | 0 | tmp = tmp->next; |
4078 | 0 | } |
4079 | 0 | continue; |
4080 | 0 | } |
4081 | 0 | } |
4082 | 0 | if (cur == def) |
4083 | 0 | break; |
4084 | 0 | if (cur->next != NULL) { |
4085 | 0 | cur = cur->next; |
4086 | 0 | continue; |
4087 | 0 | } |
4088 | 0 | do { |
4089 | 0 | cur = cur->parent; |
4090 | 0 | if (cur == NULL) |
4091 | 0 | break; |
4092 | 0 | if (cur == def) |
4093 | 0 | return (ret); |
4094 | 0 | if (cur->next != NULL) { |
4095 | 0 | cur = cur->next; |
4096 | 0 | break; |
4097 | 0 | } |
4098 | 0 | } while (cur != NULL); |
4099 | 0 | } |
4100 | 0 | return (ret); |
4101 | 0 | } |
4102 | | |
4103 | | /** |
4104 | | * xmlRelaxNGCheckChoiceDeterminism: |
4105 | | * @ctxt: a Relax-NG parser context |
4106 | | * @def: the choice definition |
4107 | | * |
4108 | | * Also used to find indeterministic pattern in choice |
4109 | | */ |
4110 | | static void |
4111 | | xmlRelaxNGCheckChoiceDeterminism(xmlRelaxNGParserCtxtPtr ctxt, |
4112 | | xmlRelaxNGDefinePtr def) |
4113 | 0 | { |
4114 | 0 | xmlRelaxNGDefinePtr **list; |
4115 | 0 | xmlRelaxNGDefinePtr cur; |
4116 | 0 | int nbchild = 0, i, j, ret; |
4117 | 0 | int is_nullable = 0; |
4118 | 0 | int is_indeterminist = 0; |
4119 | 0 | xmlHashTablePtr triage = NULL; |
4120 | 0 | int is_triable = 1; |
4121 | |
|
4122 | 0 | if ((def == NULL) || (def->type != XML_RELAXNG_CHOICE)) |
4123 | 0 | return; |
4124 | | |
4125 | 0 | if (def->dflags & IS_PROCESSED) |
4126 | 0 | return; |
4127 | | |
4128 | | /* |
4129 | | * Don't run that check in case of error. Infinite recursion |
4130 | | * becomes possible. |
4131 | | */ |
4132 | 0 | if (ctxt->nbErrors != 0) |
4133 | 0 | return; |
4134 | | |
4135 | 0 | is_nullable = xmlRelaxNGIsNullable(def); |
4136 | |
|
4137 | 0 | cur = def->content; |
4138 | 0 | while (cur != NULL) { |
4139 | 0 | nbchild++; |
4140 | 0 | cur = cur->next; |
4141 | 0 | } |
4142 | |
|
4143 | 0 | list = (xmlRelaxNGDefinePtr **) xmlMalloc(nbchild * |
4144 | 0 | sizeof(xmlRelaxNGDefinePtr |
4145 | 0 | *)); |
4146 | 0 | if (list == NULL) { |
4147 | 0 | xmlRngPErrMemory(ctxt, "building choice\n"); |
4148 | 0 | return; |
4149 | 0 | } |
4150 | 0 | i = 0; |
4151 | | /* |
4152 | | * a bit strong but safe |
4153 | | */ |
4154 | 0 | if (is_nullable == 0) { |
4155 | 0 | triage = xmlHashCreate(10); |
4156 | 0 | } else { |
4157 | 0 | is_triable = 0; |
4158 | 0 | } |
4159 | 0 | cur = def->content; |
4160 | 0 | while (cur != NULL) { |
4161 | 0 | list[i] = xmlRelaxNGGetElements(ctxt, cur, 0); |
4162 | 0 | if ((list[i] == NULL) || (list[i][0] == NULL)) { |
4163 | 0 | is_triable = 0; |
4164 | 0 | } else if (is_triable == 1) { |
4165 | 0 | xmlRelaxNGDefinePtr *tmp; |
4166 | 0 | int res; |
4167 | |
|
4168 | 0 | tmp = list[i]; |
4169 | 0 | while ((*tmp != NULL) && (is_triable == 1)) { |
4170 | 0 | if ((*tmp)->type == XML_RELAXNG_TEXT) { |
4171 | 0 | res = xmlHashAddEntry2(triage, |
4172 | 0 | BAD_CAST "#text", NULL, |
4173 | 0 | (void *) cur); |
4174 | 0 | if (res != 0) |
4175 | 0 | is_triable = -1; |
4176 | 0 | } else if (((*tmp)->type == XML_RELAXNG_ELEMENT) && |
4177 | 0 | ((*tmp)->name != NULL)) { |
4178 | 0 | if (((*tmp)->ns == NULL) || ((*tmp)->ns[0] == 0)) |
4179 | 0 | res = xmlHashAddEntry2(triage, |
4180 | 0 | (*tmp)->name, NULL, |
4181 | 0 | (void *) cur); |
4182 | 0 | else |
4183 | 0 | res = xmlHashAddEntry2(triage, |
4184 | 0 | (*tmp)->name, (*tmp)->ns, |
4185 | 0 | (void *) cur); |
4186 | 0 | if (res != 0) |
4187 | 0 | is_triable = -1; |
4188 | 0 | } else if ((*tmp)->type == XML_RELAXNG_ELEMENT) { |
4189 | 0 | if (((*tmp)->ns == NULL) || ((*tmp)->ns[0] == 0)) |
4190 | 0 | res = xmlHashAddEntry2(triage, |
4191 | 0 | BAD_CAST "#any", NULL, |
4192 | 0 | (void *) cur); |
4193 | 0 | else |
4194 | 0 | res = xmlHashAddEntry2(triage, |
4195 | 0 | BAD_CAST "#any", (*tmp)->ns, |
4196 | 0 | (void *) cur); |
4197 | 0 | if (res != 0) |
4198 | 0 | is_triable = -1; |
4199 | 0 | } else { |
4200 | 0 | is_triable = -1; |
4201 | 0 | } |
4202 | 0 | tmp++; |
4203 | 0 | } |
4204 | 0 | } |
4205 | 0 | i++; |
4206 | 0 | cur = cur->next; |
4207 | 0 | } |
4208 | |
|
4209 | 0 | for (i = 0; i < nbchild; i++) { |
4210 | 0 | if (list[i] == NULL) |
4211 | 0 | continue; |
4212 | 0 | for (j = 0; j < i; j++) { |
4213 | 0 | if (list[j] == NULL) |
4214 | 0 | continue; |
4215 | 0 | ret = xmlRelaxNGCompareElemDefLists(ctxt, list[i], list[j]); |
4216 | 0 | if (ret == 0) { |
4217 | 0 | is_indeterminist = 1; |
4218 | 0 | } |
4219 | 0 | } |
4220 | 0 | } |
4221 | 0 | for (i = 0; i < nbchild; i++) { |
4222 | 0 | if (list[i] != NULL) |
4223 | 0 | xmlFree(list[i]); |
4224 | 0 | } |
4225 | |
|
4226 | 0 | xmlFree(list); |
4227 | 0 | if (is_indeterminist) { |
4228 | 0 | def->dflags |= IS_INDETERMINIST; |
4229 | 0 | } |
4230 | 0 | if (is_triable == 1) { |
4231 | 0 | def->dflags |= IS_TRIABLE; |
4232 | 0 | def->data = triage; |
4233 | 0 | } else if (triage != NULL) { |
4234 | 0 | xmlHashFree(triage, NULL); |
4235 | 0 | } |
4236 | 0 | def->dflags |= IS_PROCESSED; |
4237 | 0 | } |
4238 | | |
4239 | | /** |
4240 | | * xmlRelaxNGCheckGroupAttrs: |
4241 | | * @ctxt: a Relax-NG parser context |
4242 | | * @def: the group definition |
4243 | | * |
4244 | | * Detects violations of rule 7.3 |
4245 | | */ |
4246 | | static void |
4247 | | xmlRelaxNGCheckGroupAttrs(xmlRelaxNGParserCtxtPtr ctxt, |
4248 | | xmlRelaxNGDefinePtr def) |
4249 | 0 | { |
4250 | 0 | xmlRelaxNGDefinePtr **list; |
4251 | 0 | xmlRelaxNGDefinePtr cur; |
4252 | 0 | int nbchild = 0, i, j, ret; |
4253 | |
|
4254 | 0 | if ((def == NULL) || |
4255 | 0 | ((def->type != XML_RELAXNG_GROUP) && |
4256 | 0 | (def->type != XML_RELAXNG_ELEMENT))) |
4257 | 0 | return; |
4258 | | |
4259 | 0 | if (def->dflags & IS_PROCESSED) |
4260 | 0 | return; |
4261 | | |
4262 | | /* |
4263 | | * Don't run that check in case of error. Infinite recursion |
4264 | | * becomes possible. |
4265 | | */ |
4266 | 0 | if (ctxt->nbErrors != 0) |
4267 | 0 | return; |
4268 | | |
4269 | 0 | cur = def->attrs; |
4270 | 0 | while (cur != NULL) { |
4271 | 0 | nbchild++; |
4272 | 0 | cur = cur->next; |
4273 | 0 | } |
4274 | 0 | cur = def->content; |
4275 | 0 | while (cur != NULL) { |
4276 | 0 | nbchild++; |
4277 | 0 | cur = cur->next; |
4278 | 0 | } |
4279 | |
|
4280 | 0 | list = (xmlRelaxNGDefinePtr **) xmlMalloc(nbchild * |
4281 | 0 | sizeof(xmlRelaxNGDefinePtr |
4282 | 0 | *)); |
4283 | 0 | if (list == NULL) { |
4284 | 0 | xmlRngPErrMemory(ctxt, "building group\n"); |
4285 | 0 | return; |
4286 | 0 | } |
4287 | 0 | i = 0; |
4288 | 0 | cur = def->attrs; |
4289 | 0 | while (cur != NULL) { |
4290 | 0 | list[i] = xmlRelaxNGGetElements(ctxt, cur, 1); |
4291 | 0 | i++; |
4292 | 0 | cur = cur->next; |
4293 | 0 | } |
4294 | 0 | cur = def->content; |
4295 | 0 | while (cur != NULL) { |
4296 | 0 | list[i] = xmlRelaxNGGetElements(ctxt, cur, 1); |
4297 | 0 | i++; |
4298 | 0 | cur = cur->next; |
4299 | 0 | } |
4300 | |
|
4301 | 0 | for (i = 0; i < nbchild; i++) { |
4302 | 0 | if (list[i] == NULL) |
4303 | 0 | continue; |
4304 | 0 | for (j = 0; j < i; j++) { |
4305 | 0 | if (list[j] == NULL) |
4306 | 0 | continue; |
4307 | 0 | ret = xmlRelaxNGCompareElemDefLists(ctxt, list[i], list[j]); |
4308 | 0 | if (ret == 0) { |
4309 | 0 | xmlRngPErr(ctxt, def->node, XML_RNGP_GROUP_ATTR_CONFLICT, |
4310 | 0 | "Attributes conflicts in group\n", NULL, NULL); |
4311 | 0 | } |
4312 | 0 | } |
4313 | 0 | } |
4314 | 0 | for (i = 0; i < nbchild; i++) { |
4315 | 0 | if (list[i] != NULL) |
4316 | 0 | xmlFree(list[i]); |
4317 | 0 | } |
4318 | |
|
4319 | 0 | xmlFree(list); |
4320 | 0 | def->dflags |= IS_PROCESSED; |
4321 | 0 | } |
4322 | | |
4323 | | /** |
4324 | | * xmlRelaxNGComputeInterleaves: |
4325 | | * @def: the interleave definition |
4326 | | * @ctxt: a Relax-NG parser context |
4327 | | * @name: the definition name |
4328 | | * |
4329 | | * A lot of work for preprocessing interleave definitions |
4330 | | * is potentially needed to get a decent execution speed at runtime |
4331 | | * - trying to get a total order on the element nodes generated |
4332 | | * by the interleaves, order the list of interleave definitions |
4333 | | * following that order. |
4334 | | * - if <text/> is used to handle mixed content, it is better to |
4335 | | * flag this in the define and simplify the runtime checking |
4336 | | * algorithm |
4337 | | */ |
4338 | | static void |
4339 | | xmlRelaxNGComputeInterleaves(void *payload, void *data, |
4340 | | const xmlChar * name ATTRIBUTE_UNUSED) |
4341 | 0 | { |
4342 | 0 | xmlRelaxNGDefinePtr def = (xmlRelaxNGDefinePtr) payload; |
4343 | 0 | xmlRelaxNGParserCtxtPtr ctxt = (xmlRelaxNGParserCtxtPtr) data; |
4344 | 0 | xmlRelaxNGDefinePtr cur, *tmp; |
4345 | |
|
4346 | 0 | xmlRelaxNGPartitionPtr partitions = NULL; |
4347 | 0 | xmlRelaxNGInterleaveGroupPtr *groups = NULL; |
4348 | 0 | xmlRelaxNGInterleaveGroupPtr group; |
4349 | 0 | int i, j, ret, res; |
4350 | 0 | int nbgroups = 0; |
4351 | 0 | int nbchild = 0; |
4352 | 0 | int is_mixed = 0; |
4353 | 0 | int is_determinist = 1; |
4354 | | |
4355 | | /* |
4356 | | * Don't run that check in case of error. Infinite recursion |
4357 | | * becomes possible. |
4358 | | */ |
4359 | 0 | if (ctxt->nbErrors != 0) |
4360 | 0 | return; |
4361 | | |
4362 | | #ifdef DEBUG_INTERLEAVE |
4363 | | xmlGenericError(xmlGenericErrorContext, |
4364 | | "xmlRelaxNGComputeInterleaves(%s)\n", name); |
4365 | | #endif |
4366 | 0 | cur = def->content; |
4367 | 0 | while (cur != NULL) { |
4368 | 0 | nbchild++; |
4369 | 0 | cur = cur->next; |
4370 | 0 | } |
4371 | |
|
4372 | | #ifdef DEBUG_INTERLEAVE |
4373 | | xmlGenericError(xmlGenericErrorContext, " %d child\n", nbchild); |
4374 | | #endif |
4375 | 0 | groups = (xmlRelaxNGInterleaveGroupPtr *) |
4376 | 0 | xmlMalloc(nbchild * sizeof(xmlRelaxNGInterleaveGroupPtr)); |
4377 | 0 | if (groups == NULL) |
4378 | 0 | goto error; |
4379 | 0 | cur = def->content; |
4380 | 0 | while (cur != NULL) { |
4381 | 0 | groups[nbgroups] = (xmlRelaxNGInterleaveGroupPtr) |
4382 | 0 | xmlMalloc(sizeof(xmlRelaxNGInterleaveGroup)); |
4383 | 0 | if (groups[nbgroups] == NULL) |
4384 | 0 | goto error; |
4385 | 0 | if (cur->type == XML_RELAXNG_TEXT) |
4386 | 0 | is_mixed++; |
4387 | 0 | groups[nbgroups]->rule = cur; |
4388 | 0 | groups[nbgroups]->defs = xmlRelaxNGGetElements(ctxt, cur, 2); |
4389 | 0 | groups[nbgroups]->attrs = xmlRelaxNGGetElements(ctxt, cur, 1); |
4390 | 0 | nbgroups++; |
4391 | 0 | cur = cur->next; |
4392 | 0 | } |
4393 | | #ifdef DEBUG_INTERLEAVE |
4394 | | xmlGenericError(xmlGenericErrorContext, " %d groups\n", nbgroups); |
4395 | | #endif |
4396 | | |
4397 | | /* |
4398 | | * Let's check that all rules makes a partitions according to 7.4 |
4399 | | */ |
4400 | 0 | partitions = (xmlRelaxNGPartitionPtr) |
4401 | 0 | xmlMalloc(sizeof(xmlRelaxNGPartition)); |
4402 | 0 | if (partitions == NULL) |
4403 | 0 | goto error; |
4404 | 0 | memset(partitions, 0, sizeof(xmlRelaxNGPartition)); |
4405 | 0 | partitions->nbgroups = nbgroups; |
4406 | 0 | partitions->triage = xmlHashCreate(nbgroups); |
4407 | 0 | for (i = 0; i < nbgroups; i++) { |
4408 | 0 | group = groups[i]; |
4409 | 0 | for (j = i + 1; j < nbgroups; j++) { |
4410 | 0 | if (groups[j] == NULL) |
4411 | 0 | continue; |
4412 | | |
4413 | 0 | ret = xmlRelaxNGCompareElemDefLists(ctxt, group->defs, |
4414 | 0 | groups[j]->defs); |
4415 | 0 | if (ret == 0) { |
4416 | 0 | xmlRngPErr(ctxt, def->node, XML_RNGP_ELEM_TEXT_CONFLICT, |
4417 | 0 | "Element or text conflicts in interleave\n", |
4418 | 0 | NULL, NULL); |
4419 | 0 | } |
4420 | 0 | ret = xmlRelaxNGCompareElemDefLists(ctxt, group->attrs, |
4421 | 0 | groups[j]->attrs); |
4422 | 0 | if (ret == 0) { |
4423 | 0 | xmlRngPErr(ctxt, def->node, XML_RNGP_ATTR_CONFLICT, |
4424 | 0 | "Attributes conflicts in interleave\n", NULL, |
4425 | 0 | NULL); |
4426 | 0 | } |
4427 | 0 | } |
4428 | 0 | tmp = group->defs; |
4429 | 0 | if ((tmp != NULL) && (*tmp != NULL)) { |
4430 | 0 | while (*tmp != NULL) { |
4431 | 0 | if ((*tmp)->type == XML_RELAXNG_TEXT) { |
4432 | 0 | res = xmlHashAddEntry2(partitions->triage, |
4433 | 0 | BAD_CAST "#text", NULL, |
4434 | 0 | (void *) (ptrdiff_t) (i + 1)); |
4435 | 0 | if (res != 0) |
4436 | 0 | is_determinist = -1; |
4437 | 0 | } else if (((*tmp)->type == XML_RELAXNG_ELEMENT) && |
4438 | 0 | ((*tmp)->name != NULL)) { |
4439 | 0 | if (((*tmp)->ns == NULL) || ((*tmp)->ns[0] == 0)) |
4440 | 0 | res = xmlHashAddEntry2(partitions->triage, |
4441 | 0 | (*tmp)->name, NULL, |
4442 | 0 | (void *) (ptrdiff_t) (i + 1)); |
4443 | 0 | else |
4444 | 0 | res = xmlHashAddEntry2(partitions->triage, |
4445 | 0 | (*tmp)->name, (*tmp)->ns, |
4446 | 0 | (void *) (ptrdiff_t) (i + 1)); |
4447 | 0 | if (res != 0) |
4448 | 0 | is_determinist = -1; |
4449 | 0 | } else if ((*tmp)->type == XML_RELAXNG_ELEMENT) { |
4450 | 0 | if (((*tmp)->ns == NULL) || ((*tmp)->ns[0] == 0)) |
4451 | 0 | res = xmlHashAddEntry2(partitions->triage, |
4452 | 0 | BAD_CAST "#any", NULL, |
4453 | 0 | (void *) (ptrdiff_t) (i + 1)); |
4454 | 0 | else |
4455 | 0 | res = xmlHashAddEntry2(partitions->triage, |
4456 | 0 | BAD_CAST "#any", (*tmp)->ns, |
4457 | 0 | (void *) (ptrdiff_t) (i + 1)); |
4458 | 0 | if ((*tmp)->nameClass != NULL) |
4459 | 0 | is_determinist = 2; |
4460 | 0 | if (res != 0) |
4461 | 0 | is_determinist = -1; |
4462 | 0 | } else { |
4463 | 0 | is_determinist = -1; |
4464 | 0 | } |
4465 | 0 | tmp++; |
4466 | 0 | } |
4467 | 0 | } else { |
4468 | 0 | is_determinist = 0; |
4469 | 0 | } |
4470 | 0 | } |
4471 | 0 | partitions->groups = groups; |
4472 | | |
4473 | | /* |
4474 | | * and save the partition list back in the def |
4475 | | */ |
4476 | 0 | def->data = partitions; |
4477 | 0 | if (is_mixed != 0) |
4478 | 0 | def->dflags |= IS_MIXED; |
4479 | 0 | if (is_determinist == 1) |
4480 | 0 | partitions->flags = IS_DETERMINIST; |
4481 | 0 | if (is_determinist == 2) |
4482 | 0 | partitions->flags = IS_DETERMINIST | IS_NEEDCHECK; |
4483 | 0 | return; |
4484 | | |
4485 | 0 | error: |
4486 | 0 | xmlRngPErrMemory(ctxt, "in interleave computation\n"); |
4487 | 0 | if (groups != NULL) { |
4488 | 0 | for (i = 0; i < nbgroups; i++) |
4489 | 0 | if (groups[i] != NULL) { |
4490 | 0 | if (groups[i]->defs != NULL) |
4491 | 0 | xmlFree(groups[i]->defs); |
4492 | 0 | xmlFree(groups[i]); |
4493 | 0 | } |
4494 | 0 | xmlFree(groups); |
4495 | 0 | } |
4496 | 0 | xmlRelaxNGFreePartition(partitions); |
4497 | 0 | } |
4498 | | |
4499 | | /** |
4500 | | * xmlRelaxNGParseInterleave: |
4501 | | * @ctxt: a Relax-NG parser context |
4502 | | * @node: the data node. |
4503 | | * |
4504 | | * parse the content of a RelaxNG interleave node. |
4505 | | * |
4506 | | * Returns the definition pointer or NULL in case of error |
4507 | | */ |
4508 | | static xmlRelaxNGDefinePtr |
4509 | | xmlRelaxNGParseInterleave(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) |
4510 | 0 | { |
4511 | 0 | xmlRelaxNGDefinePtr def = NULL; |
4512 | 0 | xmlRelaxNGDefinePtr last = NULL, cur; |
4513 | 0 | xmlNodePtr child; |
4514 | |
|
4515 | 0 | def = xmlRelaxNGNewDefine(ctxt, node); |
4516 | 0 | if (def == NULL) { |
4517 | 0 | return (NULL); |
4518 | 0 | } |
4519 | 0 | def->type = XML_RELAXNG_INTERLEAVE; |
4520 | |
|
4521 | 0 | if (ctxt->interleaves == NULL) |
4522 | 0 | ctxt->interleaves = xmlHashCreate(10); |
4523 | 0 | if (ctxt->interleaves == NULL) { |
4524 | 0 | xmlRngPErrMemory(ctxt, "create interleaves\n"); |
4525 | 0 | } else { |
4526 | 0 | char name[32]; |
4527 | |
|
4528 | 0 | snprintf(name, 32, "interleave%d", ctxt->nbInterleaves++); |
4529 | 0 | if (xmlHashAddEntry(ctxt->interleaves, BAD_CAST name, def) < 0) { |
4530 | 0 | xmlRngPErr(ctxt, node, XML_RNGP_INTERLEAVE_ADD, |
4531 | 0 | "Failed to add %s to hash table\n", |
4532 | 0 | (const xmlChar *) name, NULL); |
4533 | 0 | } |
4534 | 0 | } |
4535 | 0 | child = node->children; |
4536 | 0 | if (child == NULL) { |
4537 | 0 | xmlRngPErr(ctxt, node, XML_RNGP_INTERLEAVE_NO_CONTENT, |
4538 | 0 | "Element interleave is empty\n", NULL, NULL); |
4539 | 0 | } |
4540 | 0 | while (child != NULL) { |
4541 | 0 | if (IS_RELAXNG(child, "element")) { |
4542 | 0 | cur = xmlRelaxNGParseElement(ctxt, child); |
4543 | 0 | } else { |
4544 | 0 | cur = xmlRelaxNGParsePattern(ctxt, child); |
4545 | 0 | } |
4546 | 0 | if (cur != NULL) { |
4547 | 0 | cur->parent = def; |
4548 | 0 | if (last == NULL) { |
4549 | 0 | def->content = last = cur; |
4550 | 0 | } else { |
4551 | 0 | last->next = cur; |
4552 | 0 | last = cur; |
4553 | 0 | } |
4554 | 0 | } |
4555 | 0 | child = child->next; |
4556 | 0 | } |
4557 | |
|
4558 | 0 | return (def); |
4559 | 0 | } |
4560 | | |
4561 | | /** |
4562 | | * xmlRelaxNGParseInclude: |
4563 | | * @ctxt: a Relax-NG parser context |
4564 | | * @node: the include node |
4565 | | * |
4566 | | * Integrate the content of an include node in the current grammar |
4567 | | * |
4568 | | * Returns 0 in case of success or -1 in case of error |
4569 | | */ |
4570 | | static int |
4571 | | xmlRelaxNGParseInclude(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) |
4572 | 0 | { |
4573 | 0 | xmlRelaxNGIncludePtr incl; |
4574 | 0 | xmlNodePtr root; |
4575 | 0 | int ret = 0, tmp; |
4576 | |
|
4577 | 0 | incl = node->psvi; |
4578 | 0 | if (incl == NULL) { |
4579 | 0 | xmlRngPErr(ctxt, node, XML_RNGP_INCLUDE_EMPTY, |
4580 | 0 | "Include node has no data\n", NULL, NULL); |
4581 | 0 | return (-1); |
4582 | 0 | } |
4583 | 0 | root = xmlDocGetRootElement(incl->doc); |
4584 | 0 | if (root == NULL) { |
4585 | 0 | xmlRngPErr(ctxt, node, XML_RNGP_EMPTY, "Include document is empty\n", |
4586 | 0 | NULL, NULL); |
4587 | 0 | return (-1); |
4588 | 0 | } |
4589 | 0 | if (!xmlStrEqual(root->name, BAD_CAST "grammar")) { |
4590 | 0 | xmlRngPErr(ctxt, node, XML_RNGP_GRAMMAR_MISSING, |
4591 | 0 | "Include document root is not a grammar\n", NULL, NULL); |
4592 | 0 | return (-1); |
4593 | 0 | } |
4594 | | |
4595 | | /* |
4596 | | * Merge the definition from both the include and the internal list |
4597 | | */ |
4598 | 0 | if (root->children != NULL) { |
4599 | 0 | tmp = xmlRelaxNGParseGrammarContent(ctxt, root->children); |
4600 | 0 | if (tmp != 0) |
4601 | 0 | ret = -1; |
4602 | 0 | } |
4603 | 0 | if (node->children != NULL) { |
4604 | 0 | tmp = xmlRelaxNGParseGrammarContent(ctxt, node->children); |
4605 | 0 | if (tmp != 0) |
4606 | 0 | ret = -1; |
4607 | 0 | } |
4608 | 0 | return (ret); |
4609 | 0 | } |
4610 | | |
4611 | | /** |
4612 | | * xmlRelaxNGParseDefine: |
4613 | | * @ctxt: a Relax-NG parser context |
4614 | | * @node: the define node |
4615 | | * |
4616 | | * parse the content of a RelaxNG define element node. |
4617 | | * |
4618 | | * Returns 0 in case of success or -1 in case of error |
4619 | | */ |
4620 | | static int |
4621 | | xmlRelaxNGParseDefine(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) |
4622 | 0 | { |
4623 | 0 | xmlChar *name; |
4624 | 0 | int ret = 0, tmp; |
4625 | 0 | xmlRelaxNGDefinePtr def; |
4626 | 0 | const xmlChar *olddefine; |
4627 | |
|
4628 | 0 | name = xmlGetProp(node, BAD_CAST "name"); |
4629 | 0 | if (name == NULL) { |
4630 | 0 | xmlRngPErr(ctxt, node, XML_RNGP_DEFINE_NAME_MISSING, |
4631 | 0 | "define has no name\n", NULL, NULL); |
4632 | 0 | } else { |
4633 | 0 | xmlRelaxNGNormExtSpace(name); |
4634 | 0 | if (xmlValidateNCName(name, 0)) { |
4635 | 0 | xmlRngPErr(ctxt, node, XML_RNGP_INVALID_DEFINE_NAME, |
4636 | 0 | "define name '%s' is not an NCName\n", name, NULL); |
4637 | 0 | } |
4638 | 0 | def = xmlRelaxNGNewDefine(ctxt, node); |
4639 | 0 | if (def == NULL) { |
4640 | 0 | xmlFree(name); |
4641 | 0 | return (-1); |
4642 | 0 | } |
4643 | 0 | def->type = XML_RELAXNG_DEF; |
4644 | 0 | def->name = name; |
4645 | 0 | if (node->children == NULL) { |
4646 | 0 | xmlRngPErr(ctxt, node, XML_RNGP_DEFINE_EMPTY, |
4647 | 0 | "define has no children\n", NULL, NULL); |
4648 | 0 | } else { |
4649 | 0 | olddefine = ctxt->define; |
4650 | 0 | ctxt->define = name; |
4651 | 0 | def->content = |
4652 | 0 | xmlRelaxNGParsePatterns(ctxt, node->children, 0); |
4653 | 0 | ctxt->define = olddefine; |
4654 | 0 | } |
4655 | 0 | if (ctxt->grammar->defs == NULL) |
4656 | 0 | ctxt->grammar->defs = xmlHashCreate(10); |
4657 | 0 | if (ctxt->grammar->defs == NULL) { |
4658 | 0 | xmlRngPErr(ctxt, node, XML_RNGP_DEFINE_CREATE_FAILED, |
4659 | 0 | "Could not create definition hash\n", NULL, NULL); |
4660 | 0 | ret = -1; |
4661 | 0 | } else { |
4662 | 0 | tmp = xmlHashAddEntry(ctxt->grammar->defs, name, def); |
4663 | 0 | if (tmp < 0) { |
4664 | 0 | xmlRelaxNGDefinePtr prev; |
4665 | |
|
4666 | 0 | prev = xmlHashLookup(ctxt->grammar->defs, name); |
4667 | 0 | if (prev == NULL) { |
4668 | 0 | xmlRngPErr(ctxt, node, XML_RNGP_DEFINE_CREATE_FAILED, |
4669 | 0 | "Internal error on define aggregation of %s\n", |
4670 | 0 | name, NULL); |
4671 | 0 | ret = -1; |
4672 | 0 | } else { |
4673 | 0 | while (prev->nextHash != NULL) |
4674 | 0 | prev = prev->nextHash; |
4675 | 0 | prev->nextHash = def; |
4676 | 0 | } |
4677 | 0 | } |
4678 | 0 | } |
4679 | 0 | } |
4680 | 0 | return (ret); |
4681 | 0 | } |
4682 | | |
4683 | | /** |
4684 | | * xmlRelaxNGParseImportRef: |
4685 | | * @payload: the parser context |
4686 | | * @data: the current grammar |
4687 | | * @name: the reference name |
4688 | | * |
4689 | | * Import import one references into the current grammar |
4690 | | */ |
4691 | | static void |
4692 | 0 | xmlRelaxNGParseImportRef(void *payload, void *data, const xmlChar *name) { |
4693 | 0 | xmlRelaxNGParserCtxtPtr ctxt = (xmlRelaxNGParserCtxtPtr) data; |
4694 | 0 | xmlRelaxNGDefinePtr def = (xmlRelaxNGDefinePtr) payload; |
4695 | 0 | int tmp; |
4696 | |
|
4697 | 0 | def->dflags |= IS_EXTERNAL_REF; |
4698 | |
|
4699 | 0 | tmp = xmlHashAddEntry(ctxt->grammar->refs, name, def); |
4700 | 0 | if (tmp < 0) { |
4701 | 0 | xmlRelaxNGDefinePtr prev; |
4702 | |
|
4703 | 0 | prev = (xmlRelaxNGDefinePtr) |
4704 | 0 | xmlHashLookup(ctxt->grammar->refs, def->name); |
4705 | 0 | if (prev == NULL) { |
4706 | 0 | if (def->name != NULL) { |
4707 | 0 | xmlRngPErr(ctxt, NULL, XML_RNGP_REF_CREATE_FAILED, |
4708 | 0 | "Error refs definitions '%s'\n", |
4709 | 0 | def->name, NULL); |
4710 | 0 | } else { |
4711 | 0 | xmlRngPErr(ctxt, NULL, XML_RNGP_REF_CREATE_FAILED, |
4712 | 0 | "Error refs definitions\n", |
4713 | 0 | NULL, NULL); |
4714 | 0 | } |
4715 | 0 | } else { |
4716 | 0 | def->nextHash = prev->nextHash; |
4717 | 0 | prev->nextHash = def; |
4718 | 0 | } |
4719 | 0 | } |
4720 | 0 | } |
4721 | | |
4722 | | /** |
4723 | | * xmlRelaxNGParseImportRefs: |
4724 | | * @ctxt: the parser context |
4725 | | * @grammar: the sub grammar |
4726 | | * |
4727 | | * Import references from the subgrammar into the current grammar |
4728 | | * |
4729 | | * Returns 0 in case of success, -1 in case of failure |
4730 | | */ |
4731 | | static int |
4732 | | xmlRelaxNGParseImportRefs(xmlRelaxNGParserCtxtPtr ctxt, |
4733 | 0 | xmlRelaxNGGrammarPtr grammar) { |
4734 | 0 | if ((ctxt == NULL) || (grammar == NULL) || (ctxt->grammar == NULL)) |
4735 | 0 | return(-1); |
4736 | 0 | if (grammar->refs == NULL) |
4737 | 0 | return(0); |
4738 | 0 | if (ctxt->grammar->refs == NULL) |
4739 | 0 | ctxt->grammar->refs = xmlHashCreate(10); |
4740 | 0 | if (ctxt->grammar->refs == NULL) { |
4741 | 0 |