|
1 /* |
|
2 * libxml2_parser.c : an XML 1.0 parser, namespaces and validity support are mostly |
|
3 * implemented on top of the SAX interfaces |
|
4 * |
|
5 * References: |
|
6 * The XML specification: |
|
7 * http://www.w3.org/TR/REC-xml |
|
8 * Original 1.0 version: |
|
9 * http://www.w3.org/TR/1998/REC-xml-19980210 |
|
10 * XML second edition workingdraft |
|
11 * http://www.w3.org/TR/2000/WD-xml-2e-20000814 |
|
12 * |
|
13 * Okay this is a big file, the parser core is around 7000 lines, then it |
|
14 * is followed by the progressive parser top routines, then the various |
|
15 * high level APIs to call the parser and a few miscellaneous functions. |
|
16 * A number of helper functions and deprecated ones have been moved to |
|
17 * parserInternals.c to reduce this file size. |
|
18 * As much as possible the functions are associated with their relative |
|
19 * production in the XML specification. A few productions defining the |
|
20 * different ranges of character are actually implanted either in |
|
21 * parserInternals.h or parserInternals.c |
|
22 * The DOM tree build is realized from the default SAX callbacks in |
|
23 * the module SAX.c. |
|
24 * The routines doing the validation checks are in valid.c and called either |
|
25 * from the SAX callbacks or as standalone functions using a preparsed |
|
26 * document. |
|
27 * |
|
28 * See Copyright for the status of this software. |
|
29 * |
|
30 * daniel@veillard.com |
|
31 * Portion Copyright © 2009 Nokia Corporation and/or its subsidiary(-ies). All rights reserved. |
|
32 */ |
|
33 |
|
34 #pragma warning(disable: 4127 4132) |
|
35 |
|
36 #define IN_LIBXML |
|
37 #include "xmlenglibxml.h" |
|
38 |
|
39 #if (defined(WIN32) || defined(__SYMBIAN32__)) && !defined (__CYGWIN__) |
|
40 #define XML_DIR_SEP '\\' |
|
41 #else |
|
42 #define XML_DIR_SEP '/' |
|
43 #endif |
|
44 |
|
45 #include <stdlib.h> |
|
46 #include <string.h> |
|
47 #include <stdarg.h> |
|
48 |
|
49 #include <stdapis/libxml2/libxml2_globals.h> |
|
50 #include <stdapis/libxml2/libxml2_parserinternals.h> |
|
51 #include "libxml2_errencoding.h" |
|
52 #include "libxml2_xmlerror2.h" |
|
53 #include <stdapis/libxml2/libxml2_uri.h> |
|
54 |
|
55 #ifdef LIBXML_CATALOG_ENABLED |
|
56 #include "libxml2_catalog.h" |
|
57 #endif |
|
58 |
|
59 #ifdef HAVE_CTYPE_H |
|
60 #include <ctype.h> |
|
61 #endif |
|
62 #ifdef HAVE_STDLIB_H |
|
63 #include <stdlib.h> |
|
64 #endif |
|
65 #ifdef HAVE_SYS_STAT_H |
|
66 #include <sys/stat.h> |
|
67 #endif |
|
68 #ifdef HAVE_FCNTL_H |
|
69 #include <fcntl.h> |
|
70 #endif |
|
71 #ifdef HAVE_UNISTD_H |
|
72 #include <unistd.h> |
|
73 #endif |
|
74 #ifdef HAVE_ZLIB_H |
|
75 #include <zlib.h> |
|
76 #endif |
|
77 |
|
78 #define SAX2 1 |
|
79 |
|
80 #define XML_PARSER_BIG_BUFFER_SIZE 300 |
|
81 #define XML_PARSER_BUFFER_SIZE 100 |
|
82 |
|
83 |
|
84 /* DEPR void xmlParserHandleReference(xmlParserCtxtPtr ctxt); */ |
|
85 xmlEntityPtr xmlParseStringPEReference(xmlParserCtxtPtr ctxt, |
|
86 const xmlChar **str); |
|
87 |
|
88 static xmlParserErrors |
|
89 xmlParseExternalEntityPrivate(xmlDocPtr doc, xmlParserCtxtPtr oldctxt, |
|
90 xmlSAXHandlerPtr sax, |
|
91 void *user_data, int depth, const xmlChar *URL, |
|
92 const xmlChar *ID, xmlNodePtr *list); |
|
93 |
|
94 #ifdef LIBXML_LEGACY_ENABLED |
|
95 static void |
|
96 xmlAddEntityReference(xmlEntityPtr ent, xmlNodePtr firstNode, |
|
97 xmlNodePtr lastNode); |
|
98 #endif /* LIBXML_LEGACY_ENABLED */ |
|
99 |
|
100 static xmlParserErrors |
|
101 xmlParseBalancedChunkMemoryInternal(xmlParserCtxtPtr oldctxt, |
|
102 const xmlChar *string, void *user_data, xmlNodePtr *lst); |
|
103 |
|
104 /************************************************************************ |
|
105 * * |
|
106 * Some factorized error routines * |
|
107 * * |
|
108 ************************************************************************/ |
|
109 |
|
110 /** |
|
111 * xmlErrAttributeDup: |
|
112 * @param ctxt an XML parser context |
|
113 * @param prefix the attribute prefix |
|
114 * @param localname the attribute localname |
|
115 * |
|
116 * Handle a redefinition of attribute error |
|
117 */ |
|
118 static void |
|
119 xmlErrAttributeDup(xmlParserCtxtPtr ctxt, const xmlChar * prefix, |
|
120 const xmlChar * localname) |
|
121 { |
|
122 if ((ctxt != NULL) && (ctxt->disableSAX != 0) && |
|
123 (ctxt->instate == XML_PARSER_EOF)) |
|
124 return; |
|
125 ctxt->errNo = XML_ERR_ATTRIBUTE_REDEFINED; |
|
126 if (prefix == NULL) |
|
127 __xmlRaiseError(NULL, NULL, NULL, ctxt, NULL, XML_FROM_PARSER, |
|
128 ctxt->errNo, XML_ERR_FATAL, NULL, 0, |
|
129 (const char *) localname, NULL, NULL, 0, 0, |
|
130 EMBED_ERRTXT("Attribute %s redefined\n"), localname); |
|
131 else |
|
132 __xmlRaiseError(NULL, NULL, NULL, ctxt, NULL, XML_FROM_PARSER, |
|
133 ctxt->errNo, XML_ERR_FATAL, NULL, 0, |
|
134 (const char *) prefix, (const char *) localname, |
|
135 NULL, 0, 0, EMBED_ERRTXT("Attribute %s:%s redefined\n"), prefix, |
|
136 localname); |
|
137 ctxt->wellFormed = 0; |
|
138 if (ctxt->recovery == 0) |
|
139 ctxt->disableSAX = 1; |
|
140 } |
|
141 |
|
142 /** |
|
143 * xmlFatalErr: |
|
144 * @param ctxt an XML parser context |
|
145 * @param error the error number |
|
146 * @param extra extra information string |
|
147 * |
|
148 * Handle a fatal parser error, i.e. violating Well-Formedness constraints |
|
149 */ |
|
150 static void |
|
151 xmlFatalErr(xmlParserCtxtPtr ctxt, xmlParserErrors error, const char *info) |
|
152 { |
|
153 const char *errmsg; |
|
154 |
|
155 if ((ctxt != NULL) && (ctxt->disableSAX != 0) && (ctxt->instate == XML_PARSER_EOF)) |
|
156 return; |
|
157 |
|
158 #ifdef XMLENGINE_EXCLUDE_EMBED_MSG |
|
159 errmsg = "Error message is not availabe\n"; |
|
160 #else |
|
161 switch (error) { // DONE: Disable this SWITCH if EMBED_ERRTXT returns NULL |
|
162 case XML_ERR_INVALID_HEX_CHARREF: |
|
163 errmsg = EMBED_ERRTXT("CharRef: invalid hexadecimal value\n"); |
|
164 break; |
|
165 case XML_ERR_INVALID_DEC_CHARREF: |
|
166 errmsg = EMBED_ERRTXT("CharRef: invalid decimal value\n"); |
|
167 break; |
|
168 case XML_ERR_INVALID_CHARREF: |
|
169 errmsg = EMBED_ERRTXT("CharRef: invalid value\n"); |
|
170 break; |
|
171 case XML_ERR_INTERNAL_ERROR: |
|
172 errmsg = EMBED_ERRTXT("internal error"); |
|
173 break; |
|
174 case XML_ERR_PEREF_AT_EOF: |
|
175 errmsg = EMBED_ERRTXT("PEReference at end of document\n"); |
|
176 break; |
|
177 case XML_ERR_PEREF_IN_PROLOG: |
|
178 errmsg = EMBED_ERRTXT("PEReference in prolog\n"); |
|
179 break; |
|
180 case XML_ERR_PEREF_IN_EPILOG: |
|
181 errmsg = EMBED_ERRTXT("PEReference in epilog\n"); |
|
182 break; |
|
183 case XML_ERR_PEREF_NO_NAME: |
|
184 errmsg = EMBED_ERRTXT("PEReference: no name\n"); |
|
185 break; |
|
186 case XML_ERR_PEREF_SEMICOL_MISSING: |
|
187 errmsg = EMBED_ERRTXT("PEReference: expecting ';'\n"); |
|
188 break; |
|
189 case XML_ERR_ENTITY_LOOP: |
|
190 errmsg = EMBED_ERRTXT("Detected an entity reference loop\n"); |
|
191 break; |
|
192 case XML_ERR_ENTITY_NOT_STARTED: |
|
193 errmsg = EMBED_ERRTXT("EntityValue: \" or ' expected\n"); |
|
194 break; |
|
195 case XML_ERR_ENTITY_PE_INTERNAL: |
|
196 errmsg = EMBED_ERRTXT("PEReferences forbidden in internal subset\n"); |
|
197 break; |
|
198 case XML_ERR_ENTITY_NOT_FINISHED: |
|
199 errmsg = EMBED_ERRTXT("EntityValue: \" or ' expected\n"); |
|
200 break; |
|
201 case XML_ERR_ATTRIBUTE_NOT_STARTED: |
|
202 errmsg = EMBED_ERRTXT("AttValue: \" or ' expected\n"); |
|
203 break; |
|
204 case XML_ERR_LT_IN_ATTRIBUTE: |
|
205 errmsg = EMBED_ERRTXT("Unescaped '<' not allowed in attributes values\n"); |
|
206 break; |
|
207 case XML_ERR_LITERAL_NOT_STARTED: |
|
208 errmsg = EMBED_ERRTXT("SystemLiteral \" or ' expected\n"); |
|
209 break; |
|
210 case XML_ERR_LITERAL_NOT_FINISHED: |
|
211 errmsg = EMBED_ERRTXT("UnfinishedSystem or Public ID \" or ' expected\n"); |
|
212 break; |
|
213 case XML_ERR_MISPLACED_CDATA_END: |
|
214 errmsg = EMBED_ERRTXT("Sequence ']]>' not allowed in content\n"); |
|
215 break; |
|
216 case XML_ERR_URI_REQUIRED: |
|
217 errmsg = EMBED_ERRTXT("SYSTEM or PUBLIC, the URI is missing\n"); |
|
218 break; |
|
219 case XML_ERR_PUBID_REQUIRED: |
|
220 errmsg = EMBED_ERRTXT("PUBLIC, the Public Identifier is missing\n"); |
|
221 break; |
|
222 case XML_ERR_HYPHEN_IN_COMMENT: |
|
223 errmsg = EMBED_ERRTXT("Comment must not contain '--' (double-hyphen)\n"); |
|
224 break; |
|
225 case XML_ERR_PI_NOT_STARTED: |
|
226 errmsg = EMBED_ERRTXT("xmlParsePI : no target name\n"); |
|
227 break; |
|
228 case XML_ERR_RESERVED_XML_NAME: |
|
229 errmsg = EMBED_ERRTXT("Invalid PI name\n"); |
|
230 break; |
|
231 case XML_ERR_NOTATION_NOT_STARTED: |
|
232 errmsg = EMBED_ERRTXT("NOTATION: Name expected here\n"); |
|
233 break; |
|
234 case XML_ERR_NOTATION_NOT_FINISHED: |
|
235 errmsg = EMBED_ERRTXT("'>' required to close NOTATION declaration\n"); |
|
236 break; |
|
237 case XML_ERR_VALUE_REQUIRED: |
|
238 errmsg = EMBED_ERRTXT("Entity value required\n"); |
|
239 break; |
|
240 case XML_ERR_URI_FRAGMENT: |
|
241 errmsg = EMBED_ERRTXT("Fragment not allowed"); |
|
242 break; |
|
243 case XML_ERR_ATTLIST_NOT_STARTED: |
|
244 errmsg = EMBED_ERRTXT("'(' required to start ATTLIST enumeration\n"); |
|
245 break; |
|
246 case XML_ERR_NMTOKEN_REQUIRED: |
|
247 errmsg = EMBED_ERRTXT("NmToken expected in ATTLIST enumeration\n"); |
|
248 break; |
|
249 case XML_ERR_ATTLIST_NOT_FINISHED: |
|
250 errmsg = EMBED_ERRTXT("')' required to finish ATTLIST enumeration\n"); |
|
251 break; |
|
252 case XML_ERR_MIXED_NOT_STARTED: |
|
253 errmsg = EMBED_ERRTXT("MixedContentDecl : '|' or ')*' expected\n"); |
|
254 break; |
|
255 case XML_ERR_PCDATA_REQUIRED: |
|
256 errmsg = EMBED_ERRTXT("MixedContentDecl : '#PCDATA' expected\n"); |
|
257 break; |
|
258 case XML_ERR_ELEMCONTENT_NOT_STARTED: |
|
259 errmsg = EMBED_ERRTXT("ContentDecl : Name or '(' expected\n"); |
|
260 break; |
|
261 case XML_ERR_ELEMCONTENT_NOT_FINISHED: |
|
262 errmsg = EMBED_ERRTXT("ContentDecl : ',' '|' or ')' expected\n"); |
|
263 break; |
|
264 case XML_ERR_PEREF_IN_INT_SUBSET: |
|
265 errmsg = |
|
266 EMBED_ERRTXT("PEReference: forbidden within markup decl in internal subset\n"); |
|
267 break; |
|
268 case XML_ERR_GT_REQUIRED: |
|
269 errmsg =EMBED_ERRTXT("expected '>'\n"); |
|
270 break; |
|
271 case XML_ERR_CONDSEC_INVALID: |
|
272 errmsg = EMBED_ERRTXT("XML conditional section '[' expected\n"); |
|
273 break; |
|
274 case XML_ERR_EXT_SUBSET_NOT_FINISHED: |
|
275 errmsg = EMBED_ERRTXT("Content error in the external subset\n"); |
|
276 break; |
|
277 case XML_ERR_CONDSEC_INVALID_KEYWORD: |
|
278 errmsg = |
|
279 EMBED_ERRTXT("conditional section INCLUDE or IGNORE keyword expected\n"); |
|
280 break; |
|
281 case XML_ERR_CONDSEC_NOT_FINISHED: |
|
282 errmsg = EMBED_ERRTXT("XML conditional section not closed\n"); |
|
283 break; |
|
284 case XML_ERR_XMLDECL_NOT_STARTED: |
|
285 errmsg = EMBED_ERRTXT("Text declaration '<?xml' required\n"); |
|
286 break; |
|
287 case XML_ERR_XMLDECL_NOT_FINISHED: |
|
288 errmsg = EMBED_ERRTXT("parsing XML declaration: '?>' expected\n"); |
|
289 break; |
|
290 case XML_ERR_EXT_ENTITY_STANDALONE: |
|
291 errmsg = EMBED_ERRTXT("external parsed entities cannot be standalone\n"); |
|
292 break; |
|
293 case XML_ERR_ENTITYREF_SEMICOL_MISSING: |
|
294 errmsg = EMBED_ERRTXT("EntityRef: expecting ';'\n"); |
|
295 break; |
|
296 case XML_ERR_DOCTYPE_NOT_FINISHED: |
|
297 errmsg = EMBED_ERRTXT("DOCTYPE improperly terminated\n"); |
|
298 break; |
|
299 case XML_ERR_LTSLASH_REQUIRED: |
|
300 errmsg = EMBED_ERRTXT("EndTag: '</' not found\n"); |
|
301 break; |
|
302 case XML_ERR_EQUAL_REQUIRED: |
|
303 errmsg = EMBED_ERRTXT("expected '='\n"); |
|
304 break; |
|
305 case XML_ERR_STRING_NOT_CLOSED: |
|
306 errmsg = EMBED_ERRTXT("String not closed expecting \" or '\n"); |
|
307 break; |
|
308 case XML_ERR_STRING_NOT_STARTED: |
|
309 errmsg = EMBED_ERRTXT("String not started expecting ' or \"\n"); |
|
310 break; |
|
311 case XML_ERR_ENCODING_NAME: |
|
312 errmsg = EMBED_ERRTXT("Invalid XML encoding name\n"); |
|
313 break; |
|
314 case XML_ERR_STANDALONE_VALUE: |
|
315 errmsg = EMBED_ERRTXT("standalone accepts only 'yes' or 'no'\n"); |
|
316 break; |
|
317 case XML_ERR_DOCUMENT_EMPTY: |
|
318 errmsg = EMBED_ERRTXT("Document is empty\n"); |
|
319 break; |
|
320 case XML_ERR_DOCUMENT_END: |
|
321 errmsg = EMBED_ERRTXT("Extra content at the end of the document\n"); |
|
322 break; |
|
323 case XML_ERR_NOT_WELL_BALANCED: |
|
324 errmsg = EMBED_ERRTXT("chunk is not well balanced\n"); |
|
325 break; |
|
326 case XML_ERR_EXTRA_CONTENT: |
|
327 errmsg = EMBED_ERRTXT("extra content at the end of well balanced chunk\n"); |
|
328 break; |
|
329 case XML_ERR_VERSION_MISSING: |
|
330 errmsg = EMBED_ERRTXT("Malformed declaration expecting version\n"); |
|
331 break; |
|
332 case XML_ERR_STACK_LOW: |
|
333 errmsg = EMBED_ERRTXT("Thread's stack has reached critical level\n"); |
|
334 break; |
|
335 #if 0 |
|
336 case: |
|
337 errmsg = "\n"; |
|
338 break; |
|
339 #endif |
|
340 default: |
|
341 errmsg = EMBED_ERRTXT("Unregistered error message\n"); |
|
342 } |
|
343 #endif /* !XMLENGINE_EXCLUDE_EMBED_MSG */ |
|
344 |
|
345 ctxt->errNo = error; |
|
346 __xmlRaiseError(NULL, NULL, NULL, ctxt, NULL, XML_FROM_PARSER, error, |
|
347 XML_ERR_FATAL, NULL, 0, info, NULL, NULL, 0, 0, errmsg, |
|
348 info); |
|
349 ctxt->wellFormed = 0; |
|
350 if (ctxt->recovery == 0) |
|
351 ctxt->disableSAX = 1; |
|
352 } |
|
353 |
|
354 /** |
|
355 * xmlFatalErrMsg: |
|
356 * @param ctxt an XML parser context |
|
357 * @param error the error number |
|
358 * @param msg the error message |
|
359 * |
|
360 * Handle a fatal parser error, i.e. violating Well-Formedness constraints |
|
361 */ |
|
362 static void |
|
363 xmlFatalErrMsg(xmlParserCtxtPtr ctxt, xmlParserErrors error, |
|
364 const char *msg) |
|
365 { |
|
366 if ((ctxt != NULL) && (ctxt->disableSAX != 0) && |
|
367 (ctxt->instate == XML_PARSER_EOF)) |
|
368 return; |
|
369 ctxt->errNo = error; |
|
370 __xmlRaiseError(NULL, NULL, NULL, ctxt, NULL, XML_FROM_PARSER, error, |
|
371 XML_ERR_FATAL, NULL, 0, NULL, NULL, NULL, 0, 0, msg); |
|
372 ctxt->wellFormed = 0; |
|
373 if (ctxt->recovery == 0) |
|
374 ctxt->disableSAX = 1; |
|
375 } |
|
376 |
|
377 /** |
|
378 * xmlWarningMsg: |
|
379 * @param ctxt an XML parser context |
|
380 * @param error the error number |
|
381 * @param msg the error message |
|
382 * @param str1 extra data |
|
383 * @param str2 extra data |
|
384 * |
|
385 * Handle a warning. |
|
386 */ |
|
387 static void |
|
388 xmlWarningMsg(xmlParserCtxtPtr ctxt, xmlParserErrors error, |
|
389 const char *msg, const xmlChar *str1, const xmlChar *str2) |
|
390 { |
|
391 xmlStructuredErrorFunc schannel = NULL; |
|
392 |
|
393 if ((ctxt != NULL) && (ctxt->disableSAX != 0) && |
|
394 (ctxt->instate == XML_PARSER_EOF)) |
|
395 return; |
|
396 ctxt->errNo = error; |
|
397 if ((ctxt->sax != NULL) && (ctxt->sax->initialized == XML_SAX2_MAGIC)) |
|
398 schannel = ctxt->sax->serror; |
|
399 __xmlRaiseError(schannel, |
|
400 (ctxt->sax) ? ctxt->sax->warning : NULL, |
|
401 ctxt->userData, |
|
402 ctxt, NULL, XML_FROM_PARSER, error, |
|
403 XML_ERR_WARNING, NULL, 0, |
|
404 (const char *) str1, (const char *) str2, NULL, 0, 0, |
|
405 msg, (const char *) str1, (const char *) str2); |
|
406 } |
|
407 |
|
408 /** |
|
409 * xmlValidityError: |
|
410 * @param ctxt an XML parser context |
|
411 * @param error the error number |
|
412 * @param msg the error message |
|
413 * @param str1 extra data |
|
414 * |
|
415 * Handle a validity error. |
|
416 */ |
|
417 static void |
|
418 xmlValidityError(xmlParserCtxtPtr ctxt, xmlParserErrors error, |
|
419 const char *msg, const xmlChar *str1) |
|
420 { |
|
421 xmlStructuredErrorFunc schannel = NULL; |
|
422 |
|
423 if ((ctxt != NULL) && (ctxt->disableSAX != 0) && |
|
424 (ctxt->instate == XML_PARSER_EOF)) |
|
425 return; |
|
426 ctxt->errNo = error; |
|
427 if ((ctxt->sax != NULL) && (ctxt->sax->initialized == XML_SAX2_MAGIC)) |
|
428 schannel = ctxt->sax->serror; |
|
429 __xmlRaiseError(schannel, |
|
430 ctxt->vctxt.error, ctxt->vctxt.userData, |
|
431 ctxt, NULL, XML_FROM_DTD, error, |
|
432 XML_ERR_ERROR, NULL, 0, (const char *) str1, |
|
433 NULL, NULL, 0, 0, |
|
434 msg, (const char *) str1); |
|
435 ctxt->valid = 0; |
|
436 } |
|
437 |
|
438 /** |
|
439 * xmlFatalErrMsgInt: |
|
440 * @param ctxt an XML parser context |
|
441 * @param error the error number |
|
442 * @param msg the error message |
|
443 * @param val an integer value |
|
444 * |
|
445 * Handle a fatal parser error, i.e. violating Well-Formedness constraints |
|
446 */ |
|
447 static void |
|
448 xmlFatalErrMsgInt(xmlParserCtxtPtr ctxt, xmlParserErrors error, |
|
449 const char *msg, int val) |
|
450 { |
|
451 if ((ctxt != NULL) && (ctxt->disableSAX != 0) && |
|
452 (ctxt->instate == XML_PARSER_EOF)) |
|
453 return; |
|
454 ctxt->errNo = error; |
|
455 __xmlRaiseError(NULL, NULL, NULL, |
|
456 ctxt, NULL, XML_FROM_PARSER, error, XML_ERR_FATAL, |
|
457 NULL, 0, NULL, NULL, NULL, val, 0, msg, val); |
|
458 ctxt->wellFormed = 0; |
|
459 if (ctxt->recovery == 0) |
|
460 ctxt->disableSAX = 1; |
|
461 } |
|
462 |
|
463 /** |
|
464 * xmlFatalErrMsgStrIntStr: |
|
465 * @param ctxt an XML parser context |
|
466 * @param error the error number |
|
467 * @param msg the error message |
|
468 * @param str1 an string info |
|
469 * @param val an integer value |
|
470 * @param str2 an string info |
|
471 * |
|
472 * Handle a fatal parser error, i.e. violating Well-Formedness constraints |
|
473 */ |
|
474 static void |
|
475 xmlFatalErrMsgStrIntStr(xmlParserCtxtPtr ctxt, xmlParserErrors error, |
|
476 const char *msg, const xmlChar *str1, int val, |
|
477 const xmlChar *str2) |
|
478 { |
|
479 if ((ctxt != NULL) && (ctxt->disableSAX != 0) && |
|
480 (ctxt->instate == XML_PARSER_EOF)) |
|
481 return; |
|
482 ctxt->errNo = error; |
|
483 __xmlRaiseError(NULL, NULL, NULL, |
|
484 ctxt, NULL, XML_FROM_PARSER, error, XML_ERR_FATAL, |
|
485 NULL, 0, (const char *) str1, (const char *) str2, |
|
486 NULL, val, 0, msg, str1, val, str2); |
|
487 ctxt->wellFormed = 0; |
|
488 if (ctxt->recovery == 0) |
|
489 ctxt->disableSAX = 1; |
|
490 } |
|
491 |
|
492 /** |
|
493 * xmlFatalErrMsgStr: |
|
494 * @param ctxt an XML parser context |
|
495 * @param error the error number |
|
496 * @param msg the error message |
|
497 * @param val a string value |
|
498 * |
|
499 * Handle a fatal parser error, i.e. violating Well-Formedness constraints |
|
500 */ |
|
501 static void |
|
502 xmlFatalErrMsgStr(xmlParserCtxtPtr ctxt, xmlParserErrors error, |
|
503 const char *msg, const xmlChar * val) |
|
504 { |
|
505 if ((ctxt != NULL) && (ctxt->disableSAX != 0) && |
|
506 (ctxt->instate == XML_PARSER_EOF)) |
|
507 return; |
|
508 ctxt->errNo = error; |
|
509 __xmlRaiseError(NULL, NULL, NULL, ctxt, NULL, |
|
510 XML_FROM_PARSER, error, XML_ERR_FATAL, |
|
511 NULL, 0, (const char *) val, NULL, NULL, 0, 0, msg, |
|
512 val); |
|
513 ctxt->wellFormed = 0; |
|
514 if (ctxt->recovery == 0) |
|
515 ctxt->disableSAX = 1; |
|
516 } |
|
517 |
|
518 /** |
|
519 * xmlErrMsgStr: |
|
520 * @param ctxt an XML parser context |
|
521 * @param error the error number |
|
522 * @param msg the error message |
|
523 * @param val a string value |
|
524 * |
|
525 * Handle a non fatal parser error |
|
526 */ |
|
527 static void |
|
528 xmlErrMsgStr(xmlParserCtxtPtr ctxt, xmlParserErrors error, |
|
529 const char *msg, const xmlChar * val) |
|
530 { |
|
531 if ((ctxt != NULL) && (ctxt->disableSAX != 0) && |
|
532 (ctxt->instate == XML_PARSER_EOF)) |
|
533 return; |
|
534 ctxt->errNo = error; |
|
535 __xmlRaiseError(NULL, NULL, NULL, ctxt, NULL, |
|
536 XML_FROM_PARSER, error, XML_ERR_ERROR, |
|
537 NULL, 0, (const char *) val, NULL, NULL, 0, 0, msg, |
|
538 val); |
|
539 } |
|
540 |
|
541 /** |
|
542 * xmlNsErr: |
|
543 * @param ctxt an XML parser context |
|
544 * @param error the error number |
|
545 * @param msg the message |
|
546 * @param info1 extra information string |
|
547 * @param info2 extra information string |
|
548 * |
|
549 * Handle a fatal parser error, i.e. violating Well-Formedness constraints |
|
550 */ |
|
551 static void |
|
552 xmlNsErr(xmlParserCtxtPtr ctxt, xmlParserErrors error, |
|
553 const char *msg, |
|
554 const xmlChar * info1, const xmlChar * info2, |
|
555 const xmlChar * info3) |
|
556 { |
|
557 if ((ctxt != NULL) && (ctxt->disableSAX != 0) && |
|
558 (ctxt->instate == XML_PARSER_EOF)) |
|
559 return; |
|
560 ctxt->errNo = error; |
|
561 __xmlRaiseError(NULL, NULL, NULL, ctxt, NULL, XML_FROM_NAMESPACE, error, |
|
562 XML_ERR_ERROR, NULL, 0, (const char *) info1, |
|
563 (const char *) info2, (const char *) info3, 0, 0, msg, |
|
564 info1, info2, info3); |
|
565 ctxt->nsWellFormed = 0; |
|
566 } |
|
567 |
|
568 // XMLENGINE: New code |
|
569 /** |
|
570 * xmlParserOOMErr: |
|
571 * @param ctxt an XML parser context |
|
572 * |
|
573 * Handle a OOM error during parsing XML; |
|
574 * parser is set into state that prevents further processing |
|
575 */ |
|
576 static void |
|
577 xmlParserOOMErr(xmlParserCtxtPtr ctxt) |
|
578 { |
|
579 // Note: this function is mere a simpler (smaller) form to use |
|
580 // it should not change |
|
581 xmlErrMemory(ctxt, NULL); |
|
582 } |
|
583 // |
|
584 |
|
585 /** |
|
586 * xmlCheckCdataPush: |
|
587 * @param cur pointer to the bock of characters |
|
588 * @param len length of the block in bytes |
|
589 * |
|
590 * Check that the block of characters is okay as SCdata content [20] |
|
591 * |
|
592 * Returns the number of bytes to pass if okay, a negative index where an |
|
593 * UTF-8 error occured otherwise |
|
594 */ |
|
595 static int |
|
596 xmlCheckCdataPush(const xmlChar *utf, int len) { |
|
597 int ix; |
|
598 unsigned char c; |
|
599 int codepoint; |
|
600 |
|
601 if ((utf == NULL) || (len <= 0)) |
|
602 return(0); |
|
603 |
|
604 for (ix = 0; ix < len;) { /* string is 0-terminated */ |
|
605 c = utf[ix]; |
|
606 if ((c & 0x80) == 0x00) { /* 1-byte code, starts with 10 */ |
|
607 if (c >= 0x20) |
|
608 ix++; |
|
609 else if ((c == 0xA) || (c == 0xD) || (c == 0x9)) |
|
610 ix++; |
|
611 else |
|
612 return(-ix); |
|
613 } else if ((c & 0xe0) == 0xc0) {/* 2-byte code, starts with 110 */ |
|
614 if (ix + 2 > len) return(ix); |
|
615 if ((utf[ix+1] & 0xc0 ) != 0x80) |
|
616 return(-ix); |
|
617 codepoint = (utf[ix] & 0x1f) << 6; |
|
618 codepoint |= utf[ix+1] & 0x3f; |
|
619 if (!xmlIsCharQ(codepoint)) |
|
620 return(-ix); |
|
621 ix += 2; |
|
622 } else if ((c & 0xf0) == 0xe0) {/* 3-byte code, starts with 1110 */ |
|
623 if (ix + 3 > len) return(ix); |
|
624 if (((utf[ix+1] & 0xc0) != 0x80) || |
|
625 ((utf[ix+2] & 0xc0) != 0x80)) |
|
626 return(-ix); |
|
627 codepoint = (utf[ix] & 0xf) << 12; |
|
628 codepoint |= (utf[ix+1] & 0x3f) << 6; |
|
629 codepoint |= utf[ix+2] & 0x3f; |
|
630 if (!xmlIsCharQ(codepoint)) |
|
631 return(-ix); |
|
632 ix += 3; |
|
633 } else if ((c & 0xf8) == 0xf0) {/* 4-byte code, starts with 11110 */ |
|
634 if (ix + 4 > len) return(ix); |
|
635 if (((utf[ix+1] & 0xc0) != 0x80) || |
|
636 ((utf[ix+2] & 0xc0) != 0x80) || |
|
637 ((utf[ix+3] & 0xc0) != 0x80)) |
|
638 return(-ix); |
|
639 codepoint = (utf[ix] & 0x7) << 18; |
|
640 codepoint |= (utf[ix+1] & 0x3f) << 12; |
|
641 codepoint |= (utf[ix+2] & 0x3f) << 6; |
|
642 codepoint |= utf[ix+3] & 0x3f; |
|
643 if (!xmlIsCharQ(codepoint)) |
|
644 return(-ix); |
|
645 ix += 4; |
|
646 } else /* unknown encoding */ |
|
647 return(-ix); |
|
648 } |
|
649 return(ix); |
|
650 } |
|
651 |
|
652 /************************************************************************ |
|
653 * * |
|
654 * SAX2 defaulted attributes handling * |
|
655 * * |
|
656 ************************************************************************/ |
|
657 |
|
658 /** |
|
659 * xmlDetectSAX2: |
|
660 * @param ctxt an XML parser context |
|
661 * |
|
662 * Do the SAX2 detection and specific intialization |
|
663 * |
|
664 * OOM: possible --> OOM flag is set |
|
665 */ |
|
666 static void |
|
667 xmlDetectSAX2(xmlParserCtxtPtr ctxt) |
|
668 { |
|
669 if (!ctxt) |
|
670 return; |
|
671 #ifdef LIBXML_SAX1_ENABLED |
|
672 if ((ctxt->sax) && (ctxt->sax->initialized == XML_SAX2_MAGIC) && |
|
673 ((ctxt->sax->startElementNs != NULL) || |
|
674 (ctxt->sax->endElementNs != NULL))) |
|
675 { |
|
676 ctxt->sax2 = 1; |
|
677 } |
|
678 #else |
|
679 ctxt->sax2 = 1; |
|
680 #endif /* LIBXML_SAX1_ENABLED */ |
|
681 // Each of these can end with OOM condition |
|
682 ctxt->str_xml = xmlDictLookup(ctxt->dict, BAD_CAST "xml", 3); |
|
683 ctxt->str_xmlns = xmlDictLookup(ctxt->dict, BAD_CAST "xmlns", 5); |
|
684 ctxt->str_xml_ns = xmlDictLookup(ctxt->dict, XML_XML_NAMESPACE, 36); |
|
685 if(ctxt->sax && ctxt->sax->startElementNs == xmlSAX2StartElementNs) |
|
686 { |
|
687 ctxt->stackLowThreshold = MIN_STACK_THRESHOLD; |
|
688 } |
|
689 else |
|
690 { |
|
691 ctxt->stackLowThreshold = MAX_STACK_THRESHOLD; |
|
692 } |
|
693 } |
|
694 |
|
695 typedef struct _xmlDefAttrs xmlDefAttrs; |
|
696 typedef xmlDefAttrs *xmlDefAttrsPtr; |
|
697 struct _xmlDefAttrs { |
|
698 int nbAttrs; /* number of defaulted attributes on that element */ |
|
699 int maxAttrs; /* the size of the array */ |
|
700 const xmlChar *values[4]; /* array of localname/prefix/values */ |
|
701 }; |
|
702 |
|
703 /** |
|
704 * xmlAddDefAttrs: |
|
705 * @param ctxt an XML parser context |
|
706 * @param fullname the element fullname |
|
707 * @param fullattr the attribute fullname |
|
708 * @param value the attribute value |
|
709 * |
|
710 * Add a defaulted attribute for an element |
|
711 */ |
|
712 static void |
|
713 xmlAddDefAttrs(xmlParserCtxtPtr ctxt, |
|
714 const xmlChar *fullname, |
|
715 const xmlChar *fullattr, |
|
716 const xmlChar *value) |
|
717 { |
|
718 xmlDefAttrsPtr defaults; |
|
719 int len; |
|
720 const xmlChar* name; |
|
721 const xmlChar* prefix; |
|
722 LOAD_GS_SAFE_CTXT(ctxt) |
|
723 |
|
724 if (ctxt->attsDefault == NULL) { |
|
725 ctxt->attsDefault = xmlHashCreate(10); |
|
726 if (ctxt->attsDefault == NULL) |
|
727 goto mem_error; |
|
728 } |
|
729 |
|
730 /* |
|
731 * split the element name into prefix:localname , the string found |
|
732 * are within the DTD and then not associated to namespace names. |
|
733 */ |
|
734 name = xmlSplitQName3(fullname, &len); |
|
735 if (name == NULL) { |
|
736 name = xmlDictLookup(ctxt->dict, fullname, -1); |
|
737 prefix = NULL; |
|
738 } else { |
|
739 name = xmlDictLookup(ctxt->dict, name, -1); |
|
740 prefix = xmlDictLookup(ctxt->dict, fullname, len); |
|
741 } |
|
742 |
|
743 /* |
|
744 * make sure there is some storage |
|
745 */ |
|
746 defaults = (xmlDefAttrsPtr)xmlHashLookup2(ctxt->attsDefault, name, prefix); |
|
747 if (defaults == NULL) |
|
748 { |
|
749 defaults = (xmlDefAttrsPtr) xmlMalloc(sizeof(xmlDefAttrs) + |
|
750 12 * sizeof(const xmlChar *)); |
|
751 if (defaults == NULL) |
|
752 goto mem_error; |
|
753 defaults->maxAttrs = 4; |
|
754 defaults->nbAttrs = 0; |
|
755 if ( xmlHashUpdateEntry2(ctxt->attsDefault, name, prefix, defaults, NULL) == -1 ) |
|
756 { |
|
757 xmlFree( defaults ); |
|
758 return ; |
|
759 } |
|
760 if ( OOM_FLAG ) |
|
761 return ; |
|
762 } |
|
763 else if (defaults->nbAttrs >= defaults->maxAttrs) |
|
764 { |
|
765 // DONE: Fix xmlRealloc |
|
766 // NOTE: nothing to fix since 'defaults' is stored in hash table |
|
767 defaults = (xmlDefAttrsPtr) xmlRealloc(defaults, sizeof(xmlDefAttrs) + |
|
768 (2 * defaults->maxAttrs * 4) * sizeof(const xmlChar*)); |
|
769 if (defaults == NULL) |
|
770 goto mem_error; |
|
771 defaults->maxAttrs *= 2; |
|
772 if ( xmlHashUpdateEntry2(ctxt->attsDefault, name, prefix, defaults, NULL) == -1 ) |
|
773 { |
|
774 xmlFree( defaults ); |
|
775 return ; |
|
776 } |
|
777 if ( OOM_FLAG ) |
|
778 return ; |
|
779 } |
|
780 |
|
781 /* |
|
782 * split the element name into prefix:localname , the string found |
|
783 * are within the DTD and then not associated to namespace names. |
|
784 */ |
|
785 name = xmlSplitQName3(fullattr, &len); |
|
786 if (name == NULL) { |
|
787 name = xmlDictLookup(ctxt->dict, fullattr, -1); |
|
788 prefix = NULL; |
|
789 } else { |
|
790 name = xmlDictLookup(ctxt->dict, name, -1); |
|
791 prefix = xmlDictLookup(ctxt->dict, fullattr, len); |
|
792 } |
|
793 |
|
794 defaults->values[4 * defaults->nbAttrs] = name; |
|
795 defaults->values[4 * defaults->nbAttrs + 1] = prefix; |
|
796 /* intern the string and precompute the end */ |
|
797 len = xmlStrlen(value); |
|
798 value = xmlDictLookup(ctxt->dict, value, len); |
|
799 defaults->values[4 * defaults->nbAttrs + 2] = value; |
|
800 defaults->values[4 * defaults->nbAttrs + 3] = value + len; |
|
801 defaults->nbAttrs++; |
|
802 |
|
803 return; |
|
804 |
|
805 mem_error: |
|
806 xmlErrMemory(ctxt, NULL); |
|
807 return; |
|
808 } |
|
809 |
|
810 /** |
|
811 * xmlAddSpecialAttr: |
|
812 * @param ctxt an XML parser context |
|
813 * @param fullname the element fullname |
|
814 * @param fullattr the attribute fullname |
|
815 * @param type the attribute type |
|
816 * |
|
817 * Register that this attribute is not CDATA |
|
818 */ |
|
819 static void |
|
820 xmlAddSpecialAttr(xmlParserCtxtPtr ctxt, |
|
821 const xmlChar *fullname, |
|
822 const xmlChar *fullattr, |
|
823 int type) |
|
824 { |
|
825 if (ctxt->attsSpecial == NULL) { |
|
826 ctxt->attsSpecial = xmlHashCreate(10); |
|
827 if (ctxt->attsSpecial == NULL) |
|
828 goto mem_error; |
|
829 } |
|
830 |
|
831 xmlHashAddEntry2(ctxt->attsSpecial, fullname, fullattr, |
|
832 (void *) (long) type); |
|
833 return; |
|
834 |
|
835 mem_error: |
|
836 xmlParserOOMErr(ctxt); |
|
837 return; |
|
838 } |
|
839 |
|
840 /** |
|
841 * xmlCheckLanguageID: |
|
842 * @param lang pointer to the string value |
|
843 * |
|
844 * Checks that the value conforms to the LanguageID production: |
|
845 * |
|
846 * NOTE: this is somewhat deprecated, those productions were removed from |
|
847 * the XML Second edition. |
|
848 * |
|
849 * [33] LanguageID ::= Langcode ('-' Subcode)* |
|
850 * [34] Langcode ::= ISO639Code | IanaCode | UserCode |
|
851 * [35] ISO639Code ::= ([a-z] | [A-Z]) ([a-z] | [A-Z]) |
|
852 * [36] IanaCode ::= ('i' | 'I') '-' ([a-z] | [A-Z])+ |
|
853 * [37] UserCode ::= ('x' | 'X') '-' ([a-z] | [A-Z])+ |
|
854 * [38] Subcode ::= ([a-z] | [A-Z])+ |
|
855 * |
|
856 * Returns 1 if correct 0 otherwise |
|
857 **/ |
|
858 XMLPUBFUNEXPORT int |
|
859 xmlCheckLanguageID(const xmlChar * lang) |
|
860 { |
|
861 const xmlChar *cur = lang; |
|
862 |
|
863 if (cur == NULL) |
|
864 return (0); |
|
865 if (((cur[0] == 'i') && (cur[1] == '-')) || |
|
866 ((cur[0] == 'I') && (cur[1] == '-'))) { |
|
867 /* |
|
868 * IANA code |
|
869 */ |
|
870 cur += 2; |
|
871 while (((cur[0] >= 'A') && (cur[0] <= 'Z')) || /* non input consuming */ |
|
872 ((cur[0] >= 'a') && (cur[0] <= 'z'))) |
|
873 cur++; |
|
874 } else if (((cur[0] == 'x') && (cur[1] == '-')) || |
|
875 ((cur[0] == 'X') && (cur[1] == '-'))) { |
|
876 /* |
|
877 * User code |
|
878 */ |
|
879 cur += 2; |
|
880 while (((cur[0] >= 'A') && (cur[0] <= 'Z')) || /* non input consuming */ |
|
881 ((cur[0] >= 'a') && (cur[0] <= 'z'))) |
|
882 cur++; |
|
883 } else if (((cur[0] >= 'A') && (cur[0] <= 'Z')) || |
|
884 ((cur[0] >= 'a') && (cur[0] <= 'z'))) { |
|
885 /* |
|
886 * ISO639 |
|
887 */ |
|
888 cur++; |
|
889 if (((cur[0] >= 'A') && (cur[0] <= 'Z')) || |
|
890 ((cur[0] >= 'a') && (cur[0] <= 'z'))) |
|
891 cur++; |
|
892 else |
|
893 return (0); |
|
894 } else |
|
895 return (0); |
|
896 while (cur[0] != 0) { /* non input consuming */ |
|
897 if (cur[0] != '-') |
|
898 return (0); |
|
899 cur++; |
|
900 if (((cur[0] >= 'A') && (cur[0] <= 'Z')) || |
|
901 ((cur[0] >= 'a') && (cur[0] <= 'z'))) |
|
902 cur++; |
|
903 else |
|
904 return (0); |
|
905 while (((cur[0] >= 'A') && (cur[0] <= 'Z')) || /* non input consuming */ |
|
906 ((cur[0] >= 'a') && (cur[0] <= 'z'))) |
|
907 cur++; |
|
908 } |
|
909 return (1); |
|
910 } |
|
911 |
|
912 /************************************************************************ |
|
913 * * |
|
914 * Parser stacks related functions and macros * |
|
915 * * |
|
916 ************************************************************************/ |
|
917 |
|
918 xmlEntityPtr xmlParseStringEntityRef(xmlParserCtxtPtr ctxt, |
|
919 const xmlChar** str); |
|
920 |
|
921 #ifdef SAX2 |
|
922 /** |
|
923 * nsPush: |
|
924 * @param ctxt an XML parser context |
|
925 * @param prefix the namespace prefix or NULL |
|
926 * @param URL the namespace name |
|
927 * |
|
928 * Pushes a new parser namespace on top of the ns stack |
|
929 * |
|
930 * Returns -1 in case of error, -2 if the namespace should be discarded |
|
931 * and the index in the stack otherwise. |
|
932 */ |
|
933 static int |
|
934 nsPush(xmlParserCtxtPtr ctxt, const xmlChar *prefix, const xmlChar *URL) |
|
935 { |
|
936 if (ctxt->options & XML_PARSE_NSCLEAN) |
|
937 { |
|
938 int i; |
|
939 for (i = 0; i < ctxt->nsNr; i += 2) |
|
940 { |
|
941 if (ctxt->nsTab[i] == prefix) |
|
942 { |
|
943 /* in scope */ |
|
944 if (ctxt->nsTab[i + 1] == URL) |
|
945 return(-2); |
|
946 /* out of scope keep it */ |
|
947 break; |
|
948 } |
|
949 } |
|
950 } |
|
951 if ((ctxt->nsMax == 0) || (ctxt->nsTab == NULL)) { |
|
952 ctxt->nsMax = 10; |
|
953 ctxt->nsNr = 0; |
|
954 |
|
955 ctxt->nsTab = (const xmlChar **) |
|
956 xmlMalloc(ctxt->nsMax * sizeof(xmlChar *)); |
|
957 if (ctxt->nsTab == NULL) { |
|
958 xmlParserOOMErr(ctxt); |
|
959 ctxt->nsMax = 0; |
|
960 return (-1); |
|
961 } |
|
962 } else if (ctxt->nsNr >= ctxt->nsMax) { |
|
963 const xmlChar** largerTab; |
|
964 |
|
965 ctxt->nsMax *= 2; |
|
966 // DONE: Fix memory leak here (when realloc returns NULL) |
|
967 largerTab = (const xmlChar **) |
|
968 xmlRealloc((char *) ctxt->nsTab, |
|
969 ctxt->nsMax * sizeof(ctxt->nsTab[0])); |
|
970 if (!largerTab) { |
|
971 xmlParserOOMErr(ctxt); |
|
972 ctxt->nsMax /= 2; |
|
973 return (-1); |
|
974 } |
|
975 ctxt->nsTab = largerTab; |
|
976 } |
|
977 ctxt->nsTab[ctxt->nsNr++] = prefix; |
|
978 ctxt->nsTab[ctxt->nsNr++] = URL; |
|
979 // XE: BEGIN NEW CODE |
|
980 /* |
|
981 * SAX: prefix mapping ! |
|
982 */ |
|
983 if ((ctxt->sax != NULL) && |
|
984 (ctxt->sax->startPrefixMapping != NULL) && |
|
985 (!ctxt->disableSAX)) |
|
986 { |
|
987 ctxt->sax->startPrefixMapping(ctxt->userData, prefix, URL); |
|
988 } |
|
989 // XE: END NEW CODE |
|
990 return (ctxt->nsNr); |
|
991 } |
|
992 /** |
|
993 * nsPop: |
|
994 * @param ctxt an XML parser context |
|
995 * @param nr the number to pop |
|
996 * |
|
997 * Pops the top nr parser prefix/namespace from the ns stack |
|
998 * |
|
999 * Returns the number of namespaces removed |
|
1000 */ |
|
1001 static int |
|
1002 nsPop(xmlParserCtxtPtr ctxt, int nr) |
|
1003 { |
|
1004 int i; |
|
1005 |
|
1006 if (ctxt->nsTab == NULL) return(0); |
|
1007 if (ctxt->nsNr < nr) { |
|
1008 xmlGenericError(xmlGenericErrorContext, EMBED_ERRTXT("Pbm popping %d NS\n"), nr); |
|
1009 nr = ctxt->nsNr; |
|
1010 } |
|
1011 if (ctxt->nsNr <= 0) |
|
1012 return (0); |
|
1013 |
|
1014 // XE: REPLACED CODE |
|
1015 //for (i = 0;i < nr;i++) { |
|
1016 // nr is even number, because pairs of (URL,prefix) are removed from ctxt->nsTab[] array |
|
1017 // by this moment ctxt->nsNr points to the next free cell after ...{prefix}{URL}{..}... |
|
1018 // ctxt->nsTab[ctxt->nsNr]-------^ |
|
1019 // XE: REPLACED WITH |
|
1020 for (i = nr/2; i > 0; i--) { |
|
1021 ctxt->nsNr--; |
|
1022 ctxt->nsTab[ctxt->nsNr] = NULL; // clean up URL |
|
1023 ctxt->nsNr--; |
|
1024 // XE: BEGIN NEW CODE |
|
1025 |
|
1026 /* |
|
1027 * SAX: end of prefix mapping ! |
|
1028 */ |
|
1029 if ((ctxt->sax != NULL) && |
|
1030 (ctxt->sax->endPrefixMapping != NULL) && |
|
1031 (!ctxt->disableSAX)) |
|
1032 { |
|
1033 ctxt->sax->endPrefixMapping(ctxt->userData, ctxt->nsTab[ctxt->nsNr]); |
|
1034 } |
|
1035 // XE: END NEW CODE |
|
1036 ctxt->nsTab[ctxt->nsNr] = NULL; // clean up prefix name |
|
1037 |
|
1038 |
|
1039 } |
|
1040 return(nr); |
|
1041 } |
|
1042 #endif |
|
1043 |
|
1044 static int |
|
1045 xmlCtxtGrowAttrs(xmlParserCtxtPtr ctxt, int nr) { |
|
1046 const xmlChar **atts; |
|
1047 int *attallocs; |
|
1048 int maxatts; |
|
1049 |
|
1050 if (ctxt->atts == NULL) { |
|
1051 maxatts = 55; /* allow for 10 attrs by default */ |
|
1052 atts = (const xmlChar **) |
|
1053 xmlMalloc(maxatts * sizeof(xmlChar *)); |
|
1054 if (atts == NULL) goto mem_error; |
|
1055 ctxt->atts = atts; |
|
1056 attallocs = (int *) xmlMalloc((maxatts / 5) * sizeof(int)); |
|
1057 if (attallocs == NULL) goto mem_error; |
|
1058 ctxt->attallocs = attallocs; |
|
1059 ctxt->maxatts = maxatts; |
|
1060 } else if (nr + 5 > ctxt->maxatts) { |
|
1061 maxatts = (nr + 5) * 2; |
|
1062 atts = (const xmlChar **) xmlRealloc((void *) ctxt->atts, |
|
1063 maxatts * sizeof(const xmlChar *)); |
|
1064 if (atts == NULL) goto mem_error; |
|
1065 ctxt->atts = atts; |
|
1066 attallocs = (int *) xmlRealloc((void *) ctxt->attallocs, |
|
1067 (maxatts / 5) * sizeof(int)); |
|
1068 if (attallocs == NULL) goto mem_error; |
|
1069 ctxt->attallocs = attallocs; |
|
1070 ctxt->maxatts = maxatts; |
|
1071 } |
|
1072 return(ctxt->maxatts); |
|
1073 mem_error: |
|
1074 xmlParserOOMErr(ctxt); |
|
1075 return(-1); |
|
1076 } |
|
1077 |
|
1078 /** |
|
1079 * inputPush: |
|
1080 * @param ctxt an XML parser context |
|
1081 * @param value the parser input |
|
1082 * |
|
1083 * Pushes a new parser input on top of the input stack |
|
1084 * |
|
1085 * Returns -1 in case of error, the index in the stack otherwise |
|
1086 * |
|
1087 * OOM: possible --> returns -1 and OOM flag is set |
|
1088 */ |
|
1089 XMLPUBFUNEXPORT int |
|
1090 inputPush(xmlParserCtxtPtr ctxt, xmlParserInputPtr value) |
|
1091 { |
|
1092 if (ctxt->inputNr >= ctxt->inputMax) |
|
1093 { |
|
1094 // DONE: Fix xmlRealloc |
|
1095 void* tmp; |
|
1096 ctxt->inputMax *= 2; |
|
1097 tmp = xmlRealloc(ctxt->inputTab, |
|
1098 ctxt->inputMax * sizeof(ctxt->inputTab[0])); |
|
1099 if (!tmp) { |
|
1100 ctxt->inputMax /= 2; |
|
1101 xmlParserOOMErr(ctxt); |
|
1102 return (-1); |
|
1103 } |
|
1104 ctxt->inputTab = (xmlParserInputPtr*) tmp; |
|
1105 } |
|
1106 ctxt->inputTab[ctxt->inputNr] = value; |
|
1107 ctxt->input = value; |
|
1108 return (ctxt->inputNr++); |
|
1109 } |
|
1110 |
|
1111 /** |
|
1112 * inputPop: |
|
1113 * @param ctxt an XML parser context |
|
1114 * |
|
1115 * Pops the top parser input from the input stack |
|
1116 * |
|
1117 * Returns the input just removed |
|
1118 */ |
|
1119 XMLPUBFUNEXPORT xmlParserInputPtr |
|
1120 inputPop(xmlParserCtxtPtr ctxt) |
|
1121 { |
|
1122 xmlParserInputPtr ret; |
|
1123 |
|
1124 if (ctxt->inputNr <= 0) |
|
1125 return (0); |
|
1126 ctxt->inputNr--; |
|
1127 if (ctxt->inputNr > 0) |
|
1128 ctxt->input = ctxt->inputTab[ctxt->inputNr - 1]; |
|
1129 else |
|
1130 ctxt->input = NULL; |
|
1131 ret = ctxt->inputTab[ctxt->inputNr]; |
|
1132 ctxt->inputTab[ctxt->inputNr] = 0; |
|
1133 return (ret); |
|
1134 } |
|
1135 /** |
|
1136 * nodePush: |
|
1137 * @param ctxt an XML parser context |
|
1138 * @param value the element node |
|
1139 * |
|
1140 * Pushes a new element node on top of the node stack |
|
1141 * |
|
1142 * Returns 0 in case of error, the index in the stack otherwise |
|
1143 */ |
|
1144 XMLPUBFUNEXPORT int |
|
1145 nodePush(xmlParserCtxtPtr ctxt, xmlNodePtr value) |
|
1146 { |
|
1147 LOAD_GS_SAFE_CTXT(ctxt) |
|
1148 if (ctxt->nodeNr >= ctxt->nodeMax) |
|
1149 { |
|
1150 // DONE: Fix xmlRealloc |
|
1151 void* tmp; |
|
1152 ctxt->nodeMax *= 2; |
|
1153 tmp = xmlRealloc(ctxt->nodeTab, |
|
1154 ctxt->nodeMax * sizeof(ctxt->nodeTab[0])); |
|
1155 if (!tmp) { |
|
1156 ctxt->nodeMax /= 2; |
|
1157 xmlParserOOMErr(ctxt); |
|
1158 return (0); |
|
1159 } |
|
1160 ctxt->nodeTab = (xmlNodePtr*) tmp; |
|
1161 } |
|
1162 |
|
1163 if (((unsigned int) ctxt->nodeNr) > xmlParserMaxDepth) |
|
1164 { |
|
1165 xmlFatalErrMsgInt(ctxt, XML_ERR_INTERNAL_ERROR, |
|
1166 EMBED_ERRTXT("Excessive depth in document: change xmlParserMaxDepth = %d\n"), |
|
1167 xmlParserMaxDepth); |
|
1168 ctxt->instate = XML_PARSER_EOF; |
|
1169 return(0); |
|
1170 } |
|
1171 |
|
1172 ctxt->nodeTab[ctxt->nodeNr] = value; |
|
1173 ctxt->node = value; |
|
1174 return (ctxt->nodeNr++); |
|
1175 } |
|
1176 |
|
1177 /** |
|
1178 * nodePop: |
|
1179 * @param ctxt an XML parser context |
|
1180 * |
|
1181 * Pops the top element node from the node stack |
|
1182 * |
|
1183 * Returns the node just removed |
|
1184 */ |
|
1185 XMLPUBFUNEXPORT xmlNodePtr |
|
1186 nodePop(xmlParserCtxtPtr ctxt) |
|
1187 { |
|
1188 xmlNodePtr ret; |
|
1189 |
|
1190 if (ctxt->nodeNr <= 0) |
|
1191 return (0); |
|
1192 ctxt->nodeNr--; |
|
1193 if (ctxt->nodeNr > 0) |
|
1194 ctxt->node = ctxt->nodeTab[ctxt->nodeNr - 1]; |
|
1195 else |
|
1196 ctxt->node = NULL; |
|
1197 ret = ctxt->nodeTab[ctxt->nodeNr]; |
|
1198 ctxt->nodeTab[ctxt->nodeNr] = 0; |
|
1199 return (ret); |
|
1200 } |
|
1201 /** |
|
1202 * nameNsPush: |
|
1203 * @param ctxt an XML parser context |
|
1204 * @param value the element name |
|
1205 * @param prefix the element prefix |
|
1206 * @param URI the element namespace name |
|
1207 * |
|
1208 * Pushes a new element name/prefix/URL on top of the name stack |
|
1209 * |
|
1210 * Returns -1 in case of error, the index in the stack otherwise |
|
1211 */ |
|
1212 static int |
|
1213 nameNsPush(xmlParserCtxtPtr ctxt, const xmlChar * value, |
|
1214 const xmlChar *prefix, const xmlChar *URI, int nsNr) |
|
1215 { |
|
1216 if (ctxt->nameNr >= ctxt->nameMax) { |
|
1217 const xmlChar * *tmp; |
|
1218 void **tmp2; |
|
1219 ctxt->nameMax *= 2; |
|
1220 tmp = (const xmlChar * *) xmlRealloc((xmlChar * *)ctxt->nameTab, |
|
1221 ctxt->nameMax * |
|
1222 sizeof(ctxt->nameTab[0])); |
|
1223 if (tmp == NULL) { |
|
1224 ctxt->nameMax /= 2; |
|
1225 goto mem_error; |
|
1226 } |
|
1227 ctxt->nameTab = tmp; |
|
1228 tmp2 = (void **) xmlRealloc((void * *)ctxt->pushTab, |
|
1229 ctxt->nameMax * 3 * |
|
1230 sizeof(ctxt->pushTab[0])); |
|
1231 if (tmp2 == NULL) { |
|
1232 ctxt->nameMax /= 2; |
|
1233 goto mem_error; |
|
1234 } |
|
1235 ctxt->pushTab = tmp2; |
|
1236 } |
|
1237 ctxt->nameTab[ctxt->nameNr] = value; |
|
1238 ctxt->name = value; |
|
1239 ctxt->pushTab[ctxt->nameNr * 3] = (void *) prefix; |
|
1240 ctxt->pushTab[ctxt->nameNr * 3 + 1] = (void *) URI; |
|
1241 ctxt->pushTab[ctxt->nameNr * 3 + 2] = (void *) (long) nsNr; |
|
1242 return (ctxt->nameNr++); |
|
1243 mem_error: |
|
1244 xmlParserOOMErr(ctxt); |
|
1245 return (-1); |
|
1246 } |
|
1247 /** |
|
1248 * nameNsPop: |
|
1249 * @param ctxt an XML parser context |
|
1250 * |
|
1251 * Pops the top element/prefix/URI name from the name stack |
|
1252 * |
|
1253 * Returns the name just removed |
|
1254 */ |
|
1255 static const xmlChar * |
|
1256 nameNsPop(xmlParserCtxtPtr ctxt) |
|
1257 { |
|
1258 const xmlChar *ret; |
|
1259 |
|
1260 if (ctxt->nameNr <= 0) |
|
1261 return (0); |
|
1262 ctxt->nameNr--; |
|
1263 if (ctxt->nameNr > 0) |
|
1264 ctxt->name = ctxt->nameTab[ctxt->nameNr - 1]; |
|
1265 else |
|
1266 ctxt->name = NULL; |
|
1267 ret = ctxt->nameTab[ctxt->nameNr]; |
|
1268 ctxt->nameTab[ctxt->nameNr] = NULL; |
|
1269 return (ret); |
|
1270 } |
|
1271 |
|
1272 /** |
|
1273 * namePush: |
|
1274 * @param ctxt an XML parser context |
|
1275 * @param value the element name |
|
1276 * |
|
1277 * Pushes a new element name on top of the name stack |
|
1278 * |
|
1279 * Returns -1 in case of error, the index in the stack otherwise |
|
1280 */ |
|
1281 XMLPUBFUNEXPORT extern int |
|
1282 namePush(xmlParserCtxtPtr ctxt, const xmlChar * value) |
|
1283 { |
|
1284 if (ctxt->nameNr >= ctxt->nameMax) { |
|
1285 const xmlChar** tmp; |
|
1286 ctxt->nameMax *= 2; |
|
1287 tmp = (const xmlChar**) xmlRealloc((xmlChar**)ctxt->nameTab, |
|
1288 ctxt->nameMax * |
|
1289 sizeof(ctxt->nameTab[0])); |
|
1290 if (!tmp) { |
|
1291 ctxt->nameMax /= 2; |
|
1292 xmlParserOOMErr(ctxt); |
|
1293 return (-1); |
|
1294 } |
|
1295 ctxt->nameTab = tmp; |
|
1296 } |
|
1297 ctxt->nameTab[ctxt->nameNr] = value; |
|
1298 ctxt->name = value; |
|
1299 return (ctxt->nameNr++); |
|
1300 } |
|
1301 |
|
1302 /** |
|
1303 * namePop: |
|
1304 * @param ctxt an XML parser context |
|
1305 * |
|
1306 * Pops the top element name from the name stack |
|
1307 * |
|
1308 * Returns the name just removed |
|
1309 */ |
|
1310 XMLPUBFUNEXPORT extern const xmlChar* |
|
1311 namePop(xmlParserCtxtPtr ctxt) |
|
1312 { |
|
1313 const xmlChar *ret; |
|
1314 |
|
1315 if (ctxt->nameNr <= 0) |
|
1316 return (0); |
|
1317 ctxt->nameNr--; |
|
1318 if (ctxt->nameNr > 0) |
|
1319 ctxt->name = ctxt->nameTab[ctxt->nameNr - 1]; |
|
1320 else |
|
1321 ctxt->name = NULL; |
|
1322 ret = ctxt->nameTab[ctxt->nameNr]; |
|
1323 ctxt->nameTab[ctxt->nameNr] = 0; |
|
1324 return (ret); |
|
1325 } |
|
1326 |
|
1327 static int spacePush(xmlParserCtxtPtr ctxt, int val) |
|
1328 { |
|
1329 if (ctxt->spaceNr >= ctxt->spaceMax) { |
|
1330 // DONE: Fix xmlRealloc |
|
1331 void* tmp; |
|
1332 ctxt->spaceMax *= 2; |
|
1333 tmp = xmlRealloc(ctxt->spaceTab, |
|
1334 ctxt->spaceMax * sizeof(ctxt->spaceTab[0])); |
|
1335 if (!tmp) { |
|
1336 ctxt->spaceMax /= 2; |
|
1337 xmlParserOOMErr(ctxt); |
|
1338 return(0); |
|
1339 } |
|
1340 ctxt->spaceTab = (int*) tmp; |
|
1341 } |
|
1342 ctxt->spaceTab[ctxt->spaceNr] = val; |
|
1343 ctxt->space = &ctxt->spaceTab[ctxt->spaceNr]; |
|
1344 return(ctxt->spaceNr++); |
|
1345 } |
|
1346 |
|
1347 static int spacePop(xmlParserCtxtPtr ctxt) |
|
1348 { |
|
1349 int ret; |
|
1350 if (ctxt->spaceNr <= 0) return(0); |
|
1351 ctxt->spaceNr--; |
|
1352 if (ctxt->spaceNr > 0) |
|
1353 ctxt->space = &ctxt->spaceTab[ctxt->spaceNr - 1]; |
|
1354 else |
|
1355 ctxt->space = NULL; |
|
1356 ret = ctxt->spaceTab[ctxt->spaceNr]; |
|
1357 ctxt->spaceTab[ctxt->spaceNr] = -1; |
|
1358 return(ret); |
|
1359 } |
|
1360 |
|
1361 /* |
|
1362 * Macros for accessing the content. Those should be used only by the parser, |
|
1363 * and not exported. |
|
1364 * |
|
1365 * Dirty macros, i.e. one often need to make assumption on the context to |
|
1366 * use them |
|
1367 * |
|
1368 * CUR_PTR return the current pointer to the xmlChar to be parsed. |
|
1369 * To be used with extreme caution since operations consuming |
|
1370 * characters may move the input buffer to a different location ! |
|
1371 * CUR returns the current xmlChar value, i.e. a 8 bit value if compiled |
|
1372 * This should be used internally by the parser |
|
1373 * only to compare to ASCII values otherwise it would break when |
|
1374 * running with UTF-8 encoding. |
|
1375 * RAW same as CUR but in the input buffer, bypass any token |
|
1376 * extraction that may have been done |
|
1377 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only |
|
1378 * to compare on ASCII based substring. |
|
1379 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined |
|
1380 * strings without newlines within the parser. |
|
1381 * NEXT1(l) Skip 1 xmlChar, and must also be used only to skip 1 non-newline ASCII |
|
1382 * defined char within the parser. |
|
1383 * Clean macros, not dependent of an ASCII context, expect UTF-8 encoding |
|
1384 * |
|
1385 * NEXT Skip to the next character, this does the proper decoding |
|
1386 * in UTF-8 mode. It also pop-up unfinishedEntities on the fly. |
|
1387 * NEXTL(l) Skip the current unicode character of l xmlChars long. |
|
1388 * CUR_CHAR(l) returns the current unicode character (int), set l |
|
1389 * to the number of xmlChars used for the encoding [0-5]. |
|
1390 * CUR_SCHAR same but operate on a string instead of the context |
|
1391 * COPY_BUF copy the current unicode char to the target buffer, increment |
|
1392 * the index |
|
1393 * GROW, SHRINK handling of input buffers |
|
1394 */ |
|
1395 |
|
1396 #define RAW (*ctxt->input->cur) |
|
1397 #define CUR (*ctxt->input->cur) |
|
1398 #define NXT(val) ctxt->input->cur[(val)] |
|
1399 #define CUR_PTR ctxt->input->cur |
|
1400 |
|
1401 #define CMP4( s, c1, c2, c3, c4 ) \ |
|
1402 ( ((unsigned char *) s)[ 0 ] == c1 && ((unsigned char *) s)[ 1 ] == c2 && \ |
|
1403 ((unsigned char *) s)[ 2 ] == c3 && ((unsigned char *) s)[ 3 ] == c4 ) |
|
1404 #define CMP5( s, c1, c2, c3, c4, c5 ) \ |
|
1405 ( CMP4( s, c1, c2, c3, c4 ) && ((unsigned char *) s)[ 4 ] == c5 ) |
|
1406 #define CMP6( s, c1, c2, c3, c4, c5, c6 ) \ |
|
1407 ( CMP5( s, c1, c2, c3, c4, c5 ) && ((unsigned char *) s)[ 5 ] == c6 ) |
|
1408 #define CMP7( s, c1, c2, c3, c4, c5, c6, c7 ) \ |
|
1409 ( CMP6( s, c1, c2, c3, c4, c5, c6 ) && ((unsigned char *) s)[ 6 ] == c7 ) |
|
1410 #define CMP8( s, c1, c2, c3, c4, c5, c6, c7, c8 ) \ |
|
1411 ( CMP7( s, c1, c2, c3, c4, c5, c6, c7 ) && ((unsigned char *) s)[ 7 ] == c8 ) |
|
1412 #define CMP9( s, c1, c2, c3, c4, c5, c6, c7, c8, c9 ) \ |
|
1413 ( CMP8( s, c1, c2, c3, c4, c5, c6, c7, c8 ) && \ |
|
1414 ((unsigned char *) s)[ 8 ] == c9 ) |
|
1415 #define CMP10( s, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10 ) \ |
|
1416 ( CMP9( s, c1, c2, c3, c4, c5, c6, c7, c8, c9 ) && \ |
|
1417 ((unsigned char *) s)[ 9 ] == c10 ) |
|
1418 |
|
1419 #define SKIP(val) do { \ |
|
1420 ctxt->nbChars += (val),ctxt->input->cur += (val),ctxt->input->col+=(val); \ |
|
1421 if (*ctxt->input->cur == '%') xmlParserHandlePEReference(ctxt); \ |
|
1422 if ((*ctxt->input->cur == 0) && \ |
|
1423 (xmlParserInputGrow(ctxt->input, INPUT_CHUNK) <= 0)) \ |
|
1424 xmlPopInput(ctxt); \ |
|
1425 } while (0) |
|
1426 |
|
1427 #define SKIPL(val) do { \ |
|
1428 int skipl; \ |
|
1429 for(skipl=0; skipl<val; skipl++) { \ |
|
1430 if (*(ctxt->input->cur) == '\n') { \ |
|
1431 ctxt->input->line++; ctxt->input->col = 1; \ |
|
1432 } else ctxt->input->col++; \ |
|
1433 ctxt->nbChars++; \ |
|
1434 ctxt->input->cur++; \ |
|
1435 } \ |
|
1436 if (*ctxt->input->cur == '%') xmlParserHandlePEReference(ctxt); \ |
|
1437 if ((*ctxt->input->cur == 0) && \ |
|
1438 (xmlParserInputGrow(ctxt->input, INPUT_CHUNK) <= 0)) \ |
|
1439 xmlPopInput(ctxt); \ |
|
1440 } while (0) |
|
1441 |
|
1442 #define SHRINK if ((ctxt->progressive == 0) && \ |
|
1443 (ctxt->input->cur - ctxt->input->base > 2 * INPUT_CHUNK) && \ |
|
1444 (ctxt->input->end - ctxt->input->cur < 2 * INPUT_CHUNK)) \ |
|
1445 xmlSHRINK (ctxt); |
|
1446 |
|
1447 static void xmlSHRINK (xmlParserCtxtPtr ctxt) { |
|
1448 xmlParserInputShrink(ctxt->input); |
|
1449 if ((*ctxt->input->cur == 0) && |
|
1450 (xmlParserInputGrow(ctxt->input, INPUT_CHUNK) <= 0)) |
|
1451 xmlPopInput(ctxt); |
|
1452 } |
|
1453 |
|
1454 /** |
|
1455 OOM: possible --> OOM flag is set |
|
1456 */ |
|
1457 #define GROW if ((ctxt->progressive == 0) && \ |
|
1458 (ctxt->input->end - ctxt->input->cur < INPUT_CHUNK)) \ |
|
1459 xmlGROW (ctxt); |
|
1460 |
|
1461 /** |
|
1462 OOM: possible --> OOM flag is set |
|
1463 */ |
|
1464 static void xmlGROW (xmlParserCtxtPtr ctxt) { |
|
1465 xmlParserInputGrow(ctxt->input, INPUT_CHUNK); |
|
1466 if ((*ctxt->input->cur == 0) && |
|
1467 (xmlParserInputGrow(ctxt->input, INPUT_CHUNK) <= 0)) |
|
1468 { |
|
1469 xmlPopInput(ctxt); |
|
1470 } |
|
1471 } |
|
1472 |
|
1473 #define SKIP_BLANKS xmlSkipBlankChars(ctxt) |
|
1474 |
|
1475 /* |
|
1476 * OOM: possible --> check OOM flag |
|
1477 */ |
|
1478 #define NEXT xmlNextChar(ctxt) |
|
1479 |
|
1480 #define NEXT1 { \ |
|
1481 ctxt->input->col++; \ |
|
1482 ctxt->input->cur++; \ |
|
1483 ctxt->nbChars++; \ |
|
1484 if (*ctxt->input->cur == 0) \ |
|
1485 xmlParserInputGrow(ctxt->input, INPUT_CHUNK); \ |
|
1486 } |
|
1487 |
|
1488 // OOM: not reviewed yet |
|
1489 |
|
1490 |
|
1491 #define NEXTL(l) do { \ |
|
1492 if (*(ctxt->input->cur) == '\n') { \ |
|
1493 ctxt->input->line++; ctxt->input->col = 1; \ |
|
1494 }else{ \ |
|
1495 ctxt->input->col++; \ |
|
1496 } \ |
|
1497 ctxt->input->cur += l; \ |
|
1498 if (*ctxt->input->cur == '%') \ |
|
1499 xmlParserHandlePEReference(ctxt); \ |
|
1500 } while (0) |
|
1501 |
|
1502 // OOM: possible --> sets flag when returns 0 |
|
1503 #define CUR_CHAR(l) xmlCurrentChar(ctxt, &l) |
|
1504 #define CUR_SCHAR(s, l) xmlStringCurrentChar(ctxt, s, &l) |
|
1505 |
|
1506 #define COPY_BUF(l,b,i,v) \ |
|
1507 if (l == 1) b[i++] = (xmlChar) v; \ |
|
1508 else i += xmlCopyCharMultiByte(&b[i],v) |
|
1509 |
|
1510 /** |
|
1511 * xmlSkipBlankChars: |
|
1512 * @param ctxt the XML parser context |
|
1513 * |
|
1514 * skip all blanks character found at that point in the input streams. |
|
1515 * It pops up finished entities in the process if allowable at that point. |
|
1516 * |
|
1517 * Returns the number of space chars skipped |
|
1518 * |
|
1519 * OOM: possible --> |
|
1520 */ |
|
1521 XMLPUBFUNEXPORT int |
|
1522 xmlSkipBlankChars(xmlParserCtxtPtr ctxt) { |
|
1523 int res = 0; |
|
1524 /* |
|
1525 * It's Okay to use CUR/NEXT here since all the blanks are on |
|
1526 * the ASCII range. |
|
1527 */ |
|
1528 if ((ctxt->inputNr == 1) && (ctxt->instate != XML_PARSER_DTD)) { |
|
1529 const xmlChar *cur; |
|
1530 /* |
|
1531 * if we are in the document content, go really fast |
|
1532 */ |
|
1533 cur = ctxt->input->cur; |
|
1534 while (IS_BLANK_CH(*cur)) { |
|
1535 if (*cur == '\n') { |
|
1536 ctxt->input->line++; ctxt->input->col = 1; |
|
1537 } |
|
1538 cur++; |
|
1539 res++; |
|
1540 if (*cur == 0) { |
|
1541 ctxt->input->cur = cur; |
|
1542 xmlParserInputGrow(ctxt->input, INPUT_CHUNK); |
|
1543 cur = ctxt->input->cur; |
|
1544 } |
|
1545 } |
|
1546 ctxt->input->cur = cur; |
|
1547 } else { |
|
1548 int cur; |
|
1549 do { |
|
1550 cur = CUR; |
|
1551 while (IS_BLANK(cur)) { /* CHECKED tstblanks.xml */ |
|
1552 NEXT; |
|
1553 cur = CUR; |
|
1554 res++; |
|
1555 } |
|
1556 while ((cur == 0) && (ctxt->inputNr > 1) && |
|
1557 (ctxt->instate != XML_PARSER_COMMENT)) { |
|
1558 xmlPopInput(ctxt); |
|
1559 cur = CUR; |
|
1560 } |
|
1561 /* |
|
1562 * Need to handle support of entities branching here |
|
1563 */ |
|
1564 if (*ctxt->input->cur == '%') xmlParserHandlePEReference(ctxt); |
|
1565 } while (IS_BLANK(cur)); /* CHECKED tstblanks.xml */ |
|
1566 } |
|
1567 return(res); |
|
1568 } |
|
1569 |
|
1570 /************************************************************************ |
|
1571 * * |
|
1572 * Commodity functions to handle entities * |
|
1573 * * |
|
1574 ************************************************************************/ |
|
1575 |
|
1576 /** |
|
1577 * xmlPopInput: |
|
1578 * @param ctxt an XML parser context |
|
1579 * |
|
1580 * xmlPopInput: the current input pointed by ctxt->input came to an end |
|
1581 * pop it and return the next char. |
|
1582 * |
|
1583 * Returns the current xmlChar in the parser context |
|
1584 * |
|
1585 * OOM: possible --> check OOM flag!!! |
|
1586 */ |
|
1587 XMLPUBFUNEXPORT xmlChar |
|
1588 xmlPopInput(xmlParserCtxtPtr ctxt) { |
|
1589 |
|
1590 LOAD_GS_SAFE_CTXT(ctxt) |
|
1591 if (ctxt->inputNr == 1) |
|
1592 return(0); /* End of main Input */ |
|
1593 if (xmlParserDebugEntities) |
|
1594 xmlGenericError(xmlGenericErrorContext, EMBED_ERRTXT("Popping input %d\n"), ctxt->inputNr); |
|
1595 xmlFreeInputStream(inputPop(ctxt)); |
|
1596 if ((*ctxt->input->cur == 0) && |
|
1597 (xmlParserInputGrow(ctxt->input, INPUT_CHUNK) <= 0)) |
|
1598 { |
|
1599 if(OOM_FLAG) |
|
1600 return 0; |
|
1601 return(xmlPopInput(ctxt)); |
|
1602 } |
|
1603 return(CUR); |
|
1604 } |
|
1605 |
|
1606 /** |
|
1607 * xmlPushInput: |
|
1608 * @param ctxt an XML parser context |
|
1609 * @param input an XML parser input fragment (entity, XML fragment ...). |
|
1610 * |
|
1611 * xmlPushInput: switch to a new input stream which is stacked on top |
|
1612 * of the previous one(s). |
|
1613 */ |
|
1614 XMLPUBFUNEXPORT void |
|
1615 xmlPushInput(xmlParserCtxtPtr ctxt, xmlParserInputPtr input) { |
|
1616 LOAD_GS_SAFE_CTXT(ctxt) |
|
1617 if (input == NULL) return; |
|
1618 |
|
1619 if (xmlParserDebugEntities) { |
|
1620 if ((ctxt->input != NULL) && (ctxt->input->filename)) |
|
1621 xmlGenericError(xmlGenericErrorContext, |
|
1622 EMBED_ERRTXT("%s(%d): "), ctxt->input->filename, |
|
1623 ctxt->input->line); |
|
1624 xmlGenericError(xmlGenericErrorContext, |
|
1625 EMBED_ERRTXT("Pushing input %d : %.30s\n"), ctxt->inputNr+1, input->cur); |
|
1626 } |
|
1627 inputPush(ctxt, input); |
|
1628 GROW; |
|
1629 } |
|
1630 |
|
1631 /** |
|
1632 * xmlParseCharRef: |
|
1633 * @param ctxt an XML parser context |
|
1634 * |
|
1635 * parse Reference declarations |
|
1636 * |
|
1637 * [66] CharRef ::= '&#' [0-9]+ ';' | |
|
1638 * '&#x' [0-9a-fA-F]+ ';' |
|
1639 * |
|
1640 * [ WFC: Legal Character ] |
|
1641 * Characters referred to using character references must match the |
|
1642 * production for Char. |
|
1643 * |
|
1644 * Returns the value parsed (as an int), 0 in case of error |
|
1645 */ |
|
1646 XMLPUBFUNEXPORT int |
|
1647 xmlParseCharRef(xmlParserCtxtPtr ctxt) { |
|
1648 unsigned int val = 0; |
|
1649 int count = 0; |
|
1650 |
|
1651 /* |
|
1652 * Using RAW/CUR/NEXT is okay since we are working on ASCII range here |
|
1653 */ |
|
1654 if ((RAW == '&') && (NXT(1) == '#') && |
|
1655 (NXT(2) == 'x')) { |
|
1656 SKIP(3); |
|
1657 GROW; |
|
1658 while (RAW != ';') { /* loop blocked by count */ |
|
1659 if (count++ > 20) { |
|
1660 count = 0; |
|
1661 GROW; |
|
1662 } |
|
1663 if ((RAW >= '0') && (RAW <= '9')) |
|
1664 val = val * 16 + (CUR - '0'); |
|
1665 else if ((RAW >= 'a') && (RAW <= 'f') && (count < 20)) |
|
1666 val = val * 16 + (CUR - 'a') + 10; |
|
1667 else if ((RAW >= 'A') && (RAW <= 'F') && (count < 20)) |
|
1668 val = val * 16 + (CUR - 'A') + 10; |
|
1669 else { |
|
1670 xmlFatalErr(ctxt, XML_ERR_INVALID_HEX_CHARREF, NULL); |
|
1671 val = 0; |
|
1672 break; |
|
1673 } |
|
1674 NEXT; |
|
1675 count++; |
|
1676 } |
|
1677 if (RAW == ';') { |
|
1678 /* on purpose to avoid reentrancy problems with NEXT and SKIP */ |
|
1679 ctxt->input->col++; |
|
1680 ctxt->nbChars ++; |
|
1681 ctxt->input->cur++; |
|
1682 } |
|
1683 } else if ((RAW == '&') && (NXT(1) == '#')) { |
|
1684 SKIP(2); |
|
1685 GROW; |
|
1686 while (RAW != ';') { /* loop blocked by count */ |
|
1687 if (count++ > 20) { |
|
1688 count = 0; |
|
1689 GROW; |
|
1690 } |
|
1691 if ((RAW >= '0') && (RAW <= '9')) |
|
1692 val = val * 10 + (CUR - '0'); |
|
1693 else { |
|
1694 xmlFatalErr(ctxt, XML_ERR_INVALID_DEC_CHARREF, NULL); |
|
1695 val = 0; |
|
1696 break; |
|
1697 } |
|
1698 NEXT; |
|
1699 count++; |
|
1700 } |
|
1701 if (RAW == ';') { |
|
1702 /* on purpose to avoid reentrancy problems with NEXT and SKIP */ |
|
1703 ctxt->input->col++; |
|
1704 ctxt->nbChars ++; |
|
1705 ctxt->input->cur++; |
|
1706 } |
|
1707 } else { |
|
1708 xmlFatalErr(ctxt, XML_ERR_INVALID_CHARREF, NULL); |
|
1709 } |
|
1710 |
|
1711 /* |
|
1712 * [ WFC: Legal Character ] |
|
1713 * Characters referred to using character references must match the |
|
1714 * production for Char. |
|
1715 */ |
|
1716 if (IS_CHAR(val)) { |
|
1717 return(val); |
|
1718 } else { |
|
1719 xmlFatalErrMsgInt(ctxt, XML_ERR_INVALID_CHAR, |
|
1720 EMBED_ERRTXT("xmlParseCharRef: invalid xmlChar value %d\n"), |
|
1721 val); |
|
1722 } |
|
1723 return(0); |
|
1724 } |
|
1725 |
|
1726 /** |
|
1727 * xmlParseStringCharRef: |
|
1728 * @param ctxt an XML parser context |
|
1729 * @param str a pointer to an index in the string |
|
1730 * |
|
1731 * parse Reference declarations, variant parsing from a string rather |
|
1732 * than an an input flow. |
|
1733 * |
|
1734 * [66] CharRef ::= '&#' [0-9]+ ';' | |
|
1735 * '&#x' [0-9a-fA-F]+ ';' |
|
1736 * |
|
1737 * [ WFC: Legal Character ] |
|
1738 * Characters referred to using character references must match the |
|
1739 * production for Char. |
|
1740 * |
|
1741 * Returns the value parsed (as an int), 0 in case of error, str will be |
|
1742 * updated to the current value of the index |
|
1743 */ |
|
1744 static int |
|
1745 xmlParseStringCharRef(xmlParserCtxtPtr ctxt, const xmlChar **str) { |
|
1746 const xmlChar *ptr; |
|
1747 xmlChar cur; |
|
1748 int val = 0; |
|
1749 |
|
1750 if ((str == NULL) || (*str == NULL)) return(0); |
|
1751 ptr = *str; |
|
1752 cur = *ptr; |
|
1753 if ((cur == '&') && (ptr[1] == '#') && (ptr[2] == 'x')) { |
|
1754 ptr += 3; |
|
1755 cur = *ptr; |
|
1756 while (cur != ';') { /* Non input consuming loop */ |
|
1757 if ((cur >= '0') && (cur <= '9')) |
|
1758 val = val * 16 + (cur - '0'); |
|
1759 else if ((cur >= 'a') && (cur <= 'f')) |
|
1760 val = val * 16 + (cur - 'a') + 10; |
|
1761 else if ((cur >= 'A') && (cur <= 'F')) |
|
1762 val = val * 16 + (cur - 'A') + 10; |
|
1763 else { |
|
1764 xmlFatalErr(ctxt, XML_ERR_INVALID_HEX_CHARREF, NULL); |
|
1765 val = 0; |
|
1766 break; |
|
1767 } |
|
1768 ptr++; |
|
1769 cur = *ptr; |
|
1770 } |
|
1771 if (cur == ';') |
|
1772 ptr++; |
|
1773 } else if ((cur == '&') && (ptr[1] == '#')){ |
|
1774 ptr += 2; |
|
1775 cur = *ptr; |
|
1776 while (cur != ';') { /* Non input consuming loops */ |
|
1777 if ((cur >= '0') && (cur <= '9')) |
|
1778 val = val * 10 + (cur - '0'); |
|
1779 else { |
|
1780 xmlFatalErr(ctxt, XML_ERR_INVALID_DEC_CHARREF, NULL); |
|
1781 val = 0; |
|
1782 break; |
|
1783 } |
|
1784 ptr++; |
|
1785 cur = *ptr; |
|
1786 } |
|
1787 if (cur == ';') |
|
1788 ptr++; |
|
1789 } else { |
|
1790 xmlFatalErr(ctxt, XML_ERR_INVALID_CHARREF, NULL); |
|
1791 return(0); |
|
1792 } |
|
1793 *str = ptr; |
|
1794 |
|
1795 /* |
|
1796 * [ WFC: Legal Character ] |
|
1797 * Characters referred to using character references must match the |
|
1798 * production for Char. |
|
1799 */ |
|
1800 if (IS_CHAR(val)) { |
|
1801 return(val); |
|
1802 } else { |
|
1803 xmlFatalErrMsgInt(ctxt, XML_ERR_INVALID_CHAR, |
|
1804 EMBED_ERRTXT("xmlParseStringCharRef: invalid xmlChar value %d\n"), |
|
1805 val); |
|
1806 } |
|
1807 return(0); |
|
1808 } |
|
1809 |
|
1810 /** |
|
1811 * xmlNewBlanksWrapperInputStream: |
|
1812 * @param ctxt an XML parser context |
|
1813 * @param entity an Entity pointer |
|
1814 * |
|
1815 * Create a new input stream for wrapping |
|
1816 * blanks around a PEReference |
|
1817 * |
|
1818 * Returns the new input stream or NULL |
|
1819 */ |
|
1820 |
|
1821 static void deallocblankswrapper (xmlChar *str) {xmlFree(str);} |
|
1822 |
|
1823 static xmlParserInputPtr |
|
1824 xmlNewBlanksWrapperInputStream(xmlParserCtxtPtr ctxt, xmlEntityPtr entity) { |
|
1825 xmlParserInputPtr input; |
|
1826 xmlChar *buffer; |
|
1827 size_t length; |
|
1828 LOAD_GS_SAFE_CTXT(ctxt) |
|
1829 if (entity == NULL) { |
|
1830 xmlFatalErr(ctxt, XML_ERR_INTERNAL_ERROR, |
|
1831 EMBED_ERRTXT("xmlNewBlanksWrapperInputStream entity\n")); |
|
1832 return(NULL); |
|
1833 } |
|
1834 if (xmlParserDebugEntities) |
|
1835 xmlGenericError(xmlGenericErrorContext, |
|
1836 EMBED_ERRTXT("new blanks wrapper for entity: %s\n"), entity->name); |
|
1837 input = xmlNewInputStream(ctxt); |
|
1838 if (input == NULL) { |
|
1839 return(NULL); |
|
1840 } |
|
1841 length = xmlStrlen(entity->name) + 5; |
|
1842 buffer = (xmlChar*)xmlMallocAtomic(length); |
|
1843 if (buffer == NULL) { |
|
1844 xmlParserOOMErr(ctxt); |
|
1845 return(NULL); |
|
1846 } |
|
1847 buffer [0] = ' '; |
|
1848 buffer [1] = '%'; |
|
1849 buffer [length-3] = ';'; |
|
1850 buffer [length-2] = ' '; |
|
1851 buffer [length-1] = 0; |
|
1852 memcpy(buffer + 2, entity->name, length - 5); |
|
1853 input->free = deallocblankswrapper; |
|
1854 input->base = buffer; |
|
1855 input->cur = buffer; |
|
1856 input->length = length; |
|
1857 input->end = &buffer[length]; |
|
1858 return(input); |
|
1859 } |
|
1860 |
|
1861 /** |
|
1862 * xmlParserHandlePEReference: |
|
1863 * @param ctxt the parser context |
|
1864 * |
|
1865 * [69] PEReference ::= '%' Name ';' |
|
1866 * |
|
1867 * [ WFC: No Recursion ] |
|
1868 * A parsed entity must not contain a recursive |
|
1869 * reference to itself, either directly or indirectly. |
|
1870 * |
|
1871 * [ WFC: Entity Declared ] |
|
1872 * In a document without any DTD, a document with only an internal DTD |
|
1873 * subset which contains no parameter entity references, or a document |
|
1874 * with "standalone='yes'", ... ... The declaration of a parameter |
|
1875 * entity must precede any reference to it... |
|
1876 * |
|
1877 * [ VC: Entity Declared ] |
|
1878 * In a document with an external subset or external parameter entities |
|
1879 * with "standalone='no'", ... ... The declaration of a parameter entity |
|
1880 * must precede any reference to it... |
|
1881 * |
|
1882 * [ WFC: In DTD ] |
|
1883 * Parameter-entity references may only appear in the DTD. |
|
1884 * NOTE: misleading but this is handled. |
|
1885 * |
|
1886 * A PEReference may have been detected in the current input stream |
|
1887 * the handling is done accordingly to |
|
1888 * http://www.w3.org/TR/REC-xml#entproc |
|
1889 * i.e. |
|
1890 * - Included in literal in entity values |
|
1891 * - Included as Parameter Entity reference within DTDs |
|
1892 * |
|
1893 * OOM: possible ------ review NOT FINISHED YET |
|
1894 */ |
|
1895 XMLPUBFUNEXPORT void |
|
1896 xmlParserHandlePEReference(xmlParserCtxtPtr ctxt) { |
|
1897 const xmlChar *name; |
|
1898 xmlEntityPtr entity = NULL; |
|
1899 xmlParserInputPtr input; |
|
1900 LOAD_GS_SAFE_CTXT(ctxt) |
|
1901 |
|
1902 if (RAW != '%') return; |
|
1903 |
|
1904 |
|
1905 switch(ctxt->instate) { |
|
1906 case XML_PARSER_CDATA_SECTION: |
|
1907 return; |
|
1908 case XML_PARSER_COMMENT: |
|
1909 return; |
|
1910 case XML_PARSER_START_TAG: |
|
1911 return; |
|
1912 case XML_PARSER_END_TAG: |
|
1913 return; |
|
1914 case XML_PARSER_EOF: |
|
1915 xmlFatalErr(ctxt, XML_ERR_PEREF_AT_EOF, NULL); |
|
1916 return; |
|
1917 case XML_PARSER_PROLOG: |
|
1918 case XML_PARSER_START: |
|
1919 case XML_PARSER_MISC: |
|
1920 xmlFatalErr(ctxt, XML_ERR_PEREF_IN_PROLOG, NULL); |
|
1921 return; |
|
1922 case XML_PARSER_ENTITY_DECL: |
|
1923 case XML_PARSER_CONTENT: |
|
1924 case XML_PARSER_ATTRIBUTE_VALUE: |
|
1925 case XML_PARSER_PI: |
|
1926 case XML_PARSER_SYSTEM_LITERAL: |
|
1927 case XML_PARSER_PUBLIC_LITERAL: |
|
1928 /* we just ignore it there */ |
|
1929 return; |
|
1930 case XML_PARSER_EPILOG: |
|
1931 xmlFatalErr(ctxt, XML_ERR_PEREF_IN_EPILOG, NULL); |
|
1932 return; |
|
1933 case XML_PARSER_ENTITY_VALUE: |
|
1934 /* |
|
1935 * NOTE: in the case of entity values, we don't do the |
|
1936 * substitution here since we need the literal |
|
1937 * entity value to be able to save the internal |
|
1938 * subset of the document. |
|
1939 * This will be handled by xmlStringDecodeEntities |
|
1940 */ |
|
1941 return; |
|
1942 case XML_PARSER_DTD: |
|
1943 /* |
|
1944 * [WFC: Well-Formedness Constraint: PEs in Internal Subset] |
|
1945 * In the internal DTD subset, parameter-entity references |
|
1946 * can occur only where markup declarations can occur, not |
|
1947 * within markup declarations. |
|
1948 * In that case this is handled in xmlParseMarkupDecl |
|
1949 */ |
|
1950 if ((ctxt->external == 0) && (ctxt->inputNr == 1)) |
|
1951 return; |
|
1952 if (IS_BLANK_CH(NXT(1)) || NXT(1) == 0) |
|
1953 return; |
|
1954 break; |
|
1955 case XML_PARSER_IGNORE: |
|
1956 return; |
|
1957 } |
|
1958 |
|
1959 NEXT; |
|
1960 name = xmlParseName(ctxt); // may set OOM flag |
|
1961 if(OOM_FLAG) |
|
1962 return; |
|
1963 |
|
1964 if (xmlParserDebugEntities) |
|
1965 xmlGenericError(xmlGenericErrorContext, EMBED_ERRTXT("PEReference: %s\n"), name); |
|
1966 if (name == NULL) { |
|
1967 xmlFatalErr(ctxt, XML_ERR_PEREF_NO_NAME, NULL); |
|
1968 return; |
|
1969 } |
|
1970 // XMLENGINE: OK: IF condition branches were exchanged and ELSE bacame main flow |
|
1971 if (RAW != ';') |
|
1972 { |
|
1973 xmlFatalErr(ctxt, XML_ERR_PEREF_SEMICOL_MISSING, NULL); |
|
1974 return; |
|
1975 } |
|
1976 |
|
1977 NEXT; |
|
1978 if(OOM_FLAG) |
|
1979 return; |
|
1980 |
|
1981 if ((ctxt->sax != NULL) && (ctxt->sax->getParameterEntity != NULL)) |
|
1982 entity = ctxt->sax->getParameterEntity(ctxt->userData, name); |
|
1983 if (entity == NULL) |
|
1984 { |
|
1985 /* |
|
1986 * [ WFC: Entity Declared ] |
|
1987 * In a document without any DTD, a document with only an |
|
1988 * internal DTD subset which contains no parameter entity |
|
1989 * references, or a document with "standalone='yes'", ... |
|
1990 * ... The declaration of a parameter entity must precede |
|
1991 * any reference to it... |
|
1992 */ |
|
1993 if ((ctxt->standalone == 1) || |
|
1994 ((ctxt->hasExternalSubset == 0) && |
|
1995 (ctxt->hasPErefs == 0))) |
|
1996 { |
|
1997 xmlFatalErrMsgStr(ctxt, XML_ERR_UNDECLARED_ENTITY, |
|
1998 EMBED_ERRTXT("PEReference: %%%s; not found\n"), name); |
|
1999 } else { |
|
2000 /* |
|
2001 * [ VC: Entity Declared ] |
|
2002 * In a document with an external subset or external |
|
2003 * parameter entities with "standalone='no'", ... |
|
2004 * ... The declaration of a parameter entity must precede |
|
2005 * any reference to it... |
|
2006 */ |
|
2007 if ((ctxt->validate) && (ctxt->vctxt.error != NULL)) { |
|
2008 xmlValidityError(ctxt, XML_WAR_UNDECLARED_ENTITY, |
|
2009 EMBED_ERRTXT("PEReference: %%%s; not found\n"), name); |
|
2010 }else{ |
|
2011 xmlWarningMsg(ctxt, XML_WAR_UNDECLARED_ENTITY, |
|
2012 EMBED_ERRTXT("PEReference: %%%s; not found\n"), name, NULL); |
|
2013 } |
|
2014 ctxt->valid = 0; |
|
2015 } |
|
2016 } // if (entity == NULL) |
|
2017 else if (ctxt->input->free != deallocblankswrapper) |
|
2018 { |
|
2019 input = xmlNewBlanksWrapperInputStream(ctxt, entity); |
|
2020 xmlPushInput(ctxt, input); |
|
2021 } |
|
2022 else if ((entity->etype == XML_INTERNAL_PARAMETER_ENTITY) || |
|
2023 (entity->etype == XML_EXTERNAL_PARAMETER_ENTITY)) |
|
2024 { |
|
2025 xmlChar start[4]; |
|
2026 xmlCharEncoding enc; |
|
2027 |
|
2028 /* |
|
2029 * handle the extra spaces added before and after |
|
2030 * c.f. http://www.w3.org/TR/REC-xml#as-PE |
|
2031 * this is done independently. |
|
2032 */ |
|
2033 input = xmlNewEntityInputStream(ctxt, entity); |
|
2034 xmlPushInput(ctxt, input); |
|
2035 |
|
2036 /* |
|
2037 * Get the 4 first bytes and decode the charset |
|
2038 * if enc != XML_CHAR_ENCODING_NONE |
|
2039 * plug some encoding conversion routines. |
|
2040 * Note that, since we may have some non-UTF8 |
|
2041 * encoding (like UTF16, ), the 'length' |
|
2042 * is not known, but we can calculate based upon |
|
2043 * the amount of data in the buffer. |
|
2044 */ |
|
2045 GROW |
|
2046 if ((ctxt->input->end - ctxt->input->cur)>=4) { |
|
2047 start[0] = RAW; |
|
2048 start[1] = NXT(1); |
|
2049 start[2] = NXT(2); |
|
2050 start[3] = NXT(3); |
|
2051 enc = xmlDetectCharEncoding(start, 4); |
|
2052 if (enc != XML_CHAR_ENCODING_NONE) { |
|
2053 xmlSwitchEncoding(ctxt, enc); |
|
2054 } |
|
2055 } |
|
2056 |
|
2057 if ((entity->etype == XML_EXTERNAL_PARAMETER_ENTITY) && |
|
2058 (CMP5(CUR_PTR, '<', '?', 'x', 'm', 'l' )) && |
|
2059 (IS_BLANK_CH(NXT(5)))) |
|
2060 { |
|
2061 xmlParseTextDecl(ctxt); |
|
2062 } |
|
2063 } else { |
|
2064 xmlFatalErrMsgStr(ctxt, XML_ERR_ENTITY_IS_PARAMETER, |
|
2065 EMBED_ERRTXT("PEReference: %s is not a parameter entity\n"), |
|
2066 name); |
|
2067 } |
|
2068 } |
|
2069 |
|
2070 /* |
|
2071 * Macro used to grow the current buffer. |
|
2072 */ |
|
2073 |
|
2074 |
|
2075 /** |
|
2076 * SYMBIAN : DEFECT FIX : DEF129002 (libxml2 buffer overflow vulnerability) |
|
2077 * Increase the buffer size by sufficient amount before doubling it. |
|
2078 * So that, this will help in dealing with the long-entity names. |
|
2079 * The original defect can be located in debian bug tracking database |
|
2080 * with defect number 498768. |
|
2081 */ |
|
2082 |
|
2083 #define GROW_BUFFER(buffer) { \ |
|
2084 xmlChar *tmp; \ |
|
2085 buffer##_size += XML_PARSER_BUFFER_SIZE ; \ |
|
2086 buffer##_size *= 2; \ |
|
2087 tmp = (xmlChar *) \ |
|
2088 xmlRealloc(buffer, buffer##_size * sizeof(xmlChar)); \ |
|
2089 if (tmp == NULL) goto mem_error; \ |
|
2090 buffer = tmp; \ |
|
2091 } |
|
2092 |
|
2093 |
|
2094 /** |
|
2095 * xmlStringLenDecodeEntities: |
|
2096 * @param ctxt the parser context |
|
2097 * @param str the input string |
|
2098 * @param len the string length |
|
2099 * @param what combination of XML_SUBSTITUTE_REF and XML_SUBSTITUTE_PEREF |
|
2100 * @param end an end marker xmlChar, 0 if none |
|
2101 * @param end2 an end marker xmlChar, 0 if none |
|
2102 * @param end3 an end marker xmlChar, 0 if none |
|
2103 * |
|
2104 * Takes a entity string content and process to do the adequate substitutions. |
|
2105 * |
|
2106 * [67] Reference ::= EntityRef | CharRef |
|
2107 * |
|
2108 * [69] PEReference ::= '%' Name ';' |
|
2109 * |
|
2110 * Returns A newly allocated string with the substitution done. The caller |
|
2111 * must deallocate it ! |
|
2112 */ |
|
2113 XMLPUBFUNEXPORT xmlChar * |
|
2114 xmlStringLenDecodeEntities(xmlParserCtxtPtr ctxt, const xmlChar *str, int len, |
|
2115 int what, xmlChar end, xmlChar end2, xmlChar end3) { |
|
2116 xmlChar *buffer = NULL; |
|
2117 int buffer_size = 0; |
|
2118 |
|
2119 xmlChar *current = NULL; |
|
2120 const xmlChar *last; |
|
2121 xmlEntityPtr ent; |
|
2122 int c,l; |
|
2123 int nbchars = 0; |
|
2124 LOAD_GS_SAFE_CTXT(ctxt) |
|
2125 |
|
2126 if ((str == NULL) || (len < 0)) |
|
2127 return(NULL); |
|
2128 last = str + len; |
|
2129 |
|
2130 if (ctxt->depth > 40) { |
|
2131 xmlFatalErr(ctxt, XML_ERR_ENTITY_LOOP, NULL); |
|
2132 return(NULL); |
|
2133 } |
|
2134 |
|
2135 /* |
|
2136 * allocate a translation buffer. |
|
2137 */ |
|
2138 buffer_size = XML_PARSER_BIG_BUFFER_SIZE; |
|
2139 buffer = (xmlChar *) xmlMallocAtomic(buffer_size * sizeof(xmlChar)); |
|
2140 if (buffer == NULL) goto mem_error; |
|
2141 |
|
2142 /* |
|
2143 * OK loop until we reach one of the ending char or a size limit. |
|
2144 * we are operating on already parsed values. |
|
2145 */ |
|
2146 if (str < last) |
|
2147 c = CUR_SCHAR(str, l); |
|
2148 else |
|
2149 c = 0; |
|
2150 while ((c != 0) && (c != end) && /* non input consuming loop */ |
|
2151 (c != end2) && (c != end3)) { |
|
2152 |
|
2153 if (c == 0) break; |
|
2154 if ((c == '&') && (str[1] == '#')) { |
|
2155 int val = xmlParseStringCharRef(ctxt, &str); |
|
2156 if (val != 0) { |
|
2157 COPY_BUF(0,buffer,nbchars,val); |
|
2158 } |
|
2159 } else if ((c == '&') && (what & XML_SUBSTITUTE_REF)) { |
|
2160 if (xmlParserDebugEntities) |
|
2161 xmlGenericError(xmlGenericErrorContext, |
|
2162 EMBED_ERRTXT("String decoding Entity Reference: %.30s\n"), |
|
2163 str); |
|
2164 ent = xmlParseStringEntityRef(ctxt, &str); |
|
2165 if ((ent != NULL) && |
|
2166 (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) { |
|
2167 if (ent->content != NULL) { |
|
2168 COPY_BUF(0,buffer,nbchars,ent->content[0]); |
|
2169 } else { |
|
2170 xmlFatalErrMsg(ctxt, XML_ERR_INTERNAL_ERROR, |
|
2171 EMBED_ERRTXT("predefined entity has no content\n")); |
|
2172 } |
|
2173 } else if ((ent != NULL) && (ent->content != NULL)) { |
|
2174 xmlChar *rep; |
|
2175 |
|
2176 ctxt->depth++; |
|
2177 rep = xmlStringDecodeEntities(ctxt, ent->content, what, |
|
2178 0, 0, 0); |
|
2179 ctxt->depth--; |
|
2180 if (rep != NULL) { |
|
2181 current = rep; |
|
2182 while (*current != 0) { /* non input consuming loop */ |
|
2183 buffer[nbchars++] = *current++; |
|
2184 if (nbchars > |
|
2185 buffer_size - XML_PARSER_BUFFER_SIZE) { |
|
2186 GROW_BUFFER(buffer); |
|
2187 } |
|
2188 } |
|
2189 xmlFree(rep); |
|
2190 } |
|
2191 } else if (ent != NULL) { |
|
2192 int i = xmlStrlen(ent->name); |
|
2193 const xmlChar *cur = ent->name; |
|
2194 |
|
2195 buffer[nbchars++] = '&'; |
|
2196 if (nbchars > buffer_size - i - XML_PARSER_BUFFER_SIZE) { |
|
2197 GROW_BUFFER(buffer); |
|
2198 } |
|
2199 for (;i > 0;i--) |
|
2200 buffer[nbchars++] = *cur++; |
|
2201 buffer[nbchars++] = ';'; |
|
2202 } |
|
2203 } else if (c == '%' && (what & XML_SUBSTITUTE_PEREF)) { |
|
2204 if (xmlParserDebugEntities) |
|
2205 xmlGenericError(xmlGenericErrorContext, |
|
2206 EMBED_ERRTXT("String decoding PE Reference: %.30s\n"), str); |
|
2207 ent = xmlParseStringPEReference(ctxt, &str); |
|
2208 if (ent != NULL) { |
|
2209 xmlChar *rep; |
|
2210 |
|
2211 ctxt->depth++; |
|
2212 rep = xmlStringDecodeEntities(ctxt, ent->content, what, |
|
2213 0, 0, 0); |
|
2214 ctxt->depth--; |
|
2215 if (rep != NULL) { |
|
2216 current = rep; |
|
2217 while (*current != 0) { /* non input consuming loop */ |
|
2218 buffer[nbchars++] = *current++; |
|
2219 if (nbchars > |
|
2220 buffer_size - XML_PARSER_BUFFER_SIZE) { |
|
2221 GROW_BUFFER(buffer); |
|
2222 } |
|
2223 } |
|
2224 xmlFree(rep); |
|
2225 } |
|
2226 } |
|
2227 } else { |
|
2228 COPY_BUF(l,buffer,nbchars,c); |
|
2229 str += l; |
|
2230 if (nbchars > buffer_size - XML_PARSER_BUFFER_SIZE) { |
|
2231 GROW_BUFFER(buffer); |
|
2232 } |
|
2233 } |
|
2234 if (str < last) |
|
2235 c = CUR_SCHAR(str, l); |
|
2236 else |
|
2237 c = 0; |
|
2238 } |
|
2239 buffer[nbchars++] = 0; |
|
2240 return(buffer); |
|
2241 |
|
2242 mem_error: |
|
2243 xmlParserOOMErr(ctxt); |
|
2244 return(NULL); |
|
2245 } |
|
2246 |
|
2247 /** |
|
2248 * xmlStringDecodeEntities: |
|
2249 * @param ctxt the parser context |
|
2250 * @param str the input string |
|
2251 * @param what combination of XML_SUBSTITUTE_REF and XML_SUBSTITUTE_PEREF |
|
2252 * @param end an end marker xmlChar, 0 if none |
|
2253 * @param end2 an end marker xmlChar, 0 if none |
|
2254 * @param end3 an end marker xmlChar, 0 if none |
|
2255 * |
|
2256 * Takes a entity string content and process to do the adequate substitutions. |
|
2257 * |
|
2258 * [67] Reference ::= EntityRef | CharRef |
|
2259 * |
|
2260 * [69] PEReference ::= '%' Name ';' |
|
2261 * |
|
2262 * Returns A newly allocated string with the substitution done. The caller |
|
2263 * must deallocate it ! |
|
2264 */ |
|
2265 XMLPUBFUNEXPORT xmlChar * |
|
2266 xmlStringDecodeEntities(xmlParserCtxtPtr ctxt, const xmlChar *str, int what, |
|
2267 xmlChar end, xmlChar end2, xmlChar end3) { |
|
2268 return(xmlStringLenDecodeEntities(ctxt, str, xmlStrlen(str), what, |
|
2269 end, end2, end3)); |
|
2270 } |
|
2271 |
|
2272 /************************************************************************ |
|
2273 * * |
|
2274 * Commodity functions, cleanup needed ? * |
|
2275 * * |
|
2276 ************************************************************************/ |
|
2277 |
|
2278 /** |
|
2279 * areBlanks: |
|
2280 * @param ctxt an XML parser context |
|
2281 * @param str a xmlChar * |
|
2282 * @param len the size of str |
|
2283 * @param blank_chars we know the chars are blanks |
|
2284 * |
|
2285 * Is this a sequence of blank chars that one can ignore ? |
|
2286 * |
|
2287 * Returns 1 if ignorable 0 otherwise. |
|
2288 */ |
|
2289 |
|
2290 static int areBlanks(xmlParserCtxtPtr ctxt, const xmlChar *str, int len, |
|
2291 int blank_chars) { |
|
2292 int i, ret; |
|
2293 xmlNodePtr lastChild; |
|
2294 |
|
2295 /* |
|
2296 * Don't spend time trying to differentiate them, the same callback is |
|
2297 * used ! |
|
2298 */ |
|
2299 if (ctxt->sax->ignorableWhitespace == ctxt->sax->characters) |
|
2300 return(0); |
|
2301 |
|
2302 /* |
|
2303 * Check for xml:space value. |
|
2304 */ |
|
2305 if (*(ctxt->space) == 1) |
|
2306 return(0); |
|
2307 |
|
2308 /* |
|
2309 * Check that the string is made of blanks |
|
2310 */ |
|
2311 if (blank_chars == 0) { |
|
2312 for (i = 0;i < len;i++) |
|
2313 if (!(IS_BLANK_CH(str[i]))) |
|
2314 return(0); |
|
2315 } |
|
2316 |
|
2317 /* |
|
2318 * Look if the element is mixed content in the DTD if available |
|
2319 */ |
|
2320 if (!ctxt->node) |
|
2321 return(0); |
|
2322 if (ctxt->myDoc) { |
|
2323 ret = xmlIsMixedElement(ctxt->myDoc, ctxt->node->name); |
|
2324 |
|
2325 if (ret == 0) return(1); // replace with |
|
2326 if (ret == 1) return(0); // return 1-ret; OR return !(ret&1) |
|
2327 } |
|
2328 |
|
2329 /* |
|
2330 * Otherwise, heuristic :-\ |
|
2331 */ |
|
2332 if (RAW != '<') |
|
2333 return(0); |
|
2334 if ((ctxt->node->children == NULL) && |
|
2335 (RAW == '<') && (NXT(1) == '/')) |
|
2336 return(0); |
|
2337 |
|
2338 |
|
2339 lastChild = xmlGetLastChild(ctxt->node); |
|
2340 if (lastChild == NULL) { |
|
2341 if ((ctxt->node->type != XML_ELEMENT_NODE) && |
|
2342 (ctxt->node->content != NULL)) return(0); |
|
2343 } else { |
|
2344 if (xmlNodeIsText(lastChild)) |
|
2345 return(0); |
|
2346 else |
|
2347 if ((ctxt->node->children != NULL) && |
|
2348 (xmlNodeIsText(ctxt->node->children))) |
|
2349 return(0); |
|
2350 } |
|
2351 return(1); |
|
2352 } |
|
2353 |
|
2354 /************************************************************************ |
|
2355 * * |
|
2356 * Extra stuff for namespace support * |
|
2357 * Relates to http://www.w3.org/TR/WD-xml-names * |
|
2358 * * |
|
2359 ************************************************************************/ |
|
2360 |
|
2361 /** |
|
2362 * xmlSplitQName: |
|
2363 * @param ctxt an XML parser context |
|
2364 * @param name an XML parser context |
|
2365 * @param prefix a xmlChar ** |
|
2366 * |
|
2367 * parse an UTF8 encoded XML qualified name string |
|
2368 * |
|
2369 * [NS 5] QName ::= (Prefix ':')? LocalPart |
|
2370 * |
|
2371 * [NS 6] Prefix ::= NCName |
|
2372 * |
|
2373 * [NS 7] LocalPart ::= NCName |
|
2374 * |
|
2375 * Returns the local part, and prefix is updated |
|
2376 * to get the Prefix if any. |
|
2377 * |
|
2378 * OOM: possible --> returns NULL (*prefix is NULL too); |
|
2379 * always check OOM flag to distinguish OOM and "bad QName" |
|
2380 */ |
|
2381 // DONE: Make sure that in OOM (prefix is set to NULL and freed if needed) |
|
2382 XMLPUBFUNEXPORT xmlChar* |
|
2383 xmlSplitQName(xmlParserCtxtPtr ctxt, const xmlChar* name, xmlChar** prefix) |
|
2384 { |
|
2385 xmlChar buf[XML_MAX_NAMELEN + 5]; |
|
2386 xmlChar* buffer = NULL; // We use it instead of 'buf' for too long names |
|
2387 int len = 0; |
|
2388 int max = XML_MAX_NAMELEN; |
|
2389 xmlChar* ret = NULL; |
|
2390 const xmlChar* cur = name; |
|
2391 int c; |
|
2392 |
|
2393 *prefix = NULL; |
|
2394 |
|
2395 if (cur == NULL) |
|
2396 return(NULL); |
|
2397 |
|
2398 #ifndef XML_XML_NAMESPACE |
|
2399 /* xml: prefix is not really a namespace */ |
|
2400 if ((cur[0] == 'x') && (cur[1] == 'm') && |
|
2401 (cur[2] == 'l') && (cur[3] == ':')) |
|
2402 { |
|
2403 return(xmlStrdup(name)); |
|
2404 } |
|
2405 #endif |
|
2406 |
|
2407 /* nasty but well=formed */ |
|
2408 if (cur[0] == ':') |
|
2409 return(xmlStrdup(name)); |
|
2410 |
|
2411 c = *cur++; |
|
2412 while ((c != 0) && (c != ':') && (len < max)) { /* tested bigname.xml */ |
|
2413 buf[len++] = c; |
|
2414 c = *cur++; |
|
2415 } |
|
2416 if (len >= max) |
|
2417 { |
|
2418 /* |
|
2419 * Okay someone managed to make a huge name, so he's ready to pay |
|
2420 * for the processing speed. |
|
2421 */ |
|
2422 max = len * 2; |
|
2423 |
|
2424 buffer = (xmlChar*) xmlMallocAtomic(max * sizeof(xmlChar)); |
|
2425 if (!buffer) |
|
2426 goto OOM_exit; |
|
2427 |
|
2428 // NOTE: Now 'buffer' must be returned or freed (in OOM).. |
|
2429 memcpy(buffer, buf, len); |
|
2430 while ((c != 0) && (c != ':')) |
|
2431 { /* tested bigname.xml */ |
|
2432 if (len + 10 > max) |
|
2433 { |
|
2434 void* tmp; // DONE: Fix xmlRealloc |
|
2435 max *= 2; |
|
2436 tmp = xmlRealloc(buffer, max * sizeof(xmlChar)); |
|
2437 if (!tmp) { |
|
2438 OOM_free_buffer: |
|
2439 if(buffer) // Note: must check if jump here from other parts of function |
|
2440 xmlFree(buffer); |
|
2441 OOM_exit: |
|
2442 xmlParserOOMErr(ctxt); |
|
2443 return(NULL); |
|
2444 } |
|
2445 buffer = (xmlChar*) tmp; |
|
2446 } |
|
2447 buffer[len++] = c; |
|
2448 c = *cur++; |
|
2449 } |
|
2450 buffer[len] = 0; |
|
2451 } |
|
2452 |
|
2453 /* nasty but well=formed |
|
2454 if ((c == ':') && (*cur == 0)) { |
|
2455 return(xmlStrdup(name)); |
|
2456 } */ |
|
2457 |
|
2458 if (buffer == NULL) |
|
2459 ret = xmlStrndup(buf, len); |
|
2460 else { |
|
2461 ret = buffer; // NOTE: 'buffer' is to be returned so far |
|
2462 buffer = NULL; |
|
2463 max = XML_MAX_NAMELEN; |
|
2464 } |
|
2465 |
|
2466 |
|
2467 if (c == ':') |
|
2468 { |
|
2469 c = *cur; |
|
2470 *prefix = ret; // NOTE: in 'prefix' we return 'buffer' or a copy from 'buf' |
|
2471 if (c == 0) { |
|
2472 return(xmlStrndup(BAD_CAST "", 0)); |
|
2473 } |
|
2474 len = 0; |
|
2475 |
|
2476 /* |
|
2477 * Check that the first character is proper to start |
|
2478 * a new name |
|
2479 */ |
|
2480 if (!(((c >= 0x61) && (c <= 0x7A)) || |
|
2481 ((c >= 0x41) && (c <= 0x5A)) || |
|
2482 (c == '_') || (c == ':'))) |
|
2483 { |
|
2484 int l; |
|
2485 int first = CUR_SCHAR(cur, l); |
|
2486 |
|
2487 if (!IS_LETTER(first) && (first != '_')) { |
|
2488 xmlFatalErrMsgStr(ctxt, XML_NS_ERR_QNAME, |
|
2489 EMBED_ERRTXT("Name %s is not XML Namespace compliant\n"), |
|
2490 name); |
|
2491 } |
|
2492 } |
|
2493 cur++; |
|
2494 |
|
2495 while ((c != 0) && (len < max)) |
|
2496 { /* tested bigname2.xml */ |
|
2497 buf[len++] = c; |
|
2498 c = *cur++; |
|
2499 } |
|
2500 if (len >= max) { |
|
2501 /* |
|
2502 * Okay someone managed to make a huge name, so he's ready to pay |
|
2503 * for the processing speed. |
|
2504 */ |
|
2505 max = len * 2; |
|
2506 |
|
2507 buffer = (xmlChar*) xmlMallocAtomic(max * sizeof(xmlChar)); |
|
2508 if (!buffer) |
|
2509 goto OOM_free_prefix_buffer; // NOTE: it's ok to free NULL buffer here |
|
2510 |
|
2511 memcpy(buffer, buf, len); |
|
2512 while (c != 0) |
|
2513 { /* tested bigname2.xml */ |
|
2514 if (len + 10 > max) |
|
2515 { |
|
2516 void* tmp; // DONE: Fix xmlRealloc |
|
2517 max *= 2; |
|
2518 tmp = xmlRealloc(buffer, max * sizeof(xmlChar)); |
|
2519 if (!tmp) { |
|
2520 OOM_free_prefix_buffer: |
|
2521 xmlFree(*prefix); |
|
2522 *prefix = NULL; |
|
2523 goto OOM_free_buffer; |
|
2524 } |
|
2525 buffer = (xmlChar*) tmp; |
|
2526 } |
|
2527 buffer[len++] = c; |
|
2528 c = *cur++; |
|
2529 } |
|
2530 buffer[len] = 0; |
|
2531 } |
|
2532 |
|
2533 if (!buffer){ |
|
2534 ret = xmlStrndup(buf, len); // DONE: Check OOM, free prefix if needed |
|
2535 if(!ret) |
|
2536 goto OOM_free_prefix_buffer; |
|
2537 } else { |
|
2538 ret = buffer; |
|
2539 } |
|
2540 } // end if (c == ':') |
|
2541 |
|
2542 return(ret); |
|
2543 } |
|
2544 |
|
2545 /************************************************************************ |
|
2546 * * |
|
2547 * The parser itself * |
|
2548 * Relates to http://www.w3.org/TR/REC-xml * |
|
2549 * * |
|
2550 ************************************************************************/ |
|
2551 |
|
2552 static const xmlChar * xmlParseNameComplex(xmlParserCtxtPtr ctxt); |
|
2553 static xmlChar * xmlParseAttValueInternal(xmlParserCtxtPtr ctxt, |
|
2554 int *len, int *alloc, int normalize); |
|
2555 |
|
2556 /** |
|
2557 * xmlParseName: |
|
2558 * @param ctxt an XML parser context |
|
2559 * |
|
2560 * parse an XML name. |
|
2561 * |
|
2562 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' | |
|
2563 * CombiningChar | Extender |
|
2564 * |
|
2565 * [5] Name ::= (Letter | '_' | ':') (NameChar)* |
|
2566 * |
|
2567 * [6] Names ::= Name (S Name)* |
|
2568 * |
|
2569 * Returns the Name parsed or NULL |
|
2570 * |
|
2571 * OOM: possible --- Review is not finished (for xmlParseNameComplex) |
|
2572 *--> OOM flag is set when NULL is returned |
|
2573 */ |
|
2574 |
|
2575 XMLPUBFUNEXPORT const xmlChar* |
|
2576 xmlParseName(xmlParserCtxtPtr ctxt) { |
|
2577 const xmlChar *in; |
|
2578 const xmlChar *ret; |
|
2579 int count = 0; |
|
2580 LOAD_GS_SAFE_CTXT(ctxt) |
|
2581 |
|
2582 GROW; |
|
2583 if(OOM_FLAG) |
|
2584 return NULL; |
|
2585 /* |
|
2586 * Accelerator for simple ASCII names |
|
2587 */ |
|
2588 in = ctxt->input->cur; |
|
2589 if (((*in >= 0x61) && (*in <= 0x7A)) || |
|
2590 ((*in >= 0x41) && (*in <= 0x5A)) || |
|
2591 (*in == '_') || (*in == ':')) |
|
2592 { |
|
2593 in++; |
|
2594 while (((*in >= 0x61) && (*in <= 0x7A)) || |
|
2595 ((*in >= 0x41) && (*in <= 0x5A)) || |
|
2596 ((*in >= 0x30) && (*in <= 0x39)) || |
|
2597 (*in == '_') || (*in == '-') || |
|
2598 (*in == ':') || (*in == '.')) |
|
2599 in++; |
|
2600 |
|
2601 if ((*in > 0) && (*in < 0x80)) { |
|
2602 count = in - ctxt->input->cur; |
|
2603 ret = xmlDictLookup(ctxt->dict, ctxt->input->cur, count); |
|
2604 if(OOM_FLAG) |
|
2605 return NULL; |
|
2606 ctxt->input->cur = in; |
|
2607 ctxt->nbChars += count; |
|
2608 ctxt->input->col += count; |
|
2609 if (ret == NULL) |
|
2610 xmlParserOOMErr(ctxt); |
|
2611 return(ret); |
|
2612 } |
|
2613 } |
|
2614 return(xmlParseNameComplex(ctxt)); |
|
2615 } |
|
2616 |
|
2617 /** |
|
2618 * xmlParseNameAndCompare: |
|
2619 * @param ctxt an XML parser context |
|
2620 * |
|
2621 * parse an XML name and compares for match |
|
2622 * (specialized for endtag parsing) |
|
2623 * |
|
2624 * Returns NULL for an illegal name, (xmlChar*) 1 for success |
|
2625 * and the name for mismatch |
|
2626 */ |
|
2627 |
|
2628 static const xmlChar * |
|
2629 xmlParseNameAndCompare(xmlParserCtxtPtr ctxt, xmlChar const *other) { |
|
2630 register const xmlChar *cmp = other; |
|
2631 register const xmlChar *in; |
|
2632 const xmlChar *ret; |
|
2633 |
|
2634 GROW; |
|
2635 |
|
2636 in = ctxt->input->cur; |
|
2637 while (*in != 0 && *in == *cmp) { |
|
2638 ++in; |
|
2639 ++cmp; |
|
2640 } |
|
2641 if (*cmp == 0 && (*in == '>' || IS_BLANK_CH (*in))) { |
|
2642 /* success */ |
|
2643 ctxt->input->cur = in; |
|
2644 return (const xmlChar*) 1; |
|
2645 } |
|
2646 /* failure (or end of input buffer), check with full function */ |
|
2647 ret = xmlParseName (ctxt); |
|
2648 /* strings coming from the dictionnary direct compare possible */ |
|
2649 if (ret == other) { |
|
2650 return (const xmlChar*) 1; |
|
2651 } |
|
2652 return ret; |
|
2653 } |
|
2654 |
|
2655 /** |
|
2656 |
|
2657 OOM: |
|
2658 */ |
|
2659 static const xmlChar* |
|
2660 xmlParseNameComplex(xmlParserCtxtPtr ctxt) { |
|
2661 int len = 0, clen; // DONE: renamed 'l' --> 'clen' |
|
2662 int c; |
|
2663 int count = 0; |
|
2664 |
|
2665 /* |
|
2666 * Handler for more complex cases |
|
2667 */ |
|
2668 GROW; |
|
2669 c = CUR_CHAR(clen); |
|
2670 |
|
2671 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */ |
|
2672 (!IS_LETTER(c) && (c != '_') && (c != ':'))) |
|
2673 { |
|
2674 return(NULL); |
|
2675 } |
|
2676 |
|
2677 while ( |
|
2678 (c != ' ') && (c != '>') && (c != '/') /* test bigname.xml */ |
|
2679 && |
|
2680 ( IS_LETTER(c) || IS_DIGIT(c) || |
|
2681 (c == '.') || (c == '-') || |
|
2682 (c == '_') || (c == ':') || |
|
2683 IS_COMBINING(c)|| IS_EXTENDER(c) |
|
2684 ) |
|
2685 ) |
|
2686 { |
|
2687 if (count++ > 100) { |
|
2688 count = 0; |
|
2689 GROW; |
|
2690 } |
|
2691 len += clen; |
|
2692 NEXTL(clen); |
|
2693 c = CUR_CHAR(clen); // may set OOM flag |
|
2694 } |
|
2695 return(xmlDictLookup(ctxt->dict, ctxt->input->cur - len, len)); |
|
2696 } |
|
2697 |
|
2698 /** |
|
2699 * xmlParseStringName: |
|
2700 * @param ctxt an XML parser context |
|
2701 * @param str a pointer to the string pointer (IN/OUT) |
|
2702 * |
|
2703 * parse an XML name. |
|
2704 * |
|
2705 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' | |
|
2706 * CombiningChar | Extender |
|
2707 * |
|
2708 * [5] Name ::= (Letter | '_' | ':') (NameChar)* |
|
2709 * |
|
2710 * [6] Names ::= Name (S Name)* |
|
2711 * |
|
2712 * Returns the Name parsed or NULL. The str pointer |
|
2713 * is updated to the current location in the string. |
|
2714 */ |
|
2715 static xmlChar* |
|
2716 xmlParseStringName(xmlParserCtxtPtr ctxt, const xmlChar** str) |
|
2717 { |
|
2718 xmlChar buf[XML_MAX_NAMELEN + 5]; |
|
2719 const xmlChar* cur = *str; |
|
2720 int len = 0, l; |
|
2721 int c; |
|
2722 |
|
2723 c = CUR_SCHAR(cur, l); |
|
2724 if (!IS_LETTER(c) && |
|
2725 (c != '_') && |
|
2726 (c != ':')) |
|
2727 { |
|
2728 return(NULL); |
|
2729 } |
|
2730 |
|
2731 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigentname.xml */ |
|
2732 (c == '.') || (c == '-') || |
|
2733 (c == '_') || (c == ':') || |
|
2734 (IS_COMBINING(c)) || |
|
2735 (IS_EXTENDER(c))) |
|
2736 { |
|
2737 COPY_BUF(l,buf,len,c); |
|
2738 cur += l; |
|
2739 c = CUR_SCHAR(cur, l); |
|
2740 if (len >= XML_MAX_NAMELEN) |
|
2741 { /* test bigentname.xml */ |
|
2742 /* |
|
2743 * Okay someone managed to make a huge name, so he's ready to pay |
|
2744 * for the processing speed. |
|
2745 */ |
|
2746 xmlChar* buffer; |
|
2747 int max = len * 2; |
|
2748 |
|
2749 buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar)); |
|
2750 if (!buffer) |
|
2751 goto OOM_exit; |
|
2752 |
|
2753 memcpy(buffer, buf, len); |
|
2754 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || |
|
2755 /* test bigentname.xml */ |
|
2756 (c == '.') || (c == '-') || |
|
2757 (c == '_') || (c == ':') || |
|
2758 (IS_COMBINING(c)) || |
|
2759 (IS_EXTENDER(c))) |
|
2760 { |
|
2761 if (len + 10 > max) |
|
2762 { // DONE: Fix xmlRealloc |
|
2763 void* tmp; |
|
2764 max *= 2; |
|
2765 tmp = xmlRealloc(buffer, max * sizeof(xmlChar)); |
|
2766 if (!tmp) { |
|
2767 xmlFree(buffer); |
|
2768 OOM_exit: |
|
2769 xmlParserOOMErr(ctxt); |
|
2770 return(NULL); |
|
2771 } |
|
2772 buffer = (xmlChar*) tmp; |
|
2773 } |
|
2774 COPY_BUF(l,buffer,len,c); |
|
2775 cur += l; |
|
2776 c = CUR_SCHAR(cur, l); |
|
2777 } |
|
2778 buffer[len] = 0; |
|
2779 *str = cur; |
|
2780 return(buffer); |
|
2781 } |
|
2782 } |
|
2783 *str = cur; |
|
2784 return(xmlStrndup(buf, len)); |
|
2785 } |
|
2786 |
|
2787 /** |
|
2788 * xmlParseNmtoken: |
|
2789 * @param ctxt an XML parser context |
|
2790 * |
|
2791 * parse an XML Nmtoken. |
|
2792 * |
|
2793 * [7] Nmtoken ::= (NameChar)+ |
|
2794 * |
|
2795 * [8] Nmtokens ::= Nmtoken (S Nmtoken)* |
|
2796 * |
|
2797 * Returns the Nmtoken parsed or NULL |
|
2798 * |
|
2799 * OOM: possible --> for too long names; check OOM flag |
|
2800 */ |
|
2801 XMLPUBFUNEXPORT xmlChar* |
|
2802 xmlParseNmtoken(xmlParserCtxtPtr ctxt) |
|
2803 { |
|
2804 xmlChar buf[XML_MAX_NAMELEN + 5]; |
|
2805 int len = 0, l; |
|
2806 int c; |
|
2807 int count = 0; |
|
2808 |
|
2809 GROW; |
|
2810 c = CUR_CHAR(l); |
|
2811 |
|
2812 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigtoken.xml */ |
|
2813 (c == '.') || (c == '-') || |
|
2814 (c == '_') || (c == ':') || |
|
2815 (IS_COMBINING(c)) || |
|
2816 (IS_EXTENDER(c))) |
|
2817 { |
|
2818 if (count++ > 100) { |
|
2819 count = 0; |
|
2820 GROW; |
|
2821 } |
|
2822 COPY_BUF(l,buf,len,c); |
|
2823 NEXTL(l); |
|
2824 c = CUR_CHAR(l); |
|
2825 |
|
2826 if (len >= XML_MAX_NAMELEN) |
|
2827 { |
|
2828 /* |
|
2829 * Okay someone managed to make a huge token, so he's ready to pay |
|
2830 * for the processing speed. |
|
2831 */ |
|
2832 xmlChar *buffer; |
|
2833 int max = len * 2; |
|
2834 |
|
2835 buffer = (xmlChar*) xmlMallocAtomic(max * sizeof(xmlChar)); |
|
2836 if (!buffer) |
|
2837 goto OOM_exit; |
|
2838 |
|
2839 memcpy(buffer, buf, len); |
|
2840 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigtoken.xml */ |
|
2841 (c == '.') || (c == '-') || |
|
2842 (c == '_') || (c == ':') || |
|
2843 (IS_COMBINING(c)) || |
|
2844 (IS_EXTENDER(c))) |
|
2845 { |
|
2846 if (count++ > 100) { |
|
2847 count = 0; |
|
2848 GROW; |
|
2849 } |
|
2850 if (len + 10 > max) { |
|
2851 // DONE: Fix xmlRealloc |
|
2852 void* tmp; |
|
2853 max *= 2; |
|
2854 tmp = xmlRealloc(buffer, max * sizeof(xmlChar)); |
|
2855 if (!tmp) { |
|
2856 xmlFree(buffer); |
|
2857 OOM_exit: |
|
2858 xmlParserOOMErr(ctxt); |
|
2859 return(NULL); |
|
2860 } |
|
2861 buffer = (xmlChar*) tmp; |
|
2862 } |
|
2863 COPY_BUF(l,buffer,len,c); |
|
2864 NEXTL(l); |
|
2865 c = CUR_CHAR(l); |
|
2866 } |
|
2867 buffer[len] = 0; |
|
2868 return(buffer); |
|
2869 } // if (len >= XML_MAX_NAMELEN) |
|
2870 } // while |
|
2871 if (len == 0) |
|
2872 return(NULL); |
|
2873 return(xmlStrndup(buf, len)); |
|
2874 } |
|
2875 |
|
2876 /** |
|
2877 * xmlParseEntityValue: |
|
2878 * @param ctxt an XML parser context |
|
2879 * @param orig if non-NULL store a copy of the original entity value |
|
2880 * |
|
2881 * parse a value for ENTITY declarations |
|
2882 * |
|
2883 * [9] EntityValue ::= '"' ([^%&"] | PEReference | Reference)* '"' | |
|
2884 * "'" ([^%&'] | PEReference | Reference)* "'" |
|
2885 * |
|
2886 * Returns the EntityValue parsed with reference substituted or NULL |
|
2887 */ |
|
2888 |
|
2889 XMLPUBFUNEXPORT xmlChar * |
|
2890 xmlParseEntityValue(xmlParserCtxtPtr ctxt, xmlChar **orig) { |
|
2891 xmlChar *buf = NULL; |
|
2892 int len = 0; |
|
2893 int size = XML_PARSER_BUFFER_SIZE; |
|
2894 int c, l; |
|
2895 xmlChar stop; |
|
2896 xmlChar *ret = NULL; |
|
2897 const xmlChar *cur = NULL; |
|
2898 xmlParserInputPtr input; |
|
2899 |
|
2900 if (RAW == '"') stop = '"'; |
|
2901 else if (RAW == '\'') stop = '\''; |
|
2902 else { |
|
2903 xmlFatalErr(ctxt, XML_ERR_ENTITY_NOT_STARTED, NULL); |
|
2904 return(NULL); |
|
2905 } |
|
2906 buf = (xmlChar *) xmlMallocAtomic(size * sizeof(xmlChar)); |
|
2907 if (buf == NULL) { |
|
2908 xmlParserOOMErr(ctxt); |
|
2909 return(NULL); |
|
2910 } |
|
2911 |
|
2912 /* |
|
2913 * The content of the entity definition is copied in a buffer. |
|
2914 */ |
|
2915 |
|
2916 ctxt->instate = XML_PARSER_ENTITY_VALUE; |
|
2917 input = ctxt->input; |
|
2918 GROW; |
|
2919 NEXT; |
|
2920 c = CUR_CHAR(l); |
|
2921 /* |
|
2922 * NOTE: 4.4.5 Included in Literal |
|
2923 * When a parameter entity reference appears in a literal entity |
|
2924 * value, ... a single or double quote character in the replacement |
|
2925 * text is always treated as a normal data character and will not |
|
2926 * terminate the literal. |
|
2927 * In practice it means we stop the loop only when back at parsing |
|
2928 * the initial entity and the quote is found |
|
2929 */ |
|
2930 while ((IS_CHAR(c)) && ((c != stop) || /* checked */ |
|
2931 (ctxt->input != input))) |
|
2932 { |
|
2933 if (len + 5 >= size) { |
|
2934 // DONE: Fix xmlRealloc |
|
2935 void* tmp; |
|
2936 size *= 2; |
|
2937 tmp = xmlRealloc(buf, size * sizeof(xmlChar)); |
|
2938 if (!tmp) { |
|
2939 xmlFree(buf); |
|
2940 xmlParserOOMErr(ctxt); |
|
2941 return(NULL); |
|
2942 } |
|
2943 buf = (xmlChar*) tmp; |
|
2944 } |
|
2945 COPY_BUF(l,buf,len,c); |
|
2946 NEXTL(l); |
|
2947 /* |
|
2948 * Pop-up of finished entities. |
|
2949 */ |
|
2950 while ((RAW == 0) && (ctxt->inputNr > 1)) /* non input consuming */ |
|
2951 xmlPopInput(ctxt); |
|
2952 |
|
2953 GROW; |
|
2954 c = CUR_CHAR(l); |
|
2955 if (c == 0) { |
|
2956 GROW; |
|
2957 c = CUR_CHAR(l); |
|
2958 } |
|
2959 } |
|
2960 buf[len] = 0; |
|
2961 |
|
2962 /* |
|
2963 * Raise problem w.r.t. '&' and '%' being used in non-entities |
|
2964 * reference constructs. Note Charref will be handled in |
|
2965 * xmlStringDecodeEntities() |
|
2966 */ |
|
2967 cur = buf; |
|
2968 while (*cur != 0) { /* non input consuming */ |
|
2969 if ((*cur == '%') || ((*cur == '&') && (cur[1] != '#'))) { |
|
2970 xmlChar *name; |
|
2971 xmlChar tmp = *cur; |
|
2972 |
|
2973 cur++; |
|
2974 name = xmlParseStringName(ctxt, &cur); |
|
2975 if ((name == NULL) || (*cur != ';')) { |
|
2976 xmlFatalErrMsgInt(ctxt, XML_ERR_ENTITY_CHAR_ERROR, |
|
2977 EMBED_ERRTXT("EntityValue: '%c' forbidden except for entities references\n"), |
|
2978 tmp); |
|
2979 } |
|
2980 if ((tmp == '%') && (ctxt->inSubset == 1) && |
|
2981 (ctxt->inputNr == 1)) { |
|
2982 xmlFatalErr(ctxt, XML_ERR_ENTITY_PE_INTERNAL, NULL); |
|
2983 } |
|
2984 if (name != NULL) |
|
2985 xmlFree(name); |
|
2986 if (*cur == 0) |
|
2987 break; |
|
2988 } |
|
2989 cur++; |
|
2990 } |
|
2991 |
|
2992 /* |
|
2993 * Then PEReference entities are substituted. |
|
2994 */ |
|
2995 if (c != stop) { |
|
2996 xmlFatalErr(ctxt, XML_ERR_ENTITY_NOT_FINISHED, NULL); |
|
2997 xmlFree(buf); |
|
2998 } else { |
|
2999 NEXT; |
|
3000 /* |
|
3001 * NOTE: 4.4.7 Bypassed |
|
3002 * When a general entity reference appears in the EntityValue in |
|
3003 * an entity declaration, it is bypassed and left as is. |
|
3004 * so XML_SUBSTITUTE_REF is not set here. |
|
3005 */ |
|
3006 ret = xmlStringDecodeEntities(ctxt, buf, XML_SUBSTITUTE_PEREF, |
|
3007 0, 0, 0); |
|
3008 if (orig != NULL) |
|
3009 *orig = buf; |
|
3010 else |
|
3011 xmlFree(buf); |
|
3012 } |
|
3013 |
|
3014 return(ret); |
|
3015 } |
|
3016 |
|
3017 /** |
|
3018 * xmlParseAttValueComplex: |
|
3019 * @param ctxt an XML parser context |
|
3020 * @param len the resulting attribute len |
|
3021 * @param normalize wether to apply the inner normalization |
|
3022 * |
|
3023 * parse a value for an attribute, this is the fallback function |
|
3024 * of xmlParseAttValue() when the attribute parsing requires handling |
|
3025 * of non-ASCII characters, or normalization compaction. |
|
3026 * |
|
3027 * Returns the AttValue parsed or NULL. The value has to be freed by the caller. |
|
3028 */ |
|
3029 static xmlChar * |
|
3030 xmlParseAttValueComplex(xmlParserCtxtPtr ctxt, int *attlen, int normalize) { |
|
3031 xmlChar limit = 0; |
|
3032 xmlChar *buf = NULL; |
|
3033 int len = 0; |
|
3034 int buf_size = 0; |
|
3035 int c, l, in_space = 0; |
|
3036 xmlChar *current = NULL; |
|
3037 xmlEntityPtr ent; |
|
3038 |
|
3039 if (NXT(0) == '"') { |
|
3040 ctxt->instate = XML_PARSER_ATTRIBUTE_VALUE; |
|
3041 limit = '"'; |
|
3042 NEXT; |
|
3043 } else if (NXT(0) == '\'') { |
|
3044 limit = '\''; |
|
3045 ctxt->instate = XML_PARSER_ATTRIBUTE_VALUE; |
|
3046 NEXT; |
|
3047 } else { |
|
3048 xmlFatalErr(ctxt, XML_ERR_ATTRIBUTE_NOT_STARTED, NULL); |
|
3049 return(NULL); |
|
3050 } |
|
3051 |
|
3052 /* |
|
3053 * allocate a translation buffer. |
|
3054 */ |
|
3055 buf_size = XML_PARSER_BUFFER_SIZE; |
|
3056 buf = (xmlChar *) xmlMallocAtomic(buf_size * sizeof(xmlChar)); |
|
3057 if (buf == NULL) goto mem_error; |
|
3058 |
|
3059 /* |
|
3060 * OK loop until we reach one of the ending char or a size limit. |
|
3061 */ |
|
3062 c = CUR_CHAR(l); |
|
3063 while ((NXT(0) != limit) && /* checked */ |
|
3064 (c != '<')) { |
|
3065 if (c == 0) break; |
|
3066 if (c == '&') { |
|
3067 in_space = 0; |
|
3068 if (NXT(1) == '#') { |
|
3069 int val = xmlParseCharRef(ctxt); |
|
3070 |
|
3071 if (val == '&') { |
|
3072 if (ctxt->replaceEntities) { |
|
3073 if (len > buf_size - 10) { |
|
3074 GROW_BUFFER(buf); |
|
3075 } |
|
3076 buf[len++] = '&'; |
|
3077 } else { |
|
3078 /* |
|
3079 * The reparsing will be done in xmlStringGetNodeList() |
|
3080 * called by the attribute() function in SAX.c |
|
3081 */ |
|
3082 if (len > buf_size - 10) { |
|
3083 GROW_BUFFER(buf); |
|
3084 } |
|
3085 buf[len++] = '&'; |
|
3086 buf[len++] = '#'; |
|
3087 buf[len++] = '3'; |
|
3088 buf[len++] = '8'; |
|
3089 buf[len++] = ';'; |
|
3090 } |
|
3091 } else { |
|
3092 if (len > buf_size - 10) { |
|
3093 GROW_BUFFER(buf); |
|
3094 } |
|
3095 len += xmlCopyChar(0, &buf[len], val); |
|
3096 } |
|
3097 } else { |
|
3098 ent = xmlParseEntityRef(ctxt); |
|
3099 // XML ENGINE: TEST CODE: for disabling "Unknown entity reference" error |
|
3100 //if(!ent)return; |
|
3101 |
|
3102 if ((ent != NULL) && |
|
3103 (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) { |
|
3104 if (len > buf_size - 10) { |
|
3105 GROW_BUFFER(buf); |
|
3106 } |
|
3107 if ((ctxt->replaceEntities == 0) && |
|
3108 (ent->content[0] == '&')) |
|
3109 { |
|
3110 buf[len++] = '&'; |
|
3111 buf[len++] = '#'; |
|
3112 buf[len++] = '3'; |
|
3113 buf[len++] = '8'; |
|
3114 buf[len++] = ';'; |
|
3115 } else { |
|
3116 buf[len++] = ent->content[0]; |
|
3117 } |
|
3118 } else if ((ent != NULL) && |
|
3119 (ctxt->replaceEntities != 0)) { |
|
3120 xmlChar *rep; |
|
3121 |
|
3122 if (ent->etype != XML_INTERNAL_PREDEFINED_ENTITY) { |
|
3123 rep = xmlStringDecodeEntities(ctxt, ent->content, |
|
3124 XML_SUBSTITUTE_REF, |
|
3125 0, 0, 0); |
|
3126 if (rep != NULL) { |
|
3127 current = rep; |
|
3128 while (*current != 0) { /* non input consuming */ |
|
3129 buf[len++] = *current++; |
|
3130 if (len > buf_size - 10) { |
|
3131 GROW_BUFFER(buf); |
|
3132 } |
|
3133 } |
|
3134 xmlFree(rep); |
|
3135 } |
|
3136 } else { |
|
3137 if (len > buf_size - 10) { |
|
3138 GROW_BUFFER(buf); |
|
3139 } |
|
3140 if (ent->content != NULL) |
|
3141 buf[len++] = ent->content[0]; |
|
3142 } |
|
3143 } else if (ent != NULL) { |
|
3144 int i = xmlStrlen(ent->name); |
|
3145 const xmlChar *cur = ent->name; |
|
3146 |
|
3147 /* |
|
3148 * This may look absurd but is needed to detect |
|
3149 * entities problems |
|
3150 */ |
|
3151 if ((ent->etype != XML_INTERNAL_PREDEFINED_ENTITY) && |
|
3152 (ent->content != NULL)) { |
|
3153 xmlChar *rep; |
|
3154 rep = xmlStringDecodeEntities(ctxt, ent->content, |
|
3155 XML_SUBSTITUTE_REF, 0, 0, 0); |
|
3156 if (rep != NULL) |
|
3157 xmlFree(rep); |
|
3158 } |
|
3159 |
|
3160 /* |
|
3161 * Just output the reference |
|
3162 */ |
|
3163 buf[len++] = '&'; |
|
3164 /** |
|
3165 * SYMBIAN : DEFECT FIX : DEF129002 (libxml2 buffer overflow vulnerability) |
|
3166 * Make sure that the buffer is grown until it becomes |
|
3167 * large enough to avoid buffer overflow in case of long-entity |
|
3168 * names.The original defect can be located in debian bug tracking database |
|
3169 * with defect number 498768. |
|
3170 */ |
|
3171 while (len > buf_size - i - 10) { |
|
3172 GROW_BUFFER(buf); |
|
3173 } |
|
3174 for (;i > 0;i--) |
|
3175 buf[len++] = *cur++; |
|
3176 buf[len++] = ';'; |
|
3177 } |
|
3178 } |
|
3179 } else { |
|
3180 if ((c == 0x20) || (c == 0xD) || (c == 0xA) || (c == 0x9)) { |
|
3181 if ((len != 0) || (!normalize)) { |
|
3182 if ((!normalize) || (!in_space)) { |
|
3183 COPY_BUF(l,buf,len,0x20); |
|
3184 if (len > buf_size - 10) { |
|
3185 GROW_BUFFER(buf); |
|
3186 } |
|
3187 } |
|
3188 in_space = 1; |
|
3189 } |
|
3190 } else { |
|
3191 in_space = 0; |
|
3192 COPY_BUF(l,buf,len,c); |
|
3193 if (len > buf_size - 10) { |
|
3194 GROW_BUFFER(buf); |
|
3195 } |
|
3196 } |
|
3197 NEXTL(l); |
|
3198 } |
|
3199 GROW; |
|
3200 c = CUR_CHAR(l); |
|
3201 } |
|
3202 if ((in_space) && (normalize)) { |
|
3203 while (buf[len - 1] == 0x20) len--; |
|
3204 } |
|
3205 buf[len] = 0; |
|
3206 if (RAW == '<') { |
|
3207 xmlFatalErr(ctxt, XML_ERR_LT_IN_ATTRIBUTE, NULL); |
|
3208 } else if (RAW != limit) { |
|
3209 xmlFatalErrMsg(ctxt, XML_ERR_ATTRIBUTE_NOT_FINISHED, |
|
3210 EMBED_ERRTXT("AttValue: ' expected\n")); |
|
3211 } else |
|
3212 NEXT; |
|
3213 if (attlen != NULL) *attlen = len; |
|
3214 return(buf); |
|
3215 |
|
3216 mem_error: |
|
3217 xmlParserOOMErr(ctxt); |
|
3218 return(NULL); |
|
3219 } |
|
3220 |
|
3221 /** |
|
3222 * xmlParseAttValue: |
|
3223 * @param ctxt an XML parser context |
|
3224 * |
|
3225 * parse a value for an attribute |
|
3226 * Note: the parser won't do substitution of entities here, this |
|
3227 * will be handled later in xmlStringGetNodeList |
|
3228 * |
|
3229 * [10] AttValue ::= '"' ([^<&"] | Reference)* '"' | |
|
3230 * "'" ([^<&'] | Reference)* "'" |
|
3231 * |
|
3232 * 3.3.3 Attribute-Value Normalization: |
|
3233 * Before the value of an attribute is passed to the application or |
|
3234 * checked for validity, the XML processor must normalize it as follows: |
|
3235 * - a character reference is processed by appending the referenced |
|
3236 * character to the attribute value |
|
3237 * - an entity reference is processed by recursively processing the |
|
3238 * replacement text of the entity |
|
3239 * - a whitespace character (#x20, #xD, #xA, #x9) is processed by |
|
3240 * appending #x20 to the normalized value, except that only a single |
|
3241 * #x20 is appended for a "#xD#xA" sequence that is part of an external |
|
3242 * parsed entity or the literal entity value of an internal parsed entity |
|
3243 * - other characters are processed by appending them to the normalized value |
|
3244 * If the declared value is not CDATA, then the XML processor must further |
|
3245 * process the normalized attribute value by discarding any leading and |
|
3246 * trailing space (#x20) characters, and by replacing sequences of space |
|
3247 * (#x20) characters by a single space (#x20) character. |
|
3248 * All attributes for which no declaration has been read should be treated |
|
3249 * by a non-validating parser as if declared CDATA. |
|
3250 * |
|
3251 * Returns the AttValue parsed or NULL. The value has to be freed by the caller. |
|
3252 */ |
|
3253 |
|
3254 |
|
3255 XMLPUBFUNEXPORT xmlChar * |
|
3256 xmlParseAttValue(xmlParserCtxtPtr ctxt) { |
|
3257 return(xmlParseAttValueInternal(ctxt, NULL, NULL, 0)); |
|
3258 } |
|
3259 |
|
3260 /** |
|
3261 * xmlParseSystemLiteral: |
|
3262 * @param ctxt an XML parser context |
|
3263 * |
|
3264 * parse an XML Literal |
|
3265 * |
|
3266 * [11] SystemLiteral ::= ('"' [^"]* '"') | ("'" [^']* "'") |
|
3267 * |
|
3268 * Returns the SystemLiteral parsed or NULL |
|
3269 */ |
|
3270 |
|
3271 XMLPUBFUNEXPORT xmlChar * |
|
3272 xmlParseSystemLiteral(xmlParserCtxtPtr ctxt) { |
|
3273 xmlChar *buf = NULL; |
|
3274 int len = 0; |
|
3275 int size = XML_PARSER_BUFFER_SIZE; |
|
3276 int cur, l; |
|
3277 xmlChar stop; |
|
3278 int state = ctxt->instate; |
|
3279 int count = 0; |
|
3280 |
|
3281 SHRINK; |
|
3282 if (RAW == '"') { |
|
3283 NEXT; |
|
3284 stop = '"'; |
|
3285 } else if (RAW == '\'') { |
|
3286 NEXT; |
|
3287 stop = '\''; |
|
3288 } else { |
|
3289 xmlFatalErr(ctxt, XML_ERR_LITERAL_NOT_STARTED, NULL); |
|
3290 return(NULL); |
|
3291 } |
|
3292 |
|
3293 buf = (xmlChar*) xmlMallocAtomic(size * sizeof(xmlChar)); |
|
3294 if (!buf){ |
|
3295 xmlParserOOMErr(ctxt); |
|
3296 return NULL; |
|
3297 } |
|
3298 ctxt->instate = XML_PARSER_SYSTEM_LITERAL; |
|
3299 cur = CUR_CHAR(l); |
|
3300 while ((IS_CHAR(cur)) && (cur != stop)) |
|
3301 { /* checked */ |
|
3302 if (len + 5 >= size) { |
|
3303 // DONE: Fix xmlRealloc |
|
3304 xmlChar* tmp; |
|
3305 size *= 2; |
|
3306 tmp = (xmlChar*) xmlRealloc(buf, size * sizeof(xmlChar)); |
|
3307 if (!tmp) { |
|
3308 xmlFree(buf); |
|
3309 xmlParserOOMErr(ctxt); |
|
3310 ctxt->instate = (xmlParserInputState) state; |
|
3311 return(NULL); |
|
3312 } |
|
3313 buf = tmp; |
|
3314 } |
|
3315 count++; |
|
3316 if (count > 50) { |
|
3317 GROW; |
|
3318 count = 0; |
|
3319 } |
|
3320 COPY_BUF(l,buf,len,cur); |
|
3321 NEXTL(l); |
|
3322 cur = CUR_CHAR(l); |
|
3323 if (cur == 0) { |
|
3324 GROW; |
|
3325 SHRINK; |
|
3326 cur = CUR_CHAR(l); |
|
3327 } |
|
3328 } |
|
3329 buf[len] = 0; |
|
3330 ctxt->instate = (xmlParserInputState) state; |
|
3331 if (!IS_CHAR(cur)) { |
|
3332 xmlFatalErr(ctxt, XML_ERR_LITERAL_NOT_FINISHED, NULL); |
|
3333 } else { |
|
3334 NEXT; |
|
3335 } |
|
3336 return(buf); |
|
3337 } |
|
3338 |
|
3339 /** |
|
3340 * xmlParsePubidLiteral: |
|
3341 * @param ctxt an XML parser context |
|
3342 * |
|
3343 * parse an XML public literal |
|
3344 * |
|
3345 * [12] PubidLiteral ::= '"' PubidChar* '"' | "'" (PubidChar - "'")* "'" |
|
3346 * |
|
3347 * Returns the PubidLiteral parsed or NULL. |
|
3348 */ |
|
3349 XMLPUBFUNEXPORT xmlChar * |
|
3350 xmlParsePubidLiteral(xmlParserCtxtPtr ctxt) |
|
3351 { |
|
3352 xmlChar* buf = NULL; |
|
3353 int len = 0; |
|
3354 int size = XML_PARSER_BUFFER_SIZE; |
|
3355 xmlChar cur; |
|
3356 xmlChar stop; |
|
3357 int count = 0; |
|
3358 xmlParserInputState oldstate = ctxt->instate; |
|
3359 |
|
3360 SHRINK; |
|
3361 if (RAW == '"') { |
|
3362 NEXT; |
|
3363 stop = '"'; |
|
3364 } else if (RAW == '\'') { |
|
3365 NEXT; |
|
3366 stop = '\''; |
|
3367 } else { |
|
3368 xmlFatalErr(ctxt, XML_ERR_LITERAL_NOT_STARTED, NULL); |
|
3369 return(NULL); |
|
3370 } |
|
3371 buf = (xmlChar *) xmlMallocAtomic(size * sizeof(xmlChar)); |
|
3372 if (!buf) |
|
3373 goto OOM_exit; |
|
3374 |
|
3375 ctxt->instate = XML_PARSER_PUBLIC_LITERAL; |
|
3376 cur = CUR; |
|
3377 while ((IS_PUBIDCHAR_CH(cur)) && (cur != stop)) |
|
3378 { /* checked */ |
|
3379 if (len + 1 >= size) |
|
3380 { |
|
3381 // DONE: Fix xmlRealloc |
|
3382 xmlChar* tmp; |
|
3383 size *= 2; |
|
3384 tmp = (xmlChar*) xmlRealloc(buf, size * sizeof(xmlChar)); |
|
3385 if (!tmp) { |
|
3386 xmlFree(buf); |
|
3387 OOM_exit: |
|
3388 xmlParserOOMErr(ctxt); |
|
3389 return(NULL); |
|
3390 } |
|
3391 buf = tmp; |
|
3392 } |
|
3393 buf[len++] = cur; |
|
3394 count++; |
|
3395 if (count > 50) { |
|
3396 GROW; |
|
3397 count = 0; |
|
3398 } |
|
3399 NEXT; |
|
3400 cur = CUR; |
|
3401 if (cur == 0) { |
|
3402 GROW; |
|
3403 SHRINK; |
|
3404 cur = CUR; |
|
3405 } |
|
3406 } // while PUBID CHARs |
|
3407 |
|
3408 buf[len] = 0; |
|
3409 if (cur != stop) { |
|
3410 xmlFatalErr(ctxt, XML_ERR_LITERAL_NOT_FINISHED, NULL); |
|
3411 } else { |
|
3412 NEXT; |
|
3413 } |
|
3414 ctxt->instate = oldstate; |
|
3415 return(buf); |
|
3416 } |
|
3417 |
|
3418 void xmlParseCharDataComplex(xmlParserCtxtPtr ctxt, int cdata); |
|
3419 /** |
|
3420 * xmlParseCharData: |
|
3421 * @param ctxt an XML parser context |
|
3422 * @param cdata int indicating whether we are within a CDATA section |
|
3423 * |
|
3424 * parse a CharData section. |
|
3425 * if we are within a CDATA section ']]>' marks an end of section. |
|
3426 * |
|
3427 * The right angle bracket (>) may be represented using the string ">", |
|
3428 * and must, for compatibility, be escaped using ">" or a character |
|
3429 * reference when it appears in the string "]]>" in content, when that |
|
3430 * string is not marking the end of a CDATA section. |
|
3431 * |
|
3432 * [14] CharData ::= [^<&]* - ([^<&]* ']]>' [^<&]*) |
|
3433 */ |
|
3434 |
|
3435 XMLPUBFUNEXPORT void |
|
3436 xmlParseCharData(xmlParserCtxtPtr ctxt, int cdata) { |
|
3437 const xmlChar *in; |
|
3438 int nbchar = 0; |
|
3439 int line = ctxt->input->line; |
|
3440 int col = ctxt->input->col; |
|
3441 |
|
3442 SHRINK; |
|
3443 GROW; |
|
3444 /* |
|
3445 * Accelerated common case where input don't need to be |
|
3446 * modified before passing it to the handler. |
|
3447 */ |
|
3448 if (cdata) |
|
3449 goto parse_complex; |
|
3450 //-------------------------------------------------------------------- |
|
3451 in = ctxt->input->cur; |
|
3452 |
|
3453 do |
|
3454 { |
|
3455 get_more_space: |
|
3456 while (*in == 0x20) |
|
3457 in++; |
|
3458 |
|
3459 if (*in == 0xA) { |
|
3460 ctxt->input->line++; |
|
3461 in++; |
|
3462 while (*in == 0xA) { |
|
3463 ctxt->input->line++; |
|
3464 in++; |
|
3465 } |
|
3466 goto get_more_space; |
|
3467 } |
|
3468 |
|
3469 if (*in == '<') { |
|
3470 nbchar = in - ctxt->input->cur; |
|
3471 if (nbchar > 0) { |
|
3472 const xmlChar* tmp = ctxt->input->cur; |
|
3473 ctxt->input->cur = in; |
|
3474 |
|
3475 if (ctxt->sax->ignorableWhitespace != ctxt->sax->characters) { |
|
3476 if (areBlanks(ctxt, tmp, nbchar, 1)){ |
|
3477 ctxt->sax->ignorableWhitespace(ctxt->userData, tmp, nbchar); |
|
3478 } else |
|
3479 if (ctxt->sax->characters) |
|
3480 ctxt->sax->characters(ctxt->userData, tmp, nbchar); |
|
3481 } else |
|
3482 if (ctxt->sax->characters) { |
|
3483 ctxt->sax->characters(ctxt->userData, tmp, nbchar); |
|
3484 } |
|
3485 } |
|
3486 return; |
|
3487 } |
|
3488 get_more: |
|
3489 while (((*in > ']') && (*in <= 0x7F)) || |
|
3490 ((*in > '&') && (*in < '<')) || |
|
3491 ((*in > '<') && (*in < ']')) || |
|
3492 ((*in >= 0x20) && (*in < '&')) || |
|
3493 (*in == 0x09)) |
|
3494 { |
|
3495 in++; |
|
3496 } |
|
3497 |
|
3498 if (*in == 0xA) { |
|
3499 ctxt->input->line++; |
|
3500 in++; |
|
3501 while (*in == 0xA) { |
|
3502 ctxt->input->line++; |
|
3503 in++; |
|
3504 } |
|
3505 goto get_more; |
|
3506 } |
|
3507 if (*in == ']') { |
|
3508 if ((in[1] == ']') && (in[2] == '>')) { |
|
3509 xmlFatalErr(ctxt, XML_ERR_MISPLACED_CDATA_END, NULL); |
|
3510 ctxt->input->cur = in; |
|
3511 return; |
|
3512 } |
|
3513 in++; |
|
3514 goto get_more; |
|
3515 } |
|
3516 nbchar = in - ctxt->input->cur; |
|
3517 if (nbchar > 0) { |
|
3518 if (ctxt->sax->ignorableWhitespace != ctxt->sax->characters |
|
3519 && |
|
3520 IS_BLANK_CH(*ctxt->input->cur)) |
|
3521 { |
|
3522 const xmlChar *tmp = ctxt->input->cur; |
|
3523 ctxt->input->cur = in; |
|
3524 |
|
3525 if (areBlanks(ctxt, tmp, nbchar, 0)) |
|
3526 { |
|
3527 ctxt->sax->ignorableWhitespace(ctxt->userData, tmp, nbchar); |
|
3528 } |
|
3529 else if (ctxt->sax->characters) |
|
3530 { |
|
3531 ctxt->sax->characters(ctxt->userData, tmp, nbchar); |
|
3532 } |
|
3533 } else { |
|
3534 if (ctxt->sax->characters) |
|
3535 { |
|
3536 ctxt->sax->characters(ctxt->userData, ctxt->input->cur, nbchar); |
|
3537 } |
|
3538 } |
|
3539 line = ctxt->input->line; // moved from both IF branches above |
|
3540 col = ctxt->input->col; // |
|
3541 } |
|
3542 ctxt->input->cur = in; |
|
3543 if (*in == 0xD) { |
|
3544 in++; |
|
3545 if (*in == 0xA) { |
|
3546 ctxt->input->cur = in; |
|
3547 in++; |
|
3548 ctxt->input->line++; |
|
3549 continue; /* do-while loop */ |
|
3550 } |
|
3551 in--; |
|
3552 } |
|
3553 |
|
3554 if (*in == '<' || *in == '&') { |
|
3555 return; |
|
3556 } |
|
3557 SHRINK; |
|
3558 GROW; |
|
3559 in = ctxt->input->cur; |
|
3560 // end of DO-WHILE loop |
|
3561 } while ((*in >= 0x20 && *in <= 0x7F) || (*in == 0x09)); |
|
3562 |
|
3563 //nbchar = 0; // NOT needed |
|
3564 |
|
3565 //--------------------------------------------------------------------------------------- |
|
3566 parse_complex: |
|
3567 ctxt->input->line = line; |
|
3568 ctxt->input->col = col; |
|
3569 xmlParseCharDataComplex(ctxt, cdata); |
|
3570 } |
|
3571 |
|
3572 /** |
|
3573 * xmlParseCharDataComplex: |
|
3574 * @param ctxt an XML parser context |
|
3575 * @param cdata int indicating whether we are within a CDATA section |
|
3576 * |
|
3577 * parse a CharData section.this is the fallback function |
|
3578 * of xmlParseCharData() when the parsing requires handling |
|
3579 * of non-ASCII characters. |
|
3580 */ |
|
3581 void |
|
3582 xmlParseCharDataComplex(xmlParserCtxtPtr ctxt, int cdata) { |
|
3583 xmlChar buf[XML_PARSER_BIG_BUFFER_SIZE + 5]; |
|
3584 int nbchar = 0; |
|
3585 int cur, l; |
|
3586 int count = 0; |
|
3587 |
|
3588 SHRINK; |
|
3589 GROW; |
|
3590 cur = CUR_CHAR(l); |
|
3591 while ((cur != '<') && /* checked */ |
|
3592 (cur != '&') && |
|
3593 (IS_CHAR(cur))) /* test also done in xmlCurrentChar() */ { |
|
3594 if ((cur == ']') && (NXT(1) == ']') && |
|
3595 (NXT(2) == '>')) { |
|
3596 if (cdata) break; |
|
3597 else { |
|
3598 xmlFatalErr(ctxt, XML_ERR_MISPLACED_CDATA_END, NULL); |
|
3599 } |
|
3600 } |
|
3601 COPY_BUF(l,buf,nbchar,cur); |
|
3602 if (nbchar >= XML_PARSER_BIG_BUFFER_SIZE) { |
|
3603 buf[nbchar] = 0; |
|
3604 |
|
3605 /* |
|
3606 * OK the segment is to be consumed as chars. |
|
3607 */ |
|
3608 if ((ctxt->sax != NULL) && (!ctxt->disableSAX)) { |
|
3609 if (areBlanks(ctxt, buf, nbchar, 0)) { |
|
3610 if (ctxt->sax->ignorableWhitespace != NULL) |
|
3611 ctxt->sax->ignorableWhitespace(ctxt->userData, |
|
3612 buf, nbchar); |
|
3613 } else { |
|
3614 if (ctxt->sax->characters != NULL) |
|
3615 ctxt->sax->characters(ctxt->userData, buf, nbchar); |
|
3616 } |
|
3617 } |
|
3618 nbchar = 0; |
|
3619 } |
|
3620 count++; |
|
3621 if (count > 50) { |
|
3622 GROW; |
|
3623 count = 0; |
|
3624 } |
|
3625 NEXTL(l); |
|
3626 cur = CUR_CHAR(l); |
|
3627 } |
|
3628 if (nbchar != 0) { |
|
3629 buf[nbchar] = 0; |
|
3630 /* |
|
3631 * OK the segment is to be consumed as chars. |
|
3632 */ |
|
3633 if ((ctxt->sax != NULL) && (!ctxt->disableSAX)) { |
|
3634 if (areBlanks(ctxt, buf, nbchar, 0)) { |
|
3635 if (ctxt->sax->ignorableWhitespace != NULL) |
|
3636 ctxt->sax->ignorableWhitespace(ctxt->userData, buf, nbchar); |
|
3637 } else { |
|
3638 if (ctxt->sax->characters != NULL) |
|
3639 ctxt->sax->characters(ctxt->userData, buf, nbchar); |
|
3640 } |
|
3641 } |
|
3642 } |
|
3643 } |
|
3644 |
|
3645 /** |
|
3646 * xmlParseExternalID: |
|
3647 * @param ctxt an XML parser context |
|
3648 * @param publicID a xmlChar** receiving PubidLiteral |
|
3649 * @param strict indicate whether we should restrict parsing to only |
|
3650 * production [75], see NOTE below |
|
3651 * |
|
3652 * Parse an External ID or a Public ID |
|
3653 * |
|
3654 * NOTE: Productions [75] and [83] interact badly since [75] can generate |
|
3655 * 'PUBLIC' S PubidLiteral S SystemLiteral |
|
3656 * |
|
3657 * [75] ExternalID ::= 'SYSTEM' S SystemLiteral |
|
3658 * | 'PUBLIC' S PubidLiteral S SystemLiteral |
|
3659 * |
|
3660 * [83] PublicID ::= 'PUBLIC' S PubidLiteral |
|
3661 * |
|
3662 * Returns the function returns SystemLiteral and in the second |
|
3663 * case publicID receives PubidLiteral, is strict is off |
|
3664 * it is possible to return NULL and have publicID set. |
|
3665 */ |
|
3666 |
|
3667 XMLPUBFUNEXPORT xmlChar * |
|
3668 xmlParseExternalID(xmlParserCtxtPtr ctxt, xmlChar **publicID, int strict) { |
|
3669 xmlChar *URI = NULL; |
|
3670 |
|
3671 SHRINK; |
|
3672 |
|
3673 *publicID = NULL; |
|
3674 if (CMP6(CUR_PTR, 'S', 'Y', 'S', 'T', 'E', 'M')) { |
|
3675 SKIP(6); |
|
3676 if (!IS_BLANK_CH(CUR)) { |
|
3677 xmlFatalErrMsg(ctxt, XML_ERR_SPACE_REQUIRED, |
|
3678 EMBED_ERRTXT("Space required after 'SYSTEM'\n")); |
|
3679 } |
|
3680 SKIP_BLANKS; |
|
3681 URI = xmlParseSystemLiteral(ctxt); |
|
3682 if (URI == NULL) { |
|
3683 xmlFatalErr(ctxt, XML_ERR_URI_REQUIRED, NULL); |
|
3684 } |
|
3685 } else if (CMP6(CUR_PTR, 'P', 'U', 'B', 'L', 'I', 'C')) { |
|
3686 SKIP(6); |
|
3687 if (!IS_BLANK_CH(CUR)) { |
|
3688 xmlFatalErrMsg(ctxt, XML_ERR_SPACE_REQUIRED, |
|
3689 EMBED_ERRTXT("Space required after 'PUBLIC'\n")); |
|
3690 } |
|
3691 SKIP_BLANKS; |
|
3692 *publicID = xmlParsePubidLiteral(ctxt); |
|
3693 if (*publicID == NULL) { |
|
3694 xmlFatalErr(ctxt, XML_ERR_PUBID_REQUIRED, NULL); |
|
3695 } |
|
3696 if (strict) { |
|
3697 /* |
|
3698 * We don't handle [83] so "S SystemLiteral" is required. |
|
3699 */ |
|
3700 if (!IS_BLANK_CH(CUR)) { |
|
3701 xmlFatalErrMsg(ctxt, XML_ERR_SPACE_REQUIRED, |
|
3702 EMBED_ERRTXT("Space required after the Public Identifier\n")); |
|
3703 } |
|
3704 } else { |
|
3705 /* |
|
3706 * We handle [83] so we return immediately, if |
|
3707 * "S SystemLiteral" is not detected. From a purely parsing |
|
3708 * point of view that's a nice mess. |
|
3709 */ |
|
3710 const xmlChar *ptr; |
|
3711 GROW; |
|
3712 |
|
3713 ptr = CUR_PTR; |
|
3714 if (!IS_BLANK_CH(*ptr)) return(NULL); |
|
3715 |
|
3716 while (IS_BLANK_CH(*ptr)) ptr++; |
|
3717 if ((*ptr != '\'') && (*ptr != '"')) return(NULL); |
|
3718 } |
|
3719 SKIP_BLANKS; |
|
3720 URI = xmlParseSystemLiteral(ctxt); |
|
3721 if (URI == NULL) { |
|
3722 xmlFatalErr(ctxt, XML_ERR_URI_REQUIRED, NULL); |
|
3723 } |
|
3724 } |
|
3725 return(URI); |
|
3726 } |
|
3727 |
|
3728 /** |
|
3729 * xmlParseComment: |
|
3730 * @param ctxt an XML parser context |
|
3731 * |
|
3732 * Skip an XML (SGML) comment <!-- .... --> |
|
3733 * The spec says that "For compatibility, the string "--" (double-hyphen) |
|
3734 * must not occur within comments. " |
|
3735 * |
|
3736 * [15] Comment ::= '<!--' ((Char - '-') | ('-' (Char - '-')))* '-->' |
|
3737 */ |
|
3738 XMLPUBFUNEXPORT void |
|
3739 xmlParseComment(xmlParserCtxtPtr ctxt) { |
|
3740 xmlChar *buf = NULL; |
|
3741 int len; |
|
3742 int size = XML_PARSER_BUFFER_SIZE; |
|
3743 int q, ql; |
|
3744 int r, rl; |
|
3745 int cur, l; |
|
3746 xmlParserInputState state; |
|
3747 xmlParserInputPtr input = ctxt->input; |
|
3748 int count = 0; |
|
3749 |
|
3750 /* |
|
3751 * Check that there is a comment right here. |
|
3752 */ |
|
3753 if ((RAW != '<') || (NXT(1) != '!') || |
|
3754 (NXT(2) != '-') || (NXT(3) != '-')) return; |
|
3755 |
|
3756 state = ctxt->instate; |
|
3757 ctxt->instate = XML_PARSER_COMMENT; |
|
3758 SHRINK; |
|
3759 SKIP(4); |
|
3760 buf = (xmlChar *) xmlMallocAtomic(size * sizeof(xmlChar)); |
|
3761 if (buf == NULL) |
|
3762 goto OOM_exit; |
|
3763 |
|
3764 q = CUR_CHAR(ql); |
|
3765 if (q == 0) |
|
3766 goto not_terminated; |
|
3767 NEXTL(ql); |
|
3768 r = CUR_CHAR(rl); |
|
3769 if (r == 0) |
|
3770 goto not_terminated; |
|
3771 NEXTL(rl); |
|
3772 cur = CUR_CHAR(l); |
|
3773 if (cur == 0) |
|
3774 goto not_terminated; |
|
3775 len = 0; |
|
3776 while (IS_CHAR(cur) && /* checked */ |
|
3777 ((cur != '>') || |
|
3778 (r != '-') || (q != '-'))) { |
|
3779 if ((r == '-') && (q == '-')) { |
|
3780 xmlFatalErr(ctxt, XML_ERR_HYPHEN_IN_COMMENT, NULL); |
|
3781 } |
|
3782 if (len + 5 >= size) { |
|
3783 // DONE: Fix xmlRealloc |
|
3784 xmlChar* tmp; |
|
3785 size *= 2; |
|
3786 tmp = (xmlChar*) xmlRealloc(buf, size * sizeof(xmlChar)); |
|
3787 if (!tmp) { |
|
3788 xmlFree(buf); |
|
3789 OOM_exit: |
|
3790 xmlParserOOMErr(ctxt); |
|
3791 ctxt->instate = state; |
|
3792 return; |
|
3793 } |
|
3794 buf = tmp; |
|
3795 } |
|
3796 COPY_BUF(ql,buf,len,q); |
|
3797 q = r; |
|
3798 ql = rl; |
|
3799 r = cur; |
|
3800 rl = l; |
|
3801 |
|
3802 count++; |
|
3803 if (count > 50) { |
|
3804 GROW; |
|
3805 count = 0; |
|
3806 } |
|
3807 NEXTL(l); |
|
3808 cur = CUR_CHAR(l); |
|
3809 if (cur == 0) { |
|
3810 SHRINK; |
|
3811 GROW; |
|
3812 cur = CUR_CHAR(l); |
|
3813 } |
|
3814 } |
|
3815 buf[len] = 0; |
|
3816 if (!IS_CHAR(cur)) { |
|
3817 xmlFatalErrMsgStr(ctxt, XML_ERR_COMMENT_NOT_FINISHED, |
|
3818 EMBED_ERRTXT("Comment not terminated \n<!--%.50s\n"), buf); |
|
3819 xmlFree(buf); |
|
3820 } else { |
|
3821 if (input != ctxt->input) { |
|
3822 xmlFatalErrMsg(ctxt, XML_ERR_ENTITY_BOUNDARY, |
|
3823 EMBED_ERRTXT("Comment doesn't start and stop in the same entity\n")); |
|
3824 } |
|
3825 NEXT; |
|
3826 if ((ctxt->sax != NULL) && (ctxt->sax->comment != NULL) && |
|
3827 (!ctxt->disableSAX)) |
|
3828 ctxt->sax->comment(ctxt->userData, buf); |
|
3829 xmlFree(buf); |
|
3830 } |
|
3831 ctxt->instate = state; |
|
3832 return; |
|
3833 not_terminated: |
|
3834 xmlFatalErrMsgStr(ctxt, XML_ERR_COMMENT_NOT_FINISHED, |
|
3835 EMBED_ERRTXT("Comment not terminated\n"), NULL); |
|
3836 xmlFree(buf); |
|
3837 } |
|
3838 |
|
3839 /** |
|
3840 * xmlParsePITarget: |
|
3841 * @param ctxt an XML parser context |
|
3842 * |
|
3843 * parse the name of a PI |
|
3844 * |
|
3845 * [17] PITarget ::= Name - (('X' | 'x') ('M' | 'm') ('L' | 'l')) |
|
3846 * |
|
3847 * Returns the PITarget name or NULL |
|
3848 */ |
|
3849 |
|
3850 XMLPUBFUNEXPORT const xmlChar * |
|
3851 xmlParsePITarget(xmlParserCtxtPtr ctxt) { |
|
3852 |
|
3853 const xmlChar *name; |
|
3854 LOAD_GS_SAFE_CTXT(ctxt) |
|
3855 |
|
3856 name = xmlParseName(ctxt); |
|
3857 if ((name != NULL) && |
|
3858 ((name[0] == 'x') || (name[0] == 'X')) && |
|
3859 ((name[1] == 'm') || (name[1] == 'M')) && |
|
3860 ((name[2] == 'l') || (name[2] == 'L'))) { |
|
3861 int i; |
|
3862 if ((name[0] == 'x') && (name[1] == 'm') && |
|
3863 (name[2] == 'l') && (name[3] == 0)) { |
|
3864 xmlFatalErrMsg(ctxt, XML_ERR_RESERVED_XML_NAME, |
|
3865 EMBED_ERRTXT("XML declaration allowed only at the start of the document\n")); |
|
3866 return(name); |
|
3867 } else if (name[3] == 0) { |
|
3868 xmlFatalErr(ctxt, XML_ERR_RESERVED_XML_NAME, NULL); |
|
3869 return(name); |
|
3870 } |
|
3871 for (i = 0;;i++) { |
|
3872 if (xmlW3CPIs[i] == NULL) break; |
|
3873 if (xmlStrEqual(name, (const xmlChar *)xmlW3CPIs[i])) |
|
3874 return(name); |
|
3875 } |
|
3876 xmlWarningMsg(ctxt, XML_ERR_RESERVED_XML_NAME, |
|
3877 EMBED_ERRTXT("xmlParsePITarget: invalid name prefix 'xml'\n"), |
|
3878 NULL, NULL); |
|
3879 } |
|
3880 return(name); |
|
3881 } |
|
3882 |
|
3883 #ifdef LIBXML_CATALOG_ENABLED |
|
3884 /** |
|
3885 * xmlParseCatalogPI: |
|
3886 * @param ctxt an XML parser context |
|
3887 * @param catalog the PI value string |
|
3888 * |
|
3889 * parse an XML Catalog Processing Instruction. |
|
3890 * |
|
3891 * <?oasis-xml-catalog catalog="http://example.com/catalog.xml"?> |
|
3892 * |
|
3893 * Occurs only if allowed by the user and if happening in the Misc |
|
3894 * part of the document before any doctype informations |
|
3895 * This will add the given catalog to the parsing context in order |
|
3896 * to be used if there is a resolution need further down in the document |
|
3897 */ |
|
3898 |
|
3899 static void |
|
3900 xmlParseCatalogPI(xmlParserCtxtPtr ctxt, const xmlChar *catalog) { |
|
3901 xmlChar *URL = NULL; |
|
3902 const xmlChar *tmp, *base; |
|
3903 xmlChar marker; |
|
3904 |
|
3905 tmp = catalog; |
|
3906 while (IS_BLANK_CH(*tmp)) tmp++; |
|
3907 if (xmlStrncmp(tmp, BAD_CAST"catalog", 7)) |
|
3908 goto error; |
|
3909 tmp += 7; |
|
3910 while (IS_BLANK_CH(*tmp)) tmp++; |
|
3911 if (*tmp != '=') { |
|
3912 return; |
|
3913 } |
|
3914 tmp++; |
|
3915 while (IS_BLANK_CH(*tmp)) tmp++; |
|
3916 marker = *tmp; |
|
3917 if ((marker != '\'') && (marker != '"')) |
|
3918 goto error; |
|
3919 tmp++; |
|
3920 base = tmp; |
|
3921 while ((*tmp != 0) && (*tmp != marker)) tmp++; |
|
3922 if (*tmp == 0) |
|
3923 goto error; |
|
3924 URL = xmlStrndup(base, tmp - base); |
|
3925 tmp++; |
|
3926 while (IS_BLANK_CH(*tmp)) tmp++; |
|
3927 if (*tmp != 0) |
|
3928 goto error; |
|
3929 |
|
3930 if (URL != NULL) { |
|
3931 ctxt->catalogs = xmlCatalogAddLocal(ctxt->catalogs, URL); |
|
3932 xmlFree(URL); |
|
3933 } |
|
3934 return; |
|
3935 |
|
3936 error: |
|
3937 xmlWarningMsg(ctxt, XML_WAR_CATALOG_PI, |
|
3938 "Catalog PI syntax error: %s\n", |
|
3939 catalog, NULL); |
|
3940 if (URL != NULL) |
|
3941 xmlFree(URL); |
|
3942 } |
|
3943 #endif |
|
3944 |
|
3945 /** |
|
3946 * xmlParsePI: |
|
3947 * @param ctxt an XML parser context |
|
3948 * |
|
3949 * parse an XML Processing Instruction. |
|
3950 * |
|
3951 * [16] PI ::= '<?' PITarget (S (Char* - (Char* '?>' Char*)))? '?>' |
|
3952 * |
|
3953 * The processing is transfered to SAX once parsed. |
|
3954 */ |
|
3955 |
|
3956 XMLPUBFUNEXPORT void |
|
3957 xmlParsePI(xmlParserCtxtPtr ctxt) { |
|
3958 xmlChar *buf = NULL; |
|
3959 int len = 0; |
|
3960 int size = XML_PARSER_BUFFER_SIZE; |
|
3961 int cur, l; |
|
3962 const xmlChar *target; |
|
3963 xmlParserInputState state; |
|
3964 int count = 0; |
|
3965 |
|
3966 if ((RAW == '<') && (NXT(1) == '?')) { |
|
3967 xmlParserInputPtr input = ctxt->input; |
|
3968 state = ctxt->instate; |
|
3969 ctxt->instate = XML_PARSER_PI; |
|
3970 /* |
|
3971 * this is a Processing Instruction. |
|
3972 */ |
|
3973 SKIP(2); |
|
3974 SHRINK; |
|
3975 |
|
3976 /* |
|
3977 * Parse the target name and check for special support like |
|
3978 * namespace. |
|
3979 */ |
|
3980 target = xmlParsePITarget(ctxt); |
|
3981 if (target != NULL) { |
|
3982 if ((RAW == '?') && (NXT(1) == '>')) { |
|
3983 if (input != ctxt->input) { |
|
3984 xmlFatalErrMsg(ctxt, XML_ERR_ENTITY_BOUNDARY, |
|
3985 EMBED_ERRTXT("PI declaration doesn't start and stop in the same entity\n")); |
|
3986 } |
|
3987 SKIP(2); |
|
3988 |
|
3989 /* |
|
3990 * SAX: PI detected. |
|
3991 */ |
|
3992 if ((ctxt->sax) && (!ctxt->disableSAX) && |
|
3993 (ctxt->sax->processingInstruction != NULL)) |
|
3994 ctxt->sax->processingInstruction(ctxt->userData, |
|
3995 target, NULL); |
|
3996 ctxt->instate = state; |
|
3997 return; |
|
3998 } |
|
3999 buf = (xmlChar*) xmlMallocAtomic(size * sizeof(xmlChar)); |
|
4000 if (!buf) |
|
4001 goto OOM_exit; |
|
4002 |
|
4003 cur = CUR; |
|
4004 if (!IS_BLANK(cur)) { |
|
4005 xmlFatalErrMsgStr(ctxt, XML_ERR_SPACE_REQUIRED, |
|
4006 EMBED_ERRTXT("ParsePI: PI %s space expected\n"), target); |
|
4007 } |
|
4008 SKIP_BLANKS; |
|
4009 cur = CUR_CHAR(l); |
|
4010 while (IS_CHAR(cur) && /* checked */ |
|
4011 ((cur != '?') || (NXT(1) != '>'))) { |
|
4012 if (len + 5 >= size) { |
|
4013 // DONE: Fix xmlRealloc |
|
4014 xmlChar* tmp; |
|
4015 size *= 2; |
|
4016 tmp = (xmlChar*) xmlRealloc(buf, size * sizeof(xmlChar)); |
|
4017 if (!tmp) { |
|
4018 xmlFree(buf); |
|
4019 OOM_exit: |
|
4020 xmlParserOOMErr(ctxt); |
|
4021 ctxt->instate = state; |
|
4022 return; |
|
4023 } |
|
4024 buf = tmp; |
|
4025 } |
|
4026 count++; |
|
4027 if (count > 50) { |
|
4028 GROW; |
|
4029 count = 0; |
|
4030 } |
|
4031 COPY_BUF(l,buf,len,cur); |
|
4032 NEXTL(l); |
|
4033 cur = CUR_CHAR(l); |
|
4034 if (cur == 0) { |
|
4035 SHRINK; |
|
4036 GROW; |
|
4037 cur = CUR_CHAR(l); |
|
4038 } |
|
4039 } |
|
4040 buf[len] = 0; |
|
4041 if (cur != '?') { |
|
4042 xmlFatalErrMsgStr(ctxt, XML_ERR_PI_NOT_FINISHED, |
|
4043 EMBED_ERRTXT("ParsePI: PI %s never end ...\n"), target); |
|
4044 } else { |
|
4045 if (input != ctxt->input) { |
|
4046 xmlFatalErrMsg(ctxt, XML_ERR_SPACE_REQUIRED, |
|
4047 EMBED_ERRTXT("PI declaration doesn't start and stop in the same entity\n")); |
|
4048 } |
|
4049 SKIP(2); |
|
4050 |
|
4051 #ifdef LIBXML_CATALOG_ENABLED |
|
4052 if (((state == XML_PARSER_MISC) || |
|
4053 (state == XML_PARSER_START)) && |
|
4054 (xmlStrEqual(target, XML_CATALOG_PI))) { |
|
4055 xmlCatalogAllow allow = xmlCatalogGetDefaults(); |
|
4056 if ((allow == XML_CATA_ALLOW_DOCUMENT) || |
|
4057 (allow == XML_CATA_ALLOW_ALL)) |
|
4058 xmlParseCatalogPI(ctxt, buf); |
|
4059 } |
|
4060 #endif |
|
4061 |
|
4062 |
|
4063 /* |
|
4064 * SAX: PI detected. |
|
4065 */ |
|
4066 if ((ctxt->sax) && (!ctxt->disableSAX) && |
|
4067 (ctxt->sax->processingInstruction != NULL)) |
|
4068 ctxt->sax->processingInstruction(ctxt->userData, |
|
4069 target, buf); |
|
4070 } |
|
4071 xmlFree(buf); |
|
4072 } else { |
|
4073 xmlFatalErr(ctxt, XML_ERR_PI_NOT_STARTED, NULL); |
|
4074 } |
|
4075 ctxt->instate = state; |
|
4076 } |
|
4077 } |
|
4078 |
|
4079 /** |
|
4080 * xmlParseNotationDecl: |
|
4081 * @param ctxt an XML parser context |
|
4082 * |
|
4083 * parse a notation declaration |
|
4084 * |
|
4085 * [82] NotationDecl ::= '<!NOTATION' S Name S (ExternalID | PublicID) S? '>' |
|
4086 * |
|
4087 * Hence there is actually 3 choices: |
|
4088 * 'PUBLIC' S PubidLiteral |
|
4089 * 'PUBLIC' S PubidLiteral S SystemLiteral |
|
4090 * and 'SYSTEM' S SystemLiteral |
|
4091 * |
|
4092 * See the NOTE on xmlParseExternalID(). |
|
4093 */ |
|
4094 |
|
4095 XMLPUBFUNEXPORT void |
|
4096 xmlParseNotationDecl(xmlParserCtxtPtr ctxt) { |
|
4097 const xmlChar *name; |
|
4098 xmlChar *Pubid; |
|
4099 xmlChar *Systemid; |
|
4100 |
|
4101 if (CMP10(CUR_PTR, '<', '!', 'N', 'O', 'T', 'A', 'T', 'I', 'O', 'N')) { |
|
4102 xmlParserInputPtr input = ctxt->input; |
|
4103 SHRINK; |
|
4104 SKIP(10); |
|
4105 if (!IS_BLANK_CH(CUR)) { |
|
4106 xmlFatalErrMsg(ctxt, XML_ERR_SPACE_REQUIRED, |
|
4107 EMBED_ERRTXT("Space required after '<!NOTATION'\n")); |
|
4108 return; |
|
4109 } |
|
4110 SKIP_BLANKS; |
|
4111 |
|
4112 name = xmlParseName(ctxt); |
|
4113 if (name == NULL) { |
|
4114 xmlFatalErr(ctxt, XML_ERR_NOTATION_NOT_STARTED, NULL); |
|
4115 return; |
|
4116 } |
|
4117 if (!IS_BLANK_CH(CUR)) { |
|
4118 xmlFatalErrMsg(ctxt, XML_ERR_SPACE_REQUIRED, |
|
4119 EMBED_ERRTXT("Space required after the NOTATION name'\n")); |
|
4120 return; |
|
4121 } |
|
4122 SKIP_BLANKS; |
|
4123 |
|
4124 /* |
|
4125 * Parse the IDs. |
|
4126 */ |
|
4127 Systemid = xmlParseExternalID(ctxt, &Pubid, 0); |
|
4128 SKIP_BLANKS; |
|
4129 |
|
4130 if (RAW == '>') { |
|
4131 if (input != ctxt->input) { |
|
4132 xmlFatalErrMsg(ctxt, XML_ERR_SPACE_REQUIRED, |
|
4133 EMBED_ERRTXT("Notation declaration doesn't start and stop in the same entity\n")); |
|
4134 } |
|
4135 NEXT; |
|
4136 if ((ctxt->sax != NULL) && (!ctxt->disableSAX) && |
|
4137 (ctxt->sax->notationDecl != NULL)) |
|
4138 ctxt->sax->notationDecl(ctxt->userData, name, Pubid, Systemid); |
|
4139 } else { |
|
4140 xmlFatalErr(ctxt, XML_ERR_NOTATION_NOT_FINISHED, NULL); |
|
4141 } |
|
4142 if (Systemid != NULL) xmlFree(Systemid); |
|
4143 if (Pubid != NULL) xmlFree(Pubid); |
|
4144 } |
|
4145 } |
|
4146 |
|
4147 /** |
|
4148 * xmlParseEntityDecl: |
|
4149 * @param ctxt an XML parser context |
|
4150 * |
|
4151 * parse <!ENTITY declarations |
|
4152 * |
|
4153 * [70] EntityDecl ::= GEDecl | PEDecl |
|
4154 * |
|
4155 * [71] GEDecl ::= '<!ENTITY' S Name S EntityDef S? '>' |
|
4156 * |
|
4157 * [72] PEDecl ::= '<!ENTITY' S '%' S Name S PEDef S? '>' |
|
4158 * |
|
4159 * [73] EntityDef ::= EntityValue | (ExternalID NDataDecl?) |
|
4160 * |
|
4161 * [74] PEDef ::= EntityValue | ExternalID |
|
4162 * |
|
4163 * [76] NDataDecl ::= S 'NDATA' S Name |
|
4164 * |
|
4165 * [ VC: Notation Declared ] |
|
4166 * The Name must match the declared name of a notation. |
|
4167 */ |
|
4168 |
|
4169 XMLPUBFUNEXPORT void |
|
4170 xmlParseEntityDecl(xmlParserCtxtPtr ctxt) { |
|
4171 const xmlChar *name = NULL; |
|
4172 xmlChar *value = NULL; |
|
4173 xmlChar *URI = NULL, *literal = NULL; |
|
4174 const xmlChar *ndata = NULL; |
|
4175 int isParameter = 0; |
|
4176 xmlChar *orig = NULL; |
|
4177 int skipped; |
|
4178 |
|
4179 GROW; |
|
4180 if (CMP8(CUR_PTR, '<', '!', 'E', 'N', 'T', 'I', 'T', 'Y')) { |
|
4181 xmlParserInputPtr input = ctxt->input; |
|
4182 SHRINK; |
|
4183 SKIP(8); |
|
4184 skipped = SKIP_BLANKS; |
|
4185 if (skipped == 0) { |
|
4186 xmlFatalErrMsg(ctxt, XML_ERR_SPACE_REQUIRED, |
|
4187 EMBED_ERRTXT("Space required after '<!ENTITY'\n")); |
|
4188 } |
|
4189 |
|
4190 if (RAW == '%') { |
|
4191 NEXT; |
|
4192 skipped = SKIP_BLANKS; |
|
4193 if (skipped == 0) { |
|
4194 xmlFatalErrMsg(ctxt, XML_ERR_SPACE_REQUIRED, |
|
4195 EMBED_ERRTXT("Space required after '%'\n")); |
|
4196 } |
|
4197 isParameter = 1; |
|
4198 } |
|
4199 |
|
4200 name = xmlParseName(ctxt); |
|
4201 if (name == NULL) { |
|
4202 xmlFatalErrMsg(ctxt, XML_ERR_NAME_REQUIRED, |
|
4203 EMBED_ERRTXT("xmlParseEntityDecl: no name\n")); |
|
4204 return; |
|
4205 } |
|
4206 skipped = SKIP_BLANKS; |
|
4207 if (skipped == 0) { |
|
4208 xmlFatalErrMsg(ctxt, XML_ERR_SPACE_REQUIRED, |
|
4209 EMBED_ERRTXT("Space required after the entity name\n")); |
|
4210 } |
|
4211 |
|
4212 ctxt->instate = XML_PARSER_ENTITY_DECL; |
|
4213 /* |
|
4214 * handle the various case of definitions... |
|
4215 */ |
|
4216 if (isParameter) { |
|
4217 if ((RAW == '"') || (RAW == '\'')) { |
|
4218 value = xmlParseEntityValue(ctxt, &orig); |
|
4219 if (value) { |
|
4220 if ((ctxt->sax != NULL) && |
|
4221 (!ctxt->disableSAX) && (ctxt->sax->entityDecl != NULL)) |
|
4222 ctxt->sax->entityDecl(ctxt->userData, name, |
|
4223 XML_INTERNAL_PARAMETER_ENTITY, |
|
4224 NULL, NULL, value); |
|
4225 } |
|
4226 } else { |
|
4227 URI = xmlParseExternalID(ctxt, &literal, 1); |
|
4228 if ((URI == NULL) && (literal == NULL)) { |
|
4229 xmlFatalErr(ctxt, XML_ERR_VALUE_REQUIRED, NULL); |
|
4230 } |
|
4231 if (URI) { |
|
4232 xmlURIPtr uri; |
|
4233 |
|
4234 uri = xmlParseURI((const char *) URI); |
|
4235 if (uri == NULL) { |
|
4236 xmlErrMsgStr(ctxt, XML_ERR_INVALID_URI, |
|
4237 EMBED_ERRTXT("Invalid URI: %s\n"), URI); |
|
4238 /* |
|
4239 * This really ought to be a well formedness error |
|
4240 * but the XML Core WG decided otherwise c.f. issue |
|
4241 * E26 of the XML erratas. |
|
4242 */ |
|
4243 } else { |
|
4244 if (uri->fragment != NULL) { |
|
4245 /* |
|
4246 * Okay this is foolish to block those but not |
|
4247 * invalid URIs. |
|
4248 */ |
|
4249 xmlFatalErr(ctxt, XML_ERR_URI_FRAGMENT, NULL); |
|
4250 } else { |
|
4251 if ((ctxt->sax != NULL) && |
|
4252 (!ctxt->disableSAX) && |
|
4253 (ctxt->sax->entityDecl != NULL)) |
|
4254 ctxt->sax->entityDecl(ctxt->userData, name, |
|
4255 XML_EXTERNAL_PARAMETER_ENTITY, |
|
4256 literal, URI, NULL); |
|
4257 } |
|
4258 xmlFreeURI(uri); |
|
4259 } |
|
4260 } |
|
4261 } |
|
4262 } else { |
|
4263 if ((RAW == '"') || (RAW == '\'')) |
|
4264 { |
|
4265 value = xmlParseEntityValue(ctxt, &orig); |
|
4266 if ((ctxt->sax != NULL) && |
|
4267 (!ctxt->disableSAX) && (ctxt->sax->entityDecl != NULL)) |
|
4268 ctxt->sax->entityDecl(ctxt->userData, name, |
|
4269 XML_INTERNAL_GENERAL_ENTITY, |
|
4270 NULL, NULL, value); |
|
4271 /* |
|
4272 * For expat compatibility in SAX mode. |
|
4273 */ |
|
4274 if ((ctxt->myDoc == NULL) || |
|
4275 (xmlStrEqual(ctxt->myDoc->version, SAX_COMPAT_MODE))) |
|
4276 { |
|
4277 if (ctxt->myDoc == NULL) { |
|
4278 ctxt->myDoc = xmlNewDoc(SAX_COMPAT_MODE); |
|
4279 } |
|
4280 if (ctxt->myDoc->intSubset == NULL) |
|
4281 ctxt->myDoc->intSubset = xmlNewDtd(ctxt->myDoc, BAD_CAST "fake", NULL, NULL); |
|
4282 |
|
4283 xmlSAX2EntityDecl(ctxt, name, XML_INTERNAL_GENERAL_ENTITY, NULL, NULL, value); |
|
4284 } |
|
4285 } else { |
|
4286 URI = xmlParseExternalID(ctxt, &literal, 1); |
|
4287 if ((URI == NULL) && (literal == NULL)) { |
|
4288 xmlFatalErr(ctxt, XML_ERR_VALUE_REQUIRED, NULL); |
|
4289 } |
|
4290 if (URI) { |
|
4291 xmlURIPtr uri; |
|
4292 |
|
4293 uri = xmlParseURI((const char *)URI); |
|
4294 if (uri == NULL) |
|
4295 { |
|
4296 xmlErrMsgStr(ctxt, XML_ERR_INVALID_URI, |
|
4297 EMBED_ERRTXT("Invalid URI: %s\n"), URI); |
|
4298 /* |
|
4299 * This really ought to be a well formedness error |
|
4300 * but the XML Core WG decided otherwise c.f. issue |
|
4301 * E26 of the XML erratas. |
|
4302 */ |
|
4303 } else { |
|
4304 if (uri->fragment != NULL) { |
|
4305 /* |
|
4306 * Okay this is foolish to block those but not |
|
4307 * invalid URIs. |
|
4308 */ |
|
4309 xmlFatalErr(ctxt, XML_ERR_URI_FRAGMENT, NULL); |
|
4310 } |
|
4311 xmlFreeURI(uri); |
|
4312 } |
|
4313 } |
|
4314 if ((RAW != '>') && (!IS_BLANK_CH(CUR))) { |
|
4315 xmlFatalErrMsg(ctxt, XML_ERR_SPACE_REQUIRED, |
|
4316 EMBED_ERRTXT("Space required before 'NDATA'\n")); |
|
4317 } |
|
4318 SKIP_BLANKS; |
|
4319 if (CMP5(CUR_PTR, 'N', 'D', 'A', 'T', 'A')) |
|
4320 { |
|
4321 SKIP(5); |
|
4322 if (!IS_BLANK_CH(CUR)) { |
|
4323 xmlFatalErrMsg(ctxt, XML_ERR_SPACE_REQUIRED, |
|
4324 EMBED_ERRTXT("Space required after 'NDATA'\n")); |
|
4325 } |
|
4326 SKIP_BLANKS; |
|
4327 ndata = xmlParseName(ctxt); |
|
4328 if ((ctxt->sax != NULL) && (!ctxt->disableSAX) && |
|
4329 (ctxt->sax->unparsedEntityDecl != NULL)) |
|
4330 { |
|
4331 ctxt->sax->unparsedEntityDecl(ctxt->userData, name, |
|
4332 literal, URI, ndata); |
|
4333 } |
|
4334 } else { |
|
4335 if ((ctxt->sax != NULL) && |
|
4336 (!ctxt->disableSAX) && (ctxt->sax->entityDecl != NULL)) |
|
4337 { |
|
4338 ctxt->sax->entityDecl(ctxt->userData, name, |
|
4339 XML_EXTERNAL_GENERAL_PARSED_ENTITY, |
|
4340 literal, URI, NULL); |
|
4341 } |
|
4342 /* |
|
4343 * For expat compatibility in SAX mode. |
|
4344 * assuming the entity repalcement was asked for |
|
4345 */ |
|
4346 if ((ctxt->replaceEntities != 0) && |
|
4347 ((ctxt->myDoc == NULL) || |
|
4348 (xmlStrEqual(ctxt->myDoc->version, SAX_COMPAT_MODE)))) |
|
4349 { |
|
4350 if (ctxt->myDoc == NULL) { |
|
4351 ctxt->myDoc = xmlNewDoc(SAX_COMPAT_MODE); |
|
4352 } |
|
4353 |
|
4354 if (ctxt->myDoc->intSubset == NULL) |
|
4355 ctxt->myDoc->intSubset = xmlNewDtd(ctxt->myDoc, BAD_CAST "fake", NULL, NULL); |
|
4356 xmlSAX2EntityDecl(ctxt, name, |
|
4357 XML_EXTERNAL_GENERAL_PARSED_ENTITY, |
|
4358 literal, URI, NULL); |
|
4359 } |
|
4360 } |
|
4361 } |
|
4362 } |
|
4363 SKIP_BLANKS; |
|
4364 if (RAW != '>') { |
|
4365 xmlFatalErrMsgStr(ctxt, XML_ERR_ENTITY_NOT_FINISHED, |
|
4366 EMBED_ERRTXT("xmlParseEntityDecl: entity %s not terminated\n"), name); |
|
4367 } else { |
|
4368 if (input != ctxt->input) { |
|
4369 xmlFatalErrMsg(ctxt, XML_ERR_ENTITY_BOUNDARY, |
|
4370 EMBED_ERRTXT("Entity declaration doesn't start and stop in the same entity\n")); |
|
4371 } |
|
4372 NEXT; |
|
4373 } |
|
4374 if (orig != NULL) { |
|
4375 /* |
|
4376 * Ugly mechanism to save the raw entity value. |
|
4377 */ |
|
4378 xmlEntityPtr cur = NULL; |
|
4379 |
|
4380 if (isParameter) { |
|
4381 if ((ctxt->sax != NULL) && |
|
4382 (ctxt->sax->getParameterEntity != NULL)) |
|
4383 cur = ctxt->sax->getParameterEntity(ctxt->userData, name); |
|
4384 } else { |
|
4385 if ((ctxt->sax != NULL) && |
|
4386 (ctxt->sax->getEntity != NULL)) |
|
4387 cur = ctxt->sax->getEntity(ctxt->userData, name); |
|
4388 if ((cur == NULL) && (ctxt->userData==ctxt)) { |
|
4389 cur = xmlSAX2GetEntity(ctxt, name); |
|
4390 } |
|
4391 } |
|
4392 if (cur != NULL) { |
|
4393 if (cur->orig != NULL) |
|
4394 xmlFree(orig); |
|
4395 else |
|
4396 cur->orig = orig; |
|
4397 } else |
|
4398 xmlFree(orig); |
|
4399 } |
|
4400 if (value != NULL) xmlFree(value); |
|
4401 if (URI != NULL) xmlFree(URI); |
|
4402 if (literal != NULL) xmlFree(literal); |
|
4403 } |
|
4404 } |
|
4405 |
|
4406 /** |
|
4407 * xmlParseDefaultDecl: |
|
4408 * @param ctxt an XML parser context |
|
4409 * @param value Receive a possible fixed default value for the attribute |
|
4410 * |
|
4411 * Parse an attribute default declaration |
|
4412 * |
|
4413 * [60] DefaultDecl ::= '#REQUIRED' | '#IMPLIED' | (('#FIXED' S)? AttValue) |
|
4414 * |
|
4415 * [ VC: Required Attribute ] |
|
4416 * if the default declaration is the keyword #REQUIRED, then the |
|
4417 * attribute must be specified for all elements of the type in the |
|
4418 * attribute-list declaration. |
|
4419 * |
|
4420 * [ VC: Attribute Default Legal ] |
|
4421 * The declared default value must meet the lexical constraints of |
|
4422 * the declared attribute type c.f. xmlValidateAttributeDecl() |
|
4423 * |
|
4424 * [ VC: Fixed Attribute Default ] |
|
4425 * if an attribute has a default value declared with the #FIXED |
|
4426 * keyword, instances of that attribute must match the default value. |
|
4427 * |
|
4428 * [ WFC: No < in Attribute Values ] |
|
4429 * handled in xmlParseAttValue() |
|
4430 * |
|
4431 * returns: XML_ATTRIBUTE_NONE, XML_ATTRIBUTE_REQUIRED, XML_ATTRIBUTE_IMPLIED |
|
4432 * or XML_ATTRIBUTE_FIXED. |
|
4433 */ |
|
4434 |
|
4435 XMLPUBFUNEXPORT int |
|
4436 xmlParseDefaultDecl(xmlParserCtxtPtr ctxt, xmlChar **value) { |
|
4437 int val; |
|
4438 xmlChar *ret; |
|
4439 |
|
4440 *value = NULL; |
|
4441 if (CMP9(CUR_PTR, '#', 'R', 'E', 'Q', 'U', 'I', 'R', 'E', 'D')) { |
|
4442 SKIP(9); |
|
4443 return(XML_ATTRIBUTE_REQUIRED); |
|
4444 } |
|
4445 if (CMP8(CUR_PTR, '#', 'I', 'M', 'P', 'L', 'I', 'E', 'D')) { |
|
4446 SKIP(8); |
|
4447 return(XML_ATTRIBUTE_IMPLIED); |
|
4448 } |
|
4449 val = XML_ATTRIBUTE_NONE; |
|
4450 if (CMP6(CUR_PTR, '#', 'F', 'I', 'X', 'E', 'D')) { |
|
4451 SKIP(6); |
|
4452 val = XML_ATTRIBUTE_FIXED; |
|
4453 if (!IS_BLANK_CH(CUR)) { |
|
4454 xmlFatalErrMsg(ctxt, XML_ERR_SPACE_REQUIRED, |
|
4455 EMBED_ERRTXT("Space required after '#FIXED'\n")); |
|
4456 } |
|
4457 SKIP_BLANKS; |
|
4458 } |
|
4459 ret = xmlParseAttValue(ctxt); |
|
4460 ctxt->instate = XML_PARSER_DTD; |
|
4461 if (ret == NULL) { |
|
4462 xmlFatalErrMsg(ctxt, (xmlParserErrors)ctxt->errNo, |
|
4463 EMBED_ERRTXT("Attribute default value declaration error\n")); |
|
4464 } else |
|
4465 *value = ret; |
|
4466 return(val); |
|
4467 } |
|
4468 |
|
4469 /** |
|
4470 * xmlParseNotationType: |
|
4471 * @param ctxt an XML parser context |
|
4472 * |
|
4473 * parse an Notation attribute type. |
|
4474 * |
|
4475 * Note: the leading 'NOTATION' S part has already being parsed... |
|
4476 * |
|
4477 * [58] NotationType ::= 'NOTATION' S '(' S? Name (S? '|' S? Name)* S? ')' |
|
4478 * |
|
4479 * [ VC: Notation Attributes ] |
|
4480 * Values of this type must match one of the notation names included |
|
4481 * in the declaration; all notation names in the declaration must be declared. |
|
4482 * |
|
4483 * Returns: the notation attribute tree built while parsing |
|
4484 */ |
|
4485 |
|
4486 XMLPUBFUNEXPORT xmlEnumerationPtr |
|
4487 xmlParseNotationType(xmlParserCtxtPtr ctxt) { |
|
4488 const xmlChar *name; |
|
4489 xmlEnumerationPtr ret = NULL, last = NULL, cur; |
|
4490 |
|
4491 if (RAW != '(') { |
|
4492 xmlFatalErr(ctxt, XML_ERR_NOTATION_NOT_STARTED, NULL); |
|
4493 return(NULL); |
|
4494 } |
|
4495 SHRINK; |
|
4496 do { |
|
4497 NEXT; |
|
4498 SKIP_BLANKS; |
|
4499 name = xmlParseName(ctxt); |
|
4500 if (name == NULL) { |
|
4501 xmlFatalErrMsg(ctxt, XML_ERR_NAME_REQUIRED, |
|
4502 EMBED_ERRTXT("Name expected in NOTATION declaration\n")); |
|
4503 return(ret); |
|
4504 } |
|
4505 cur = xmlCreateEnumeration(name); |
|
4506 if (cur == NULL) return(ret); |
|
4507 if (last == NULL) ret = last = cur; |
|
4508 else { |
|
4509 last->next = cur; |
|
4510 last = cur; |
|
4511 } |
|
4512 SKIP_BLANKS; |
|
4513 } while (RAW == '|'); |
|
4514 if (RAW != ')') { |
|
4515 xmlFatalErr(ctxt, XML_ERR_NOTATION_NOT_FINISHED, NULL); |
|
4516 if ((last != NULL) && (last != ret)) |
|
4517 xmlFreeEnumeration(last); |
|
4518 return(ret); |
|
4519 } |
|
4520 NEXT; |
|
4521 return(ret); |
|
4522 } |
|
4523 |
|
4524 /** |
|
4525 * xmlParseEnumerationType: |
|
4526 * @param ctxt an XML parser context |
|
4527 * |
|
4528 * parse an Enumeration attribute type. |
|
4529 * |
|
4530 * [59] Enumeration ::= '(' S? Nmtoken (S? '|' S? Nmtoken)* S? ')' |
|
4531 * |
|
4532 * [ VC: Enumeration ] |
|
4533 * Values of this type must match one of the Nmtoken tokens in |
|
4534 * the declaration |
|
4535 * |
|
4536 * Returns: the enumeration attribute tree built while parsing |
|
4537 */ |
|
4538 |
|
4539 XMLPUBFUNEXPORT xmlEnumerationPtr |
|
4540 xmlParseEnumerationType(xmlParserCtxtPtr ctxt) { |
|
4541 xmlChar *name; |
|
4542 xmlEnumerationPtr ret = NULL, last = NULL, cur; |
|
4543 |
|
4544 if (RAW != '(') { |
|
4545 xmlFatalErr(ctxt, XML_ERR_ATTLIST_NOT_STARTED, NULL); |
|
4546 return(NULL); |
|
4547 } |
|
4548 SHRINK; |
|
4549 do { |
|
4550 NEXT; |
|
4551 SKIP_BLANKS; |
|
4552 name = xmlParseNmtoken(ctxt); |
|
4553 if (name == NULL) { |
|
4554 xmlFatalErr(ctxt, XML_ERR_NMTOKEN_REQUIRED, NULL); |
|
4555 return(ret); |
|
4556 } |
|
4557 cur = xmlCreateEnumeration(name); |
|
4558 xmlFree(name); |
|
4559 if (cur == NULL) return(ret); |
|
4560 if (last == NULL) ret = last = cur; |
|
4561 else { |
|
4562 last->next = cur; |
|
4563 last = cur; |
|
4564 } |
|
4565 SKIP_BLANKS; |
|
4566 } while (RAW == '|'); |
|
4567 if (RAW != ')') { |
|
4568 xmlFatalErr(ctxt, XML_ERR_ATTLIST_NOT_FINISHED, NULL); |
|
4569 return(ret); |
|
4570 } |
|
4571 NEXT; |
|
4572 return(ret); |
|
4573 } |
|
4574 |
|
4575 /** |
|
4576 * xmlParseEnumeratedType: |
|
4577 * @param ctxt an XML parser context |
|
4578 * @param tree the enumeration tree built while parsing |
|
4579 * |
|
4580 * parse an Enumerated attribute type. |
|
4581 * |
|
4582 * [57] EnumeratedType ::= NotationType | Enumeration |
|
4583 * |
|
4584 * [58] NotationType ::= 'NOTATION' S '(' S? Name (S? '|' S? Name)* S? ')' |
|
4585 * |
|
4586 * |
|
4587 * Returns: XML_ATTRIBUTE_ENUMERATION or XML_ATTRIBUTE_NOTATION |
|
4588 */ |
|
4589 |
|
4590 XMLPUBFUNEXPORT int |
|
4591 xmlParseEnumeratedType(xmlParserCtxtPtr ctxt, xmlEnumerationPtr *tree) { |
|
4592 if (CMP8(CUR_PTR, 'N', 'O', 'T', 'A', 'T', 'I', 'O', 'N')) { |
|
4593 SKIP(8); |
|
4594 if (!IS_BLANK_CH(CUR)) { |
|
4595 xmlFatalErrMsg(ctxt, XML_ERR_SPACE_REQUIRED, |
|
4596 EMBED_ERRTXT("Space required after 'NOTATION'\n")); |
|
4597 return(0); |
|
4598 } |
|
4599 SKIP_BLANKS; |
|
4600 *tree = xmlParseNotationType(ctxt); |
|
4601 if (*tree == NULL) return(0); |
|
4602 return(XML_ATTRIBUTE_NOTATION); |
|
4603 } |
|
4604 *tree = xmlParseEnumerationType(ctxt); |
|
4605 if (*tree == NULL) return(0); |
|
4606 return(XML_ATTRIBUTE_ENUMERATION); |
|
4607 } |
|
4608 |
|
4609 /** |
|
4610 * xmlParseAttributeType: |
|
4611 * @param ctxt an XML parser context |
|
4612 * @param tree the enumeration tree built while parsing |
|
4613 * |
|
4614 * parse the Attribute list def for an element |
|
4615 * |
|
4616 * [54] AttType ::= StringType | TokenizedType | EnumeratedType |
|
4617 * |
|
4618 * [55] StringType ::= 'CDATA' |
|
4619 * |
|
4620 * [56] TokenizedType ::= 'ID' | 'IDREF' | 'IDREFS' | 'ENTITY' | |
|
4621 * 'ENTITIES' | 'NMTOKEN' | 'NMTOKENS' |
|
4622 * |
|
4623 * Validity constraints for attribute values syntax are checked in |
|
4624 * xmlValidateAttributeValue() |
|
4625 * |
|
4626 * [ VC: ID ] |
|
4627 * Values of type ID must match the Name production. A name must not |
|
4628 * appear more than once in an XML document as a value of this type; |
|
4629 * i.e., ID values must uniquely identify the elements which bear them. |
|
4630 * |
|
4631 * [ VC: One ID per Element Type ] |
|
4632 * No element type may have more than one ID attribute specified. |
|
4633 * |
|
4634 * [ VC: ID Attribute Default ] |
|
4635 * An ID attribute must have a declared default of #IMPLIED or #REQUIRED. |
|
4636 * |
|
4637 * [ VC: IDREF ] |
|
4638 * Values of type IDREF must match the Name production, and values |
|
4639 * of type IDREFS must match Names; each IDREF Name must match the value |
|
4640 * of an ID attribute on some element in the XML document; i.e. IDREF |
|
4641 * values must match the value of some ID attribute. |
|
4642 * |
|
4643 * [ VC: Entity Name ] |
|
4644 * Values of type ENTITY must match the Name production, values |
|
4645 * of type ENTITIES must match Names; each Entity Name must match the |
|
4646 * name of an unparsed entity declared in the DTD. |
|
4647 * |
|
4648 * [ VC: Name Token ] |
|
4649 * Values of type NMTOKEN must match the Nmtoken production; values |
|
4650 * of type NMTOKENS must match Nmtokens. |
|
4651 * |
|
4652 * Returns the attribute type |
|
4653 */ |
|
4654 XMLPUBFUNEXPORT int |
|
4655 xmlParseAttributeType(xmlParserCtxtPtr ctxt, xmlEnumerationPtr *tree) { |
|
4656 SHRINK; |
|
4657 if (CMP5(CUR_PTR, 'C', 'D', 'A', 'T', 'A')) { |
|
4658 SKIP(5); |
|
4659 return(XML_ATTRIBUTE_CDATA); |
|
4660 } else if (CMP6(CUR_PTR, 'I', 'D', 'R', 'E', 'F', 'S')) { |
|
4661 SKIP(6); |
|
4662 return(XML_ATTRIBUTE_IDREFS); |
|
4663 } else if (CMP5(CUR_PTR, 'I', 'D', 'R', 'E', 'F')) { |
|
4664 SKIP(5); |
|
4665 return(XML_ATTRIBUTE_IDREF); |
|
4666 } else if ((RAW == 'I') && (NXT(1) == 'D')) { |
|
4667 SKIP(2); |
|
4668 return(XML_ATTRIBUTE_ID); |
|
4669 } else if (CMP6(CUR_PTR, 'E', 'N', 'T', 'I', 'T', 'Y')) { |
|
4670 SKIP(6); |
|
4671 return(XML_ATTRIBUTE_ENTITY); |
|
4672 } else if (CMP8(CUR_PTR, 'E', 'N', 'T', 'I', 'T', 'I', 'E', 'S')) { |
|
4673 SKIP(8); |
|
4674 return(XML_ATTRIBUTE_ENTITIES); |
|
4675 } else if (CMP8(CUR_PTR, 'N', 'M', 'T', 'O', 'K', 'E', 'N', 'S')) { |
|
4676 SKIP(8); |
|
4677 return(XML_ATTRIBUTE_NMTOKENS); |
|
4678 } else if (CMP7(CUR_PTR, 'N', 'M', 'T', 'O', 'K', 'E', 'N')) { |
|
4679 SKIP(7); |
|
4680 return(XML_ATTRIBUTE_NMTOKEN); |
|
4681 } |
|
4682 return(xmlParseEnumeratedType(ctxt, tree)); |
|
4683 } |
|
4684 |
|
4685 /** |
|
4686 * xmlParseAttributeListDecl: |
|
4687 * @param ctxt an XML parser context |
|
4688 * |
|
4689 * : parse the Attribute list def for an element |
|
4690 * |
|
4691 * [52] AttlistDecl ::= '<!ATTLIST' S Name AttDef* S? '>' |
|
4692 * |
|
4693 * [53] AttDef ::= S Name S AttType S DefaultDecl |
|
4694 * |
|
4695 */ |
|
4696 XMLPUBFUNEXPORT void |
|
4697 xmlParseAttributeListDecl(xmlParserCtxtPtr ctxt) { |
|
4698 const xmlChar *elemName; |
|
4699 const xmlChar *attrName; |
|
4700 xmlEnumerationPtr tree; |
|
4701 |
|
4702 if (CMP9(CUR_PTR, '<', '!', 'A', 'T', 'T', 'L', 'I', 'S', 'T')) { |
|
4703 xmlParserInputPtr input = ctxt->input; |
|
4704 |
|
4705 SKIP(9); |
|
4706 if (!IS_BLANK_CH(CUR)) { |
|
4707 xmlFatalErrMsg(ctxt, XML_ERR_SPACE_REQUIRED, |
|
4708 EMBED_ERRTXT("Space required after '<!ATTLIST'\n")); |
|
4709 } |
|
4710 SKIP_BLANKS; |
|
4711 elemName = xmlParseName(ctxt); |
|
4712 if (elemName == NULL) { |
|
4713 xmlFatalErrMsg(ctxt, XML_ERR_NAME_REQUIRED, |
|
4714 EMBED_ERRTXT("ATTLIST: no name for Element\n")); |
|
4715 return; |
|
4716 } |
|
4717 SKIP_BLANKS; |
|
4718 GROW; |
|
4719 while (RAW != '>') { |
|
4720 const xmlChar *check = CUR_PTR; |
|
4721 int type; |
|
4722 int def; |
|
4723 xmlChar *defaultValue = NULL; |
|
4724 |
|
4725 GROW; |
|
4726 tree = NULL; |
|
4727 attrName = xmlParseName(ctxt); |
|
4728 if (attrName == NULL) { |
|
4729 xmlFatalErrMsg(ctxt, XML_ERR_NAME_REQUIRED, |
|
4730 EMBED_ERRTXT("ATTLIST: no name for Attribute\n")); |
|
4731 break; |
|
4732 } |
|
4733 GROW; |
|
4734 if (!IS_BLANK_CH(CUR)) { |
|
4735 xmlFatalErrMsg(ctxt, XML_ERR_SPACE_REQUIRED, |
|
4736 EMBED_ERRTXT("Space required after the attribute name\n")); |
|
4737 if (defaultValue != NULL) |
|
4738 xmlFree(defaultValue); |
|
4739 break; |
|
4740 } |
|
4741 SKIP_BLANKS; |
|
4742 |
|
4743 type = xmlParseAttributeType(ctxt, &tree); |
|
4744 if (type <= 0) { |
|
4745 if (defaultValue != NULL) |
|
4746 xmlFree(defaultValue); |
|
4747 break; |
|
4748 } |
|
4749 |
|
4750 GROW; |
|
4751 if (!IS_BLANK_CH(CUR)) { |
|
4752 xmlFatalErrMsg(ctxt, XML_ERR_SPACE_REQUIRED, |
|
4753 EMBED_ERRTXT("Space required after the attribute type\n")); |
|
4754 if (defaultValue != NULL) |
|
4755 xmlFree(defaultValue); |
|
4756 if (tree != NULL) |
|
4757 xmlFreeEnumeration(tree); |
|
4758 break; |
|
4759 } |
|
4760 SKIP_BLANKS; |
|
4761 |
|
4762 def = xmlParseDefaultDecl(ctxt, &defaultValue); |
|
4763 if (def <= 0) { |
|
4764 if (defaultValue != NULL) |
|
4765 xmlFree(defaultValue); |
|
4766 if (tree != NULL) |
|
4767 xmlFreeEnumeration(tree); |
|
4768 break; |
|
4769 } |
|
4770 |
|
4771 GROW; |
|
4772 if (RAW != '>') { |
|
4773 if (!IS_BLANK_CH(CUR)) { |
|
4774 xmlFatalErrMsg(ctxt, XML_ERR_SPACE_REQUIRED, |
|
4775 EMBED_ERRTXT("Space required after the attribute default value\n")); |
|
4776 if (defaultValue != NULL) |
|
4777 xmlFree(defaultValue); |
|
4778 if (tree != NULL) |
|
4779 xmlFreeEnumeration(tree); |
|
4780 break; |
|
4781 } |
|
4782 SKIP_BLANKS; |
|
4783 } |
|
4784 if (check == CUR_PTR) { |
|
4785 xmlFatalErr(ctxt, XML_ERR_INTERNAL_ERROR, |
|
4786 EMBED_ERRTXT("in xmlParseAttributeListDecl\n")); |
|
4787 if (defaultValue != NULL) |
|
4788 xmlFree(defaultValue); |
|
4789 if (tree != NULL) |
|
4790 xmlFreeEnumeration(tree); |
|
4791 break; |
|
4792 } |
|
4793 if ((ctxt->sax != NULL) && (!ctxt->disableSAX) && |
|
4794 (ctxt->sax->attributeDecl != NULL)) |
|
4795 ctxt->sax->attributeDecl(ctxt->userData, elemName, attrName, |
|
4796 type, def, defaultValue, tree); |
|
4797 else if (tree != NULL) |
|
4798 xmlFreeEnumeration(tree); |
|
4799 |
|
4800 if ((ctxt->sax2) && (defaultValue != NULL) && |
|
4801 (def != XML_ATTRIBUTE_IMPLIED) && |
|
4802 (def != XML_ATTRIBUTE_REQUIRED)) { |
|
4803 xmlAddDefAttrs(ctxt, elemName, attrName, defaultValue); |
|
4804 } |
|
4805 if ((ctxt->sax2) && (type != XML_ATTRIBUTE_CDATA)) { |
|
4806 xmlAddSpecialAttr(ctxt, elemName, attrName, type); |
|
4807 } |
|
4808 if (defaultValue != NULL) |
|
4809 xmlFree(defaultValue); |
|
4810 GROW; |
|
4811 } |
|
4812 if (RAW == '>') { |
|
4813 if (input != ctxt->input) { |
|
4814 xmlFatalErrMsg(ctxt, XML_ERR_ENTITY_BOUNDARY, |
|
4815 EMBED_ERRTXT("Attribute list declaration doesn't start and stop in the same entity\n")); |
|
4816 } |
|
4817 NEXT; |
|
4818 } |
|
4819 } |
|
4820 } |
|
4821 |
|
4822 /** |
|
4823 * xmlParseElementMixedContentDecl: |
|
4824 * @param ctxt an XML parser context |
|
4825 * @param inputchk the input used for the current entity, needed for boundary checks |
|
4826 * |
|
4827 * parse the declaration for a Mixed Element content |
|
4828 * The leading '(' and spaces have been skipped in xmlParseElementContentDecl |
|
4829 * |
|
4830 * [51] Mixed ::= '(' S? '#PCDATA' (S? '|' S? Name)* S? ')*' | |
|
4831 * '(' S? '#PCDATA' S? ')' |
|
4832 * |
|
4833 * [ VC: Proper Group/PE Nesting ] applies to [51] too (see [49]) |
|
4834 * |
|
4835 * [ VC: No Duplicate Types ] |
|
4836 * The same name must not appear more than once in a single |
|
4837 * mixed-content declaration. |
|
4838 * |
|
4839 * returns: the list of the xmlElementContentPtr describing the element choices |
|
4840 * or NULL if error |
|
4841 */ |
|
4842 XMLPUBFUNEXPORT xmlElementContentPtr |
|
4843 xmlParseElementMixedContentDecl(xmlParserCtxtPtr ctxt, int inputchk) |
|
4844 { |
|
4845 xmlElementContentPtr ret = NULL; |
|
4846 xmlElementContentPtr cur = NULL; |
|
4847 xmlElementContentPtr n; |
|
4848 const xmlChar* elem = NULL; |
|
4849 |
|
4850 GROW; |
|
4851 |
|
4852 if (!CMP7(CUR_PTR, '#', 'P', 'C', 'D', 'A', 'T', 'A')) |
|
4853 { |
|
4854 xmlFatalErr(ctxt, XML_ERR_PCDATA_REQUIRED, NULL); |
|
4855 return NULL; |
|
4856 } |
|
4857 |
|
4858 SKIP(7); |
|
4859 SKIP_BLANKS; |
|
4860 SHRINK; |
|
4861 if (RAW == ')') |
|
4862 { |
|
4863 if ((ctxt->validate) && (ctxt->input->id != inputchk)) { |
|
4864 xmlValidityError(ctxt, XML_ERR_ENTITY_BOUNDARY, |
|
4865 EMBED_ERRTXT("Element content declaration doesn't start and stop in the same entity\n"), |
|
4866 NULL); |
|
4867 } |
|
4868 NEXT; |
|
4869 ret = xmlNewElementContent(NULL, XML_ELEMENT_CONTENT_PCDATA); |
|
4870 if(!ret) // no need to check OOM_FLAG |
|
4871 { |
|
4872 return /* NULL */ ret; |
|
4873 } |
|
4874 if (RAW == '*') { |
|
4875 ret->ocur = XML_ELEMENT_CONTENT_MULT; |
|
4876 NEXT; |
|
4877 } |
|
4878 return(ret); |
|
4879 } |
|
4880 |
|
4881 if ((RAW == '(') || (RAW == '|')) |
|
4882 { |
|
4883 ret = cur = xmlNewElementContent(NULL, XML_ELEMENT_CONTENT_PCDATA); |
|
4884 if (!ret) |
|
4885 return /* NULL */ ret ; |
|
4886 } |
|
4887 |
|
4888 while (RAW == '|') |
|
4889 { |
|
4890 NEXT; |
|
4891 if (elem == NULL) { |
|
4892 ret = xmlNewElementContent(NULL, XML_ELEMENT_CONTENT_OR); |
|
4893 if (!ret) |
|
4894 return /* NULL */ ret; |
|
4895 ret->c1 = cur; |
|
4896 if (cur) |
|
4897 cur->parent = ret; |
|
4898 cur = ret; |
|
4899 } else { |
|
4900 n = xmlNewElementContent(NULL, XML_ELEMENT_CONTENT_OR); |
|
4901 if (!n) |
|
4902 return /* NULL */ n; |
|
4903 n->c1 = xmlNewElementContent(elem, XML_ELEMENT_CONTENT_ELEMENT); |
|
4904 if (n->c1 != NULL) |
|
4905 n->c1->parent = n; |
|
4906 cur->c2 = n; |
|
4907 // if (n != NULL) // this check is redundant |
|
4908 n->parent = cur; |
|
4909 cur = n; |
|
4910 } |
|
4911 SKIP_BLANKS; |
|
4912 elem = xmlParseName(ctxt); |
|
4913 if (!elem) { |
|
4914 xmlFatalErrMsg(ctxt, XML_ERR_NAME_REQUIRED, |
|
4915 EMBED_ERRTXT("xmlParseElementMixedContentDecl : Name expected\n")); |
|
4916 xmlFreeElementContent(cur); |
|
4917 return(NULL); |
|
4918 } |
|
4919 SKIP_BLANKS; |
|
4920 GROW; |
|
4921 } |
|
4922 |
|
4923 if ((RAW == ')') && (NXT(1) == '*')) { |
|
4924 if (elem != NULL) { |
|
4925 cur->c2 = xmlNewElementContent(elem, XML_ELEMENT_CONTENT_ELEMENT); |
|
4926 if (cur->c2 != NULL) |
|
4927 cur->c2->parent = cur; |
|
4928 } |
|
4929 ret->ocur = XML_ELEMENT_CONTENT_MULT; |
|
4930 if ((ctxt->validate) && (ctxt->input->id != inputchk)) { |
|
4931 xmlValidityError(ctxt, XML_ERR_ENTITY_BOUNDARY, |
|
4932 EMBED_ERRTXT("Element content declaration doesn't start and stop in the same entity\n"), |
|
4933 NULL); |
|
4934 } |
|
4935 SKIP(2); |
|
4936 } else { |
|
4937 xmlFreeElementContent(ret); |
|
4938 xmlFatalErr(ctxt, XML_ERR_MIXED_NOT_STARTED, NULL); |
|
4939 return(NULL); |
|
4940 } |
|
4941 |
|
4942 return(ret); |
|
4943 } |
|
4944 |
|
4945 /** |
|
4946 * xmlParseElementChildrenContentDecl: |
|
4947 * @param ctxt an XML parser context |
|
4948 * @param inputchk the input used for the current entity, needed for boundary checks |
|
4949 * |
|
4950 * parse the declaration for a Mixed Element content |
|
4951 * The leading '(' and spaces have been skipped in xmlParseElementContentDecl |
|
4952 * |
|
4953 * |
|
4954 * [47] children ::= (choice | seq) ('?' | '*' | '+')? |
|
4955 * |
|
4956 * [48] cp ::= (Name | choice | seq) ('?' | '*' | '+')? |
|
4957 * |
|
4958 * [49] choice ::= '(' S? cp ( S? '|' S? cp )* S? ')' |
|
4959 * |
|
4960 * [50] seq ::= '(' S? cp ( S? ',' S? cp )* S? ')' |
|
4961 * |
|
4962 * [ VC: Proper Group/PE Nesting ] applies to [49] and [50] |
|
4963 * Parameter-entity replacement text must be properly nested |
|
4964 * with parenthesized groups. That is to say, if either of the |
|
4965 * opening or closing parentheses in a choice, seq, or Mixed |
|
4966 * construct is contained in the replacement text for a parameter |
|
4967 * entity, both must be contained in the same replacement text. For |
|
4968 * interoperability, if a parameter-entity reference appears in a |
|
4969 * choice, seq, or Mixed construct, its replacement text should not |
|
4970 * be empty, and neither the first nor last non-blank character of |
|
4971 * the replacement text should be a connector (| or ,). |
|
4972 * |
|
4973 * Returns the tree of xmlElementContentPtr describing the element |
|
4974 * hierarchy. |
|
4975 */ |
|
4976 XMLPUBFUNEXPORT xmlElementContentPtr |
|
4977 xmlParseElementChildrenContentDecl (xmlParserCtxtPtr ctxt, int inputchk) |
|
4978 { |
|
4979 xmlElementContentPtr ret = NULL, cur = NULL, last = NULL, op = NULL; |
|
4980 const xmlChar *elem; |
|
4981 xmlChar type = 0; |
|
4982 |
|
4983 SKIP_BLANKS; |
|
4984 GROW; |
|
4985 if (RAW == '(') |
|
4986 { |
|
4987 int inputid = ctxt->input->id; |
|
4988 |
|
4989 /* Recurse on first child */ |
|
4990 NEXT; |
|
4991 SKIP_BLANKS; |
|
4992 cur = ret = xmlParseElementChildrenContentDecl(ctxt, inputid); |
|
4993 SKIP_BLANKS; |
|
4994 GROW; |
|
4995 } |
|
4996 else |
|
4997 { |
|
4998 elem = xmlParseName(ctxt); |
|
4999 if (elem == NULL) { |
|
5000 xmlFatalErr(ctxt, XML_ERR_ELEMCONTENT_NOT_STARTED, NULL); |
|
5001 return(NULL); |
|
5002 } |
|
5003 cur = ret = xmlNewElementContent(elem, XML_ELEMENT_CONTENT_ELEMENT); |
|
5004 if (cur == NULL) { |
|
5005 xmlParserOOMErr(ctxt); |
|
5006 return(NULL); |
|
5007 } |
|
5008 GROW; |
|
5009 if (RAW == '?') { |
|
5010 cur->ocur = XML_ELEMENT_CONTENT_OPT; |
|
5011 NEXT; |
|
5012 } else if (RAW == '*') { |
|
5013 cur->ocur = XML_ELEMENT_CONTENT_MULT; |
|
5014 NEXT; |
|
5015 } else if (RAW == '+') { |
|
5016 cur->ocur = XML_ELEMENT_CONTENT_PLUS; |
|
5017 NEXT; |
|
5018 } else { |
|
5019 cur->ocur = XML_ELEMENT_CONTENT_ONCE; |
|
5020 } |
|
5021 GROW; |
|
5022 } |
|
5023 |
|
5024 SKIP_BLANKS; |
|
5025 SHRINK; |
|
5026 |
|
5027 while (RAW != ')') |
|
5028 { |
|
5029 /* |
|
5030 * Each loop we parse one separator and one element. |
|
5031 */ |
|
5032 if (RAW == ',') |
|
5033 { |
|
5034 if (type == 0){ |
|
5035 type = CUR; |
|
5036 } |
|
5037 /* |
|
5038 * Detect "Name | Name , Name" error |
|
5039 */ |
|
5040 else if (type != CUR) |
|
5041 { |
|
5042 xmlFatalErrMsgInt(ctxt, XML_ERR_SEPARATOR_REQUIRED, |
|
5043 EMBED_ERRTXT("xmlParseElementChildrenContentDecl : '%c' expected\n"), |
|
5044 type); |
|
5045 if ((last != NULL) && (last != ret)) |
|
5046 xmlFreeElementContent(last); |
|
5047 if (ret != NULL) |
|
5048 xmlFreeElementContent(ret); |
|
5049 return(NULL); |
|
5050 } |
|
5051 |
|
5052 NEXT; |
|
5053 |
|
5054 op = xmlNewElementContent(NULL, XML_ELEMENT_CONTENT_SEQ); |
|
5055 if (op == NULL) { |
|
5056 if ((last != NULL) && (last != ret)) |
|
5057 xmlFreeElementContent(last); |
|
5058 xmlFreeElementContent(ret); |
|
5059 return(NULL); |
|
5060 } |
|
5061 if (last == NULL) { |
|
5062 op->c1 = ret; |
|
5063 if (ret != NULL) |
|
5064 ret->parent = op; |
|
5065 ret = cur = op; |
|
5066 } else { |
|
5067 cur->c2 = op; |
|
5068 if (op != NULL) |
|
5069 op->parent = cur; |
|
5070 op->c1 = last; |
|
5071 if (last != NULL) |
|
5072 last->parent = op; |
|
5073 cur =op; |
|
5074 last = NULL; |
|
5075 } |
|
5076 } |
|
5077 else if (RAW == '|') |
|
5078 { |
|
5079 |
|
5080 if (type == 0){ |
|
5081 type = CUR; |
|
5082 } |
|
5083 /* |
|
5084 * Detect "Name , Name | Name" error |
|
5085 */ |
|
5086 else if (type != CUR) { |
|
5087 xmlFatalErrMsgInt(ctxt, XML_ERR_SEPARATOR_REQUIRED, |
|
5088 EMBED_ERRTXT("xmlParseElementChildrenContentDecl : '%c' expected\n"), |
|
5089 type); |
|
5090 if ((last != NULL) && (last != ret)) |
|
5091 xmlFreeElementContent(last); |
|
5092 if (ret != NULL) |
|
5093 xmlFreeElementContent(ret); |
|
5094 return(NULL); |
|
5095 } |
|
5096 NEXT; |
|
5097 |
|
5098 op = xmlNewElementContent(NULL, XML_ELEMENT_CONTENT_OR); |
|
5099 if (op == NULL) { |
|
5100 if ((last != NULL) && (last != ret)) |
|
5101 xmlFreeElementContent(last); |
|
5102 if (ret != NULL) |
|
5103 xmlFreeElementContent(ret); |
|
5104 return(NULL); |
|
5105 } |
|
5106 if (last == NULL) { |
|
5107 op->c1 = ret; |
|
5108 if (ret != NULL) |
|
5109 ret->parent = op; |
|
5110 ret = cur = op; |
|
5111 } else { |
|
5112 cur->c2 = op; |
|
5113 if (op != NULL) |
|
5114 op->parent = cur; |
|
5115 op->c1 = last; |
|
5116 if (last != NULL) |
|
5117 last->parent = op; |
|
5118 cur =op; |
|
5119 last = NULL; |
|
5120 } |
|
5121 } else { |
|
5122 // RAW is not ',' or '|' |
|
5123 xmlFatalErr(ctxt, XML_ERR_ELEMCONTENT_NOT_FINISHED, NULL); |
|
5124 if (ret != NULL) |
|
5125 xmlFreeElementContent(ret); |
|
5126 return(NULL); |
|
5127 } |
|
5128 |
|
5129 GROW; |
|
5130 SKIP_BLANKS; |
|
5131 GROW; |
|
5132 if (RAW == '(') |
|
5133 { |
|
5134 int inputid = ctxt->input->id; |
|
5135 /* Recurse on second child */ |
|
5136 NEXT; |
|
5137 SKIP_BLANKS; |
|
5138 last = xmlParseElementChildrenContentDecl(ctxt, inputid); |
|
5139 SKIP_BLANKS; |
|
5140 } |
|
5141 else |
|
5142 { |
|
5143 elem = xmlParseName(ctxt); |
|
5144 if (elem == NULL) { |
|
5145 xmlFatalErr(ctxt, XML_ERR_ELEMCONTENT_NOT_STARTED, NULL); |
|
5146 if (ret != NULL) |
|
5147 xmlFreeElementContent(ret); |
|
5148 return(NULL); |
|
5149 } |
|
5150 last = xmlNewElementContent(elem, XML_ELEMENT_CONTENT_ELEMENT); |
|
5151 if(!last) |
|
5152 { // OOM |
|
5153 if (ret != NULL) |
|
5154 { |
|
5155 xmlFreeElementContent(ret); |
|
5156 } |
|
5157 xmlParserOOMErr(ctxt); |
|
5158 return(NULL); |
|
5159 } |
|
5160 |
|
5161 if (RAW == '?') { |
|
5162 last->ocur = XML_ELEMENT_CONTENT_OPT; |
|
5163 NEXT; |
|
5164 } else if (RAW == '*') { |
|
5165 last->ocur = XML_ELEMENT_CONTENT_MULT; |
|
5166 NEXT; |
|
5167 } else if (RAW == '+') { |
|
5168 last->ocur = XML_ELEMENT_CONTENT_PLUS; |
|
5169 NEXT; |
|
5170 } else { |
|
5171 last->ocur = XML_ELEMENT_CONTENT_ONCE; |
|
5172 } |
|
5173 } |
|
5174 SKIP_BLANKS; |
|
5175 GROW; |
|
5176 } // end of while (RAW != ')') |
|
5177 |
|
5178 //============================================================ |
|
5179 if ((cur != NULL) && (last != NULL)) { |
|
5180 cur->c2 = last; |
|
5181 if (last != NULL) |
|
5182 last->parent = cur; |
|
5183 } |
|
5184 if ((ctxt->validate) && (ctxt->input->id != inputchk)) |
|
5185 { |
|
5186 xmlValidityError(ctxt, XML_ERR_ENTITY_BOUNDARY, |
|
5187 EMBED_ERRTXT("Element content declaration doesn't start and stop in the same entity\n"), |
|
5188 NULL); |
|
5189 } |
|
5190 NEXT; |
|
5191 |
|
5192 if (RAW == '?') |
|
5193 { |
|
5194 if (ret != NULL) { |
|
5195 if ((ret->ocur == XML_ELEMENT_CONTENT_PLUS) || |
|
5196 (ret->ocur == XML_ELEMENT_CONTENT_MULT)) |
|
5197 ret->ocur = XML_ELEMENT_CONTENT_MULT; |
|
5198 else |
|
5199 ret->ocur = XML_ELEMENT_CONTENT_OPT; |
|
5200 } |
|
5201 NEXT; |
|
5202 } |
|
5203 else if (RAW == '*') |
|
5204 { |
|
5205 if (ret != NULL) |
|
5206 { |
|
5207 ret->ocur = XML_ELEMENT_CONTENT_MULT; |
|
5208 cur = ret; |
|
5209 /* |
|
5210 * Some normalization: |
|
5211 * (a | b* | c?)* == (a | b | c)* |
|
5212 */ |
|
5213 while (cur->type == XML_ELEMENT_CONTENT_OR) |
|
5214 { |
|
5215 if ((cur->c1 != NULL) && |
|
5216 ((cur->c1->ocur == XML_ELEMENT_CONTENT_OPT) || |
|
5217 (cur->c1->ocur == XML_ELEMENT_CONTENT_MULT))) |
|
5218 { |
|
5219 cur->c1->ocur = XML_ELEMENT_CONTENT_ONCE; |
|
5220 } |
|
5221 if((cur->c2 != NULL) && |
|
5222 ((cur->c2->ocur == XML_ELEMENT_CONTENT_OPT) || |
|
5223 (cur->c2->ocur == XML_ELEMENT_CONTENT_MULT))) |
|
5224 { |
|
5225 cur->c2->ocur = XML_ELEMENT_CONTENT_ONCE; |
|
5226 } |
|
5227 cur = cur->c2; |
|
5228 } |
|
5229 } |
|
5230 NEXT; |
|
5231 } |
|
5232 else if (RAW == '+') |
|
5233 { |
|
5234 if (ret != NULL) |
|
5235 { |
|
5236 int found = 0; |
|
5237 |
|
5238 if ((ret->ocur == XML_ELEMENT_CONTENT_OPT) || |
|
5239 (ret->ocur == XML_ELEMENT_CONTENT_MULT)) |
|
5240 { |
|
5241 ret->ocur = XML_ELEMENT_CONTENT_MULT; |
|
5242 } |
|
5243 else |
|
5244 { |
|
5245 ret->ocur = XML_ELEMENT_CONTENT_PLUS; |
|
5246 } |
|
5247 /* |
|
5248 * Some normalization: |
|
5249 * (a | b*)+ == (a | b)* |
|
5250 * (a | b?)+ == (a | b)* |
|
5251 */ |
|
5252 while (cur->type == XML_ELEMENT_CONTENT_OR) |
|
5253 { |
|
5254 if ((cur->c1 != NULL) && |
|
5255 ((cur->c1->ocur == XML_ELEMENT_CONTENT_OPT) || |
|
5256 (cur->c1->ocur == XML_ELEMENT_CONTENT_MULT))) |
|
5257 { |
|
5258 cur->c1->ocur = XML_ELEMENT_CONTENT_ONCE; |
|
5259 found = 1; |
|
5260 } |
|
5261 if ((cur->c2 != NULL) && |
|
5262 ((cur->c2->ocur == XML_ELEMENT_CONTENT_OPT) || |
|
5263 (cur->c2->ocur == XML_ELEMENT_CONTENT_MULT))) |
|
5264 { |
|
5265 cur->c2->ocur = XML_ELEMENT_CONTENT_ONCE; |
|
5266 found = 1; |
|
5267 } |
|
5268 cur = cur->c2; |
|
5269 } |
|
5270 if (found) |
|
5271 ret->ocur = XML_ELEMENT_CONTENT_MULT; |
|
5272 } |
|
5273 NEXT; |
|
5274 } |
|
5275 return(ret); |
|
5276 } |
|
5277 |
|
5278 /** |
|
5279 * xmlParseElementContentDecl: |
|
5280 * @param ctxt an XML parser context |
|
5281 * @param name the name of the element being defined. |
|
5282 * @param result the Element Content pointer will be stored here if any |
|
5283 * |
|
5284 * parse the declaration for an Element content either Mixed or Children, |
|
5285 * the cases EMPTY and ANY are handled directly in xmlParseElementDecl |
|
5286 * |
|
5287 * [46] contentspec ::= 'EMPTY' | 'ANY' | Mixed | children |
|
5288 * |
|
5289 * returns: the type of element content XML_ELEMENT_TYPE_xxx or -1 if error |
|
5290 */ |
|
5291 |
|
5292 XMLPUBFUNEXPORT int |
|
5293 xmlParseElementContentDecl(xmlParserCtxtPtr ctxt, const xmlChar *name, |
|
5294 xmlElementContentPtr *result) { |
|
5295 |
|
5296 xmlElementContentPtr tree = NULL; |
|
5297 int inputid = ctxt->input->id; |
|
5298 int res; |
|
5299 LOAD_GS_SAFE_CTXT(ctxt) |
|
5300 |
|
5301 *result = NULL; |
|
5302 |
|
5303 if (RAW != '(') { |
|
5304 xmlFatalErrMsgStr(ctxt, XML_ERR_ELEMCONTENT_NOT_STARTED, |
|
5305 EMBED_ERRTXT("xmlParseElementContentDecl : %s '(' expected\n"), name); |
|
5306 return(-1); |
|
5307 } |
|
5308 NEXT; |
|
5309 GROW; |
|
5310 SKIP_BLANKS; |
|
5311 if (CMP7(CUR_PTR, '#', 'P', 'C', 'D', 'A', 'T', 'A')) |
|
5312 { |
|
5313 tree = xmlParseElementMixedContentDecl(ctxt, inputid); |
|
5314 if(OOM_FLAG) |
|
5315 { |
|
5316 return(-1); |
|
5317 } |
|
5318 res = XML_ELEMENT_TYPE_MIXED; |
|
5319 } |
|
5320 else |
|
5321 { |
|
5322 tree = xmlParseElementChildrenContentDecl(ctxt, inputid); |
|
5323 if(OOM_FLAG) |
|
5324 { |
|
5325 return(-1); |
|
5326 } |
|
5327 res = XML_ELEMENT_TYPE_ELEMENT; |
|
5328 } |
|
5329 SKIP_BLANKS; |
|
5330 *result = tree; |
|
5331 return(res); |
|
5332 } |
|
5333 |
|
5334 /** |
|
5335 * xmlParseElementDecl: |
|
5336 * @param ctxt an XML parser context |
|
5337 * |
|
5338 * parse an Element declaration. |
|
5339 * |
|
5340 * [45] elementdecl ::= '<!ELEMENT' S Name S contentspec S? '>' |
|
5341 * |
|
5342 * [ VC: Unique Element Type Declaration ] |
|
5343 * No element type may be declared more than once |
|
5344 * |
|
5345 * Returns the type of the element, or -1 in case of error |
|
5346 */ |
|
5347 XMLPUBFUNEXPORT int |
|
5348 xmlParseElementDecl(xmlParserCtxtPtr ctxt) { |
|
5349 const xmlChar *name; |
|
5350 int ret = -1; |
|
5351 xmlElementContentPtr content = NULL; |
|
5352 |
|
5353 GROW; |
|
5354 if (CMP9(CUR_PTR, '<', '!', 'E', 'L', 'E', 'M', 'E', 'N', 'T')) { |
|
5355 xmlParserInputPtr input = ctxt->input; |
|
5356 |
|
5357 SKIP(9); |
|
5358 if (!IS_BLANK_CH(CUR)) { |
|
5359 xmlFatalErrMsg(ctxt, XML_ERR_SPACE_REQUIRED, |
|
5360 EMBED_ERRTXT("Space required after 'ELEMENT'\n")); |
|
5361 } |
|
5362 SKIP_BLANKS; |
|
5363 name = xmlParseName(ctxt); |
|
5364 if (name == NULL) { |
|
5365 xmlFatalErrMsg(ctxt, XML_ERR_NAME_REQUIRED, |
|
5366 EMBED_ERRTXT("xmlParseElementDecl: no name for Element\n")); |
|
5367 return(-1); |
|
5368 } |
|
5369 while ((RAW == 0) && (ctxt->inputNr > 1)) |
|
5370 xmlPopInput(ctxt); |
|
5371 if (!IS_BLANK_CH(CUR)) { |
|
5372 xmlFatalErrMsg(ctxt, XML_ERR_SPACE_REQUIRED, |
|
5373 EMBED_ERRTXT("Space required after the element name\n")); |
|
5374 } |
|
5375 SKIP_BLANKS; |
|
5376 if (CMP5(CUR_PTR, 'E', 'M', 'P', 'T', 'Y')) { |
|
5377 SKIP(5); |
|
5378 /* |
|
5379 * Element must always be empty. |
|
5380 */ |
|
5381 ret = XML_ELEMENT_TYPE_EMPTY; |
|
5382 } else if ((RAW == 'A') && (NXT(1) == 'N') && |
|
5383 (NXT(2) == 'Y')) { |
|
5384 SKIP(3); |
|
5385 /* |
|
5386 * Element is a generic container. |
|
5387 */ |
|
5388 ret = XML_ELEMENT_TYPE_ANY; |
|
5389 } else if (RAW == '(') |
|
5390 { |
|
5391 ret = xmlParseElementContentDecl(ctxt, name, &content); |
|
5392 if(ret == -1) |
|
5393 { |
|
5394 return ret /* -1 */; |
|
5395 } |
|
5396 } |
|
5397 else { |
|
5398 /* |
|
5399 * [ WFC: PEs in Internal Subset ] error handling. |
|
5400 */ |
|
5401 if ((RAW == '%') && |
|
5402 (ctxt->external == 0) && |
|
5403 (ctxt->inputNr == 1)) |
|
5404 { |
|
5405 xmlFatalErrMsg(ctxt, XML_ERR_PEREF_IN_INT_SUBSET, |
|
5406 EMBED_ERRTXT("PEReference: forbidden within markup decl in internal subset\n")); |
|
5407 } else { |
|
5408 xmlFatalErrMsg(ctxt, XML_ERR_ELEMCONTENT_NOT_STARTED, |
|
5409 EMBED_ERRTXT("xmlParseElementDecl: 'EMPTY', 'ANY' or '(' expected\n")); |
|
5410 } |
|
5411 return(-1); |
|
5412 } |
|
5413 |
|
5414 SKIP_BLANKS; |
|
5415 /* |
|
5416 * Pop-up of finished entities. |
|
5417 */ |
|
5418 while ((RAW == 0) && (ctxt->inputNr > 1)) |
|
5419 xmlPopInput(ctxt); |
|
5420 SKIP_BLANKS; |
|
5421 |
|
5422 if (RAW != '>') { |
|
5423 xmlFatalErr(ctxt, XML_ERR_GT_REQUIRED, NULL); |
|
5424 } else { |
|
5425 if (input != ctxt->input) { |
|
5426 xmlFatalErrMsg(ctxt, XML_ERR_ENTITY_BOUNDARY, |
|
5427 EMBED_ERRTXT("Element declaration doesn't start and stop in the same entity\n")); |
|
5428 } |
|
5429 |
|
5430 NEXT; |
|
5431 if ((ctxt->sax != NULL) && (!ctxt->disableSAX) && |
|
5432 (ctxt->sax->elementDecl != NULL)) |
|
5433 ctxt->sax->elementDecl(ctxt->userData, name, ret, |
|
5434 content); |
|
5435 } |
|
5436 if (content != NULL) { |
|
5437 xmlFreeElementContent(content); |
|
5438 } |
|
5439 } |
|
5440 return(ret); |
|
5441 } |
|
5442 |
|
5443 /** |
|
5444 * xmlParseConditionalSections |
|
5445 * @param ctxt an XML parser context |
|
5446 * |
|
5447 * [61] conditionalSect ::= includeSect | ignoreSect |
|
5448 * [62] includeSect ::= '<![' S? 'INCLUDE' S? '[' extSubsetDecl ']]>' |
|
5449 * [63] ignoreSect ::= '<![' S? 'IGNORE' S? '[' ignoreSectContents* ']]>' |
|
5450 * [64] ignoreSectContents ::= Ignore ('<![' ignoreSectContents ']]>' Ignore)* |
|
5451 * [65] Ignore ::= Char* - (Char* ('<![' | ']]>') Char*) |
|
5452 */ |
|
5453 |
|
5454 static void |
|
5455 xmlParseConditionalSections(xmlParserCtxtPtr ctxt) { |
|
5456 LOAD_GS_SAFE_CTXT(ctxt) |
|
5457 SKIP(3); |
|
5458 SKIP_BLANKS; |
|
5459 if (CMP7(CUR_PTR, 'I', 'N', 'C', 'L', 'U', 'D', 'E')) { |
|
5460 SKIP(7); |
|
5461 SKIP_BLANKS; |
|
5462 if (RAW != '[') { |
|
5463 xmlFatalErr(ctxt, XML_ERR_CONDSEC_INVALID, NULL); |
|
5464 } else { |
|
5465 NEXT; |
|
5466 } |
|
5467 if (xmlParserDebugEntities) { |
|
5468 if ((ctxt->input != NULL) && (ctxt->input->filename)) |
|
5469 xmlGenericError(xmlGenericErrorContext, |
|
5470 EMBED_ERRTXT("%s(%d): "), ctxt->input->filename, |
|
5471 ctxt->input->line); |
|
5472 xmlGenericError(xmlGenericErrorContext, |
|
5473 EMBED_ERRTXT("Entering INCLUDE Conditional Section\n")); |
|
5474 } |
|
5475 |
|
5476 while ((RAW != 0) && ((RAW != ']') || (NXT(1) != ']') || |
|
5477 (NXT(2) != '>'))) { |
|
5478 const xmlChar *check = CUR_PTR; |
|
5479 unsigned int cons = ctxt->input->consumed; |
|
5480 |
|
5481 if ((RAW == '<') && (NXT(1) == '!') && (NXT(2) == '[')) { |
|
5482 xmlParseConditionalSections(ctxt); |
|
5483 } else if (IS_BLANK_CH(CUR)) { |
|
5484 NEXT; |
|
5485 } else if (RAW == '%') { |
|
5486 xmlParsePEReference(ctxt); |
|
5487 } else |
|
5488 xmlParseMarkupDecl(ctxt); |
|
5489 |
|
5490 /* |
|
5491 * Pop-up of finished entities. |
|
5492 */ |
|
5493 while ((RAW == 0) && (ctxt->inputNr > 1)) |
|
5494 xmlPopInput(ctxt); |
|
5495 |
|
5496 if ((CUR_PTR == check) && (cons == ctxt->input->consumed)) { |
|
5497 xmlFatalErr(ctxt, XML_ERR_EXT_SUBSET_NOT_FINISHED, NULL); |
|
5498 break; |
|
5499 } |
|
5500 } |
|
5501 if (xmlParserDebugEntities) { |
|
5502 if ((ctxt->input != NULL) && (ctxt->input->filename)) |
|
5503 xmlGenericError(xmlGenericErrorContext, |
|
5504 EMBED_ERRTXT("%s(%d): "), ctxt->input->filename, |
|
5505 ctxt->input->line); |
|
5506 xmlGenericError(xmlGenericErrorContext, |
|
5507 EMBED_ERRTXT("Leaving INCLUDE Conditional Section\n")); |
|
5508 } |
|
5509 |
|
5510 } else if (CMP6(CUR_PTR, 'I', 'G', 'N', 'O', 'R', 'E')) { |
|
5511 int state; |
|
5512 xmlParserInputState instate; |
|
5513 int depth = 0; |
|
5514 |
|
5515 SKIP(6); |
|
5516 SKIP_BLANKS; |
|
5517 if (RAW != '[') { |
|
5518 xmlFatalErr(ctxt, XML_ERR_CONDSEC_INVALID, NULL); |
|
5519 } else { |
|
5520 NEXT; |
|
5521 } |
|
5522 if (xmlParserDebugEntities) { |
|
5523 if ((ctxt->input != NULL) && (ctxt->input->filename)) |
|
5524 xmlGenericError(xmlGenericErrorContext, |
|
5525 EMBED_ERRTXT("%s(%d): "), ctxt->input->filename, |
|
5526 ctxt->input->line); |
|
5527 xmlGenericError(xmlGenericErrorContext, |
|
5528 EMBED_ERRTXT("Entering IGNORE Conditional Section\n")); |
|
5529 } |
|
5530 |
|
5531 /* |
|
5532 * Parse up to the end of the conditional section |
|
5533 * But disable SAX event generating DTD building in the meantime |
|
5534 */ |
|
5535 state = ctxt->disableSAX; |
|
5536 instate = ctxt->instate; |
|
5537 if (ctxt->recovery == 0) ctxt->disableSAX = 1; |
|
5538 ctxt->instate = XML_PARSER_IGNORE; |
|
5539 |
|
5540 while ((depth >= 0) && (RAW != 0)) { |
|
5541 if ((RAW == '<') && (NXT(1) == '!') && (NXT(2) == '[')) { |
|
5542 depth++; |
|
5543 SKIP(3); |
|
5544 continue; |
|
5545 } |
|
5546 if ((RAW == ']') && (NXT(1) == ']') && (NXT(2) == '>')) { |
|
5547 if (--depth >= 0) SKIP(3); |
|
5548 continue; |
|
5549 } |
|
5550 NEXT; |
|
5551 continue; |
|
5552 } |
|
5553 |
|
5554 ctxt->disableSAX = state; |
|
5555 ctxt->instate = instate; |
|
5556 |
|
5557 if (xmlParserDebugEntities) { |
|
5558 if ((ctxt->input != NULL) && (ctxt->input->filename)) |
|
5559 xmlGenericError(xmlGenericErrorContext, |
|
5560 EMBED_ERRTXT("%s(%d): "), ctxt->input->filename, |
|
5561 ctxt->input->line); |
|
5562 xmlGenericError(xmlGenericErrorContext, |
|
5563 EMBED_ERRTXT("Leaving IGNORE Conditional Section\n")); |
|
5564 } |
|
5565 |
|
5566 } else { |
|
5567 xmlFatalErr(ctxt, XML_ERR_CONDSEC_INVALID_KEYWORD, NULL); |
|
5568 } |
|
5569 |
|
5570 if (RAW == 0) |
|
5571 SHRINK; |
|
5572 |
|
5573 if (RAW == 0) { |
|
5574 xmlFatalErr(ctxt, XML_ERR_CONDSEC_NOT_FINISHED, NULL); |
|
5575 } else { |
|
5576 SKIP(3); |
|
5577 } |
|
5578 } |
|
5579 |
|
5580 /** |
|
5581 * xmlParseMarkupDecl: |
|
5582 * @param ctxt an XML parser context |
|
5583 * |
|
5584 * parse Markup declarations |
|
5585 * |
|
5586 * [29] markupdecl ::= elementdecl | AttlistDecl | EntityDecl | |
|
5587 * NotationDecl | PI | Comment |
|
5588 * |
|
5589 * [ VC: Proper Declaration/PE Nesting ] |
|
5590 * Parameter-entity replacement text must be properly nested with |
|
5591 * markup declarations. That is to say, if either the first character |
|
5592 * or the last character of a markup declaration (markupdecl above) is |
|
5593 * contained in the replacement text for a parameter-entity reference, |
|
5594 * both must be contained in the same replacement text. |
|
5595 * |
|
5596 * [ WFC: PEs in Internal Subset ] |
|
5597 * In the internal DTD subset, parameter-entity references can occur |
|
5598 * only where markup declarations can occur, not within markup declarations. |
|
5599 * (This does not apply to references that occur in external parameter |
|
5600 * entities or to the external subset.) |
|
5601 */ |
|
5602 XMLPUBFUNEXPORT void |
|
5603 xmlParseMarkupDecl(xmlParserCtxtPtr ctxt) { |
|
5604 LOAD_GS_SAFE_CTXT(ctxt) |
|
5605 GROW; |
|
5606 if( (xmlParseElementDecl(ctxt) == -1) && OOM_FLAG) |
|
5607 { |
|
5608 return; |
|
5609 } |
|
5610 xmlParseAttributeListDecl(ctxt); |
|
5611 xmlParseEntityDecl(ctxt); |
|
5612 xmlParseNotationDecl(ctxt); |
|
5613 xmlParsePI(ctxt); |
|
5614 xmlParseComment(ctxt); |
|
5615 /* |
|
5616 * This is only for internal subset. On external entities, |
|
5617 * the replacement is done before parsing stage |
|
5618 */ |
|
5619 if ((ctxt->external == 0) && (ctxt->inputNr == 1)) |
|
5620 xmlParsePEReference(ctxt); |
|
5621 |
|
5622 /* |
|
5623 * Conditional sections are allowed from entities included |
|
5624 * by PE References in the internal subset. |
|
5625 */ |
|
5626 if ((ctxt->external == 0) && (ctxt->inputNr > 1)) { |
|
5627 if ((RAW == '<') && (NXT(1) == '!') && (NXT(2) == '[')) { |
|
5628 xmlParseConditionalSections(ctxt); |
|
5629 } |
|
5630 } |
|
5631 |
|
5632 ctxt->instate = XML_PARSER_DTD; |
|
5633 } |
|
5634 |
|
5635 /** |
|
5636 * xmlParseTextDecl: |
|
5637 * @param ctxt an XML parser context |
|
5638 * |
|
5639 * parse an XML declaration header for external entities |
|
5640 * |
|
5641 * [77] TextDecl ::= '<?xml' VersionInfo? EncodingDecl S? '?>' |
|
5642 * |
|
5643 * Question: Seems that EncodingDecl is mandatory ? Is that a typo ? |
|
5644 */ |
|
5645 |
|
5646 XMLPUBFUNEXPORT void |
|
5647 xmlParseTextDecl(xmlParserCtxtPtr ctxt) { |
|
5648 xmlChar *version; |
|
5649 const xmlChar *encoding; |
|
5650 |
|
5651 /* |
|
5652 * We know that '<?xml' is here. |
|
5653 */ |
|
5654 if ((CMP5(CUR_PTR, '<', '?', 'x', 'm', 'l')) && (IS_BLANK_CH(NXT(5)))) { |
|
5655 SKIP(5); |
|
5656 } else { |
|
5657 xmlFatalErr(ctxt, XML_ERR_XMLDECL_NOT_STARTED, NULL); |
|
5658 return; |
|
5659 } |
|
5660 |
|
5661 if (!IS_BLANK_CH(CUR)) { |
|
5662 xmlFatalErrMsg(ctxt, XML_ERR_SPACE_REQUIRED, |
|
5663 EMBED_ERRTXT("Space needed after '<?xml'\n")); |
|
5664 } |
|
5665 SKIP_BLANKS; |
|
5666 |
|
5667 /* |
|
5668 * We may have the VersionInfo here. |
|
5669 */ |
|
5670 version = xmlParseVersionInfo(ctxt); |
|
5671 if (version == NULL) |
|
5672 version = xmlCharStrdup(XML_DEFAULT_VERSION); |
|
5673 else { |
|
5674 if (!IS_BLANK_CH(CUR)) { |
|
5675 xmlFatalErrMsg(ctxt, XML_ERR_SPACE_REQUIRED, |
|
5676 EMBED_ERRTXT("Space needed here\n")); |
|
5677 } |
|
5678 } |
|
5679 ctxt->input->version = version; |
|
5680 |
|
5681 /* |
|
5682 * We must have the encoding declaration |
|
5683 */ |
|
5684 encoding = xmlParseEncodingDecl(ctxt); |
|
5685 if (ctxt->errNo == XML_ERR_UNSUPPORTED_ENCODING) { |
|
5686 /* |
|
5687 * The XML REC instructs us to stop parsing right here |
|
5688 */ |
|
5689 return; |
|
5690 } |
|
5691 if ((encoding == NULL) && (ctxt->errNo == XML_ERR_OK)) { |
|
5692 xmlFatalErrMsg(ctxt, XML_ERR_MISSING_ENCODING, |
|
5693 EMBED_ERRTXT("Missing encoding in text declaration\n")); |
|
5694 } |
|
5695 |
|
5696 SKIP_BLANKS; |
|
5697 if ((RAW == '?') && (NXT(1) == '>')) { |
|
5698 SKIP(2); |
|
5699 } else if (RAW == '>') { |
|
5700 /* Deprecated old WD ... */ |
|
5701 xmlFatalErr(ctxt, XML_ERR_XMLDECL_NOT_FINISHED, NULL); |
|
5702 NEXT; |
|
5703 } else { |
|
5704 xmlFatalErr(ctxt, XML_ERR_XMLDECL_NOT_FINISHED, NULL); |
|
5705 MOVETO_ENDTAG(CUR_PTR); |
|
5706 NEXT; |
|
5707 } |
|
5708 } |
|
5709 |
|
5710 /** |
|
5711 * xmlParseExternalSubset: |
|
5712 * @param ctxt an XML parser context |
|
5713 * @param ExternalID the external identifier |
|
5714 * @param SystemID the system identifier (or URL) |
|
5715 * |
|
5716 * parse Markup declarations from an external subset |
|
5717 * |
|
5718 * [30] extSubset ::= textDecl? extSubsetDecl |
|
5719 * |
|
5720 * [31] extSubsetDecl ::= (markupdecl | conditionalSect | PEReference | S) * |
|
5721 */ |
|
5722 XMLPUBFUNEXPORT void |
|
5723 xmlParseExternalSubset(xmlParserCtxtPtr ctxt, const xmlChar *ExternalID, |
|
5724 const xmlChar *SystemID) { |
|
5725 xmlDetectSAX2(ctxt); |
|
5726 GROW; |
|
5727 if (CMP5(CUR_PTR, '<', '?', 'x', 'm', 'l')) { |
|
5728 xmlParseTextDecl(ctxt); |
|
5729 if (ctxt->errNo == XML_ERR_UNSUPPORTED_ENCODING) { |
|
5730 /* |
|
5731 * The XML REC instructs us to stop parsing right here |
|
5732 */ |
|
5733 ctxt->instate = XML_PARSER_EOF; |
|
5734 return; |
|
5735 } |
|
5736 } |
|
5737 if (ctxt->myDoc == NULL) { |
|
5738 ctxt->myDoc = xmlNewDoc(BAD_CAST "1.0"); |
|
5739 } |
|
5740 if ((ctxt->myDoc != NULL) && (ctxt->myDoc->intSubset == NULL)) |
|
5741 xmlCreateIntSubset(ctxt->myDoc, NULL, ExternalID, SystemID); |
|
5742 |
|
5743 ctxt->instate = XML_PARSER_DTD; |
|
5744 ctxt->external = 1; |
|
5745 while (((RAW == '<') && (NXT(1) == '?')) || |
|
5746 ((RAW == '<') && (NXT(1) == '!')) || |
|
5747 (RAW == '%') || IS_BLANK_CH(CUR)) { |
|
5748 const xmlChar *check = CUR_PTR; |
|
5749 unsigned int cons = ctxt->input->consumed; |
|
5750 |
|
5751 GROW; |
|
5752 if ((RAW == '<') && (NXT(1) == '!') && (NXT(2) == '[')) { |
|
5753 xmlParseConditionalSections(ctxt); |
|
5754 } else if (IS_BLANK_CH(CUR)) { |
|
5755 NEXT; |
|
5756 } else if (RAW == '%') { |
|
5757 xmlParsePEReference(ctxt); |
|
5758 } else |
|
5759 xmlParseMarkupDecl(ctxt); |
|
5760 |
|
5761 /* |
|
5762 * Pop-up of finished entities. |
|
5763 */ |
|
5764 while ((RAW == 0) && (ctxt->inputNr > 1)) |
|
5765 xmlPopInput(ctxt); |
|
5766 |
|
5767 if ((CUR_PTR == check) && (cons == ctxt->input->consumed)) { |
|
5768 xmlFatalErr(ctxt, XML_ERR_EXT_SUBSET_NOT_FINISHED, NULL); |
|
5769 break; |
|
5770 } |
|
5771 } |
|
5772 |
|
5773 if (RAW != 0) { |
|
5774 xmlFatalErr(ctxt, XML_ERR_EXT_SUBSET_NOT_FINISHED, NULL); |
|
5775 } |
|
5776 |
|
5777 } |
|
5778 |
|
5779 /** |
|
5780 * xmlParseReference: |
|
5781 * @param ctxt an XML parser context |
|
5782 * |
|
5783 * parse and handle entity references in content, depending on the SAX |
|
5784 * interface, this may end-up in a call to character() if this is a |
|
5785 * CharRef, a predefined entity, if there is no reference() callback. |
|
5786 * or if the parser was asked to switch to that mode. |
|
5787 * |
|
5788 * [67] Reference ::= EntityRef | CharRef |
|
5789 */ |
|
5790 XMLPUBFUNEXPORT void |
|
5791 xmlParseReference(xmlParserCtxtPtr ctxt) { |
|
5792 xmlEntityPtr ent; |
|
5793 xmlChar *val; |
|
5794 LOAD_GS_SAFE_CTXT(ctxt) |
|
5795 if (RAW != '&') return; |
|
5796 |
|
5797 if (NXT(1) == '#') { |
|
5798 int i = 0; |
|
5799 xmlChar out[10]; |
|
5800 int hex = NXT(2); |
|
5801 int value = xmlParseCharRef(ctxt); |
|
5802 |
|
5803 if (ctxt->charset != XML_CHAR_ENCODING_UTF8) { |
|
5804 /* |
|
5805 * So we are using non-UTF-8 buffers |
|
5806 * Check that the char fit on 8bits, if not |
|
5807 * generate a CharRef. |
|
5808 */ |
|
5809 if (value <= 0xFF) { |
|
5810 out[0] = value; |
|
5811 out[1] = 0; |
|
5812 if ((ctxt->sax != NULL) && (ctxt->sax->characters != NULL) && |
|
5813 (!ctxt->disableSAX)) |
|
5814 ctxt->sax->characters(ctxt->userData, out, 1); |
|
5815 } else { |
|
5816 if ((hex == 'x') || (hex == 'X')) |
|
5817 snprintf((char *)out, sizeof(out), "#x%X", value); |
|
5818 else |
|
5819 snprintf((char *)out, sizeof(out), "#%d", value); |
|
5820 if ((ctxt->sax != NULL) && (ctxt->sax->reference != NULL) && |
|
5821 (!ctxt->disableSAX)) |
|
5822 ctxt->sax->reference(ctxt->userData, out); |
|
5823 } |
|
5824 } else { |
|
5825 /* |
|
5826 * Just encode the value in UTF-8 |
|
5827 */ |
|
5828 COPY_BUF(0 ,out, i, value); |
|
5829 out[i] = 0; |
|
5830 if ((ctxt->sax != NULL) && (ctxt->sax->characters != NULL) && |
|
5831 (!ctxt->disableSAX)) |
|
5832 ctxt->sax->characters(ctxt->userData, out, i); |
|
5833 } |
|
5834 } else { |
|
5835 ent = xmlParseEntityRef(ctxt); |
|
5836 if (ent == NULL) return; |
|
5837 if (!ctxt->wellFormed) |
|
5838 return; |
|
5839 if ((ent->name != NULL) && |
|
5840 (ent->etype != XML_INTERNAL_PREDEFINED_ENTITY)) { |
|
5841 xmlNodePtr list = NULL; |
|
5842 xmlParserErrors ret = XML_ERR_OK; |
|
5843 |
|
5844 |
|
5845 /* |
|
5846 * The first reference to the entity trigger a parsing phase |
|
5847 * where the ent->children is filled with the result from |
|
5848 * the parsing. |
|
5849 */ |
|
5850 if (ent->children == NULL) { |
|
5851 xmlChar *value; |
|
5852 value = ent->content; |
|
5853 |
|
5854 /* |
|
5855 * Check that this entity is well formed |
|
5856 */ |
|
5857 if ((value != NULL) && (value[0] != 0) && |
|
5858 (value[1] == 0) && (value[0] == '<') && |
|
5859 (xmlStrEqual(ent->name, BAD_CAST "lt"))) { |
|
5860 /* |
|
5861 * DONE: get definite answer on this !!! |
|
5862 * Lots of entity decls are used to declare a single |
|
5863 * char |
|
5864 * <!ENTITY lt "<"> |
|
5865 * Which seems to be valid since |
|
5866 * 2.4: The ampersand character (&) and the left angle |
|
5867 * bracket (<) may appear in their literal form only |
|
5868 * when used ... They are also legal within the literal |
|
5869 * entity value of an internal entity declaration;i |
|
5870 * see "4.3.2 Well-Formed Parsed Entities". |
|
5871 * IMHO 2.4 and 4.3.2 are directly in contradiction. |
|
5872 * Looking at the OASIS test suite and James Clark |
|
5873 * tests, this is broken. However the XML REC uses |
|
5874 * it. Is the XML REC not well-formed ???? |
|
5875 * |
|
5876 * |
|
5877 * ANSWER: since lt gt amp .. are already defined, |
|
5878 * this is a redefinition and hence the fact that the |
|
5879 * content is not well balanced is not a Wf error, this |
|
5880 * is lousy but acceptable. |
|
5881 */ |
|
5882 list = xmlNewDocText(ctxt->myDoc, value); |
|
5883 if (list != NULL) { |
|
5884 if ((ent->etype == XML_INTERNAL_GENERAL_ENTITY) && |
|
5885 (ent->children == NULL)) { |
|
5886 ent->children = list; |
|
5887 ent->last = list; |
|
5888 ent->owner = 1; |
|
5889 list->parent = (xmlNodePtr) ent; |
|
5890 } else { |
|
5891 xmlFreeNodeList(list); |
|
5892 } |
|
5893 } else if (list != NULL) { |
|
5894 xmlFreeNodeList(list); |
|
5895 } |
|
5896 } else { |
|
5897 /* |
|
5898 * 4.3.2: An internal general parsed entity is well-formed |
|
5899 * if its replacement text matches the production labeled |
|
5900 * content. |
|
5901 */ |
|
5902 |
|
5903 void *user_data; |
|
5904 /* |
|
5905 * This is a bit hackish but this seems the best |
|
5906 * way to make sure both SAX and DOM entity support |
|
5907 * behaves okay. |
|
5908 */ |
|
5909 if (ctxt->userData == ctxt) |
|
5910 user_data = NULL; |
|
5911 else |
|
5912 user_data = ctxt->userData; |
|
5913 |
|
5914 if (ent->etype == XML_INTERNAL_GENERAL_ENTITY) { |
|
5915 ctxt->depth++; |
|
5916 ret = xmlParseBalancedChunkMemoryInternal(ctxt, |
|
5917 value, user_data, &list); |
|
5918 if(OOM_FLAG) |
|
5919 { |
|
5920 return; |
|
5921 } |
|
5922 ctxt->depth--; |
|
5923 } else if (ent->etype == |
|
5924 XML_EXTERNAL_GENERAL_PARSED_ENTITY) { |
|
5925 ctxt->depth++; |
|
5926 ret = xmlParseExternalEntityPrivate(ctxt->myDoc, ctxt, |
|
5927 ctxt->sax, user_data, ctxt->depth, |
|
5928 ent->URI, ent->ExternalID, &list); |
|
5929 ctxt->depth--; |
|
5930 } else { |
|
5931 ret = XML_ERR_ENTITY_PE_INTERNAL; |
|
5932 xmlErrMsgStr(ctxt, XML_ERR_INTERNAL_ERROR, |
|
5933 EMBED_ERRTXT("invalid entity type found\n"), NULL); |
|
5934 } |
|
5935 if (ret == XML_ERR_ENTITY_LOOP) { |
|
5936 xmlFatalErr(ctxt, XML_ERR_ENTITY_LOOP, NULL); |
|
5937 return; |
|
5938 } else if ((ret == XML_ERR_OK) && (list != NULL)) { |
|
5939 if (((ent->etype == XML_INTERNAL_GENERAL_ENTITY) || |
|
5940 (ent->etype == XML_EXTERNAL_GENERAL_PARSED_ENTITY))&& |
|
5941 (ent->children == NULL)) { |
|
5942 ent->children = list; |
|
5943 if (ctxt->replaceEntities) { |
|
5944 /* |
|
5945 * Prune it directly in the generated document |
|
5946 * except for single text nodes. |
|
5947 */ |
|
5948 if ((list->type == XML_TEXT_NODE) && |
|
5949 (list->next == NULL)) { |
|
5950 list->parent = (xmlNodePtr) ent; |
|
5951 list = NULL; |
|
5952 ent->owner = 1; |
|
5953 } else { |
|
5954 ent->owner = 0; |
|
5955 while (list != NULL) { |
|
5956 list->parent = (xmlNodePtr) ctxt->node; |
|
5957 list->doc = ctxt->myDoc; |
|
5958 if (list->next == NULL) |
|
5959 ent->last = list; |
|
5960 list = list->next; |
|
5961 } |
|
5962 list = ent->children; |
|
5963 #ifdef LIBXML_LEGACY_ENABLED |
|
5964 if (ent->etype == XML_EXTERNAL_GENERAL_PARSED_ENTITY) |
|
5965 xmlAddEntityReference(ent, list, NULL); |
|
5966 #endif /* LIBXML_LEGACY_ENABLED */ |
|
5967 } |
|
5968 } else { |
|
5969 ent->owner = 1; |
|
5970 while (list != NULL) { |
|
5971 list->parent = (xmlNodePtr) ent; |
|
5972 if (list->next == NULL) |
|
5973 ent->last = list; |
|
5974 list = list->next; |
|
5975 } |
|
5976 } |
|
5977 } else { |
|
5978 xmlFreeNodeList(list); |
|
5979 list = NULL; |
|
5980 } |
|
5981 } else if ((ret != XML_ERR_OK) && |
|
5982 (ret != XML_WAR_UNDECLARED_ENTITY)) { |
|
5983 xmlFatalErr(ctxt, ret, NULL); |
|
5984 } else if (list != NULL) { |
|
5985 xmlFreeNodeList(list); |
|
5986 list = NULL; |
|
5987 } |
|
5988 } |
|
5989 } |
|
5990 if ((ctxt->sax != NULL) && (ctxt->sax->reference != NULL) && |
|
5991 (ctxt->replaceEntities == 0) && (!ctxt->disableSAX)) { |
|
5992 /* |
|
5993 * Create a node. |
|
5994 */ |
|
5995 ctxt->sax->reference(ctxt->userData, ent->name); |
|
5996 return; |
|
5997 } else if (ctxt->replaceEntities) { |
|
5998 if ((ctxt->node != NULL) && (ent->children != NULL)) { |
|
5999 /* |
|
6000 * Seems we are generating the DOM content, do |
|
6001 * a simple tree copy for all references except the first |
|
6002 * In the first occurrence list contains the replacement |
|
6003 */ |
|
6004 if ((list == NULL) && (ent->owner == 0)) { |
|
6005 xmlNodePtr nw = NULL, cur, firstChild = NULL; |
|
6006 cur = ent->children; |
|
6007 while (cur != NULL) { |
|
6008 nw = xmlCopyNode(cur, 1); |
|
6009 if (nw != NULL) { |
|
6010 nw->_private = cur->_private; |
|
6011 if (firstChild == NULL){ |
|
6012 firstChild = nw; |
|
6013 } |
|
6014 xmlAddChild(ctxt->node, nw); |
|
6015 } |
|
6016 if (cur == ent->last) |
|
6017 break; |
|
6018 cur = cur->next; |
|
6019 } |
|
6020 #ifdef LIBXML_LEGACY_ENABLED |
|
6021 if (ent->etype == XML_EXTERNAL_GENERAL_PARSED_ENTITY) |
|
6022 xmlAddEntityReference(ent, firstChild, nw); |
|
6023 #endif /* LIBXML_LEGACY_ENABLED */ |
|
6024 } else if (list == NULL) { |
|
6025 xmlNodePtr nw = NULL, cur, next, last, |
|
6026 firstChild = NULL; |
|
6027 /* |
|
6028 * Copy the entity child list and make it the new |
|
6029 * entity child list. The goal is to make sure any |
|
6030 * ID or REF referenced will be the one from the |
|
6031 * document content and not the entity copy. |
|
6032 */ |
|
6033 cur = ent->children; |
|
6034 ent->children = NULL; |
|
6035 last = ent->last; |
|
6036 ent->last = NULL; |
|
6037 while (cur != NULL) { |
|
6038 next = cur->next; |
|
6039 cur->next = NULL; |
|
6040 cur->parent = NULL; |
|
6041 nw = xmlCopyNode(cur, 1); |
|
6042 if (nw != NULL) { |
|
6043 nw->_private = cur->_private; |
|
6044 if (firstChild == NULL){ |
|
6045 firstChild = cur; |
|
6046 } |
|
6047 xmlAddChild((xmlNodePtr) ent, nw); |
|
6048 xmlAddChild(ctxt->node, cur); |
|
6049 } |
|
6050 if (cur == last) |
|
6051 break; |
|
6052 cur = next; |
|
6053 } |
|
6054 ent->owner = 1; |
|
6055 #ifdef LIBXML_LEGACY_ENABLED |
|
6056 if (ent->etype == XML_EXTERNAL_GENERAL_PARSED_ENTITY) |
|
6057 xmlAddEntityReference(ent, firstChild, nw); |
|
6058 #endif /* LIBXML_LEGACY_ENABLED */ |
|
6059 } else { |
|
6060 /* |
|
6061 * the name change is to avoid coalescing of the |
|
6062 * node with a possible previous text one which |
|
6063 * would make ent->children a dangling pointer |
|
6064 */ |
|
6065 if (ent->children->type == XML_TEXT_NODE) |
|
6066 ent->children->name = xmlStrdup(BAD_CAST "nbktext"); |
|
6067 if ((ent->last != ent->children) && |
|
6068 (ent->last->type == XML_TEXT_NODE)) |
|
6069 ent->last->name = xmlStrdup(BAD_CAST "nbktext"); |
|
6070 xmlAddChildList(ctxt->node, ent->children); |
|
6071 } |
|
6072 |
|
6073 /* |
|
6074 * This is to avoid a nasty side effect, see |
|
6075 * characters() in SAX.c |
|
6076 */ |
|
6077 ctxt->nodemem = 0; |
|
6078 ctxt->nodelen = 0; |
|
6079 return; |
|
6080 } else { |
|
6081 /* |
|
6082 * Probably running in SAX mode |
|
6083 */ |
|
6084 xmlParserInputPtr input; |
|
6085 |
|
6086 input = xmlNewEntityInputStream(ctxt, ent); |
|
6087 xmlPushInput(ctxt, input); |
|
6088 if ((ent->etype == XML_EXTERNAL_GENERAL_PARSED_ENTITY) && |
|
6089 (CMP5(CUR_PTR, '<', '?', 'x', 'm', 'l')) && |
|
6090 (IS_BLANK_CH(NXT(5)))) { |
|
6091 xmlParseTextDecl(ctxt); |
|
6092 if (ctxt->errNo == XML_ERR_UNSUPPORTED_ENCODING) { |
|
6093 /* |
|
6094 * The XML REC instructs us to stop parsing right here |
|
6095 */ |
|
6096 ctxt->instate = XML_PARSER_EOF; |
|
6097 return; |
|
6098 } |
|
6099 if (input->standalone == 1) { |
|
6100 xmlFatalErr(ctxt, XML_ERR_EXT_ENTITY_STANDALONE, |
|
6101 NULL); |
|
6102 } |
|
6103 } |
|
6104 return; |
|
6105 } |
|
6106 } |
|
6107 } else { |
|
6108 val = ent->content; |
|
6109 if (val == NULL) return; |
|
6110 /* |
|
6111 * inline the entity. |
|
6112 */ |
|
6113 if ((ctxt->sax != NULL) && (ctxt->sax->characters != NULL) && |
|
6114 (!ctxt->disableSAX)) |
|
6115 ctxt->sax->characters(ctxt->userData, val, xmlStrlen(val)); |
|
6116 } |
|
6117 } |
|
6118 } |
|
6119 |
|
6120 /** |
|
6121 * xmlParseEntityRef: |
|
6122 * @param ctxt an XML parser context |
|
6123 * |
|
6124 * parse ENTITY references declarations |
|
6125 * |
|
6126 * [68] EntityRef ::= '&' Name ';' |
|
6127 * |
|
6128 * [ WFC: Entity Declared ] |
|
6129 * In a document without any DTD, a document with only an internal DTD |
|
6130 * subset which contains no parameter entity references, or a document |
|
6131 * with "standalone='yes'", the Name given in the entity reference |
|
6132 * must match that in an entity declaration, except that well-formed |
|
6133 * documents need not declare any of the following entities: amp, lt, |
|
6134 * gt, apos, quot. The declaration of a parameter entity must precede |
|
6135 * any reference to it. Similarly, the declaration of a general entity |
|
6136 * must precede any reference to it which appears in a default value in an |
|
6137 * attribute-list declaration. Note that if entities are declared in the |
|
6138 * external subset or in external parameter entities, a non-validating |
|
6139 * processor is not obligated to read and process their declarations; |
|
6140 * for such documents, the rule that an entity must be declared is a |
|
6141 * well-formedness constraint only if standalone='yes'. |
|
6142 * |
|
6143 * [ WFC: Parsed Entity ] |
|
6144 * An entity reference must not contain the name of an unparsed entity |
|
6145 * |
|
6146 * Returns the xmlEntityPtr if found, or NULL otherwise. |
|
6147 */ |
|
6148 XMLPUBFUNEXPORT xmlEntityPtr |
|
6149 xmlParseEntityRef(xmlParserCtxtPtr ctxt) { |
|
6150 const xmlChar *name; |
|
6151 xmlEntityPtr ent = NULL; |
|
6152 |
|
6153 GROW; |
|
6154 |
|
6155 if (RAW == '&') { |
|
6156 NEXT; |
|
6157 name = xmlParseName(ctxt); |
|
6158 if (name == NULL) { |
|
6159 xmlFatalErrMsg(ctxt, XML_ERR_NAME_REQUIRED, |
|
6160 EMBED_ERRTXT("xmlParseEntityRef: no name\n")); |
|
6161 } else { |
|
6162 if (RAW == ';') { |
|
6163 NEXT; |
|
6164 /* |
|
6165 * Ask first SAX for entity resolution, otherwise try the |
|
6166 * predefined set. |
|
6167 */ |
|
6168 if (ctxt->sax != NULL) { |
|
6169 if (ctxt->sax->getEntity != NULL) |
|
6170 ent = ctxt->sax->getEntity(ctxt->userData, name); |
|
6171 if ((ctxt->wellFormed == 1 ) && (ent == NULL)) |
|
6172 ent = xmlGetPredefinedEntity(name); |
|
6173 if ((ctxt->wellFormed == 1 ) && (ent == NULL) && |
|
6174 (ctxt->userData==ctxt)) { |
|
6175 ent = xmlSAX2GetEntity(ctxt, name); |
|
6176 } |
|
6177 } |
|
6178 /* |
|
6179 * [ WFC: Entity Declared ] |
|
6180 * In a document without any DTD, a document with only an |
|
6181 * internal DTD subset which contains no parameter entity |
|
6182 * references, or a document with "standalone='yes'", the |
|
6183 * Name given in the entity reference must match that in an |
|
6184 * entity declaration, except that well-formed documents |
|
6185 * need not declare any of the following entities: amp, lt, |
|
6186 * gt, apos, quot. |
|
6187 * The declaration of a parameter entity must precede any |
|
6188 * reference to it. |
|
6189 * Similarly, the declaration of a general entity must |
|
6190 * precede any reference to it which appears in a default |
|
6191 * value in an attribute-list declaration. Note that if |
|
6192 * entities are declared in the external subset or in |
|
6193 * external parameter entities, a non-validating processor |
|
6194 * is not obligated to read and process their declarations; |
|
6195 * for such documents, the rule that an entity must be |
|
6196 * declared is a well-formedness constraint only if |
|
6197 * standalone='yes'. |
|
6198 */ |
|
6199 if (ent == NULL) { |
|
6200 // XML ENGINE: TEST CODE: for disabling "Unknown entity reference" error |
|
6201 //return NULL; |
|
6202 // |
|
6203 if ((ctxt->standalone == 1) || |
|
6204 ((ctxt->hasExternalSubset == 0) && |
|
6205 (ctxt->hasPErefs == 0))) { |
|
6206 xmlFatalErrMsgStr(ctxt, XML_ERR_UNDECLARED_ENTITY, |
|
6207 EMBED_ERRTXT("Entity '%s' not defined\n"), name); |
|
6208 } else { |
|
6209 xmlErrMsgStr(ctxt, XML_WAR_UNDECLARED_ENTITY, |
|
6210 EMBED_ERRTXT("Entity '%s' not defined\n"), name); |
|
6211 } |
|
6212 ctxt->valid = 0; |
|
6213 } |
|
6214 |
|
6215 /* |
|
6216 * [ WFC: Parsed Entity ] |
|
6217 * An entity reference must not contain the name of an |
|
6218 * unparsed entity |
|
6219 */ |
|
6220 else if (ent->etype == XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) { |
|
6221 xmlFatalErrMsgStr(ctxt, XML_ERR_UNPARSED_ENTITY, |
|
6222 EMBED_ERRTXT("Entity reference to unparsed entity %s\n"), name); |
|
6223 } |
|
6224 |
|
6225 /* |
|
6226 * [ WFC: No External Entity References ] |
|
6227 * Attribute values cannot contain direct or indirect |
|
6228 * entity references to external entities. |
|
6229 */ |
|
6230 else if ((ctxt->instate == XML_PARSER_ATTRIBUTE_VALUE) && |
|
6231 (ent->etype == XML_EXTERNAL_GENERAL_PARSED_ENTITY)) { |
|
6232 xmlFatalErrMsgStr(ctxt, XML_ERR_ENTITY_IS_EXTERNAL, |
|
6233 EMBED_ERRTXT("Attribute references external entity '%s'\n"), name); |
|
6234 } |
|
6235 /* |
|
6236 * [ WFC: No < in Attribute Values ] |
|
6237 * The replacement text of any entity referred to directly or |
|
6238 * indirectly in an attribute value (other than "<") must |
|
6239 * not contain a <. |
|
6240 */ |
|
6241 else if ((ctxt->instate == XML_PARSER_ATTRIBUTE_VALUE) && |
|
6242 (ent != NULL) && |
|
6243 (!xmlStrEqual(ent->name, BAD_CAST "lt")) && |
|
6244 (ent->content != NULL) && |
|
6245 (xmlStrchr(ent->content, '<'))) { |
|
6246 xmlFatalErrMsgStr(ctxt, XML_ERR_LT_IN_ATTRIBUTE, |
|
6247 EMBED_ERRTXT("'<' in entity '%s' is not allowed in attributes values\n"), name); |
|
6248 } |
|
6249 |
|
6250 /* |
|
6251 * Internal check, no parameter entities here ... |
|
6252 */ |
|
6253 else { |
|
6254 switch (ent->etype) { |
|
6255 case XML_INTERNAL_PARAMETER_ENTITY: |
|
6256 case XML_EXTERNAL_PARAMETER_ENTITY: |
|
6257 xmlFatalErrMsgStr(ctxt, XML_ERR_ENTITY_IS_PARAMETER, |
|
6258 EMBED_ERRTXT("Attempt to reference the parameter entity '%s'\n"), |
|
6259 name); |
|
6260 break; |
|
6261 default: |
|
6262 break; |
|
6263 } |
|
6264 } |
|
6265 |
|
6266 /* |
|
6267 * [ WFC: No Recursion ] |
|
6268 * A parsed entity must not contain a recursive reference |
|
6269 * to itself, either directly or indirectly. |
|
6270 * Done somewhere else |
|
6271 */ |
|
6272 |
|
6273 } else { |
|
6274 xmlFatalErr(ctxt, XML_ERR_ENTITYREF_SEMICOL_MISSING, NULL); |
|
6275 } |
|
6276 } |
|
6277 } |
|
6278 return(ent); |
|
6279 } |
|
6280 |
|
6281 /** |
|
6282 * xmlParseStringEntityRef: |
|
6283 * @param ctxt an XML parser context |
|
6284 * @param str a pointer to an index in the string |
|
6285 * |
|
6286 * parse ENTITY references declarations, but this version parses it from |
|
6287 * a string value. |
|
6288 * |
|
6289 * [68] EntityRef ::= '&' Name ';' |
|
6290 * |
|
6291 * [ WFC: Entity Declared ] |
|
6292 * In a document without any DTD, a document with only an internal DTD |
|
6293 * subset which contains no parameter entity references, or a document |
|
6294 * with "standalone='yes'", the Name given in the entity reference |
|
6295 * must match that in an entity declaration, except that well-formed |
|
6296 * documents need not declare any of the following entities: amp, lt, |
|
6297 * gt, apos, quot. The declaration of a parameter entity must precede |
|
6298 * any reference to it. Similarly, the declaration of a general entity |
|
6299 * must precede any reference to it which appears in a default value in an |
|
6300 * attribute-list declaration. Note that if entities are declared in the |
|
6301 * external subset or in external parameter entities, a non-validating |
|
6302 * processor is not obligated to read and process their declarations; |
|
6303 * for such documents, the rule that an entity must be declared is a |
|
6304 * well-formedness constraint only if standalone='yes'. |
|
6305 * |
|
6306 * [ WFC: Parsed Entity ] |
|
6307 * An entity reference must not contain the name of an unparsed entity |
|
6308 * |
|
6309 * Returns the xmlEntityPtr if found, or NULL otherwise. The str pointer |
|
6310 * is updated to the current location in the string. |
|
6311 */ |
|
6312 xmlEntityPtr |
|
6313 xmlParseStringEntityRef(xmlParserCtxtPtr ctxt, const xmlChar ** str) { |
|
6314 xmlChar *name; |
|
6315 const xmlChar *ptr; |
|
6316 xmlChar cur; |
|
6317 xmlEntityPtr ent = NULL; |
|
6318 |
|
6319 if ((str == NULL) || (*str == NULL)) |
|
6320 return(NULL); |
|
6321 ptr = *str; |
|
6322 cur = *ptr; |
|
6323 if (cur == '&') { |
|
6324 ptr++; |
|
6325 cur = *ptr; |
|
6326 name = xmlParseStringName(ctxt, &ptr); |
|
6327 if (name == NULL) { |
|
6328 xmlFatalErrMsg(ctxt, XML_ERR_NAME_REQUIRED, EMBED_ERRTXT("xmlParseStringEntityRef: no name\n")); |
|
6329 } else { |
|
6330 if (*ptr == ';') { |
|
6331 ptr++; |
|
6332 /* |
|
6333 * Ask first SAX for entity resolution, otherwise try the |
|
6334 * predefined set. |
|
6335 */ |
|
6336 if (ctxt->sax != NULL) { |
|
6337 if (ctxt->sax->getEntity != NULL) |
|
6338 ent = ctxt->sax->getEntity(ctxt->userData, name); |
|
6339 if (ent == NULL) |
|
6340 ent = xmlGetPredefinedEntity(name); |
|
6341 if ((ent == NULL) && (ctxt->userData==ctxt)) { |
|
6342 ent = xmlSAX2GetEntity(ctxt, name); |
|
6343 } |
|
6344 } |
|
6345 /* |
|
6346 * [ WFC: Entity Declared ] |
|
6347 * In a document without any DTD, a document with only an |
|
6348 * internal DTD subset which contains no parameter entity |
|
6349 * references, or a document with "standalone='yes'", the |
|
6350 * Name given in the entity reference must match that in an |
|
6351 * entity declaration, except that well-formed documents |
|
6352 * need not declare any of the following entities: amp, lt, |
|
6353 * gt, apos, quot. |
|
6354 * The declaration of a parameter entity must precede any |
|
6355 * reference to it. |
|
6356 * Similarly, the declaration of a general entity must |
|
6357 * precede any reference to it which appears in a default |
|
6358 * value in an attribute-list declaration. Note that if |
|
6359 * entities are declared in the external subset or in |
|
6360 * external parameter entities, a non-validating processor |
|
6361 * is not obligated to read and process their declarations; |
|
6362 * for such documents, the rule that an entity must be |
|
6363 * declared is a well-formedness constraint only if |
|
6364 * standalone='yes'. |
|
6365 */ |
|
6366 if (ent == NULL) { |
|
6367 |
|
6368 if ((ctxt->standalone == 1) || |
|
6369 ((ctxt->hasExternalSubset == 0) && (ctxt->hasPErefs == 0))) |
|
6370 { |
|
6371 xmlFatalErrMsgStr( |
|
6372 ctxt, |
|
6373 XML_ERR_UNDECLARED_ENTITY, |
|
6374 EMBED_ERRTXT("Entity '%s' not defined\n"), |
|
6375 name); |
|
6376 } else { |
|
6377 xmlErrMsgStr( |
|
6378 ctxt, |
|
6379 XML_WAR_UNDECLARED_ENTITY, |
|
6380 EMBED_ERRTXT("Entity '%s' not defined\n"), |
|
6381 name); |
|
6382 } |
|
6383 |
|
6384 } |
|
6385 |
|
6386 /* |
|
6387 * [ WFC: Parsed Entity ] |
|
6388 * An entity reference must not contain the name of an |
|
6389 * unparsed entity |
|
6390 */ |
|
6391 else if (ent->etype == XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) { |
|
6392 xmlFatalErrMsgStr(ctxt, XML_ERR_UNPARSED_ENTITY, |
|
6393 EMBED_ERRTXT("Entity reference to unparsed entity %s\n"), name); |
|
6394 } |
|
6395 |
|
6396 /* |
|
6397 * [ WFC: No External Entity References ] |
|
6398 * Attribute values cannot contain direct or indirect |
|
6399 * entity references to external entities. |
|
6400 */ |
|
6401 else if ((ctxt->instate == XML_PARSER_ATTRIBUTE_VALUE) && |
|
6402 (ent->etype == XML_EXTERNAL_GENERAL_PARSED_ENTITY)) { |
|
6403 xmlFatalErrMsgStr(ctxt, XML_ERR_ENTITY_IS_EXTERNAL, |
|
6404 EMBED_ERRTXT("Attribute references external entity '%s'\n"), name); |
|
6405 } |
|
6406 /* |
|
6407 * [ WFC: No < in Attribute Values ] |
|
6408 * The replacement text of any entity referred to directly or |
|
6409 * indirectly in an attribute value (other than "<") must |
|
6410 * not contain a <. |
|
6411 */ |
|
6412 else if ((ctxt->instate == XML_PARSER_ATTRIBUTE_VALUE) && |
|
6413 (ent != NULL) && |
|
6414 (!xmlStrEqual(ent->name, BAD_CAST "lt")) && |
|
6415 (ent->content != NULL) && |
|
6416 (xmlStrchr(ent->content, '<'))) { |
|
6417 xmlFatalErrMsgStr(ctxt, XML_ERR_LT_IN_ATTRIBUTE, |
|
6418 EMBED_ERRTXT("'<' in entity '%s' is not allowed in attributes values\n"), |
|
6419 name); |
|
6420 } |
|
6421 |
|
6422 /* |
|
6423 * Internal check, no parameter entities here ... |
|
6424 */ |
|
6425 else { |
|
6426 switch (ent->etype) { |
|
6427 case XML_INTERNAL_PARAMETER_ENTITY: |
|
6428 case XML_EXTERNAL_PARAMETER_ENTITY: |
|
6429 xmlFatalErrMsgStr(ctxt, XML_ERR_ENTITY_IS_PARAMETER, |
|
6430 EMBED_ERRTXT("Attempt to reference the parameter entity '%s'\n"), |
|
6431 name); |
|
6432 break; |
|
6433 default: |
|
6434 break; |
|
6435 } |
|
6436 } |
|
6437 |
|
6438 /* |
|
6439 * [ WFC: No Recursion ] |
|
6440 * A parsed entity must not contain a recursive reference |
|
6441 * to itself, either directly or indirectly. |
|
6442 * Done somewhere else |
|
6443 */ |
|
6444 |
|
6445 } else { |
|
6446 xmlFatalErr(ctxt, XML_ERR_ENTITYREF_SEMICOL_MISSING, NULL); |
|
6447 } |
|
6448 xmlFree(name); |
|
6449 } |
|
6450 } |
|
6451 *str = ptr; |
|
6452 return(ent); |
|
6453 } |
|
6454 |
|
6455 /** |
|
6456 * xmlParsePEReference: |
|
6457 * @param ctxt an XML parser context |
|
6458 * |
|
6459 * parse PEReference declarations |
|
6460 * The entity content is handled directly by pushing it's content as |
|
6461 * a new input stream. |
|
6462 * |
|
6463 * [69] PEReference ::= '%' Name ';' |
|
6464 * |
|
6465 * [ WFC: No Recursion ] |
|
6466 * A parsed entity must not contain a recursive |
|
6467 * reference to itself, either directly or indirectly. |
|
6468 * |
|
6469 * [ WFC: Entity Declared ] |
|
6470 * In a document without any DTD, a document with only an internal DTD |
|
6471 * subset which contains no parameter entity references, or a document |
|
6472 * with "standalone='yes'", ... ... The declaration of a parameter |
|
6473 * entity must precede any reference to it... |
|
6474 * |
|
6475 * [ VC: Entity Declared ] |
|
6476 * In a document with an external subset or external parameter entities |
|
6477 * with "standalone='no'", ... ... The declaration of a parameter entity |
|
6478 * must precede any reference to it... |
|
6479 * |
|
6480 * [ WFC: In DTD ] |
|
6481 * Parameter-entity references may only appear in the DTD. |
|
6482 * NOTE: misleading but this is handled. |
|
6483 */ |
|
6484 XMLPUBFUNEXPORT void |
|
6485 xmlParsePEReference(xmlParserCtxtPtr ctxt) |
|
6486 { |
|
6487 const xmlChar *name; |
|
6488 xmlEntityPtr entity = NULL; |
|
6489 xmlParserInputPtr input; |
|
6490 |
|
6491 if (RAW == '%') { |
|
6492 NEXT; |
|
6493 name = xmlParseName(ctxt); |
|
6494 if (name == NULL) { |
|
6495 xmlFatalErrMsg(ctxt, XML_ERR_NAME_REQUIRED, |
|
6496 EMBED_ERRTXT("xmlParsePEReference: no name\n")); |
|
6497 } else { |
|
6498 if (RAW == ';') { |
|
6499 NEXT; |
|
6500 if ((ctxt->sax != NULL) && |
|
6501 (ctxt->sax->getParameterEntity != NULL)) |
|
6502 entity = ctxt->sax->getParameterEntity(ctxt->userData, |
|
6503 name); |
|
6504 if (entity == NULL) { |
|
6505 /* |
|
6506 * [ WFC: Entity Declared ] |
|
6507 * In a document without any DTD, a document with only an |
|
6508 * internal DTD subset which contains no parameter entity |
|
6509 * references, or a document with "standalone='yes'", ... |
|
6510 * ... The declaration of a parameter entity must precede |
|
6511 * any reference to it... |
|
6512 */ |
|
6513 if ((ctxt->standalone == 1) || |
|
6514 ((ctxt->hasExternalSubset == 0) && |
|
6515 (ctxt->hasPErefs == 0))) { |
|
6516 xmlFatalErrMsgStr(ctxt, XML_ERR_UNDECLARED_ENTITY, |
|
6517 EMBED_ERRTXT("PEReference: %%%s; not found\n"), |
|
6518 name); |
|
6519 } else { |
|
6520 /* |
|
6521 * [ VC: Entity Declared ] |
|
6522 * In a document with an external subset or external |
|
6523 * parameter entities with "standalone='no'", ... |
|
6524 * ... The declaration of a parameter entity must |
|
6525 * precede any reference to it... |
|
6526 */ |
|
6527 xmlWarningMsg(ctxt, XML_WAR_UNDECLARED_ENTITY, |
|
6528 EMBED_ERRTXT("PEReference: %%%s; not found\n"), |
|
6529 name, NULL); |
|
6530 ctxt->valid = 0; |
|
6531 } |
|
6532 } else { |
|
6533 /* |
|
6534 * Internal checking in case the entity quest barfed |
|
6535 */ |
|
6536 if ((entity->etype != XML_INTERNAL_PARAMETER_ENTITY) && |
|
6537 (entity->etype != XML_EXTERNAL_PARAMETER_ENTITY)) { |
|
6538 xmlWarningMsg(ctxt, XML_WAR_UNDECLARED_ENTITY, |
|
6539 EMBED_ERRTXT("Internal: %%%s; is not a parameter entity\n"), |
|
6540 name, NULL); |
|
6541 } else if (ctxt->input->free != deallocblankswrapper) { |
|
6542 input = |
|
6543 xmlNewBlanksWrapperInputStream(ctxt, entity); |
|
6544 xmlPushInput(ctxt, input); |
|
6545 } else { |
|
6546 /* |
|
6547 |
|
6548 * handle the extra spaces added before and after |
|
6549 * c.f. http://www.w3.org/TR/REC-xml#as-PE |
|
6550 */ |
|
6551 input = xmlNewEntityInputStream(ctxt, entity); |
|
6552 xmlPushInput(ctxt, input); |
|
6553 if ((entity->etype == XML_EXTERNAL_PARAMETER_ENTITY) && |
|
6554 (CMP5(CUR_PTR, '<', '?', 'x', 'm', 'l')) && |
|
6555 (IS_BLANK_CH(NXT(5)))) { |
|
6556 xmlParseTextDecl(ctxt); |
|
6557 if (ctxt->errNo == |
|
6558 XML_ERR_UNSUPPORTED_ENCODING) { |
|
6559 /* |
|
6560 * The XML REC instructs us to stop parsing |
|
6561 * right here |
|
6562 */ |
|
6563 ctxt->instate = XML_PARSER_EOF; |
|
6564 return; |
|
6565 } |
|
6566 } |
|
6567 } |
|
6568 } |
|
6569 ctxt->hasPErefs = 1; |
|
6570 } else { |
|
6571 xmlFatalErr(ctxt, XML_ERR_ENTITYREF_SEMICOL_MISSING, NULL); |
|
6572 } |
|
6573 } |
|
6574 } |
|
6575 } |
|
6576 |
|
6577 /** |
|
6578 * xmlParseStringPEReference: |
|
6579 * @param ctxt an XML parser context |
|
6580 * @param str a pointer to an index in the string |
|
6581 * |
|
6582 * parse PEReference declarations |
|
6583 * |
|
6584 * [69] PEReference ::= '%' Name ';' |
|
6585 * |
|
6586 * [ WFC: No Recursion ] |
|
6587 * A parsed entity must not contain a recursive |
|
6588 * reference to itself, either directly or indirectly. |
|
6589 * |
|
6590 * [ WFC: Entity Declared ] |
|
6591 * In a document without any DTD, a document with only an internal DTD |
|
6592 * subset which contains no parameter entity references, or a document |
|
6593 * with "standalone='yes'", ... ... The declaration of a parameter |
|
6594 * entity must precede any reference to it... |
|
6595 * |
|
6596 * [ VC: Entity Declared ] |
|
6597 * In a document with an external subset or external parameter entities |
|
6598 * with "standalone='no'", ... ... The declaration of a parameter entity |
|
6599 * must precede any reference to it... |
|
6600 * |
|
6601 * [ WFC: In DTD ] |
|
6602 * Parameter-entity references may only appear in the DTD. |
|
6603 * NOTE: misleading but this is handled. |
|
6604 * |
|
6605 * Returns the string of the entity content. |
|
6606 * str is updated to the current value of the index |
|
6607 */ |
|
6608 xmlEntityPtr |
|
6609 xmlParseStringPEReference(xmlParserCtxtPtr ctxt, const xmlChar **str) { |
|
6610 const xmlChar *ptr; |
|
6611 xmlChar cur; |
|
6612 xmlChar *name; |
|
6613 xmlEntityPtr entity = NULL; |
|
6614 |
|
6615 if ((str == NULL) || (*str == NULL)) return(NULL); |
|
6616 ptr = *str; |
|
6617 cur = *ptr; |
|
6618 if (cur == '%') { |
|
6619 ptr++; |
|
6620 cur = *ptr; |
|
6621 name = xmlParseStringName(ctxt, &ptr); |
|
6622 if (name == NULL) { |
|
6623 xmlFatalErrMsg(ctxt, XML_ERR_NAME_REQUIRED, |
|
6624 EMBED_ERRTXT("xmlParseStringPEReference: no name\n")); |
|
6625 } else { |
|
6626 cur = *ptr; |
|
6627 if (cur == ';') { |
|
6628 ptr++; |
|
6629 cur = *ptr; |
|
6630 if ((ctxt->sax != NULL) && |
|
6631 (ctxt->sax->getParameterEntity != NULL)) |
|
6632 entity = ctxt->sax->getParameterEntity(ctxt->userData, |
|
6633 name); |
|
6634 if (entity == NULL) { |
|
6635 /* |
|
6636 * [ WFC: Entity Declared ] |
|
6637 * In a document without any DTD, a document with only an |
|
6638 * internal DTD subset which contains no parameter entity |
|
6639 * references, or a document with "standalone='yes'", ... |
|
6640 * ... The declaration of a parameter entity must precede |
|
6641 * any reference to it... |
|
6642 */ |
|
6643 if ((ctxt->standalone == 1) || |
|
6644 ((ctxt->hasExternalSubset == 0) && |
|
6645 (ctxt->hasPErefs == 0))) { |
|
6646 xmlFatalErrMsgStr(ctxt, XML_ERR_UNDECLARED_ENTITY, |
|
6647 EMBED_ERRTXT("PEReference: %%%s; not found\n"), name); |
|
6648 } else { |
|
6649 /* |
|
6650 * [ VC: Entity Declared ] |
|
6651 * In a document with an external subset or external |
|
6652 * parameter entities with "standalone='no'", ... |
|
6653 * ... The declaration of a parameter entity must |
|
6654 * precede any reference to it... |
|
6655 */ |
|
6656 xmlWarningMsg(ctxt, XML_WAR_UNDECLARED_ENTITY, |
|
6657 EMBED_ERRTXT("PEReference: %%%s; not found\n"), |
|
6658 name, NULL); |
|
6659 ctxt->valid = 0; |
|
6660 } |
|
6661 } else { |
|
6662 /* |
|
6663 * Internal checking in case the entity quest barfed |
|
6664 */ |
|
6665 if ((entity->etype != XML_INTERNAL_PARAMETER_ENTITY) && |
|
6666 (entity->etype != XML_EXTERNAL_PARAMETER_ENTITY)) { |
|
6667 xmlWarningMsg(ctxt, XML_WAR_UNDECLARED_ENTITY, |
|
6668 EMBED_ERRTXT("%%%s; is not a parameter entity\n"), |
|
6669 name, NULL); |
|
6670 } |
|
6671 } |
|
6672 ctxt->hasPErefs = 1; |
|
6673 } else { |
|
6674 xmlFatalErr(ctxt, XML_ERR_ENTITYREF_SEMICOL_MISSING, NULL); |
|
6675 } |
|
6676 xmlFree(name); |
|
6677 } |
|
6678 } |
|
6679 *str = ptr; |
|
6680 return(entity); |
|
6681 } |
|
6682 |
|
6683 /** |
|
6684 * xmlParseDocTypeDecl: |
|
6685 * @param ctxt an XML parser context |
|
6686 * |
|
6687 * parse a DOCTYPE declaration |
|
6688 * |
|
6689 * [28] doctypedecl ::= '<!DOCTYPE' S Name (S ExternalID)? S? |
|
6690 * ('[' (markupdecl | PEReference | S)* ']' S?)? '>' |
|
6691 * |
|
6692 * [ VC: Root Element Type ] |
|
6693 * The Name in the document type declaration must match the element |
|
6694 * type of the root element. |
|
6695 */ |
|
6696 |
|
6697 XMLPUBFUNEXPORT void |
|
6698 xmlParseDocTypeDecl(xmlParserCtxtPtr ctxt) { |
|
6699 const xmlChar *name = NULL; |
|
6700 xmlChar *ExternalID = NULL; |
|
6701 xmlChar *URI = NULL; |
|
6702 |
|
6703 /* |
|
6704 * We know that '<!DOCTYPE' has been detected. |
|
6705 */ |
|
6706 SKIP(9); |
|
6707 |
|
6708 SKIP_BLANKS; |
|
6709 |
|
6710 /* |
|
6711 * Parse the DOCTYPE name. |
|
6712 */ |
|
6713 name = xmlParseName(ctxt); |
|
6714 if (name == NULL) { |
|
6715 xmlFatalErrMsg(ctxt, XML_ERR_NAME_REQUIRED, |
|
6716 EMBED_ERRTXT("xmlParseDocTypeDecl : no DOCTYPE name !\n")); |
|
6717 } |
|
6718 ctxt->intSubName = name; |
|
6719 |
|
6720 SKIP_BLANKS; |
|
6721 |
|
6722 /* |
|
6723 * Check for SystemID and ExternalID |
|
6724 */ |
|
6725 URI = xmlParseExternalID(ctxt, &ExternalID, 1); |
|
6726 |
|
6727 if ((URI != NULL) || (ExternalID != NULL)) { |
|
6728 ctxt->hasExternalSubset = 1; |
|
6729 } |
|
6730 ctxt->extSubURI = URI; |
|
6731 ctxt->extSubSystem = ExternalID; |
|
6732 |
|
6733 SKIP_BLANKS; |
|
6734 |
|
6735 /* |
|
6736 * Create and update the internal subset. |
|
6737 */ |
|
6738 if ((ctxt->sax != NULL) && (ctxt->sax->internalSubset != NULL) && |
|
6739 (!ctxt->disableSAX)) |
|
6740 ctxt->sax->internalSubset(ctxt->userData, name, ExternalID, URI); |
|
6741 |
|
6742 /* |
|
6743 * Is there any internal subset declarations ? |
|
6744 * they are handled separately in xmlParseInternalSubset() |
|
6745 */ |
|
6746 if (RAW == '[') |
|
6747 return; |
|
6748 |
|
6749 /* |
|
6750 * We should be at the end of the DOCTYPE declaration. |
|
6751 */ |
|
6752 if (RAW != '>') { |
|
6753 xmlFatalErr(ctxt, XML_ERR_DOCTYPE_NOT_FINISHED, NULL); |
|
6754 } |
|
6755 NEXT; |
|
6756 } |
|
6757 |
|
6758 /** |
|
6759 * xmlParseInternalSubset: |
|
6760 * @param ctxt an XML parser context |
|
6761 * |
|
6762 * parse the internal subset declaration |
|
6763 * |
|
6764 * [28 end] ('[' (markupdecl | PEReference | S)* ']' S?)? '>' |
|
6765 */ |
|
6766 |
|
6767 static void |
|
6768 xmlParseInternalSubset(xmlParserCtxtPtr ctxt) { |
|
6769 LOAD_GS_SAFE_CTXT(ctxt) |
|
6770 /* |
|
6771 * Is there any DTD definition ? |
|
6772 */ |
|
6773 if (RAW == '[') { |
|
6774 ctxt->instate = XML_PARSER_DTD; |
|
6775 NEXT; |
|
6776 /* |
|
6777 * Parse the succession of Markup declarations and |
|
6778 * PEReferences. |
|
6779 * Subsequence (markupdecl | PEReference | S)* |
|
6780 */ |
|
6781 while (RAW != ']') { |
|
6782 const xmlChar *check = CUR_PTR; |
|
6783 unsigned int cons = ctxt->input->consumed; |
|
6784 |
|
6785 SKIP_BLANKS; |
|
6786 xmlParseMarkupDecl(ctxt); |
|
6787 if(OOM_FLAG) |
|
6788 { |
|
6789 return; |
|
6790 } |
|
6791 xmlParsePEReference(ctxt); |
|
6792 |
|
6793 /* |
|
6794 * Pop-up of finished entities. |
|
6795 */ |
|
6796 while ((RAW == 0) && (ctxt->inputNr > 1)) |
|
6797 xmlPopInput(ctxt); |
|
6798 |
|
6799 if ((CUR_PTR == check) && (cons == ctxt->input->consumed)) { |
|
6800 xmlFatalErr(ctxt, XML_ERR_INTERNAL_ERROR, |
|
6801 EMBED_ERRTXT("xmlParseInternalSubset: error detected in Markup declaration\n")); |
|
6802 break; |
|
6803 } |
|
6804 } |
|
6805 if (RAW == ']') { |
|
6806 NEXT; |
|
6807 SKIP_BLANKS; |
|
6808 } |
|
6809 } |
|
6810 |
|
6811 /* |
|
6812 * We should be at the end of the DOCTYPE declaration. |
|
6813 */ |
|
6814 if (RAW != '>') { |
|
6815 xmlFatalErr(ctxt, XML_ERR_DOCTYPE_NOT_FINISHED, NULL); |
|
6816 } |
|
6817 NEXT; |
|
6818 } |
|
6819 |
|
6820 #ifdef LIBXML_SAX1_ENABLED |
|
6821 /** |
|
6822 * xmlParseAttribute: |
|
6823 * @param ctxt an XML parser context |
|
6824 * @param value a xmlChar ** used to store the value of the attribute |
|
6825 * |
|
6826 * parse an attribute |
|
6827 * |
|
6828 * [41] Attribute ::= Name Eq AttValue |
|
6829 * |
|
6830 * [ WFC: No External Entity References ] |
|
6831 * Attribute values cannot contain direct or indirect entity references |
|
6832 * to external entities. |
|
6833 * |
|
6834 * [ WFC: No < in Attribute Values ] |
|
6835 * The replacement text of any entity referred to directly or indirectly in |
|
6836 * an attribute value (other than "<") must not contain a <. |
|
6837 * |
|
6838 * [ VC: Attribute Value Type ] |
|
6839 * The attribute must have been declared; the value must be of the type |
|
6840 * declared for it. |
|
6841 * |
|
6842 * [25] Eq ::= S? '=' S? |
|
6843 * |
|
6844 * With namespace: |
|
6845 * |
|
6846 * [NS 11] Attribute ::= QName Eq AttValue |
|
6847 * |
|
6848 * Also the case QName == xmlns:??? is handled independently as a namespace |
|
6849 * definition. |
|
6850 * |
|
6851 * Returns the attribute name, and the value in *value. |
|
6852 */ |
|
6853 |
|
6854 XMLPUBFUNEXPORT const xmlChar * |
|
6855 xmlParseAttribute(xmlParserCtxtPtr ctxt, xmlChar **value) { |
|
6856 const xmlChar *name; |
|
6857 xmlChar *val; |
|
6858 |
|
6859 *value = NULL; |
|
6860 GROW; |
|
6861 name = xmlParseName(ctxt); |
|
6862 if (name == NULL) { |
|
6863 xmlFatalErrMsg(ctxt, XML_ERR_NAME_REQUIRED, EMBED_ERRTXT("error parsing attribute name\n")); |
|
6864 return(NULL); |
|
6865 } |
|
6866 |
|
6867 /* |
|
6868 * read the value |
|
6869 */ |
|
6870 SKIP_BLANKS; |
|
6871 if (RAW == '=') { |
|
6872 NEXT; |
|
6873 SKIP_BLANKS; |
|
6874 val = xmlParseAttValue(ctxt); |
|
6875 ctxt->instate = XML_PARSER_CONTENT; |
|
6876 } else { |
|
6877 xmlFatalErrMsgStr(ctxt, XML_ERR_ATTRIBUTE_WITHOUT_VALUE, |
|
6878 EMBED_ERRTXT("Specification mandate value for attribute %s\n"), name); |
|
6879 return(NULL); |
|
6880 } |
|
6881 |
|
6882 /* |
|
6883 * Check that xml:lang conforms to the specification |
|
6884 * No more registered as an error, just generate a warning now |
|
6885 * since this was deprecated in XML second edition |
|
6886 */ |
|
6887 if ((ctxt->pedantic) && (xmlStrEqual(name, BAD_CAST "xml:lang"))) { |
|
6888 if (!xmlCheckLanguageID(val)) { |
|
6889 xmlWarningMsg(ctxt, XML_WAR_LANG_VALUE, |
|
6890 EMBED_ERRTXT("Malformed value for xml:lang : %s\n"), |
|
6891 val, NULL); |
|
6892 } |
|
6893 } |
|
6894 |
|
6895 /* |
|
6896 * Check that xml:space conforms to the specification |
|
6897 */ |
|
6898 if (xmlStrEqual(name, BAD_CAST "xml:space")) { |
|
6899 if (xmlStrEqual(val, BAD_CAST "default")) |
|
6900 *(ctxt->space) = 0; |
|
6901 else if (xmlStrEqual(val, BAD_CAST "preserve")) |
|
6902 *(ctxt->space) = 1; |
|
6903 else { |
|
6904 xmlFatalErrMsgStr(ctxt, XML_ERR_ATTRIBUTE_WITHOUT_VALUE, |
|
6905 EMBED_ERRTXT("Invalid value \"%s\" for xml:space : \"default\" or \"preserve\" expected\n"), |
|
6906 val); |
|
6907 } |
|
6908 } |
|
6909 |
|
6910 *value = val; |
|
6911 return(name); |
|
6912 } |
|
6913 |
|
6914 /** |
|
6915 * xmlParseStartTag: |
|
6916 * @param ctxt an XML parser context |
|
6917 * |
|
6918 * parse a start of tag either for rule element or |
|
6919 * EmptyElement. In both case we don't parse the tag closing chars. |
|
6920 * |
|
6921 * [40] STag ::= '<' Name (S Attribute)* S? '>' |
|
6922 * |
|
6923 * [ WFC: Unique Att Spec ] |
|
6924 * No attribute name may appear more than once in the same start-tag or |
|
6925 * empty-element tag. |
|
6926 * |
|
6927 * [44] EmptyElemTag ::= '<' Name (S Attribute)* S? '/>' |
|
6928 * |
|
6929 * [ WFC: Unique Att Spec ] |
|
6930 * No attribute name may appear more than once in the same start-tag or |
|
6931 * empty-element tag. |
|
6932 * |
|
6933 * With namespace: |
|
6934 * |
|
6935 * [NS 8] STag ::= '<' QName (S Attribute)* S? '>' |
|
6936 * |
|
6937 * [NS 10] EmptyElement ::= '<' QName (S Attribute)* S? '/>' |
|
6938 * |
|
6939 * Returns the element name parsed |
|
6940 */ |
|
6941 |
|
6942 XMLPUBFUNEXPORT const xmlChar * |
|
6943 xmlParseStartTag(xmlParserCtxtPtr ctxt) { |
|
6944 const xmlChar *name; |
|
6945 const xmlChar *attname; |
|
6946 xmlChar *attvalue; |
|
6947 const xmlChar **atts = ctxt->atts; |
|
6948 int nbatts = 0; |
|
6949 int maxatts = ctxt->maxatts; |
|
6950 int i; |
|
6951 |
|
6952 if (RAW != '<') return(NULL); |
|
6953 NEXT1; |
|
6954 |
|
6955 name = xmlParseName(ctxt); |
|
6956 if (name == NULL) { |
|
6957 xmlFatalErrMsg(ctxt, XML_ERR_NAME_REQUIRED, |
|
6958 EMBED_ERRTXT("xmlParseStartTag: invalid element name\n")); |
|
6959 return(NULL); |
|
6960 } |
|
6961 |
|
6962 /* |
|
6963 * Now parse the attributes, it ends up with the ending |
|
6964 * |
|
6965 * (S Attribute)* S? |
|
6966 */ |
|
6967 SKIP_BLANKS; |
|
6968 GROW; |
|
6969 |
|
6970 while ((RAW != '>') && |
|
6971 ((RAW != '/') || (NXT(1) != '>')) && |
|
6972 (IS_BYTE_CHAR(RAW))) { |
|
6973 const xmlChar *q = CUR_PTR; |
|
6974 unsigned int cons = ctxt->input->consumed; |
|
6975 |
|
6976 attname = xmlParseAttribute(ctxt, &attvalue); |
|
6977 if ((attname != NULL) && (attvalue != NULL)) { |
|
6978 /* |
|
6979 * [ WFC: Unique Att Spec ] |
|
6980 * No attribute name may appear more than once in the same |
|
6981 * start-tag or empty-element tag. |
|
6982 */ |
|
6983 for (i = 0; i < nbatts;i += 2) { |
|
6984 if (xmlStrEqual(atts[i], attname)) { |
|
6985 xmlErrAttributeDup(ctxt, NULL, attname); |
|
6986 xmlFree(attvalue); |
|
6987 goto failed; |
|
6988 } |
|
6989 } |
|
6990 /* |
|
6991 * Add the pair to atts |
|
6992 */ |
|
6993 if (atts == NULL) { |
|
6994 maxatts = 22; /* allow for 10 attrs by default */ |
|
6995 atts = (const xmlChar **) |
|
6996 xmlMalloc(maxatts * sizeof(xmlChar *)); |
|
6997 if (atts == NULL) { |
|
6998 xmlParserOOMErr(ctxt); |
|
6999 if (attvalue != NULL) |
|
7000 xmlFree(attvalue); |
|
7001 goto failed; |
|
7002 } |
|
7003 ctxt->atts = atts; |
|
7004 ctxt->maxatts = maxatts; |
|
7005 } else if (nbatts + 4 > maxatts) { |
|
7006 const xmlChar **n; |
|
7007 |
|
7008 maxatts *= 2; |
|
7009 n = (const xmlChar **) xmlRealloc((void *) atts, |
|
7010 maxatts * sizeof(const xmlChar *)); |
|
7011 if (n == NULL) { |
|
7012 xmlParserOOMErr(ctxt); |
|
7013 if (attvalue != NULL) |
|
7014 xmlFree(attvalue); |
|
7015 goto failed; |
|
7016 } |
|
7017 atts = n; |
|
7018 ctxt->atts = atts; |
|
7019 ctxt->maxatts = maxatts; |
|
7020 } |
|
7021 atts[nbatts++] = attname; |
|
7022 atts[nbatts++] = attvalue; |
|
7023 atts[nbatts] = NULL; |
|
7024 atts[nbatts + 1] = NULL; |
|
7025 } else { |
|
7026 if (attvalue != NULL) |
|
7027 xmlFree(attvalue); |
|
7028 } |
|
7029 |
|
7030 failed: |
|
7031 |
|
7032 GROW |
|
7033 if ((RAW == '>') || (((RAW == '/') && (NXT(1) == '>')))) |
|
7034 break; |
|
7035 if (!IS_BLANK_CH(RAW)) { |
|
7036 xmlFatalErrMsg(ctxt, XML_ERR_SPACE_REQUIRED, |
|
7037 EMBED_ERRTXT("attributes construct error\n")); |
|
7038 } |
|
7039 SKIP_BLANKS; |
|
7040 if ((cons == ctxt->input->consumed) && (q == CUR_PTR) && |
|
7041 (attname == NULL) && (attvalue == NULL)) { |
|
7042 xmlFatalErrMsg(ctxt, XML_ERR_INTERNAL_ERROR, |
|
7043 EMBED_ERRTXT("xmlParseStartTag: problem parsing attributes\n")); |
|
7044 break; |
|
7045 } |
|
7046 SHRINK; |
|
7047 GROW; |
|
7048 } |
|
7049 |
|
7050 /* |
|
7051 * SAX: Start of Element ! |
|
7052 */ |
|
7053 if ((ctxt->sax != NULL) && (ctxt->sax->startElement != NULL) && |
|
7054 (!ctxt->disableSAX)) { |
|
7055 if (nbatts > 0) |
|
7056 ctxt->sax->startElement(ctxt->userData, name, atts); |
|
7057 else |
|
7058 ctxt->sax->startElement(ctxt->userData, name, NULL); |
|
7059 } |
|
7060 |
|
7061 if (atts != NULL) { |
|
7062 /* Free only the content strings */ |
|
7063 for (i = 1;i < nbatts;i+=2) |
|
7064 if (atts[i] != NULL) |
|
7065 xmlFree((xmlChar *) atts[i]); |
|
7066 } |
|
7067 return(name); |
|
7068 } |
|
7069 |
|
7070 /** |
|
7071 * xmlParseEndTag1: |
|
7072 * @param ctxt an XML parser context |
|
7073 * @param line line of the start tag |
|
7074 * @param nsNr number of namespaces on the start tag |
|
7075 * |
|
7076 * parse an end of tag |
|
7077 * |
|
7078 * [42] ETag ::= '</' Name S? '>' |
|
7079 * |
|
7080 * With namespace |
|
7081 * |
|
7082 * [NS 9] ETag ::= '</' QName S? '>' |
|
7083 */ |
|
7084 |
|
7085 static void |
|
7086 xmlParseEndTag1(xmlParserCtxtPtr ctxt, int line) { |
|
7087 const xmlChar *name; |
|
7088 |
|
7089 GROW; |
|
7090 if ((RAW != '<') || (NXT(1) != '/')) { |
|
7091 xmlFatalErrMsg(ctxt, XML_ERR_LTSLASH_REQUIRED, |
|
7092 EMBED_ERRTXT("xmlParseEndTag: '</' not found\n")); |
|
7093 return; |
|
7094 } |
|
7095 SKIP(2); |
|
7096 |
|
7097 name = xmlParseNameAndCompare(ctxt,ctxt->name); |
|
7098 |
|
7099 /* |
|
7100 * We should definitely be at the ending "S? '>'" part |
|
7101 */ |
|
7102 GROW; |
|
7103 SKIP_BLANKS; |
|
7104 if ((!IS_BYTE_CHAR(RAW)) || (RAW != '>')) { |
|
7105 xmlFatalErr(ctxt, XML_ERR_GT_REQUIRED, NULL); |
|
7106 } else |
|
7107 NEXT1; |
|
7108 |
|
7109 /* |
|
7110 * [ WFC: Element Type Match ] |
|
7111 * The Name in an element's end-tag must match the element type in the |
|
7112 * start-tag. |
|
7113 * |
|
7114 */ |
|
7115 if (name != (xmlChar*)1) { |
|
7116 if (name == NULL) name = BAD_CAST "unparseable"; |
|
7117 xmlFatalErrMsgStrIntStr(ctxt, XML_ERR_TAG_NAME_MISMATCH, |
|
7118 EMBED_ERRTXT("Opening and ending tag mismatch: %s line %d and %s\n"), |
|
7119 ctxt->name, line, name); |
|
7120 } |
|
7121 |
|
7122 /* |
|
7123 * SAX: End of Tag |
|
7124 */ |
|
7125 if ((ctxt->sax != NULL) && (ctxt->sax->endElement != NULL) && |
|
7126 (!ctxt->disableSAX)) |
|
7127 ctxt->sax->endElement(ctxt->userData, ctxt->name); |
|
7128 |
|
7129 namePop(ctxt); |
|
7130 spacePop(ctxt); |
|
7131 return; |
|
7132 } |
|
7133 |
|
7134 /** |
|
7135 * xmlParseEndTag: |
|
7136 * @param ctxt an XML parser context |
|
7137 * |
|
7138 * parse an end of tag |
|
7139 * |
|
7140 * [42] ETag ::= '</' Name S? '>' |
|
7141 * |
|
7142 * With namespace |
|
7143 * |
|
7144 * [NS 9] ETag ::= '</' QName S? '>' |
|
7145 */ |
|
7146 |
|
7147 XMLPUBFUNEXPORT void |
|
7148 xmlParseEndTag(xmlParserCtxtPtr ctxt) { |
|
7149 xmlParseEndTag1(ctxt, 0); |
|
7150 } |
|
7151 #endif /* LIBXML_SAX1_ENABLED */ |
|
7152 |
|
7153 /************************************************************************ |
|
7154 * * |
|
7155 * SAX 2 specific operations * |
|
7156 * * |
|
7157 ************************************************************************/ |
|
7158 |
|
7159 static const xmlChar * |
|
7160 xmlParseNCNameComplex(xmlParserCtxtPtr ctxt) { |
|
7161 int len = 0, l; |
|
7162 int c; |
|
7163 int count = 0; |
|
7164 |
|
7165 /* |
|
7166 * Handler for more complex cases |
|
7167 */ |
|
7168 GROW; |
|
7169 c = CUR_CHAR(l); |
|
7170 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */ |
|
7171 (!IS_LETTER(c) && (c != '_'))) { |
|
7172 return(NULL); |
|
7173 } |
|
7174 |
|
7175 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */ |
|
7176 ((IS_LETTER(c)) || (IS_DIGIT(c)) || |
|
7177 (c == '.') || (c == '-') || (c == '_') || |
|
7178 (IS_COMBINING(c)) || |
|
7179 (IS_EXTENDER(c)))) { |
|
7180 if (count++ > 100) { |
|
7181 count = 0; |
|
7182 GROW; |
|
7183 } |
|
7184 len += l; |
|
7185 NEXTL(l); |
|
7186 c = CUR_CHAR(l); |
|
7187 } |
|
7188 return(xmlDictLookup(ctxt->dict, ctxt->input->cur - len, len)); |
|
7189 } |
|
7190 |
|
7191 /* |
|
7192 * xmlGetNamespace: |
|
7193 * @param ctxt an XML parser context |
|
7194 * @param prefix the prefix to lookup |
|
7195 * |
|
7196 * Lookup the namespace name for the prefix (which can be NULL) |
|
7197 * The prefix must come from the ctxt->dict dictionary |
|
7198 * |
|
7199 * Returns the namespace name or NULL if not bound |
|
7200 */ |
|
7201 static const xmlChar* |
|
7202 xmlGetNamespace(xmlParserCtxtPtr ctxt, const xmlChar *prefix) |
|
7203 { |
|
7204 int i; |
|
7205 |
|
7206 if (prefix == ctxt->str_xml) |
|
7207 return(ctxt->str_xml_ns); |
|
7208 |
|
7209 for (i = ctxt->nsNr - 2;i >= 0;i-=2) |
|
7210 if (ctxt->nsTab[i] == prefix) { |
|
7211 if (!prefix && (*ctxt->nsTab[i + 1] == 0)) |
|
7212 return(NULL); |
|
7213 return(ctxt->nsTab[i + 1]); |
|
7214 } |
|
7215 return(NULL); |
|
7216 } |
|
7217 |
|
7218 /** |
|
7219 * xmlParseNCName: |
|
7220 * @param ctxt an XML parser context |
|
7221 * @param len lenght of the string parsed |
|
7222 * |
|
7223 * parse an XML name. |
|
7224 * |
|
7225 * [4NS] NCNameChar ::= Letter | Digit | '.' | '-' | '_' | |
|
7226 * CombiningChar | Extender |
|
7227 * |
|
7228 * [5NS] NCName ::= (Letter | '_') (NCNameChar)* |
|
7229 * |
|
7230 * Returns the Name parsed or NULL |
|
7231 */ |
|
7232 |
|
7233 static const xmlChar* |
|
7234 xmlParseNCName(xmlParserCtxtPtr ctxt) |
|
7235 { |
|
7236 const xmlChar* in; |
|
7237 const xmlChar* ret; |
|
7238 |
|
7239 /* |
|
7240 * Accelerator for simple ASCII names |
|
7241 */ |
|
7242 in = ctxt->input->cur; |
|
7243 if (((*in >= 0x61) && (*in <= 0x7A)) || |
|
7244 ((*in >= 0x41) && (*in <= 0x5A)) || |
|
7245 (*in == '_')) |
|
7246 { |
|
7247 in++; |
|
7248 while (((*in >= 0x61) && (*in <= 0x7A)) || |
|
7249 ((*in >= 0x41) && (*in <= 0x5A)) || |
|
7250 ((*in >= 0x30) && (*in <= 0x39)) || |
|
7251 (*in == '_') || (*in == '-') || |
|
7252 (*in == '.')) |
|
7253 { |
|
7254 in++; |
|
7255 } |
|
7256 if ((*in > 0) && (*in < 0x80)) |
|
7257 { |
|
7258 int count = in - ctxt->input->cur; |
|
7259 ret = xmlDictLookup(ctxt->dict, ctxt->input->cur, count); |
|
7260 ctxt->input->cur = in; |
|
7261 ctxt->nbChars += count; |
|
7262 ctxt->input->col += count; |
|
7263 if (!ret) { |
|
7264 xmlParserOOMErr(ctxt); |
|
7265 } |
|
7266 return(ret); |
|
7267 } |
|
7268 } |
|
7269 return(xmlParseNCNameComplex(ctxt)); |
|
7270 } |
|
7271 |
|
7272 /** |
|
7273 * xmlParseQName: |
|
7274 * @param ctxt an XML parser context |
|
7275 * @param prefix pointer to store the prefix part |
|
7276 * |
|
7277 * parse an XML Namespace QName |
|
7278 * |
|
7279 * [6] QName ::= (Prefix ':')? LocalPart |
|
7280 * [7] Prefix ::= NCName |
|
7281 * [8] LocalPart ::= NCName |
|
7282 * |
|
7283 * Returns the Name parsed or NULL |
|
7284 */ |
|
7285 |
|
7286 static const xmlChar * |
|
7287 xmlParseQName(xmlParserCtxtPtr ctxt, const xmlChar **prefix) { |
|
7288 const xmlChar *l, *p; |
|
7289 |
|
7290 GROW; |
|
7291 |
|
7292 l = xmlParseNCName(ctxt); |
|
7293 if (l == NULL) { |
|
7294 if (CUR == ':') { |
|
7295 l = xmlParseName(ctxt); |
|
7296 if (l != NULL) { |
|
7297 xmlNsErr(ctxt, XML_NS_ERR_QNAME, EMBED_ERRTXT("Failed to parse QName '%s'\n"), l, NULL, NULL); |
|
7298 *prefix = NULL; |
|
7299 return(l); |
|
7300 } |
|
7301 } |
|
7302 return(NULL); |
|
7303 } |
|
7304 if (CUR == ':') { |
|
7305 NEXT; |
|
7306 p = l; |
|
7307 l = xmlParseNCName(ctxt); |
|
7308 if (l == NULL) { |
|
7309 xmlChar *tmp; |
|
7310 xmlNsErr(ctxt, XML_NS_ERR_QNAME, EMBED_ERRTXT("Failed to parse QName '%s:'\n"), p, NULL, NULL); |
|
7311 tmp = xmlBuildQName(BAD_CAST "", p, NULL, 0); |
|
7312 p = xmlDictLookup(ctxt->dict, tmp, -1); |
|
7313 if (tmp != NULL) |
|
7314 xmlFree(tmp); |
|
7315 *prefix = NULL; |
|
7316 return(p); |
|
7317 } |
|
7318 if (CUR == ':') { |
|
7319 xmlChar *tmp; |
|
7320 xmlNsErr(ctxt, XML_NS_ERR_QNAME, EMBED_ERRTXT("Failed to parse QName '%s:%s:'\n"), p, l, NULL); |
|
7321 NEXT; |
|
7322 tmp = (xmlChar *) xmlParseName(ctxt); |
|
7323 if (tmp != NULL) { |
|
7324 tmp = xmlBuildQName(tmp, l, NULL, 0); |
|
7325 l = xmlDictLookup(ctxt->dict, tmp, -1); |
|
7326 if (tmp != NULL) xmlFree(tmp); |
|
7327 *prefix = p; |
|
7328 return(l); |
|
7329 } |
|
7330 tmp = xmlBuildQName(BAD_CAST "", l, NULL, 0); |
|
7331 l = xmlDictLookup(ctxt->dict, tmp, -1); |
|
7332 if (tmp != NULL) |
|
7333 xmlFree(tmp); |
|
7334 *prefix = p; |
|
7335 return(l); |
|
7336 } |
|
7337 *prefix = p; |
|
7338 } else |
|
7339 *prefix = NULL; |
|
7340 return(l); |
|
7341 } |
|
7342 |
|
7343 /** |
|
7344 * xmlParseQNameAndCompare: |
|
7345 * @param ctxt an XML parser context |
|
7346 * @param name the localname |
|
7347 * @param prefix the prefix, if any. |
|
7348 * |
|
7349 * parse an XML name and compares for match |
|
7350 * (specialized for endtag parsing) |
|
7351 * |
|
7352 * Returns NULL for an illegal name, (xmlChar*) 1 for success |
|
7353 * and the name for mismatch |
|
7354 */ |
|
7355 |
|
7356 static const xmlChar * |
|
7357 xmlParseQNameAndCompare(xmlParserCtxtPtr ctxt, xmlChar const *name, |
|
7358 xmlChar const *prefix) { |
|
7359 const xmlChar *cmp = name; |
|
7360 const xmlChar *in; |
|
7361 const xmlChar *ret; |
|
7362 const xmlChar *prefix2; |
|
7363 |
|
7364 if (prefix == NULL) return(xmlParseNameAndCompare(ctxt, name)); |
|
7365 |
|
7366 GROW; |
|
7367 in = ctxt->input->cur; |
|
7368 |
|
7369 cmp = prefix; |
|
7370 while (*in != 0 && *in == *cmp) { |
|
7371 ++in; |
|
7372 ++cmp; |
|
7373 } |
|
7374 if ((*cmp == 0) && (*in == ':')) { |
|
7375 in++; |
|
7376 cmp = name; |
|
7377 while (*in != 0 && *in == *cmp) { |
|
7378 ++in; |
|
7379 ++cmp; |
|
7380 } |
|
7381 if (*cmp == 0 && (*in == '>' || IS_BLANK_CH (*in))) { |
|
7382 /* success */ |
|
7383 ctxt->input->cur = in; |
|
7384 return((const xmlChar*) 1); |
|
7385 } |
|
7386 } |
|
7387 /* |
|
7388 * all strings coms from the dictionary, equality can be done directly |
|
7389 */ |
|
7390 ret = xmlParseQName (ctxt, &prefix2); |
|
7391 if ((ret == name) && (prefix == prefix2)) |
|
7392 return((const xmlChar*) 1); |
|
7393 return ret; |
|
7394 } |
|
7395 |
|
7396 /** |
|
7397 * xmlParseAttValueInternal: |
|
7398 * @param ctxt an XML parser context |
|
7399 * @param len attribute len result |
|
7400 * @param alloc whether the attribute was reallocated as a new string |
|
7401 * @param normalize if 1 then further non-CDATA normalization must be done |
|
7402 * |
|
7403 * parse a value for an attribute. |
|
7404 * NOTE: if no normalization is needed, the routine will return pointers |
|
7405 * directly from the data buffer. |
|
7406 * |
|
7407 * 3.3.3 Attribute-Value Normalization: |
|
7408 * Before the value of an attribute is passed to the application or |
|
7409 * checked for validity, the XML processor must normalize it as follows: |
|
7410 * - a character reference is processed by appending the referenced |
|
7411 * character to the attribute value |
|
7412 * - an entity reference is processed by recursively processing the |
|
7413 * replacement text of the entity |
|
7414 * - a whitespace character (#x20, #xD, #xA, #x9) is processed by |
|
7415 * appending #x20 to the normalized value, except that only a single |
|
7416 * #x20 is appended for a "#xD#xA" sequence that is part of an external |
|
7417 * parsed entity or the literal entity value of an internal parsed entity |
|
7418 * - other characters are processed by appending them to the normalized value |
|
7419 * If the declared value is not CDATA, then the XML processor must further |
|
7420 * process the normalized attribute value by discarding any leading and |
|
7421 * trailing space (#x20) characters, and by replacing sequences of space |
|
7422 * (#x20) characters by a single space (#x20) character. |
|
7423 * All attributes for which no declaration has been read should be treated |
|
7424 * by a non-validating parser as if declared CDATA. |
|
7425 * |
|
7426 * Returns the AttValue parsed or NULL. The value has to be freed by the |
|
7427 * caller if it was copied, this can be detected by val[*len] == 0. |
|
7428 */ |
|
7429 |
|
7430 static xmlChar * |
|
7431 xmlParseAttValueInternal(xmlParserCtxtPtr ctxt, int *len, int *alloc, |
|
7432 int normalize) |
|
7433 { |
|
7434 xmlChar limit = 0; |
|
7435 const xmlChar *in = NULL, *start, *end, *last; |
|
7436 xmlChar *ret = NULL; |
|
7437 |
|
7438 GROW; |
|
7439 in = (xmlChar *) CUR_PTR; |
|
7440 if (*in != '"' && *in != '\'') { |
|
7441 xmlFatalErr(ctxt, XML_ERR_ATTRIBUTE_NOT_STARTED, NULL); |
|
7442 return (NULL); |
|
7443 } |
|
7444 ctxt->instate = XML_PARSER_ATTRIBUTE_VALUE; |
|
7445 |
|
7446 /* |
|
7447 * try to handle in this routine the most common case where no |
|
7448 * allocation of a new string is required and where content is |
|
7449 * pure ASCII. |
|
7450 */ |
|
7451 limit = *in++; |
|
7452 end = ctxt->input->end; |
|
7453 start = in; |
|
7454 if (in >= end) { |
|
7455 const xmlChar *oldbase = ctxt->input->base; |
|
7456 GROW; |
|
7457 if (oldbase != ctxt->input->base) { |
|
7458 long delta = ctxt->input->base - oldbase; |
|
7459 start = start + delta; |
|
7460 in = in + delta; |
|
7461 } |
|
7462 end = ctxt->input->end; |
|
7463 } |
|
7464 if (normalize) { |
|
7465 /* |
|
7466 * Skip any leading spaces |
|
7467 */ |
|
7468 while ((in < end) && (*in != limit) && |
|
7469 ((*in == 0x20) || (*in == 0x9) || |
|
7470 (*in == 0xA) || (*in == 0xD))) |
|
7471 { |
|
7472 in++; |
|
7473 start = in; |
|
7474 if (in >= end) { |
|
7475 const xmlChar *oldbase = ctxt->input->base; |
|
7476 GROW; |
|
7477 if (oldbase != ctxt->input->base) { |
|
7478 long delta = ctxt->input->base - oldbase; |
|
7479 start = start + delta; |
|
7480 in = in + delta; |
|
7481 } |
|
7482 end = ctxt->input->end; |
|
7483 } |
|
7484 } |
|
7485 while (( in < end) && (*in != limit) && |
|
7486 (*in >= 0x20) && (*in <= 0x7f) && (*in != '&') && (*in != '<')) |
|
7487 { |
|
7488 if ((*in++ == 0x20) && (*in == 0x20)) break; |
|
7489 if (in >= end) { |
|
7490 const xmlChar *oldbase = ctxt->input->base; |
|
7491 GROW; |
|
7492 if (oldbase != ctxt->input->base) { |
|
7493 long delta = ctxt->input->base - oldbase; |
|
7494 start = start + delta; |
|
7495 in = in + delta; |
|
7496 } |
|
7497 end = ctxt->input->end; |
|
7498 } |
|
7499 } |
|
7500 last = in; |
|
7501 /* |
|
7502 * skip the trailing blanks |
|
7503 */ |
|
7504 while ((last[-1] == 0x20) && (last > start)) last--; |
|
7505 while ((in < end) && (*in != limit) && |
|
7506 ((*in == 0x20) || (*in == 0x9) || (*in == 0xA) || (*in == 0xD))) |
|
7507 { |
|
7508 in++; |
|
7509 if (in >= end) { |
|
7510 const xmlChar *oldbase = ctxt->input->base; |
|
7511 GROW; |
|
7512 if (oldbase != ctxt->input->base) { |
|
7513 long delta = ctxt->input->base - oldbase; |
|
7514 start = start + delta; |
|
7515 in = in + delta; |
|
7516 last = last + delta; |
|
7517 } |
|
7518 end = ctxt->input->end; |
|
7519 } |
|
7520 } |
|
7521 if (*in != limit) goto need_complex; |
|
7522 } // if (normalize) |
|
7523 else |
|
7524 { // if (!normalize) |
|
7525 while ((in < end) && (*in != limit) && |
|
7526 (*in >= 0x20) && (*in <= 0x7f) && (*in != '&') && (*in != '<')) |
|
7527 { |
|
7528 in++; |
|
7529 if (in >= end) { |
|
7530 const xmlChar *oldbase = ctxt->input->base; |
|
7531 GROW; |
|
7532 if (oldbase != ctxt->input->base) { |
|
7533 long delta = ctxt->input->base - oldbase; |
|
7534 start = start + delta; |
|
7535 in = in + delta; |
|
7536 } |
|
7537 end = ctxt->input->end; |
|
7538 } |
|
7539 } |
|
7540 last = in; |
|
7541 if (*in != limit) goto need_complex; |
|
7542 } // if (!normalize) |
|
7543 |
|
7544 in++; |
|
7545 if (len != NULL) { |
|
7546 *len = last - start; |
|
7547 ret = (xmlChar *) start; |
|
7548 } else { |
|
7549 if (alloc) *alloc = 1; |
|
7550 ret = xmlStrndup(start, last - start); |
|
7551 } |
|
7552 CUR_PTR = in; |
|
7553 if (alloc) *alloc = 0; |
|
7554 return ret; |
|
7555 |
|
7556 need_complex: |
|
7557 if (alloc) *alloc = 1; |
|
7558 return xmlParseAttValueComplex(ctxt, len, normalize); |
|
7559 } |
|
7560 |
|
7561 /** |
|
7562 * xmlParseAttribute2: |
|
7563 * @param ctxt an XML parser context |
|
7564 * @param pref the element prefix |
|
7565 * @param elem the element name |
|
7566 * @param prefix a xmlChar ** used to store the value of the attribute prefix |
|
7567 * @param value a xmlChar ** used to store the value of the attribute |
|
7568 * @param len an int * to save the length of the attribute |
|
7569 * @param alloc an int * to indicate if the attribute was allocated |
|
7570 * |
|
7571 * parse an attribute in the new SAX2 framework. |
|
7572 * |
|
7573 * Returns the attribute name, and the value in *value, . |
|
7574 */ |
|
7575 |
|
7576 static const xmlChar * |
|
7577 xmlParseAttribute2(xmlParserCtxtPtr ctxt, |
|
7578 const xmlChar *pref, const xmlChar *elem, |
|
7579 const xmlChar **prefix, xmlChar **value, |
|
7580 int *len, int *alloc) { |
|
7581 const xmlChar *name; |
|
7582 xmlChar *val; |
|
7583 int normalize = 0; |
|
7584 |
|
7585 *value = NULL; |
|
7586 GROW; |
|
7587 name = xmlParseQName(ctxt, prefix); |
|
7588 if (name == NULL) { |
|
7589 xmlFatalErrMsg(ctxt, XML_ERR_NAME_REQUIRED, EMBED_ERRTXT("error parsing attribute name\n")); |
|
7590 return(NULL); |
|
7591 } |
|
7592 |
|
7593 /* |
|
7594 * get the type if needed |
|
7595 */ |
|
7596 if (ctxt->attsSpecial != NULL) { |
|
7597 int type; |
|
7598 |
|
7599 type = (int)(long)xmlHashQLookup2(ctxt->attsSpecial, pref, elem, *prefix, name); |
|
7600 if (type != 0) normalize = 1; |
|
7601 } |
|
7602 |
|
7603 /* |
|
7604 * read the value |
|
7605 */ |
|
7606 SKIP_BLANKS; |
|
7607 if (RAW == '=') { |
|
7608 NEXT; |
|
7609 SKIP_BLANKS; |
|
7610 val = xmlParseAttValueInternal(ctxt, len, alloc, normalize); |
|
7611 ctxt->instate = XML_PARSER_CONTENT; |
|
7612 } else { |
|
7613 xmlFatalErrMsgStr(ctxt, XML_ERR_ATTRIBUTE_WITHOUT_VALUE, |
|
7614 EMBED_ERRTXT("Specification mandate value for attribute %s\n"), name); |
|
7615 return(NULL); |
|
7616 } |
|
7617 |
|
7618 /* |
|
7619 * Check that xml:lang conforms to the specification |
|
7620 * No more registered as an error, just generate a warning now |
|
7621 * since this was deprecated in XML second edition |
|
7622 */ |
|
7623 if ((ctxt->pedantic) && (xmlStrEqual(name, BAD_CAST "xml:lang"))) { |
|
7624 if (!xmlCheckLanguageID(val)) { |
|
7625 xmlWarningMsg(ctxt, XML_WAR_LANG_VALUE, |
|
7626 EMBED_ERRTXT("Malformed value for xml:lang : %s\n"), |
|
7627 val, NULL); |
|
7628 } |
|
7629 } |
|
7630 |
|
7631 /* |
|
7632 * Check that xml:space conforms to the specification |
|
7633 */ |
|
7634 if (xmlStrEqual(name, BAD_CAST "xml:space")) { |
|
7635 if (xmlStrEqual(val, BAD_CAST "default")) |
|
7636 *(ctxt->space) = 0; |
|
7637 else if (xmlStrEqual(val, BAD_CAST "preserve")) |
|
7638 *(ctxt->space) = 1; |
|
7639 else { |
|
7640 xmlFatalErrMsgStr(ctxt, XML_ERR_ATTRIBUTE_WITHOUT_VALUE, |
|
7641 EMBED_ERRTXT("Invalid value \"%s\" for xml:space : \"default\" or \"preserve\" expected\n"), |
|
7642 val); |
|
7643 } |
|
7644 } |
|
7645 |
|
7646 *value = val; |
|
7647 return(name); |
|
7648 } |
|
7649 |
|
7650 /** |
|
7651 * xmlParseStartTag2: |
|
7652 * @param ctxt an XML parser context |
|
7653 * |
|
7654 * parse a start of tag either for rule element or |
|
7655 * EmptyElement. In both case we don't parse the tag closing chars. |
|
7656 * This routine is called when running SAX2 parsing |
|
7657 * |
|
7658 * [40] STag ::= '<' Name (S Attribute)* S? '>' |
|
7659 * |
|
7660 * [ WFC: Unique Att Spec ] |
|
7661 * No attribute name may appear more than once in the same start-tag or |
|
7662 * empty-element tag. |
|
7663 * |
|
7664 * [44] EmptyElemTag ::= '<' Name (S Attribute)* S? '/>' |
|
7665 * |
|
7666 * [ WFC: Unique Att Spec ] |
|
7667 * No attribute name may appear more than once in the same start-tag or |
|
7668 * empty-element tag. |
|
7669 * |
|
7670 * With namespace: |
|
7671 * |
|
7672 * [NS 8] STag ::= '<' QName (S Attribute)* S? '>' |
|
7673 * |
|
7674 * [NS 10] EmptyElement ::= '<' QName (S Attribute)* S? '/>' |
|
7675 * |
|
7676 * Returns the element name parsed |
|
7677 * |
|
7678 * OOM: possible --> check OOM flag / NULL is returned too |
|
7679 */ |
|
7680 |
|
7681 static const xmlChar * |
|
7682 xmlParseStartTag2(xmlParserCtxtPtr ctxt, const xmlChar **pref, |
|
7683 const xmlChar **URI, int *tlen) |
|
7684 { |
|
7685 const xmlChar *localname; |
|
7686 const xmlChar *prefix; |
|
7687 const xmlChar *attname; |
|
7688 const xmlChar *aprefix; |
|
7689 const xmlChar *nsname; |
|
7690 xmlChar *attvalue; // = NULL : unneeded initialization -- done by xmlParseAttribute2 |
|
7691 const xmlChar **atts = ctxt->atts; |
|
7692 int maxatts = ctxt->maxatts; |
|
7693 int nratts, nbatts, nbdef; |
|
7694 int i, j, nbNs, attval; |
|
7695 const xmlChar *base; |
|
7696 unsigned long cur; |
|
7697 LOAD_GS_SAFE_CTXT(ctxt) |
|
7698 |
|
7699 if (RAW != '<') |
|
7700 return(NULL); |
|
7701 NEXT1; |
|
7702 |
|
7703 /* |
|
7704 * NOTE: it is crucial with the SAX2 API to never call SHRINK beyond that |
|
7705 * point since the attribute values may be stored as pointers to |
|
7706 * the buffer and calling SHRINK would destroy them ! |
|
7707 * The Shrinking is only possible once the full set of attribute |
|
7708 * callbacks have been done. |
|
7709 */ |
|
7710 reparse: |
|
7711 SHRINK; |
|
7712 base = ctxt->input->base; |
|
7713 cur = ctxt->input->cur - ctxt->input->base; |
|
7714 nbatts = 0; |
|
7715 nratts = 0; |
|
7716 nbdef = 0; |
|
7717 nbNs = 0; |
|
7718 attval = 0; |
|
7719 |
|
7720 localname = xmlParseQName(ctxt, &prefix); |
|
7721 if (localname == NULL) { |
|
7722 xmlFatalErrMsg(ctxt, XML_ERR_NAME_REQUIRED, EMBED_ERRTXT("StartTag: invalid element name\n")); |
|
7723 return(NULL); |
|
7724 } |
|
7725 |
|
7726 *tlen = ctxt->input->cur - ctxt->input->base - cur; |
|
7727 |
|
7728 /* |
|
7729 * Now parse the attributes, it ends up with the ending |
|
7730 * |
|
7731 * (S Attribute)* S? |
|
7732 */ |
|
7733 |
|
7734 SKIP_BLANKS; |
|
7735 GROW; |
|
7736 |
|
7737 if (ctxt->input->base != base) |
|
7738 goto base_changed; |
|
7739 |
|
7740 while ((RAW != '>') && |
|
7741 ((RAW != '/') || (NXT(1) != '>')) && |
|
7742 (IS_BYTE_CHAR(RAW))) |
|
7743 { |
|
7744 // Parse one attribute |
|
7745 |
|
7746 const xmlChar *q = CUR_PTR; |
|
7747 unsigned int cons = ctxt->input->consumed; |
|
7748 int len = -1, alloc = 0; |
|
7749 |
|
7750 attname = xmlParseAttribute2(ctxt, prefix, localname, &aprefix, &attvalue, &len, &alloc); |
|
7751 if ((attname != NULL) && (attvalue != NULL)) |
|
7752 { |
|
7753 // if 'len' has not changed, then there was memory allocation |
|
7754 // (because of complex, expanded attribute value) |
|
7755 if (len < 0) |
|
7756 len = xmlStrlen(attvalue); |
|
7757 |
|
7758 if ((attname == ctxt->str_xmlns) && (aprefix == NULL)) |
|
7759 { |
|
7760 // we have [ xmlns="uri" ] - a default namespace definition |
|
7761 const xmlChar *URL = xmlDictLookup(ctxt->dict, attvalue, len); |
|
7762 xmlURIPtr uri; |
|
7763 |
|
7764 if(!URL) |
|
7765 goto OOM; |
|
7766 |
|
7767 if (*URL != 0) { |
|
7768 uri = xmlParseURI((const char *) URL); |
|
7769 if (uri == NULL) { |
|
7770 if(OOM_FLAG)goto OOM; |
|
7771 xmlWarningMsg(ctxt, XML_WAR_NS_URI, |
|
7772 EMBED_ERRTXT("xmlns: %s not a valid URI\n"), URL, NULL); |
|
7773 } else { |
|
7774 if (uri->scheme == NULL) { |
|
7775 xmlWarningMsg(ctxt, XML_WAR_NS_URI_RELATIVE, |
|
7776 EMBED_ERRTXT("xmlns: URI %s is not absolute\n"), URL, NULL); |
|
7777 } |
|
7778 xmlFreeURI(uri); |
|
7779 } |
|
7780 } |
|
7781 /* |
|
7782 * check that it's not a defined namespace |
|
7783 */ |
|
7784 for (j = 1;j <= nbNs;j++) |
|
7785 if (ctxt->nsTab[ctxt->nsNr - 2 * j] == NULL) |
|
7786 break; |
|
7787 |
|
7788 if (j <= nbNs){ |
|
7789 xmlErrAttributeDup(ctxt, NULL, attname); |
|
7790 }else{ |
|
7791 // SAX2 startPrefixMapping callback is invoked in nsPush |
|
7792 if (nsPush(ctxt, NULL, URL) > 0) |
|
7793 nbNs++; |
|
7794 } |
|
7795 if (alloc != 0) |
|
7796 xmlFree(attvalue); |
|
7797 |
|
7798 SKIP_BLANKS; |
|
7799 continue; |
|
7800 } |
|
7801 |
|
7802 if (aprefix == ctxt->str_xmlns) |
|
7803 { |
|
7804 // we have [ xmlns:prefix="uri" ] - a prefix mapping definition |
|
7805 const xmlChar *URL = xmlDictLookup(ctxt->dict, attvalue, len); |
|
7806 xmlURIPtr uri; |
|
7807 |
|
7808 if (attname == ctxt->str_xml) { |
|
7809 if (URL != ctxt->str_xml_ns) { |
|
7810 xmlNsErr(ctxt, XML_NS_ERR_XML_NAMESPACE, |
|
7811 EMBED_ERRTXT("xml namespace prefix mapped to wrong URI\n"), |
|
7812 NULL, NULL, NULL); |
|
7813 } |
|
7814 /* |
|
7815 * Do not keep a namespace definition node |
|
7816 */ |
|
7817 if (alloc != 0) xmlFree(attvalue); |
|
7818 SKIP_BLANKS; |
|
7819 continue; |
|
7820 } // attname == ctxt->str_xml |
|
7821 |
|
7822 uri = xmlParseURI((const char *) URL); |
|
7823 if (uri == NULL) { |
|
7824 xmlWarningMsg(ctxt, XML_WAR_NS_URI, |
|
7825 EMBED_ERRTXT("xmlns:%s: '%s' is not a valid URI\n"), attname, URL); |
|
7826 } else { |
|
7827 if ((ctxt->pedantic) && (uri->scheme == NULL)) { |
|
7828 xmlWarningMsg(ctxt, XML_WAR_NS_URI_RELATIVE, |
|
7829 EMBED_ERRTXT("xmlns:%s: URI %s is not absolute\n"), attname, URL); |
|
7830 } |
|
7831 xmlFreeURI(uri); |
|
7832 } // uri == NULL |
|
7833 |
|
7834 /* |
|
7835 * check that it's not a defined namespace |
|
7836 */ |
|
7837 for (j = 1;j <= nbNs;j++) |
|
7838 if (ctxt->nsTab[ctxt->nsNr - 2 * j] == attname) |
|
7839 break; |
|
7840 if (j <= nbNs){ |
|
7841 xmlErrAttributeDup(ctxt, aprefix, attname); |
|
7842 }else{ |
|
7843 // SAX2 startPrefixMapping callback is invoked in nsPush |
|
7844 if (nsPush(ctxt, attname, URL) > 0) |
|
7845 nbNs++; |
|
7846 } |
|
7847 if (alloc != 0) |
|
7848 xmlFree(attvalue); |
|
7849 |
|
7850 SKIP_BLANKS; |
|
7851 if (ctxt->input->base != base) { |
|
7852 if (alloc != 0) |
|
7853 xmlFree(attvalue); |
|
7854 goto base_changed; |
|
7855 } |
|
7856 continue; |
|
7857 } // if (aprefix == ctxt->str_xmlns) |
|
7858 |
|
7859 |
|
7860 // If we are here, then we have parsed usual [ attribute="value" ] pair |
|
7861 |
|
7862 /* |
|
7863 * Add the pair to atts |
|
7864 */ |
|
7865 if ((atts == NULL) || (nbatts + 5 > maxatts)) { |
|
7866 if (xmlCtxtGrowAttrs(ctxt, nbatts + 5) < 0) { |
|
7867 if (attvalue[len] == 0) |
|
7868 xmlFree(attvalue); |
|
7869 goto failed; |
|
7870 } |
|
7871 maxatts = ctxt->maxatts; |
|
7872 atts = ctxt->atts; |
|
7873 } |
|
7874 |
|
7875 ctxt->attallocs[nratts++] = alloc; |
|
7876 atts[nbatts++] = attname; |
|
7877 atts[nbatts++] = aprefix; |
|
7878 atts[nbatts++] = NULL; /* the URI will be fetched later */ |
|
7879 atts[nbatts++] = attvalue; |
|
7880 attvalue += len; |
|
7881 atts[nbatts++] = attvalue; // the pointer after the end of attribute is stored instead of length |
|
7882 /* |
|
7883 * tag if some deallocation is needed |
|
7884 */ |
|
7885 if (alloc != 0) |
|
7886 attval = 1; |
|
7887 |
|
7888 |
|
7889 } // if ((attname != NULL) && (attvalue != NULL)) |
|
7890 else { |
|
7891 if ((attvalue != NULL) && (attvalue[len] == 0)) |
|
7892 xmlFree(attvalue); |
|
7893 } |
|
7894 |
|
7895 failed: |
|
7896 |
|
7897 GROW; |
|
7898 |
|
7899 if (ctxt->input->base != base) |
|
7900 goto base_changed; |
|
7901 |
|
7902 if ((RAW == '>') || (((RAW == '/') && (NXT(1) == '>')))) |
|
7903 { |
|
7904 break; // while |
|
7905 } |
|
7906 |
|
7907 if (!IS_BLANK_CH(RAW)) { |
|
7908 xmlFatalErrMsg(ctxt, XML_ERR_SPACE_REQUIRED, EMBED_ERRTXT("attributes construct error\n")); |
|
7909 } |
|
7910 |
|
7911 SKIP_BLANKS; |
|
7912 |
|
7913 if (( cons == ctxt->input->consumed ) && |
|
7914 ( q == CUR_PTR ) && |
|
7915 ( attname == NULL ) && |
|
7916 (attvalue == NULL )) |
|
7917 { |
|
7918 xmlFatalErr(ctxt, XML_ERR_INTERNAL_ERROR, EMBED_ERRTXT("xmlParseStartTag: problem parsing attributes\n")); |
|
7919 break; // while |
|
7920 } |
|
7921 |
|
7922 GROW; |
|
7923 |
|
7924 if (ctxt->input->base != base) |
|
7925 goto base_changed; |
|
7926 |
|
7927 } // end of while (...) //Parse one attribute |
|
7928 |
|
7929 |
|
7930 /* |
|
7931 * The attributes defaulting |
|
7932 */ |
|
7933 if (ctxt->attsDefault != NULL) |
|
7934 { |
|
7935 xmlDefAttrsPtr defaults; |
|
7936 defaults = (xmlDefAttrsPtr)xmlHashLookup2(ctxt->attsDefault, localname, prefix); |
|
7937 if (defaults != NULL) |
|
7938 { |
|
7939 for (i = 0;i < defaults->nbAttrs;i++) |
|
7940 { |
|
7941 attname = defaults->values[4 * i]; |
|
7942 aprefix = defaults->values[4 * i + 1]; |
|
7943 |
|
7944 /* |
|
7945 * special work for namespaces defaulted defs |
|
7946 */ |
|
7947 |
|
7948 if ((attname == ctxt->str_xmlns) && (aprefix == NULL)) { |
|
7949 /* |
|
7950 * check that it's not a defined namespace |
|
7951 */ |
|
7952 for (j = 1;j <= nbNs;j++) |
|
7953 if (ctxt->nsTab[ctxt->nsNr - 2 * j] == NULL) |
|
7954 break; |
|
7955 if (j <= nbNs) |
|
7956 continue; // for (i = 0;i < defaults->nbAttrs;i++) |
|
7957 |
|
7958 nsname = xmlGetNamespace(ctxt, NULL); |
|
7959 |
|
7960 // DONE: make defaulted namespace mappings added to attributes for XmlInterface support |
|
7961 if (nsname != defaults->values[4 * i + 2]) { |
|
7962 // SAX2 startPrefixMapping callback is invoked in nsPush |
|
7963 if (nsPush(ctxt, NULL, defaults->values[4 * i + 2]) > 0) |
|
7964 nbNs++; |
|
7965 } |
|
7966 |
|
7967 } // (attname == ctxt->str_xmlns) && (aprefix == NULL) |
|
7968 else |
|
7969 if (aprefix == ctxt->str_xmlns) { |
|
7970 /* |
|
7971 * check that it's not a defined namespace |
|
7972 */ |
|
7973 for (j = 1;j <= nbNs;j++) |
|
7974 if (ctxt->nsTab[ctxt->nsNr - 2 * j] == attname) |
|
7975 break; |
|
7976 if (j <= nbNs) |
|
7977 continue; // for (i = 0;i < defaults->nbAttrs;i++) |
|
7978 |
|
7979 // DONE: make prefix-to-namespace mappings added to attributes for complete SAX2 |
|
7980 nsname = xmlGetNamespace(ctxt, attname); |
|
7981 if (nsname != defaults->values[2]) { |
|
7982 // SAX2 startPrefixMapping callback is invoked in nsPush |
|
7983 if (nsPush(ctxt, attname, defaults->values[4 * i + 2]) > 0) |
|
7984 nbNs++; |
|
7985 } |
|
7986 |
|
7987 } //(aprefix == ctxt->str_xmlns) |
|
7988 else { |
|
7989 /* |
|
7990 * check that it's not a defined attribute |
|
7991 */ |
|
7992 for (j = 0;j < nbatts;j+=5) { |
|
7993 if ((attname == atts[j]) && (aprefix == atts[j+1])) |
|
7994 break; |
|
7995 } |
|
7996 |
|
7997 if (j < nbatts) |
|
7998 continue; // for (i = 0;i < defaults->nbAttrs;i++) |
|
7999 |
|
8000 if ((atts == NULL) || (nbatts + 5 > maxatts)) { |
|
8001 if (xmlCtxtGrowAttrs(ctxt, nbatts + 5) < 0) |
|
8002 { // OOM |
|
8003 if(attvalue) |
|
8004 { |
|
8005 xmlFree(attvalue); |
|
8006 } |
|
8007 return(NULL); |
|
8008 } |
|
8009 maxatts = ctxt->maxatts; |
|
8010 atts = ctxt->atts; |
|
8011 } |
|
8012 |
|
8013 atts[nbatts++] = attname; |
|
8014 atts[nbatts++] = aprefix; |
|
8015 atts[nbatts++] = aprefix ? xmlGetNamespace(ctxt, aprefix) |
|
8016 : aprefix /* it's NULL here */; |
|
8017 atts[nbatts++] = defaults->values[4 * i + 2]; |
|
8018 atts[nbatts++] = defaults->values[4 * i + 3]; |
|
8019 nbdef++; |
|
8020 } |
|
8021 } // for (i = 0;i < defaults->nbAttrs;i++) |
|
8022 } // if (defaults != NULL) |
|
8023 } // if (ctxt->attsDefault != NULL) |
|
8024 |
|
8025 /* |
|
8026 * The attributes checkings |
|
8027 */ |
|
8028 for (i = 0; i < nbatts;i += 5) |
|
8029 { |
|
8030 if (atts[i + 1] != NULL) { |
|
8031 nsname = xmlGetNamespace(ctxt, atts[i + 1]); |
|
8032 if (nsname == NULL) { |
|
8033 xmlNsErr(ctxt, XML_NS_ERR_UNDEFINED_NAMESPACE, |
|
8034 "Namespace prefix %s for %s on %s is not defined\n", |
|
8035 atts[i + 1], atts[i], localname); |
|
8036 } |
|
8037 atts[i + 2] = nsname; |
|
8038 } else |
|
8039 nsname = NULL; |
|
8040 |
|
8041 /* |
|
8042 * [ WFC: Unique Att Spec ] |
|
8043 * No attribute name may appear more than once in the same |
|
8044 * start-tag or empty-element tag. |
|
8045 * As extended by the Namespace in XML REC. |
|
8046 */ |
|
8047 for (j = 0; j < i;j += 5) |
|
8048 { |
|
8049 if (atts[i] == atts[j]) |
|
8050 { |
|
8051 if (atts[i+1] == atts[j+1]) |
|
8052 { |
|
8053 xmlErrAttributeDup(ctxt, atts[i+1], atts[i]); |
|
8054 break; |
|
8055 } |
|
8056 if ((nsname != NULL) && (atts[j + 2] == nsname)) |
|
8057 { |
|
8058 xmlNsErr(ctxt, XML_NS_ERR_ATTRIBUTE_REDEFINED, |
|
8059 EMBED_ERRTXT("Namespaced Attribute %s in '%s' redefined\n"), |
|
8060 atts[i], nsname, NULL); |
|
8061 break; |
|
8062 } |
|
8063 } |
|
8064 } // for (i = 0; j < i; j += 5) |
|
8065 } // for (i = 0; i < nbatts; i += 5) |
|
8066 |
|
8067 // check element's namespace: if there is, then should be defined already |
|
8068 nsname = xmlGetNamespace(ctxt, prefix); |
|
8069 if ((prefix != NULL) && (nsname == NULL)) |
|
8070 { |
|
8071 xmlNsErr(ctxt, XML_NS_ERR_UNDEFINED_NAMESPACE, |
|
8072 EMBED_ERRTXT("Namespace prefix %s on %s is not defined\n"), |
|
8073 prefix, localname, NULL); |
|
8074 } |
|
8075 |
|
8076 *pref = prefix; |
|
8077 *URI = nsname; |
|
8078 |
|
8079 /* |
|
8080 * SAX: Start of Element ! |
|
8081 */ |
|
8082 if ((ctxt->sax != NULL) && |
|
8083 (ctxt->sax->startElementNs != NULL) && |
|
8084 (!ctxt->disableSAX)) |
|
8085 { |
|
8086 |
|
8087 if (nbNs > 0) |
|
8088 { |
|
8089 ctxt->sax->startElementNs(ctxt->userData, |
|
8090 localname, prefix, |
|
8091 nsname, nbNs, &ctxt->nsTab[ctxt->nsNr - 2 * nbNs], |
|
8092 nbatts / 5, nbdef, atts); |
|
8093 } |
|
8094 else |
|
8095 { |
|
8096 ctxt->sax->startElementNs(ctxt->userData, |
|
8097 localname, prefix, |
|
8098 nsname, 0, NULL, |
|
8099 nbatts / 5, nbdef, atts); |
|
8100 } |
|
8101 } |
|
8102 |
|
8103 /* |
|
8104 * Free up attribute allocated strings if needed |
|
8105 */ |
|
8106 if (attval != 0) { |
|
8107 for (i = 3,j = 0; j < nratts;i += 5,j++) |
|
8108 if ((ctxt->attallocs[j] != 0) && (atts[i] != NULL)) |
|
8109 xmlFree((xmlChar *) atts[i]); |
|
8110 } |
|
8111 // check OOM after calling callback |
|
8112 if(OOM_FLAG) |
|
8113 { |
|
8114 goto OOM; |
|
8115 } |
|
8116 // XE: BEGIN NEW CODE - save number of newly defined (and pushed to stack) namespaces |
|
8117 ctxt->lastNsNr = nbNs; |
|
8118 // XE: END NEW CODE |
|
8119 |
|
8120 return(localname); |
|
8121 |
|
8122 base_changed: |
|
8123 /* |
|
8124 * the attribute strings are valid iif the base didn't changed |
|
8125 */ |
|
8126 if (attval != 0) { |
|
8127 for (i = 3,j = 0; j < nratts;i += 5,j++) |
|
8128 if ((ctxt->attallocs[j] != 0) && (atts[i] != NULL)) |
|
8129 xmlFree((xmlChar *) atts[i]); |
|
8130 } |
|
8131 ctxt->input->cur = ctxt->input->base + cur; |
|
8132 |
|
8133 if (ctxt->wellFormed == 1) { |
|
8134 goto reparse; |
|
8135 } |
|
8136 return(NULL); |
|
8137 //--------------------------------- |
|
8138 OOM: |
|
8139 xmlParserOOMErr(ctxt); |
|
8140 return NULL; |
|
8141 } |
|
8142 |
|
8143 /** |
|
8144 * xmlParseEndTag2: |
|
8145 * @param ctxt an XML parser context |
|
8146 * @param line line of the start tag |
|
8147 * @param nsNr number of namespaces on the start tag |
|
8148 * |
|
8149 * parse an end of tag |
|
8150 * |
|
8151 * [42] ETag ::= '</' Name S? '>' |
|
8152 * |
|
8153 * With namespace |
|
8154 * |
|
8155 * [NS 9] ETag ::= '</' QName S? '>' |
|
8156 */ |
|
8157 |
|
8158 static void |
|
8159 xmlParseEndTag2(xmlParserCtxtPtr ctxt, const xmlChar *prefix, |
|
8160 const xmlChar *URI, int line, int nsNr, int tlen) { |
|
8161 const xmlChar *name; |
|
8162 |
|
8163 GROW; |
|
8164 if ((RAW != '<') || (NXT(1) != '/')) { |
|
8165 xmlFatalErr(ctxt, XML_ERR_LTSLASH_REQUIRED, NULL); |
|
8166 return; |
|
8167 } |
|
8168 SKIP(2); |
|
8169 |
|
8170 if ((tlen > 0) && (strncmp((char*) ctxt->input->cur, (char*) ctxt->name, tlen) == 0)) { |
|
8171 if (ctxt->input->cur[tlen] == '>') { |
|
8172 ctxt->input->cur += tlen + 1; |
|
8173 goto done; |
|
8174 } |
|
8175 ctxt->input->cur += tlen; |
|
8176 name = (xmlChar*)1; |
|
8177 } else { |
|
8178 if (prefix == NULL) |
|
8179 name = xmlParseNameAndCompare(ctxt, ctxt->name); |
|
8180 else |
|
8181 name = xmlParseQNameAndCompare(ctxt, ctxt->name, prefix); |
|
8182 } |
|
8183 |
|
8184 /* |
|
8185 * We should definitely be at the ending "S? '>'" part |
|
8186 */ |
|
8187 GROW; |
|
8188 SKIP_BLANKS; |
|
8189 if ((!IS_BYTE_CHAR(RAW)) || (RAW != '>')) { |
|
8190 xmlFatalErr(ctxt, XML_ERR_GT_REQUIRED, NULL); |
|
8191 } else |
|
8192 NEXT1; |
|
8193 |
|
8194 /* |
|
8195 * [ WFC: Element Type Match ] |
|
8196 * The Name in an element's end-tag must match the element type in the |
|
8197 * start-tag. |
|
8198 * |
|
8199 */ |
|
8200 if (name != (xmlChar*)1) { |
|
8201 if (name == NULL) name = BAD_CAST "unparseable"; |
|
8202 xmlFatalErrMsgStrIntStr(ctxt, XML_ERR_TAG_NAME_MISMATCH, |
|
8203 EMBED_ERRTXT("Opening and ending tag mismatch: %s line %d and %s\n"), |
|
8204 ctxt->name, line, name); |
|
8205 } |
|
8206 |
|
8207 /* |
|
8208 * SAX: End of Tag |
|
8209 */ |
|
8210 done: |
|
8211 if ((ctxt->sax != NULL) && |
|
8212 (ctxt->sax->endElementNs != NULL) && |
|
8213 (!ctxt->disableSAX)) |
|
8214 { |
|
8215 ctxt->sax->endElementNs(ctxt->userData, ctxt->name, prefix, URI); |
|
8216 } |
|
8217 |
|
8218 spacePop(ctxt); |
|
8219 if (nsNr != 0){ |
|
8220 // SAX2 endPrefixMapping callback is invoked in nsPop for every popped prefix |
|
8221 nsPop(ctxt, nsNr); |
|
8222 } |
|
8223 return; |
|
8224 } |
|
8225 |
|
8226 /** |
|
8227 * xmlParseCDSect: |
|
8228 * @param ctxt an XML parser context |
|
8229 * |
|
8230 * Parse escaped pure raw content. |
|
8231 * |
|
8232 * [18] CDSect ::= CDStart CData CDEnd |
|
8233 * |
|
8234 * [19] CDStart ::= '<![CDATA[' |
|
8235 * |
|
8236 * [20] Data ::= (Char* - (Char* ']]>' Char*)) |
|
8237 * |
|
8238 * [21] CDEnd ::= ']]>' |
|
8239 */ |
|
8240 XMLPUBFUNEXPORT void |
|
8241 xmlParseCDSect(xmlParserCtxtPtr ctxt) { |
|
8242 xmlChar *buf = NULL; |
|
8243 int len = 0; |
|
8244 int size = XML_PARSER_BUFFER_SIZE; |
|
8245 int r, rl; |
|
8246 int s, sl; |
|
8247 int cur, l; |
|
8248 int count = 0; |
|
8249 |
|
8250 /* Check 2.6.0 was NXT(0) not RAW */ |
|
8251 if (CMP9(CUR_PTR, '<', '!', '[', 'C', 'D', 'A', 'T', 'A', '[')) { |
|
8252 SKIP(9); |
|
8253 } else |
|
8254 return; |
|
8255 |
|
8256 ctxt->instate = XML_PARSER_CDATA_SECTION; |
|
8257 r = CUR_CHAR(rl); |
|
8258 if (!IS_CHAR(r)) { |
|
8259 xmlFatalErr(ctxt, XML_ERR_CDATA_NOT_FINISHED, NULL); |
|
8260 ctxt->instate = XML_PARSER_CONTENT; |
|
8261 return; |
|
8262 } |
|
8263 NEXTL(rl); |
|
8264 s = CUR_CHAR(sl); |
|
8265 if (!IS_CHAR(s)) { |
|
8266 xmlFatalErr(ctxt, XML_ERR_CDATA_NOT_FINISHED, NULL); |
|
8267 ctxt->instate = XML_PARSER_CONTENT; |
|
8268 return; |
|
8269 } |
|
8270 NEXTL(sl); |
|
8271 cur = CUR_CHAR(l); |
|
8272 buf = (xmlChar*) xmlMallocAtomic(size * sizeof(xmlChar)); |
|
8273 if (!buf) |
|
8274 goto OOM_exit; |
|
8275 |
|
8276 while (IS_CHAR(cur) && |
|
8277 ((r != ']') || (s != ']') || (cur != '>'))) { |
|
8278 if (len + 5 >= size) { |
|
8279 // DONE: Fix xmlRealloc |
|
8280 xmlChar* tmp; |
|
8281 size *= 2; |
|
8282 tmp = (xmlChar*) xmlRealloc(buf, size * sizeof(xmlChar)); |
|
8283 if (!tmp) { |
|
8284 xmlFree(buf); |
|
8285 OOM_exit: |
|
8286 xmlParserOOMErr(ctxt); |
|
8287 return; |
|
8288 } |
|
8289 buf = tmp; |
|
8290 } |
|
8291 COPY_BUF(rl,buf,len,r); |
|
8292 r = s; |
|
8293 rl = sl; |
|
8294 s = cur; |
|
8295 sl = l; |
|
8296 count++; |
|
8297 if (count > 50) { |
|
8298 GROW; |
|
8299 count = 0; |
|
8300 } |
|
8301 NEXTL(l); |
|
8302 cur = CUR_CHAR(l); |
|
8303 } |
|
8304 buf[len] = 0; |
|
8305 ctxt->instate = XML_PARSER_CONTENT; |
|
8306 if (cur != '>') { |
|
8307 xmlFatalErrMsgStr(ctxt, XML_ERR_CDATA_NOT_FINISHED, |
|
8308 EMBED_ERRTXT("CData section not finished\n%.50s\n"), buf); |
|
8309 xmlFree(buf); |
|
8310 return; |
|
8311 } |
|
8312 NEXTL(l); |
|
8313 |
|
8314 /* |
|
8315 * OK the buffer is to be consumed as cdata. |
|
8316 */ |
|
8317 if ((ctxt->sax != NULL) && (!ctxt->disableSAX)) { |
|
8318 if (ctxt->sax->cdataBlock != NULL) |
|
8319 ctxt->sax->cdataBlock(ctxt->userData, buf, len); |
|
8320 else if (ctxt->sax->characters != NULL) |
|
8321 ctxt->sax->characters(ctxt->userData, buf, len); |
|
8322 } |
|
8323 xmlFree(buf); |
|
8324 } |
|
8325 |
|
8326 /** |
|
8327 * xmlParseContent: |
|
8328 * @param ctxt an XML parser context |
|
8329 * |
|
8330 * Parse a content: |
|
8331 * |
|
8332 * [43] content ::= (element | CharData | Reference | CDSect | PI | Comment)* |
|
8333 */ |
|
8334 |
|
8335 XMLPUBFUNEXPORT void |
|
8336 xmlParseContent(xmlParserCtxtPtr ctxt) { |
|
8337 LOAD_GS_SAFE_CTXT(ctxt) |
|
8338 GROW; |
|
8339 while ((RAW != 0) && |
|
8340 ((RAW != '<') || (NXT(1) != '/'))) { |
|
8341 const xmlChar *test = CUR_PTR; |
|
8342 unsigned int cons = ctxt->input->consumed; |
|
8343 const xmlChar *cur = ctxt->input->cur; |
|
8344 |
|
8345 /* |
|
8346 * First case : a Processing Instruction. |
|
8347 */ |
|
8348 if ((*cur == '<') && (cur[1] == '?')) { |
|
8349 xmlParsePI(ctxt); |
|
8350 } |
|
8351 |
|
8352 /* |
|
8353 * Second case : a CDSection |
|
8354 */ |
|
8355 /* 2.6.0 test was *cur not RAW */ |
|
8356 else if (CMP9(CUR_PTR, '<', '!', '[', 'C', 'D', 'A', 'T', 'A', '[')) { |
|
8357 xmlParseCDSect(ctxt); |
|
8358 } |
|
8359 |
|
8360 /* |
|
8361 * Third case : a comment |
|
8362 */ |
|
8363 else if ((*cur == '<') && (NXT(1) == '!') && |
|
8364 (NXT(2) == '-') && (NXT(3) == '-')) { |
|
8365 xmlParseComment(ctxt); |
|
8366 ctxt->instate = XML_PARSER_CONTENT; |
|
8367 } |
|
8368 |
|
8369 /* |
|
8370 * Fourth case : a sub-element. |
|
8371 */ |
|
8372 else if (*cur == '<') |
|
8373 { |
|
8374 if( (((unsigned int)&cur) - ((unsigned int) xeStackLimit)) < ctxt->stackLowThreshold ) |
|
8375 { |
|
8376 SET_OOM_FLAG; |
|
8377 xmlFatalErr(ctxt, XML_ERR_STACK_LOW, NULL); |
|
8378 return; |
|
8379 } |
|
8380 |
|
8381 xmlParseElement(ctxt); |
|
8382 if(OOM_FLAG) |
|
8383 { |
|
8384 return; |
|
8385 } |
|
8386 } |
|
8387 |
|
8388 /* |
|
8389 * Fifth case : a reference. If if has not been resolved, |
|
8390 * parsing returns it's Name, create the node |
|
8391 */ |
|
8392 |
|
8393 else if (*cur == '&') { |
|
8394 xmlParseReference(ctxt); |
|
8395 } |
|
8396 |
|
8397 /* |
|
8398 * Last case, text. Note that References are handled directly. |
|
8399 */ |
|
8400 else { |
|
8401 xmlParseCharData(ctxt, 0); |
|
8402 } |
|
8403 |
|
8404 GROW; |
|
8405 /* |
|
8406 * Pop-up of finished entities. |
|
8407 */ |
|
8408 while ((RAW == 0) && (ctxt->inputNr > 1)) |
|
8409 xmlPopInput(ctxt); |
|
8410 SHRINK; |
|
8411 |
|
8412 if ((cons == ctxt->input->consumed) && (test == CUR_PTR)) { |
|
8413 xmlFatalErr(ctxt, XML_ERR_INTERNAL_ERROR, |
|
8414 EMBED_ERRTXT("detected an error in element content\n")); |
|
8415 ctxt->instate = XML_PARSER_EOF; |
|
8416 break; |
|
8417 } |
|
8418 } |
|
8419 } |
|
8420 |
|
8421 /** |
|
8422 * xmlParseElement: |
|
8423 * @param ctxt an XML parser context |
|
8424 * |
|
8425 * parse an XML element, this is highly recursive |
|
8426 * |
|
8427 * [39] element ::= EmptyElemTag | STag content ETag |
|
8428 * |
|
8429 * [ WFC: Element Type Match ] |
|
8430 * The Name in an element's end-tag must match the element type in the |
|
8431 * start-tag. |
|
8432 * |
|
8433 */ |
|
8434 |
|
8435 XMLPUBFUNEXPORT void |
|
8436 xmlParseElement(xmlParserCtxtPtr ctxt) |
|
8437 { |
|
8438 const xmlChar *name; |
|
8439 const xmlChar *prefix; |
|
8440 const xmlChar *URI; |
|
8441 #ifdef XMLENGINE_ENABLE_PARSER_RECORD_INFO |
|
8442 xmlParserNodeInfo node_info; |
|
8443 xmlNodePtr ret; |
|
8444 #endif |
|
8445 int line, tlen; |
|
8446 int nsNr = ctxt->nsNr; |
|
8447 LOAD_GS_SAFE_CTXT(ctxt) |
|
8448 |
|
8449 #ifdef XMLENGINE_ENABLE_PARSER_RECORD_INFO |
|
8450 /* Capture start position */ |
|
8451 |
|
8452 if (ctxt->record_info) { |
|
8453 node_info.begin_pos = ctxt->input->consumed + |
|
8454 (CUR_PTR - ctxt->input->base); |
|
8455 node_info.begin_line = ctxt->input->line; |
|
8456 } |
|
8457 #endif |
|
8458 |
|
8459 if (ctxt->spaceNr == 0) |
|
8460 spacePush(ctxt, -1); |
|
8461 else |
|
8462 spacePush(ctxt, *ctxt->space); |
|
8463 |
|
8464 line = ctxt->input->line; |
|
8465 #ifdef LIBXML_SAX1_ENABLED |
|
8466 if (ctxt->sax2) |
|
8467 #endif /* LIBXML_SAX1_ENABLED */ |
|
8468 name = xmlParseStartTag2(ctxt, &prefix, &URI, &tlen); |
|
8469 #ifdef LIBXML_SAX1_ENABLED |
|
8470 else |
|
8471 name = xmlParseStartTag(ctxt); |
|
8472 #endif /* LIBXML_SAX1_ENABLED */ |
|
8473 if (name == NULL) { |
|
8474 spacePop(ctxt); |
|
8475 return; |
|
8476 } |
|
8477 namePush(ctxt, name); |
|
8478 #ifdef XMLENGINE_ENABLE_PARSER_RECORD_INFO |
|
8479 ret = ctxt->node; |
|
8480 #endif |
|
8481 |
|
8482 #ifdef LIBXML_VALID_ENABLED |
|
8483 /* |
|
8484 * [ VC: Root Element Type ] |
|
8485 * The Name in the document type declaration must match the element |
|
8486 * type of the root element. |
|
8487 */ |
|
8488 if (ctxt->validate && ctxt->wellFormed && ctxt->myDoc && |
|
8489 ctxt->node && (ctxt->node == ctxt->myDoc->children)) |
|
8490 ctxt->valid &= xmlValidateRoot(&ctxt->vctxt, ctxt->myDoc); |
|
8491 #endif /* LIBXML_VALID_ENABLED */ |
|
8492 |
|
8493 /* |
|
8494 * Check for an Empty Element. |
|
8495 */ |
|
8496 if ((RAW == '/') && (NXT(1) == '>')) { |
|
8497 SKIP(2); |
|
8498 if (ctxt->sax2) { |
|
8499 if ((ctxt->sax != NULL) && (ctxt->sax->endElementNs != NULL) && |
|
8500 (!ctxt->disableSAX)) |
|
8501 ctxt->sax->endElementNs(ctxt->userData, name, prefix, URI); |
|
8502 #ifdef LIBXML_SAX1_ENABLED |
|
8503 } else { |
|
8504 if ((ctxt->sax != NULL) && (ctxt->sax->endElement != NULL) && |
|
8505 (!ctxt->disableSAX)) |
|
8506 ctxt->sax->endElement(ctxt->userData, name); |
|
8507 #endif /* LIBXML_SAX1_ENABLED */ |
|
8508 } |
|
8509 namePop(ctxt); |
|
8510 spacePop(ctxt); |
|
8511 if (nsNr != ctxt->nsNr) |
|
8512 nsPop(ctxt, ctxt->nsNr - nsNr); |
|
8513 #ifdef XMLENGINE_ENABLE_PARSER_RECORD_INFO |
|
8514 if ( ret != NULL && ctxt->record_info ) { |
|
8515 node_info.end_pos = ctxt->input->consumed + |
|
8516 (CUR_PTR - ctxt->input->base); |
|
8517 node_info.end_line = ctxt->input->line; |
|
8518 node_info.node = ret; |
|
8519 xmlParserAddNodeInfo(ctxt, &node_info); |
|
8520 } |
|
8521 #endif |
|
8522 return; |
|
8523 } |
|
8524 if (RAW == '>') { |
|
8525 NEXT1; |
|
8526 } else { |
|
8527 xmlFatalErrMsgStrIntStr(ctxt, XML_ERR_GT_REQUIRED, |
|
8528 EMBED_ERRTXT("Couldn't find end of Start Tag %s line %d\n"), |
|
8529 name, line, NULL); |
|
8530 |
|
8531 /* |
|
8532 * end of parsing of this node. |
|
8533 */ |
|
8534 nodePop(ctxt); |
|
8535 namePop(ctxt); |
|
8536 spacePop(ctxt); |
|
8537 if (nsNr != ctxt->nsNr) |
|
8538 nsPop(ctxt, ctxt->nsNr - nsNr); |
|
8539 |
|
8540 #ifdef XMLENGINE_ENABLE_PARSER_RECORD_INFO |
|
8541 /* |
|
8542 * Capture end position and add node |
|
8543 */ |
|
8544 if ( ret != NULL && ctxt->record_info ) { |
|
8545 node_info.end_pos = ctxt->input->consumed + (CUR_PTR - ctxt->input->base); |
|
8546 node_info.end_line = ctxt->input->line; |
|
8547 node_info.node = ret; |
|
8548 xmlParserAddNodeInfo(ctxt, &node_info); |
|
8549 } |
|
8550 #endif |
|
8551 return; |
|
8552 } |
|
8553 |
|
8554 /* |
|
8555 * Parse the content of the element: |
|
8556 */ |
|
8557 xmlParseContent(ctxt); |
|
8558 if(OOM_FLAG) |
|
8559 { |
|
8560 return; |
|
8561 } |
|
8562 if (!IS_BYTE_CHAR(RAW)) { |
|
8563 xmlFatalErrMsgStrIntStr(ctxt, XML_ERR_TAG_NOT_FINISHED, |
|
8564 EMBED_ERRTXT("Premature end of data in tag %s line %d\n"), |
|
8565 name, line, NULL); |
|
8566 |
|
8567 /* |
|
8568 * end of parsing of this node. |
|
8569 */ |
|
8570 nodePop(ctxt); |
|
8571 namePop(ctxt); |
|
8572 spacePop(ctxt); |
|
8573 if (nsNr != ctxt->nsNr) |
|
8574 nsPop(ctxt, ctxt->nsNr - nsNr); |
|
8575 return; |
|
8576 } |
|
8577 |
|
8578 /* |
|
8579 * parse the end of tag: '</' should be here. |
|
8580 */ |
|
8581 if (ctxt->sax2) { |
|
8582 xmlParseEndTag2(ctxt, prefix, URI, line, ctxt->nsNr - nsNr, tlen); |
|
8583 namePop(ctxt); |
|
8584 } |
|
8585 #ifdef LIBXML_SAX1_ENABLED |
|
8586 else |
|
8587 xmlParseEndTag1(ctxt, line); |
|
8588 #endif /* LIBXML_SAX1_ENABLED */ |
|
8589 |
|
8590 #ifdef XMLENGINE_ENABLE_PARSER_RECORD_INFO |
|
8591 /* |
|
8592 * Capture end position and add node |
|
8593 */ |
|
8594 if ( ret != NULL && ctxt->record_info ) { |
|
8595 node_info.end_pos = ctxt->input->consumed + |
|
8596 (CUR_PTR - ctxt->input->base); |
|
8597 node_info.end_line = ctxt->input->line; |
|
8598 node_info.node = ret; |
|
8599 xmlParserAddNodeInfo(ctxt, &node_info); |
|
8600 } |
|
8601 #endif |
|
8602 } |
|
8603 |
|
8604 /** |
|
8605 * xmlParseVersionNum: |
|
8606 * @param ctxt an XML parser context |
|
8607 * |
|
8608 * parse the XML version value. |
|
8609 * |
|
8610 * [26] VersionNum ::= ([a-zA-Z0-9_.:] | '-')+ |
|
8611 * |
|
8612 * Returns the string giving the XML version number, or NULL |
|
8613 * |
|
8614 * OOM: possible --> sets OOM flag when NULL is returned |
|
8615 */ |
|
8616 XMLPUBFUNEXPORT xmlChar* |
|
8617 xmlParseVersionNum(xmlParserCtxtPtr ctxt) |
|
8618 { |
|
8619 xmlChar* buf; |
|
8620 int len = 0; |
|
8621 int size = 10; |
|
8622 xmlChar cur; |
|
8623 |
|
8624 buf = (xmlChar*) xmlMallocAtomic(size * sizeof(xmlChar)); |
|
8625 if (!buf) |
|
8626 goto OOM_exit; |
|
8627 |
|
8628 cur = CUR; |
|
8629 while (((cur >= 'a') && (cur <= 'z')) || |
|
8630 ((cur >= 'A') && (cur <= 'Z')) || |
|
8631 ((cur >= '0') && (cur <= '9')) || |
|
8632 (cur == '_') || (cur == '.') || |
|
8633 (cur == ':') || (cur == '-')) |
|
8634 { |
|
8635 if (len + 1 >= size) |
|
8636 { |
|
8637 // DONE: Fix xmlRealloc |
|
8638 xmlChar* tmp; |
|
8639 size *= 2; |
|
8640 tmp = (xmlChar*) xmlRealloc(buf, size * sizeof(xmlChar)); |
|
8641 if (!tmp) { |
|
8642 xmlFree(buf); |
|
8643 OOM_exit: |
|
8644 xmlParserOOMErr(ctxt); |
|
8645 return(NULL); |
|
8646 } |
|
8647 buf = tmp; |
|
8648 } |
|
8649 buf[len++] = cur; |
|
8650 NEXT; |
|
8651 cur=CUR; |
|
8652 } |
|
8653 buf[len] = 0; |
|
8654 return(buf); |
|
8655 } |
|
8656 |
|
8657 /** |
|
8658 * xmlParseVersionInfo: |
|
8659 * @param ctxt an XML parser context |
|
8660 * |
|
8661 * parse the XML version. |
|
8662 * |
|
8663 * [24] VersionInfo ::= S 'version' Eq (' VersionNum ' | " VersionNum ") |
|
8664 * [25] Eq ::= S? '=' S? |
|
8665 * |
|
8666 * Returns the version string, e.g. "1.0" |
|
8667 * |
|
8668 * OOM: |
|
8669 */ |
|
8670 XMLPUBFUNEXPORT xmlChar* |
|
8671 xmlParseVersionInfo(xmlParserCtxtPtr ctxt) { |
|
8672 xmlChar* version; |
|
8673 xmlChar ch; |
|
8674 int errCode; |
|
8675 LOAD_GS_SAFE_CTXT(ctxt) |
|
8676 |
|
8677 |
|
8678 |
|
8679 |
|
8680 if (CMP7(CUR_PTR, 'v', 'e', 'r', 's', 'i', 'o', 'n')) |
|
8681 { |
|
8682 SKIP(7); |
|
8683 SKIP_BLANKS; |
|
8684 //XMLENGINE: BEGIN REPLACE CODE |
|
8685 //XMLENGINE: NEW CODE |
|
8686 if(OOM_FLAG) goto OOM; |
|
8687 if (RAW != '=') { |
|
8688 errCode = XML_ERR_EQUAL_REQUIRED; |
|
8689 goto ERR; |
|
8690 } |
|
8691 NEXT; |
|
8692 if(OOM_FLAG) |
|
8693 goto OOM; |
|
8694 SKIP_BLANKS; |
|
8695 if(OOM_FLAG) |
|
8696 goto OOM; |
|
8697 |
|
8698 ch = RAW; |
|
8699 if (ch == '"' || ch=='\'') |
|
8700 { // DONE: OPTIMIZE: Combine two cases when RAW='\"' or '\'' |
|
8701 NEXT; |
|
8702 if(OOM_FLAG) |
|
8703 goto OOM; |
|
8704 version = xmlParseVersionNum(ctxt); |
|
8705 if (RAW == ch) { |
|
8706 NEXT; |
|
8707 if(OOM_FLAG) |
|
8708 goto OOM; // checks xmlParseVersionNum too |
|
8709 return version; |
|
8710 } else { |
|
8711 errCode = XML_ERR_STRING_NOT_CLOSED; |
|
8712 goto ERR; |
|
8713 } |
|
8714 } else { |
|
8715 errCode = XML_ERR_STRING_NOT_STARTED; |
|
8716 goto ERR; |
|
8717 } |
|
8718 //XMLENGINE: END REPLACE CODE |
|
8719 } |
|
8720 OOM: |
|
8721 return NULL; |
|
8722 ERR: |
|
8723 xmlFatalErr(ctxt, (xmlParserErrors)errCode, NULL); |
|
8724 goto OOM; |
|
8725 } |
|
8726 |
|
8727 /** |
|
8728 * xmlParseEncName: |
|
8729 * @param ctxt an XML parser context |
|
8730 * |
|
8731 * parse the XML encoding name |
|
8732 * |
|
8733 * [81] EncName ::= [A-Za-z] ([A-Za-z0-9._] | '-')* |
|
8734 * |
|
8735 * Returns the encoding name value or NULL |
|
8736 */ |
|
8737 XMLPUBFUNEXPORT xmlChar * |
|
8738 xmlParseEncName(xmlParserCtxtPtr ctxt) { |
|
8739 xmlChar *buf = NULL; |
|
8740 int len = 0; |
|
8741 int size = 10; |
|
8742 xmlChar cur; |
|
8743 |
|
8744 cur = CUR; |
|
8745 if (((cur >= 'a') && (cur <= 'z')) || |
|
8746 ((cur >= 'A') && (cur <= 'Z'))) { |
|
8747 buf = (xmlChar*) xmlMallocAtomic(size * sizeof(xmlChar)); |
|
8748 if (!buf) |
|
8749 goto OOM_exit; |
|
8750 |
|
8751 buf[len++] = cur; |
|
8752 NEXT; |
|
8753 cur = CUR; |
|
8754 while (((cur >= 'a') && (cur <= 'z')) || |
|
8755 ((cur >= 'A') && (cur <= 'Z')) || |
|
8756 ((cur >= '0') && (cur <= '9')) || |
|
8757 (cur == '.') || (cur == '_') || |
|
8758 (cur == '-')) { |
|
8759 if (len + 1 >= size) { |
|
8760 // DONE: Fix xmlRealloc |
|
8761 xmlChar* tmp; |
|
8762 size *= 2; |
|
8763 tmp = (xmlChar*) xmlRealloc(buf, size * sizeof(xmlChar)); |
|
8764 if (!tmp) { |
|
8765 xmlFree(buf); |
|
8766 OOM_exit: |
|
8767 xmlParserOOMErr(ctxt); |
|
8768 return(NULL); |
|
8769 } |
|
8770 buf = tmp; |
|
8771 } |
|
8772 buf[len++] = cur; |
|
8773 NEXT; |
|
8774 cur = CUR; |
|
8775 if (cur == 0) { |
|
8776 SHRINK; |
|
8777 GROW; |
|
8778 cur = CUR; |
|
8779 } |
|
8780 } |
|
8781 buf[len] = 0; |
|
8782 } else { |
|
8783 xmlFatalErr(ctxt, XML_ERR_ENCODING_NAME, NULL); |
|
8784 } |
|
8785 return(buf); |
|
8786 } |
|
8787 |
|
8788 /** |
|
8789 * xmlParseEncodingDecl: |
|
8790 * @param ctxt an XML parser context |
|
8791 * |
|
8792 * parse the XML encoding declaration |
|
8793 * |
|
8794 * [80] EncodingDecl ::= S 'encoding' Eq ('"' EncName '"' | "'" EncName "'") |
|
8795 * |
|
8796 * this setups the conversion filters. |
|
8797 * |
|
8798 * Returns the encoding value or NULL |
|
8799 */ |
|
8800 |
|
8801 XMLPUBFUNEXPORT const xmlChar * |
|
8802 xmlParseEncodingDecl(xmlParserCtxtPtr ctxt) { |
|
8803 xmlChar *encoding = NULL; |
|
8804 |
|
8805 SKIP_BLANKS; |
|
8806 if (CMP8(CUR_PTR, 'e', 'n', 'c', 'o', 'd', 'i', 'n', 'g')) { |
|
8807 SKIP(8); |
|
8808 SKIP_BLANKS; |
|
8809 if (RAW != '=') { |
|
8810 xmlFatalErr(ctxt, XML_ERR_EQUAL_REQUIRED, NULL); |
|
8811 return(NULL); |
|
8812 } |
|
8813 NEXT; |
|
8814 SKIP_BLANKS; |
|
8815 if (RAW == '"') { |
|
8816 NEXT; |
|
8817 encoding = xmlParseEncName(ctxt); |
|
8818 if (RAW != '"') { |
|
8819 xmlFatalErr(ctxt, XML_ERR_STRING_NOT_CLOSED, NULL); |
|
8820 } else |
|
8821 NEXT; |
|
8822 } else if (RAW == '\''){ |
|
8823 NEXT; |
|
8824 encoding = xmlParseEncName(ctxt); |
|
8825 if (RAW != '\'') { |
|
8826 xmlFatalErr(ctxt, XML_ERR_STRING_NOT_CLOSED, NULL); |
|
8827 } else |
|
8828 NEXT; |
|
8829 } else { |
|
8830 xmlFatalErr(ctxt, XML_ERR_STRING_NOT_STARTED, NULL); |
|
8831 } |
|
8832 /* |
|
8833 * UTF-16 encoding stwich has already taken place at this stage, |
|
8834 * more over the little-endian/big-endian selection is already done |
|
8835 */ |
|
8836 if ((encoding != NULL) && |
|
8837 ((!xmlStrcasecmp(encoding, BAD_CAST "UTF-16")) || |
|
8838 (!xmlStrcasecmp(encoding, BAD_CAST "UTF16")))) { |
|
8839 if (ctxt->encoding != NULL) |
|
8840 xmlFree((xmlChar *) ctxt->encoding); |
|
8841 ctxt->encoding = encoding; |
|
8842 } |
|
8843 /* |
|
8844 * UTF-8 encoding is handled natively |
|
8845 */ |
|
8846 else if ((encoding != NULL) && |
|
8847 ((!xmlStrcasecmp(encoding, BAD_CAST "UTF-8")) || |
|
8848 (!xmlStrcasecmp(encoding, BAD_CAST "UTF8")))) { |
|
8849 if (ctxt->encoding != NULL) |
|
8850 xmlFree((xmlChar *) ctxt->encoding); |
|
8851 ctxt->encoding = encoding; |
|
8852 } |
|
8853 else if (encoding != NULL) { |
|
8854 xmlCharEncodingHandlerPtr handler; |
|
8855 |
|
8856 if (ctxt->input->encoding != NULL) |
|
8857 xmlFree((xmlChar *) ctxt->input->encoding); |
|
8858 ctxt->input->encoding = encoding; |
|
8859 |
|
8860 handler = xmlFindCharEncodingHandler((const char *) encoding); |
|
8861 if (handler != NULL) { |
|
8862 xmlSwitchToEncoding(ctxt, handler); |
|
8863 } else { |
|
8864 xmlFatalErrMsgStr(ctxt, XML_ERR_UNSUPPORTED_ENCODING, |
|
8865 EMBED_ERRTXT("Unsupported encoding %s\n"), encoding); |
|
8866 return(NULL); |
|
8867 } |
|
8868 } |
|
8869 } |
|
8870 return(encoding); |
|
8871 } |
|
8872 |
|
8873 /** |
|
8874 * xmlParseSDDecl: |
|
8875 * @param ctxt an XML parser context |
|
8876 * |
|
8877 * parse the XML standalone declaration |
|
8878 * |
|
8879 * [32] SDDecl ::= S 'standalone' Eq |
|
8880 * (("'" ('yes' | 'no') "'") | ('"' ('yes' | 'no')'"')) |
|
8881 * |
|
8882 * [ VC: Standalone Document Declaration ] |
|
8883 * The standalone document declaration must have the value "no" |
|
8884 * if any external markup declarations contain declarations of: |
|
8885 * - attributes with default values, if elements to which these |
|
8886 * attributes apply appear in the document without specifications |
|
8887 * of values for these attributes, or |
|
8888 * - entities (other than amp, lt, gt, apos, quot), if references |
|
8889 * to those entities appear in the document, or |
|
8890 * - attributes with values subject to normalization, where the |
|
8891 * attribute appears in the document with a value which will change |
|
8892 * as a result of normalization, or |
|
8893 * - element types with element content, if white space occurs directly |
|
8894 * within any instance of those types. |
|
8895 * |
|
8896 * Returns 1 if standalone, 0 otherwise |
|
8897 */ |
|
8898 |
|
8899 XMLPUBFUNEXPORT int |
|
8900 xmlParseSDDecl(xmlParserCtxtPtr ctxt) { |
|
8901 int standalone = -1; |
|
8902 |
|
8903 SKIP_BLANKS; |
|
8904 if (CMP10(CUR_PTR, 's', 't', 'a', 'n', 'd', 'a', 'l', 'o', 'n', 'e')) { |
|
8905 SKIP(10); |
|
8906 SKIP_BLANKS; |
|
8907 if (RAW != '=') { |
|
8908 xmlFatalErr(ctxt, XML_ERR_EQUAL_REQUIRED, NULL); |
|
8909 return(standalone); |
|
8910 } |
|
8911 NEXT; |
|
8912 SKIP_BLANKS; |
|
8913 if (RAW == '\''){ |
|
8914 NEXT; |
|
8915 if ((RAW == 'n') && (NXT(1) == 'o')) { |
|
8916 standalone = 0; |
|
8917 SKIP(2); |
|
8918 } else if ((RAW == 'y') && (NXT(1) == 'e') && |
|
8919 (NXT(2) == 's')) { |
|
8920 standalone = 1; |
|
8921 SKIP(3); |
|
8922 } else { |
|
8923 xmlFatalErr(ctxt, XML_ERR_STANDALONE_VALUE, NULL); |
|
8924 } |
|
8925 if (RAW != '\'') { |
|
8926 xmlFatalErr(ctxt, XML_ERR_STRING_NOT_CLOSED, NULL); |
|
8927 } else |
|
8928 NEXT; |
|
8929 } else if (RAW == '"'){ |
|
8930 NEXT; |
|
8931 if ((RAW == 'n') && (NXT(1) == 'o')) { |
|
8932 standalone = 0; |
|
8933 SKIP(2); |
|
8934 } else if ((RAW == 'y') && (NXT(1) == 'e') && |
|
8935 (NXT(2) == 's')) { |
|
8936 standalone = 1; |
|
8937 SKIP(3); |
|
8938 } else { |
|
8939 xmlFatalErr(ctxt, XML_ERR_STANDALONE_VALUE, NULL); |
|
8940 } |
|
8941 if (RAW != '"') { |
|
8942 xmlFatalErr(ctxt, XML_ERR_STRING_NOT_CLOSED, NULL); |
|
8943 } else |
|
8944 NEXT; |
|
8945 } else { |
|
8946 xmlFatalErr(ctxt, XML_ERR_STRING_NOT_STARTED, NULL); |
|
8947 } |
|
8948 } |
|
8949 return(standalone); |
|
8950 } |
|
8951 |
|
8952 /** |
|
8953 * xmlParseXMLDecl: |
|
8954 * @param ctxt an XML parser context |
|
8955 * |
|
8956 * parse an XML declaration header |
|
8957 * |
|
8958 * [23] XMLDecl ::= '<?xml' VersionInfo EncodingDecl? SDDecl? S? '?>' |
|
8959 * |
|
8960 * OOM: |
|
8961 */ |
|
8962 XMLPUBFUNEXPORT void |
|
8963 xmlParseXMLDecl(xmlParserCtxtPtr ctxt) { |
|
8964 xmlChar *version; |
|
8965 /* |
|
8966 * We know that '<?xml' is here. |
|
8967 */ |
|
8968 SKIP(5); |
|
8969 |
|
8970 if (!IS_BLANK_CH(RAW)) { |
|
8971 xmlFatalErrMsg(ctxt, XML_ERR_SPACE_REQUIRED, |
|
8972 EMBED_ERRTXT("Blank needed after '<?xml'\n")); |
|
8973 } |
|
8974 SKIP_BLANKS; |
|
8975 |
|
8976 /* |
|
8977 * We must have the VersionInfo here. |
|
8978 */ |
|
8979 version = xmlParseVersionInfo(ctxt); |
|
8980 if (version == NULL) { |
|
8981 xmlFatalErr(ctxt, XML_ERR_VERSION_MISSING, NULL); |
|
8982 } else { |
|
8983 if (!xmlStrEqual(version, (const xmlChar *) XML_DEFAULT_VERSION)) { |
|
8984 /* |
|
8985 |
|
8986 */ |
|
8987 xmlWarningMsg(ctxt, XML_WAR_UNKNOWN_VERSION, |
|
8988 EMBED_ERRTXT("Unsupported version '%s'\n"), |
|
8989 version, NULL); |
|
8990 } |
|
8991 if (ctxt->version != NULL) |
|
8992 xmlFree((void *) ctxt->version); |
|
8993 ctxt->version = version; |
|
8994 } |
|
8995 |
|
8996 /* |
|
8997 * We may have the encoding declaration |
|
8998 */ |
|
8999 if (!IS_BLANK_CH(RAW)) { |
|
9000 if ((RAW == '?') && (NXT(1) == '>')) { |
|
9001 SKIP(2); |
|
9002 return; |
|
9003 } |
|
9004 xmlFatalErrMsg(ctxt, XML_ERR_SPACE_REQUIRED, EMBED_ERRTXT("Blank needed here\n")); |
|
9005 } |
|
9006 xmlParseEncodingDecl(ctxt); |
|
9007 if (ctxt->errNo == XML_ERR_UNSUPPORTED_ENCODING) { |
|
9008 /* |
|
9009 * The XML REC instructs us to stop parsing right here |
|
9010 */ |
|
9011 return; |
|
9012 } |
|
9013 |
|
9014 /* |
|
9015 * We may have the standalone status. |
|
9016 */ |
|
9017 if ((ctxt->input->encoding != NULL) && (!IS_BLANK_CH(RAW))) { |
|
9018 if ((RAW == '?') && (NXT(1) == '>')) { |
|
9019 SKIP(2); |
|
9020 return; |
|
9021 } |
|
9022 xmlFatalErrMsg(ctxt, XML_ERR_SPACE_REQUIRED, EMBED_ERRTXT("Blank needed here\n")); |
|
9023 } |
|
9024 SKIP_BLANKS; |
|
9025 ctxt->input->standalone = xmlParseSDDecl(ctxt); |
|
9026 |
|
9027 SKIP_BLANKS; |
|
9028 if ((RAW == '?') && (NXT(1) == '>')) { |
|
9029 SKIP(2); |
|
9030 } else if (RAW == '>') { |
|
9031 /* Deprecated old WD ... */ |
|
9032 xmlFatalErr(ctxt, XML_ERR_XMLDECL_NOT_FINISHED, NULL); |
|
9033 NEXT; |
|
9034 } else { |
|
9035 xmlFatalErr(ctxt, XML_ERR_XMLDECL_NOT_FINISHED, NULL); |
|
9036 MOVETO_ENDTAG(CUR_PTR); |
|
9037 NEXT; |
|
9038 } |
|
9039 } |
|
9040 |
|
9041 /** |
|
9042 * xmlParseMisc: |
|
9043 * @param ctxt an XML parser context |
|
9044 * |
|
9045 * parse an XML Misc* optional field. |
|
9046 * |
|
9047 * [27] Misc ::= Comment | PI | S |
|
9048 */ |
|
9049 |
|
9050 XMLPUBFUNEXPORT void |
|
9051 xmlParseMisc(xmlParserCtxtPtr ctxt) { |
|
9052 while (((RAW == '<') && (NXT(1) == '?')) || |
|
9053 (CMP4(CUR_PTR, '<', '!', '-', '-')) || |
|
9054 IS_BLANK_CH(CUR)) { |
|
9055 if ((RAW == '<') && (NXT(1) == '?')) { |
|
9056 xmlParsePI(ctxt); |
|
9057 } else if (IS_BLANK_CH(CUR)) { |
|
9058 NEXT; |
|
9059 } else |
|
9060 xmlParseComment(ctxt); |
|
9061 } |
|
9062 } |
|
9063 |
|
9064 /** |
|
9065 * xmlParseDocument: |
|
9066 * @param ctxt an XML parser context |
|
9067 * |
|
9068 * parse an XML document (and build a tree if using the standard SAX |
|
9069 * interface). |
|
9070 * |
|
9071 * [1] document ::= prolog element Misc* |
|
9072 * |
|
9073 * [22] prolog ::= XMLDecl? Misc* (doctypedecl Misc*)? |
|
9074 * |
|
9075 * Returns 0, -1 in case of error. the parser context is augmented |
|
9076 * as a result of the parsing. |
|
9077 * |
|
9078 * OOM: possible, of course --> check OOM flag [REVIEW NOT FINISHED] |
|
9079 */ |
|
9080 |
|
9081 XMLPUBFUNEXPORT int |
|
9082 xmlParseDocument(xmlParserCtxtPtr ctxt) { |
|
9083 xmlChar start[4]; |
|
9084 xmlCharEncoding enc; |
|
9085 LOAD_GS_SAFE_CTXT(ctxt) |
|
9086 |
|
9087 xmlInitParser(); |
|
9088 if(OOM_FLAG) |
|
9089 return -1; |
|
9090 GROW; |
|
9091 if(OOM_FLAG) |
|
9092 return -1; |
|
9093 |
|
9094 /* |
|
9095 * SAX: detecting the level. |
|
9096 */ |
|
9097 xmlDetectSAX2(ctxt); |
|
9098 if(OOM_FLAG) |
|
9099 return (-1); |
|
9100 /* |
|
9101 * SAX: beginning of the document processing. |
|
9102 */ |
|
9103 if ((ctxt->sax) && (ctxt->sax->setDocumentLocator)) |
|
9104 { |
|
9105 ctxt->sax->setDocumentLocator(ctxt->userData, (xmlSAXLocatorPtr)&xmlDefaultSAXLocator); |
|
9106 if(OOM_FLAG) |
|
9107 return -1; |
|
9108 } |
|
9109 |
|
9110 if ((ctxt->encoding == (const xmlChar*)XML_CHAR_ENCODING_NONE) && |
|
9111 ((ctxt->input->end - ctxt->input->cur) >= 4)) |
|
9112 { |
|
9113 /* |
|
9114 * Get the 4 first bytes and decode the charset |
|
9115 * if enc != XML_CHAR_ENCODING_NONE |
|
9116 * plug some encoding conversion routines. |
|
9117 */ |
|
9118 start[0] = RAW; |
|
9119 start[1] = NXT(1); |
|
9120 start[2] = NXT(2); |
|
9121 start[3] = NXT(3); |
|
9122 enc = xmlDetectCharEncoding(&start[0], 4); |
|
9123 if (enc != XML_CHAR_ENCODING_NONE) { |
|
9124 xmlSwitchEncoding(ctxt, enc); |
|
9125 if(OOM_FLAG) |
|
9126 return -1; |
|
9127 } |
|
9128 } |
|
9129 |
|
9130 |
|
9131 if (CUR == 0) { |
|
9132 xmlFatalErr(ctxt, XML_ERR_DOCUMENT_EMPTY, NULL); |
|
9133 } |
|
9134 |
|
9135 /* |
|
9136 * Check for the XMLDecl in the Prolog. |
|
9137 */ |
|
9138 GROW; |
|
9139 if(OOM_FLAG) |
|
9140 return -1; |
|
9141 if ((CMP5(CUR_PTR, '<', '?', 'x', 'm', 'l')) && (IS_BLANK_CH(NXT(5)))) |
|
9142 { |
|
9143 /* |
|
9144 * Note that we will switch encoding on the fly. |
|
9145 */ |
|
9146 xmlParseXMLDecl(ctxt); |
|
9147 if(OOM_FLAG) |
|
9148 return -1; |
|
9149 if (ctxt->errNo == XML_ERR_UNSUPPORTED_ENCODING) { |
|
9150 /* |
|
9151 * The XML REC instructs us to stop parsing right here |
|
9152 */ |
|
9153 return(-1); |
|
9154 } |
|
9155 ctxt->standalone = ctxt->input->standalone; |
|
9156 SKIP_BLANKS; |
|
9157 if(OOM_FLAG) |
|
9158 return -1; |
|
9159 } else { |
|
9160 ctxt->version = xmlCharStrdup(XML_DEFAULT_VERSION); |
|
9161 if(OOM_FLAG) |
|
9162 return -1; |
|
9163 } |
|
9164 if ((ctxt->sax) && (ctxt->sax->startDocument) && (!ctxt->disableSAX)) |
|
9165 { |
|
9166 ctxt->sax->startDocument(ctxt->userData); |
|
9167 if(OOM_FLAG) |
|
9168 return -1; |
|
9169 } |
|
9170 /* |
|
9171 * The Misc part of the Prolog |
|
9172 */ |
|
9173 GROW; |
|
9174 if(OOM_FLAG) |
|
9175 return -1; |
|
9176 xmlParseMisc(ctxt); |
|
9177 if(OOM_FLAG) |
|
9178 return -1; |
|
9179 /* |
|
9180 * Then possibly doc type declaration(s) and more Misc |
|
9181 * (doctypedecl Misc*)? |
|
9182 */ |
|
9183 GROW; |
|
9184 if(OOM_FLAG) |
|
9185 return -1; |
|
9186 if (CMP9(CUR_PTR, '<', '!', 'D', 'O', 'C', 'T', 'Y', 'P', 'E')) { |
|
9187 |
|
9188 ctxt->inSubset = 1; |
|
9189 xmlParseDocTypeDecl(ctxt); |
|
9190 if(OOM_FLAG) |
|
9191 return -1; |
|
9192 if (RAW == '[') { |
|
9193 ctxt->instate = XML_PARSER_DTD; |
|
9194 xmlParseInternalSubset(ctxt); |
|
9195 if(OOM_FLAG) |
|
9196 return -1; |
|
9197 } |
|
9198 |
|
9199 /* |
|
9200 * Create and update the external subset. |
|
9201 */ |
|
9202 ctxt->inSubset = 2; |
|
9203 if ((ctxt->sax != NULL) && (ctxt->sax->externalSubset != NULL) && |
|
9204 (!ctxt->disableSAX)) |
|
9205 { |
|
9206 ctxt->sax->externalSubset(ctxt->userData, ctxt->intSubName, |
|
9207 ctxt->extSubSystem, ctxt->extSubURI); |
|
9208 if(OOM_FLAG) |
|
9209 return -1; |
|
9210 } |
|
9211 ctxt->inSubset = 0; |
|
9212 |
|
9213 ctxt->instate = XML_PARSER_PROLOG; |
|
9214 xmlParseMisc(ctxt); |
|
9215 if(OOM_FLAG) |
|
9216 return -1; |
|
9217 } |
|
9218 |
|
9219 /* |
|
9220 * Time to start parsing the tree itself |
|
9221 */ |
|
9222 GROW; |
|
9223 if(OOM_FLAG) |
|
9224 return -1; |
|
9225 if (RAW != '<') { |
|
9226 xmlFatalErrMsg(ctxt, XML_ERR_DOCUMENT_EMPTY, |
|
9227 EMBED_ERRTXT("Start tag expected, '<' not found\n")); |
|
9228 } else { |
|
9229 ctxt->instate = XML_PARSER_CONTENT; |
|
9230 xmlParseElement(ctxt); |
|
9231 if(OOM_FLAG) |
|
9232 return -1; |
|
9233 ctxt->instate = XML_PARSER_EPILOG; |
|
9234 |
|
9235 |
|
9236 /* |
|
9237 * The Misc part at the end |
|
9238 */ |
|
9239 xmlParseMisc(ctxt); |
|
9240 if(OOM_FLAG) |
|
9241 return -1; |
|
9242 if (RAW != 0) { |
|
9243 xmlFatalErr(ctxt, XML_ERR_DOCUMENT_END, NULL); |
|
9244 } |
|
9245 ctxt->instate = XML_PARSER_EOF; |
|
9246 } |
|
9247 |
|
9248 /* |
|
9249 * SAX: end of the document processing. |
|
9250 */ |
|
9251 if ((ctxt->sax) && (ctxt->sax->endDocument != NULL)) |
|
9252 { |
|
9253 ctxt->sax->endDocument(ctxt->userData); |
|
9254 if(OOM_FLAG) |
|
9255 return -1; |
|
9256 } |
|
9257 |
|
9258 /* |
|
9259 * Remove locally kept entity definitions if the tree was not built |
|
9260 */ |
|
9261 if ((ctxt->myDoc != NULL) && |
|
9262 (xmlStrEqual(ctxt->myDoc->version, SAX_COMPAT_MODE))) |
|
9263 { |
|
9264 xmlFreeDoc(ctxt->myDoc); |
|
9265 ctxt->myDoc = NULL; |
|
9266 } |
|
9267 |
|
9268 if (! ctxt->wellFormed) { |
|
9269 ctxt->valid = 0; |
|
9270 return(-1); |
|
9271 } |
|
9272 return(0); |
|
9273 } |
|
9274 |
|
9275 /** |
|
9276 * xmlParseExtParsedEnt: |
|
9277 * @param ctxt an XML parser context |
|
9278 * |
|
9279 * parse a general parsed entity |
|
9280 * An external general parsed entity is well-formed if it matches the |
|
9281 * production labeled extParsedEnt. |
|
9282 * |
|
9283 * [78] extParsedEnt ::= TextDecl? content |
|
9284 * |
|
9285 * Returns 0, -1 in case of error. the parser context is augmented |
|
9286 * as a result of the parsing. |
|
9287 */ |
|
9288 |
|
9289 XMLPUBFUNEXPORT int |
|
9290 xmlParseExtParsedEnt(xmlParserCtxtPtr ctxt) { |
|
9291 xmlChar start[4]; |
|
9292 xmlCharEncoding enc; |
|
9293 LOAD_GS_SAFE_CTXT(ctxt) |
|
9294 |
|
9295 xmlDefaultSAXHandlerInit(); |
|
9296 if(OOM_FLAG) |
|
9297 return -1; |
|
9298 |
|
9299 xmlDetectSAX2(ctxt); |
|
9300 if(OOM_FLAG) |
|
9301 return -1; |
|
9302 |
|
9303 GROW; |
|
9304 if(OOM_FLAG) |
|
9305 return -1; |
|
9306 /* |
|
9307 * SAX: beginning of the document processing. |
|
9308 */ |
|
9309 if ((ctxt->sax) && (ctxt->sax->setDocumentLocator)) |
|
9310 { |
|
9311 ctxt->sax->setDocumentLocator(ctxt->userData, (xmlSAXLocatorPtr)&xmlDefaultSAXLocator); |
|
9312 } |
|
9313 /* |
|
9314 * Get the 4 first bytes and decode the charset |
|
9315 * if enc != XML_CHAR_ENCODING_NONE |
|
9316 * plug some encoding conversion routines. |
|
9317 */ |
|
9318 if ((ctxt->input->end - ctxt->input->cur) >= 4) { |
|
9319 start[0] = RAW; |
|
9320 start[1] = NXT(1); |
|
9321 start[2] = NXT(2); |
|
9322 start[3] = NXT(3); |
|
9323 enc = xmlDetectCharEncoding(start, 4); |
|
9324 if (enc != XML_CHAR_ENCODING_NONE) { |
|
9325 xmlSwitchEncoding(ctxt, enc); |
|
9326 if(OOM_FLAG) |
|
9327 return -1; |
|
9328 } |
|
9329 } |
|
9330 |
|
9331 if (CUR == 0) { |
|
9332 xmlFatalErr(ctxt, XML_ERR_DOCUMENT_EMPTY, NULL); |
|
9333 } |
|
9334 |
|
9335 /* |
|
9336 * Check for the XMLDecl in the Prolog. |
|
9337 */ |
|
9338 GROW; |
|
9339 if(OOM_FLAG) |
|
9340 return -1; |
|
9341 |
|
9342 if ((CMP5(CUR_PTR, '<', '?', 'x', 'm', 'l')) && (IS_BLANK_CH(NXT(5)))) { |
|
9343 |
|
9344 /* |
|
9345 * Note that we will switch encoding on the fly. |
|
9346 */ |
|
9347 xmlParseXMLDecl(ctxt); |
|
9348 if (ctxt->errNo == XML_ERR_UNSUPPORTED_ENCODING) { |
|
9349 /* |
|
9350 * The XML REC instructs us to stop parsing right here |
|
9351 */ |
|
9352 return(-1); |
|
9353 } |
|
9354 SKIP_BLANKS; |
|
9355 } else { |
|
9356 ctxt->version = xmlCharStrdup(XML_DEFAULT_VERSION); |
|
9357 } |
|
9358 if ((ctxt->sax) && (ctxt->sax->startDocument) && (!ctxt->disableSAX)) |
|
9359 ctxt->sax->startDocument(ctxt->userData); |
|
9360 |
|
9361 /* |
|
9362 * Doing validity checking on chunk doesn't make sense |
|
9363 */ |
|
9364 ctxt->instate = XML_PARSER_CONTENT; |
|
9365 ctxt->validate = 0; |
|
9366 ctxt->loadsubset = 0; |
|
9367 ctxt->depth = 0; |
|
9368 |
|
9369 xmlParseContent(ctxt); |
|
9370 |
|
9371 if ((RAW == '<') && (NXT(1) == '/')) { |
|
9372 xmlFatalErr(ctxt, XML_ERR_NOT_WELL_BALANCED, NULL); |
|
9373 } else if (RAW != 0) { |
|
9374 xmlFatalErr(ctxt, XML_ERR_EXTRA_CONTENT, NULL); |
|
9375 } |
|
9376 |
|
9377 /* |
|
9378 * SAX: end of the document processing. |
|
9379 */ |
|
9380 if ((ctxt->sax) && (ctxt->sax->endDocument != NULL)) |
|
9381 ctxt->sax->endDocument(ctxt->userData); |
|
9382 |
|
9383 if (! ctxt->wellFormed) return(-1); |
|
9384 return(0); |
|
9385 } |
|
9386 |
|
9387 #ifdef LIBXML_PUSH_ENABLED |
|
9388 /************************************************************************ |
|
9389 * * |
|
9390 * Progressive parsing interfaces * |
|
9391 * * |
|
9392 ************************************************************************/ |
|
9393 |
|
9394 /** |
|
9395 * xmlParseLookupSequence: |
|
9396 * @param ctxt an XML parser context |
|
9397 * @param first the first char to lookup |
|
9398 * @param next the next char to lookup or zero |
|
9399 * @param third the next char to lookup or zero |
|
9400 * |
|
9401 * Try to find if a sequence (first, next, third) or just (first next) or |
|
9402 * (first) is available in the input stream. |
|
9403 * This function has a side effect of (possibly) incrementing ctxt->checkIndex |
|
9404 * to avoid rescanning sequences of bytes, it DOES change the state of the |
|
9405 * parser, do not use liberally. |
|
9406 * |
|
9407 * Returns the index to the current parsing point if the full sequence |
|
9408 * is available, -1 otherwise. |
|
9409 */ |
|
9410 static int |
|
9411 xmlParseLookupSequence(xmlParserCtxtPtr ctxt, xmlChar first, |
|
9412 xmlChar next, xmlChar third) { |
|
9413 int base, len; |
|
9414 xmlParserInputPtr in; |
|
9415 const xmlChar *buf; |
|
9416 |
|
9417 in = ctxt->input; |
|
9418 if (in == NULL) return(-1); |
|
9419 base = in->cur - in->base; |
|
9420 if (base < 0) return(-1); |
|
9421 if (ctxt->checkIndex > base) |
|
9422 base = ctxt->checkIndex; |
|
9423 if (in->buf == NULL) { |
|
9424 buf = in->base; |
|
9425 len = in->length; |
|
9426 } else { |
|
9427 buf = in->buf->buffer->content; |
|
9428 len = in->buf->buffer->use; |
|
9429 } |
|
9430 /* take into account the sequence length */ |
|
9431 if (third) len -= 2; |
|
9432 else if (next) len --; |
|
9433 for (;base < len;base++) { |
|
9434 if (buf[base] == first) { |
|
9435 if (third != 0) { |
|
9436 if ((buf[base + 1] != next) || |
|
9437 (buf[base + 2] != third)) continue; |
|
9438 } else if (next != 0) { |
|
9439 if (buf[base + 1] != next) continue; |
|
9440 } |
|
9441 ctxt->checkIndex = 0; |
|
9442 #ifdef DEBUG_PUSH |
|
9443 if (next == 0) |
|
9444 xmlGenericError(xmlGenericErrorContext, |
|
9445 "PP: lookup '%c' found at %d\n", |
|
9446 first, base); |
|
9447 else if (third == 0) |
|
9448 xmlGenericError(xmlGenericErrorContext, |
|
9449 "PP: lookup '%c%c' found at %d\n", |
|
9450 first, next, base); |
|
9451 else |
|
9452 xmlGenericError(xmlGenericErrorContext, |
|
9453 "PP: lookup '%c%c%c' found at %d\n", |
|
9454 first, next, third, base); |
|
9455 #endif |
|
9456 return(base - (in->cur - in->base)); |
|
9457 } |
|
9458 } |
|
9459 ctxt->checkIndex = base; |
|
9460 #ifdef DEBUG_PUSH |
|
9461 if (next == 0) |
|
9462 xmlGenericError(xmlGenericErrorContext, |
|
9463 "PP: lookup '%c' failed\n", first); |
|
9464 else if (third == 0) |
|
9465 xmlGenericError(xmlGenericErrorContext, |
|
9466 "PP: lookup '%c%c' failed\n", first, next); |
|
9467 else |
|
9468 xmlGenericError(xmlGenericErrorContext, |
|
9469 "PP: lookup '%c%c%c' failed\n", first, next, third); |
|
9470 #endif |
|
9471 return(-1); |
|
9472 } |
|
9473 |
|
9474 /** |
|
9475 * xmlParseGetLasts: |
|
9476 * @param ctxt an XML parser context |
|
9477 * @param lastlt pointer to store the last '<' from the input |
|
9478 * @param lastgt pointer to store the last '>' from the input |
|
9479 * |
|
9480 * Lookup the last < and > in the current chunk |
|
9481 */ |
|
9482 static void |
|
9483 xmlParseGetLasts(xmlParserCtxtPtr ctxt, const xmlChar **lastlt, |
|
9484 const xmlChar **lastgt) { |
|
9485 const xmlChar *tmp; |
|
9486 |
|
9487 if ((ctxt == NULL) || (lastlt == NULL) || (lastgt == NULL)) { |
|
9488 xmlGenericError(xmlGenericErrorContext, |
|
9489 EMBED_ERRTXT("Internal error: xmlParseGetLasts\n")); |
|
9490 return; |
|
9491 } |
|
9492 if ((ctxt->progressive == 1) && (ctxt->inputNr == 1)) { |
|
9493 tmp = ctxt->input->end; |
|
9494 tmp--; |
|
9495 while ((tmp >= ctxt->input->base) && (*tmp != '<') && |
|
9496 (*tmp != '>')) tmp--; |
|
9497 if (tmp < ctxt->input->base) { |
|
9498 *lastlt = NULL; |
|
9499 *lastgt = NULL; |
|
9500 } else if (*tmp == '<') { |
|
9501 *lastlt = tmp; |
|
9502 tmp--; |
|
9503 while ((tmp >= ctxt->input->base) && (*tmp != '>')) tmp--; |
|
9504 if (tmp < ctxt->input->base) |
|
9505 *lastgt = NULL; |
|
9506 else |
|
9507 *lastgt = tmp; |
|
9508 } else { |
|
9509 *lastgt = tmp; |
|
9510 tmp--; |
|
9511 while ((tmp >= ctxt->input->base) && (*tmp != '<')) tmp--; |
|
9512 if (tmp < ctxt->input->base) |
|
9513 *lastlt = NULL; |
|
9514 else |
|
9515 *lastlt = tmp; |
|
9516 } |
|
9517 |
|
9518 } else { |
|
9519 *lastlt = NULL; |
|
9520 *lastgt = NULL; |
|
9521 } |
|
9522 } |
|
9523 /** |
|
9524 * xmlParseTryOrFinish: |
|
9525 * @param ctxt an XML parser context |
|
9526 * @param terminate last chunk indicator |
|
9527 * |
|
9528 * Try to progress on parsing |
|
9529 * |
|
9530 * Returns zero if no parsing was possible |
|
9531 */ |
|
9532 static int |
|
9533 xmlParseTryOrFinish(xmlParserCtxtPtr ctxt, int terminate) { |
|
9534 int ret = 0; |
|
9535 int avail, tlen; |
|
9536 xmlChar cur, next; |
|
9537 const xmlChar *lastlt, *lastgt; |
|
9538 LOAD_GS_SAFE_CTXT(ctxt) |
|
9539 |
|
9540 if (ctxt->input == NULL) |
|
9541 return(0); |
|
9542 |
|
9543 #ifdef DEBUG_PUSH |
|
9544 switch (ctxt->instate) { |
|
9545 case XML_PARSER_EOF: |
|
9546 xmlGenericError(xmlGenericErrorContext, |
|
9547 "PP: try EOF\n"); break; |
|
9548 case XML_PARSER_START: |
|
9549 xmlGenericError(xmlGenericErrorContext, |
|
9550 "PP: try START\n"); break; |
|
9551 case XML_PARSER_MISC: |
|
9552 xmlGenericError(xmlGenericErrorContext, |
|
9553 "PP: try MISC\n");break; |
|
9554 case XML_PARSER_COMMENT: |
|
9555 xmlGenericError(xmlGenericErrorContext, |
|
9556 "PP: try COMMENT\n");break; |
|
9557 case XML_PARSER_PROLOG: |
|
9558 xmlGenericError(xmlGenericErrorContext, |
|
9559 "PP: try PROLOG\n");break; |
|
9560 case XML_PARSER_START_TAG: |
|
9561 xmlGenericError(xmlGenericErrorContext, |
|
9562 "PP: try START_TAG\n");break; |
|
9563 case XML_PARSER_CONTENT: |
|
9564 xmlGenericError(xmlGenericErrorContext, |
|
9565 "PP: try CONTENT\n");break; |
|
9566 case XML_PARSER_CDATA_SECTION: |
|
9567 xmlGenericError(xmlGenericErrorContext, |
|
9568 "PP: try CDATA_SECTION\n");break; |
|
9569 case XML_PARSER_END_TAG: |
|
9570 xmlGenericError(xmlGenericErrorContext, |
|
9571 "PP: try END_TAG\n");break; |
|
9572 case XML_PARSER_ENTITY_DECL: |
|
9573 xmlGenericError(xmlGenericErrorContext, |
|
9574 "PP: try ENTITY_DECL\n");break; |
|
9575 case XML_PARSER_ENTITY_VALUE: |
|
9576 xmlGenericError(xmlGenericErrorContext, |
|
9577 "PP: try ENTITY_VALUE\n");break; |
|
9578 case XML_PARSER_ATTRIBUTE_VALUE: |
|
9579 xmlGenericError(xmlGenericErrorContext, |
|
9580 "PP: try ATTRIBUTE_VALUE\n");break; |
|
9581 case XML_PARSER_DTD: |
|
9582 xmlGenericError(xmlGenericErrorContext, |
|
9583 "PP: try DTD\n");break; |
|
9584 case XML_PARSER_EPILOG: |
|
9585 xmlGenericError(xmlGenericErrorContext, |
|
9586 "PP: try EPILOG\n");break; |
|
9587 case XML_PARSER_PI: |
|
9588 xmlGenericError(xmlGenericErrorContext, |
|
9589 "PP: try PI\n");break; |
|
9590 case XML_PARSER_IGNORE: |
|
9591 xmlGenericError(xmlGenericErrorContext, |
|
9592 "PP: try IGNORE\n");break; |
|
9593 } |
|
9594 #endif |
|
9595 |
|
9596 if ((ctxt->input != NULL) && (ctxt->input->cur - ctxt->input->base > 4096)) { |
|
9597 xmlSHRINK(ctxt); |
|
9598 ctxt->checkIndex = 0; |
|
9599 } |
|
9600 |
|
9601 xmlParseGetLasts(ctxt, &lastlt, &lastgt); |
|
9602 |
|
9603 while (1) |
|
9604 { |
|
9605 if ((ctxt->errNo != XML_ERR_OK) && (ctxt->disableSAX == 1)) |
|
9606 return(0); |
|
9607 |
|
9608 /* |
|
9609 * Pop-up of finished entities. |
|
9610 */ |
|
9611 while ((RAW == 0) && (ctxt->inputNr > 1)) |
|
9612 xmlPopInput(ctxt); |
|
9613 |
|
9614 if (ctxt->input == NULL) break; |
|
9615 if (ctxt->input->buf == NULL){ |
|
9616 avail = ctxt->input->length - (ctxt->input->cur - ctxt->input->base); |
|
9617 }else{ |
|
9618 /* |
|
9619 * If we are operating on converted input, try to flush |
|
9620 * remainng chars to avoid them stalling in the non-converted |
|
9621 * buffer. |
|
9622 */ |
|
9623 if ((ctxt->input->buf->raw != NULL) && (ctxt->input->buf->raw->use > 0)) |
|
9624 { |
|
9625 int base = ctxt->input->base - ctxt->input->buf->buffer->content; |
|
9626 int current = ctxt->input->cur - ctxt->input->base; |
|
9627 xmlParserInputBufferPush(ctxt->input->buf, 0, ""); |
|
9628 ctxt->input->base = ctxt->input->buf->buffer->content + base; |
|
9629 ctxt->input->cur = ctxt->input->base + current; |
|
9630 ctxt->input->end = &ctxt->input->buf->buffer->content[ ctxt->input->buf->buffer->use]; |
|
9631 } |
|
9632 |
|
9633 avail = ctxt->input->buf->buffer->use - (ctxt->input->cur - ctxt->input->base); |
|
9634 } |
|
9635 |
|
9636 if (avail < 1) |
|
9637 goto done; |
|
9638 |
|
9639 switch (ctxt->instate) { |
|
9640 |
|
9641 case XML_PARSER_EOF: |
|
9642 /* |
|
9643 * Document parsing is done ! |
|
9644 */ |
|
9645 goto done; |
|
9646 |
|
9647 case XML_PARSER_START: |
|
9648 if (ctxt->charset == XML_CHAR_ENCODING_NONE) { |
|
9649 xmlChar start[4]; |
|
9650 xmlCharEncoding enc; |
|
9651 |
|
9652 /* |
|
9653 * Very first chars read from the document flow. |
|
9654 */ |
|
9655 if (avail < 4) goto done; |
|
9656 /* |
|
9657 * Get the 4 first bytes and decode the charset |
|
9658 * if enc != XML_CHAR_ENCODING_NONE |
|
9659 * plug some encoding conversion routines. |
|
9660 */ |
|
9661 start[0] = RAW; |
|
9662 start[1] = NXT(1); |
|
9663 start[2] = NXT(2); |
|
9664 start[3] = NXT(3); |
|
9665 enc = xmlDetectCharEncoding(start, 4); |
|
9666 if (enc != XML_CHAR_ENCODING_NONE) { |
|
9667 xmlSwitchEncoding(ctxt, enc); |
|
9668 } |
|
9669 break; |
|
9670 } |
|
9671 |
|
9672 if (avail < 2) |
|
9673 goto done; |
|
9674 |
|
9675 cur = ctxt->input->cur[0]; |
|
9676 next = ctxt->input->cur[1]; |
|
9677 |
|
9678 if (cur == 0) { |
|
9679 if ((ctxt->sax) && (ctxt->sax->setDocumentLocator)) |
|
9680 { |
|
9681 ctxt->sax->setDocumentLocator(ctxt->userData, (xmlSAXLocatorPtr)&xmlDefaultSAXLocator); |
|
9682 } |
|
9683 xmlFatalErr(ctxt, XML_ERR_DOCUMENT_EMPTY, NULL); |
|
9684 ctxt->instate = XML_PARSER_EOF; |
|
9685 #ifdef DEBUG_PUSH |
|
9686 xmlGenericError(xmlGenericErrorContext, "PP: entering EOF\n"); |
|
9687 #endif |
|
9688 if ((ctxt->sax) && (ctxt->sax->endDocument != NULL)) |
|
9689 ctxt->sax->endDocument(ctxt->userData); |
|
9690 goto done; |
|
9691 } |
|
9692 |
|
9693 if ((cur == '<') && (next == '?')) { |
|
9694 /* PI or XML decl */ |
|
9695 if (avail < 5) return(ret); |
|
9696 if ((!terminate) && (xmlParseLookupSequence(ctxt, '?', '>', 0) < 0)) |
|
9697 return(ret); |
|
9698 if ((ctxt->sax) && (ctxt->sax->setDocumentLocator)) |
|
9699 { |
|
9700 ctxt->sax->setDocumentLocator(ctxt->userData, (xmlSAXLocatorPtr)&xmlDefaultSAXLocator); |
|
9701 } |
|
9702 if ((ctxt->input->cur[2] == 'x') && |
|
9703 (ctxt->input->cur[3] == 'm') && |
|
9704 (ctxt->input->cur[4] == 'l') && |
|
9705 (IS_BLANK_CH(ctxt->input->cur[5]))) |
|
9706 { |
|
9707 ret += 5; |
|
9708 #ifdef DEBUG_PUSH |
|
9709 xmlGenericError(xmlGenericErrorContext, "PP: Parsing XML Decl\n"); |
|
9710 #endif |
|
9711 xmlParseXMLDecl(ctxt); |
|
9712 if (ctxt->errNo == XML_ERR_UNSUPPORTED_ENCODING) { |
|
9713 /* |
|
9714 * The XML REC instructs us to stop parsing right |
|
9715 * here |
|
9716 */ |
|
9717 ctxt->instate = XML_PARSER_EOF; |
|
9718 return(0); |
|
9719 } |
|
9720 |
|
9721 ctxt->standalone = ctxt->input->standalone; |
|
9722 |
|
9723 if ((ctxt->encoding == NULL) && (ctxt->input->encoding != NULL)) |
|
9724 ctxt->encoding = xmlStrdup(ctxt->input->encoding); |
|
9725 |
|
9726 if ((ctxt->sax) && (ctxt->sax->startDocument) && (!ctxt->disableSAX)) |
|
9727 ctxt->sax->startDocument(ctxt->userData); |
|
9728 |
|
9729 ctxt->instate = XML_PARSER_MISC; |
|
9730 #ifdef DEBUG_PUSH |
|
9731 xmlGenericError(xmlGenericErrorContext, "PP: entering MISC\n"); |
|
9732 #endif |
|
9733 } |
|
9734 else |
|
9735 { |
|
9736 ctxt->version = xmlCharStrdup(XML_DEFAULT_VERSION); |
|
9737 if ((ctxt->sax) && (ctxt->sax->startDocument) && (!ctxt->disableSAX)) |
|
9738 ctxt->sax->startDocument(ctxt->userData); |
|
9739 |
|
9740 ctxt->instate = XML_PARSER_MISC; |
|
9741 #ifdef DEBUG_PUSH |
|
9742 xmlGenericError(xmlGenericErrorContext, "PP: entering MISC\n"); |
|
9743 #endif |
|
9744 } |
|
9745 } // if ((cur == '<') && (next == '?')) |
|
9746 else |
|
9747 { |
|
9748 if ((ctxt->sax) && (ctxt->sax->setDocumentLocator)) |
|
9749 { |
|
9750 ctxt->sax->setDocumentLocator(ctxt->userData, (xmlSAXLocatorPtr) &xmlDefaultSAXLocator); |
|
9751 } |
|
9752 ctxt->version = xmlCharStrdup(XML_DEFAULT_VERSION); |
|
9753 if(OOM_FLAG) |
|
9754 { |
|
9755 xmlParserOOMErr(ctxt); |
|
9756 return(0); |
|
9757 } |
|
9758 |
|
9759 if ((ctxt->sax) && (ctxt->sax->startDocument) && (!ctxt->disableSAX)) |
|
9760 { |
|
9761 ctxt->sax->startDocument(ctxt->userData); |
|
9762 if(OOM_FLAG) |
|
9763 { |
|
9764 xmlParserOOMErr(ctxt); |
|
9765 return(0); |
|
9766 } |
|
9767 } |
|
9768 ctxt->instate = XML_PARSER_MISC; |
|
9769 #ifdef DEBUG_PUSH |
|
9770 xmlGenericError(xmlGenericErrorContext, "PP: entering MISC\n"); |
|
9771 #endif |
|
9772 } |
|
9773 break; |
|
9774 |
|
9775 case XML_PARSER_START_TAG: { |
|
9776 const xmlChar *name; |
|
9777 const xmlChar *prefix; |
|
9778 const xmlChar *URI; |
|
9779 int nsNr = ctxt->nsNr; |
|
9780 |
|
9781 if ((avail < 2) && (ctxt->inputNr == 1)) |
|
9782 goto done; |
|
9783 |
|
9784 cur = ctxt->input->cur[0]; |
|
9785 if (cur != '<') { |
|
9786 xmlFatalErr(ctxt, XML_ERR_DOCUMENT_EMPTY, NULL); |
|
9787 ctxt->instate = XML_PARSER_EOF; |
|
9788 if ((ctxt->sax) && (ctxt->sax->endDocument != NULL)) |
|
9789 ctxt->sax->endDocument(ctxt->userData); |
|
9790 goto done; |
|
9791 } |
|
9792 |
|
9793 if (!terminate) { |
|
9794 if (ctxt->progressive) { |
|
9795 /* > can be found unescaped in attribute values */ |
|
9796 if ((lastlt == NULL) || (ctxt->input->cur >= lastlt)) |
|
9797 goto done; |
|
9798 } |
|
9799 else if (xmlParseLookupSequence(ctxt, '>', 0, 0) < 0) { |
|
9800 goto done; |
|
9801 } |
|
9802 } |
|
9803 if (ctxt->spaceNr == 0){ |
|
9804 spacePush(ctxt, -1); |
|
9805 }else{ |
|
9806 spacePush(ctxt, *ctxt->space); |
|
9807 } |
|
9808 #ifdef LIBXML_SAX1_ENABLED |
|
9809 if (ctxt->sax2) |
|
9810 { |
|
9811 #endif /* LIBXML_SAX1_ENABLED */ |
|
9812 name = xmlParseStartTag2(ctxt, &prefix, &URI, &tlen); |
|
9813 #ifdef LIBXML_SAX1_ENABLED |
|
9814 } |
|
9815 else |
|
9816 { |
|
9817 name = xmlParseStartTag(ctxt); |
|
9818 } |
|
9819 #endif /* LIBXML_SAX1_ENABLED */ |
|
9820 if(OOM_FLAG) |
|
9821 { |
|
9822 // Note: xmlParseStartTag2 should have set parser into error state already |
|
9823 xmlParserOOMErr(ctxt); // just in case |
|
9824 return(0); |
|
9825 } |
|
9826 |
|
9827 if (name == NULL) { |
|
9828 spacePop(ctxt); |
|
9829 ctxt->instate = XML_PARSER_EOF; |
|
9830 if ((ctxt->sax) && (ctxt->sax->endDocument != NULL)) |
|
9831 ctxt->sax->endDocument(ctxt->userData); |
|
9832 goto done; |
|
9833 } |
|
9834 |
|
9835 #ifdef LIBXML_VALID_ENABLED |
|
9836 /* |
|
9837 * [ VC: Root Element Type ] |
|
9838 * The Name in the document type declaration must match |
|
9839 * the element type of the root element. |
|
9840 */ |
|
9841 if (ctxt->validate && |
|
9842 ctxt->wellFormed && ctxt->myDoc && |
|
9843 ctxt->node && (ctxt->node == ctxt->myDoc->children)) |
|
9844 { |
|
9845 ctxt->valid &= xmlValidateRoot(&ctxt->vctxt, ctxt->myDoc); |
|
9846 } |
|
9847 #endif /* LIBXML_VALID_ENABLED */ |
|
9848 |
|
9849 /* |
|
9850 * Check for an Empty Element. |
|
9851 */ |
|
9852 if ((RAW == '/') && (NXT(1) == '>')) { |
|
9853 SKIP(2); |
|
9854 |
|
9855 if (ctxt->sax2) { |
|
9856 if ((ctxt->sax != NULL) && |
|
9857 (ctxt->sax->endElementNs != NULL) && |
|
9858 (!ctxt->disableSAX)) |
|
9859 { |
|
9860 ctxt->sax->endElementNs(ctxt->userData, name, prefix, URI); |
|
9861 } |
|
9862 #ifdef LIBXML_SAX1_ENABLED |
|
9863 } else { |
|
9864 if ((ctxt->sax != NULL) && |
|
9865 (ctxt->sax->endElement != NULL) && |
|
9866 (!ctxt->disableSAX)) |
|
9867 { |
|
9868 ctxt->sax->endElement(ctxt->userData, name); |
|
9869 } |
|
9870 #endif /* LIBXML_SAX1_ENABLED */ |
|
9871 } |
|
9872 spacePop(ctxt); |
|
9873 if (ctxt->nameNr == 0) { |
|
9874 ctxt->instate = XML_PARSER_EPILOG; |
|
9875 } else { |
|
9876 ctxt->instate = XML_PARSER_CONTENT; |
|
9877 } |
|
9878 // XE: BEGIN NEW CODE |
|
9879 // Remove from namsespaces stack all namespaces |
|
9880 // that were declared in this empty element |
|
9881 nsPop(ctxt, ctxt->lastNsNr*2); |
|
9882 // XE: END NEW CODE |
|
9883 break; |
|
9884 } // if ((RAW == '/') && (NXT(1) == '>')) |
|
9885 |
|
9886 if (RAW == '>') { |
|
9887 NEXT; |
|
9888 } else { |
|
9889 xmlFatalErrMsgStr(ctxt, XML_ERR_GT_REQUIRED, EMBED_ERRTXT("Couldn't find end of Start Tag %s\n"), name); |
|
9890 nodePop(ctxt); |
|
9891 spacePop(ctxt); |
|
9892 } |
|
9893 if (ctxt->sax2){ |
|
9894 nameNsPush(ctxt, name, prefix, URI, ctxt->nsNr - nsNr); |
|
9895 #ifdef LIBXML_SAX1_ENABLED |
|
9896 }else{ |
|
9897 namePush(ctxt, name); |
|
9898 #endif /* LIBXML_SAX1_ENABLED */ |
|
9899 } |
|
9900 |
|
9901 ctxt->instate = XML_PARSER_CONTENT; |
|
9902 break; |
|
9903 } |
|
9904 |
|
9905 case XML_PARSER_CONTENT: { |
|
9906 const xmlChar *test; |
|
9907 unsigned int cons; |
|
9908 if ((avail < 2) && (ctxt->inputNr == 1)) |
|
9909 goto done; |
|
9910 cur = ctxt->input->cur[0]; |
|
9911 next = ctxt->input->cur[1]; |
|
9912 |
|
9913 test = CUR_PTR; |
|
9914 cons = ctxt->input->consumed; |
|
9915 if ((cur == '<') && (next == '/')) { |
|
9916 ctxt->instate = XML_PARSER_END_TAG; |
|
9917 break; |
|
9918 } else if ((cur == '<') && (next == '?')) { |
|
9919 if ((!terminate) && |
|
9920 (xmlParseLookupSequence(ctxt, '?', '>', 0) < 0)) |
|
9921 goto done; |
|
9922 xmlParsePI(ctxt); |
|
9923 } else if ((cur == '<') && (next != '!')) { |
|
9924 ctxt->instate = XML_PARSER_START_TAG; |
|
9925 break; |
|
9926 } else if ((cur == '<') && (next == '!') && |
|
9927 (ctxt->input->cur[2] == '-') && |
|
9928 (ctxt->input->cur[3] == '-')) { |
|
9929 if ((!terminate) && |
|
9930 (xmlParseLookupSequence(ctxt, '-', '-', '>') < 0)) |
|
9931 goto done; |
|
9932 xmlParseComment(ctxt); |
|
9933 ctxt->instate = XML_PARSER_CONTENT; |
|
9934 } else if ((cur == '<') && (ctxt->input->cur[1] == '!') && |
|
9935 (ctxt->input->cur[2] == '[') && |
|
9936 (ctxt->input->cur[3] == 'C') && |
|
9937 (ctxt->input->cur[4] == 'D') && |
|
9938 (ctxt->input->cur[5] == 'A') && |
|
9939 (ctxt->input->cur[6] == 'T') && |
|
9940 (ctxt->input->cur[7] == 'A') && |
|
9941 (ctxt->input->cur[8] == '[')) { |
|
9942 SKIP(9); |
|
9943 ctxt->instate = XML_PARSER_CDATA_SECTION; |
|
9944 break; |
|
9945 } else if ((cur == '<') && (next == '!') && |
|
9946 (avail < 9)) { |
|
9947 goto done; |
|
9948 } else if (cur == '&') { |
|
9949 if ((!terminate) && |
|
9950 (xmlParseLookupSequence(ctxt, ';', 0, 0) < 0)) |
|
9951 goto done; |
|
9952 xmlParseReference(ctxt); |
|
9953 if(OOM_FLAG) |
|
9954 { |
|
9955 return(0); |
|
9956 } |
|
9957 } else { |
|
9958 |
|
9959 /* |
|
9960 * Goal of the following test is: |
|
9961 * - minimize calls to the SAX 'character' callback |
|
9962 * when they are mergeable |
|
9963 * - handle an problem for isBlank when we only parse |
|
9964 * a sequence of blank chars and the next one is |
|
9965 * not available to check against '<' presence. |
|
9966 * - tries to homogenize the differences in SAX |
|
9967 * callbacks between the push and pull versions |
|
9968 * of the parser. |
|
9969 */ |
|
9970 if ((ctxt->inputNr == 1) && |
|
9971 (avail < XML_PARSER_BIG_BUFFER_SIZE)) { |
|
9972 if (!terminate) { |
|
9973 if (ctxt->progressive) { |
|
9974 if ((lastlt == NULL) || |
|
9975 (ctxt->input->cur > lastlt)) |
|
9976 goto done; |
|
9977 } else if (xmlParseLookupSequence(ctxt, |
|
9978 '<', 0, 0) < 0) { |
|
9979 goto done; |
|
9980 } |
|
9981 } |
|
9982 } |
|
9983 ctxt->checkIndex = 0; |
|
9984 xmlParseCharData(ctxt, 0); |
|
9985 } |
|
9986 /* |
|
9987 * Pop-up of finished entities. |
|
9988 */ |
|
9989 while ((RAW == 0) && (ctxt->inputNr > 1)) |
|
9990 xmlPopInput(ctxt); |
|
9991 if ((cons == ctxt->input->consumed) && (test == CUR_PTR)) { |
|
9992 xmlFatalErr(ctxt, XML_ERR_INTERNAL_ERROR, |
|
9993 EMBED_ERRTXT("detected an error in element content\n")); |
|
9994 ctxt->instate = XML_PARSER_EOF; |
|
9995 break; |
|
9996 } |
|
9997 break; |
|
9998 } |
|
9999 case XML_PARSER_END_TAG: |
|
10000 if (avail < 2) |
|
10001 goto done; |
|
10002 if (!terminate) { |
|
10003 if (ctxt->progressive) { |
|
10004 if ((lastgt == NULL) || (ctxt->input->cur > lastgt)) |
|
10005 goto done; |
|
10006 } else if (xmlParseLookupSequence(ctxt, '>', 0, 0) < 0) { |
|
10007 goto done; |
|
10008 } |
|
10009 } |
|
10010 if (ctxt->sax2) { |
|
10011 xmlParseEndTag2(ctxt, |
|
10012 (xmlChar*) ctxt->pushTab[ctxt->nameNr * 3 - 3], |
|
10013 (xmlChar*) ctxt->pushTab[ctxt->nameNr * 3 - 2], 0, |
|
10014 (int) (long) ctxt->pushTab[ctxt->nameNr * 3 - 1], 0); |
|
10015 nameNsPop(ctxt); |
|
10016 } |
|
10017 #ifdef LIBXML_SAX1_ENABLED |
|
10018 else |
|
10019 xmlParseEndTag1(ctxt, 0); |
|
10020 #endif /* LIBXML_SAX1_ENABLED */ |
|
10021 if (ctxt->nameNr == 0) { |
|
10022 ctxt->instate = XML_PARSER_EPILOG; |
|
10023 } else { |
|
10024 ctxt->instate = XML_PARSER_CONTENT; |
|
10025 } |
|
10026 break; |
|
10027 case XML_PARSER_CDATA_SECTION: { |
|
10028 /* |
|
10029 * The Push mode need to have the SAX callback for |
|
10030 * cdataBlock merge back contiguous callbacks. |
|
10031 */ |
|
10032 int base; |
|
10033 |
|
10034 base = xmlParseLookupSequence(ctxt, ']', ']', '>'); |
|
10035 if (base < 0) { |
|
10036 if (avail >= XML_PARSER_BIG_BUFFER_SIZE + 2) { |
|
10037 int tmp; |
|
10038 |
|
10039 tmp = xmlCheckCdataPush(ctxt->input->cur, |
|
10040 XML_PARSER_BIG_BUFFER_SIZE); |
|
10041 if (tmp < 0) { |
|
10042 tmp = -tmp; |
|
10043 ctxt->input->cur += tmp; |
|
10044 goto encoding_error; |
|
10045 } |
|
10046 if ((ctxt->sax != NULL) && (!ctxt->disableSAX)) { |
|
10047 if (ctxt->sax->cdataBlock != NULL) |
|
10048 ctxt->sax->cdataBlock(ctxt->userData, |
|
10049 ctxt->input->cur, tmp); |
|
10050 else if (ctxt->sax->characters != NULL) |
|
10051 ctxt->sax->characters(ctxt->userData, |
|
10052 ctxt->input->cur, tmp); |
|
10053 } |
|
10054 SKIPL(tmp); |
|
10055 ctxt->checkIndex = 0; |
|
10056 } |
|
10057 goto done; |
|
10058 } else { |
|
10059 int tmp; |
|
10060 |
|
10061 tmp = xmlCheckCdataPush(ctxt->input->cur, base); |
|
10062 if ((tmp < 0) || (tmp != base)) { |
|
10063 tmp = -tmp; |
|
10064 ctxt->input->cur += tmp; |
|
10065 goto encoding_error; |
|
10066 } |
|
10067 if ((ctxt->sax != NULL) && (base > 0) && |
|
10068 (!ctxt->disableSAX)) { |
|
10069 if (ctxt->sax->cdataBlock != NULL) |
|
10070 ctxt->sax->cdataBlock(ctxt->userData, |
|
10071 ctxt->input->cur, base); |
|
10072 else if (ctxt->sax->characters != NULL) |
|
10073 ctxt->sax->characters(ctxt->userData, |
|
10074 ctxt->input->cur, base); |
|
10075 } |
|
10076 SKIPL(base + 3); |
|
10077 ctxt->checkIndex = 0; |
|
10078 ctxt->instate = XML_PARSER_CONTENT; |
|
10079 #ifdef DEBUG_PUSH |
|
10080 xmlGenericError(xmlGenericErrorContext, |
|
10081 "PP: entering CONTENT\n"); |
|
10082 #endif |
|
10083 } |
|
10084 break; |
|
10085 } |
|
10086 case XML_PARSER_MISC: |
|
10087 SKIP_BLANKS; |
|
10088 if (ctxt->input->buf == NULL) |
|
10089 avail = ctxt->input->length - |
|
10090 (ctxt->input->cur - ctxt->input->base); |
|
10091 else |
|
10092 avail = ctxt->input->buf->buffer->use - |
|
10093 (ctxt->input->cur - ctxt->input->base); |
|
10094 if (avail < 2) |
|
10095 goto done; |
|
10096 cur = ctxt->input->cur[0]; |
|
10097 next = ctxt->input->cur[1]; |
|
10098 if ((cur == '<') && (next == '?')) { |
|
10099 if ((!terminate) && |
|
10100 (xmlParseLookupSequence(ctxt, '?', '>', 0) < 0)) |
|
10101 goto done; |
|
10102 #ifdef DEBUG_PUSH |
|
10103 xmlGenericError(xmlGenericErrorContext, |
|
10104 "PP: Parsing PI\n"); |
|
10105 #endif |
|
10106 xmlParsePI(ctxt); |
|
10107 } else if ((cur == '<') && (next == '!') && |
|
10108 (ctxt->input->cur[2] == '-') && |
|
10109 (ctxt->input->cur[3] == '-')) { |
|
10110 if ((!terminate) && |
|
10111 (xmlParseLookupSequence(ctxt, '-', '-', '>') < 0)) |
|
10112 goto done; |
|
10113 #ifdef DEBUG_PUSH |
|
10114 xmlGenericError(xmlGenericErrorContext, |
|
10115 "PP: Parsing Comment\n"); |
|
10116 #endif |
|
10117 xmlParseComment(ctxt); |
|
10118 ctxt->instate = XML_PARSER_MISC; |
|
10119 } else if ((cur == '<') && (next == '!') && |
|
10120 (ctxt->input->cur[2] == 'D') && |
|
10121 (ctxt->input->cur[3] == 'O') && |
|
10122 (ctxt->input->cur[4] == 'C') && |
|
10123 (ctxt->input->cur[5] == 'T') && |
|
10124 (ctxt->input->cur[6] == 'Y') && |
|
10125 (ctxt->input->cur[7] == 'P') && |
|
10126 (ctxt->input->cur[8] == 'E')) { |
|
10127 if ((!terminate) && |
|
10128 (xmlParseLookupSequence(ctxt, '>', 0, 0) < 0)) |
|
10129 goto done; |
|
10130 #ifdef DEBUG_PUSH |
|
10131 xmlGenericError(xmlGenericErrorContext, |
|
10132 "PP: Parsing internal subset\n"); |
|
10133 #endif |
|
10134 ctxt->inSubset = 1; |
|
10135 xmlParseDocTypeDecl(ctxt); |
|
10136 if (RAW == '[') { |
|
10137 ctxt->instate = XML_PARSER_DTD; |
|
10138 #ifdef DEBUG_PUSH |
|
10139 xmlGenericError(xmlGenericErrorContext, |
|
10140 "PP: entering DTD\n"); |
|
10141 #endif |
|
10142 } else { |
|
10143 /* |
|
10144 * Create and update the external subset. |
|
10145 */ |
|
10146 ctxt->inSubset = 2; |
|
10147 if ((ctxt->sax != NULL) && (!ctxt->disableSAX) && |
|
10148 (ctxt->sax->externalSubset != NULL)) |
|
10149 { |
|
10150 ctxt->sax->externalSubset(ctxt->userData, |
|
10151 ctxt->intSubName, ctxt->extSubSystem, |
|
10152 ctxt->extSubURI); |
|
10153 } |
|
10154 ctxt->inSubset = 0; |
|
10155 ctxt->instate = XML_PARSER_PROLOG; |
|
10156 #ifdef DEBUG_PUSH |
|
10157 xmlGenericError(xmlGenericErrorContext, "PP: entering PROLOG\n"); |
|
10158 #endif |
|
10159 } |
|
10160 } else if ((cur == '<') && (next == '!') && (avail < 9)) { |
|
10161 goto done; |
|
10162 } else { |
|
10163 ctxt->instate = XML_PARSER_START_TAG; |
|
10164 ctxt->progressive = 1; |
|
10165 xmlParseGetLasts(ctxt, &lastlt, &lastgt); |
|
10166 #ifdef DEBUG_PUSH |
|
10167 xmlGenericError(xmlGenericErrorContext, |
|
10168 "PP: entering START_TAG\n"); |
|
10169 #endif |
|
10170 } |
|
10171 break; |
|
10172 case XML_PARSER_PROLOG: |
|
10173 SKIP_BLANKS; |
|
10174 if (ctxt->input->buf == NULL) |
|
10175 avail = ctxt->input->length - (ctxt->input->cur - ctxt->input->base); |
|
10176 else |
|
10177 avail = ctxt->input->buf->buffer->use - (ctxt->input->cur - ctxt->input->base); |
|
10178 if (avail < 2) |
|
10179 goto done; |
|
10180 cur = ctxt->input->cur[0]; |
|
10181 next = ctxt->input->cur[1]; |
|
10182 if ((cur == '<') && (next == '?')) { |
|
10183 if ((!terminate) && |
|
10184 (xmlParseLookupSequence(ctxt, '?', '>', 0) < 0)) |
|
10185 goto done; |
|
10186 #ifdef DEBUG_PUSH |
|
10187 xmlGenericError(xmlGenericErrorContext, |
|
10188 "PP: Parsing PI\n"); |
|
10189 #endif |
|
10190 xmlParsePI(ctxt); |
|
10191 } else if ((cur == '<') && (next == '!') && |
|
10192 (ctxt->input->cur[2] == '-') && (ctxt->input->cur[3] == '-')) { |
|
10193 if ((!terminate) && |
|
10194 (xmlParseLookupSequence(ctxt, '-', '-', '>') < 0)) |
|
10195 goto done; |
|
10196 #ifdef DEBUG_PUSH |
|
10197 xmlGenericError(xmlGenericErrorContext, |
|
10198 "PP: Parsing Comment\n"); |
|
10199 #endif |
|
10200 xmlParseComment(ctxt); |
|
10201 ctxt->instate = XML_PARSER_PROLOG; |
|
10202 } else if ((cur == '<') && (next == '!') && |
|
10203 (avail < 4)) { |
|
10204 goto done; |
|
10205 } else { |
|
10206 ctxt->instate = XML_PARSER_START_TAG; |
|
10207 if (ctxt->progressive == 0) |
|
10208 ctxt->progressive = 1; |
|
10209 xmlParseGetLasts(ctxt, &lastlt, &lastgt); |
|
10210 #ifdef DEBUG_PUSH |
|
10211 xmlGenericError(xmlGenericErrorContext, |
|
10212 "PP: entering START_TAG\n"); |
|
10213 #endif |
|
10214 } |
|
10215 break; |
|
10216 case XML_PARSER_EPILOG: |
|
10217 SKIP_BLANKS; |
|
10218 if (ctxt->input->buf == NULL) |
|
10219 avail = ctxt->input->length - (ctxt->input->cur - ctxt->input->base); |
|
10220 else |
|
10221 avail = ctxt->input->buf->buffer->use - (ctxt->input->cur - ctxt->input->base); |
|
10222 if (avail < 2) |
|
10223 goto done; |
|
10224 cur = ctxt->input->cur[0]; |
|
10225 next = ctxt->input->cur[1]; |
|
10226 if ((cur == '<') && (next == '?')) { |
|
10227 if ((!terminate) && |
|
10228 (xmlParseLookupSequence(ctxt, '?', '>', 0) < 0)) |
|
10229 goto done; |
|
10230 #ifdef DEBUG_PUSH |
|
10231 xmlGenericError(xmlGenericErrorContext, |
|
10232 "PP: Parsing PI\n"); |
|
10233 #endif |
|
10234 xmlParsePI(ctxt); |
|
10235 ctxt->instate = XML_PARSER_EPILOG; |
|
10236 } else if ((cur == '<') && (next == '!') && |
|
10237 (ctxt->input->cur[2] == '-') && (ctxt->input->cur[3] == '-')) { |
|
10238 if ((!terminate) && |
|
10239 (xmlParseLookupSequence(ctxt, '-', '-', '>') < 0)) |
|
10240 goto done; |
|
10241 #ifdef DEBUG_PUSH |
|
10242 xmlGenericError(xmlGenericErrorContext, |
|
10243 "PP: Parsing Comment\n"); |
|
10244 #endif |
|
10245 xmlParseComment(ctxt); |
|
10246 ctxt->instate = XML_PARSER_EPILOG; |
|
10247 } else if ((cur == '<') && (next == '!') && |
|
10248 (avail < 4)) { |
|
10249 goto done; |
|
10250 } else { |
|
10251 xmlFatalErr(ctxt, XML_ERR_DOCUMENT_END, NULL); |
|
10252 ctxt->instate = XML_PARSER_EOF; |
|
10253 #ifdef DEBUG_PUSH |
|
10254 xmlGenericError(xmlGenericErrorContext, |
|
10255 "PP: entering EOF\n"); |
|
10256 #endif |
|
10257 if ((ctxt->sax) && (ctxt->sax->endDocument != NULL)) |
|
10258 ctxt->sax->endDocument(ctxt->userData); |
|
10259 goto done; |
|
10260 } |
|
10261 break; |
|
10262 case XML_PARSER_DTD: { |
|
10263 /* |
|
10264 * Sorry but progressive parsing of the internal subset |
|
10265 * is not expected to be supported. We first check that |
|
10266 * the full content of the internal subset is available and |
|
10267 * the parsing is launched only at that point. |
|
10268 * Internal subset ends up with "']' S? '>'" in an unescaped |
|
10269 * section and not in a ']]>' sequence which are conditional |
|
10270 * sections (whoever argued to keep that crap in XML deserve |
|
10271 * a place in hell !). |
|
10272 */ |
|
10273 int base, i; |
|
10274 xmlChar *buf; |
|
10275 xmlChar quote = 0; |
|
10276 |
|
10277 base = ctxt->input->cur - ctxt->input->base; |
|
10278 if (base < 0) return(0); |
|
10279 if (ctxt->checkIndex > base) |
|
10280 base = ctxt->checkIndex; |
|
10281 buf = ctxt->input->buf->buffer->content; |
|
10282 for (;(unsigned int) base < ctxt->input->buf->buffer->use; |
|
10283 base++) { |
|
10284 if (quote != 0) { |
|
10285 if (buf[base] == quote) |
|
10286 quote = 0; |
|
10287 continue; |
|
10288 } |
|
10289 if ((quote == 0) && (buf[base] == '<')) { |
|
10290 int found = 0; |
|
10291 /* special handling of comments */ |
|
10292 if (((unsigned int) base + 4 < |
|
10293 ctxt->input->buf->buffer->use) && |
|
10294 (buf[base + 1] == '!') && |
|
10295 (buf[base + 2] == '-') && |
|
10296 (buf[base + 3] == '-')) { |
|
10297 for (;(unsigned int) base + 3 < |
|
10298 ctxt->input->buf->buffer->use; base++) { |
|
10299 if ((buf[base] == '-') && |
|
10300 (buf[base + 1] == '-') && |
|
10301 (buf[base + 2] == '>')) { |
|
10302 found = 1; |
|
10303 base += 2; |
|
10304 break; |
|
10305 } |
|
10306 } |
|
10307 if (!found) { |
|
10308 break; /* for */ |
|
10309 } |
|
10310 continue; |
|
10311 } |
|
10312 } |
|
10313 if (buf[base] == '"') { |
|
10314 quote = '"'; |
|
10315 continue; |
|
10316 } |
|
10317 if (buf[base] == '\'') { |
|
10318 quote = '\''; |
|
10319 continue; |
|
10320 } |
|
10321 if (buf[base] == ']') { |
|
10322 if ((unsigned int) base +1 >= |
|
10323 ctxt->input->buf->buffer->use) |
|
10324 break; |
|
10325 if (buf[base + 1] == ']') { |
|
10326 /* conditional crap, skip both ']' ! */ |
|
10327 base++; |
|
10328 continue; |
|
10329 } |
|
10330 for (i = 0; |
|
10331 (unsigned int) base + i < ctxt->input->buf->buffer->use; |
|
10332 i++) { |
|
10333 if (buf[base + i] == '>') |
|
10334 goto found_end_int_subset; |
|
10335 } |
|
10336 break; |
|
10337 } |
|
10338 } |
|
10339 /* |
|
10340 * We didn't found the end of the Internal subset |
|
10341 */ |
|
10342 if (quote == 0) |
|
10343 ctxt->checkIndex = base; |
|
10344 #ifdef DEBUG_PUSH |
|
10345 if (next == 0) |
|
10346 xmlGenericError(xmlGenericErrorContext, |
|
10347 "PP: lookup of int subset end filed\n"); |
|
10348 #endif |
|
10349 goto done; |
|
10350 |
|
10351 found_end_int_subset: |
|
10352 xmlParseInternalSubset(ctxt); |
|
10353 if(OOM_FLAG) |
|
10354 { |
|
10355 return 0; |
|
10356 } |
|
10357 ctxt->inSubset = 2; |
|
10358 if ((ctxt->sax != NULL) && (!ctxt->disableSAX) && |
|
10359 (ctxt->sax->externalSubset != NULL)) |
|
10360 ctxt->sax->externalSubset(ctxt->userData, ctxt->intSubName, |
|
10361 ctxt->extSubSystem, ctxt->extSubURI); |
|
10362 ctxt->inSubset = 0; |
|
10363 ctxt->instate = XML_PARSER_PROLOG; |
|
10364 ctxt->checkIndex = 0; |
|
10365 #ifdef DEBUG_PUSH |
|
10366 xmlGenericError(xmlGenericErrorContext, |
|
10367 "PP: entering PROLOG\n"); |
|
10368 #endif |
|
10369 break; |
|
10370 } |
|
10371 case XML_PARSER_COMMENT: |
|
10372 xmlGenericError(xmlGenericErrorContext, |
|
10373 EMBED_ERRTXT("PP: internal error, state == COMMENT\n")); |
|
10374 ctxt->instate = XML_PARSER_CONTENT; |
|
10375 #ifdef DEBUG_PUSH |
|
10376 xmlGenericError(xmlGenericErrorContext, |
|
10377 "PP: entering CONTENT\n"); |
|
10378 #endif |
|
10379 break; |
|
10380 case XML_PARSER_IGNORE: |
|
10381 xmlGenericError(xmlGenericErrorContext, |
|
10382 EMBED_ERRTXT("PP: internal error, state == IGNORE")); |
|
10383 ctxt->instate = XML_PARSER_DTD; |
|
10384 #ifdef DEBUG_PUSH |
|
10385 xmlGenericError(xmlGenericErrorContext, |
|
10386 "PP: entering DTD\n"); |
|
10387 #endif |
|
10388 break; |
|
10389 case XML_PARSER_PI: |
|
10390 xmlGenericError(xmlGenericErrorContext, |
|
10391 EMBED_ERRTXT("PP: internal error, state == PI\n")); |
|
10392 ctxt->instate = XML_PARSER_CONTENT; |
|
10393 #ifdef DEBUG_PUSH |
|
10394 xmlGenericError(xmlGenericErrorContext, |
|
10395 "PP: entering CONTENT\n"); |
|
10396 #endif |
|
10397 break; |
|
10398 case XML_PARSER_ENTITY_DECL: |
|
10399 xmlGenericError(xmlGenericErrorContext, |
|
10400 EMBED_ERRTXT("PP: internal error, state == ENTITY_DECL\n")); |
|
10401 ctxt->instate = XML_PARSER_DTD; |
|
10402 #ifdef DEBUG_PUSH |
|
10403 xmlGenericError(xmlGenericErrorContext, |
|
10404 "PP: entering DTD\n"); |
|
10405 #endif |
|
10406 break; |
|
10407 case XML_PARSER_ENTITY_VALUE: |
|
10408 xmlGenericError(xmlGenericErrorContext, |
|
10409 EMBED_ERRTXT("PP: internal error, state == ENTITY_VALUE\n")); |
|
10410 ctxt->instate = XML_PARSER_CONTENT; |
|
10411 #ifdef DEBUG_PUSH |
|
10412 xmlGenericError(xmlGenericErrorContext, |
|
10413 "PP: entering DTD\n"); |
|
10414 #endif |
|
10415 break; |
|
10416 case XML_PARSER_ATTRIBUTE_VALUE: |
|
10417 xmlGenericError(xmlGenericErrorContext, |
|
10418 EMBED_ERRTXT("PP: internal error, state == ATTRIBUTE_VALUE\n")); |
|
10419 ctxt->instate = XML_PARSER_START_TAG; |
|
10420 #ifdef DEBUG_PUSH |
|
10421 xmlGenericError(xmlGenericErrorContext, |
|
10422 "PP: entering START_TAG\n"); |
|
10423 #endif |
|
10424 break; |
|
10425 case XML_PARSER_SYSTEM_LITERAL: |
|
10426 xmlGenericError(xmlGenericErrorContext, |
|
10427 EMBED_ERRTXT("PP: internal error, state == SYSTEM_LITERAL\n")); |
|
10428 ctxt->instate = XML_PARSER_START_TAG; |
|
10429 #ifdef DEBUG_PUSH |
|
10430 xmlGenericError(xmlGenericErrorContext, |
|
10431 "PP: entering START_TAG\n"); |
|
10432 #endif |
|
10433 break; |
|
10434 case XML_PARSER_PUBLIC_LITERAL: |
|
10435 xmlGenericError(xmlGenericErrorContext, |
|
10436 EMBED_ERRTXT("PP: internal error, state == PUBLIC_LITERAL\n")); |
|
10437 ctxt->instate = XML_PARSER_START_TAG; |
|
10438 #ifdef DEBUG_PUSH |
|
10439 xmlGenericError(xmlGenericErrorContext, |
|
10440 "PP: entering START_TAG\n"); |
|
10441 #endif |
|
10442 break; |
|
10443 } |
|
10444 } |
|
10445 done: |
|
10446 #ifdef DEBUG_PUSH |
|
10447 xmlGenericError(xmlGenericErrorContext, "PP: done %d\n", ret); |
|
10448 #endif |
|
10449 return(ret); |
|
10450 encoding_error: |
|
10451 { |
|
10452 char buffer[150]; |
|
10453 snprintf(buffer, 149, "Bytes: 0x%02X 0x%02X 0x%02X 0x%02X\n", |
|
10454 ctxt->input->cur[0], ctxt->input->cur[1], |
|
10455 ctxt->input->cur[2], ctxt->input->cur[3]); |
|
10456 __xmlErrEncoding(ctxt, XML_ERR_INVALID_CHAR, |
|
10457 "Input is not proper UTF-8, indicate encoding !\n%s", |
|
10458 BAD_CAST buffer, NULL); |
|
10459 } |
|
10460 return(0); |
|
10461 } |
|
10462 |
|
10463 /** |
|
10464 * xmlParseChunk: |
|
10465 * @param ctxt an XML parser context |
|
10466 * @param chunk an char array |
|
10467 * @param size the size in byte of the chunk |
|
10468 * @param terminate last chunk indicator |
|
10469 * |
|
10470 * Parse a Chunk of memory |
|
10471 * |
|
10472 * Returns zero if no error, the xmlParserErrors otherwise. |
|
10473 */ |
|
10474 XMLPUBFUNEXPORT int |
|
10475 xmlParseChunk(xmlParserCtxtPtr ctxt, const char* chunk, int size, int terminate) |
|
10476 { |
|
10477 LOAD_GS_SAFE_CTXT(ctxt) |
|
10478 if ((ctxt->errNo != XML_ERR_OK) && (ctxt->disableSAX == 1)) |
|
10479 return(ctxt->errNo); |
|
10480 |
|
10481 if (ctxt->instate == XML_PARSER_START) |
|
10482 { |
|
10483 xmlDetectSAX2(ctxt); |
|
10484 if( OOM_FLAG ) |
|
10485 { |
|
10486 xmlParserOOMErr(ctxt); |
|
10487 return(XML_ERR_NO_MEMORY); |
|
10488 } |
|
10489 } |
|
10490 |
|
10491 if (size > 0 && |
|
10492 chunk && |
|
10493 ctxt->input && |
|
10494 ctxt->input->buf && |
|
10495 ctxt->instate != XML_PARSER_EOF) |
|
10496 { |
|
10497 int base = ctxt->input->base - ctxt->input->buf->buffer->content; |
|
10498 int cur = ctxt->input->cur - ctxt->input->base; |
|
10499 |
|
10500 xmlParserInputBufferPush(ctxt->input->buf, size, chunk); |
|
10501 ctxt->input->base = ctxt->input->buf->buffer->content + base; |
|
10502 ctxt->input->cur = ctxt->input->base + cur; |
|
10503 ctxt->input->end = &ctxt->input->buf->buffer->content[ctxt->input->buf->buffer->use]; |
|
10504 #ifdef DEBUG_PUSH |
|
10505 xmlGenericError(xmlGenericErrorContext, "PP: pushed %d\n", size); |
|
10506 #endif |
|
10507 } |
|
10508 else if (ctxt->instate != XML_PARSER_EOF) |
|
10509 { |
|
10510 if (ctxt->input && ctxt->input->buf) |
|
10511 { |
|
10512 xmlParserInputBufferPtr in = ctxt->input->buf; |
|
10513 if (in->encoder && |
|
10514 in->buffer && |
|
10515 in->raw) |
|
10516 { |
|
10517 int nbchars; |
|
10518 |
|
10519 nbchars = xmlCharEncInFunc(in->encoder, in->buffer, in->raw); |
|
10520 if (nbchars < 0) |
|
10521 { |
|
10522 |
|
10523 xmlGenericError(xmlGenericErrorContext, |
|
10524 EMBED_ERRTXT("xmlParseChunk: encoder error\n")); |
|
10525 return(XML_ERR_INVALID_ENCODING); |
|
10526 } |
|
10527 } |
|
10528 } |
|
10529 } |
|
10530 //----------------------------------- |
|
10531 xmlParseTryOrFinish(ctxt, terminate); |
|
10532 //----------------------------------- |
|
10533 if( OOM_FLAG ) |
|
10534 { |
|
10535 xmlParserOOMErr(ctxt); // set error state and disable parser |
|
10536 } |
|
10537 if (ctxt->errNo != XML_ERR_OK && |
|
10538 ctxt->disableSAX == 1) |
|
10539 { |
|
10540 return(ctxt->errNo); |
|
10541 } |
|
10542 if (terminate) |
|
10543 { |
|
10544 /* |
|
10545 * Check for termination |
|
10546 */ |
|
10547 xmlParserInputPtr input = ctxt->input; |
|
10548 int avail = (input->buf |
|
10549 ? input->buf->buffer->use |
|
10550 : input->length ) |
|
10551 - (input->cur - input->base); |
|
10552 |
|
10553 if ( ((ctxt->instate != XML_PARSER_EOF) && |
|
10554 (ctxt->instate != XML_PARSER_EPILOG)) |
|
10555 || |
|
10556 ((ctxt->instate == XML_PARSER_EPILOG) && |
|
10557 (avail > 0)) |
|
10558 ) |
|
10559 { |
|
10560 xmlFatalErr(ctxt, XML_ERR_DOCUMENT_END, NULL); |
|
10561 } |
|
10562 if (ctxt->instate != XML_PARSER_EOF) |
|
10563 { |
|
10564 if (ctxt->sax && ctxt->sax->endDocument) |
|
10565 ctxt->sax->endDocument(ctxt->userData); |
|
10566 } |
|
10567 ctxt->instate = XML_PARSER_EOF; |
|
10568 } |
|
10569 return ((xmlParserErrors) ctxt->errNo); |
|
10570 } |
|
10571 |
|
10572 /************************************************************************ |
|
10573 * * |
|
10574 * I/O front end functions to the parser * |
|
10575 * * |
|
10576 ************************************************************************/ |
|
10577 |
|
10578 /** |
|
10579 * xmlStopParser: |
|
10580 * @param ctxt an XML parser context |
|
10581 * |
|
10582 * Blocks further parser processing |
|
10583 */ |
|
10584 XMLPUBFUNEXPORT void |
|
10585 xmlStopParser(xmlParserCtxtPtr ctxt) { |
|
10586 if (ctxt == NULL) |
|
10587 return; |
|
10588 ctxt->instate = XML_PARSER_EOF; |
|
10589 ctxt->disableSAX = 1; |
|
10590 if (ctxt->input != NULL) |
|
10591 ctxt->input->cur = BAD_CAST""; |
|
10592 } |
|
10593 |
|
10594 /** |
|
10595 * xmlCreatePushParserCtxt: |
|
10596 * @param sax a SAX handler |
|
10597 * @param user_data The user data returned on SAX callbacks |
|
10598 * @param chunk a pointer to an array of chars |
|
10599 * @param size number of chars in the array |
|
10600 * @param filename an optional file name or URI |
|
10601 * |
|
10602 * Create a parser context for using the XML parser in push mode. |
|
10603 * If buffer and size are non-NULL, the data is used to detect |
|
10604 * the encoding. The remaining characters will be parsed so they |
|
10605 * don't need to be fed in again through xmlParseChunk. |
|
10606 * To allow content encoding detection, size should be >= 4 |
|
10607 * The value of filename is used for fetching external entities |
|
10608 * and error/warning reports. |
|
10609 * |
|
10610 * Returns the new parser context or NULL |
|
10611 * |
|
10612 * OOM: possible --> returns NULL |
|
10613 */ |
|
10614 |
|
10615 XMLPUBFUNEXPORT xmlParserCtxtPtr |
|
10616 xmlCreatePushParserCtxt(xmlSAXHandlerPtr sax, void* user_data, |
|
10617 const char* chunk, int size, const char* filename) |
|
10618 { |
|
10619 LOAD_GS_DIRECT |
|
10620 xmlParserCtxtPtr ctxt; |
|
10621 xmlParserInputPtr inputStream; |
|
10622 xmlParserInputBufferPtr buf; |
|
10623 xmlCharEncoding enc = XML_CHAR_ENCODING_NONE; |
|
10624 |
|
10625 /* |
|
10626 * plug some encoding conversion routines |
|
10627 */ |
|
10628 if (chunk && (size >= 4)) |
|
10629 enc = xmlDetectCharEncoding((const xmlChar*) chunk, size); |
|
10630 |
|
10631 buf = xmlAllocParserInputBuffer(enc); // OOM possible |
|
10632 if (!buf) |
|
10633 goto OOM; |
|
10634 |
|
10635 ctxt = xmlNewParserCtxt(); |
|
10636 if (!ctxt) { |
|
10637 goto OOM_buf; |
|
10638 } |
|
10639 ctxt->pushTab = (void**) xmlMalloc(ctxt->nameMax * 3 * sizeof(xmlChar*)); |
|
10640 |
|
10641 if (!ctxt->pushTab) { |
|
10642 goto OOM_ctxt_buf; |
|
10643 } |
|
10644 |
|
10645 if (sax) { |
|
10646 #ifdef LIBXML_SAX1_ENABLED |
|
10647 if (ctxt->sax != (xmlSAXHandlerPtr) &xmlDefaultSAXHandler) |
|
10648 #endif /* LIBXML_SAX1_ENABLED */ |
|
10649 { |
|
10650 xmlFree(ctxt->sax); |
|
10651 } |
|
10652 ctxt->sax = (xmlSAXHandlerPtr) xmlMalloc(sizeof(xmlSAXHandler)); |
|
10653 if (!ctxt->sax) { |
|
10654 goto OOM_ctxt_buf; |
|
10655 } |
|
10656 memcpy(ctxt->sax, sax, sizeof(xmlSAXHandler)); |
|
10657 if (user_data) |
|
10658 ctxt->userData = user_data; |
|
10659 } |
|
10660 // DONE: just call xmlParserGetDirectory it returns NULL for NULL argument |
|
10661 ctxt->directory = filename |
|
10662 ? xmlParserGetDirectory(filename) |
|
10663 : NULL; |
|
10664 |
|
10665 inputStream = xmlNewInputStream(ctxt); |
|
10666 if (!inputStream) { |
|
10667 goto OOM_ctxt_buf; |
|
10668 } |
|
10669 |
|
10670 inputStream->filename = filename |
|
10671 ? (char *) xmlCanonicPath((const xmlChar*) filename) |
|
10672 : NULL; |
|
10673 |
|
10674 inputStream->buf = buf; |
|
10675 inputStream->base = inputStream->buf->buffer->content; |
|
10676 inputStream->cur = inputStream->buf->buffer->content; |
|
10677 inputStream->end = &inputStream->buf->buffer->content[inputStream->buf->buffer->use]; |
|
10678 |
|
10679 if (inputPush(ctxt, inputStream) < 0) |
|
10680 { |
|
10681 goto OOM_istream_ctxt_buf; |
|
10682 } |
|
10683 |
|
10684 if (size > 0 && |
|
10685 chunk && |
|
10686 ctxt->input && |
|
10687 ctxt->input->buf) |
|
10688 { |
|
10689 int base = ctxt->input->base - ctxt->input->buf->buffer->content; |
|
10690 int cur = ctxt->input->cur - ctxt->input->base; |
|
10691 |
|
10692 xmlParserInputBufferPush(ctxt->input->buf, size, chunk); |
|
10693 |
|
10694 ctxt->input->base = ctxt->input->buf->buffer->content + base; |
|
10695 ctxt->input->cur = ctxt->input->base + cur; |
|
10696 ctxt->input->end = &ctxt->input->buf->buffer->content[ctxt->input->buf->buffer->use]; |
|
10697 #ifdef DEBUG_PUSH |
|
10698 xmlGenericError(xmlGenericErrorContext, "PP: pushed %d\n", size); |
|
10699 #endif |
|
10700 } |
|
10701 |
|
10702 if (enc != XML_CHAR_ENCODING_NONE) { |
|
10703 xmlSwitchEncoding(ctxt, enc); |
|
10704 } |
|
10705 |
|
10706 return(ctxt); |
|
10707 //------------------------------ |
|
10708 OOM_istream_ctxt_buf: |
|
10709 inputStream->buf = NULL; // NOTE: 'buf' is already part of inputStream -- do not free it twice!!! |
|
10710 xmlFreeInputStream(inputStream); |
|
10711 OOM_ctxt_buf: |
|
10712 xmlFreeParserCtxt(ctxt); |
|
10713 OOM_buf: |
|
10714 xmlFreeParserInputBuffer(buf); |
|
10715 OOM: |
|
10716 xmlParserOOMErr(NULL); |
|
10717 return(NULL); |
|
10718 } |
|
10719 #endif /* LIBXML_PUSH_ENABLED */ |
|
10720 |
|
10721 |
|
10722 #ifndef XMLENGINE_EXCLUDE_UNUSED |
|
10723 /** |
|
10724 * xmlCreateIOParserCtxt: |
|
10725 * @param sax a SAX handler |
|
10726 * @param user_data The user data returned on SAX callbacks |
|
10727 * @param ioread an I/O read function |
|
10728 * @param ioclose an I/O close function |
|
10729 * @param ioctx an I/O handler |
|
10730 * @param enc the charset encoding if known |
|
10731 * |
|
10732 * Create a parser context for using the XML parser with an existing |
|
10733 * I/O stream |
|
10734 * |
|
10735 * Returns the new parser context or NULL |
|
10736 */ |
|
10737 xmlParserCtxtPtr |
|
10738 xmlCreateIOParserCtxt(xmlSAXHandlerPtr sax, void *user_data, |
|
10739 xmlInputReadCallback ioread, xmlInputCloseCallback ioclose, |
|
10740 void *ioctx, xmlCharEncoding enc) |
|
10741 { |
|
10742 xmlParserCtxtPtr ctxt; |
|
10743 xmlParserInputPtr inputStream; |
|
10744 xmlParserInputBufferPtr buf; |
|
10745 |
|
10746 buf = xmlParserInputBufferCreateIO(ioread, ioclose, ioctx, enc); |
|
10747 if (buf == NULL) return(NULL); |
|
10748 |
|
10749 ctxt = xmlNewParserCtxt(); |
|
10750 if (ctxt == NULL) { |
|
10751 xmlFree(buf); |
|
10752 return(NULL); |
|
10753 } |
|
10754 if (sax != NULL) { |
|
10755 #ifdef LIBXML_SAX1_ENABLED |
|
10756 if (ctxt->sax != (xmlSAXHandlerPtr) &xmlDefaultSAXHandler) |
|
10757 #endif /* LIBXML_SAX1_ENABLED */ |
|
10758 xmlFree(ctxt->sax); |
|
10759 ctxt->sax = (xmlSAXHandlerPtr) xmlMalloc(sizeof(xmlSAXHandler)); |
|
10760 if (ctxt->sax == NULL) { |
|
10761 xmlParserOOMErr(ctxt); |
|
10762 xmlFree(ctxt); |
|
10763 return(NULL); |
|
10764 } |
|
10765 memcpy(ctxt->sax, sax, sizeof(xmlSAXHandler)); |
|
10766 if (user_data != NULL) |
|
10767 ctxt->userData = user_data; |
|
10768 } |
|
10769 |
|
10770 inputStream = xmlNewIOInputStream(ctxt, buf, enc); |
|
10771 if (inputStream == NULL) { |
|
10772 xmlFreeParserCtxt(ctxt); |
|
10773 return(NULL); |
|
10774 } |
|
10775 inputPush(ctxt, inputStream); |
|
10776 |
|
10777 return(ctxt); |
|
10778 } |
|
10779 #endif /* ifndef XMLENGINE_EXCLUDE_UNUSED */ |
|
10780 |
|
10781 |
|
10782 #ifdef LIBXML_VALID_ENABLED |
|
10783 /************************************************************************ |
|
10784 * * |
|
10785 * Front ends when parsing a DTD * |
|
10786 * * |
|
10787 ************************************************************************/ |
|
10788 |
|
10789 /** |
|
10790 * xmlIOParseDTD: |
|
10791 * @param sax the SAX handler block or NULL |
|
10792 * @param input an Input Buffer |
|
10793 * @param enc the charset encoding if known |
|
10794 * |
|
10795 * Load and parse a DTD |
|
10796 * |
|
10797 * Returns the resulting xmlDtdPtr or NULL in case of error. |
|
10798 * input will be freed at parsing end. |
|
10799 */ |
|
10800 |
|
10801 xmlDtdPtr |
|
10802 xmlIOParseDTD(xmlSAXHandlerPtr sax, xmlParserInputBufferPtr input, |
|
10803 xmlCharEncoding enc) |
|
10804 { |
|
10805 xmlDtdPtr ret = NULL; |
|
10806 xmlParserCtxtPtr ctxt; |
|
10807 xmlParserInputPtr pinput = NULL; |
|
10808 xmlChar start[4]; |
|
10809 |
|
10810 if (input == NULL) |
|
10811 return(NULL); |
|
10812 |
|
10813 ctxt = xmlNewParserCtxt(); |
|
10814 if (ctxt == NULL) { |
|
10815 return(NULL); |
|
10816 } |
|
10817 |
|
10818 /* |
|
10819 * Set-up the SAX context |
|
10820 */ |
|
10821 if (sax != NULL) { |
|
10822 if (ctxt->sax != NULL) |
|
10823 xmlFree(ctxt->sax); |
|
10824 ctxt->sax = sax; |
|
10825 ctxt->userData = ctxt; |
|
10826 } |
|
10827 xmlDetectSAX2(ctxt); |
|
10828 |
|
10829 /* |
|
10830 * generate a parser input from the I/O handler |
|
10831 */ |
|
10832 |
|
10833 pinput = xmlNewIOInputStream(ctxt, input, XML_CHAR_ENCODING_NONE); |
|
10834 if (pinput == NULL) { |
|
10835 if (sax != NULL) ctxt->sax = NULL; |
|
10836 xmlFreeParserCtxt(ctxt); |
|
10837 return(NULL); |
|
10838 } |
|
10839 |
|
10840 /* |
|
10841 * plug some encoding conversion routines here. |
|
10842 */ |
|
10843 xmlPushInput(ctxt, pinput); |
|
10844 if (enc != XML_CHAR_ENCODING_NONE) { |
|
10845 xmlSwitchEncoding(ctxt, enc); |
|
10846 } |
|
10847 |
|
10848 pinput->filename = NULL; |
|
10849 pinput->line = 1; |
|
10850 pinput->col = 1; |
|
10851 pinput->base = ctxt->input->cur; |
|
10852 pinput->cur = ctxt->input->cur; |
|
10853 pinput->free = NULL; |
|
10854 |
|
10855 /* |
|
10856 * let's parse that entity knowing it's an external subset. |
|
10857 */ |
|
10858 ctxt->inSubset = 2; |
|
10859 ctxt->myDoc = xmlNewDoc(BAD_CAST "1.0"); |
|
10860 ctxt->myDoc->extSubset = xmlNewDtd(ctxt->myDoc, BAD_CAST "none", |
|
10861 BAD_CAST "none", BAD_CAST "none"); |
|
10862 |
|
10863 if ((enc == XML_CHAR_ENCODING_NONE) && |
|
10864 ((ctxt->input->end - ctxt->input->cur) >= 4)) { |
|
10865 /* |
|
10866 * Get the 4 first bytes and decode the charset |
|
10867 * if enc != XML_CHAR_ENCODING_NONE |
|
10868 * plug some encoding conversion routines. |
|
10869 */ |
|
10870 start[0] = RAW; |
|
10871 start[1] = NXT(1); |
|
10872 start[2] = NXT(2); |
|
10873 start[3] = NXT(3); |
|
10874 enc = xmlDetectCharEncoding(start, 4); |
|
10875 if (enc != XML_CHAR_ENCODING_NONE) { |
|
10876 xmlSwitchEncoding(ctxt, enc); |
|
10877 } |
|
10878 } |
|
10879 |
|
10880 xmlParseExternalSubset(ctxt, BAD_CAST "none", BAD_CAST "none"); |
|
10881 |
|
10882 if (ctxt->myDoc != NULL) { |
|
10883 if (ctxt->wellFormed) { |
|
10884 ret = ctxt->myDoc->extSubset; |
|
10885 ctxt->myDoc->extSubset = NULL; |
|
10886 if (ret != NULL) { |
|
10887 xmlNodePtr tmp; |
|
10888 |
|
10889 ret->doc = NULL; |
|
10890 tmp = ret->children; |
|
10891 while (tmp != NULL) { |
|
10892 tmp->doc = NULL; |
|
10893 tmp = tmp->next; |
|
10894 } |
|
10895 } |
|
10896 } else { |
|
10897 ret = NULL; |
|
10898 } |
|
10899 xmlFreeDoc(ctxt->myDoc); |
|
10900 ctxt->myDoc = NULL; |
|
10901 } |
|
10902 if (sax != NULL) ctxt->sax = NULL; |
|
10903 xmlFreeParserCtxt(ctxt); |
|
10904 |
|
10905 return(ret); |
|
10906 } |
|
10907 |
|
10908 /** |
|
10909 * xmlSAXParseDTD: |
|
10910 * @param sax the SAX handler block |
|
10911 * @param ExternalID a NAME* containing the External ID of the DTD |
|
10912 * @param SystemID a NAME* containing the URL to the DTD |
|
10913 * |
|
10914 * Load and parse an external subset. |
|
10915 * |
|
10916 * Returns the resulting xmlDtdPtr or NULL in case of error. |
|
10917 */ |
|
10918 |
|
10919 xmlDtdPtr |
|
10920 xmlSAXParseDTD(xmlSAXHandlerPtr sax, const xmlChar *ExternalID, |
|
10921 const xmlChar *SystemID) { |
|
10922 xmlDtdPtr ret = NULL; |
|
10923 xmlParserCtxtPtr ctxt; |
|
10924 xmlParserInputPtr input = NULL; |
|
10925 xmlCharEncoding enc; |
|
10926 |
|
10927 if ((ExternalID == NULL) && (SystemID == NULL)) return(NULL); |
|
10928 |
|
10929 ctxt = xmlNewParserCtxt(); |
|
10930 if (ctxt == NULL) { |
|
10931 return(NULL); |
|
10932 } |
|
10933 |
|
10934 /* |
|
10935 * Set-up the SAX context |
|
10936 */ |
|
10937 if (sax != NULL) { |
|
10938 if (ctxt->sax != NULL) |
|
10939 xmlFree(ctxt->sax); |
|
10940 ctxt->sax = sax; |
|
10941 ctxt->userData = ctxt; |
|
10942 } |
|
10943 |
|
10944 /* |
|
10945 * Ask the Entity resolver to load the damn thing |
|
10946 */ |
|
10947 |
|
10948 if ((ctxt->sax != NULL) && (ctxt->sax->resolveEntity != NULL)) |
|
10949 input = ctxt->sax->resolveEntity(ctxt, ExternalID, SystemID); |
|
10950 if (input == NULL) { |
|
10951 if (sax != NULL) ctxt->sax = NULL; |
|
10952 xmlFreeParserCtxt(ctxt); |
|
10953 return(NULL); |
|
10954 } |
|
10955 |
|
10956 /* |
|
10957 * plug some encoding conversion routines here. |
|
10958 */ |
|
10959 xmlPushInput(ctxt, input); |
|
10960 if ((ctxt->input->end - ctxt->input->cur) >= 4) { |
|
10961 enc = xmlDetectCharEncoding(ctxt->input->cur, 4); |
|
10962 xmlSwitchEncoding(ctxt, enc); |
|
10963 } |
|
10964 |
|
10965 if (input->filename == NULL) |
|
10966 input->filename = (char *) xmlCanonicPath(SystemID); |
|
10967 input->line = 1; |
|
10968 input->col = 1; |
|
10969 input->base = ctxt->input->cur; |
|
10970 input->cur = ctxt->input->cur; |
|
10971 input->free = NULL; |
|
10972 |
|
10973 /* |
|
10974 * let's parse that entity knowing it's an external subset. |
|
10975 */ |
|
10976 ctxt->inSubset = 2; |
|
10977 ctxt->myDoc = xmlNewDoc(BAD_CAST "1.0"); |
|
10978 ctxt->myDoc->extSubset = xmlNewDtd(ctxt->myDoc, BAD_CAST "none", |
|
10979 ExternalID, SystemID); |
|
10980 xmlParseExternalSubset(ctxt, ExternalID, SystemID); |
|
10981 |
|
10982 if (ctxt->myDoc != NULL) { |
|
10983 if (ctxt->wellFormed) { |
|
10984 ret = ctxt->myDoc->extSubset; |
|
10985 ctxt->myDoc->extSubset = NULL; |
|
10986 if (ret != NULL) { |
|
10987 xmlNodePtr tmp; |
|
10988 |
|
10989 ret->doc = NULL; |
|
10990 tmp = ret->children; |
|
10991 while (tmp != NULL) { |
|
10992 tmp->doc = NULL; |
|
10993 tmp = tmp->next; |
|
10994 } |
|
10995 } |
|
10996 } else { |
|
10997 ret = NULL; |
|
10998 } |
|
10999 xmlFreeDoc(ctxt->myDoc); |
|
11000 ctxt->myDoc = NULL; |
|
11001 } |
|
11002 if (sax != NULL) ctxt->sax = NULL; |
|
11003 xmlFreeParserCtxt(ctxt); |
|
11004 |
|
11005 return(ret); |
|
11006 } |
|
11007 |
|
11008 |
|
11009 /** |
|
11010 * xmlParseDTD: |
|
11011 * @param ExternalID a NAME* containing the External ID of the DTD |
|
11012 * @param SystemID a NAME* containing the URL to the DTD |
|
11013 * |
|
11014 * Load and parse an external subset. |
|
11015 * |
|
11016 * Returns the resulting xmlDtdPtr or NULL in case of error. |
|
11017 */ |
|
11018 |
|
11019 xmlDtdPtr |
|
11020 xmlParseDTD(const xmlChar *ExternalID, const xmlChar *SystemID) { |
|
11021 return(xmlSAXParseDTD(NULL, ExternalID, SystemID)); |
|
11022 } |
|
11023 #endif /* LIBXML_VALID_ENABLED */ |
|
11024 |
|
11025 /************************************************************************ |
|
11026 * * |
|
11027 * Front ends when parsing an Entity * |
|
11028 * * |
|
11029 ************************************************************************/ |
|
11030 |
|
11031 /** |
|
11032 * xmlParseCtxtExternalEntity: |
|
11033 * @param ctx the existing parsing context |
|
11034 * @param URL the URL for the entity to load |
|
11035 * @param ID the System ID for the entity to load |
|
11036 * @param lst the return value for the set of parsed nodes |
|
11037 * |
|
11038 * Parse an external general entity within an existing parsing context |
|
11039 * An external general parsed entity is well-formed if it matches the |
|
11040 * production labeled extParsedEnt. |
|
11041 * |
|
11042 * [78] extParsedEnt ::= TextDecl? content |
|
11043 * |
|
11044 * Returns 0 if the entity is well formed, -1 in case of args problem and |
|
11045 * the parser error code otherwise |
|
11046 */ |
|
11047 |
|
11048 XMLPUBFUNEXPORT int |
|
11049 xmlParseCtxtExternalEntity(xmlParserCtxtPtr ctx, const xmlChar *URL, |
|
11050 const xmlChar *ID, xmlNodePtr *lst) { |
|
11051 xmlParserCtxtPtr ctxt; |
|
11052 xmlDocPtr newDoc; |
|
11053 xmlSAXHandlerPtr oldsax = NULL; |
|
11054 int ret = 0; |
|
11055 xmlChar start[4]; |
|
11056 xmlCharEncoding enc; |
|
11057 |
|
11058 if (ctx->depth > 40) { |
|
11059 return(XML_ERR_ENTITY_LOOP); |
|
11060 } |
|
11061 |
|
11062 if (lst != NULL) |
|
11063 *lst = NULL; |
|
11064 if ((URL == NULL) && (ID == NULL)) |
|
11065 return(-1); |
|
11066 if (ctx->myDoc == NULL) /* @@ relax but check for dereferences */ |
|
11067 return(-1); |
|
11068 |
|
11069 |
|
11070 ctxt = xmlCreateEntityParserCtxt(URL, ID, NULL); |
|
11071 if (ctxt == NULL) return(-1); |
|
11072 ctxt->userData = ctxt; |
|
11073 ctxt->_private = ctx->_private; |
|
11074 oldsax = ctxt->sax; |
|
11075 ctxt->sax = ctx->sax; |
|
11076 xmlDetectSAX2(ctxt); |
|
11077 newDoc = xmlNewDoc(BAD_CAST "1.0"); |
|
11078 if (newDoc == NULL) { |
|
11079 xmlFreeParserCtxt(ctxt); |
|
11080 return(-1); |
|
11081 } |
|
11082 if (ctx->myDoc != NULL) { |
|
11083 newDoc->intSubset = ctx->myDoc->intSubset; |
|
11084 newDoc->extSubset = ctx->myDoc->extSubset; |
|
11085 } |
|
11086 if (ctx->myDoc->URL != NULL) { |
|
11087 newDoc->URL = xmlStrdup(ctx->myDoc->URL); |
|
11088 } |
|
11089 newDoc->children = xmlNewDocNode(newDoc, NULL, BAD_CAST "pseudoroot", NULL); |
|
11090 if (newDoc->children == NULL) { |
|
11091 ctxt->sax = oldsax; |
|
11092 xmlFreeParserCtxt(ctxt); |
|
11093 newDoc->intSubset = NULL; |
|
11094 newDoc->extSubset = NULL; |
|
11095 xmlFreeDoc(newDoc); |
|
11096 return(-1); |
|
11097 } |
|
11098 nodePush(ctxt, newDoc->children); |
|
11099 if (ctx->myDoc == NULL) { |
|
11100 ctxt->myDoc = newDoc; |
|
11101 } else { |
|
11102 ctxt->myDoc = ctx->myDoc; |
|
11103 newDoc->children->doc = ctx->myDoc; |
|
11104 } |
|
11105 |
|
11106 /* |
|
11107 * Get the 4 first bytes and decode the charset |
|
11108 * if enc != XML_CHAR_ENCODING_NONE |
|
11109 * plug some encoding conversion routines. |
|
11110 */ |
|
11111 GROW |
|
11112 if ((ctxt->input->end - ctxt->input->cur) >= 4) { |
|
11113 start[0] = RAW; |
|
11114 start[1] = NXT(1); |
|
11115 start[2] = NXT(2); |
|
11116 start[3] = NXT(3); |
|
11117 enc = xmlDetectCharEncoding(start, 4); |
|
11118 if (enc != XML_CHAR_ENCODING_NONE) { |
|
11119 xmlSwitchEncoding(ctxt, enc); |
|
11120 } |
|
11121 } |
|
11122 |
|
11123 /* |
|
11124 * Parse a possible text declaration first |
|
11125 */ |
|
11126 if ((CMP5(CUR_PTR, '<', '?', 'x', 'm', 'l')) && (IS_BLANK_CH(NXT(5)))) { |
|
11127 xmlParseTextDecl(ctxt); |
|
11128 } |
|
11129 |
|
11130 /* |
|
11131 * Doing validity checking on chunk doesn't make sense |
|
11132 */ |
|
11133 ctxt->instate = XML_PARSER_CONTENT; |
|
11134 ctxt->validate = ctx->validate; |
|
11135 ctxt->valid = ctx->valid; |
|
11136 ctxt->loadsubset = ctx->loadsubset; |
|
11137 ctxt->depth = ctx->depth + 1; |
|
11138 ctxt->replaceEntities = ctx->replaceEntities; |
|
11139 if (ctxt->validate) { |
|
11140 ctxt->vctxt.error = ctx->vctxt.error; |
|
11141 ctxt->vctxt.warning = ctx->vctxt.warning; |
|
11142 } else { |
|
11143 ctxt->vctxt.error = NULL; |
|
11144 ctxt->vctxt.warning = NULL; |
|
11145 } |
|
11146 ctxt->vctxt.nodeTab = NULL; |
|
11147 ctxt->vctxt.nodeNr = 0; |
|
11148 ctxt->vctxt.nodeMax = 0; |
|
11149 ctxt->vctxt.node = NULL; |
|
11150 if (ctxt->dict != NULL) xmlDictFree(ctxt->dict); |
|
11151 ctxt->dict = ctx->dict; |
|
11152 ctxt->str_xml = xmlDictLookup(ctxt->dict, BAD_CAST "xml", 3); |
|
11153 ctxt->str_xmlns = xmlDictLookup(ctxt->dict, BAD_CAST "xmlns", 5); |
|
11154 ctxt->str_xml_ns = xmlDictLookup(ctxt->dict, XML_XML_NAMESPACE, 36); |
|
11155 ctxt->dictNames = ctx->dictNames; |
|
11156 ctxt->attsDefault = ctx->attsDefault; |
|
11157 ctxt->attsSpecial = ctx->attsSpecial; |
|
11158 |
|
11159 xmlParseContent(ctxt); |
|
11160 |
|
11161 ctx->validate = ctxt->validate; |
|
11162 ctx->valid = ctxt->valid; |
|
11163 if ((RAW == '<') && (NXT(1) == '/')) { |
|
11164 xmlFatalErr(ctxt, XML_ERR_NOT_WELL_BALANCED, NULL); |
|
11165 } else if (RAW != 0) { |
|
11166 xmlFatalErr(ctxt, XML_ERR_EXTRA_CONTENT, NULL); |
|
11167 } |
|
11168 if (ctxt->node != newDoc->children) { |
|
11169 xmlFatalErr(ctxt, XML_ERR_NOT_WELL_BALANCED, NULL); |
|
11170 } |
|
11171 |
|
11172 if (!ctxt->wellFormed) { |
|
11173 if (ctxt->errNo == 0) |
|
11174 ret = 1; |
|
11175 else |
|
11176 ret = ctxt->errNo; |
|
11177 } else { |
|
11178 if (lst != NULL) { |
|
11179 xmlNodePtr cur; |
|
11180 |
|
11181 /* |
|
11182 * Return the newly created nodeset after unlinking it from |
|
11183 * they pseudo parent. |
|
11184 */ |
|
11185 cur = newDoc->children->children; |
|
11186 *lst = cur; |
|
11187 while (cur != NULL) { |
|
11188 cur->parent = NULL; |
|
11189 cur = cur->next; |
|
11190 } |
|
11191 newDoc->children->children = NULL; |
|
11192 } |
|
11193 ret = 0; |
|
11194 } |
|
11195 ctxt->sax = oldsax; |
|
11196 ctxt->dict = NULL; |
|
11197 ctxt->attsDefault = NULL; |
|
11198 ctxt->attsSpecial = NULL; |
|
11199 xmlFreeParserCtxt(ctxt); |
|
11200 newDoc->intSubset = NULL; |
|
11201 newDoc->extSubset = NULL; |
|
11202 xmlFreeDoc(newDoc); |
|
11203 |
|
11204 return(ret); |
|
11205 } |
|
11206 |
|
11207 /** |
|
11208 * xmlParseExternalEntityPrivate: |
|
11209 * @param doc the document the chunk pertains to |
|
11210 * @param oldctxt the previous parser context if available |
|
11211 * @param sax the SAX handler bloc (possibly NULL) |
|
11212 * @param user_data The user data returned on SAX callbacks (possibly NULL) |
|
11213 * @param depth Used for loop detection, use 0 |
|
11214 * @param URL the URL for the entity to load |
|
11215 * @param systemID the System ID for the entity to load |
|
11216 * @param list the return value for the set of parsed nodes |
|
11217 * |
|
11218 * Private version of xmlParseExternalEntity() |
|
11219 * |
|
11220 * Returns 0 if the entity is well formed, -1 in case of args problem and |
|
11221 * the parser error code otherwise |
|
11222 */ |
|
11223 |
|
11224 static xmlParserErrors |
|
11225 xmlParseExternalEntityPrivate(xmlDocPtr doc, |
|
11226 xmlParserCtxtPtr oldctxt, |
|
11227 xmlSAXHandlerPtr sax, |
|
11228 void *user_data, |
|
11229 int depth, |
|
11230 const xmlChar *URL, |
|
11231 const xmlChar *systemID, |
|
11232 xmlNodePtr *list) |
|
11233 { |
|
11234 xmlParserCtxtPtr ctxt; |
|
11235 xmlDocPtr newDoc; |
|
11236 xmlSAXHandlerPtr oldsax = NULL; |
|
11237 xmlParserErrors ret = XML_ERR_OK; |
|
11238 xmlChar start[4]; |
|
11239 xmlCharEncoding enc; |
|
11240 |
|
11241 if (depth > 40) { |
|
11242 return(XML_ERR_ENTITY_LOOP); |
|
11243 } |
|
11244 |
|
11245 if (list != NULL) |
|
11246 *list = NULL; |
|
11247 if ((URL == NULL) && (systemID == NULL)) |
|
11248 return(XML_ERR_INTERNAL_ERROR); |
|
11249 if (doc == NULL) /* @@ relax but check for dereferences */ |
|
11250 return(XML_ERR_INTERNAL_ERROR); |
|
11251 |
|
11252 |
|
11253 ctxt = xmlCreateEntityParserCtxt(URL, systemID, NULL); |
|
11254 |
|
11255 if (ctxt == NULL) |
|
11256 return(XML_WAR_UNDECLARED_ENTITY); |
|
11257 ctxt->userData = ctxt; |
|
11258 if (oldctxt != NULL) { |
|
11259 ctxt->_private = oldctxt->_private; |
|
11260 ctxt->loadsubset = oldctxt->loadsubset; |
|
11261 ctxt->validate = oldctxt->validate; |
|
11262 ctxt->external = oldctxt->external; |
|
11263 #ifdef XMLENGINE_ENABLE_PARSER_RECORD_INFO |
|
11264 ctxt->record_info = oldctxt->record_info; |
|
11265 ctxt->node_seq.maximum = oldctxt->node_seq.maximum; |
|
11266 ctxt->node_seq.length = oldctxt->node_seq.length; |
|
11267 ctxt->node_seq.buffer = oldctxt->node_seq.buffer; |
|
11268 #endif |
|
11269 } else { |
|
11270 /* |
|
11271 * Doing validity checking on chunk without context |
|
11272 * doesn't make sense |
|
11273 */ |
|
11274 ctxt->_private = NULL; |
|
11275 ctxt->validate = 0; |
|
11276 ctxt->external = 2; |
|
11277 ctxt->loadsubset = 0; |
|
11278 } |
|
11279 if (sax != NULL) { |
|
11280 oldsax = ctxt->sax; |
|
11281 ctxt->sax = sax; |
|
11282 if (user_data != NULL) |
|
11283 ctxt->userData = user_data; |
|
11284 } |
|
11285 xmlDetectSAX2(ctxt); |
|
11286 newDoc = xmlNewDoc(BAD_CAST "1.0"); |
|
11287 if (newDoc == NULL) { |
|
11288 // OOM |
|
11289 #ifdef XMLENGINE_ENABLE_PARSER_RECORD_INFO |
|
11290 ctxt->node_seq.maximum = 0; |
|
11291 ctxt->node_seq.length = 0; |
|
11292 ctxt->node_seq.buffer = NULL; |
|
11293 #endif |
|
11294 xmlFreeParserCtxt(ctxt); |
|
11295 return(XML_ERR_INTERNAL_ERROR); |
|
11296 } |
|
11297 if (doc != NULL) { |
|
11298 newDoc->intSubset = doc->intSubset; |
|
11299 newDoc->extSubset = doc->extSubset; |
|
11300 if (doc->URL != NULL) { |
|
11301 newDoc->URL = xmlStrdup(doc->URL); |
|
11302 } |
|
11303 } |
|
11304 newDoc->children = xmlNewDocNode(newDoc, NULL, BAD_CAST "pseudoroot", NULL); |
|
11305 if (newDoc->children == NULL) { |
|
11306 // OOM |
|
11307 if (sax != NULL) |
|
11308 ctxt->sax = oldsax; |
|
11309 |
|
11310 #ifdef XMLENGINE_ENABLE_PARSER_RECORD_INFO |
|
11311 ctxt->node_seq.maximum = 0; |
|
11312 ctxt->node_seq.length = 0; |
|
11313 ctxt->node_seq.buffer = NULL; |
|
11314 #endif |
|
11315 xmlFreeParserCtxt(ctxt); |
|
11316 newDoc->intSubset = NULL; |
|
11317 newDoc->extSubset = NULL; |
|
11318 xmlFreeDoc(newDoc); |
|
11319 return(XML_ERR_INTERNAL_ERROR); |
|
11320 } |
|
11321 nodePush(ctxt, newDoc->children); |
|
11322 if (doc == NULL) { |
|
11323 ctxt->myDoc = newDoc; |
|
11324 } else { |
|
11325 ctxt->myDoc = doc; |
|
11326 newDoc->children->doc = doc; |
|
11327 } |
|
11328 |
|
11329 /* |
|
11330 * Get the 4 first bytes and decode the charset |
|
11331 * if enc != XML_CHAR_ENCODING_NONE |
|
11332 * plug some encoding conversion routines. |
|
11333 */ |
|
11334 GROW; |
|
11335 if ((ctxt->input->end - ctxt->input->cur) >= 4) { |
|
11336 start[0] = RAW; |
|
11337 start[1] = NXT(1); |
|
11338 start[2] = NXT(2); |
|
11339 start[3] = NXT(3); |
|
11340 enc = xmlDetectCharEncoding(start, 4); |
|
11341 if (enc != XML_CHAR_ENCODING_NONE) { |
|
11342 xmlSwitchEncoding(ctxt, enc); |
|
11343 } |
|
11344 } |
|
11345 |
|
11346 /* |
|
11347 * Parse a possible text declaration first |
|
11348 */ |
|
11349 if ((CMP5(CUR_PTR, '<', '?', 'x', 'm', 'l')) && (IS_BLANK_CH(NXT(5)))) { |
|
11350 xmlParseTextDecl(ctxt); |
|
11351 } |
|
11352 |
|
11353 ctxt->instate = XML_PARSER_CONTENT; |
|
11354 ctxt->depth = depth; |
|
11355 |
|
11356 xmlParseContent(ctxt); |
|
11357 |
|
11358 if ((RAW == '<') && (NXT(1) == '/')) { |
|
11359 xmlFatalErr(ctxt, XML_ERR_NOT_WELL_BALANCED, NULL); |
|
11360 } else if (RAW != 0) { |
|
11361 xmlFatalErr(ctxt, XML_ERR_EXTRA_CONTENT, NULL); |
|
11362 } |
|
11363 if (ctxt->node != newDoc->children) { |
|
11364 xmlFatalErr(ctxt, XML_ERR_NOT_WELL_BALANCED, NULL); |
|
11365 } |
|
11366 |
|
11367 if (!ctxt->wellFormed) { |
|
11368 if (ctxt->errNo == 0) |
|
11369 ret = XML_ERR_INTERNAL_ERROR; |
|
11370 else |
|
11371 ret = (xmlParserErrors)ctxt->errNo; |
|
11372 } else { |
|
11373 if (list != NULL) { |
|
11374 xmlNodePtr cur; |
|
11375 |
|
11376 /* |
|
11377 * Return the newly created nodeset after unlinking it from |
|
11378 * they pseudo parent. |
|
11379 */ |
|
11380 cur = newDoc->children->children; |
|
11381 *list = cur; |
|
11382 while (cur != NULL) { |
|
11383 cur->parent = NULL; |
|
11384 cur = cur->next; |
|
11385 } |
|
11386 newDoc->children->children = NULL; |
|
11387 } |
|
11388 ret = XML_ERR_OK; |
|
11389 } |
|
11390 if (sax != NULL) |
|
11391 ctxt->sax = oldsax; |
|
11392 |
|
11393 #ifdef XMLENGINE_ENABLE_PARSER_RECORD_INFO |
|
11394 if(oldctxt) |
|
11395 { |
|
11396 oldctxt->node_seq.maximum = ctxt->node_seq.maximum; |
|
11397 oldctxt->node_seq.length = ctxt->node_seq.length; |
|
11398 oldctxt->node_seq.buffer = ctxt->node_seq.buffer; |
|
11399 } |
|
11400 ctxt->node_seq.maximum = 0; |
|
11401 ctxt->node_seq.length = 0; |
|
11402 ctxt->node_seq.buffer = NULL; |
|
11403 #endif |
|
11404 |
|
11405 xmlFreeParserCtxt(ctxt); |
|
11406 newDoc->intSubset = NULL; |
|
11407 newDoc->extSubset = NULL; |
|
11408 xmlFreeDoc(newDoc); |
|
11409 |
|
11410 return(ret); |
|
11411 } |
|
11412 |
|
11413 #ifdef LIBXML_SAX1_ENABLED |
|
11414 /** |
|
11415 * xmlParseExternalEntity: |
|
11416 * @param doc the document the chunk pertains to |
|
11417 * @param sax the SAX handler bloc (possibly NULL) |
|
11418 * @param user_data The user data returned on SAX callbacks (possibly NULL) |
|
11419 * @param depth Used for loop detection, use 0 |
|
11420 * @param URL the URL for the entity to load |
|
11421 * @param systemID the System ID for the entity to load |
|
11422 * @param lst the return value for the set of parsed nodes |
|
11423 * |
|
11424 * Parse an external general entity |
|
11425 * An external general parsed entity is well-formed if it matches the |
|
11426 * production labeled extParsedEnt. |
|
11427 * |
|
11428 * [78] extParsedEnt ::= TextDecl? content |
|
11429 * |
|
11430 * Returns 0 if the entity is well formed, -1 in case of args problem and |
|
11431 * the parser error code otherwise |
|
11432 */ |
|
11433 |
|
11434 XMLPUBFUNEXPORT int |
|
11435 xmlParseExternalEntity(xmlDocPtr doc, xmlSAXHandlerPtr sax, void *user_data, |
|
11436 int depth, const xmlChar *URL, const xmlChar *systemID, xmlNodePtr *lst) { |
|
11437 return(xmlParseExternalEntityPrivate(doc, NULL, sax, user_data, depth, URL, |
|
11438 systemID, lst)); |
|
11439 } |
|
11440 |
|
11441 /** |
|
11442 * xmlParseBalancedChunkMemory: |
|
11443 * @param doc the document the chunk pertains to |
|
11444 * @param sax the SAX handler bloc (possibly NULL) |
|
11445 * @param user_data The user data returned on SAX callbacks (possibly NULL) |
|
11446 * @param depth Used for loop detection, use 0 |
|
11447 * @param string the input string in UTF8 or ISO-Latin (zero terminated) |
|
11448 * @param lst the return value for the set of parsed nodes |
|
11449 * |
|
11450 * Parse a well-balanced chunk of an XML document |
|
11451 * called by the parser |
|
11452 * The allowed sequence for the Well Balanced Chunk is the one defined by |
|
11453 * the content production in the XML grammar: |
|
11454 * |
|
11455 * [43] content ::= (element | CharData | Reference | CDSect | PI | Comment)* |
|
11456 * |
|
11457 * Returns 0 if the chunk is well balanced, -1 in case of args problem and |
|
11458 * the parser error code otherwise |
|
11459 */ |
|
11460 |
|
11461 XMLPUBFUNEXPORT int |
|
11462 xmlParseBalancedChunkMemory(xmlDocPtr doc, xmlSAXHandlerPtr sax, |
|
11463 void *user_data, int depth, const xmlChar *string, xmlNodePtr *lst) { |
|
11464 return xmlParseBalancedChunkMemoryRecover( doc, sax, user_data, |
|
11465 depth, string, lst, 0 ); |
|
11466 } |
|
11467 #endif /* LIBXML_SAX1_ENABLED */ |
|
11468 |
|
11469 /** |
|
11470 * xmlParseBalancedChunkMemoryInternal: |
|
11471 * @param oldctxt the existing parsing context |
|
11472 * @param string the input string in UTF8 or ISO-Latin (zero terminated) |
|
11473 * @param user_data the user data field for the parser context |
|
11474 * @param lst the return value for the set of parsed nodes |
|
11475 * |
|
11476 * |
|
11477 * Parse a well-balanced chunk of an XML document |
|
11478 * called by the parser |
|
11479 * The allowed sequence for the Well Balanced Chunk is the one defined by |
|
11480 * the content production in the XML grammar: |
|
11481 * |
|
11482 * [43] content ::= (element | CharData | Reference | CDSect | PI | Comment)* |
|
11483 * |
|
11484 * Returns XML_ERR_OK if the chunk is well balanced, and the parser |
|
11485 * error code otherwise |
|
11486 * |
|
11487 * In case recover is set to 1, the nodelist will not be empty even if |
|
11488 * the parsed chunk is not well balanced. |
|
11489 */ |
|
11490 static xmlParserErrors |
|
11491 xmlParseBalancedChunkMemoryInternal(xmlParserCtxtPtr oldctxt, |
|
11492 const xmlChar *string, void *user_data, xmlNodePtr *lst) { |
|
11493 xmlParserCtxtPtr ctxt; |
|
11494 xmlDocPtr newDoc = NULL; |
|
11495 xmlSAXHandlerPtr oldsax = NULL; |
|
11496 xmlNodePtr content = NULL; |
|
11497 int size; |
|
11498 xmlParserErrors ret = XML_ERR_OK; |
|
11499 LOAD_GS_SAFE_CTXT(oldctxt) |
|
11500 |
|
11501 if (oldctxt->depth > 40) { |
|
11502 return(XML_ERR_ENTITY_LOOP); |
|
11503 } |
|
11504 |
|
11505 |
|
11506 if (lst != NULL) |
|
11507 *lst = NULL; |
|
11508 if (string == NULL) |
|
11509 return(XML_ERR_INTERNAL_ERROR); |
|
11510 |
|
11511 size = xmlStrlen(string); |
|
11512 |
|
11513 ctxt = xmlCreateMemoryParserCtxt((char *) string, size); |
|
11514 if (ctxt == NULL) return(XML_WAR_UNDECLARED_ENTITY); |
|
11515 if (user_data != NULL) |
|
11516 ctxt->userData = user_data; |
|
11517 else |
|
11518 ctxt->userData = ctxt; |
|
11519 if (ctxt->dict != NULL) xmlDictFree(ctxt->dict); |
|
11520 ctxt->dict = oldctxt->dict; |
|
11521 ctxt->str_xml = xmlDictLookup(ctxt->dict, BAD_CAST "xml", 3); |
|
11522 ctxt->str_xmlns = xmlDictLookup(ctxt->dict, BAD_CAST "xmlns", 5); |
|
11523 ctxt->str_xml_ns = xmlDictLookup(ctxt->dict, XML_XML_NAMESPACE, 36); |
|
11524 |
|
11525 oldsax = ctxt->sax; |
|
11526 ctxt->sax = oldctxt->sax; |
|
11527 xmlDetectSAX2(ctxt); |
|
11528 ctxt->replaceEntities = oldctxt->replaceEntities; |
|
11529 ctxt->options = oldctxt->options; |
|
11530 |
|
11531 ctxt->_private = oldctxt->_private; |
|
11532 if (oldctxt->myDoc == NULL) { |
|
11533 newDoc = xmlNewDoc(BAD_CAST "1.0"); |
|
11534 if (newDoc == NULL) { |
|
11535 ctxt->sax = oldsax; |
|
11536 ctxt->dict = NULL; |
|
11537 xmlFreeParserCtxt(ctxt); |
|
11538 return(XML_ERR_INTERNAL_ERROR); |
|
11539 } |
|
11540 ctxt->myDoc = newDoc; |
|
11541 } else { |
|
11542 ctxt->myDoc = oldctxt->myDoc; |
|
11543 content = ctxt->myDoc->children; |
|
11544 } |
|
11545 ctxt->myDoc->children = xmlNewDocNode(ctxt->myDoc, NULL, |
|
11546 BAD_CAST "pseudoroot", NULL); |
|
11547 if (ctxt->myDoc->children == NULL) { |
|
11548 ctxt->sax = oldsax; |
|
11549 ctxt->dict = NULL; |
|
11550 xmlFreeParserCtxt(ctxt); |
|
11551 if (newDoc != NULL) |
|
11552 xmlFreeDoc(newDoc); |
|
11553 return(XML_ERR_INTERNAL_ERROR); |
|
11554 } |
|
11555 nodePush(ctxt, ctxt->myDoc->children); |
|
11556 ctxt->instate = XML_PARSER_CONTENT; // can be XML_PARSER_EOF if error! |
|
11557 ctxt->depth = oldctxt->depth + 1; |
|
11558 |
|
11559 ctxt->validate = 0; |
|
11560 ctxt->loadsubset = oldctxt->loadsubset; |
|
11561 if ((oldctxt->validate) || (oldctxt->replaceEntities != 0)) { |
|
11562 /* |
|
11563 * ID/IDREF registration will be done in xmlValidateElement below |
|
11564 */ |
|
11565 ctxt->loadsubset |= XML_SKIP_IDS; |
|
11566 } |
|
11567 ctxt->dictNames = oldctxt->dictNames; |
|
11568 ctxt->attsDefault = oldctxt->attsDefault; |
|
11569 ctxt->attsSpecial = oldctxt->attsSpecial; |
|
11570 |
|
11571 xmlParseContent(ctxt); |
|
11572 if(OOM_FLAG) |
|
11573 { |
|
11574 xmlFreeParserCtxt(ctxt); |
|
11575 xmlParserOOMErr(ctxt); |
|
11576 return(XML_ERR_NO_MEMORY); |
|
11577 } |
|
11578 if ((RAW == '<') && (NXT(1) == '/')) { |
|
11579 xmlFatalErr(ctxt, XML_ERR_NOT_WELL_BALANCED, NULL); |
|
11580 } else if (RAW != 0) { |
|
11581 xmlFatalErr(ctxt, XML_ERR_EXTRA_CONTENT, NULL); |
|
11582 } |
|
11583 if (ctxt->node != ctxt->myDoc->children) { |
|
11584 xmlFatalErr(ctxt, XML_ERR_NOT_WELL_BALANCED, NULL); |
|
11585 } |
|
11586 |
|
11587 if (!ctxt->wellFormed) { |
|
11588 if (ctxt->errNo == 0) |
|
11589 ret = XML_ERR_INTERNAL_ERROR; |
|
11590 else |
|
11591 ret = (xmlParserErrors)ctxt->errNo; |
|
11592 } else { |
|
11593 ret = XML_ERR_OK; |
|
11594 } |
|
11595 |
|
11596 if ((lst != NULL) && (ret == XML_ERR_OK)) { |
|
11597 xmlNodePtr cur; |
|
11598 |
|
11599 /* |
|
11600 * Return the newly created nodeset after unlinking it from |
|
11601 * they pseudo parent. |
|
11602 */ |
|
11603 cur = ctxt->myDoc->children->children; |
|
11604 *lst = cur; |
|
11605 while (cur != NULL) { |
|
11606 #ifdef LIBXML_VALID_ENABLED |
|
11607 if (oldctxt->validate && oldctxt->wellFormed && |
|
11608 oldctxt->myDoc && oldctxt->myDoc->intSubset) { |
|
11609 oldctxt->valid &= xmlValidateElement(&oldctxt->vctxt, |
|
11610 oldctxt->myDoc, cur); |
|
11611 } |
|
11612 #endif /* LIBXML_VALID_ENABLED */ |
|
11613 cur->parent = NULL; |
|
11614 cur = cur->next; |
|
11615 } |
|
11616 ctxt->myDoc->children->children = NULL; |
|
11617 } |
|
11618 if (ctxt->myDoc != NULL) { |
|
11619 xmlFreeNode(ctxt->myDoc->children); |
|
11620 ctxt->myDoc->children = content; |
|
11621 } |
|
11622 |
|
11623 ctxt->sax = oldsax; |
|
11624 ctxt->dict = NULL; |
|
11625 ctxt->attsDefault = NULL; |
|
11626 ctxt->attsSpecial = NULL; |
|
11627 xmlFreeParserCtxt(ctxt); |
|
11628 if (newDoc != NULL) |
|
11629 xmlFreeDoc(newDoc); |
|
11630 |
|
11631 return(ret); |
|
11632 } |
|
11633 |
|
11634 // XMLENGINE: this function [xmlParseInNodeContext] is taken from |
|
11635 // the newer version of the code (2.6.21); |
|
11636 // It is required for WS-Security implementation (xmlsec) |
|
11637 |
|
11638 /** |
|
11639 * xmlParseInNodeContext: |
|
11640 * @param node the context node |
|
11641 * @param data the input string |
|
11642 * @param datalen the input string length in bytes |
|
11643 * @param options a combination of xmlParserOption |
|
11644 * @param lst the return value for the set of parsed nodes |
|
11645 * |
|
11646 * Parse a well-balanced chunk of an XML document |
|
11647 * within the context (DTD, namespaces, etc ...) of the given node. |
|
11648 * |
|
11649 * The allowed sequence for the data is a Well Balanced Chunk defined by |
|
11650 * the content production in the XML grammar: |
|
11651 * |
|
11652 * [43] content ::= (element | CharData | Reference | CDSect | PI | Comment)* |
|
11653 * |
|
11654 * Returns XML_ERR_OK if the chunk is well balanced, and the parser |
|
11655 * error code otherwise |
|
11656 */ |
|
11657 XMLPUBFUNEXPORT xmlParserErrors |
|
11658 xmlParseInNodeContext(xmlNodePtr node, const char *data, int datalen, |
|
11659 int options, xmlNodePtr *lst) |
|
11660 { |
|
11661 #ifdef SAX2 |
|
11662 xmlParserCtxtPtr ctxt; |
|
11663 xmlDocPtr doc = NULL; |
|
11664 xmlNodePtr fake, cur; |
|
11665 int nsnr = 0; |
|
11666 |
|
11667 xmlParserErrors ret = XML_ERR_OK; |
|
11668 LOAD_GS_SAFE_NODE(node) |
|
11669 |
|
11670 /* |
|
11671 * check all input parameters, grab the document |
|
11672 */ |
|
11673 if ((lst == NULL) || (node == NULL) || (data == NULL) || (datalen < 0)) |
|
11674 { |
|
11675 return(XML_ERR_INTERNAL_ERROR); |
|
11676 } |
|
11677 |
|
11678 switch (node->type) { |
|
11679 case XML_ELEMENT_NODE: |
|
11680 case XML_ATTRIBUTE_NODE: |
|
11681 case XML_TEXT_NODE: |
|
11682 case XML_CDATA_SECTION_NODE: |
|
11683 case XML_ENTITY_REF_NODE: |
|
11684 case XML_PI_NODE: |
|
11685 case XML_COMMENT_NODE: |
|
11686 case XML_DOCUMENT_NODE: |
|
11687 case XML_HTML_DOCUMENT_NODE: |
|
11688 break; |
|
11689 default: |
|
11690 return(XML_ERR_INTERNAL_ERROR); |
|
11691 |
|
11692 } |
|
11693 |
|
11694 while ((node != NULL) && |
|
11695 (node->type != XML_ELEMENT_NODE) && |
|
11696 (node->type != XML_DOCUMENT_NODE) && |
|
11697 (node->type != XML_HTML_DOCUMENT_NODE)) |
|
11698 { |
|
11699 node = node->parent; |
|
11700 } |
|
11701 |
|
11702 if (node == NULL) |
|
11703 return(XML_ERR_INTERNAL_ERROR); |
|
11704 |
|
11705 if (node->type == XML_ELEMENT_NODE){ |
|
11706 doc = node->doc; |
|
11707 } else { |
|
11708 doc = (xmlDocPtr) node; |
|
11709 } |
|
11710 |
|
11711 if (doc == NULL) |
|
11712 return(XML_ERR_INTERNAL_ERROR); |
|
11713 |
|
11714 /* |
|
11715 * allocate a context and set-up everything not related to the |
|
11716 * node position in the tree |
|
11717 */ |
|
11718 if (doc->type == XML_DOCUMENT_NODE) |
|
11719 ctxt = xmlCreateMemoryParserCtxt((char *) data, datalen); |
|
11720 #ifdef LIBXML_HTML_ENABLED |
|
11721 else if (doc->type == XML_HTML_DOCUMENT_NODE) |
|
11722 ctxt = htmlCreateMemoryParserCtxt((char *) data, datalen); |
|
11723 #endif |
|
11724 else |
|
11725 return(XML_ERR_INTERNAL_ERROR); |
|
11726 |
|
11727 if (ctxt == NULL) |
|
11728 return(XML_ERR_NO_MEMORY); |
|
11729 |
|
11730 fake = xmlNewComment(NULL); |
|
11731 if (fake == NULL) { |
|
11732 xmlFreeParserCtxt(ctxt); |
|
11733 return(XML_ERR_NO_MEMORY); |
|
11734 } |
|
11735 xmlAddChild(node, fake); |
|
11736 |
|
11737 /* |
|
11738 * Use input doc's dict if present, else assure XML_PARSE_NODICT is set. |
|
11739 * We need a dictionary for xmlDetectSAX2, so if there's no doc dict |
|
11740 * we must wait until the last moment to free the original one. |
|
11741 */ |
|
11742 if (doc->dict) { |
|
11743 if (ctxt->dict) |
|
11744 xmlDictFree(ctxt->dict); |
|
11745 ctxt->dict = doc->dict; |
|
11746 } else { |
|
11747 options |= XML_PARSE_NODICT; |
|
11748 } |
|
11749 |
|
11750 xmlCtxtUseOptions(ctxt, options); |
|
11751 xmlDetectSAX2(ctxt); |
|
11752 ctxt->myDoc = doc; |
|
11753 if ( OOM_FLAG ) |
|
11754 { |
|
11755 xmlFreeParserCtxt(ctxt); |
|
11756 return(XML_ERR_NO_MEMORY); |
|
11757 } |
|
11758 |
|
11759 if (node->type == XML_ELEMENT_NODE) |
|
11760 { |
|
11761 nodePush(ctxt, node); |
|
11762 /* |
|
11763 * initialize the SAX2 namespaces stack |
|
11764 */ |
|
11765 cur = node; |
|
11766 while ((cur != NULL) && (cur->type == XML_ELEMENT_NODE)) |
|
11767 { |
|
11768 xmlNsPtr ns = cur->nsDef; |
|
11769 const xmlChar *iprefix, *ihref; |
|
11770 |
|
11771 while (ns != NULL) |
|
11772 { |
|
11773 if (ctxt->dict) { |
|
11774 iprefix = xmlDictLookup(ctxt->dict, ns->prefix, -1); |
|
11775 ihref = xmlDictLookup(ctxt->dict, ns->href, -1); |
|
11776 } else { |
|
11777 iprefix = ns->prefix; |
|
11778 ihref = ns->href; |
|
11779 } |
|
11780 |
|
11781 if (xmlGetNamespace(ctxt, iprefix) == NULL) { |
|
11782 nsPush(ctxt, iprefix, ihref); |
|
11783 nsnr++; |
|
11784 } |
|
11785 ns = ns->next; |
|
11786 } |
|
11787 cur = cur->parent; |
|
11788 } |
|
11789 ctxt->instate = XML_PARSER_CONTENT; |
|
11790 } |
|
11791 |
|
11792 if ((ctxt->validate) || (ctxt->replaceEntities != 0)) |
|
11793 { |
|
11794 /* |
|
11795 * ID/IDREF registration will be done in xmlValidateElement below |
|
11796 */ |
|
11797 ctxt->loadsubset |= XML_SKIP_IDS; |
|
11798 } |
|
11799 |
|
11800 xmlParseContent(ctxt); |
|
11801 if ( OOM_FLAG ) |
|
11802 { |
|
11803 xmlFreeParserCtxt(ctxt); |
|
11804 return(XML_ERR_NO_MEMORY); |
|
11805 } |
|
11806 nsPop(ctxt, nsnr); |
|
11807 if ((RAW == '<') && (NXT(1) == '/')) { |
|
11808 xmlFatalErr(ctxt, XML_ERR_NOT_WELL_BALANCED, NULL); |
|
11809 } else if (RAW != 0) { |
|
11810 xmlFatalErr(ctxt, XML_ERR_EXTRA_CONTENT, NULL); |
|
11811 } |
|
11812 if ((ctxt->node != NULL) && (ctxt->node != node)) { |
|
11813 xmlFatalErr(ctxt, XML_ERR_NOT_WELL_BALANCED, NULL); |
|
11814 ctxt->wellFormed = 0; |
|
11815 } |
|
11816 |
|
11817 if (!ctxt->wellFormed) { |
|
11818 if (ctxt->errNo == 0) |
|
11819 ret = XML_ERR_INTERNAL_ERROR; |
|
11820 else |
|
11821 ret = (xmlParserErrors)ctxt->errNo; |
|
11822 } else { |
|
11823 ret = XML_ERR_OK; |
|
11824 } |
|
11825 |
|
11826 /* |
|
11827 * Return the newly created nodeset after unlinking it from |
|
11828 * the pseudo sibling. |
|
11829 */ |
|
11830 |
|
11831 cur = fake->next; |
|
11832 fake->next = NULL; |
|
11833 node->last = fake; |
|
11834 |
|
11835 if (cur != NULL) { |
|
11836 cur->prev = NULL; |
|
11837 } |
|
11838 |
|
11839 *lst = cur; |
|
11840 |
|
11841 while (cur != NULL) { |
|
11842 cur->parent = NULL; |
|
11843 cur = cur->next; |
|
11844 } |
|
11845 |
|
11846 xmlUnlinkNode(fake); |
|
11847 xmlFreeNode(fake); |
|
11848 |
|
11849 |
|
11850 if (ret != XML_ERR_OK) { |
|
11851 xmlFreeNodeList(*lst); |
|
11852 *lst = NULL; |
|
11853 } |
|
11854 |
|
11855 if (doc->dict != NULL) |
|
11856 ctxt->dict = NULL; |
|
11857 xmlFreeParserCtxt(ctxt); |
|
11858 |
|
11859 return(ret); |
|
11860 #else /* !SAX2 */ |
|
11861 return(XML_ERR_INTERNAL_ERROR); |
|
11862 #endif |
|
11863 } |
|
11864 |
|
11865 #ifdef LIBXML_SAX1_ENABLED |
|
11866 /** |
|
11867 * xmlParseBalancedChunkMemoryRecover: |
|
11868 * @param doc the document the chunk pertains to |
|
11869 * @param sax the SAX handler bloc (possibly NULL) |
|
11870 * @param user_data The user data returned on SAX callbacks (possibly NULL) |
|
11871 * @param depth Used for loop detection, use 0 |
|
11872 * @param string the input string in UTF8 or ISO-Latin (zero terminated) |
|
11873 * @param lst the return value for the set of parsed nodes |
|
11874 * @param recover return nodes even if the data is broken (use 0) |
|
11875 * |
|
11876 * |
|
11877 * Parse a well-balanced chunk of an XML document |
|
11878 * called by the parser |
|
11879 * The allowed sequence for the Well Balanced Chunk is the one defined by |
|
11880 * the content production in the XML grammar: |
|
11881 * |
|
11882 * [43] content ::= (element | CharData | Reference | CDSect | PI | Comment)* |
|
11883 * |
|
11884 * Returns 0 if the chunk is well balanced, -1 in case of args problem and |
|
11885 * the parser error code otherwise |
|
11886 * |
|
11887 * In case recover is set to 1, the nodelist will not be empty even if |
|
11888 * the parsed chunk is not well balanced. |
|
11889 */ |
|
11890 XMLPUBFUNEXPORT int |
|
11891 xmlParseBalancedChunkMemoryRecover(xmlDocPtr doc, xmlSAXHandlerPtr sax, |
|
11892 void *user_data, int depth, const xmlChar *string, xmlNodePtr *lst, |
|
11893 int recover) { |
|
11894 xmlParserCtxtPtr ctxt; |
|
11895 xmlDocPtr newDoc; |
|
11896 xmlSAXHandlerPtr oldsax = NULL; |
|
11897 xmlNodePtr content; |
|
11898 int size; |
|
11899 int ret = 0; |
|
11900 |
|
11901 if (depth > 40) { |
|
11902 return(XML_ERR_ENTITY_LOOP); |
|
11903 } |
|
11904 |
|
11905 |
|
11906 if (lst != NULL) |
|
11907 *lst = NULL; |
|
11908 if (string == NULL) |
|
11909 return(-1); |
|
11910 |
|
11911 size = xmlStrlen(string); |
|
11912 |
|
11913 ctxt = xmlCreateMemoryParserCtxt((char *) string, size); |
|
11914 if (ctxt == NULL) return(-1); |
|
11915 ctxt->userData = ctxt; |
|
11916 if (sax != NULL) { |
|
11917 oldsax = ctxt->sax; |
|
11918 ctxt->sax = sax; |
|
11919 if (user_data != NULL) |
|
11920 ctxt->userData = user_data; |
|
11921 } |
|
11922 newDoc = xmlNewDoc(BAD_CAST "1.0"); |
|
11923 if (newDoc == NULL) { |
|
11924 xmlFreeParserCtxt(ctxt); |
|
11925 return(-1); |
|
11926 } |
|
11927 if (doc != NULL) { |
|
11928 newDoc->intSubset = doc->intSubset; |
|
11929 newDoc->extSubset = doc->extSubset; |
|
11930 } |
|
11931 newDoc->children = xmlNewDocNode(newDoc, NULL, BAD_CAST "pseudoroot", NULL); |
|
11932 if (newDoc->children == NULL) { |
|
11933 if (sax != NULL) |
|
11934 ctxt->sax = oldsax; |
|
11935 xmlFreeParserCtxt(ctxt); |
|
11936 newDoc->intSubset = NULL; |
|
11937 newDoc->extSubset = NULL; |
|
11938 xmlFreeDoc(newDoc); |
|
11939 return(-1); |
|
11940 } |
|
11941 nodePush(ctxt, newDoc->children); |
|
11942 if (doc == NULL) { |
|
11943 ctxt->myDoc = newDoc; |
|
11944 } else { |
|
11945 ctxt->myDoc = newDoc; |
|
11946 newDoc->children->doc = doc; |
|
11947 } |
|
11948 ctxt->instate = XML_PARSER_CONTENT; |
|
11949 ctxt->depth = depth; |
|
11950 |
|
11951 /* |
|
11952 * Doing validity checking on chunk doesn't make sense |
|
11953 */ |
|
11954 ctxt->validate = 0; |
|
11955 ctxt->loadsubset = 0; |
|
11956 xmlDetectSAX2(ctxt); |
|
11957 |
|
11958 if ( doc != NULL ){ |
|
11959 content = doc->children; |
|
11960 doc->children = NULL; |
|
11961 xmlParseContent(ctxt); |
|
11962 doc->children = content; |
|
11963 } |
|
11964 else { |
|
11965 xmlParseContent(ctxt); |
|
11966 } |
|
11967 if ((RAW == '<') && (NXT(1) == '/')) { |
|
11968 xmlFatalErr(ctxt, XML_ERR_NOT_WELL_BALANCED, NULL); |
|
11969 } else if (RAW != 0) { |
|
11970 xmlFatalErr(ctxt, XML_ERR_EXTRA_CONTENT, NULL); |
|
11971 } |
|
11972 if (ctxt->node != newDoc->children) { |
|
11973 xmlFatalErr(ctxt, XML_ERR_NOT_WELL_BALANCED, NULL); |
|
11974 } |
|
11975 |
|
11976 if (!ctxt->wellFormed) { |
|
11977 if (ctxt->errNo == 0) |
|
11978 ret = 1; |
|
11979 else |
|
11980 ret = ctxt->errNo; |
|
11981 } else { |
|
11982 ret = 0; |
|
11983 } |
|
11984 |
|
11985 if (lst != NULL && (ret == 0 || recover == 1)) { |
|
11986 xmlNodePtr cur; |
|
11987 |
|
11988 /* |
|
11989 * Return the newly created nodeset after unlinking it from |
|
11990 * they pseudo parent. |
|
11991 */ |
|
11992 cur = newDoc->children->children; |
|
11993 *lst = cur; |
|
11994 while (cur != NULL) { |
|
11995 cur->parent = NULL; |
|
11996 cur = cur->next; |
|
11997 } |
|
11998 newDoc->children->children = NULL; |
|
11999 } |
|
12000 |
|
12001 if (sax != NULL) |
|
12002 ctxt->sax = oldsax; |
|
12003 xmlFreeParserCtxt(ctxt); |
|
12004 newDoc->intSubset = NULL; |
|
12005 newDoc->extSubset = NULL; |
|
12006 xmlFreeDoc(newDoc); |
|
12007 |
|
12008 return(ret); |
|
12009 } |
|
12010 |
|
12011 /** |
|
12012 * xmlSAXParseEntity: |
|
12013 * @param sax the SAX handler block |
|
12014 * @param filename the filename |
|
12015 * |
|
12016 * parse an XML external entity out of context and build a tree. |
|
12017 * It use the given SAX function block to handle the parsing callback. |
|
12018 * If sax is NULL, fallback to the default DOM tree building routines. |
|
12019 * |
|
12020 * [78] extParsedEnt ::= TextDecl? content |
|
12021 * |
|
12022 * This correspond to a "Well Balanced" chunk |
|
12023 * |
|
12024 * Returns the resulting document tree |
|
12025 */ |
|
12026 |
|
12027 XMLPUBFUNEXPORT xmlDocPtr |
|
12028 xmlSAXParseEntity(xmlSAXHandlerPtr sax, const char *filename) { |
|
12029 xmlDocPtr ret; |
|
12030 xmlParserCtxtPtr ctxt; |
|
12031 |
|
12032 ctxt = xmlCreateFileParserCtxt(filename); |
|
12033 if (ctxt == NULL) { |
|
12034 return(NULL); |
|
12035 } |
|
12036 if (sax != NULL) { |
|
12037 if (ctxt->sax != NULL) |
|
12038 xmlFree(ctxt->sax); |
|
12039 ctxt->sax = sax; |
|
12040 ctxt->userData = NULL; |
|
12041 } |
|
12042 |
|
12043 xmlParseExtParsedEnt(ctxt); |
|
12044 |
|
12045 if (ctxt->wellFormed) |
|
12046 ret = ctxt->myDoc; |
|
12047 else { |
|
12048 ret = NULL; |
|
12049 xmlFreeDoc(ctxt->myDoc); |
|
12050 ctxt->myDoc = NULL; |
|
12051 } |
|
12052 if (sax != NULL) |
|
12053 ctxt->sax = NULL; |
|
12054 xmlFreeParserCtxt(ctxt); |
|
12055 |
|
12056 return(ret); |
|
12057 } |
|
12058 |
|
12059 /** |
|
12060 * xmlParseEntity: |
|
12061 * @param filename the filename |
|
12062 * |
|
12063 * parse an XML external entity out of context and build a tree. |
|
12064 * |
|
12065 * [78] extParsedEnt ::= TextDecl? content |
|
12066 * |
|
12067 * This correspond to a "Well Balanced" chunk |
|
12068 * |
|
12069 * Returns the resulting document tree |
|
12070 */ |
|
12071 |
|
12072 XMLPUBFUNEXPORT xmlDocPtr |
|
12073 xmlParseEntity(const char *filename) { |
|
12074 return(xmlSAXParseEntity(NULL, filename)); |
|
12075 } |
|
12076 #endif /* LIBXML_SAX1_ENABLED */ |
|
12077 |
|
12078 /** |
|
12079 * xmlCreateEntityParserCtxt: |
|
12080 * @param URL the entity URL |
|
12081 * @param ID the entity PUBLIC ID |
|
12082 * @param base a possible base for the target URI |
|
12083 * |
|
12084 * Create a parser context for an external entity |
|
12085 * Automatic support for ZLIB/Compress compressed document is provided |
|
12086 * by default if found at compile-time. |
|
12087 * |
|
12088 * Returns the new parser context or NULL |
|
12089 */ |
|
12090 XMLPUBFUNEXPORT xmlParserCtxtPtr |
|
12091 xmlCreateEntityParserCtxt(const xmlChar* URL, |
|
12092 const xmlChar* ID, |
|
12093 const xmlChar* base) |
|
12094 { |
|
12095 xmlParserCtxtPtr ctxt; |
|
12096 xmlParserInputPtr inputStream; |
|
12097 // local variable 'directory' was removed (function was optimized) |
|
12098 xmlChar* uri; |
|
12099 |
|
12100 ctxt = xmlNewParserCtxt(); |
|
12101 if (!ctxt) |
|
12102 return(NULL); |
|
12103 |
|
12104 uri = xmlBuildURI(URL, base); |
|
12105 |
|
12106 if (!uri) { |
|
12107 inputStream = xmlLoadExternalEntity((char*) URL, (char*) ID, ctxt); |
|
12108 if (!inputStream) { |
|
12109 xmlFreeParserCtxt(ctxt); |
|
12110 return(NULL); |
|
12111 } |
|
12112 inputPush(ctxt, inputStream); |
|
12113 |
|
12114 if (!ctxt->directory) |
|
12115 ctxt->directory = xmlParserGetDirectory((char*) URL); |
|
12116 } else { |
|
12117 inputStream = xmlLoadExternalEntity((char*) uri, (char*) ID, ctxt); |
|
12118 if (!inputStream) { |
|
12119 xmlFree(uri); |
|
12120 xmlFreeParserCtxt(ctxt); |
|
12121 return(NULL); |
|
12122 } |
|
12123 |
|
12124 inputPush(ctxt, inputStream); |
|
12125 |
|
12126 if (!ctxt->directory) |
|
12127 ctxt->directory = xmlParserGetDirectory((char*) uri); // oom POSSIBLE |
|
12128 |
|
12129 xmlFree(uri); |
|
12130 } |
|
12131 return(ctxt); |
|
12132 } |
|
12133 |
|
12134 /************************************************************************ |
|
12135 * * |
|
12136 * Front ends when parsing from a file * |
|
12137 * * |
|
12138 ************************************************************************/ |
|
12139 |
|
12140 /** |
|
12141 * xmlCreateURLParserCtxt: |
|
12142 * @param filename the filename or URL |
|
12143 * @param options a combination of xmlParserOption |
|
12144 * |
|
12145 * Create a parser context for a file or URL content. |
|
12146 * Automatic support for ZLIB/Compress compressed document is provided |
|
12147 * by default if found at compile-time and for file accesses |
|
12148 * |
|
12149 * Returns the new parser context or NULL |
|
12150 */ |
|
12151 XMLPUBFUNEXPORT xmlParserCtxtPtr |
|
12152 xmlCreateURLParserCtxt(const char* filename, int options) |
|
12153 { |
|
12154 xmlParserCtxtPtr ctxt; |
|
12155 xmlParserInputPtr inputStream; |
|
12156 // local variable 'directory' was removed (function was optimized) |
|
12157 |
|
12158 ctxt = xmlNewParserCtxt(); |
|
12159 if (!ctxt) { |
|
12160 xmlParserOOMErr(ctxt); |
|
12161 return(NULL); |
|
12162 } |
|
12163 |
|
12164 if (options != 0) |
|
12165 xmlCtxtUseOptions(ctxt, options); |
|
12166 |
|
12167 inputStream = xmlLoadExternalEntity(filename, NULL, ctxt); |
|
12168 if (!inputStream) { |
|
12169 xmlFreeParserCtxt(ctxt); |
|
12170 return(NULL); |
|
12171 } |
|
12172 |
|
12173 inputPush(ctxt, inputStream); |
|
12174 if (!ctxt->directory) |
|
12175 ctxt->directory = xmlParserGetDirectory(filename); |
|
12176 |
|
12177 return(ctxt); |
|
12178 } |
|
12179 |
|
12180 |
|
12181 /** |
|
12182 * xmlCreateFileParserCtxt: |
|
12183 * @param filename the filename |
|
12184 * |
|
12185 * Create a parser context for a file content. |
|
12186 * Automatic support for ZLIB/Compress compressed document is provided |
|
12187 * by default if found at compile-time. |
|
12188 * |
|
12189 * Returns the new parser context or NULL |
|
12190 */ |
|
12191 XMLPUBFUNEXPORT xmlParserCtxtPtr |
|
12192 xmlCreateFileParserCtxt(const char *filename) |
|
12193 { |
|
12194 return(xmlCreateURLParserCtxt(filename, 0)); |
|
12195 } |
|
12196 |
|
12197 /** |
|
12198 * xmlSAXParseFileWithData: |
|
12199 * @param sax the SAX handler block |
|
12200 * @param filename the filename |
|
12201 * @param recovery work in recovery mode, i.e. tries to read no Well Formed |
|
12202 * documents |
|
12203 * @param data the userdata |
|
12204 * |
|
12205 * parse an XML file and build a tree. Automatic support for ZLIB/Compress |
|
12206 * compressed document is provided by default if found at compile-time. |
|
12207 * It use the given SAX function block to handle the parsing callback. |
|
12208 * If sax is NULL, fallback to the default DOM tree building routines. |
|
12209 * |
|
12210 * User data (void *) is stored within the parser context in the |
|
12211 * context's _private member, so it is available nearly everywhere in libxml |
|
12212 * |
|
12213 * Returns the resulting document tree |
|
12214 */ |
|
12215 |
|
12216 XMLPUBFUNEXPORT xmlDocPtr |
|
12217 xmlSAXParseFileWithData(xmlSAXHandlerPtr sax, const char *filename, |
|
12218 int recovery, void *data) { |
|
12219 xmlDocPtr ret; |
|
12220 xmlParserCtxtPtr ctxt; |
|
12221 // local variable 'directory' was removed (function was optimized) |
|
12222 |
|
12223 xmlInitParser(); |
|
12224 |
|
12225 |
|
12226 ctxt = xmlCreateFileParserCtxt(filename); |
|
12227 if (!ctxt) { |
|
12228 return(NULL); |
|
12229 } |
|
12230 |
|
12231 if (sax) { |
|
12232 if (ctxt->sax) |
|
12233 xmlFree(ctxt->sax); |
|
12234 ctxt->sax = sax; |
|
12235 } |
|
12236 |
|
12237 xmlDetectSAX2(ctxt); |
|
12238 if (data) { |
|
12239 ctxt->_private = data; |
|
12240 } |
|
12241 |
|
12242 if (!ctxt->directory) |
|
12243 ctxt->directory = xmlParserGetDirectory(filename); |
|
12244 |
|
12245 ctxt->recovery = recovery; |
|
12246 |
|
12247 xmlParseDocument(ctxt); |
|
12248 |
|
12249 if (ctxt->wellFormed || recovery) { |
|
12250 ret = ctxt->myDoc; |
|
12251 if (ret) { |
|
12252 if (ctxt->input->buf->compressed > 0) |
|
12253 ret->compression = 9; |
|
12254 else |
|
12255 ret->compression = ctxt->input->buf->compressed; |
|
12256 } |
|
12257 } else { |
|
12258 // not well-formed and w/o recovery |
|
12259 ret = NULL; |
|
12260 xmlFreeDoc(ctxt->myDoc); |
|
12261 ctxt->myDoc = NULL; |
|
12262 } |
|
12263 |
|
12264 if(sax) |
|
12265 ctxt->sax = NULL; |
|
12266 xmlFreeParserCtxt(ctxt); |
|
12267 |
|
12268 return(ret); |
|
12269 } |
|
12270 |
|
12271 /** |
|
12272 * xmlSAXParseFile: |
|
12273 * @param sax the SAX handler block |
|
12274 * @param filename the filename |
|
12275 * @param recovery work in recovery mode, i.e. tries to read no Well Formed |
|
12276 * documents |
|
12277 * |
|
12278 * parse an XML file and build a tree. Automatic support for ZLIB/Compress |
|
12279 * compressed document is provided by default if found at compile-time. |
|
12280 * It use the given SAX function block to handle the parsing callback. |
|
12281 * If sax is NULL, fallback to the default DOM tree building routines. |
|
12282 * |
|
12283 * Returns the resulting document tree |
|
12284 */ |
|
12285 |
|
12286 XMLPUBFUNEXPORT xmlDocPtr |
|
12287 xmlSAXParseFile(xmlSAXHandlerPtr sax, const char *filename, |
|
12288 int recovery) { |
|
12289 return(xmlSAXParseFileWithData(sax,filename,recovery,NULL)); |
|
12290 } |
|
12291 |
|
12292 /** |
|
12293 * xmlRecoverDoc: |
|
12294 * @param cur a pointer to an array of xmlChar |
|
12295 * |
|
12296 * parse an XML in-memory document and build a tree. |
|
12297 * In the case the document is not Well Formed, a tree is built anyway |
|
12298 * |
|
12299 * Returns the resulting document tree |
|
12300 */ |
|
12301 |
|
12302 XMLPUBFUNEXPORT xmlDocPtr |
|
12303 xmlRecoverDoc(xmlChar *cur) { |
|
12304 return(xmlSAXParseDoc(NULL, cur, 0, 1,NULL)); |
|
12305 } |
|
12306 |
|
12307 /** |
|
12308 * xmlRecoverFile: |
|
12309 * @param filename the filename |
|
12310 * |
|
12311 * parse an XML file and build a tree. Automatic support for ZLIB/Compress |
|
12312 * compressed document is provided by default if found at compile-time. |
|
12313 * In the case the document is not Well Formed, a tree is built anyway |
|
12314 * |
|
12315 * Returns the resulting document tree |
|
12316 */ |
|
12317 |
|
12318 XMLPUBFUNEXPORT xmlDocPtr |
|
12319 xmlRecoverFile(const char *filename) { |
|
12320 return(xmlSAXParseFile(NULL, filename, 1)); |
|
12321 } |
|
12322 |
|
12323 |
|
12324 /** |
|
12325 * xmlParseFile: |
|
12326 * @param filename the filename |
|
12327 * |
|
12328 * parse an XML file and build a tree. Automatic support for ZLIB/Compress |
|
12329 * compressed document is provided by default if found at compile-time. |
|
12330 * |
|
12331 * Returns the resulting document tree if the file was wellformed, |
|
12332 * NULL otherwise. |
|
12333 */ |
|
12334 |
|
12335 XMLPUBFUNEXPORT xmlDocPtr |
|
12336 xmlParseFile(const char *filename) { |
|
12337 return(xmlSAXParseFile(NULL, filename, 0)); |
|
12338 } |
|
12339 |
|
12340 /** |
|
12341 * xmlSetupParserForBuffer: |
|
12342 * @param ctxt an XML parser context |
|
12343 * @param buffer a xmlChar * buffer |
|
12344 * @param filename a file name |
|
12345 * |
|
12346 * Setup the parser context to parse a new buffer; Clears any prior |
|
12347 * contents from the parser context. The buffer parameter must not be |
|
12348 * NULL, but the filename parameter can be |
|
12349 */ |
|
12350 XMLPUBFUNEXPORT void |
|
12351 xmlSetupParserForBuffer(xmlParserCtxtPtr ctxt, const xmlChar* buffer, |
|
12352 const char* filename) |
|
12353 { |
|
12354 xmlParserInputPtr input; |
|
12355 |
|
12356 input = xmlNewInputStream(ctxt); |
|
12357 if (input == NULL) { |
|
12358 xmlParserOOMErr(ctxt); |
|
12359 xmlFree(ctxt); |
|
12360 return; |
|
12361 } |
|
12362 |
|
12363 xmlClearParserCtxt(ctxt); |
|
12364 if (filename != NULL) |
|
12365 input->filename = (char *) xmlCanonicPath((const xmlChar *)filename); |
|
12366 input->base = buffer; |
|
12367 input->cur = buffer; |
|
12368 input->end = &buffer[xmlStrlen(buffer)]; |
|
12369 inputPush(ctxt, input); |
|
12370 } |
|
12371 |
|
12372 /** |
|
12373 * xmlSAXUserParseFile: |
|
12374 * @param sax a SAX handler |
|
12375 * @param user_data The user data returned on SAX callbacks |
|
12376 * @param filename a file name |
|
12377 * |
|
12378 * parse an XML file and call the given SAX handler routines. |
|
12379 * Automatic support for ZLIB/Compress compressed document is provided |
|
12380 * |
|
12381 * Returns 0 in case of success or a error number otherwise |
|
12382 */ |
|
12383 XMLPUBFUNEXPORT int |
|
12384 xmlSAXUserParseFile(xmlSAXHandlerPtr sax, void *user_data, |
|
12385 const char *filename) { |
|
12386 LOAD_GS_DIRECT |
|
12387 |
|
12388 int ret = 0; |
|
12389 xmlParserCtxtPtr ctxt; |
|
12390 |
|
12391 ctxt = xmlCreateFileParserCtxt(filename); |
|
12392 if (ctxt == NULL) return -1; |
|
12393 #ifdef LIBXML_SAX1_ENABLED |
|
12394 if (ctxt->sax != (xmlSAXHandlerPtr) &xmlDefaultSAXHandler) |
|
12395 #endif /* LIBXML_SAX1_ENABLED */ |
|
12396 xmlFree(ctxt->sax); |
|
12397 ctxt->sax = sax; |
|
12398 xmlDetectSAX2(ctxt); |
|
12399 |
|
12400 if (user_data != NULL) |
|
12401 ctxt->userData = user_data; |
|
12402 |
|
12403 xmlParseDocument(ctxt); |
|
12404 |
|
12405 if (ctxt->wellFormed) |
|
12406 ret = 0; |
|
12407 else { |
|
12408 if (ctxt->errNo != 0) |
|
12409 ret = ctxt->errNo; |
|
12410 else |
|
12411 ret = -1; |
|
12412 } |
|
12413 if (sax != NULL) |
|
12414 ctxt->sax = NULL; |
|
12415 |
|
12416 xmlFreeParserCtxt(ctxt); |
|
12417 |
|
12418 return ret; |
|
12419 } |
|
12420 |
|
12421 |
|
12422 /************************************************************************ |
|
12423 * * |
|
12424 * Front-ends when parsing from memory * |
|
12425 * * |
|
12426 ************************************************************************/ |
|
12427 |
|
12428 /** |
|
12429 * xmlCreateMemoryParserCtxt: |
|
12430 * @param buffer a pointer to a char array |
|
12431 * @param size the size of the array |
|
12432 * |
|
12433 * Create a parser context for an XML in-memory document. |
|
12434 * |
|
12435 * Returns the new parser context or NULL |
|
12436 * |
|
12437 * OOM: possible --> returns NULL, OOM flag is set |
|
12438 */ |
|
12439 XMLPUBFUNEXPORT xmlParserCtxtPtr |
|
12440 xmlCreateMemoryParserCtxt(const char *buffer, int size) { |
|
12441 xmlParserCtxtPtr ctxt; |
|
12442 xmlParserInputPtr input; |
|
12443 xmlParserInputBufferPtr buf; |
|
12444 |
|
12445 if (!buffer || size <= 0) |
|
12446 return(NULL); |
|
12447 |
|
12448 ctxt = xmlNewParserCtxt(); |
|
12449 if (!ctxt) |
|
12450 return(NULL); // OOM |
|
12451 |
|
12452 |
|
12453 buf = xmlParserInputBufferCreateMem(buffer, size, XML_CHAR_ENCODING_NONE); |
|
12454 if (!buf) |
|
12455 goto OOM_ctxt; |
|
12456 |
|
12457 input = xmlNewInputStream(ctxt); |
|
12458 if (!input) |
|
12459 goto OOM_buf_ctxt; |
|
12460 |
|
12461 // input->filename = NULL; // It is NULL after xmlNewInputStream() |
|
12462 input->buf = buf; |
|
12463 input->base = input->buf->buffer->content; |
|
12464 input->cur = input->buf->buffer->content; |
|
12465 input->end = &input->buf->buffer->content[input->buf->buffer->use]; |
|
12466 |
|
12467 if( inputPush(ctxt, input) < 0 ){ |
|
12468 xmlFreeInputStream(input); |
|
12469 goto OOM_ctxt; |
|
12470 } |
|
12471 return(ctxt); |
|
12472 //-------------------------------------------- |
|
12473 OOM_buf_ctxt: |
|
12474 xmlFreeParserInputBuffer(buf); |
|
12475 OOM_ctxt: |
|
12476 xmlFreeParserCtxt(ctxt); |
|
12477 return(NULL); |
|
12478 } |
|
12479 |
|
12480 /** |
|
12481 * xmlSAXParseMemoryWithData: |
|
12482 * @param sax the SAX handler block |
|
12483 * @param buffer an pointer to a char array |
|
12484 * @param size the size of the array |
|
12485 * @param recovery work in recovery mode, i.e. tries to read no Well Formed |
|
12486 * documents |
|
12487 * @param data the userdata |
|
12488 * |
|
12489 * parse an XML in-memory block and use the given SAX function block |
|
12490 * to handle the parsing callback. If sax is NULL, fallback to the default |
|
12491 * DOM tree building routines. |
|
12492 * |
|
12493 * User data (void *) is stored within the parser context in the |
|
12494 * context's _private member, so it is available nearly everywhere in libxml |
|
12495 * |
|
12496 * Returns the resulting document tree |
|
12497 */ |
|
12498 |
|
12499 XMLPUBFUNEXPORT xmlDocPtr |
|
12500 xmlSAXParseMemoryWithData(xmlSAXHandlerPtr sax, const char *buffer, |
|
12501 int size, int recovery, void *data) { |
|
12502 xmlDocPtr ret; |
|
12503 xmlParserCtxtPtr ctxt; |
|
12504 |
|
12505 ctxt = xmlCreateMemoryParserCtxt(buffer, size); |
|
12506 if (ctxt == NULL) return(NULL); |
|
12507 if (sax != NULL) { |
|
12508 if (ctxt->sax != NULL) |
|
12509 xmlFree(ctxt->sax); |
|
12510 ctxt->sax = sax; |
|
12511 } |
|
12512 xmlDetectSAX2(ctxt); |
|
12513 if (data!=NULL) { |
|
12514 ctxt->_private=data; |
|
12515 } |
|
12516 |
|
12517 ctxt->recovery = recovery; |
|
12518 |
|
12519 xmlParseDocument(ctxt); |
|
12520 |
|
12521 if ((ctxt->wellFormed) || recovery) |
|
12522 ret = ctxt->myDoc; |
|
12523 else { |
|
12524 ret = NULL; |
|
12525 xmlFreeDoc(ctxt->myDoc); |
|
12526 ctxt->myDoc = NULL; |
|
12527 } |
|
12528 if (sax != NULL) |
|
12529 ctxt->sax = NULL; |
|
12530 xmlFreeParserCtxt(ctxt); |
|
12531 |
|
12532 return(ret); |
|
12533 } |
|
12534 |
|
12535 |
|
12536 |
|
12537 /** |
|
12538 * xmlSAXParseMemory: |
|
12539 * @param sax the SAX handler block |
|
12540 * @param buffer an pointer to a char array |
|
12541 * @param size the size of the array |
|
12542 * @param recovery work in recovery mode, i.e. tries to read not Well Formed |
|
12543 * documents |
|
12544 * |
|
12545 * parse an XML in-memory block and use the given SAX function block |
|
12546 * to handle the parsing callback. If sax is NULL, fallback to the default |
|
12547 * DOM tree building routines. |
|
12548 * |
|
12549 * Returns the resulting document tree |
|
12550 */ |
|
12551 XMLPUBFUNEXPORT xmlDocPtr |
|
12552 xmlSAXParseMemory(xmlSAXHandlerPtr sax, const char *buffer, |
|
12553 int size, int recovery) { |
|
12554 return xmlSAXParseMemoryWithData(sax, buffer, size, recovery, NULL); |
|
12555 } |
|
12556 |
|
12557 /** |
|
12558 * xmlParseMemory: |
|
12559 * @param buffer an pointer to a char array |
|
12560 * @param size the size of the array |
|
12561 * |
|
12562 * parse an XML in-memory block and build a tree. |
|
12563 * |
|
12564 * Returns the resulting document tree |
|
12565 */ |
|
12566 |
|
12567 XMLPUBFUNEXPORT xmlDocPtr xmlParseMemory(const char *buffer, int size) { |
|
12568 return(xmlSAXParseMemory(NULL, buffer, size, 0)); |
|
12569 } |
|
12570 |
|
12571 /** |
|
12572 * xmlRecoverMemory: |
|
12573 * @param buffer an pointer to a char array |
|
12574 * @param size the size of the array |
|
12575 * |
|
12576 * parse an XML in-memory block and build a tree. |
|
12577 * In the case the document is not Well Formed, a tree is built anyway |
|
12578 * |
|
12579 * Returns the resulting document tree |
|
12580 */ |
|
12581 |
|
12582 XMLPUBFUNEXPORT xmlDocPtr xmlRecoverMemory(const char *buffer, int size) { |
|
12583 return(xmlSAXParseMemory(NULL, buffer, size, 1)); |
|
12584 } |
|
12585 |
|
12586 /** |
|
12587 * xmlSAXUserParseMemory: |
|
12588 * @param sax a SAX handler |
|
12589 * @param user_data The user data returned on SAX callbacks |
|
12590 * @param buffer an in-memory XML document input |
|
12591 * @param size the length of the XML document in bytes |
|
12592 * |
|
12593 * A better SAX parsing routine. |
|
12594 * parse an XML in-memory buffer and call the given SAX handler routines. |
|
12595 * |
|
12596 * Returns 0 in case of success or a error number otherwise |
|
12597 */ |
|
12598 XMLPUBFUNEXPORT int xmlSAXUserParseMemory(xmlSAXHandlerPtr sax, void *user_data, |
|
12599 const char *buffer, int size) { |
|
12600 int ret = 0; |
|
12601 xmlParserCtxtPtr ctxt; |
|
12602 xmlSAXHandlerPtr oldsax = NULL; |
|
12603 |
|
12604 if (sax == NULL) return -1; |
|
12605 ctxt = xmlCreateMemoryParserCtxt(buffer, size); |
|
12606 if (ctxt == NULL) return -1; |
|
12607 oldsax = ctxt->sax; |
|
12608 ctxt->sax = sax; |
|
12609 xmlDetectSAX2(ctxt); |
|
12610 if (user_data != NULL) |
|
12611 ctxt->userData = user_data; |
|
12612 |
|
12613 xmlParseDocument(ctxt); |
|
12614 |
|
12615 if (ctxt->wellFormed) |
|
12616 ret = 0; |
|
12617 else { |
|
12618 if (ctxt->errNo != 0) |
|
12619 ret = ctxt->errNo; |
|
12620 else |
|
12621 ret = -1; |
|
12622 } |
|
12623 ctxt->sax = oldsax; |
|
12624 xmlFreeParserCtxt(ctxt); |
|
12625 |
|
12626 return ret; |
|
12627 } |
|
12628 |
|
12629 /** |
|
12630 * xmlCreateDocParserCtxt: |
|
12631 * @param cur a pointer to an array of xmlChar |
|
12632 * @param length size (bytes) of the array (0 if it should be calculated) |
|
12633 * |
|
12634 * Creates a parser context for an XML in-memory document. |
|
12635 * |
|
12636 * Returns the new parser context or NULL |
|
12637 * |
|
12638 * OOM: possible --> returns NULL for cur!=NULL && length>0; OOM flag is set |
|
12639 */ |
|
12640 XMLPUBFUNEXPORT xmlParserCtxtPtr |
|
12641 xmlCreateDocParserCtxt(const xmlChar *cur, int length) { |
|
12642 int len; |
|
12643 |
|
12644 if (!cur) |
|
12645 return(NULL); |
|
12646 len = (length > 0) ? length : xmlStrlen(cur); |
|
12647 return(xmlCreateMemoryParserCtxt((const char *)cur, len)); |
|
12648 } |
|
12649 |
|
12650 //#ifdef LIBXML_SAX1_ENABLED |
|
12651 /** |
|
12652 * xmlSAXParseDoc: |
|
12653 * @param sax the SAX handler block |
|
12654 * @param cur a pointer to an array of xmlChar |
|
12655 * @param length size (bytes) of the array (0 if it should be calculated) |
|
12656 * @param recovery work in recovery mode, i.e. tries to read no Well Formed |
|
12657 * documents |
|
12658 * @param errorCode last error code is recorded, 0 is no errors |
|
12659 * |
|
12660 * parse an XML in-memory document and build a tree. |
|
12661 * It use the given SAX function block to handle the parsing callback. |
|
12662 * If sax is NULL, fallback to the default DOM tree building routines. |
|
12663 * |
|
12664 * Returns the resulting document tree |
|
12665 * |
|
12666 * OOM: possible --> OOM flag is set (and NULL is returned too) |
|
12667 */ |
|
12668 |
|
12669 XMLPUBFUNEXPORT xmlDocPtr |
|
12670 xmlSAXParseDoc(xmlSAXHandlerPtr sax, xmlChar* cur, int length, int recovery, int* errorCode) { |
|
12671 LOAD_GS_DIRECT |
|
12672 |
|
12673 xmlDocPtr ret; |
|
12674 xmlParserCtxtPtr ctxt; |
|
12675 |
|
12676 if (!cur) |
|
12677 return(NULL); |
|
12678 |
|
12679 ctxt = xmlCreateDocParserCtxt(cur, length); // may set OOM flag |
|
12680 if (!ctxt) |
|
12681 return(NULL); // OOM or wrong args |
|
12682 if (sax) { |
|
12683 ctxt->sax = sax; |
|
12684 ctxt->userData = NULL; |
|
12685 } |
|
12686 xmlDetectSAX2(ctxt); |
|
12687 ret = NULL; |
|
12688 |
|
12689 if(OOM_FLAG) |
|
12690 goto cleanup; |
|
12691 |
|
12692 xmlParseDocument(ctxt); // may set OOM flag |
|
12693 |
|
12694 if (!OOM_FLAG && |
|
12695 (ctxt->wellFormed || recovery)) |
|
12696 { |
|
12697 ret = ctxt->myDoc; |
|
12698 } |
|
12699 else |
|
12700 { |
|
12701 //ret = NULL; // Moved upwards |
|
12702 xmlFreeDoc(ctxt->myDoc); |
|
12703 //ctxt->myDoc = NULL; // unneccessary, xmlFreeParserCtxt does not try to free it |
|
12704 } |
|
12705 cleanup: |
|
12706 if (sax) |
|
12707 ctxt->sax = NULL; // do not free set of custom callbacks |
|
12708 if(errorCode) |
|
12709 *errorCode = ctxt->errNo; // write error code to output argument |
|
12710 |
|
12711 xmlFreeParserCtxt(ctxt); |
|
12712 |
|
12713 return(ret); |
|
12714 } |
|
12715 |
|
12716 /** |
|
12717 * xmlParseDoc: |
|
12718 * @param cur a pointer to an array of xmlChar |
|
12719 * |
|
12720 * parse an XML in-memory document and build a tree. |
|
12721 * |
|
12722 * Returns the resulting document tree |
|
12723 */ |
|
12724 |
|
12725 XMLPUBFUNEXPORT xmlDocPtr |
|
12726 xmlParseDoc(xmlChar *cur) { |
|
12727 return(xmlSAXParseDoc(NULL, cur, 0, 0, NULL)); |
|
12728 } |
|
12729 //#endif /* LIBXML_SAX1_ENABLED */ |
|
12730 |
|
12731 #ifdef LIBXML_LEGACY_ENABLED |
|
12732 /************************************************************************ |
|
12733 * * |
|
12734 * Specific function to keep track of entities references * |
|
12735 * and used by the XSLT debugger * |
|
12736 * * |
|
12737 ************************************************************************/ |
|
12738 |
|
12739 static xmlEntityReferenceFunc xmlEntityRefFunc = NULL; |
|
12740 |
|
12741 /** |
|
12742 * xmlAddEntityReference: |
|
12743 * @param ent A valid entity |
|
12744 * @param firstNode A valid first node for children of entity |
|
12745 * @param lastNode A valid last node of children entity |
|
12746 * |
|
12747 * Notify of a reference to an entity of type XML_EXTERNAL_GENERAL_PARSED_ENTITY |
|
12748 */ |
|
12749 static void |
|
12750 xmlAddEntityReference(xmlEntityPtr ent, xmlNodePtr firstNode, |
|
12751 xmlNodePtr lastNode) |
|
12752 { |
|
12753 if (xmlEntityRefFunc != NULL) { |
|
12754 (*xmlEntityRefFunc) (ent, firstNode, lastNode); |
|
12755 } |
|
12756 } |
|
12757 |
|
12758 |
|
12759 /** |
|
12760 * xmlSetEntityReferenceFunc: |
|
12761 * @param func A valid function |
|
12762 * |
|
12763 * Set the function to call call back when a xml reference has been made |
|
12764 */ |
|
12765 void |
|
12766 xmlSetEntityReferenceFunc(xmlEntityReferenceFunc func) |
|
12767 { |
|
12768 xmlEntityRefFunc = func; |
|
12769 } |
|
12770 #endif /* LIBXML_LEGACY_ENABLED */ |
|
12771 |
|
12772 /************************************************************************ |
|
12773 * * |
|
12774 * Miscellaneous * |
|
12775 * * |
|
12776 ************************************************************************/ |
|
12777 |
|
12778 #ifdef LIBXML_XPATH_ENABLED |
|
12779 #include <stdapis/libxml2/libxml2_xpath.h> |
|
12780 #endif |
|
12781 |
|
12782 extern void xmlGenericErrorDefaultFunc(void *ctx, const char *msg, ...); |
|
12783 |
|
12784 /** |
|
12785 * xmlInitParser: |
|
12786 * |
|
12787 * Initialization function for the XML parser. |
|
12788 * This is not reentrant. Call once before processing in case of |
|
12789 * use in multithreaded programs. |
|
12790 * |
|
12791 * OOM: possible --> OOM flag is set |
|
12792 */ |
|
12793 |
|
12794 XMLPUBFUNEXPORT void |
|
12795 xmlInitParser(void) { |
|
12796 DEFINE_GS_PROXY //note: ensure GS proxy initialize before any GS member access |
|
12797 xmlGlobalStatePtr gs = xmlGetGlobalState(); |
|
12798 if (!gs) |
|
12799 { |
|
12800 gs = xmlCreateAndInitializeGlobalState(); |
|
12801 if (!gs) |
|
12802 return; |
|
12803 } |
|
12804 SET_GS_PROXY(gs) |
|
12805 |
|
12806 if (xmlParserInitialized != 0) |
|
12807 return; |
|
12808 |
|
12809 if ((xmlGenericError == xmlGenericErrorDefaultFunc) || |
|
12810 (xmlGenericError == NULL)) |
|
12811 { |
|
12812 initGenericErrorDefaultFunc(NULL); |
|
12813 } |
|
12814 xmlInitGlobals(); |
|
12815 xmlInitThreads(); |
|
12816 xmlInitMemory(); |
|
12817 xmlInitCharEncodingHandlers(); // may set OOM flag |
|
12818 xmlDefaultSAXHandlerInit(); |
|
12819 xmlRegisterDefaultInputCallbacks(); |
|
12820 #ifdef LIBXML_OUTPUT_ENABLED |
|
12821 xmlRegisterDefaultOutputCallbacks(); |
|
12822 #endif /* LIBXML_OUTPUT_ENABLED */ |
|
12823 #ifdef LIBXML_HTML_ENABLED |
|
12824 htmlInitAutoClose(); |
|
12825 htmlDefaultSAXHandlerInit(); |
|
12826 #endif |
|
12827 #ifdef LIBXML_XPATH_ENABLED |
|
12828 xmlXPathInit(); |
|
12829 #endif |
|
12830 //xmlParserMaxDepth = 1024; |
|
12831 xmlParserInitialized = 1; |
|
12832 } |
|
12833 |
|
12834 /** |
|
12835 * xmlCleanupParser: |
|
12836 * |
|
12837 * Cleanup function for the XML library. It tries to reclaim all |
|
12838 * parsing related global memory allocated for the library processing. |
|
12839 * It doesn't deallocate any document related memory. Calling this |
|
12840 * function should not prevent reusing the library but one should |
|
12841 * call xmlCleanupParser() only when the process has |
|
12842 * finished using the library or XML document built with it. |
|
12843 * |
|
12844 * OOM: never |
|
12845 */ |
|
12846 |
|
12847 XMLPUBFUNEXPORT void |
|
12848 xmlCleanupParser(void) { |
|
12849 LOAD_GS_DIRECT |
|
12850 if (!xmlParserInitialized) |
|
12851 return; |
|
12852 |
|
12853 xmlCleanupCharEncodingHandlers(); |
|
12854 #ifdef LIBXML_CATALOG_ENABLED |
|
12855 xmlCatalogCleanup(); |
|
12856 #endif |
|
12857 xmlCleanupInputCallbacks(); |
|
12858 #ifdef LIBXML_OUTPUT_ENABLED |
|
12859 xmlCleanupOutputCallbacks(); |
|
12860 #endif |
|
12861 xmlCleanupGlobals(); |
|
12862 xmlResetLastError(); |
|
12863 xmlCleanupThreads(); /* must be last if called not from the main thread */ |
|
12864 xmlCleanupMemory(); |
|
12865 xmlParserInitialized = 0; |
|
12866 } |
|
12867 |
|
12868 /************************************************************************ |
|
12869 * * |
|
12870 * New set (2.6.0) of simpler and more flexible APIs * |
|
12871 * * |
|
12872 ************************************************************************/ |
|
12873 |
|
12874 /** |
|
12875 * DICT_FREE: |
|
12876 * @param str a string |
|
12877 * |
|
12878 * Free a string if it is not owned by the "dict" dictionnary in the |
|
12879 * current scope |
|
12880 */ |
|
12881 #define DICT_FREE(str) \ |
|
12882 if ((str) && ((!dict) || \ |
|
12883 (xmlDictOwns(dict, (const xmlChar *)(str)) == 0))) \ |
|
12884 xmlFree((char *)(str)); |
|
12885 |
|
12886 /** |
|
12887 * xmlCtxtReset: |
|
12888 * @param ctxt an XML parser context |
|
12889 * |
|
12890 * Reset a parser context |
|
12891 */ |
|
12892 XMLPUBFUNEXPORT void |
|
12893 xmlCtxtReset(xmlParserCtxtPtr ctxt) |
|
12894 { |
|
12895 xmlParserInputPtr input; |
|
12896 xmlDictPtr dict = ctxt->dict; |
|
12897 |
|
12898 while ((input = inputPop(ctxt)) != NULL) { /* Non consuming */ |
|
12899 xmlFreeInputStream(input); |
|
12900 } |
|
12901 ctxt->inputNr = 0; |
|
12902 ctxt->input = NULL; |
|
12903 |
|
12904 ctxt->spaceNr = 0; |
|
12905 ctxt->spaceTab[0] = -1; |
|
12906 ctxt->space = &ctxt->spaceTab[0]; |
|
12907 |
|
12908 |
|
12909 ctxt->nodeNr = 0; |
|
12910 ctxt->node = NULL; |
|
12911 |
|
12912 ctxt->nameNr = 0; |
|
12913 ctxt->name = NULL; |
|
12914 |
|
12915 DICT_FREE(ctxt->version); |
|
12916 ctxt->version = NULL; |
|
12917 DICT_FREE(ctxt->encoding); |
|
12918 ctxt->encoding = NULL; |
|
12919 DICT_FREE(ctxt->directory); |
|
12920 ctxt->directory = NULL; |
|
12921 DICT_FREE(ctxt->extSubURI); |
|
12922 ctxt->extSubURI = NULL; |
|
12923 DICT_FREE(ctxt->extSubSystem); |
|
12924 ctxt->extSubSystem = NULL; |
|
12925 if (ctxt->myDoc != NULL) |
|
12926 xmlFreeDoc(ctxt->myDoc); |
|
12927 ctxt->myDoc = NULL; |
|
12928 |
|
12929 ctxt->standalone = -1; |
|
12930 ctxt->hasExternalSubset = 0; |
|
12931 ctxt->hasPErefs = 0; |
|
12932 ctxt->html = 0; |
|
12933 ctxt->external = 0; |
|
12934 ctxt->instate = XML_PARSER_START; |
|
12935 ctxt->token = 0; |
|
12936 |
|
12937 ctxt->wellFormed = 1; |
|
12938 ctxt->nsWellFormed = 1; |
|
12939 ctxt->disableSAX = 0; |
|
12940 ctxt->valid = 1; |
|
12941 |
|
12942 #if 0 |
|
12943 ctxt->vctxt.userData = ctxt; |
|
12944 ctxt->vctxt.error = xmlParserValidityError; |
|
12945 ctxt->vctxt.warning = xmlParserValidityWarning; |
|
12946 #endif |
|
12947 |
|
12948 #ifdef XMLENGINE_ENABLE_PARSER_RECORD_INFO |
|
12949 |
|
12950 ctxt->record_info = 0; |
|
12951 xmlInitNodeInfoSeq(&ctxt->node_seq); |
|
12952 #endif |
|
12953 ctxt->nbChars = 0; |
|
12954 ctxt->checkIndex = 0; |
|
12955 ctxt->inSubset = 0; |
|
12956 ctxt->errNo = XML_ERR_OK; |
|
12957 ctxt->depth = 0; |
|
12958 ctxt->charset = XML_CHAR_ENCODING_UTF8; |
|
12959 ctxt->catalogs = NULL; |
|
12960 |
|
12961 if (ctxt->attsDefault != NULL) { |
|
12962 xmlHashFree(ctxt->attsDefault, (xmlHashDeallocator) xmlFree); |
|
12963 ctxt->attsDefault = NULL; |
|
12964 } |
|
12965 if (ctxt->attsSpecial != NULL) { |
|
12966 xmlHashFree(ctxt->attsSpecial, NULL); |
|
12967 ctxt->attsSpecial = NULL; |
|
12968 } |
|
12969 |
|
12970 #ifdef LIBXML_CATALOG_ENABLED |
|
12971 if (ctxt->catalogs != NULL) |
|
12972 xmlCatalogFreeLocal(ctxt->catalogs); |
|
12973 #endif |
|
12974 if (ctxt->lastError.code != XML_ERR_OK) |
|
12975 xmlResetError(&ctxt->lastError); |
|
12976 } |
|
12977 |
|
12978 #ifndef XMLENGINE_EXCLUDE_UNUSED |
|
12979 /** |
|
12980 * xmlCtxtResetPush: |
|
12981 * @param ctxt an XML parser context |
|
12982 * @param chunk a pointer to an array of chars |
|
12983 * @param size number of chars in the array |
|
12984 * @param filename an optional file name or URI |
|
12985 * @param encoding the document encoding, or NULL |
|
12986 * |
|
12987 * Reset a push parser context |
|
12988 * |
|
12989 * Returns 0 in case of success and 1 in case of error |
|
12990 */ |
|
12991 int |
|
12992 xmlCtxtResetPush(xmlParserCtxtPtr ctxt, const char *chunk, |
|
12993 int size, const char *filename, const char *encoding) |
|
12994 { |
|
12995 xmlParserInputPtr inputStream; |
|
12996 xmlParserInputBufferPtr buf; |
|
12997 xmlCharEncoding enc = XML_CHAR_ENCODING_NONE; |
|
12998 |
|
12999 if (ctxt == NULL) |
|
13000 return(1); |
|
13001 |
|
13002 if ((encoding == NULL) && (chunk != NULL) && (size >= 4)) |
|
13003 enc = xmlDetectCharEncoding((const xmlChar *) chunk, size); |
|
13004 |
|
13005 buf = xmlAllocParserInputBuffer(enc); |
|
13006 if (buf == NULL) |
|
13007 return(1); |
|
13008 |
|
13009 if (ctxt == NULL) { |
|
13010 xmlFreeParserInputBuffer(buf); |
|
13011 return(1); |
|
13012 } |
|
13013 |
|
13014 xmlCtxtReset(ctxt); |
|
13015 |
|
13016 if (ctxt->pushTab == NULL) { |
|
13017 ctxt->pushTab = (void **) xmlMalloc(ctxt->nameMax * 3 * |
|
13018 sizeof(xmlChar *)); |
|
13019 if (ctxt->pushTab == NULL) { |
|
13020 xmlParserOOMErr(ctxt); |
|
13021 xmlFreeParserInputBuffer(buf); |
|
13022 return(1); |
|
13023 } |
|
13024 } |
|
13025 |
|
13026 if (filename == NULL) { |
|
13027 ctxt->directory = NULL; |
|
13028 } else { |
|
13029 ctxt->directory = xmlParserGetDirectory(filename); |
|
13030 } |
|
13031 |
|
13032 inputStream = xmlNewInputStream(ctxt); |
|
13033 if (inputStream == NULL) { |
|
13034 xmlFreeParserInputBuffer(buf); |
|
13035 return(1); |
|
13036 } |
|
13037 |
|
13038 if (filename == NULL) |
|
13039 inputStream->filename = NULL; |
|
13040 else |
|
13041 inputStream->filename = (char *) |
|
13042 |
|
13043 xmlCanonicPath((const xmlChar *) filename); |
|
13044 inputStream->buf = buf; |
|
13045 inputStream->base = inputStream->buf->buffer->content; |
|
13046 inputStream->cur = inputStream->buf->buffer->content; |
|
13047 inputStream->end = &inputStream->buf->buffer->content[inputStream->buf->buffer->use]; |
|
13048 |
|
13049 inputPush(ctxt, inputStream); |
|
13050 |
|
13051 if ((size > 0) && (chunk != NULL) && |
|
13052 (ctxt->input != NULL) && |
|
13053 (ctxt->input->buf != NULL)) |
|
13054 { |
|
13055 int base = ctxt->input->base - ctxt->input->buf->buffer->content; |
|
13056 int cur = ctxt->input->cur - ctxt->input->base; |
|
13057 |
|
13058 xmlParserInputBufferPush(ctxt->input->buf, size, chunk); |
|
13059 |
|
13060 ctxt->input->base = ctxt->input->buf->buffer->content + base; |
|
13061 ctxt->input->cur = ctxt->input->base + cur; |
|
13062 ctxt->input->end = |
|
13063 &ctxt->input->buf->buffer->content[ctxt->input->buf->buffer->use]; |
|
13064 #ifdef DEBUG_PUSH |
|
13065 xmlGenericError(xmlGenericErrorContext, "PP: pushed %d\n", size); |
|
13066 #endif |
|
13067 } |
|
13068 |
|
13069 if (encoding != NULL) { |
|
13070 xmlCharEncodingHandlerPtr hdlr; |
|
13071 |
|
13072 hdlr = xmlFindCharEncodingHandler(encoding); |
|
13073 if (hdlr != NULL) { |
|
13074 xmlSwitchToEncoding(ctxt, hdlr); |
|
13075 } else { |
|
13076 xmlFatalErrMsgStr(ctxt, XML_ERR_UNSUPPORTED_ENCODING, |
|
13077 EMBED_ERRTXT("Unsupported encoding %s\n"), BAD_CAST encoding); |
|
13078 } |
|
13079 } else if (enc != XML_CHAR_ENCODING_NONE) { |
|
13080 xmlSwitchEncoding(ctxt, enc); |
|
13081 } |
|
13082 |
|
13083 return(0); |
|
13084 } |
|
13085 #endif /* ifndef XMLENGINE_EXCLUDE_UNUSED */ |
|
13086 |
|
13087 |
|
13088 /** |
|
13089 * xmlCtxtUseOptions: |
|
13090 * @param ctxt an XML parser context |
|
13091 * @param options a combination of xmlParserOption |
|
13092 * |
|
13093 * Applies the options to the parser context |
|
13094 * |
|
13095 * Returns 0 in case of success, the set of unknown or unimplemented options |
|
13096 * in case of error. |
|
13097 */ |
|
13098 XMLPUBFUNEXPORT int |
|
13099 xmlCtxtUseOptions(xmlParserCtxtPtr ctxt, int options) |
|
13100 { |
|
13101 if (options & XML_PARSE_RECOVER) { |
|
13102 ctxt->recovery = 1; |
|
13103 options -= XML_PARSE_RECOVER; |
|
13104 } else |
|
13105 ctxt->recovery = 0; |
|
13106 if (options & XML_PARSE_DTDLOAD) { |
|
13107 ctxt->loadsubset = XML_DETECT_IDS; |
|
13108 options -= XML_PARSE_DTDLOAD; |
|
13109 } else |
|
13110 ctxt->loadsubset = 0; |
|
13111 if (options & XML_PARSE_DTDATTR) { |
|
13112 ctxt->loadsubset |= XML_COMPLETE_ATTRS; |
|
13113 options -= XML_PARSE_DTDATTR; |
|
13114 } |
|
13115 if (options & XML_PARSE_NOENT) { |
|
13116 ctxt->replaceEntities = 1; |
|
13117 /* ctxt->loadsubset |= XML_DETECT_IDS; */ |
|
13118 options -= XML_PARSE_NOENT; |
|
13119 } else |
|
13120 ctxt->replaceEntities = 0; |
|
13121 if (options & XML_PARSE_NOWARNING) { |
|
13122 ctxt->sax->warning = NULL; |
|
13123 options -= XML_PARSE_NOWARNING; |
|
13124 } |
|
13125 if (options & XML_PARSE_NOERROR) { |
|
13126 ctxt->sax->error = NULL; |
|
13127 ctxt->sax->fatalError = NULL; |
|
13128 options -= XML_PARSE_NOERROR; |
|
13129 } |
|
13130 if (options & XML_PARSE_PEDANTIC) { |
|
13131 ctxt->pedantic = 1; |
|
13132 options -= XML_PARSE_PEDANTIC; |
|
13133 } else |
|
13134 ctxt->pedantic = 0; |
|
13135 if (options & XML_PARSE_NOBLANKS) { |
|
13136 ctxt->keepBlanks = 0; |
|
13137 ctxt->sax->ignorableWhitespace = xmlSAX2IgnorableWhitespace; |
|
13138 options -= XML_PARSE_NOBLANKS; |
|
13139 } else |
|
13140 ctxt->keepBlanks = 1; |
|
13141 if (options & XML_PARSE_DTDVALID) { |
|
13142 ctxt->validate = 1; |
|
13143 if (options & XML_PARSE_NOWARNING) |
|
13144 ctxt->vctxt.warning = NULL; |
|
13145 if (options & XML_PARSE_NOERROR) |
|
13146 ctxt->vctxt.error = NULL; |
|
13147 options -= XML_PARSE_DTDVALID; |
|
13148 } else |
|
13149 ctxt->validate = 0; |
|
13150 #ifdef LIBXML_SAX1_ENABLED |
|
13151 if (options & XML_PARSE_SAX1) { |
|
13152 ctxt->sax->startElement = xmlSAX2StartElement; |
|
13153 ctxt->sax->endElement = xmlSAX2EndElement; |
|
13154 ctxt->sax->startElementNs = NULL; |
|
13155 ctxt->sax->endElementNs = NULL; |
|
13156 ctxt->sax->initialized = 1; |
|
13157 options -= XML_PARSE_SAX1; |
|
13158 } |
|
13159 #endif /* LIBXML_SAX1_ENABLED */ |
|
13160 if (options & XML_PARSE_NODICT) { |
|
13161 ctxt->dictNames = 0; |
|
13162 options -= XML_PARSE_NODICT; |
|
13163 } else { |
|
13164 ctxt->dictNames = 1; |
|
13165 } |
|
13166 if (options & XML_PARSE_NOCDATA) { |
|
13167 ctxt->sax->cdataBlock = NULL; |
|
13168 options -= XML_PARSE_NOCDATA; |
|
13169 } |
|
13170 if (options & XML_PARSE_NSCLEAN) { |
|
13171 ctxt->options |= XML_PARSE_NSCLEAN; |
|
13172 options -= XML_PARSE_NSCLEAN; |
|
13173 } |
|
13174 if (options & XML_PARSE_NONET) { |
|
13175 ctxt->options |= XML_PARSE_NONET; |
|
13176 options -= XML_PARSE_NONET; |
|
13177 } |
|
13178 #ifdef LIBXML_ENABLE_NODE_LINEINFO |
|
13179 ctxt->linenumbers = 1; |
|
13180 #endif |
|
13181 return (options); |
|
13182 } |
|
13183 |
|
13184 /** |
|
13185 * xmlDoRead: |
|
13186 * @param ctxt an XML parser context |
|
13187 * @param URL the base URL to use for the document |
|
13188 * @param encoding the document encoding, or NULL |
|
13189 * @param options a combination of xmlParserOption |
|
13190 * @param reuse keep the context for reuse |
|
13191 * |
|
13192 * Common front-end for the xmlRead functions |
|
13193 * |
|
13194 * Returns the resulting document tree or NULL |
|
13195 */ |
|
13196 static xmlDocPtr |
|
13197 xmlDoRead(xmlParserCtxtPtr ctxt, const char *URL, const char *encoding, |
|
13198 int options, int reuse) |
|
13199 { |
|
13200 xmlDocPtr ret; |
|
13201 |
|
13202 xmlCtxtUseOptions(ctxt, options); |
|
13203 if (encoding != NULL) { |
|
13204 xmlCharEncodingHandlerPtr hdlr; |
|
13205 |
|
13206 hdlr = xmlFindCharEncodingHandler(encoding); |
|
13207 if (hdlr != NULL) |
|
13208 xmlSwitchToEncoding(ctxt, hdlr); |
|
13209 } |
|
13210 if ((URL != NULL) && |
|
13211 (ctxt->input != NULL) && |
|
13212 (ctxt->input->filename == NULL)) |
|
13213 { |
|
13214 ctxt->input->filename = (char *) xmlStrdup((const xmlChar *) URL); |
|
13215 } |
|
13216 xmlParseDocument(ctxt); |
|
13217 if ((ctxt->wellFormed) || ctxt->recovery) |
|
13218 ret = ctxt->myDoc; |
|
13219 else { |
|
13220 ret = NULL; |
|
13221 if (ctxt->myDoc != NULL) { |
|
13222 xmlFreeDoc(ctxt->myDoc); |
|
13223 } |
|
13224 } |
|
13225 ctxt->myDoc = NULL; |
|
13226 if (!reuse) { |
|
13227 xmlFreeParserCtxt(ctxt); |
|
13228 } |
|
13229 |
|
13230 return (ret); |
|
13231 } |
|
13232 |
|
13233 /** |
|
13234 * xmlReadDoc: |
|
13235 * @param cur a pointer to a zero terminated string |
|
13236 * @param URL the base URL to use for the document |
|
13237 * @param encoding the document encoding, or NULL |
|
13238 * @param options a combination of xmlParserOption |
|
13239 * |
|
13240 * parse an XML in-memory document and build a tree. |
|
13241 * |
|
13242 * Returns the resulting document tree |
|
13243 */ |
|
13244 |
|
13245 XMLPUBFUNEXPORT xmlDocPtr |
|
13246 xmlReadDoc(const xmlChar * cur, const char *URL, const char *encoding, int options) |
|
13247 { |
|
13248 xmlParserCtxtPtr ctxt; |
|
13249 |
|
13250 if (cur == NULL) |
|
13251 return (NULL); |
|
13252 |
|
13253 ctxt = xmlCreateDocParserCtxt(cur, 0); |
|
13254 if (ctxt == NULL) |
|
13255 return (NULL); |
|
13256 return (xmlDoRead(ctxt, URL, encoding, options, 0)); |
|
13257 } |
|
13258 |
|
13259 #ifndef XMLENGINE_EXCLUDE_UNUSED |
|
13260 /** |
|
13261 * xmlReadFile: |
|
13262 * @param filename a file or URL |
|
13263 * @param encoding the document encoding, or NULL |
|
13264 * @param options a combination of xmlParserOption |
|
13265 * |
|
13266 * parse an XML file from the filesystem or the network. |
|
13267 * |
|
13268 * Returns the resulting document tree |
|
13269 */ |
|
13270 xmlDocPtr |
|
13271 xmlReadFile(const char *filename, const char *encoding, int options) |
|
13272 { |
|
13273 xmlParserCtxtPtr ctxt; |
|
13274 |
|
13275 ctxt = xmlCreateURLParserCtxt(filename, options); |
|
13276 if (ctxt == NULL) |
|
13277 return (NULL); |
|
13278 return (xmlDoRead(ctxt, NULL, encoding, options, 0)); |
|
13279 } |
|
13280 #endif |
|
13281 |
|
13282 /** |
|
13283 * xmlReadMemory: |
|
13284 * @param buffer a pointer to a char array |
|
13285 * @param size the size of the array |
|
13286 * @param URL the base URL to use for the document |
|
13287 * @param encoding the document encoding, or NULL |
|
13288 * @param options a combination of xmlParserOption |
|
13289 * |
|
13290 * parse an XML in-memory document and build a tree. |
|
13291 * |
|
13292 * Returns the resulting document tree |
|
13293 */ |
|
13294 XMLPUBFUNEXPORT xmlDocPtr |
|
13295 xmlReadMemory(const char *buffer, int size, const char *URL, const char *encoding, int options) |
|
13296 { |
|
13297 xmlParserCtxtPtr ctxt; |
|
13298 |
|
13299 ctxt = xmlCreateMemoryParserCtxt(buffer, size); |
|
13300 if (ctxt == NULL) |
|
13301 return (NULL); |
|
13302 return (xmlDoRead(ctxt, URL, encoding, options, 0)); |
|
13303 } |
|
13304 |
|
13305 #ifndef XMLENGINE_EXCLUDE_UNUSED |
|
13306 /** |
|
13307 * xmlReadFd: |
|
13308 * @param fd an open file descriptor |
|
13309 * @param URL the base URL to use for the document |
|
13310 * @param encoding the document encoding, or NULL |
|
13311 * @param options a combination of xmlParserOption |
|
13312 * |
|
13313 * parse an XML from a file descriptor and build a tree. |
|
13314 * NOTE that the file descriptor will not be closed when the |
|
13315 * reader is closed or reset. |
|
13316 * |
|
13317 * Returns the resulting document tree |
|
13318 */ |
|
13319 xmlDocPtr |
|
13320 xmlReadFd(int fd, const char *URL, const char *encoding, int options) |
|
13321 { |
|
13322 xmlParserCtxtPtr ctxt; |
|
13323 xmlParserInputBufferPtr input; |
|
13324 xmlParserInputPtr stream; |
|
13325 |
|
13326 if (fd < 0) |
|
13327 return (NULL); |
|
13328 |
|
13329 input = xmlParserInputBufferCreateFd(fd, XML_CHAR_ENCODING_NONE); |
|
13330 if (input == NULL) |
|
13331 return (NULL); |
|
13332 input->closecallback = NULL; |
|
13333 ctxt = xmlNewParserCtxt(); |
|
13334 if (ctxt == NULL) { |
|
13335 xmlFreeParserInputBuffer(input); |
|
13336 return (NULL); |
|
13337 } |
|
13338 stream = xmlNewIOInputStream(ctxt, input, XML_CHAR_ENCODING_NONE); |
|
13339 if (stream == NULL) { |
|
13340 xmlFreeParserInputBuffer(input); |
|
13341 xmlFreeParserCtxt(ctxt); |
|
13342 return (NULL); |
|
13343 } |
|
13344 inputPush(ctxt, stream); |
|
13345 return (xmlDoRead(ctxt, URL, encoding, options, 0)); |
|
13346 } |
|
13347 |
|
13348 |
|
13349 // XMLENGINE: This may be reused for xDC |
|
13350 |
|
13351 /** |
|
13352 * xmlReadIO: |
|
13353 * @param ioread an I/O read function |
|
13354 * @param ioclose an I/O close function |
|
13355 * @param ioctx an I/O handler |
|
13356 * @param URL the base URL to use for the document |
|
13357 * @param encoding the document encoding, or NULL |
|
13358 * @param options a combination of xmlParserOption |
|
13359 * |
|
13360 * parse an XML document from I/O functions and source and build a tree. |
|
13361 * |
|
13362 * Returns the resulting document tree |
|
13363 */ |
|
13364 xmlDocPtr |
|
13365 xmlReadIO(xmlInputReadCallback ioread, xmlInputCloseCallback ioclose, |
|
13366 void *ioctx, const char *URL, const char *encoding, int options) |
|
13367 { |
|
13368 xmlParserCtxtPtr ctxt; |
|
13369 xmlParserInputBufferPtr input; |
|
13370 xmlParserInputPtr stream; |
|
13371 |
|
13372 if (ioread == NULL) |
|
13373 return (NULL); |
|
13374 |
|
13375 input = xmlParserInputBufferCreateIO(ioread, ioclose, ioctx, |
|
13376 XML_CHAR_ENCODING_NONE); |
|
13377 if (input == NULL) |
|
13378 return (NULL); |
|
13379 ctxt = xmlNewParserCtxt(); |
|
13380 if (ctxt == NULL) { |
|
13381 xmlFreeParserInputBuffer(input); |
|
13382 return (NULL); |
|
13383 } |
|
13384 stream = xmlNewIOInputStream(ctxt, input, XML_CHAR_ENCODING_NONE); |
|
13385 if (stream == NULL) { |
|
13386 xmlFreeParserInputBuffer(input); |
|
13387 xmlFreeParserCtxt(ctxt); |
|
13388 return (NULL); |
|
13389 } |
|
13390 inputPush(ctxt, stream); |
|
13391 return (xmlDoRead(ctxt, URL, encoding, options, 0)); |
|
13392 } |
|
13393 |
|
13394 |
|
13395 /** |
|
13396 * xmlCtxtReadDoc: |
|
13397 * @param ctxt an XML parser context |
|
13398 * @param cur a pointer to a zero terminated string |
|
13399 * @param URL the base URL to use for the document |
|
13400 * @param encoding the document encoding, or NULL |
|
13401 * @param options a combination of xmlParserOption |
|
13402 * |
|
13403 * parse an XML in-memory document and build a tree. |
|
13404 * This reuses the existing ctxt parser context |
|
13405 * |
|
13406 * Returns the resulting document tree |
|
13407 */ |
|
13408 xmlDocPtr |
|
13409 xmlCtxtReadDoc(xmlParserCtxtPtr ctxt, const xmlChar * cur, |
|
13410 const char *URL, const char *encoding, int options) |
|
13411 { |
|
13412 xmlParserInputPtr stream; |
|
13413 |
|
13414 if (cur == NULL) |
|
13415 return (NULL); |
|
13416 if (ctxt == NULL) |
|
13417 return (NULL); |
|
13418 |
|
13419 xmlCtxtReset(ctxt); |
|
13420 |
|
13421 stream = xmlNewStringInputStream(ctxt, cur); |
|
13422 if (stream == NULL) { |
|
13423 return (NULL); |
|
13424 } |
|
13425 inputPush(ctxt, stream); |
|
13426 return (xmlDoRead(ctxt, URL, encoding, options, 1)); |
|
13427 } |
|
13428 |
|
13429 /** |
|
13430 * xmlCtxtReadFile: |
|
13431 * @param ctxt an XML parser context |
|
13432 * @param filename a file or URL |
|
13433 * @param encoding the document encoding, or NULL |
|
13434 * @param options a combination of xmlParserOption |
|
13435 * |
|
13436 * parse an XML file from the filesystem or the network. |
|
13437 * This reuses the existing ctxt parser context |
|
13438 * |
|
13439 * Returns the resulting document tree |
|
13440 */ |
|
13441 xmlDocPtr |
|
13442 xmlCtxtReadFile(xmlParserCtxtPtr ctxt, const char *filename, |
|
13443 const char *encoding, int options) |
|
13444 { |
|
13445 xmlParserInputPtr stream; |
|
13446 |
|
13447 if (filename == NULL) |
|
13448 return (NULL); |
|
13449 if (ctxt == NULL) |
|
13450 return (NULL); |
|
13451 |
|
13452 xmlCtxtReset(ctxt); |
|
13453 |
|
13454 stream = xmlNewInputFromFile(ctxt, filename); |
|
13455 if (stream == NULL) { |
|
13456 return (NULL); |
|
13457 } |
|
13458 inputPush(ctxt, stream); |
|
13459 return (xmlDoRead(ctxt, NULL, encoding, options, 1)); |
|
13460 } |
|
13461 |
|
13462 |
|
13463 /** |
|
13464 * xmlCtxtReadMemory: |
|
13465 * @param ctxt an XML parser context |
|
13466 * @param buffer a pointer to a char array |
|
13467 * @param size the size of the array |
|
13468 * @param URL the base URL to use for the document |
|
13469 * @param encoding the document encoding, or NULL |
|
13470 * @param options a combination of xmlParserOption |
|
13471 * |
|
13472 * parse an XML in-memory document and build a tree. |
|
13473 * This reuses the existing ctxt parser context |
|
13474 * |
|
13475 * Returns the resulting document tree |
|
13476 */ |
|
13477 xmlDocPtr |
|
13478 xmlCtxtReadMemory(xmlParserCtxtPtr ctxt, const char *buffer, int size, |
|
13479 const char *URL, const char *encoding, int options) |
|
13480 { |
|
13481 xmlParserInputBufferPtr input; |
|
13482 xmlParserInputPtr stream; |
|
13483 |
|
13484 if (ctxt == NULL) |
|
13485 return (NULL); |
|
13486 if (buffer == NULL) |
|
13487 return (NULL); |
|
13488 |
|
13489 xmlCtxtReset(ctxt); |
|
13490 |
|
13491 input = xmlParserInputBufferCreateMem(buffer, size, XML_CHAR_ENCODING_NONE); |
|
13492 if (input == NULL) { |
|
13493 return(NULL); |
|
13494 } |
|
13495 |
|
13496 stream = xmlNewIOInputStream(ctxt, input, XML_CHAR_ENCODING_NONE); |
|
13497 if (stream == NULL) { |
|
13498 xmlFreeParserInputBuffer(input); |
|
13499 return(NULL); |
|
13500 } |
|
13501 |
|
13502 inputPush(ctxt, stream); |
|
13503 return (xmlDoRead(ctxt, URL, encoding, options, 1)); |
|
13504 } |
|
13505 |
|
13506 |
|
13507 /** |
|
13508 * xmlCtxtReadFd: |
|
13509 * @param ctxt an XML parser context |
|
13510 * @param fd an open file descriptor |
|
13511 * @param URL the base URL to use for the document |
|
13512 * @param encoding the document encoding, or NULL |
|
13513 * @param options a combination of xmlParserOption |
|
13514 * |
|
13515 * parse an XML from a file descriptor and build a tree. |
|
13516 * This reuses the existing ctxt parser context |
|
13517 * NOTE that the file descriptor will not be closed when the |
|
13518 * reader is closed or reset. |
|
13519 * |
|
13520 * Returns the resulting document tree |
|
13521 */ |
|
13522 xmlDocPtr |
|
13523 xmlCtxtReadFd(xmlParserCtxtPtr ctxt, int fd, |
|
13524 const char *URL, const char *encoding, int options) |
|
13525 { |
|
13526 xmlParserInputBufferPtr input; |
|
13527 xmlParserInputPtr stream; |
|
13528 |
|
13529 if (fd < 0) |
|
13530 return (NULL); |
|
13531 if (ctxt == NULL) |
|
13532 return (NULL); |
|
13533 |
|
13534 xmlCtxtReset(ctxt); |
|
13535 |
|
13536 |
|
13537 input = xmlParserInputBufferCreateFd(fd, XML_CHAR_ENCODING_NONE); |
|
13538 if (input == NULL) |
|
13539 return (NULL); |
|
13540 input->closecallback = NULL; |
|
13541 stream = xmlNewIOInputStream(ctxt, input, XML_CHAR_ENCODING_NONE); |
|
13542 if (stream == NULL) { |
|
13543 xmlFreeParserInputBuffer(input); |
|
13544 return (NULL); |
|
13545 } |
|
13546 inputPush(ctxt, stream); |
|
13547 return (xmlDoRead(ctxt, URL, encoding, options, 1)); |
|
13548 } |
|
13549 |
|
13550 /** |
|
13551 * xmlCtxtReadIO: |
|
13552 * @param ctxt an XML parser context |
|
13553 * @param ioread an I/O read function |
|
13554 * @param ioclose an I/O close function |
|
13555 * @param ioctx an I/O handler |
|
13556 * @param URL the base URL to use for the document |
|
13557 * @param encoding the document encoding, or NULL |
|
13558 * @param options a combination of xmlParserOption |
|
13559 * |
|
13560 * parse an XML document from I/O functions and source and build a tree. |
|
13561 * This reuses the existing ctxt parser context |
|
13562 * |
|
13563 * Returns the resulting document tree |
|
13564 */ |
|
13565 xmlDocPtr |
|
13566 xmlCtxtReadIO(xmlParserCtxtPtr ctxt, xmlInputReadCallback ioread, |
|
13567 xmlInputCloseCallback ioclose, void *ioctx, |
|
13568 const char *URL, |
|
13569 const char *encoding, int options) |
|
13570 { |
|
13571 xmlParserInputBufferPtr input; |
|
13572 xmlParserInputPtr stream; |
|
13573 |
|
13574 if (ioread == NULL) |
|
13575 return (NULL); |
|
13576 if (ctxt == NULL) |
|
13577 return (NULL); |
|
13578 |
|
13579 xmlCtxtReset(ctxt); |
|
13580 |
|
13581 input = xmlParserInputBufferCreateIO(ioread, ioclose, ioctx, |
|
13582 XML_CHAR_ENCODING_NONE); |
|
13583 if (input == NULL) |
|
13584 return (NULL); |
|
13585 stream = xmlNewIOInputStream(ctxt, input, XML_CHAR_ENCODING_NONE); |
|
13586 if (stream == NULL) { |
|
13587 xmlFreeParserInputBuffer(input); |
|
13588 return (NULL); |
|
13589 } |
|
13590 inputPush(ctxt, stream); |
|
13591 return (xmlDoRead(ctxt, URL, encoding, options, 1)); |
|
13592 } |
|
13593 #endif /* ifndef XMLENGINE_EXCLUDE_UNUSED */ |