1/*
2   +----------------------------------------------------------------------+
3   | PHP Version 5                                                        |
4   +----------------------------------------------------------------------+
5   | Copyright (c) 1997-2013 The PHP Group                                |
6   +----------------------------------------------------------------------+
7   | This source file is subject to version 3.01 of the PHP license,      |
8   | that is bundled with this package in the file LICENSE, and is        |
9   | available through the world-wide-web at the following url:           |
10   | http://www.php.net/license/3_01.txt                                  |
11   | If you did not receive a copy of the PHP license and are unable to   |
12   | obtain it through the world-wide-web, please send a note to          |
13   | license@php.net so we can mail you a copy immediately.               |
14   +----------------------------------------------------------------------+
15   | Authors: Sterling Hughes <sterling@php.net>                          |
16   +----------------------------------------------------------------------+
17 */
18
19#include "php.h"
20#if defined(HAVE_LIBXML) && (defined(HAVE_XML) || defined(HAVE_XMLRPC)) && !defined(HAVE_LIBEXPAT)
21#include "expat_compat.h"
22
23typedef struct _php_xml_ns {
24    xmlNsPtr nsptr;
25    int ref_count;
26    void *next;
27    void *prev;
28} php_xml_ns;
29
30#ifdef LIBXML_EXPAT_COMPAT
31
32#define IS_NS_DECL(__ns) \
33    ((__ns) != NULL && strlen(__ns) == 5 && *(__ns) == 'x' && *((__ns)+1) == 'm' && \
34     *((__ns)+2) == 'l' && *((__ns)+3) == 'n' && *((__ns)+4) == 's')
35
36static void
37_qualify_namespace(XML_Parser parser, const xmlChar *name, const xmlChar *URI, xmlChar **qualified)
38{
39    if (URI) {
40            /* Use libxml functions otherwise its memory deallocation is screwed up */
41            *qualified = xmlStrdup(URI);
42            *qualified = xmlStrncat(*qualified, parser->_ns_seperator, 1);
43            *qualified = xmlStrncat(*qualified, name, xmlStrlen(name));
44    } else {
45        *qualified = xmlStrdup(name);
46    }
47}
48
49static void
50_start_element_handler(void *user, const xmlChar *name, const xmlChar **attributes)
51{
52    XML_Parser  parser = (XML_Parser) user;
53    xmlChar    *qualified_name = NULL;
54
55    if (parser->h_start_element == NULL) {
56        if (parser->h_default) {
57            int attno = 0;
58
59            qualified_name = xmlStrncatNew((xmlChar *)"<", name, xmlStrlen(name));
60            if (attributes) {
61                while (attributes[attno] != NULL) {
62                    int att_len;
63                    char *att_string, *att_name, *att_value;
64
65                    att_name = (char *)attributes[attno++];
66                    att_value = (char *)attributes[attno++];
67
68                    att_len = spprintf(&att_string, 0, " %s=\"%s\"", att_name, att_value);
69
70                    qualified_name = xmlStrncat(qualified_name, (xmlChar *)att_string, att_len);
71                    efree(att_string);
72                }
73
74            }
75            qualified_name = xmlStrncat(qualified_name, (xmlChar *)">", 1);
76            parser->h_default(parser->user, (const XML_Char *) qualified_name, xmlStrlen(qualified_name));
77            xmlFree(qualified_name);
78        }
79        return;
80    }
81
82    qualified_name = xmlStrdup(name);
83
84    parser->h_start_element(parser->user, (const XML_Char *) qualified_name, (const XML_Char **) attributes);
85
86    xmlFree(qualified_name);
87}
88
89static void
90_start_element_handler_ns(void *user, const xmlChar *name, const xmlChar *prefix, const xmlChar *URI, int nb_namespaces, const xmlChar ** namespaces, int nb_attributes, int nb_defaulted, const xmlChar ** attributes)
91{
92    XML_Parser  parser = (XML_Parser) user;
93    xmlChar    *qualified_name = NULL;
94    xmlChar **attrs = NULL;
95    int i;
96    int z = 0;
97    int y = 0;
98
99    if (nb_namespaces > 0 && parser->h_start_ns != NULL) {
100        for (i = 0; i < nb_namespaces; i += 1) {
101            parser->h_start_ns(parser->user, (const XML_Char *) namespaces[y], (const XML_Char *) namespaces[y+1]);
102            y += 2;
103        }
104        y = 0;
105    }
106
107    if (parser->h_start_element == NULL) {
108        if (parser->h_default) {
109
110            if (prefix) {
111                qualified_name = xmlStrncatNew((xmlChar *)"<", prefix, xmlStrlen(prefix));
112                qualified_name = xmlStrncat(qualified_name, (xmlChar *)":", 1);
113                qualified_name = xmlStrncat(qualified_name, name, xmlStrlen(name));
114            } else {
115                qualified_name = xmlStrncatNew((xmlChar *)"<", name, xmlStrlen(name));
116            }
117
118            if (namespaces) {
119                int i, j;
120                for (i = 0,j = 0;j < nb_namespaces;j++) {
121                    int ns_len;
122                    char *ns_string, *ns_prefix, *ns_url;
123
124                    ns_prefix = (char *) namespaces[i++];
125                    ns_url = (char *) namespaces[i++];
126
127                    if (ns_prefix) {
128                        ns_len = spprintf(&ns_string, 0, " xmlns:%s=\"%s\"", ns_prefix, ns_url);
129                    } else {
130                        ns_len = spprintf(&ns_string, 0, " xmlns=\"%s\"", ns_url);
131                    }
132                    qualified_name = xmlStrncat(qualified_name, (xmlChar *)ns_string, ns_len);
133
134                    efree(ns_string);
135                }
136            }
137
138            if (attributes) {
139                for (i = 0; i < nb_attributes; i += 1) {
140                    int att_len;
141                    char *att_string, *att_name, *att_value, *att_prefix, *att_valueend;
142
143                    att_name = (char *) attributes[y++];
144                    att_prefix = (char *)attributes[y++];
145                    y++;
146                    att_value = (char *)attributes[y++];
147                    att_valueend = (char *)attributes[y++];
148
149                    if (att_prefix) {
150                        att_len = spprintf(&att_string, 0, " %s:%s=\"", att_prefix, att_name);
151                    } else {
152                        att_len = spprintf(&att_string, 0, " %s=\"", att_name);
153                    }
154
155                    qualified_name = xmlStrncat(qualified_name, (xmlChar *)att_string, att_len);
156                    qualified_name = xmlStrncat(qualified_name, (xmlChar *)att_value, att_valueend - att_value);
157                    qualified_name = xmlStrncat(qualified_name, (xmlChar *)"\"", 1);
158
159                    efree(att_string);
160                }
161
162            }
163            qualified_name = xmlStrncat(qualified_name, (xmlChar *)">", 1);
164            parser->h_default(parser->user, (const XML_Char *) qualified_name, xmlStrlen(qualified_name));
165            xmlFree(qualified_name);
166        }
167        return;
168    }
169    _qualify_namespace(parser, name, URI, &qualified_name);
170
171    if (attributes != NULL) {
172        xmlChar    *qualified_name_attr = NULL;
173        attrs = safe_emalloc((nb_attributes  * 2) + 1, sizeof(int *), 0);
174
175        for (i = 0; i < nb_attributes; i += 1) {
176
177            if (attributes[y+1] != NULL) {
178                _qualify_namespace(parser, attributes[y] , attributes[y + 2], &qualified_name_attr);
179            } else {
180                qualified_name_attr = xmlStrdup(attributes[y]);
181            }
182            attrs[z] = qualified_name_attr;
183            attrs[z + 1] = xmlStrndup(attributes[y + 3] , (int) (attributes[y + 4] - attributes[y + 3]));
184            z += 2;
185            y += 5;
186        }
187
188        attrs[z] = NULL;
189    }
190    parser->h_start_element(parser->user, (const XML_Char *) qualified_name, (const XML_Char **) attrs);
191    if (attrs) {
192        for (i = 0; i < z; i++) {
193            xmlFree(attrs[i]);
194        }
195        efree(attrs);
196    }
197    xmlFree(qualified_name);
198}
199
200static void
201_namespace_handler(XML_Parser parser, xmlNsPtr nsptr)
202{
203    if (nsptr != NULL) {
204        _namespace_handler(parser, nsptr->next);
205        parser->h_end_ns(parser->user, nsptr->prefix);
206    }
207}
208
209static void
210_end_element_handler(void *user, const xmlChar *name)
211{
212    xmlChar    *qualified_name;
213    XML_Parser  parser = (XML_Parser) user;
214
215    if (parser->h_end_element == NULL) {
216        if (parser->h_default) {
217            char *end_element;
218
219            spprintf(&end_element, 0, "</%s>", (char *)name);
220            parser->h_default(parser->user, (const XML_Char *) end_element, strlen(end_element));
221            efree(end_element);
222        }
223        return;
224    }
225
226    qualified_name = xmlStrdup(name);
227
228    parser->h_end_element(parser->user, (const XML_Char *) qualified_name);
229
230    xmlFree(qualified_name);
231}
232
233static void
234_end_element_handler_ns(void *user, const xmlChar *name, const xmlChar * prefix, const xmlChar *URI)
235{
236    xmlChar    *qualified_name;
237    XML_Parser  parser = (XML_Parser) user;
238
239    if (parser->h_end_element == NULL) {
240        if (parser->h_default) {
241            char *end_element;
242            int end_element_len;
243
244            if (prefix) {
245                end_element_len = spprintf(&end_element, 0, "</%s:%s>", (char *) prefix, (char *)name);
246            } else {
247                end_element_len = spprintf(&end_element, 0, "</%s>", (char *)name);
248            }
249            parser->h_default(parser->user, (const XML_Char *) end_element, end_element_len);
250            efree(end_element);
251        }
252        return;
253    }
254
255    _qualify_namespace(parser, name, URI,  &qualified_name);
256
257    parser->h_end_element(parser->user, (const XML_Char *) qualified_name);
258
259    xmlFree(qualified_name);
260}
261
262static void
263_cdata_handler(void *user, const xmlChar *cdata, int cdata_len)
264{
265    XML_Parser parser = (XML_Parser) user;
266
267    if (parser->h_cdata == NULL) {
268        if (parser->h_default) {
269            parser->h_default(parser->user, (const XML_Char *) cdata, cdata_len);
270        }
271        return;
272    }
273
274    parser->h_cdata(parser->user, (const XML_Char *) cdata, cdata_len);
275}
276
277static void
278_pi_handler(void *user, const xmlChar *target, const xmlChar *data)
279{
280    XML_Parser parser = (XML_Parser) user;
281
282    if (parser->h_pi == NULL) {
283        if (parser->h_default) {
284            char    *full_pi;
285            spprintf(&full_pi, 0, "<?%s %s?>", (char *)target, (char *)data);
286            parser->h_default(parser->user, (const XML_Char *) full_pi, strlen(full_pi));
287            efree(full_pi);
288        }
289        return;
290    }
291
292    parser->h_pi(parser->user, (const XML_Char *) target, (const XML_Char *) data);
293}
294
295static void
296_unparsed_entity_decl_handler(void *user,
297                              const xmlChar *name,
298                              const xmlChar *pub_id,
299                              const xmlChar *sys_id,
300                              const xmlChar *notation)
301{
302    XML_Parser parser = (XML_Parser) user;
303
304    if (parser->h_unparsed_entity_decl == NULL) {
305        return;
306    }
307
308    parser->h_unparsed_entity_decl(parser->user, name, NULL, sys_id, pub_id, notation);
309}
310
311static void
312_notation_decl_handler(void *user, const xmlChar *notation, const xmlChar *pub_id, const xmlChar *sys_id)
313{
314    XML_Parser parser = (XML_Parser) user;
315
316    if (parser->h_notation_decl == NULL) {
317        return;
318    }
319
320    parser->h_notation_decl(parser->user, notation, NULL, sys_id, pub_id);
321}
322
323static void
324_build_comment(const xmlChar *data, int data_len, xmlChar **comment, int *comment_len)
325{
326    *comment_len = data_len + 7;
327
328    *comment = xmlMalloc(*comment_len + 1);
329    memcpy(*comment, "<!--", 4);
330    memcpy(*comment + 4, data, data_len);
331    memcpy(*comment + 4 + data_len, "-->", 3);
332
333    (*comment)[*comment_len] = '\0';
334}
335
336static void
337_comment_handler(void *user, const xmlChar *comment)
338{
339    XML_Parser parser = (XML_Parser) user;
340
341    if (parser->h_default) {
342        xmlChar *d_comment;
343        int      d_comment_len;
344
345        _build_comment(comment, xmlStrlen(comment), &d_comment, &d_comment_len);
346        parser->h_default(parser->user, d_comment, d_comment_len);
347        xmlFree(d_comment);
348    }
349}
350
351static void
352_build_entity(const xmlChar *name, int len, xmlChar **entity, int *entity_len)
353{
354    *entity_len = len + 2;
355    *entity = xmlMalloc(*entity_len + 1);
356    (*entity)[0] = '&';
357    memcpy(*entity+1, name, len);
358    (*entity)[len+1] = ';';
359    (*entity)[*entity_len] = '\0';
360}
361
362static void
363_external_entity_ref_handler(void *user, const xmlChar *names, int type, const xmlChar *sys_id, const xmlChar *pub_id, xmlChar *content)
364{
365    XML_Parser parser = (XML_Parser) user;
366
367    if (parser->h_external_entity_ref == NULL) {
368        return;
369    }
370
371    parser->h_external_entity_ref(parser, names, "", sys_id, pub_id);
372}
373
374static xmlEntityPtr
375_get_entity(void *user, const xmlChar *name)
376{
377    XML_Parser parser = (XML_Parser) user;
378    xmlEntityPtr ret = NULL;
379
380    if (parser->parser->inSubset == 0) {
381        ret = xmlGetPredefinedEntity(name);
382        if (ret == NULL)
383            ret = xmlGetDocEntity(parser->parser->myDoc, name);
384
385        if (ret == NULL || (parser->parser->instate != XML_PARSER_ENTITY_VALUE && parser->parser->instate != XML_PARSER_ATTRIBUTE_VALUE)) {
386            if (ret == NULL || ret->etype == XML_INTERNAL_GENERAL_ENTITY || ret->etype == XML_INTERNAL_PARAMETER_ENTITY || ret->etype == XML_INTERNAL_PREDEFINED_ENTITY) {
387                /* Predefined entities will expand unless no cdata handler is present */
388                if (parser->h_default && ! (ret && ret->etype == XML_INTERNAL_PREDEFINED_ENTITY && parser->h_cdata)) {
389                    xmlChar *entity;
390                    int      len;
391
392                    _build_entity(name, xmlStrlen(name), &entity, &len);
393                    parser->h_default(parser->user, (const xmlChar *) entity, len);
394                    xmlFree(entity);
395                } else {
396                    /* expat will not expand internal entities if default handler is present otherwise
397                    it will expand and pass them to cdata handler */
398                    if (parser->h_cdata && ret) {
399                        parser->h_cdata(parser->user, ret->content, xmlStrlen(ret->content));
400                    }
401                }
402            } else {
403                if (ret->etype == XML_EXTERNAL_GENERAL_PARSED_ENTITY) {
404                    _external_entity_ref_handler(user, ret->name, ret->etype, ret->SystemID, ret->ExternalID, NULL);
405                }
406            }
407        }
408    }
409
410    return ret;
411}
412
413static xmlSAXHandler
414php_xml_compat_handlers = {
415    NULL, /* internalSubset */
416    NULL, /* isStandalone */
417    NULL, /* hasInternalSubset */
418    NULL, /* hasExternalSubset */
419    NULL, /* resolveEntity */
420    _get_entity, /* getEntity */
421    NULL, /* entityDecl */
422    _notation_decl_handler,
423    NULL, /* attributeDecl */
424    NULL, /* elementDecl */
425    _unparsed_entity_decl_handler, /* unparsedEntity */
426    NULL, /* setDocumentLocator */
427    NULL, /* startDocument */
428    NULL, /* endDocument */
429    _start_element_handler, /* startElement */
430    _end_element_handler, /* endElement */
431    NULL, /* reference */
432    _cdata_handler,
433    NULL, /* ignorableWhitespace */
434    _pi_handler,
435    _comment_handler, /* comment */
436    NULL, /* warning */
437    NULL, /* error */
438    NULL,  /* fatalError */
439    NULL,  /* getParameterEntity */
440    _cdata_handler, /* cdataBlock */
441    NULL, /* externalSubset */
442    XML_SAX2_MAGIC,
443    NULL,
444    _start_element_handler_ns,
445    _end_element_handler_ns,
446    NULL
447};
448
449PHPAPI XML_Parser
450XML_ParserCreate(const XML_Char *encoding)
451{
452    return XML_ParserCreate_MM(encoding, NULL, NULL);
453}
454
455PHPAPI XML_Parser
456XML_ParserCreateNS(const XML_Char *encoding, const XML_Char sep)
457{
458    XML_Char tmp[2];
459    tmp[0] = sep;
460    tmp[1] = '\0';
461    return XML_ParserCreate_MM(encoding, NULL, tmp);
462}
463
464PHPAPI XML_Parser
465XML_ParserCreate_MM(const XML_Char *encoding, const XML_Memory_Handling_Suite *memsuite, const XML_Char *sep)
466{
467    XML_Parser parser;
468
469    parser = (XML_Parser) emalloc(sizeof(struct _XML_Parser));
470    memset(parser, 0, sizeof(struct _XML_Parser));
471    parser->use_namespace = 0;
472    parser->_ns_seperator = NULL;
473
474    parser->parser = xmlCreatePushParserCtxt((xmlSAXHandlerPtr) &php_xml_compat_handlers, (void *) parser, NULL, 0, NULL);
475    if (parser->parser == NULL) {
476        efree(parser);
477        return NULL;
478    }
479#if LIBXML_VERSION <= 20617
480    /* for older versions of libxml2, allow correct detection of
481     * charset in documents with a BOM: */
482    parser->parser->charset = XML_CHAR_ENCODING_NONE;
483#endif
484
485#if LIBXML_VERSION >= 20703
486    xmlCtxtUseOptions(parser->parser, XML_PARSE_OLDSAX);
487#endif
488
489    parser->parser->replaceEntities = 1;
490    parser->parser->wellFormed = 0;
491    if (sep != NULL) {
492        parser->use_namespace = 1;
493        parser->parser->sax2 = 1;
494        parser->_ns_seperator = xmlStrdup(sep);
495    } else {
496        /* Reset flag as XML_SAX2_MAGIC is needed for xmlCreatePushParserCtxt
497        so must be set in the handlers */
498        parser->parser->sax->initialized = 1;
499    }
500    return parser;
501}
502
503PHPAPI void
504XML_SetUserData(XML_Parser parser, void *user)
505{
506    parser->user = user;
507}
508
509PHPAPI void *
510XML_GetUserData(XML_Parser parser)
511{
512    return parser->user;
513}
514
515PHPAPI void
516XML_SetElementHandler(XML_Parser parser, XML_StartElementHandler start, XML_EndElementHandler end)
517{
518    parser->h_start_element = start;
519    parser->h_end_element = end;
520}
521
522PHPAPI void
523XML_SetCharacterDataHandler(XML_Parser parser, XML_CharacterDataHandler cdata)
524{
525    parser->h_cdata = cdata;
526}
527
528PHPAPI void
529XML_SetProcessingInstructionHandler(XML_Parser parser, XML_ProcessingInstructionHandler pi)
530{
531    parser->h_pi = pi;
532}
533
534PHPAPI void
535XML_SetCommentHandler(XML_Parser parser, XML_CommentHandler comment)
536{
537    parser->h_comment = comment;
538}
539
540PHPAPI void
541XML_SetDefaultHandler(XML_Parser parser, XML_DefaultHandler d)
542{
543    parser->h_default = d;
544}
545
546PHPAPI void
547XML_SetUnparsedEntityDeclHandler(XML_Parser parser, XML_UnparsedEntityDeclHandler unparsed_decl)
548{
549    parser->h_unparsed_entity_decl = unparsed_decl;
550}
551
552PHPAPI void
553XML_SetNotationDeclHandler(XML_Parser parser, XML_NotationDeclHandler notation_decl)
554{
555    parser->h_notation_decl = notation_decl;
556}
557
558PHPAPI void
559XML_SetExternalEntityRefHandler(XML_Parser parser, XML_ExternalEntityRefHandler ext_entity)
560{
561    parser->h_external_entity_ref = ext_entity;
562}
563
564PHPAPI void
565XML_SetStartNamespaceDeclHandler(XML_Parser parser, XML_StartNamespaceDeclHandler start_ns)
566{
567    parser->h_start_ns = start_ns;
568}
569
570PHPAPI void
571XML_SetEndNamespaceDeclHandler(XML_Parser parser, XML_EndNamespaceDeclHandler end_ns)
572{
573    parser->h_end_ns = end_ns;
574}
575
576PHPAPI int
577XML_Parse(XML_Parser parser, const XML_Char *data, int data_len, int is_final)
578{
579    int error;
580
581/* The following is a hack to keep BC with PHP 4 while avoiding
582the inifite loop in libxml <= 2.6.17 which occurs when no encoding
583has been defined and none can be detected */
584#if LIBXML_VERSION <= 20617
585    if (parser->parser->charset == XML_CHAR_ENCODING_NONE) {
586        if (data_len >= 4 || (parser->parser->input->buf->buffer->use + data_len >= 4)) {
587            xmlChar start[4];
588            int char_count;
589
590            char_count = parser->parser->input->buf->buffer->use;
591            if (char_count > 4) {
592                char_count = 4;
593            }
594
595            memcpy(start, parser->parser->input->buf->buffer->content, (size_t)char_count);
596            memcpy(start + char_count, data, (size_t)(4 - char_count));
597
598            if (xmlDetectCharEncoding(&start[0], 4) == XML_CHAR_ENCODING_NONE) {
599                parser->parser->charset = XML_CHAR_ENCODING_UTF8;
600            }
601        }
602    }
603#endif
604
605    error = xmlParseChunk(parser->parser, data, data_len, is_final);
606    if (!error) {
607        return 1;
608    } else if (parser->parser->lastError.level > XML_ERR_WARNING ){
609        return 0;
610    } else {
611        return 1;
612    }
613}
614
615PHPAPI int
616XML_GetErrorCode(XML_Parser parser)
617{
618    return parser->parser->errNo;
619}
620
621static const XML_Char *const error_mapping[] = {
622    "No error",
623    "No memory",
624    "Invalid document start",
625    "Empty document",
626    "Not well-formed (invalid token)",
627    "Invalid document end",
628    "Invalid hexadecimal character reference",
629    "Invalid decimal character reference",
630    "Invalid character reference",
631    "Invalid character",
632    "XML_ERR_CHARREF_AT_EOF",
633    "XML_ERR_CHARREF_IN_PROLOG",
634    "XML_ERR_CHARREF_IN_EPILOG",
635    "XML_ERR_CHARREF_IN_DTD",
636    "XML_ERR_ENTITYREF_AT_EOF",
637    "XML_ERR_ENTITYREF_IN_PROLOG",
638    "XML_ERR_ENTITYREF_IN_EPILOG",
639    "XML_ERR_ENTITYREF_IN_DTD",
640    "PEReference at end of document",
641    "PEReference in prolog",
642    "PEReference in epilog",
643    "PEReference: forbidden within markup decl in internal subset",
644    "XML_ERR_ENTITYREF_NO_NAME",
645    "EntityRef: expecting ';'",
646    "PEReference: no name",
647    "PEReference: expecting ';'",
648    "Undeclared entity error",
649    "Undeclared entity warning",
650    "Unparsed Entity",
651    "XML_ERR_ENTITY_IS_EXTERNAL",
652    "XML_ERR_ENTITY_IS_PARAMETER",
653    "Unknown encoding",
654    "Unsupported encoding",
655    "String not started expecting ' or \"",
656    "String not closed expecting \" or '",
657    "Namespace declaration error",
658    "EntityValue: \" or ' expected",
659    "EntityValue: \" or ' expected",
660    "< in attribute",
661    "Attribute not started",
662    "Attribute not finished",
663    "Attribute without value",
664    "Attribute redefined",
665    "SystemLiteral \" or ' expected",
666    "SystemLiteral \" or ' expected",
667    /* "XML_ERR_COMMENT_NOT_STARTED", <= eliminated on purpose */
668    "Comment not finished",
669    "Processing Instruction not started",
670    "Processing Instruction not finished",
671    "NOTATION: Name expected here",
672    "'>' required to close NOTATION declaration",
673    "'(' required to start ATTLIST enumeration",
674    "'(' required to start ATTLIST enumeration",
675    "MixedContentDecl : '|' or ')*' expected",
676    "XML_ERR_MIXED_NOT_FINISHED",
677    "ELEMENT in DTD not started",
678    "ELEMENT in DTD not finished",
679    "XML declaration not started",
680    "XML declaration not finished",
681    "XML_ERR_CONDSEC_NOT_STARTED",
682    "XML conditional section not closed",
683    "Content error in the external subset",
684    "DOCTYPE not finished",
685    "Sequence ']]>' not allowed in content",
686    "CDATA not finished",
687    "Reserved XML Name",
688    "Space required",
689    "XML_ERR_SEPARATOR_REQUIRED",
690    "NmToken expected in ATTLIST enumeration",
691    "XML_ERR_NAME_REQUIRED",
692    "MixedContentDecl : '#PCDATA' expected",
693    "SYSTEM or PUBLIC, the URI is missing",
694    "PUBLIC, the Public Identifier is missing",
695    "< required",
696    "> required",
697    "</ required",
698    "= required",
699    "Mismatched tag",
700    "Tag not finished",
701    "standalone accepts only 'yes' or 'no'",
702    "Invalid XML encoding name",
703    "Comment must not contain '--' (double-hyphen)",
704    "Invalid encoding",
705    "external parsed entities cannot be standalone",
706    "XML conditional section '[' expected",
707    "Entity value required",
708    "chunk is not well balanced",
709    "extra content at the end of well balanced chunk",
710    "XML_ERR_ENTITY_CHAR_ERROR",
711    "PEReferences forbidden in internal subset",
712    "Detected an entity reference loop",
713    "XML_ERR_ENTITY_BOUNDARY",
714    "Invalid URI",
715    "Fragment not allowed",
716    "XML_WAR_CATALOG_PI",
717    "XML_ERR_NO_DTD",
718    "conditional section INCLUDE or IGNORE keyword expected", /* 95 */
719    "Version in XML Declaration missing", /* 96 */
720    "XML_WAR_UNKNOWN_VERSION", /* 97 */
721    "XML_WAR_LANG_VALUE", /* 98 */
722    "XML_WAR_NS_URI", /* 99 */
723    "XML_WAR_NS_URI_RELATIVE", /* 100 */
724    "Missing encoding in text declaration" /* 101 */
725};
726
727PHPAPI const XML_Char *
728XML_ErrorString(int code)
729{
730    if (code < 0 || code >= (int)(sizeof(error_mapping) / sizeof(error_mapping[0]))) {
731        return "Unknown";
732    }
733    return error_mapping[code];
734}
735
736PHPAPI int
737XML_GetCurrentLineNumber(XML_Parser parser)
738{
739    return parser->parser->input->line;
740}
741
742PHPAPI int
743XML_GetCurrentColumnNumber(XML_Parser parser)
744{
745    return parser->parser->input->col;
746}
747
748PHPAPI int
749XML_GetCurrentByteIndex(XML_Parser parser)
750{
751    return parser->parser->input->consumed +
752            (parser->parser->input->cur - parser->parser->input->base);
753}
754
755PHPAPI int
756XML_GetCurrentByteCount(XML_Parser parser)
757{
758    /* WARNING: this is identical to ByteIndex; it should probably
759     * be different */
760    return parser->parser->input->consumed +
761            (parser->parser->input->cur - parser->parser->input->base);
762}
763
764PHPAPI const XML_Char *XML_ExpatVersion(void)
765{
766    return "1.0";
767}
768
769PHPAPI void
770XML_ParserFree(XML_Parser parser)
771{
772    if (parser->use_namespace) {
773        if (parser->_ns_seperator) {
774            xmlFree(parser->_ns_seperator);
775        }
776    }
777    if (parser->parser->myDoc) {
778        xmlFreeDoc(parser->parser->myDoc);
779        parser->parser->myDoc = NULL;
780    }
781    xmlFreeParserCtxt(parser->parser);
782    efree(parser);
783}
784
785#endif /* LIBXML_EXPAT_COMPAT */
786#endif
787
788/**
789 * Local Variables:
790 * tab-width: 4
791 * c-basic-offset: 4
792 * indent-tabs-mode: t
793 * End:
794 * vim600: fdm=marker
795 * vim: ts=4 noet sw=4
796 */
797