Annotation of XML/parser.c, revision 1.74

1.1       veillard    1: /*
1.3       veillard    2:  * parser.c : an XML 1.0 non-verifying parser
1.15      veillard    3:  *
                      4:  * See Copyright for the status of this software.
                      5:  *
1.60      daniel      6:  * Daniel.Veillard@w3.org
1.1       veillard    7:  */
                      8: 
1.26      daniel      9: #ifdef WIN32
                     10: #define HAVE_FCNTL_H
                     11: #include <io.h>
                     12: #else
1.9       httpng     13: #include <config.h>
1.26      daniel     14: #endif
1.1       veillard   15: #include <stdio.h>
                     16: #include <ctype.h>
1.14      veillard   17: #include <string.h> /* for memset() only */
1.50      daniel     18: #include <stdlib.h>
1.9       httpng     19: #include <sys/stat.h>
                     20: #ifdef HAVE_FCNTL_H
                     21: #include <fcntl.h>
                     22: #endif
1.10      httpng     23: #ifdef HAVE_UNISTD_H
                     24: #include <unistd.h>
                     25: #endif
1.20      daniel     26: #ifdef HAVE_ZLIB_H
                     27: #include <zlib.h>
                     28: #endif
1.1       veillard   29: 
1.14      veillard   30: #include "tree.h"
1.1       veillard   31: #include "parser.h"
1.14      veillard   32: #include "entities.h"
1.61      daniel     33: #include "valid.h"
1.69      daniel     34: #include "parserInternals.h"
1.1       veillard   35: 
1.45      daniel     36: /************************************************************************
                     37:  *                                                                     *
                     38:  *             Parser stacks related functions and macros              *
                     39:  *                                                                     *
                     40:  ************************************************************************/
1.1       veillard   41: /*
1.40      daniel     42:  * Generic function for accessing stacks in the Parser Context
1.1       veillard   43:  */
                     44: 
1.31      daniel     45: #define PUSH_AND_POP(type, name)                                       \
1.72      daniel     46: extern int name##Push(xmlParserCtxtPtr ctxt, type value) {             \
1.31      daniel     47:     if (ctxt->name##Nr >= ctxt->name##Max) {                           \
                     48:        ctxt->name##Max *= 2;                                           \
1.40      daniel     49:         ctxt->name##Tab = (void *) realloc(ctxt->name##Tab,            \
                     50:                     ctxt->name##Max * sizeof(ctxt->name##Tab[0]));     \
                     51:         if (ctxt->name##Tab == NULL) {                                 \
1.31      daniel     52:            fprintf(stderr, "realloc failed !\n");                      \
                     53:            exit(1);                                                    \
                     54:        }                                                               \
                     55:     }                                                                  \
1.40      daniel     56:     ctxt->name##Tab[ctxt->name##Nr] = value;                           \
                     57:     ctxt->name = value;                                                        \
                     58:     return(ctxt->name##Nr++);                                          \
1.31      daniel     59: }                                                                      \
1.72      daniel     60: extern type name##Pop(xmlParserCtxtPtr ctxt) {                         \
1.69      daniel     61:     type ret;                                                          \
1.40      daniel     62:     if (ctxt->name##Nr <= 0) return(0);                                        \
                     63:     ctxt->name##Nr--;                                                  \
1.50      daniel     64:     if (ctxt->name##Nr > 0)                                            \
                     65:        ctxt->name = ctxt->name##Tab[ctxt->name##Nr - 1];               \
                     66:     else                                                               \
                     67:         ctxt->name = NULL;                                             \
1.69      daniel     68:     ret = ctxt->name##Tab[ctxt->name##Nr];                             \
                     69:     ctxt->name##Tab[ctxt->name##Nr] = 0;                               \
                     70:     return(ret);                                                       \
1.31      daniel     71: }                                                                      \
                     72: 
1.40      daniel     73: PUSH_AND_POP(xmlParserInputPtr, input)
1.41      daniel     74: PUSH_AND_POP(xmlNodePtr, node)
1.40      daniel     75: 
1.55      daniel     76: /*
                     77:  * Macros for accessing the content. Those should be used only by the parser,
                     78:  * and not exported.
                     79:  *
                     80:  * Dirty macros, i.e. one need to make assumption on the context to use them
                     81:  *
                     82:  *   CUR_PTR return the current pointer to the CHAR to be parsed.
                     83:  *   CUR     returns the current CHAR value, i.e. a 8 bit value if compiled
                     84:  *           in ISO-Latin or UTF-8, and the current 16 bit value if compiled
                     85:  *           in UNICODE mode. This should be used internally by the parser
                     86:  *           only to compare to ASCII values otherwise it would break when
                     87:  *           running with UTF-8 encoding.
                     88:  *   NXT(n)  returns the n'th next CHAR. Same as CUR is should be used only
                     89:  *           to compare on ASCII based substring.
                     90:  *   SKIP(n) Skip n CHAR, and must also be used only to skip ASCII defined
                     91:  *           strings within the parser.
                     92:  *
                     93:  * Clean macros, not dependent of an ASCII context.
                     94:  *
                     95:  *   CURRENT Returns the current char value, with the full decoding of
                     96:  *           UTF-8 if we are using this mode. It returns an int.
                     97:  *   NEXT    Skip to the next character, this does the proper decoding
                     98:  *           in UTF-8 mode. It also pop-up unfinished entities on the fly.
                     99:  *           It returns the pointer to the current CHAR.
                    100:  */
1.45      daniel    101: 
                    102: #define CUR (*ctxt->input->cur)
1.55      daniel    103: #define SKIP(val) ctxt->input->cur += (val)
                    104: #define NXT(val) ctxt->input->cur[(val)]
                    105: #define CUR_PTR ctxt->input->cur
                    106: 
                    107: #define SKIP_BLANKS                                                    \
                    108:     while (IS_BLANK(*(ctxt->input->cur))) NEXT
                    109: 
                    110: #ifndef USE_UTF_8
                    111: #define CURRENT (*ctxt->input->cur)
1.45      daniel    112: #define NEXT ((*ctxt->input->cur) ?                                    \
                    113:                 (((*(ctxt->input->cur) == '\n') ?                      \
                    114:                    (ctxt->input->line++, ctxt->input->col = 1) :       \
                    115:                    (ctxt->input->col++)), ctxt->input->cur++) :        \
                    116:                (xmlPopInput(ctxt), ctxt->input->cur))
1.55      daniel    117: #else
                    118: #endif
1.42      daniel    119: 
1.40      daniel    120: 
1.50      daniel    121: /**
                    122:  * xmlPopInput:
                    123:  * @ctxt:  an XML parser context
                    124:  *
1.40      daniel    125:  * xmlPopInput: the current input pointed by ctxt->input came to an end
                    126:  *          pop it and return the next char.
1.45      daniel    127:  *
                    128:  * TODO A deallocation of the popped Input structure is needed
1.68      daniel    129:  *
                    130:  * Returns the current CHAR in the parser context
1.40      daniel    131:  */
1.55      daniel    132: CHAR
                    133: xmlPopInput(xmlParserCtxtPtr ctxt) {
1.40      daniel    134:     if (ctxt->inputNr == 1) return(0); /* End of main Input */
1.69      daniel    135:     xmlFreeInputStream(inputPop(ctxt));
1.40      daniel    136:     return(CUR);
                    137: }
                    138: 
1.50      daniel    139: /**
                    140:  * xmlPushInput:
                    141:  * @ctxt:  an XML parser context
                    142:  * @input:  an XML parser input fragment (entity, XML fragment ...).
                    143:  *
1.40      daniel    144:  * xmlPushInput: switch to a new input stream which is stacked on top
                    145:  *               of the previous one(s).
                    146:  */
1.55      daniel    147: void
                    148: xmlPushInput(xmlParserCtxtPtr ctxt, xmlParserInputPtr input) {
1.40      daniel    149:     if (input == NULL) return;
                    150:     inputPush(ctxt, input);
                    151: }
                    152: 
1.50      daniel    153: /**
1.69      daniel    154:  * xmlFreeInputStream:
                    155:  * @input:  an xmlParserInputPtr
                    156:  *
                    157:  * Free up an input stream.
                    158:  */
                    159: void
                    160: xmlFreeInputStream(xmlParserInputPtr input) {
                    161:     if (input == NULL) return;
                    162: 
                    163:     if (input->filename != NULL) free((char *) input->filename);
                    164:     if ((input->free != NULL) && (input->base != NULL))
                    165:         input->free((char *) input->base);
                    166:     memset(input, -1, sizeof(xmlParserInput));
                    167:     free(input);
                    168: }
                    169: 
                    170: /**
1.50      daniel    171:  * xmlNewEntityInputStream:
                    172:  * @ctxt:  an XML parser context
                    173:  * @entity:  an Entity pointer
                    174:  *
1.45      daniel    175:  * Create a new input stream based on a memory buffer.
1.68      daniel    176:  * Returns the new input stream
1.45      daniel    177:  */
1.50      daniel    178: xmlParserInputPtr
                    179: xmlNewEntityInputStream(xmlParserCtxtPtr ctxt, xmlEntityPtr entity) {
1.45      daniel    180:     xmlParserInputPtr input;
                    181: 
                    182:     if (entity == NULL) {
1.55      daniel    183:         if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74    ! daniel    184:            ctxt->sax->error(ctxt->userData,
1.45      daniel    185:              "internal: xmlNewEntityInputStream entity = NULL\n");
1.50      daniel    186:        return(NULL);
1.45      daniel    187:     }
                    188:     if (entity->content == NULL) {
1.55      daniel    189:         if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74    ! daniel    190:            ctxt->sax->error(ctxt->userData,
1.45      daniel    191:              "internal: xmlNewEntityInputStream entity->input = NULL\n");
1.50      daniel    192:        return(NULL);
1.45      daniel    193:     }
                    194:     input = (xmlParserInputPtr) malloc(sizeof(xmlParserInput));
                    195:     if (input == NULL) {
1.55      daniel    196:        if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74    ! daniel    197:            ctxt->sax->error(ctxt->userData, "malloc: couldn't allocate a new input stream\n");
1.50      daniel    198:        return(NULL);
1.45      daniel    199:     }
                    200:     input->filename = entity->SystemID; /* TODO !!! char <- CHAR */
                    201:     input->base = entity->content;
                    202:     input->cur = entity->content;
                    203:     input->line = 1;
                    204:     input->col = 1;
1.69      daniel    205:     input->free = NULL;
1.50      daniel    206:     return(input);
1.45      daniel    207: }
                    208: 
1.59      daniel    209: /**
                    210:  * xmlNewStringInputStream:
                    211:  * @ctxt:  an XML parser context
                    212:  * @entity:  an Entity pointer
                    213:  *
                    214:  * Create a new input stream based on a memory buffer.
1.68      daniel    215:  * Returns the new input stream
1.59      daniel    216:  */
                    217: xmlParserInputPtr
                    218: xmlNewStringInputStream(xmlParserCtxtPtr ctxt, CHAR *string) {
                    219:     xmlParserInputPtr input;
                    220: 
                    221:     if (string == NULL) {
                    222:         if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74    ! daniel    223:            ctxt->sax->error(ctxt->userData,
1.59      daniel    224:              "internal: xmlNewStringInputStream string = NULL\n");
                    225:        return(NULL);
                    226:     }
                    227:     input = (xmlParserInputPtr) malloc(sizeof(xmlParserInput));
                    228:     if (input == NULL) {
                    229:        if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74    ! daniel    230:            ctxt->sax->error(ctxt->userData, "malloc: couldn't allocate a new input stream\n");
1.59      daniel    231:        return(NULL);
                    232:     }
                    233:     input->filename = NULL;
                    234:     input->base = string;
                    235:     input->cur = string;
                    236:     input->line = 1;
                    237:     input->col = 1;
1.69      daniel    238:     input->free = NULL;
1.59      daniel    239:     return(input);
                    240: }
                    241: 
1.1       veillard  242: 
1.28      daniel    243: /************************************************************************
                    244:  *                                                                     *
                    245:  *             Commodity functions to handle CHARs                     *
                    246:  *                                                                     *
                    247:  ************************************************************************/
                    248: 
1.50      daniel    249: /**
                    250:  * xmlStrndup:
                    251:  * @cur:  the input CHAR *
                    252:  * @len:  the len of @cur
                    253:  *
                    254:  * a strndup for array of CHAR's
1.68      daniel    255:  *
                    256:  * Returns a new CHAR * or NULL
1.1       veillard  257:  */
1.55      daniel    258: CHAR *
                    259: xmlStrndup(const CHAR *cur, int len) {
1.1       veillard  260:     CHAR *ret = malloc((len + 1) * sizeof(CHAR));
                    261: 
                    262:     if (ret == NULL) {
                    263:         fprintf(stderr, "malloc of %d byte failed\n",
                    264:                (len + 1) * sizeof(CHAR));
                    265:         return(NULL);
                    266:     }
                    267:     memcpy(ret, cur, len * sizeof(CHAR));
                    268:     ret[len] = 0;
                    269:     return(ret);
                    270: }
                    271: 
1.50      daniel    272: /**
                    273:  * xmlStrdup:
                    274:  * @cur:  the input CHAR *
                    275:  *
                    276:  * a strdup for array of CHAR's
1.68      daniel    277:  *
                    278:  * Returns a new CHAR * or NULL
1.1       veillard  279:  */
1.55      daniel    280: CHAR *
                    281: xmlStrdup(const CHAR *cur) {
1.6       httpng    282:     const CHAR *p = cur;
1.1       veillard  283: 
                    284:     while (IS_CHAR(*p)) p++;
                    285:     return(xmlStrndup(cur, p - cur));
                    286: }
                    287: 
1.50      daniel    288: /**
                    289:  * xmlCharStrndup:
                    290:  * @cur:  the input char *
                    291:  * @len:  the len of @cur
                    292:  *
                    293:  * a strndup for char's to CHAR's
1.68      daniel    294:  *
                    295:  * Returns a new CHAR * or NULL
1.45      daniel    296:  */
                    297: 
1.55      daniel    298: CHAR *
                    299: xmlCharStrndup(const char *cur, int len) {
1.45      daniel    300:     int i;
                    301:     CHAR *ret = malloc((len + 1) * sizeof(CHAR));
                    302: 
                    303:     if (ret == NULL) {
                    304:         fprintf(stderr, "malloc of %d byte failed\n",
                    305:                (len + 1) * sizeof(CHAR));
                    306:         return(NULL);
                    307:     }
                    308:     for (i = 0;i < len;i++)
                    309:         ret[i] = (CHAR) cur[i];
                    310:     ret[len] = 0;
                    311:     return(ret);
                    312: }
                    313: 
1.50      daniel    314: /**
                    315:  * xmlCharStrdup:
                    316:  * @cur:  the input char *
                    317:  * @len:  the len of @cur
                    318:  *
                    319:  * a strdup for char's to CHAR's
1.68      daniel    320:  *
                    321:  * Returns a new CHAR * or NULL
1.45      daniel    322:  */
                    323: 
1.55      daniel    324: CHAR *
                    325: xmlCharStrdup(const char *cur) {
1.45      daniel    326:     const char *p = cur;
                    327: 
                    328:     while (*p != '\0') p++;
                    329:     return(xmlCharStrndup(cur, p - cur));
                    330: }
                    331: 
1.50      daniel    332: /**
                    333:  * xmlStrcmp:
                    334:  * @str1:  the first CHAR *
                    335:  * @str2:  the second CHAR *
                    336:  *
                    337:  * a strcmp for CHAR's
1.68      daniel    338:  *
                    339:  * Returns the integer result of the comparison
1.14      veillard  340:  */
                    341: 
1.55      daniel    342: int
                    343: xmlStrcmp(const CHAR *str1, const CHAR *str2) {
1.14      veillard  344:     register int tmp;
                    345: 
                    346:     do {
                    347:         tmp = *str1++ - *str2++;
                    348:        if (tmp != 0) return(tmp);
                    349:     } while ((*str1 != 0) && (*str2 != 0));
                    350:     return (*str1 - *str2);
                    351: }
                    352: 
1.50      daniel    353: /**
                    354:  * xmlStrncmp:
                    355:  * @str1:  the first CHAR *
                    356:  * @str2:  the second CHAR *
                    357:  * @len:  the max comparison length
                    358:  *
                    359:  * a strncmp for CHAR's
1.68      daniel    360:  *
                    361:  * Returns the integer result of the comparison
1.14      veillard  362:  */
                    363: 
1.55      daniel    364: int
                    365: xmlStrncmp(const CHAR *str1, const CHAR *str2, int len) {
1.14      veillard  366:     register int tmp;
                    367: 
                    368:     if (len <= 0) return(0);
                    369:     do {
                    370:         tmp = *str1++ - *str2++;
                    371:        if (tmp != 0) return(tmp);
                    372:        len--;
                    373:         if (len <= 0) return(0);
                    374:     } while ((*str1 != 0) && (*str2 != 0));
                    375:     return (*str1 - *str2);
                    376: }
                    377: 
1.50      daniel    378: /**
                    379:  * xmlStrchr:
                    380:  * @str:  the CHAR * array
                    381:  * @val:  the CHAR to search
                    382:  *
                    383:  * a strchr for CHAR's
1.68      daniel    384:  *
                    385:  * Returns the CHAR * for the first occurence or NULL.
1.14      veillard  386:  */
                    387: 
1.55      daniel    388: CHAR *
                    389: xmlStrchr(const CHAR *str, CHAR val) {
1.14      veillard  390:     while (*str != 0) {
                    391:         if (*str == val) return((CHAR *) str);
                    392:        str++;
                    393:     }
                    394:     return(NULL);
                    395: }
1.28      daniel    396: 
1.50      daniel    397: /**
                    398:  * xmlStrlen:
                    399:  * @str:  the CHAR * array
                    400:  *
                    401:  * lenght of a CHAR's string
1.68      daniel    402:  *
                    403:  * Returns the number of CHAR contained in the ARRAY.
1.45      daniel    404:  */
                    405: 
1.55      daniel    406: int
                    407: xmlStrlen(const CHAR *str) {
1.45      daniel    408:     int len = 0;
                    409: 
                    410:     if (str == NULL) return(0);
                    411:     while (*str != 0) {
                    412:        str++;
                    413:        len++;
                    414:     }
                    415:     return(len);
                    416: }
                    417: 
1.50      daniel    418: /**
                    419:  * xmlStrncat:
1.68      daniel    420:  * @cur:  the original CHAR * array
1.50      daniel    421:  * @add:  the CHAR * array added
                    422:  * @len:  the length of @add
                    423:  *
                    424:  * a strncat for array of CHAR's
1.68      daniel    425:  *
                    426:  * Returns a new CHAR * containing the concatenated string.
1.45      daniel    427:  */
                    428: 
1.55      daniel    429: CHAR *
                    430: xmlStrncat(CHAR *cur, const CHAR *add, int len) {
1.45      daniel    431:     int size;
                    432:     CHAR *ret;
                    433: 
                    434:     if ((add == NULL) || (len == 0))
                    435:         return(cur);
                    436:     if (cur == NULL)
                    437:         return(xmlStrndup(add, len));
                    438: 
                    439:     size = xmlStrlen(cur);
                    440:     ret = realloc(cur, (size + len + 1) * sizeof(CHAR));
                    441:     if (ret == NULL) {
                    442:         fprintf(stderr, "xmlStrncat: realloc of %d byte failed\n",
                    443:                (size + len + 1) * sizeof(CHAR));
                    444:         return(cur);
                    445:     }
                    446:     memcpy(&ret[size], add, len * sizeof(CHAR));
                    447:     ret[size + len] = 0;
                    448:     return(ret);
                    449: }
                    450: 
1.50      daniel    451: /**
                    452:  * xmlStrcat:
1.68      daniel    453:  * @cur:  the original CHAR * array
1.50      daniel    454:  * @add:  the CHAR * array added
                    455:  *
                    456:  * a strcat for array of CHAR's
1.68      daniel    457:  *
                    458:  * Returns a new CHAR * containing the concatenated string.
1.45      daniel    459:  */
1.55      daniel    460: CHAR *
                    461: xmlStrcat(CHAR *cur, const CHAR *add) {
1.45      daniel    462:     const CHAR *p = add;
                    463: 
                    464:     if (add == NULL) return(cur);
                    465:     if (cur == NULL) 
                    466:         return(xmlStrdup(add));
                    467: 
                    468:     while (IS_CHAR(*p)) p++;
                    469:     return(xmlStrncat(cur, add, p - add));
                    470: }
                    471: 
                    472: /************************************************************************
                    473:  *                                                                     *
                    474:  *             Commodity functions, cleanup needed ?                   *
                    475:  *                                                                     *
                    476:  ************************************************************************/
                    477: 
1.50      daniel    478: /**
                    479:  * areBlanks:
                    480:  * @ctxt:  an XML parser context
                    481:  * @str:  a CHAR *
                    482:  * @len:  the size of @str
                    483:  *
1.45      daniel    484:  * Is this a sequence of blank chars that one can ignore ?
1.50      daniel    485:  *
                    486:  * TODO: to be corrected accodingly to DTD information if available
1.68      daniel    487:  *
                    488:  * Returns 1 if ignorable 0 otherwise.
1.45      daniel    489:  */
                    490: 
                    491: static int areBlanks(xmlParserCtxtPtr ctxt, const CHAR *str, int len) {
                    492:     int i;
                    493:     xmlNodePtr lastChild;
                    494: 
                    495:     for (i = 0;i < len;i++)
                    496:         if (!(IS_BLANK(str[i]))) return(0);
                    497: 
                    498:     if (CUR != '<') return(0);
1.72      daniel    499:     if (ctxt->node == NULL) return(0);
1.45      daniel    500:     lastChild = xmlGetLastChild(ctxt->node);
                    501:     if (lastChild == NULL) {
                    502:         if (ctxt->node->content != NULL) return(0);
                    503:     } else if (xmlNodeIsText(lastChild))
                    504:         return(0);
                    505:     return(1);
                    506: }
                    507: 
1.50      daniel    508: /**
                    509:  * xmlHandleEntity:
                    510:  * @ctxt:  an XML parser context
                    511:  * @entity:  an XML entity pointer.
                    512:  *
                    513:  * Default handling of defined entities, when should we define a new input
1.45      daniel    514:  * stream ? When do we just handle that as a set of chars ?
1.50      daniel    515:  * TODO: we should call the SAX handler here and have it resolve the issue
1.45      daniel    516:  */
                    517: 
1.55      daniel    518: void
                    519: xmlHandleEntity(xmlParserCtxtPtr ctxt, xmlEntityPtr entity) {
1.45      daniel    520:     int len;
1.50      daniel    521:     xmlParserInputPtr input;
1.45      daniel    522: 
                    523:     if (entity->content == NULL) {
1.55      daniel    524:         if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74    ! daniel    525:            ctxt->sax->error(ctxt->userData, "xmlHandleEntity %s: content == NULL\n",
1.45      daniel    526:                       entity->name);
1.59      daniel    527:        ctxt->wellFormed = 0;
1.45      daniel    528:         return;
                    529:     }
                    530:     len = xmlStrlen(entity->content);
                    531:     if (len <= 2) goto handle_as_char;
                    532: 
                    533:     /*
                    534:      * Redefine its content as an input stream.
                    535:      */
1.50      daniel    536:     input = xmlNewEntityInputStream(ctxt, entity);
                    537:     xmlPushInput(ctxt, input);
1.45      daniel    538:     return;
                    539: 
                    540: handle_as_char:
                    541:     /*
                    542:      * Just handle the content as a set of chars.
                    543:      */
1.72      daniel    544:     if ((ctxt->sax != NULL) && (ctxt->sax->characters != NULL))
1.74    ! daniel    545:        ctxt->sax->characters(ctxt->userData, entity->content, len);
1.45      daniel    546: 
                    547: }
                    548: 
                    549: /*
                    550:  * Forward definition for recusive behaviour.
                    551:  */
1.50      daniel    552: CHAR *xmlParsePEReference(xmlParserCtxtPtr ctxt);
                    553: CHAR *xmlParseReference(xmlParserCtxtPtr ctxt);
1.45      daniel    554: 
1.28      daniel    555: /************************************************************************
                    556:  *                                                                     *
                    557:  *             Extra stuff for namespace support                       *
                    558:  *     Relates to http://www.w3.org/TR/WD-xml-names                    *
                    559:  *                                                                     *
                    560:  ************************************************************************/
                    561: 
1.50      daniel    562: /**
                    563:  * xmlNamespaceParseNCName:
                    564:  * @ctxt:  an XML parser context
                    565:  *
                    566:  * parse an XML namespace name.
1.28      daniel    567:  *
                    568:  * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
                    569:  *
                    570:  * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
                    571:  *                       CombiningChar | Extender
1.68      daniel    572:  *
                    573:  * Returns the namespace name or NULL
1.28      daniel    574:  */
                    575: 
1.55      daniel    576: CHAR *
                    577: xmlNamespaceParseNCName(xmlParserCtxtPtr ctxt) {
1.28      daniel    578:     const CHAR *q;
                    579:     CHAR *ret = NULL;
                    580: 
1.40      daniel    581:     if (!IS_LETTER(CUR) && (CUR != '_')) return(NULL);
                    582:     q = NEXT;
1.28      daniel    583: 
1.40      daniel    584:     while ((IS_LETTER(CUR)) || (IS_DIGIT(CUR)) ||
                    585:            (CUR == '.') || (CUR == '-') ||
                    586:           (CUR == '_') ||
                    587:           (IS_COMBINING(CUR)) ||
                    588:           (IS_EXTENDER(CUR)))
                    589:        NEXT;
1.28      daniel    590:     
1.40      daniel    591:     ret = xmlStrndup(q, CUR_PTR - q);
1.28      daniel    592: 
                    593:     return(ret);
                    594: }
                    595: 
1.50      daniel    596: /**
                    597:  * xmlNamespaceParseQName:
                    598:  * @ctxt:  an XML parser context
                    599:  * @prefix:  a CHAR ** 
                    600:  *
                    601:  * parse an XML qualified name
1.28      daniel    602:  *
                    603:  * [NS 5] QName ::= (Prefix ':')? LocalPart
                    604:  *
                    605:  * [NS 6] Prefix ::= NCName
                    606:  *
                    607:  * [NS 7] LocalPart ::= NCName
1.68      daniel    608:  *
                    609:  * Returns the function returns the local part, and prefix is updated
1.50      daniel    610:  *   to get the Prefix if any.
1.28      daniel    611:  */
                    612: 
1.55      daniel    613: CHAR *
                    614: xmlNamespaceParseQName(xmlParserCtxtPtr ctxt, CHAR **prefix) {
1.28      daniel    615:     CHAR *ret = NULL;
                    616: 
                    617:     *prefix = NULL;
                    618:     ret = xmlNamespaceParseNCName(ctxt);
1.40      daniel    619:     if (CUR == ':') {
1.28      daniel    620:         *prefix = ret;
1.40      daniel    621:        NEXT;
1.28      daniel    622:        ret = xmlNamespaceParseNCName(ctxt);
                    623:     }
                    624: 
                    625:     return(ret);
                    626: }
                    627: 
1.50      daniel    628: /**
1.72      daniel    629:  * xmlSplitQName:
                    630:  * @name:  an XML parser context
                    631:  * @prefix:  a CHAR ** 
                    632:  *
                    633:  * parse an XML qualified name string
                    634:  *
                    635:  * [NS 5] QName ::= (Prefix ':')? LocalPart
                    636:  *
                    637:  * [NS 6] Prefix ::= NCName
                    638:  *
                    639:  * [NS 7] LocalPart ::= NCName
                    640:  *
                    641:  * Returns the function returns the local part, and prefix is updated
                    642:  *   to get the Prefix if any.
                    643:  */
                    644: 
                    645: CHAR *
                    646: xmlSplitQName(const CHAR *name, CHAR **prefix) {
                    647:     CHAR *ret = NULL;
                    648:     const CHAR *q;
                    649:     const CHAR *cur = name;
                    650: 
                    651:     *prefix = NULL;
                    652:     if (!IS_LETTER(*cur) && (*cur != '_')) return(NULL);
                    653:     q = cur++;
                    654: 
                    655:     while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
                    656:            (*cur == '.') || (*cur == '-') ||
                    657:           (*cur == '_') ||
                    658:           (IS_COMBINING(*cur)) ||
                    659:           (IS_EXTENDER(*cur)))
                    660:        cur++;
                    661:     
                    662:     ret = xmlStrndup(q, cur - q);
                    663: 
                    664:     if (*cur == ':') {
                    665:        cur++;
                    666:        if (!IS_LETTER(*cur) && (*cur != '_')) return(ret);
                    667:         *prefix = ret;
                    668: 
                    669:        q = cur++;
                    670: 
                    671:        while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
                    672:               (*cur == '.') || (*cur == '-') ||
                    673:               (*cur == '_') ||
                    674:               (IS_COMBINING(*cur)) ||
                    675:               (IS_EXTENDER(*cur)))
                    676:            cur++;
                    677:        
                    678:        ret = xmlStrndup(q, cur - q);
                    679:     }
                    680: 
                    681:     return(ret);
                    682: }
                    683: /**
1.50      daniel    684:  * xmlNamespaceParseNSDef:
                    685:  * @ctxt:  an XML parser context
                    686:  *
                    687:  * parse a namespace prefix declaration
1.28      daniel    688:  *
                    689:  * [NS 1] NSDef ::= PrefixDef Eq SystemLiteral
                    690:  *
                    691:  * [NS 2] PrefixDef ::= 'xmlns' (':' NCName)?
1.68      daniel    692:  *
                    693:  * Returns the namespace name
1.28      daniel    694:  */
                    695: 
1.55      daniel    696: CHAR *
                    697: xmlNamespaceParseNSDef(xmlParserCtxtPtr ctxt) {
1.28      daniel    698:     CHAR *name = NULL;
                    699: 
1.40      daniel    700:     if ((CUR == 'x') && (NXT(1) == 'm') &&
                    701:         (NXT(2) == 'l') && (NXT(3) == 'n') &&
                    702:        (NXT(4) == 's')) {
                    703:        SKIP(5);
                    704:        if (CUR == ':') {
                    705:            NEXT;
1.28      daniel    706:            name = xmlNamespaceParseNCName(ctxt);
                    707:        }
                    708:     }
1.39      daniel    709:     return(name);
1.28      daniel    710: }
                    711: 
1.50      daniel    712: /**
                    713:  * xmlParseQuotedString:
                    714:  * @ctxt:  an XML parser context
                    715:  *
1.45      daniel    716:  * [OLD] Parse and return a string between quotes or doublequotes
1.68      daniel    717:  *
                    718:  * Returns the string parser or NULL.
1.45      daniel    719:  */
1.55      daniel    720: CHAR *
                    721: xmlParseQuotedString(xmlParserCtxtPtr ctxt) {
1.45      daniel    722:     CHAR *ret = NULL;
                    723:     const CHAR *q;
                    724: 
                    725:     if (CUR == '"') {
                    726:         NEXT;
                    727:        q = CUR_PTR;
                    728:        while (IS_CHAR(CUR) && (CUR != '"')) NEXT;
1.55      daniel    729:        if (CUR != '"') {
                    730:            if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74    ! daniel    731:                ctxt->sax->error(ctxt->userData, "String not closed \"%.50s\"\n", q);
1.59      daniel    732:            ctxt->wellFormed = 0;
1.55      daniel    733:         } else {
1.45      daniel    734:             ret = xmlStrndup(q, CUR_PTR - q);
                    735:            NEXT;
                    736:        }
                    737:     } else if (CUR == '\''){
                    738:         NEXT;
                    739:        q = CUR_PTR;
                    740:        while (IS_CHAR(CUR) && (CUR != '\'')) NEXT;
1.55      daniel    741:        if (CUR != '\'') {
                    742:            if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74    ! daniel    743:                ctxt->sax->error(ctxt->userData, "String not closed \"%.50s\"\n", q);
1.59      daniel    744:            ctxt->wellFormed = 0;
1.55      daniel    745:         } else {
1.45      daniel    746:             ret = xmlStrndup(q, CUR_PTR - q);
                    747:            NEXT;
                    748:        }
                    749:     }
                    750:     return(ret);
                    751: }
                    752: 
1.50      daniel    753: /**
                    754:  * xmlParseNamespace:
                    755:  * @ctxt:  an XML parser context
                    756:  *
1.45      daniel    757:  * [OLD] xmlParseNamespace: parse specific PI '<?namespace ...' constructs.
                    758:  *
                    759:  * This is what the older xml-name Working Draft specified, a bunch of
                    760:  * other stuff may still rely on it, so support is still here as
                    761:  * if ot was declared on the root of the Tree:-(
                    762:  */
                    763: 
1.55      daniel    764: void
                    765: xmlParseNamespace(xmlParserCtxtPtr ctxt) {
1.45      daniel    766:     CHAR *href = NULL;
                    767:     CHAR *prefix = NULL;
                    768:     int garbage = 0;
                    769: 
                    770:     /*
                    771:      * We just skipped "namespace" or "xml:namespace"
                    772:      */
                    773:     SKIP_BLANKS;
                    774: 
                    775:     while (IS_CHAR(CUR) && (CUR != '>')) {
                    776:        /*
                    777:         * We can have "ns" or "prefix" attributes
                    778:         * Old encoding as 'href' or 'AS' attributes is still supported
                    779:         */
                    780:        if ((CUR == 'n') && (NXT(1) == 's')) {
                    781:            garbage = 0;
                    782:            SKIP(2);
                    783:            SKIP_BLANKS;
                    784: 
                    785:            if (CUR != '=') continue;
                    786:            NEXT;
                    787:            SKIP_BLANKS;
                    788: 
                    789:            href = xmlParseQuotedString(ctxt);
                    790:            SKIP_BLANKS;
                    791:        } else if ((CUR == 'h') && (NXT(1) == 'r') &&
                    792:            (NXT(2) == 'e') && (NXT(3) == 'f')) {
                    793:            garbage = 0;
                    794:            SKIP(4);
                    795:            SKIP_BLANKS;
                    796: 
                    797:            if (CUR != '=') continue;
                    798:            NEXT;
                    799:            SKIP_BLANKS;
                    800: 
                    801:            href = xmlParseQuotedString(ctxt);
                    802:            SKIP_BLANKS;
                    803:        } else if ((CUR == 'p') && (NXT(1) == 'r') &&
                    804:                   (NXT(2) == 'e') && (NXT(3) == 'f') &&
                    805:                   (NXT(4) == 'i') && (NXT(5) == 'x')) {
                    806:            garbage = 0;
                    807:            SKIP(6);
                    808:            SKIP_BLANKS;
                    809: 
                    810:            if (CUR != '=') continue;
                    811:            NEXT;
                    812:            SKIP_BLANKS;
                    813: 
                    814:            prefix = xmlParseQuotedString(ctxt);
                    815:            SKIP_BLANKS;
                    816:        } else if ((CUR == 'A') && (NXT(1) == 'S')) {
                    817:            garbage = 0;
                    818:            SKIP(2);
                    819:            SKIP_BLANKS;
                    820: 
                    821:            if (CUR != '=') continue;
                    822:            NEXT;
                    823:            SKIP_BLANKS;
                    824: 
                    825:            prefix = xmlParseQuotedString(ctxt);
                    826:            SKIP_BLANKS;
                    827:        } else if ((CUR == '?') && (NXT(1) == '>')) {
                    828:            garbage = 0;
                    829:            CUR_PTR ++;
                    830:        } else {
                    831:             /*
                    832:             * Found garbage when parsing the namespace
                    833:             */
                    834:            if (!garbage)
1.55      daniel    835:                if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74    ! daniel    836:                    ctxt->sax->error(ctxt->userData, "xmlParseNamespace found garbage\n");
1.59      daniel    837:            ctxt->wellFormed = 0;
1.45      daniel    838:             NEXT;
                    839:         }
                    840:     }
                    841: 
                    842:     MOVETO_ENDTAG(CUR_PTR);
                    843:     NEXT;
                    844: 
                    845:     /*
                    846:      * Register the DTD.
1.72      daniel    847:     if (href != NULL)
                    848:        if ((ctxt->sax != NULL) && (ctxt->sax->globalNamespace != NULL))
1.74    ! daniel    849:            ctxt->sax->globalNamespace(ctxt->userData, href, prefix);
1.45      daniel    850:      */
                    851: 
                    852:     if (prefix != NULL) free(prefix);
                    853:     if (href != NULL) free(href);
                    854: }
                    855: 
1.28      daniel    856: /************************************************************************
                    857:  *                                                                     *
                    858:  *                     The parser itself                               *
                    859:  *     Relates to http://www.w3.org/TR/REC-xml                         *
                    860:  *                                                                     *
                    861:  ************************************************************************/
1.14      veillard  862: 
1.50      daniel    863: /**
                    864:  * xmlParseName:
                    865:  * @ctxt:  an XML parser context
                    866:  *
                    867:  * parse an XML name.
1.22      daniel    868:  *
                    869:  * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
                    870:  *                  CombiningChar | Extender
                    871:  *
                    872:  * [5] Name ::= (Letter | '_' | ':') (NameChar)*
                    873:  *
                    874:  * [6] Names ::= Name (S Name)*
1.68      daniel    875:  *
                    876:  * Returns the Name parsed or NULL
1.1       veillard  877:  */
                    878: 
1.55      daniel    879: CHAR *
                    880: xmlParseName(xmlParserCtxtPtr ctxt) {
1.17      daniel    881:     const CHAR *q;
                    882:     CHAR *ret = NULL;
1.1       veillard  883: 
1.40      daniel    884:     if (!IS_LETTER(CUR) && (CUR != '_') &&
                    885:         (CUR != ':')) return(NULL);
                    886:     q = NEXT;
                    887: 
                    888:     while ((IS_LETTER(CUR)) || (IS_DIGIT(CUR)) ||
                    889:            (CUR == '.') || (CUR == '-') ||
                    890:           (CUR == '_') || (CUR == ':') || 
                    891:           (IS_COMBINING(CUR)) ||
                    892:           (IS_EXTENDER(CUR)))
                    893:        NEXT;
1.22      daniel    894:     
1.40      daniel    895:     ret = xmlStrndup(q, CUR_PTR - q);
1.22      daniel    896: 
                    897:     return(ret);
                    898: }
                    899: 
1.50      daniel    900: /**
                    901:  * xmlParseNmtoken:
                    902:  * @ctxt:  an XML parser context
                    903:  * 
                    904:  * parse an XML Nmtoken.
1.22      daniel    905:  *
                    906:  * [7] Nmtoken ::= (NameChar)+
                    907:  *
                    908:  * [8] Nmtokens ::= Nmtoken (S Nmtoken)*
1.68      daniel    909:  *
                    910:  * Returns the Nmtoken parsed or NULL
1.22      daniel    911:  */
                    912: 
1.55      daniel    913: CHAR *
                    914: xmlParseNmtoken(xmlParserCtxtPtr ctxt) {
1.22      daniel    915:     const CHAR *q;
                    916:     CHAR *ret = NULL;
                    917: 
1.40      daniel    918:     q = NEXT;
1.22      daniel    919: 
1.40      daniel    920:     while ((IS_LETTER(CUR)) || (IS_DIGIT(CUR)) ||
                    921:            (CUR == '.') || (CUR == '-') ||
                    922:           (CUR == '_') || (CUR == ':') || 
                    923:           (IS_COMBINING(CUR)) ||
                    924:           (IS_EXTENDER(CUR)))
                    925:        NEXT;
1.3       veillard  926:     
1.40      daniel    927:     ret = xmlStrndup(q, CUR_PTR - q);
1.1       veillard  928: 
1.3       veillard  929:     return(ret);
1.1       veillard  930: }
                    931: 
1.50      daniel    932: /**
                    933:  * xmlParseEntityValue:
                    934:  * @ctxt:  an XML parser context
                    935:  *
                    936:  * parse a value for ENTITY decl.
1.24      daniel    937:  *
                    938:  * [9] EntityValue ::= '"' ([^%&"] | PEReference | Reference)* '"' |
                    939:  *                    "'" ([^%&'] | PEReference | Reference)* "'"
1.68      daniel    940:  *
                    941:  * Returns the EntityValue parsed or NULL
1.24      daniel    942:  */
                    943: 
1.55      daniel    944: CHAR *
                    945: xmlParseEntityValue(xmlParserCtxtPtr ctxt) {
1.46      daniel    946:     CHAR *ret = NULL, *cur;
1.24      daniel    947:     const CHAR *q;
                    948: 
1.40      daniel    949:     if (CUR == '"') {
                    950:         NEXT;
1.24      daniel    951: 
1.40      daniel    952:        q = CUR_PTR;
                    953:        while ((IS_CHAR(CUR)) && (CUR != '"')) {
                    954:            if (CUR == '%') {
1.46      daniel    955:                ret = xmlStrncat(ret, q, CUR_PTR - q);
1.50      daniel    956:                cur = xmlParsePEReference(ctxt);
1.46      daniel    957:                ret = xmlStrcat(ret, cur);
                    958:                q = CUR_PTR;
1.40      daniel    959:            } else if (CUR == '&') {
1.46      daniel    960:                ret = xmlStrncat(ret, q, CUR_PTR - q);
1.50      daniel    961:                cur = xmlParseReference(ctxt);
                    962:                if (cur != NULL) {
                    963:                    CHAR buf[2];
                    964:                    buf[0] = '&';
                    965:                    buf[1] = 0;
                    966:                    ret = xmlStrncat(ret, buf, 1);
                    967:                    ret = xmlStrcat(ret, cur);
                    968:                    buf[0] = ';';
                    969:                    buf[1] = 0;
                    970:                    ret = xmlStrncat(ret, buf, 1);
                    971:                }
1.46      daniel    972:                q = CUR_PTR;
1.24      daniel    973:            } else 
1.40      daniel    974:                NEXT;
1.24      daniel    975:        }
1.40      daniel    976:        if (!IS_CHAR(CUR)) {
1.55      daniel    977:            if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74    ! daniel    978:                ctxt->sax->error(ctxt->userData, "Unfinished EntityValue\n");
1.59      daniel    979:            ctxt->wellFormed = 0;
1.24      daniel    980:        } else {
1.46      daniel    981:            ret = xmlStrncat(ret, q, CUR_PTR - q);
1.40      daniel    982:            NEXT;
1.24      daniel    983:         }
1.40      daniel    984:     } else if (CUR == '\'') {
                    985:         NEXT;
                    986:        q = CUR_PTR;
                    987:        while ((IS_CHAR(CUR)) && (CUR != '\'')) {
                    988:            if (CUR == '%') {
1.46      daniel    989:                ret = xmlStrncat(ret, q, CUR_PTR - q);
1.50      daniel    990:                cur = xmlParsePEReference(ctxt);
1.46      daniel    991:                ret = xmlStrcat(ret, cur);
                    992:                q = CUR_PTR;
1.40      daniel    993:            } else if (CUR == '&') {
1.46      daniel    994:                ret = xmlStrncat(ret, q, CUR_PTR - q);
1.50      daniel    995:                cur = xmlParseReference(ctxt);
                    996:                if (cur != NULL) {
                    997:                    CHAR buf[2];
                    998:                    buf[0] = '&';
                    999:                    buf[1] = 0;
                   1000:                    ret = xmlStrncat(ret, buf, 1);
                   1001:                    ret = xmlStrcat(ret, cur);
                   1002:                    buf[0] = ';';
                   1003:                    buf[1] = 0;
                   1004:                    ret = xmlStrncat(ret, buf, 1);
                   1005:                }
1.46      daniel   1006:                q = CUR_PTR;
1.24      daniel   1007:            } else 
1.40      daniel   1008:                NEXT;
1.24      daniel   1009:        }
1.40      daniel   1010:        if (!IS_CHAR(CUR)) {
1.55      daniel   1011:            if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74    ! daniel   1012:                ctxt->sax->error(ctxt->userData, "Unfinished EntityValue\n");
1.59      daniel   1013:            ctxt->wellFormed = 0;
1.24      daniel   1014:        } else {
1.46      daniel   1015:            ret = xmlStrncat(ret, q, CUR_PTR - q);
1.40      daniel   1016:            NEXT;
1.24      daniel   1017:         }
                   1018:     } else {
1.55      daniel   1019:        if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74    ! daniel   1020:            ctxt->sax->error(ctxt->userData, "xmlParseEntityValue \" or ' expected\n");
1.59      daniel   1021:        ctxt->wellFormed = 0;
1.24      daniel   1022:     }
                   1023:     
                   1024:     return(ret);
                   1025: }
                   1026: 
1.50      daniel   1027: /**
                   1028:  * xmlParseAttValue:
                   1029:  * @ctxt:  an XML parser context
                   1030:  *
                   1031:  * parse a value for an attribute
1.29      daniel   1032:  *
                   1033:  * [10] AttValue ::= '"' ([^<&"] | Reference)* '"' |
                   1034:  *                   "'" ([^<&'] | Reference)* "'"
1.68      daniel   1035:  *
                   1036:  * Returns the AttValue parsed or NULL.
1.29      daniel   1037:  */
                   1038: 
1.55      daniel   1039: CHAR *
                   1040: xmlParseAttValue(xmlParserCtxtPtr ctxt) {
1.46      daniel   1041:     CHAR *ret = NULL, *cur;
1.29      daniel   1042:     const CHAR *q;
                   1043: 
1.40      daniel   1044:     if (CUR == '"') {
                   1045:         NEXT;
1.29      daniel   1046: 
1.40      daniel   1047:        q = CUR_PTR;
                   1048:        while ((IS_CHAR(CUR)) && (CUR != '"')) {
1.59      daniel   1049:            if (CUR == '<') {
                   1050:                if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74    ! daniel   1051:                    ctxt->sax->error(ctxt->userData,
1.59      daniel   1052:                       "Unescaped '<' not allowed in attributes values\n");
                   1053:                ctxt->wellFormed = 0;
                   1054:            }
1.40      daniel   1055:            if (CUR == '&') {
1.46      daniel   1056:                ret = xmlStrncat(ret, q, CUR_PTR - q);
1.50      daniel   1057:                cur = xmlParseReference(ctxt);
                   1058:                if (cur != NULL) {
                   1059:                    /*
                   1060:                     * Special case for '&amp;', we don't want to
                   1061:                     * resolve it here since it will break later
                   1062:                     * when searching entities in the string.
                   1063:                     */
                   1064:                    if ((cur[0] == '&') && (cur[1] == 0)) {
                   1065:                        CHAR buf[6] = { '&', 'a', 'm', 'p', ';', 0 };
                   1066:                        ret = xmlStrncat(ret, buf, 5);
                   1067:                    } else
                   1068:                        ret = xmlStrcat(ret, cur);
                   1069:                    free(cur);
                   1070:                }
1.46      daniel   1071:                q = CUR_PTR;
1.29      daniel   1072:            } else 
1.40      daniel   1073:                NEXT;
1.50      daniel   1074:            /*
                   1075:             * Pop out finished entity references.
                   1076:             */
                   1077:            while ((CUR == 0) && (ctxt->inputNr > 1)) {
                   1078:                if (CUR_PTR != q)
                   1079:                    ret = xmlStrncat(ret, q, CUR_PTR - q);
                   1080:                xmlPopInput(ctxt);
                   1081:                q = CUR_PTR;
                   1082:            }
1.29      daniel   1083:        }
1.40      daniel   1084:        if (!IS_CHAR(CUR)) {
1.55      daniel   1085:            if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74    ! daniel   1086:                ctxt->sax->error(ctxt->userData, "Unfinished AttValue\n");
1.59      daniel   1087:            ctxt->wellFormed = 0;
1.29      daniel   1088:        } else {
1.46      daniel   1089:            ret = xmlStrncat(ret, q, CUR_PTR - q);
1.40      daniel   1090:            NEXT;
1.29      daniel   1091:         }
1.40      daniel   1092:     } else if (CUR == '\'') {
                   1093:         NEXT;
                   1094:        q = CUR_PTR;
                   1095:        while ((IS_CHAR(CUR)) && (CUR != '\'')) {
1.59      daniel   1096:            if (CUR == '<') {
                   1097:                if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74    ! daniel   1098:                    ctxt->sax->error(ctxt->userData,
1.59      daniel   1099:                       "Unescaped '<' not allowed in attributes values\n");
                   1100:                ctxt->wellFormed = 0;
                   1101:            }
1.40      daniel   1102:            if (CUR == '&') {
1.46      daniel   1103:                ret = xmlStrncat(ret, q, CUR_PTR - q);
1.50      daniel   1104:                cur = xmlParseReference(ctxt);
                   1105:                if (cur != NULL) {
                   1106:                    /*
                   1107:                     * Special case for '&amp;', we don't want to
                   1108:                     * resolve it here since it will break later
                   1109:                     * when searching entities in the string.
                   1110:                     */
                   1111:                    if ((cur[0] == '&') && (cur[1] == 0)) {
                   1112:                        CHAR buf[6] = { '&', 'a', 'm', 'p', ';', 0 };
                   1113:                        ret = xmlStrncat(ret, buf, 5);
                   1114:                    } else
                   1115:                        ret = xmlStrcat(ret, cur);
                   1116:                    free(cur);
                   1117:                }
1.46      daniel   1118:                q = CUR_PTR;
1.29      daniel   1119:            } else 
1.40      daniel   1120:                NEXT;
1.50      daniel   1121:            /*
                   1122:             * Pop out finished entity references.
                   1123:             */
                   1124:            while ((CUR == 0) && (ctxt->inputNr > 1)) {
                   1125:                if (CUR_PTR != q)
                   1126:                    ret = xmlStrncat(ret, q, CUR_PTR - q);
                   1127:                xmlPopInput(ctxt);
                   1128:                q = CUR_PTR;
                   1129:            }
1.29      daniel   1130:        }
1.40      daniel   1131:        if (!IS_CHAR(CUR)) {
1.55      daniel   1132:            if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74    ! daniel   1133:                ctxt->sax->error(ctxt->userData, "Unfinished AttValue\n");
1.59      daniel   1134:            ctxt->wellFormed = 0;
1.29      daniel   1135:        } else {
1.46      daniel   1136:            ret = xmlStrncat(ret, q, CUR_PTR - q);
1.40      daniel   1137:            NEXT;
1.29      daniel   1138:         }
                   1139:     } else {
1.55      daniel   1140:        if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74    ! daniel   1141:            ctxt->sax->error(ctxt->userData, "AttValue: \" or ' expected\n");
1.59      daniel   1142:        ctxt->wellFormed = 0;
1.29      daniel   1143:     }
                   1144:     
                   1145:     return(ret);
                   1146: }
                   1147: 
1.50      daniel   1148: /**
                   1149:  * xmlParseSystemLiteral:
                   1150:  * @ctxt:  an XML parser context
                   1151:  * 
                   1152:  * parse an XML Literal
1.21      daniel   1153:  *
1.22      daniel   1154:  * [11] SystemLiteral ::= ('"' [^"]* '"') | ("'" [^']* "'")
1.68      daniel   1155:  *
                   1156:  * Returns the SystemLiteral parsed or NULL
1.21      daniel   1157:  */
                   1158: 
1.55      daniel   1159: CHAR *
                   1160: xmlParseSystemLiteral(xmlParserCtxtPtr ctxt) {
1.21      daniel   1161:     const CHAR *q;
                   1162:     CHAR *ret = NULL;
                   1163: 
1.40      daniel   1164:     if (CUR == '"') {
                   1165:         NEXT;
                   1166:        q = CUR_PTR;
                   1167:        while ((IS_CHAR(CUR)) && (CUR != '"'))
                   1168:            NEXT;
                   1169:        if (!IS_CHAR(CUR)) {
1.55      daniel   1170:            if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74    ! daniel   1171:                ctxt->sax->error(ctxt->userData, "Unfinished SystemLiteral\n");
1.59      daniel   1172:            ctxt->wellFormed = 0;
1.21      daniel   1173:        } else {
1.40      daniel   1174:            ret = xmlStrndup(q, CUR_PTR - q);
                   1175:            NEXT;
1.21      daniel   1176:         }
1.40      daniel   1177:     } else if (CUR == '\'') {
                   1178:         NEXT;
                   1179:        q = CUR_PTR;
                   1180:        while ((IS_CHAR(CUR)) && (CUR != '\''))
                   1181:            NEXT;
                   1182:        if (!IS_CHAR(CUR)) {
1.55      daniel   1183:            if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74    ! daniel   1184:                ctxt->sax->error(ctxt->userData, "Unfinished SystemLiteral\n");
1.59      daniel   1185:            ctxt->wellFormed = 0;
1.21      daniel   1186:        } else {
1.40      daniel   1187:            ret = xmlStrndup(q, CUR_PTR - q);
                   1188:            NEXT;
1.21      daniel   1189:         }
                   1190:     } else {
1.55      daniel   1191:        if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74    ! daniel   1192:            ctxt->sax->error(ctxt->userData, "SystemLiteral \" or ' expected\n");
1.59      daniel   1193:        ctxt->wellFormed = 0;
1.21      daniel   1194:     }
                   1195:     
                   1196:     return(ret);
                   1197: }
                   1198: 
1.50      daniel   1199: /**
                   1200:  * xmlParsePubidLiteral:
                   1201:  * @ctxt:  an XML parser context
1.21      daniel   1202:  *
1.50      daniel   1203:  * parse an XML public literal
1.68      daniel   1204:  *
                   1205:  * [12] PubidLiteral ::= '"' PubidChar* '"' | "'" (PubidChar - "'")* "'"
                   1206:  *
                   1207:  * Returns the PubidLiteral parsed or NULL.
1.21      daniel   1208:  */
                   1209: 
1.55      daniel   1210: CHAR *
                   1211: xmlParsePubidLiteral(xmlParserCtxtPtr ctxt) {
1.21      daniel   1212:     const CHAR *q;
                   1213:     CHAR *ret = NULL;
                   1214:     /*
                   1215:      * Name ::= (Letter | '_') (NameChar)*
                   1216:      */
1.40      daniel   1217:     if (CUR == '"') {
                   1218:         NEXT;
                   1219:        q = CUR_PTR;
                   1220:        while (IS_PUBIDCHAR(CUR)) NEXT;
                   1221:        if (CUR != '"') {
1.55      daniel   1222:            if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74    ! daniel   1223:                ctxt->sax->error(ctxt->userData, "Unfinished PubidLiteral\n");
1.59      daniel   1224:            ctxt->wellFormed = 0;
1.21      daniel   1225:        } else {
1.40      daniel   1226:            ret = xmlStrndup(q, CUR_PTR - q);
                   1227:            NEXT;
1.21      daniel   1228:        }
1.40      daniel   1229:     } else if (CUR == '\'') {
                   1230:         NEXT;
                   1231:        q = CUR_PTR;
                   1232:        while ((IS_LETTER(CUR)) && (CUR != '\''))
                   1233:            NEXT;
                   1234:        if (!IS_LETTER(CUR)) {
1.55      daniel   1235:            if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74    ! daniel   1236:                ctxt->sax->error(ctxt->userData, "Unfinished PubidLiteral\n");
1.59      daniel   1237:            ctxt->wellFormed = 0;
1.21      daniel   1238:        } else {
1.40      daniel   1239:            ret = xmlStrndup(q, CUR_PTR - q);
                   1240:            NEXT;
1.21      daniel   1241:        }
                   1242:     } else {
1.55      daniel   1243:        if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74    ! daniel   1244:            ctxt->sax->error(ctxt->userData, "SystemLiteral \" or ' expected\n");
1.59      daniel   1245:        ctxt->wellFormed = 0;
1.21      daniel   1246:     }
                   1247:     
                   1248:     return(ret);
                   1249: }
                   1250: 
1.50      daniel   1251: /**
                   1252:  * xmlParseCharData:
                   1253:  * @ctxt:  an XML parser context
                   1254:  * @cdata:  int indicating whether we are within a CDATA section
                   1255:  *
                   1256:  * parse a CharData section.
                   1257:  * if we are within a CDATA section ']]>' marks an end of section.
1.27      daniel   1258:  *
                   1259:  * [14] CharData ::= [^<&]* - ([^<&]* ']]>' [^<&]*)
                   1260:  */
                   1261: 
1.55      daniel   1262: void
                   1263: xmlParseCharData(xmlParserCtxtPtr ctxt, int cdata) {
1.27      daniel   1264:     const CHAR *q;
                   1265: 
1.40      daniel   1266:     q = CUR_PTR;
                   1267:     while ((IS_CHAR(CUR)) && (CUR != '<') &&
                   1268:            (CUR != '&')) {
1.59      daniel   1269:        if ((CUR == ']') && (NXT(1) == ']') &&
                   1270:            (NXT(2) == '>')) {
                   1271:            if (cdata) break;
                   1272:            else {
                   1273:                if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74    ! daniel   1274:                    ctxt->sax->error(ctxt->userData,
1.59      daniel   1275:                       "Sequence ']]>' not allowed in content\n");
                   1276:                ctxt->wellFormed = 0;
                   1277:            }
                   1278:        }
1.40      daniel   1279:         NEXT;
1.27      daniel   1280:     }
1.45      daniel   1281:     if (q == CUR_PTR) return;
                   1282: 
                   1283:     /*
                   1284:      * Ok the segment [q CUR_PTR] is to be consumed as chars.
                   1285:      */
                   1286:     if (ctxt->sax != NULL) {
1.72      daniel   1287:        if (areBlanks(ctxt, q, CUR_PTR - q)) {
                   1288:            if (ctxt->sax->ignorableWhitespace != NULL)
1.74    ! daniel   1289:                ctxt->sax->ignorableWhitespace(ctxt->userData, q, CUR_PTR - q);
1.72      daniel   1290:        } else {
                   1291:            if (ctxt->sax->characters != NULL)
1.74    ! daniel   1292:                ctxt->sax->characters(ctxt->userData, q, CUR_PTR - q);
1.72      daniel   1293:         }
1.45      daniel   1294:     }
1.27      daniel   1295: }
                   1296: 
1.50      daniel   1297: /**
                   1298:  * xmlParseExternalID:
                   1299:  * @ctxt:  an XML parser context
                   1300:  * @publicID:  a CHAR** receiving PubidLiteral
1.67      daniel   1301:  * @strict: indicate whether we should restrict parsing to only
                   1302:  *          production [75], see NOTE below
1.50      daniel   1303:  *
1.67      daniel   1304:  * Parse an External ID or a Public ID
                   1305:  *
                   1306:  * NOTE: Productions [75] and [83] interract badly since [75] can generate
                   1307:  *       'PUBLIC' S PubidLiteral S SystemLiteral
1.22      daniel   1308:  *
                   1309:  * [75] ExternalID ::= 'SYSTEM' S SystemLiteral
                   1310:  *                   | 'PUBLIC' S PubidLiteral S SystemLiteral
1.67      daniel   1311:  *
                   1312:  * [83] PublicID ::= 'PUBLIC' S PubidLiteral
                   1313:  *
1.68      daniel   1314:  * Returns the function returns SystemLiteral and in the second
1.67      daniel   1315:  *                case publicID receives PubidLiteral, is strict is off
                   1316:  *                it is possible to return NULL and have publicID set.
1.22      daniel   1317:  */
                   1318: 
1.55      daniel   1319: CHAR *
1.67      daniel   1320: xmlParseExternalID(xmlParserCtxtPtr ctxt, CHAR **publicID, int strict) {
1.39      daniel   1321:     CHAR *URI = NULL;
1.22      daniel   1322: 
1.40      daniel   1323:     if ((CUR == 'S') && (NXT(1) == 'Y') &&
                   1324:          (NXT(2) == 'S') && (NXT(3) == 'T') &&
                   1325:         (NXT(4) == 'E') && (NXT(5) == 'M')) {
                   1326:         SKIP(6);
1.59      daniel   1327:        if (!IS_BLANK(CUR)) {
                   1328:            if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74    ! daniel   1329:                ctxt->sax->error(ctxt->userData,
1.59      daniel   1330:                    "Space required after 'SYSTEM'\n");
                   1331:            ctxt->wellFormed = 0;
                   1332:        }
1.42      daniel   1333:         SKIP_BLANKS;
1.39      daniel   1334:        URI = xmlParseSystemLiteral(ctxt);
1.59      daniel   1335:        if (URI == NULL) {
1.55      daniel   1336:            if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74    ! daniel   1337:                ctxt->sax->error(ctxt->userData,
1.39      daniel   1338:                  "xmlParseExternalID: SYSTEM, no URI\n");
1.59      daniel   1339:            ctxt->wellFormed = 0;
                   1340:         }
1.40      daniel   1341:     } else if ((CUR == 'P') && (NXT(1) == 'U') &&
                   1342:               (NXT(2) == 'B') && (NXT(3) == 'L') &&
                   1343:               (NXT(4) == 'I') && (NXT(5) == 'C')) {
                   1344:         SKIP(6);
1.59      daniel   1345:        if (!IS_BLANK(CUR)) {
                   1346:            if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74    ! daniel   1347:                ctxt->sax->error(ctxt->userData,
1.59      daniel   1348:                    "Space required after 'PUBLIC'\n");
                   1349:            ctxt->wellFormed = 0;
                   1350:        }
1.42      daniel   1351:         SKIP_BLANKS;
1.39      daniel   1352:        *publicID = xmlParsePubidLiteral(ctxt);
1.59      daniel   1353:        if (*publicID == NULL) {
1.55      daniel   1354:            if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74    ! daniel   1355:                ctxt->sax->error(ctxt->userData, 
1.39      daniel   1356:                  "xmlParseExternalID: PUBLIC, no Public Identifier\n");
1.59      daniel   1357:            ctxt->wellFormed = 0;
                   1358:        }
1.67      daniel   1359:        if (strict) {
                   1360:            /*
                   1361:             * We don't handle [83] so "S SystemLiteral" is required.
                   1362:             */
                   1363:            if (!IS_BLANK(CUR)) {
                   1364:                if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74    ! daniel   1365:                    ctxt->sax->error(ctxt->userData,
1.67      daniel   1366:                        "Space required after the Public Identifier\n");
                   1367:                ctxt->wellFormed = 0;
                   1368:            }
                   1369:        } else {
                   1370:            /*
                   1371:             * We handle [83] so we return immediately, if 
                   1372:             * "S SystemLiteral" is not detected. From a purely parsing
                   1373:             * point of view that's a nice mess.
                   1374:             */
                   1375:            const CHAR *ptr = CUR_PTR;
                   1376:            if (!IS_BLANK(*ptr)) return(NULL);
                   1377:            
                   1378:            while (IS_BLANK(*ptr)) ptr++;
                   1379:            if ((*ptr != '\'') || (*ptr != '"')) return(NULL);
1.59      daniel   1380:        }
1.42      daniel   1381:         SKIP_BLANKS;
1.39      daniel   1382:        URI = xmlParseSystemLiteral(ctxt);
1.59      daniel   1383:        if (URI == NULL) {
1.55      daniel   1384:            if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74    ! daniel   1385:                ctxt->sax->error(ctxt->userData, 
1.39      daniel   1386:                   "xmlParseExternalID: PUBLIC, no URI\n");
1.59      daniel   1387:            ctxt->wellFormed = 0;
                   1388:         }
1.22      daniel   1389:     }
1.39      daniel   1390:     return(URI);
1.22      daniel   1391: }
                   1392: 
1.50      daniel   1393: /**
                   1394:  * xmlParseComment:
1.69      daniel   1395:  * @ctxt:  an XML parser context
                   1396:  * @create: should we create a node, or just skip the content
1.50      daniel   1397:  *
1.3       veillard 1398:  * Skip an XML (SGML) comment <!-- .... -->
1.31      daniel   1399:  *  This may or may not create a node (depending on the context)
1.38      daniel   1400:  *  The spec says that "For compatibility, the string "--" (double-hyphen)
                   1401:  *  must not occur within comments. "
1.22      daniel   1402:  *
                   1403:  * [15] Comment ::= '<!--' ((Char - '-') | ('-' (Char - '-')))* '-->'
1.3       veillard 1404:  */
1.72      daniel   1405: void
1.69      daniel   1406: xmlParseComment(xmlParserCtxtPtr ctxt, int create) {
1.17      daniel   1407:     const CHAR *q, *start;
                   1408:     const CHAR *r;
1.39      daniel   1409:     CHAR *val;
1.3       veillard 1410: 
                   1411:     /*
1.22      daniel   1412:      * Check that there is a comment right here.
1.3       veillard 1413:      */
1.40      daniel   1414:     if ((CUR != '<') || (NXT(1) != '!') ||
1.72      daniel   1415:         (NXT(2) != '-') || (NXT(3) != '-')) return;
1.3       veillard 1416: 
1.40      daniel   1417:     SKIP(4);
                   1418:     start = q = CUR_PTR;
                   1419:     NEXT;
                   1420:     r = CUR_PTR;
                   1421:     NEXT;
                   1422:     while (IS_CHAR(CUR) &&
                   1423:            ((CUR == ':') || (CUR != '>') ||
1.16      daniel   1424:            (*r != '-') || (*q != '-'))) {
1.59      daniel   1425:        if ((*r == '-') && (*q == '-')) {
1.55      daniel   1426:            if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74    ! daniel   1427:                ctxt->sax->error(ctxt->userData,
1.38      daniel   1428:               "Comment must not contain '--' (double-hyphen)`\n");
1.59      daniel   1429:            ctxt->wellFormed = 0;
                   1430:        }
1.40      daniel   1431:         NEXT;r++;q++;
1.3       veillard 1432:     }
1.40      daniel   1433:     if (!IS_CHAR(CUR)) {
1.55      daniel   1434:        if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74    ! daniel   1435:            ctxt->sax->error(ctxt->userData, "Comment not terminated \n<!--%.50s\n", start);
1.59      daniel   1436:        ctxt->wellFormed = 0;
1.3       veillard 1437:     } else {
1.40      daniel   1438:         NEXT;
1.31      daniel   1439:        if (create) {
1.39      daniel   1440:            val = xmlStrndup(start, q - start);
1.72      daniel   1441:            if ((ctxt->sax != NULL) && (ctxt->sax->comment != NULL))
1.74    ! daniel   1442:                ctxt->sax->comment(ctxt->userData, val);
1.39      daniel   1443:            free(val);
1.31      daniel   1444:        }
1.3       veillard 1445:     }
                   1446: }
                   1447: 
1.50      daniel   1448: /**
                   1449:  * xmlParsePITarget:
                   1450:  * @ctxt:  an XML parser context
                   1451:  * 
                   1452:  * parse the name of a PI
1.22      daniel   1453:  *
                   1454:  * [17] PITarget ::= Name - (('X' | 'x') ('M' | 'm') ('L' | 'l'))
1.68      daniel   1455:  *
                   1456:  * Returns the PITarget name or NULL
1.22      daniel   1457:  */
                   1458: 
1.55      daniel   1459: CHAR *
                   1460: xmlParsePITarget(xmlParserCtxtPtr ctxt) {
1.22      daniel   1461:     CHAR *name;
                   1462: 
                   1463:     name = xmlParseName(ctxt);
                   1464:     if ((name != NULL) && (name[3] == 0) &&
                   1465:         ((name[0] == 'x') || (name[0] == 'X')) &&
1.31      daniel   1466:         ((name[1] == 'm') || (name[1] == 'M')) &&
                   1467:         ((name[2] == 'l') || (name[2] == 'L'))) {
1.55      daniel   1468:        if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74    ! daniel   1469:            ctxt->sax->error(ctxt->userData, "xmlParsePItarget: invalid name prefix 'xml'\n");
1.22      daniel   1470:        return(NULL);
                   1471:     }
                   1472:     return(name);
                   1473: }
                   1474: 
1.50      daniel   1475: /**
                   1476:  * xmlParsePI:
                   1477:  * @ctxt:  an XML parser context
                   1478:  * 
                   1479:  * parse an XML Processing Instruction.
1.22      daniel   1480:  *
                   1481:  * [16] PI ::= '<?' PITarget (S (Char* - (Char* '?>' Char*)))? '?>'
1.68      daniel   1482:  *
1.69      daniel   1483:  * The processing is transfered to SAX once parsed.
1.3       veillard 1484:  */
                   1485: 
1.55      daniel   1486: void
                   1487: xmlParsePI(xmlParserCtxtPtr ctxt) {
1.22      daniel   1488:     CHAR *target;
                   1489: 
1.40      daniel   1490:     if ((CUR == '<') && (NXT(1) == '?')) {
1.3       veillard 1491:        /*
                   1492:         * this is a Processing Instruction.
                   1493:         */
1.40      daniel   1494:        SKIP(2);
1.3       veillard 1495: 
                   1496:        /*
1.22      daniel   1497:         * Parse the target name and check for special support like
                   1498:         * namespace.
                   1499:         *
                   1500:         * TODO : PI handling should be dynamically redefinable using an
                   1501:         *        API. Only namespace should be in the code IMHO ...
1.3       veillard 1502:         */
1.22      daniel   1503:         target = xmlParsePITarget(ctxt);
                   1504:        if (target != NULL) {
1.72      daniel   1505:            const CHAR *q = CUR_PTR;
                   1506: 
                   1507:            while (IS_CHAR(CUR) &&
                   1508:                   ((CUR != '?') || (NXT(1) != '>')))
                   1509:                NEXT;
                   1510:            if (!IS_CHAR(CUR)) {
                   1511:                if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74    ! daniel   1512:                    ctxt->sax->error(ctxt->userData,
1.72      daniel   1513:                      "xmlParsePI: PI %s never end ...\n", target);
                   1514:                ctxt->wellFormed = 0;
1.22      daniel   1515:            } else {
1.72      daniel   1516:                CHAR *data;
1.44      daniel   1517: 
1.72      daniel   1518:                data = xmlStrndup(q, CUR_PTR - q);
                   1519:                SKIP(2);
1.44      daniel   1520: 
1.72      daniel   1521:                /*
                   1522:                 * SAX: PI detected.
                   1523:                 */
                   1524:                if ((ctxt->sax) &&
                   1525:                    (ctxt->sax->processingInstruction != NULL))
1.74    ! daniel   1526:                    ctxt->sax->processingInstruction(ctxt->userData, target, data);
1.72      daniel   1527:                free(data);
1.22      daniel   1528:            }
1.39      daniel   1529:            free(target);
1.3       veillard 1530:        } else {
1.55      daniel   1531:            if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74    ! daniel   1532:                ctxt->sax->error(ctxt->userData, "xmlParsePI : no target name\n");
1.59      daniel   1533:            ctxt->wellFormed = 0;
                   1534: 
1.22      daniel   1535:            /********* Should we try to complete parsing the PI ???
1.40      daniel   1536:            while (IS_CHAR(CUR) &&
                   1537:                   (CUR != '?') && (CUR != '>'))
                   1538:                NEXT;
                   1539:            if (!IS_CHAR(CUR)) {
1.22      daniel   1540:                fprintf(stderr, "xmlParsePI: PI %s never end ...\n",
                   1541:                        target);
                   1542:            }
                   1543:             ********************************************************/
                   1544:        }
                   1545:     }
                   1546: }
                   1547: 
1.50      daniel   1548: /**
                   1549:  * xmlParseNotationDecl:
                   1550:  * @ctxt:  an XML parser context
                   1551:  *
                   1552:  * parse a notation declaration
1.22      daniel   1553:  *
                   1554:  * [82] NotationDecl ::= '<!NOTATION' S Name S (ExternalID |  PublicID) S? '>'
                   1555:  *
                   1556:  * Hence there is actually 3 choices:
                   1557:  *     'PUBLIC' S PubidLiteral
                   1558:  *     'PUBLIC' S PubidLiteral S SystemLiteral
                   1559:  * and 'SYSTEM' S SystemLiteral
1.50      daniel   1560:  *
1.67      daniel   1561:  * See the NOTE on xmlParseExternalID().
1.22      daniel   1562:  */
                   1563: 
1.55      daniel   1564: void
                   1565: xmlParseNotationDecl(xmlParserCtxtPtr ctxt) {
1.22      daniel   1566:     CHAR *name;
1.67      daniel   1567:     CHAR *Pubid;
                   1568:     CHAR *Systemid;
1.22      daniel   1569:     
1.40      daniel   1570:     if ((CUR == '<') && (NXT(1) == '!') &&
                   1571:         (NXT(2) == 'N') && (NXT(3) == 'O') &&
                   1572:         (NXT(4) == 'T') && (NXT(5) == 'A') &&
                   1573:         (NXT(6) == 'T') && (NXT(7) == 'I') &&
1.67      daniel   1574:         (NXT(8) == 'O') && (NXT(9) == 'N')) {
1.40      daniel   1575:        SKIP(10);
1.67      daniel   1576:        if (!IS_BLANK(CUR)) {
                   1577:            if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74    ! daniel   1578:                ctxt->sax->error(ctxt->userData, "Space required after '<!NOTATION'\n");
1.67      daniel   1579:            ctxt->wellFormed = 0;
                   1580:            return;
                   1581:        }
                   1582:        SKIP_BLANKS;
1.22      daniel   1583: 
                   1584:         name = xmlParseName(ctxt);
                   1585:        if (name == NULL) {
1.55      daniel   1586:            if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74    ! daniel   1587:                ctxt->sax->error(ctxt->userData, "NOTATION: Name expected here\n");
1.67      daniel   1588:            ctxt->wellFormed = 0;
                   1589:            return;
                   1590:        }
                   1591:        if (!IS_BLANK(CUR)) {
                   1592:            if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74    ! daniel   1593:                ctxt->sax->error(ctxt->userData, 
1.67      daniel   1594:                     "Space required after the NOTATION name'\n");
1.59      daniel   1595:            ctxt->wellFormed = 0;
1.22      daniel   1596:            return;
                   1597:        }
1.42      daniel   1598:        SKIP_BLANKS;
1.67      daniel   1599: 
1.22      daniel   1600:        /*
1.67      daniel   1601:         * Parse the IDs.
1.22      daniel   1602:         */
1.67      daniel   1603:        Systemid = xmlParseExternalID(ctxt, &Pubid, 1);
                   1604:        SKIP_BLANKS;
                   1605: 
                   1606:        if (CUR == '>') {
1.40      daniel   1607:            NEXT;
1.72      daniel   1608:            if ((ctxt->sax != NULL) && (ctxt->sax->notationDecl != NULL))
1.74    ! daniel   1609:                ctxt->sax->notationDecl(ctxt->userData, name, Pubid, Systemid);
1.67      daniel   1610:        } else {
                   1611:            if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74    ! daniel   1612:                ctxt->sax->error(ctxt->userData,
1.67      daniel   1613:                       "'>' required to close NOTATION declaration\n");
                   1614:            ctxt->wellFormed = 0;
                   1615:        }
1.22      daniel   1616:        free(name);
1.67      daniel   1617:        if (Systemid != NULL) free(Systemid);
                   1618:        if (Pubid != NULL) free(Pubid);
1.22      daniel   1619:     }
                   1620: }
                   1621: 
1.50      daniel   1622: /**
                   1623:  * xmlParseEntityDecl:
                   1624:  * @ctxt:  an XML parser context
                   1625:  *
                   1626:  * parse <!ENTITY declarations
1.22      daniel   1627:  *
                   1628:  * [70] EntityDecl ::= GEDecl | PEDecl
                   1629:  *
                   1630:  * [71] GEDecl ::= '<!ENTITY' S Name S EntityDef S? '>'
                   1631:  *
                   1632:  * [72] PEDecl ::= '<!ENTITY' S '%' S Name S PEDef S? '>'
                   1633:  *
                   1634:  * [73] EntityDef ::= EntityValue | (ExternalID NDataDecl?)
                   1635:  *
                   1636:  * [74] PEDef ::= EntityValue | ExternalID
1.24      daniel   1637:  *
                   1638:  * [76] NDataDecl ::= S 'NDATA' S Name
1.22      daniel   1639:  */
                   1640: 
1.55      daniel   1641: void
                   1642: xmlParseEntityDecl(xmlParserCtxtPtr ctxt) {
1.39      daniel   1643:     CHAR *name = NULL;
1.24      daniel   1644:     CHAR *value = NULL;
1.39      daniel   1645:     CHAR *URI = NULL, *literal = NULL;
1.24      daniel   1646:     CHAR *ndata = NULL;
1.39      daniel   1647:     int isParameter = 0;
1.22      daniel   1648:     
1.40      daniel   1649:     if ((CUR == '<') && (NXT(1) == '!') &&
                   1650:         (NXT(2) == 'E') && (NXT(3) == 'N') &&
                   1651:         (NXT(4) == 'T') && (NXT(5) == 'I') &&
1.59      daniel   1652:         (NXT(6) == 'T') && (NXT(7) == 'Y')) {
1.40      daniel   1653:        SKIP(8);
1.59      daniel   1654:        if (!IS_BLANK(CUR)) {
                   1655:            if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74    ! daniel   1656:                ctxt->sax->error(ctxt->userData, "Space required after '<!ENTITY'\n");
1.59      daniel   1657:            ctxt->wellFormed = 0;
                   1658:        }
                   1659:        SKIP_BLANKS;
1.40      daniel   1660: 
                   1661:        if (CUR == '%') {
                   1662:            NEXT;
1.59      daniel   1663:            if (!IS_BLANK(CUR)) {
                   1664:                if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74    ! daniel   1665:                    ctxt->sax->error(ctxt->userData, "Space required after '%'\n");
1.59      daniel   1666:                ctxt->wellFormed = 0;
                   1667:            }
1.42      daniel   1668:            SKIP_BLANKS;
1.39      daniel   1669:            isParameter = 1;
1.22      daniel   1670:        }
                   1671: 
                   1672:         name = xmlParseName(ctxt);
1.24      daniel   1673:        if (name == NULL) {
1.55      daniel   1674:            if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74    ! daniel   1675:                ctxt->sax->error(ctxt->userData, "xmlParseEntityDecl: no name\n");
1.59      daniel   1676:            ctxt->wellFormed = 0;
1.24      daniel   1677:             return;
                   1678:        }
1.59      daniel   1679:        if (!IS_BLANK(CUR)) {
                   1680:            if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74    ! daniel   1681:                ctxt->sax->error(ctxt->userData,
1.59      daniel   1682:                     "Space required after the entity name\n");
                   1683:            ctxt->wellFormed = 0;
                   1684:        }
1.42      daniel   1685:         SKIP_BLANKS;
1.24      daniel   1686: 
1.22      daniel   1687:        /*
1.68      daniel   1688:         * handle the various case of definitions...
1.22      daniel   1689:         */
1.39      daniel   1690:        if (isParameter) {
1.40      daniel   1691:            if ((CUR == '"') || (CUR == '\''))
1.24      daniel   1692:                value = xmlParseEntityValue(ctxt);
1.39      daniel   1693:                if (value) {
1.72      daniel   1694:                    if ((ctxt->sax != NULL) && (ctxt->sax->entityDecl != NULL))
1.74    ! daniel   1695:                        ctxt->sax->entityDecl(ctxt->userData, name,
1.39      daniel   1696:                                    XML_INTERNAL_PARAMETER_ENTITY,
                   1697:                                    NULL, NULL, value);
                   1698:                }
1.24      daniel   1699:            else {
1.67      daniel   1700:                URI = xmlParseExternalID(ctxt, &literal, 1);
1.39      daniel   1701:                if (URI) {
1.72      daniel   1702:                    if ((ctxt->sax != NULL) && (ctxt->sax->entityDecl != NULL))
1.74    ! daniel   1703:                        ctxt->sax->entityDecl(ctxt->userData, name,
1.39      daniel   1704:                                    XML_EXTERNAL_PARAMETER_ENTITY,
                   1705:                                    literal, URI, NULL);
                   1706:                }
1.24      daniel   1707:            }
                   1708:        } else {
1.40      daniel   1709:            if ((CUR == '"') || (CUR == '\'')) {
1.24      daniel   1710:                value = xmlParseEntityValue(ctxt);
1.72      daniel   1711:                if ((ctxt->sax != NULL) && (ctxt->sax->entityDecl != NULL))
1.74    ! daniel   1712:                    ctxt->sax->entityDecl(ctxt->userData, name,
1.39      daniel   1713:                                XML_INTERNAL_GENERAL_ENTITY,
                   1714:                                NULL, NULL, value);
                   1715:            } else {
1.67      daniel   1716:                URI = xmlParseExternalID(ctxt, &literal, 1);
1.59      daniel   1717:                if ((CUR != '>') && (!IS_BLANK(CUR))) {
                   1718:                    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74    ! daniel   1719:                        ctxt->sax->error(ctxt->userData,
1.59      daniel   1720:                            "Space required before 'NDATA'\n");
                   1721:                    ctxt->wellFormed = 0;
                   1722:                }
1.42      daniel   1723:                SKIP_BLANKS;
1.40      daniel   1724:                if ((CUR == 'N') && (NXT(1) == 'D') &&
                   1725:                    (NXT(2) == 'A') && (NXT(3) == 'T') &&
                   1726:                    (NXT(4) == 'A')) {
                   1727:                    SKIP(5);
1.59      daniel   1728:                    if (!IS_BLANK(CUR)) {
                   1729:                        if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74    ! daniel   1730:                            ctxt->sax->error(ctxt->userData,
1.59      daniel   1731:                                "Space required after 'NDATA'\n");
                   1732:                        ctxt->wellFormed = 0;
                   1733:                    }
1.42      daniel   1734:                    SKIP_BLANKS;
1.24      daniel   1735:                    ndata = xmlParseName(ctxt);
1.72      daniel   1736:                    if ((ctxt->sax != NULL) && (ctxt->sax->entityDecl != NULL))
1.74    ! daniel   1737:                        ctxt->sax->entityDecl(ctxt->userData, name,
1.39      daniel   1738:                                    XML_EXTERNAL_GENERAL_UNPARSED_ENTITY,
                   1739:                                    literal, URI, ndata);
                   1740:                } else {
1.72      daniel   1741:                    if ((ctxt->sax != NULL) && (ctxt->sax->entityDecl != NULL))
1.74    ! daniel   1742:                        ctxt->sax->entityDecl(ctxt->userData, name,
1.39      daniel   1743:                                    XML_EXTERNAL_GENERAL_PARSED_ENTITY,
                   1744:                                    literal, URI, NULL);
1.24      daniel   1745:                }
                   1746:            }
                   1747:        }
1.42      daniel   1748:        SKIP_BLANKS;
1.40      daniel   1749:        if (CUR != '>') {
1.55      daniel   1750:            if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74    ! daniel   1751:                ctxt->sax->error(ctxt->userData, 
1.31      daniel   1752:                    "xmlParseEntityDecl: entity %s not terminated\n", name);
1.59      daniel   1753:            ctxt->wellFormed = 0;
1.24      daniel   1754:        } else
1.40      daniel   1755:            NEXT;
1.39      daniel   1756:        if (name != NULL) free(name);
                   1757:        if (value != NULL) free(value);
                   1758:        if (URI != NULL) free(URI);
                   1759:        if (literal != NULL) free(literal);
                   1760:        if (ndata != NULL) free(ndata);
1.22      daniel   1761:     }
                   1762: }
                   1763: 
1.50      daniel   1764: /**
1.59      daniel   1765:  * xmlParseDefaultDecl:
                   1766:  * @ctxt:  an XML parser context
                   1767:  * @value:  Receive a possible fixed default value for the attribute
                   1768:  *
                   1769:  * Parse an attribute default declaration
                   1770:  *
                   1771:  * [60] DefaultDecl ::= '#REQUIRED' | '#IMPLIED' | (('#FIXED' S)? AttValue)
                   1772:  *
                   1773:  * returns: XML_ATTRIBUTE_NONE, XML_ATTRIBUTE_REQUIRED, XML_ATTRIBUTE_IMPLIED
                   1774:  *          or XML_ATTRIBUTE_FIXED. 
                   1775:  */
                   1776: 
                   1777: int
                   1778: xmlParseDefaultDecl(xmlParserCtxtPtr ctxt, CHAR **value) {
                   1779:     int val;
                   1780:     CHAR *ret;
                   1781: 
                   1782:     *value = NULL;
                   1783:     if ((CUR == '#') && (NXT(1) == 'R') &&
                   1784:         (NXT(2) == 'E') && (NXT(3) == 'Q') &&
                   1785:         (NXT(4) == 'U') && (NXT(5) == 'I') &&
                   1786:         (NXT(6) == 'R') && (NXT(7) == 'E') &&
                   1787:         (NXT(8) == 'D')) {
                   1788:        SKIP(9);
                   1789:        return(XML_ATTRIBUTE_REQUIRED);
                   1790:     }
                   1791:     if ((CUR == '#') && (NXT(1) == 'I') &&
                   1792:         (NXT(2) == 'M') && (NXT(3) == 'P') &&
                   1793:         (NXT(4) == 'L') && (NXT(5) == 'I') &&
                   1794:         (NXT(6) == 'E') && (NXT(7) == 'D')) {
                   1795:        SKIP(8);
                   1796:        return(XML_ATTRIBUTE_IMPLIED);
                   1797:     }
                   1798:     val = XML_ATTRIBUTE_NONE;
                   1799:     if ((CUR == '#') && (NXT(1) == 'F') &&
                   1800:         (NXT(2) == 'I') && (NXT(3) == 'X') &&
                   1801:         (NXT(4) == 'E') && (NXT(5) == 'D')) {
                   1802:        SKIP(6);
                   1803:        val = XML_ATTRIBUTE_FIXED;
                   1804:        if (!IS_BLANK(CUR)) {
                   1805:            if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74    ! daniel   1806:                ctxt->sax->error(ctxt->userData, "Space required after '#FIXED'\n");
1.59      daniel   1807:            ctxt->wellFormed = 0;
                   1808:        }
                   1809:        SKIP_BLANKS;
                   1810:     }
                   1811:     ret = xmlParseAttValue(ctxt);
                   1812:     if (ret == NULL) {
                   1813:        if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74    ! daniel   1814:            ctxt->sax->error(ctxt->userData,
1.59      daniel   1815:               "Attribute default value declaration error\n");
                   1816:        ctxt->wellFormed = 0;
                   1817:     } else
                   1818:         *value = ret;
                   1819:     return(val);
                   1820: }
                   1821: 
                   1822: /**
1.66      daniel   1823:  * xmlParseNotationType:
                   1824:  * @ctxt:  an XML parser context
                   1825:  *
                   1826:  * parse an Notation attribute type.
                   1827:  *
                   1828:  * [58] NotationType ::= 'NOTATION' S '(' S? Name (S? '|' S? Name)* S? ')'
                   1829:  *
                   1830:  * Note: the leading 'NOTATION' S part has already being parsed...
                   1831:  *
                   1832:  * Returns: the notation attribute tree built while parsing
                   1833:  */
                   1834: 
                   1835: xmlEnumerationPtr
                   1836: xmlParseNotationType(xmlParserCtxtPtr ctxt) {
                   1837:     CHAR *name;
                   1838:     xmlEnumerationPtr ret = NULL, last = NULL, cur;
                   1839: 
                   1840:     if (CUR != '(') {
                   1841:        if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74    ! daniel   1842:            ctxt->sax->error(ctxt->userData, "'(' required to start 'NOTATION'\n");
1.66      daniel   1843:        ctxt->wellFormed = 0;
                   1844:        return(NULL);
                   1845:     }
                   1846:     do {
                   1847:         NEXT;
                   1848:        SKIP_BLANKS;
                   1849:         name = xmlParseName(ctxt);
                   1850:        if (name == NULL) {
                   1851:            if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74    ! daniel   1852:                ctxt->sax->error(ctxt->userData, 
1.66      daniel   1853:                                 "Name expected in NOTATION declaration\n");
                   1854:            ctxt->wellFormed = 0;
                   1855:            return(ret);
                   1856:        }
                   1857:        cur = xmlCreateEnumeration(name);
1.67      daniel   1858:        free(name);
1.66      daniel   1859:        if (cur == NULL) return(ret);
                   1860:        if (last == NULL) ret = last = cur;
                   1861:        else {
                   1862:            last->next = cur;
                   1863:            last = cur;
                   1864:        }
                   1865:        SKIP_BLANKS;
                   1866:     } while (CUR == '|');
                   1867:     if (CUR != ')') {
                   1868:        if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74    ! daniel   1869:            ctxt->sax->error(ctxt->userData,
1.66      daniel   1870:                             "')' required to finish NOTATION declaration\n");
                   1871:        ctxt->wellFormed = 0;
                   1872:        return(ret);
                   1873:     }
                   1874:     NEXT;
                   1875:     return(ret);
                   1876: }
                   1877: 
                   1878: /**
                   1879:  * xmlParseEnumerationType:
                   1880:  * @ctxt:  an XML parser context
                   1881:  *
                   1882:  * parse an Enumeration attribute type.
                   1883:  *
                   1884:  * [59] Enumeration ::= '(' S? Nmtoken (S? '|' S? Nmtoken)* S? ')'
                   1885:  *
                   1886:  * Returns: the enumeration attribute tree built while parsing
                   1887:  */
                   1888: 
                   1889: xmlEnumerationPtr
                   1890: xmlParseEnumerationType(xmlParserCtxtPtr ctxt) {
                   1891:     CHAR *name;
                   1892:     xmlEnumerationPtr ret = NULL, last = NULL, cur;
                   1893: 
                   1894:     if (CUR != '(') {
                   1895:        if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74    ! daniel   1896:            ctxt->sax->error(ctxt->userData,
1.66      daniel   1897:                             "'(' required to start ATTLIST enumeration\n");
                   1898:        ctxt->wellFormed = 0;
                   1899:        return(NULL);
                   1900:     }
                   1901:     do {
                   1902:         NEXT;
                   1903:        SKIP_BLANKS;
                   1904:         name = xmlParseNmtoken(ctxt);
                   1905:        if (name == NULL) {
                   1906:            if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74    ! daniel   1907:                ctxt->sax->error(ctxt->userData, 
1.66      daniel   1908:                                 "NmToken expected in ATTLIST enumeration\n");
                   1909:            ctxt->wellFormed = 0;
                   1910:            return(ret);
                   1911:        }
                   1912:        cur = xmlCreateEnumeration(name);
1.67      daniel   1913:        free(name);
1.66      daniel   1914:        if (cur == NULL) return(ret);
                   1915:        if (last == NULL) ret = last = cur;
                   1916:        else {
                   1917:            last->next = cur;
                   1918:            last = cur;
                   1919:        }
                   1920:        SKIP_BLANKS;
                   1921:     } while (CUR == '|');
                   1922:     if (CUR != ')') {
                   1923:        if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74    ! daniel   1924:            ctxt->sax->error(ctxt->userData,
1.66      daniel   1925:                             "')' required to finish ATTLIST enumeration\n");
                   1926:        ctxt->wellFormed = 0;
                   1927:        return(ret);
                   1928:     }
                   1929:     NEXT;
                   1930:     return(ret);
                   1931: }
                   1932: 
                   1933: /**
1.50      daniel   1934:  * xmlParseEnumeratedType:
                   1935:  * @ctxt:  an XML parser context
1.66      daniel   1936:  * @tree:  the enumeration tree built while parsing
1.50      daniel   1937:  *
1.66      daniel   1938:  * parse an Enumerated attribute type.
1.22      daniel   1939:  *
                   1940:  * [57] EnumeratedType ::= NotationType | Enumeration
                   1941:  *
                   1942:  * [58] NotationType ::= 'NOTATION' S '(' S? Name (S? '|' S? Name)* S? ')'
                   1943:  *
1.50      daniel   1944:  *
1.66      daniel   1945:  * Returns: XML_ATTRIBUTE_ENUMERATION or XML_ATTRIBUTE_NOTATION
1.22      daniel   1946:  */
                   1947: 
1.66      daniel   1948: int
                   1949: xmlParseEnumeratedType(xmlParserCtxtPtr ctxt, xmlEnumerationPtr *tree) {
                   1950:     if ((CUR == 'N') && (NXT(1) == 'O') &&
                   1951:         (NXT(2) == 'T') && (NXT(3) == 'A') &&
                   1952:         (NXT(4) == 'T') && (NXT(5) == 'I') &&
                   1953:        (NXT(6) == 'O') && (NXT(7) == 'N')) {
                   1954:        SKIP(8);
                   1955:        if (!IS_BLANK(CUR)) {
                   1956:            if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74    ! daniel   1957:                ctxt->sax->error(ctxt->userData, "Space required after 'NOTATION'\n");
1.66      daniel   1958:            ctxt->wellFormed = 0;
                   1959:            return(0);
                   1960:        }
                   1961:         SKIP_BLANKS;
                   1962:        *tree = xmlParseNotationType(ctxt);
                   1963:        if (*tree == NULL) return(0);
                   1964:        return(XML_ATTRIBUTE_NOTATION);
                   1965:     }
                   1966:     *tree = xmlParseEnumerationType(ctxt);
                   1967:     if (*tree == NULL) return(0);
                   1968:     return(XML_ATTRIBUTE_ENUMERATION);
1.22      daniel   1969: }
                   1970: 
1.50      daniel   1971: /**
                   1972:  * xmlParseAttributeType:
                   1973:  * @ctxt:  an XML parser context
1.66      daniel   1974:  * @tree:  the enumeration tree built while parsing
1.50      daniel   1975:  *
1.59      daniel   1976:  * parse the Attribute list def for an element
1.22      daniel   1977:  *
                   1978:  * [54] AttType ::= StringType | TokenizedType | EnumeratedType
                   1979:  *
                   1980:  * [55] StringType ::= 'CDATA'
                   1981:  *
                   1982:  * [56] TokenizedType ::= 'ID' | 'IDREF' | 'IDREFS' | 'ENTITY' |
                   1983:  *                        'ENTITIES' | 'NMTOKEN' | 'NMTOKENS'
1.50      daniel   1984:  *
1.69      daniel   1985:  * Returns the attribute type
1.22      daniel   1986:  */
1.59      daniel   1987: int 
1.66      daniel   1988: xmlParseAttributeType(xmlParserCtxtPtr ctxt, xmlEnumerationPtr *tree) {
1.40      daniel   1989:     if ((CUR == 'C') && (NXT(1) == 'D') &&
                   1990:         (NXT(2) == 'A') && (NXT(3) == 'T') &&
                   1991:         (NXT(4) == 'A')) {
                   1992:        SKIP(5);
1.66      daniel   1993:        return(XML_ATTRIBUTE_CDATA);
1.40      daniel   1994:      } else if ((CUR == 'I') && (NXT(1) == 'D') &&
                   1995:         (NXT(2) == 'R') && (NXT(3) == 'E') &&
                   1996:         (NXT(4) == 'F')) {
                   1997:        SKIP(5);
1.59      daniel   1998:        return(XML_ATTRIBUTE_IDREF);
1.66      daniel   1999:      } else if ((CUR == 'I') && (NXT(1) == 'D')) {
                   2000:         SKIP(2);
                   2001:        return(XML_ATTRIBUTE_ID);
1.40      daniel   2002:      } else if ((CUR == 'I') && (NXT(1) == 'D') &&
                   2003:         (NXT(2) == 'R') && (NXT(3) == 'E') &&
                   2004:         (NXT(4) == 'F') && (NXT(5) == 'S')) {
                   2005:        SKIP(6);
1.59      daniel   2006:        return(XML_ATTRIBUTE_IDREFS);
1.40      daniel   2007:      } else if ((CUR == 'E') && (NXT(1) == 'N') &&
                   2008:         (NXT(2) == 'T') && (NXT(3) == 'I') &&
                   2009:         (NXT(4) == 'T') && (NXT(5) == 'Y')) {
                   2010:        SKIP(6);
1.59      daniel   2011:        return(XML_ATTRIBUTE_ENTITY);
1.40      daniel   2012:      } else if ((CUR == 'E') && (NXT(1) == 'N') &&
                   2013:         (NXT(2) == 'T') && (NXT(3) == 'I') &&
                   2014:         (NXT(4) == 'T') && (NXT(5) == 'I') &&
                   2015:         (NXT(6) == 'E') && (NXT(7) == 'S')) {
                   2016:        SKIP(8);
1.59      daniel   2017:        return(XML_ATTRIBUTE_ENTITIES);
1.40      daniel   2018:      } else if ((CUR == 'N') && (NXT(1) == 'M') &&
                   2019:         (NXT(2) == 'T') && (NXT(3) == 'O') &&
                   2020:         (NXT(4) == 'K') && (NXT(5) == 'E') &&
1.66      daniel   2021:         (NXT(6) == 'N') && (NXT(7) == 'S')) {
                   2022:        SKIP(8);
                   2023:        return(XML_ATTRIBUTE_NMTOKENS);
                   2024:      } else if ((CUR == 'N') && (NXT(1) == 'M') &&
                   2025:         (NXT(2) == 'T') && (NXT(3) == 'O') &&
                   2026:         (NXT(4) == 'K') && (NXT(5) == 'E') &&
1.40      daniel   2027:         (NXT(6) == 'N')) {
                   2028:        SKIP(7);
1.59      daniel   2029:        return(XML_ATTRIBUTE_NMTOKEN);
1.22      daniel   2030:      }
1.66      daniel   2031:      return(xmlParseEnumeratedType(ctxt, tree));
1.22      daniel   2032: }
                   2033: 
1.50      daniel   2034: /**
                   2035:  * xmlParseAttributeListDecl:
                   2036:  * @ctxt:  an XML parser context
                   2037:  *
                   2038:  * : parse the Attribute list def for an element
1.22      daniel   2039:  *
                   2040:  * [52] AttlistDecl ::= '<!ATTLIST' S Name AttDef* S? '>'
                   2041:  *
                   2042:  * [53] AttDef ::= S Name S AttType S DefaultDecl
1.50      daniel   2043:  *
1.22      daniel   2044:  */
1.55      daniel   2045: void
                   2046: xmlParseAttributeListDecl(xmlParserCtxtPtr ctxt) {
1.59      daniel   2047:     CHAR *elemName;
                   2048:     CHAR *attrName;
1.66      daniel   2049:     xmlEnumerationPtr tree = NULL;
1.22      daniel   2050: 
1.40      daniel   2051:     if ((CUR == '<') && (NXT(1) == '!') &&
                   2052:         (NXT(2) == 'A') && (NXT(3) == 'T') &&
                   2053:         (NXT(4) == 'T') && (NXT(5) == 'L') &&
                   2054:         (NXT(6) == 'I') && (NXT(7) == 'S') &&
1.59      daniel   2055:         (NXT(8) == 'T')) {
1.40      daniel   2056:        SKIP(9);
1.59      daniel   2057:        if (!IS_BLANK(CUR)) {
                   2058:            if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74    ! daniel   2059:                ctxt->sax->error(ctxt->userData, "Space required after '<!ATTLIST'\n");
1.59      daniel   2060:            ctxt->wellFormed = 0;
                   2061:        }
1.42      daniel   2062:         SKIP_BLANKS;
1.59      daniel   2063:         elemName = xmlParseName(ctxt);
                   2064:        if (elemName == NULL) {
1.55      daniel   2065:            if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74    ! daniel   2066:                ctxt->sax->error(ctxt->userData, "ATTLIST: no name for Element\n");
1.59      daniel   2067:            ctxt->wellFormed = 0;
1.22      daniel   2068:            return;
                   2069:        }
1.42      daniel   2070:        SKIP_BLANKS;
1.40      daniel   2071:        while (CUR != '>') {
                   2072:            const CHAR *check = CUR_PTR;
1.59      daniel   2073:            int type;
                   2074:            int def;
                   2075:            CHAR *defaultValue = NULL;
                   2076: 
                   2077:            attrName = xmlParseName(ctxt);
                   2078:            if (attrName == NULL) {
                   2079:                if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74    ! daniel   2080:                    ctxt->sax->error(ctxt->userData, "ATTLIST: no name for Attribute\n");
1.59      daniel   2081:                ctxt->wellFormed = 0;
                   2082:                break;
                   2083:            }
                   2084:            if (!IS_BLANK(CUR)) {
                   2085:                if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74    ! daniel   2086:                    ctxt->sax->error(ctxt->userData, 
1.59      daniel   2087:                        "Space required after the attribute name\n");
                   2088:                ctxt->wellFormed = 0;
                   2089:                break;
                   2090:            }
                   2091:            SKIP_BLANKS;
                   2092: 
1.66      daniel   2093:            type = xmlParseAttributeType(ctxt, &tree);
1.59      daniel   2094:            if (type <= 0) break;
1.22      daniel   2095: 
1.59      daniel   2096:            if (!IS_BLANK(CUR)) {
                   2097:                if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74    ! daniel   2098:                    ctxt->sax->error(ctxt->userData, 
1.59      daniel   2099:                        "Space required after the attribute type\n");
                   2100:                ctxt->wellFormed = 0;
                   2101:                break;
                   2102:            }
1.42      daniel   2103:            SKIP_BLANKS;
1.59      daniel   2104: 
                   2105:            def = xmlParseDefaultDecl(ctxt, &defaultValue);
                   2106:            if (def <= 0) break;
                   2107: 
                   2108:             if (CUR != '>') {
                   2109:                if (!IS_BLANK(CUR)) {
                   2110:                    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74    ! daniel   2111:                        ctxt->sax->error(ctxt->userData, 
1.59      daniel   2112:                        "Space required after the attribute default value\n");
                   2113:                    ctxt->wellFormed = 0;
                   2114:                    break;
                   2115:                }
                   2116:                SKIP_BLANKS;
                   2117:            }
1.40      daniel   2118:            if (check == CUR_PTR) {
1.55      daniel   2119:                if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74    ! daniel   2120:                    ctxt->sax->error(ctxt->userData, 
1.59      daniel   2121:                    "xmlParseAttributeListDecl: detected internal error\n");
1.22      daniel   2122:                break;
                   2123:            }
1.72      daniel   2124:            if ((ctxt->sax != NULL) && (ctxt->sax->attributeDecl != NULL))
1.74    ! daniel   2125:                ctxt->sax->attributeDecl(ctxt->userData, elemName, attrName,
1.66      daniel   2126:                                type, def, defaultValue, tree);
1.59      daniel   2127:            if (attrName != NULL)
                   2128:                free(attrName);
                   2129:            if (defaultValue != NULL)
                   2130:                free(defaultValue);
1.22      daniel   2131:        }
1.40      daniel   2132:        if (CUR == '>')
                   2133:            NEXT;
1.22      daniel   2134: 
1.59      daniel   2135:        free(elemName);
1.22      daniel   2136:     }
                   2137: }
                   2138: 
1.50      daniel   2139: /**
1.61      daniel   2140:  * xmlParseElementMixedContentDecl:
                   2141:  * @ctxt:  an XML parser context
                   2142:  *
                   2143:  * parse the declaration for a Mixed Element content
                   2144:  * The leading '(' and spaces have been skipped in xmlParseElementContentDecl
                   2145:  * 
                   2146:  * [51] Mixed ::= '(' S? '#PCDATA' (S? '|' S? Name)* S? ')*' |
                   2147:  *                '(' S? '#PCDATA' S? ')'
                   2148:  *
                   2149:  * returns: the list of the xmlElementContentPtr describing the element choices
                   2150:  */
                   2151: xmlElementContentPtr
1.62      daniel   2152: xmlParseElementMixedContentDecl(xmlParserCtxtPtr ctxt) {
1.64      daniel   2153:     xmlElementContentPtr ret = NULL, cur = NULL, n;
1.61      daniel   2154:     CHAR *elem = NULL;
                   2155: 
                   2156:     if ((CUR == '#') && (NXT(1) == 'P') &&
                   2157:         (NXT(2) == 'C') && (NXT(3) == 'D') &&
                   2158:         (NXT(4) == 'A') && (NXT(5) == 'T') &&
                   2159:         (NXT(6) == 'A')) {
                   2160:        SKIP(7);
                   2161:        SKIP_BLANKS;
1.63      daniel   2162:        if (CUR == ')') {
                   2163:            NEXT;
                   2164:            ret = xmlNewElementContent(NULL, XML_ELEMENT_CONTENT_PCDATA);
                   2165:            return(ret);
                   2166:        }
1.61      daniel   2167:        if ((CUR == '(') || (CUR == '|')) {
                   2168:            ret = cur = xmlNewElementContent(NULL, XML_ELEMENT_CONTENT_PCDATA);
                   2169:            if (ret == NULL) return(NULL);
1.63      daniel   2170:        } /********** else {
1.61      daniel   2171:            if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74    ! daniel   2172:                ctxt->sax->error(ctxt->userData, 
1.61      daniel   2173:                    "xmlParseElementMixedContentDecl : '|' or ')' expected\n");
                   2174:            ctxt->wellFormed = 0;
                   2175:            return(NULL);
1.63      daniel   2176:        } **********/
1.61      daniel   2177:        while (CUR == '|') {
1.64      daniel   2178:            NEXT;
1.61      daniel   2179:            if (elem == NULL) {
                   2180:                ret = xmlNewElementContent(NULL, XML_ELEMENT_CONTENT_OR);
                   2181:                if (ret == NULL) return(NULL);
                   2182:                ret->c1 = cur;
1.64      daniel   2183:                cur = ret;
1.61      daniel   2184:            } else {
1.64      daniel   2185:                n = xmlNewElementContent(NULL, XML_ELEMENT_CONTENT_OR);
                   2186:                if (n == NULL) return(NULL);
                   2187:                n->c1 = xmlNewElementContent(elem, XML_ELEMENT_CONTENT_ELEMENT);
                   2188:                cur->c2 = n;
                   2189:                cur = n;
1.66      daniel   2190:                free(elem);
1.61      daniel   2191:            }
                   2192:            SKIP_BLANKS;
                   2193:            elem = xmlParseName(ctxt);
                   2194:            if (elem == NULL) {
                   2195:                if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74    ! daniel   2196:                    ctxt->sax->error(ctxt->userData, 
1.61      daniel   2197:                        "xmlParseElementMixedContentDecl : Name expected\n");
                   2198:                ctxt->wellFormed = 0;
                   2199:                xmlFreeElementContent(cur);
                   2200:                return(NULL);
                   2201:            }
                   2202:            SKIP_BLANKS;
                   2203:        }
1.63      daniel   2204:        if ((CUR == ')') && (NXT(1) == '*')) {
1.66      daniel   2205:            if (elem != NULL) {
1.61      daniel   2206:                cur->c2 = xmlNewElementContent(elem,
                   2207:                                               XML_ELEMENT_CONTENT_ELEMENT);
1.66      daniel   2208:                free(elem);
                   2209:             }
1.65      daniel   2210:            ret->ocur = XML_ELEMENT_CONTENT_MULT;
1.64      daniel   2211:            SKIP(2);
1.61      daniel   2212:        } else {
1.66      daniel   2213:            if (elem != NULL) free(elem);
1.61      daniel   2214:            if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74    ! daniel   2215:                ctxt->sax->error(ctxt->userData, 
1.63      daniel   2216:                    "xmlParseElementMixedContentDecl : '|' or ')*' expected\n");
1.61      daniel   2217:            ctxt->wellFormed = 0;
                   2218:            xmlFreeElementContent(ret);
                   2219:            return(NULL);
                   2220:        }
                   2221: 
                   2222:     } else {
                   2223:        if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74    ! daniel   2224:            ctxt->sax->error(ctxt->userData, 
1.61      daniel   2225:                "xmlParseElementMixedContentDecl : '#PCDATA' expected\n");
                   2226:        ctxt->wellFormed = 0;
                   2227:     }
                   2228:     return(ret);
                   2229: }
                   2230: 
                   2231: /**
                   2232:  * xmlParseElementChildrenContentDecl:
1.50      daniel   2233:  * @ctxt:  an XML parser context
                   2234:  *
1.61      daniel   2235:  * parse the declaration for a Mixed Element content
                   2236:  * The leading '(' and spaces have been skipped in xmlParseElementContentDecl
1.22      daniel   2237:  * 
1.61      daniel   2238:  *
1.22      daniel   2239:  * [47] children ::= (choice | seq) ('?' | '*' | '+')?
                   2240:  *
                   2241:  * [48] cp ::= (Name | choice | seq) ('?' | '*' | '+')?
                   2242:  *
                   2243:  * [49] choice ::= '(' S? cp ( S? '|' S? cp )* S? ')'
                   2244:  *
                   2245:  * [50] seq ::= '(' S? cp ( S? ',' S? cp )* S? ')'
                   2246:  *
1.62      daniel   2247:  * returns: the tree of xmlElementContentPtr describing the element 
1.61      daniel   2248:  *          hierarchy.
                   2249:  */
                   2250: xmlElementContentPtr
1.62      daniel   2251: xmlParseElementChildrenContentDecl(xmlParserCtxtPtr ctxt) {
1.63      daniel   2252:     xmlElementContentPtr ret = NULL, cur = NULL, last = NULL, op = NULL;
1.62      daniel   2253:     CHAR *elem;
                   2254:     CHAR type = 0;
                   2255: 
                   2256:     SKIP_BLANKS;
                   2257:     if (CUR == '(') {
1.63      daniel   2258:         /* Recurse on first child */
1.62      daniel   2259:        NEXT;
                   2260:        SKIP_BLANKS;
                   2261:         cur = ret = xmlParseElementChildrenContentDecl(ctxt);
                   2262:        SKIP_BLANKS;
                   2263:     } else {
                   2264:        elem = xmlParseName(ctxt);
                   2265:        if (elem == NULL) {
                   2266:            if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74    ! daniel   2267:                ctxt->sax->error(ctxt->userData, 
1.62      daniel   2268:                "xmlParseElementChildrenContentDecl : Name or '(' expected\n");
                   2269:            ctxt->wellFormed = 0;
                   2270:            return(NULL);
                   2271:        }
                   2272:         cur = ret = xmlNewElementContent(elem, XML_ELEMENT_CONTENT_ELEMENT);
                   2273:        if (CUR == '?') {
                   2274:            ret->ocur = XML_ELEMENT_CONTENT_OPT;
                   2275:            NEXT;
                   2276:        } else if (CUR == '*') {
                   2277:            ret->ocur = XML_ELEMENT_CONTENT_MULT;
                   2278:            NEXT;
                   2279:        } else if (CUR == '+') {
                   2280:            ret->ocur = XML_ELEMENT_CONTENT_PLUS;
                   2281:            NEXT;
                   2282:        } else {
                   2283:            ret->ocur = XML_ELEMENT_CONTENT_ONCE;
                   2284:        }
1.66      daniel   2285:        free(elem);
1.62      daniel   2286:     }
                   2287:     SKIP_BLANKS;
                   2288:     while (CUR != ')') {
1.63      daniel   2289:         /*
                   2290:         * Each loop we parse one separator and one element.
                   2291:         */
1.62      daniel   2292:         if (CUR == ',') {
                   2293:            if (type == 0) type = CUR;
                   2294: 
                   2295:            /*
                   2296:             * Detect "Name | Name , Name" error
                   2297:             */
                   2298:            else if (type != CUR) {
                   2299:                if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74    ! daniel   2300:                    ctxt->sax->error(ctxt->userData, 
1.62      daniel   2301:                    "xmlParseElementChildrenContentDecl : '%c' expected\n",
                   2302:                    type);
                   2303:                ctxt->wellFormed = 0;
                   2304:                xmlFreeElementContent(ret);
                   2305:                return(NULL);
                   2306:            }
1.64      daniel   2307:            NEXT;
1.62      daniel   2308: 
1.63      daniel   2309:            op = xmlNewElementContent(NULL, XML_ELEMENT_CONTENT_SEQ);
                   2310:            if (op == NULL) {
                   2311:                xmlFreeElementContent(ret);
                   2312:                return(NULL);
                   2313:            }
                   2314:            if (last == NULL) {
                   2315:                op->c1 = ret;
1.65      daniel   2316:                ret = cur = op;
1.63      daniel   2317:            } else {
                   2318:                cur->c2 = op;
                   2319:                op->c1 = last;
                   2320:                cur =op;
1.65      daniel   2321:                last = NULL;
1.63      daniel   2322:            }
1.62      daniel   2323:        } else if (CUR == '|') {
                   2324:            if (type == 0) type = CUR;
                   2325: 
                   2326:            /*
1.63      daniel   2327:             * Detect "Name , Name | Name" error
1.62      daniel   2328:             */
                   2329:            else if (type != CUR) {
                   2330:                if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74    ! daniel   2331:                    ctxt->sax->error(ctxt->userData, 
1.62      daniel   2332:                    "xmlParseElementChildrenContentDecl : '%c' expected\n",
                   2333:                    type);
                   2334:                ctxt->wellFormed = 0;
                   2335:                xmlFreeElementContent(ret);
                   2336:                return(NULL);
                   2337:            }
1.64      daniel   2338:            NEXT;
1.62      daniel   2339: 
1.63      daniel   2340:            op = xmlNewElementContent(NULL, XML_ELEMENT_CONTENT_OR);
                   2341:            if (op == NULL) {
                   2342:                xmlFreeElementContent(ret);
                   2343:                return(NULL);
                   2344:            }
                   2345:            if (last == NULL) {
                   2346:                op->c1 = ret;
1.65      daniel   2347:                ret = cur = op;
1.63      daniel   2348:            } else {
                   2349:                cur->c2 = op;
                   2350:                op->c1 = last;
                   2351:                cur =op;
1.65      daniel   2352:                last = NULL;
1.63      daniel   2353:            }
1.62      daniel   2354:        } else {
                   2355:            if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74    ! daniel   2356:                ctxt->sax->error(ctxt->userData, 
1.62      daniel   2357:            "xmlParseElementChildrenContentDecl : ',' '|' or ')' expected\n");
                   2358:            ctxt->wellFormed = 0;
                   2359:            xmlFreeElementContent(ret);
                   2360:            return(NULL);
                   2361:        }
                   2362:        SKIP_BLANKS;
                   2363:        if (CUR == '(') {
1.63      daniel   2364:            /* Recurse on second child */
1.62      daniel   2365:            NEXT;
                   2366:            SKIP_BLANKS;
1.65      daniel   2367:            last = xmlParseElementChildrenContentDecl(ctxt);
1.62      daniel   2368:            SKIP_BLANKS;
                   2369:        } else {
                   2370:            elem = xmlParseName(ctxt);
                   2371:            if (elem == NULL) {
                   2372:                if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74    ! daniel   2373:                    ctxt->sax->error(ctxt->userData, 
1.62      daniel   2374:                    "xmlParseElementChildrenContentDecl : Name or '(' expected\n");
                   2375:                ctxt->wellFormed = 0;
                   2376:                return(NULL);
                   2377:            }
1.65      daniel   2378:            last = xmlNewElementContent(elem, XML_ELEMENT_CONTENT_ELEMENT);
1.66      daniel   2379:            free(elem);
1.62      daniel   2380:        }
1.63      daniel   2381:        if (CUR == '?') {
                   2382:            ret->ocur = XML_ELEMENT_CONTENT_OPT;
                   2383:            NEXT;
                   2384:        } else if (CUR == '*') {
                   2385:            ret->ocur = XML_ELEMENT_CONTENT_MULT;
                   2386:            NEXT;
                   2387:        } else if (CUR == '+') {
                   2388:            ret->ocur = XML_ELEMENT_CONTENT_PLUS;
                   2389:            NEXT;
                   2390:        } else {
                   2391:            ret->ocur = XML_ELEMENT_CONTENT_ONCE;
                   2392:        }
                   2393:        SKIP_BLANKS;
1.64      daniel   2394:     }
1.65      daniel   2395:     if ((cur != NULL) && (last != NULL)) {
                   2396:         cur->c2 = last;
1.62      daniel   2397:     }
                   2398:     NEXT;
                   2399:     if (CUR == '?') {
                   2400:         ret->ocur = XML_ELEMENT_CONTENT_OPT;
                   2401:        NEXT;
                   2402:     } else if (CUR == '*') {
                   2403:         ret->ocur = XML_ELEMENT_CONTENT_MULT;
                   2404:        NEXT;
                   2405:     } else if (CUR == '+') {
                   2406:         ret->ocur = XML_ELEMENT_CONTENT_PLUS;
                   2407:        NEXT;
                   2408:     } else {
                   2409:         ret->ocur = XML_ELEMENT_CONTENT_ONCE;
                   2410:     }
                   2411:     return(ret);
1.61      daniel   2412: }
                   2413: 
                   2414: /**
                   2415:  * xmlParseElementContentDecl:
                   2416:  * @ctxt:  an XML parser context
                   2417:  * @name:  the name of the element being defined.
                   2418:  * @result:  the Element Content pointer will be stored here if any
1.22      daniel   2419:  *
1.61      daniel   2420:  * parse the declaration for an Element content either Mixed or Children,
                   2421:  * the cases EMPTY and ANY are handled directly in xmlParseElementDecl
                   2422:  * 
                   2423:  * [46] contentspec ::= 'EMPTY' | 'ANY' | Mixed | children
1.50      daniel   2424:  *
1.61      daniel   2425:  * returns: the type of element content XML_ELEMENT_TYPE_xxx
1.22      daniel   2426:  */
                   2427: 
1.61      daniel   2428: int
                   2429: xmlParseElementContentDecl(xmlParserCtxtPtr ctxt, CHAR *name,
                   2430:                            xmlElementContentPtr *result) {
                   2431: 
                   2432:     xmlElementContentPtr tree = NULL;
                   2433:     int res;
                   2434: 
                   2435:     *result = NULL;
                   2436: 
                   2437:     if (CUR != '(') {
                   2438:        if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74    ! daniel   2439:            ctxt->sax->error(ctxt->userData, 
1.61      daniel   2440:                "xmlParseElementContentDecl : '(' expected\n");
                   2441:        ctxt->wellFormed = 0;
                   2442:        return(-1);
                   2443:     }
                   2444:     NEXT;
                   2445:     SKIP_BLANKS;
                   2446:     if ((CUR == '#') && (NXT(1) == 'P') &&
                   2447:         (NXT(2) == 'C') && (NXT(3) == 'D') &&
                   2448:         (NXT(4) == 'A') && (NXT(5) == 'T') &&
                   2449:         (NXT(6) == 'A')) {
1.62      daniel   2450:         tree = xmlParseElementMixedContentDecl(ctxt);
1.61      daniel   2451:        res = XML_ELEMENT_TYPE_MIXED;
                   2452:     } else {
1.62      daniel   2453:         tree = xmlParseElementChildrenContentDecl(ctxt);
1.61      daniel   2454:        res = XML_ELEMENT_TYPE_ELEMENT;
                   2455:     }
                   2456:     SKIP_BLANKS;
1.63      daniel   2457:     /****************************
1.61      daniel   2458:     if (CUR != ')') {
                   2459:        if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74    ! daniel   2460:            ctxt->sax->error(ctxt->userData, 
1.61      daniel   2461:                "xmlParseElementContentDecl : ')' expected\n");
                   2462:        ctxt->wellFormed = 0;
                   2463:        return(-1);
                   2464:     }
1.63      daniel   2465:      ****************************/
                   2466:     *result = tree;
1.61      daniel   2467:     return(res);
1.22      daniel   2468: }
                   2469: 
1.50      daniel   2470: /**
                   2471:  * xmlParseElementDecl:
                   2472:  * @ctxt:  an XML parser context
                   2473:  *
                   2474:  * parse an Element declaration.
1.22      daniel   2475:  *
                   2476:  * [45] elementdecl ::= '<!ELEMENT' S Name S contentspec S? '>'
                   2477:  *
                   2478:  * TODO There is a check [ VC: Unique Element Type Declaration ]
1.69      daniel   2479:  *
                   2480:  * Returns the type of the element, or -1 in case of error
1.22      daniel   2481:  */
1.59      daniel   2482: int
1.55      daniel   2483: xmlParseElementDecl(xmlParserCtxtPtr ctxt) {
1.22      daniel   2484:     CHAR *name;
1.59      daniel   2485:     int ret = -1;
1.61      daniel   2486:     xmlElementContentPtr content  = NULL;
1.22      daniel   2487: 
1.40      daniel   2488:     if ((CUR == '<') && (NXT(1) == '!') &&
                   2489:         (NXT(2) == 'E') && (NXT(3) == 'L') &&
                   2490:         (NXT(4) == 'E') && (NXT(5) == 'M') &&
                   2491:         (NXT(6) == 'E') && (NXT(7) == 'N') &&
1.59      daniel   2492:         (NXT(8) == 'T')) {
1.40      daniel   2493:        SKIP(9);
1.59      daniel   2494:        if (!IS_BLANK(CUR)) {
                   2495:            if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74    ! daniel   2496:                ctxt->sax->error(ctxt->userData, 
1.59      daniel   2497:                    "Space required after 'ELEMENT'\n");
                   2498:            ctxt->wellFormed = 0;
                   2499:        }
1.42      daniel   2500:         SKIP_BLANKS;
1.22      daniel   2501:         name = xmlParseName(ctxt);
                   2502:        if (name == NULL) {
1.55      daniel   2503:            if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74    ! daniel   2504:                ctxt->sax->error(ctxt->userData,
1.59      daniel   2505:                   "xmlParseElementDecl: no name for Element\n");
                   2506:            ctxt->wellFormed = 0;
                   2507:            return(-1);
                   2508:        }
                   2509:        if (!IS_BLANK(CUR)) {
                   2510:            if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74    ! daniel   2511:                ctxt->sax->error(ctxt->userData, 
1.59      daniel   2512:                    "Space required after the element name\n");
                   2513:            ctxt->wellFormed = 0;
1.22      daniel   2514:        }
1.42      daniel   2515:         SKIP_BLANKS;
1.40      daniel   2516:        if ((CUR == 'E') && (NXT(1) == 'M') &&
                   2517:            (NXT(2) == 'P') && (NXT(3) == 'T') &&
                   2518:            (NXT(4) == 'Y')) {
                   2519:            SKIP(5);
1.22      daniel   2520:            /*
                   2521:             * Element must always be empty.
                   2522:             */
1.59      daniel   2523:            ret = XML_ELEMENT_TYPE_EMPTY;
1.40      daniel   2524:        } else if ((CUR == 'A') && (NXT(1) == 'N') &&
                   2525:                   (NXT(2) == 'Y')) {
                   2526:            SKIP(3);
1.22      daniel   2527:            /*
                   2528:             * Element is a generic container.
                   2529:             */
1.59      daniel   2530:            ret = XML_ELEMENT_TYPE_ANY;
1.61      daniel   2531:        } else if (CUR == '(') {
                   2532:            ret = xmlParseElementContentDecl(ctxt, name, &content);
1.22      daniel   2533:        } else {
1.61      daniel   2534:            if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74    ! daniel   2535:                ctxt->sax->error(ctxt->userData, 
1.61      daniel   2536:                  "xmlParseElementDecl: 'EMPTY', 'ANY' or '(' expected\n");
                   2537:            ctxt->wellFormed = 0;
                   2538:            if (name != NULL) free(name);
                   2539:            return(-1);
1.22      daniel   2540:        }
1.42      daniel   2541:        SKIP_BLANKS;
1.40      daniel   2542:        if (CUR != '>') {
1.55      daniel   2543:            if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74    ! daniel   2544:                ctxt->sax->error(ctxt->userData, 
1.31      daniel   2545:                  "xmlParseElementDecl: expected '>' at the end\n");
1.59      daniel   2546:            ctxt->wellFormed = 0;
1.61      daniel   2547:        } else {
1.40      daniel   2548:            NEXT;
1.72      daniel   2549:            if ((ctxt->sax != NULL) && (ctxt->sax->elementDecl != NULL))
1.74    ! daniel   2550:                ctxt->sax->elementDecl(ctxt->userData, name, ret, content);
1.61      daniel   2551:        }
                   2552:        if (name != NULL) {
                   2553:            free(name);
                   2554:        }
1.22      daniel   2555:     }
1.59      daniel   2556:     return(ret);
1.22      daniel   2557: }
                   2558: 
1.50      daniel   2559: /**
                   2560:  * xmlParseMarkupDecl:
                   2561:  * @ctxt:  an XML parser context
                   2562:  * 
                   2563:  * parse Markup declarations
1.22      daniel   2564:  *
                   2565:  * [29] markupdecl ::= elementdecl | AttlistDecl | EntityDecl |
                   2566:  *                     NotationDecl | PI | Comment
                   2567:  *
                   2568:  * TODO There is a check [ VC: Proper Declaration/PE Nesting ]
                   2569:  */
1.55      daniel   2570: void
                   2571: xmlParseMarkupDecl(xmlParserCtxtPtr ctxt) {
1.22      daniel   2572:     xmlParseElementDecl(ctxt);
                   2573:     xmlParseAttributeListDecl(ctxt);
                   2574:     xmlParseEntityDecl(ctxt);
                   2575:     xmlParseNotationDecl(ctxt);
                   2576:     xmlParsePI(ctxt);
1.31      daniel   2577:     xmlParseComment(ctxt, 0);
1.22      daniel   2578: }
                   2579: 
1.50      daniel   2580: /**
                   2581:  * xmlParseCharRef:
                   2582:  * @ctxt:  an XML parser context
                   2583:  *
                   2584:  * parse Reference declarations
1.24      daniel   2585:  *
                   2586:  * [66] CharRef ::= '&#' [0-9]+ ';' |
                   2587:  *                  '&#x' [0-9a-fA-F]+ ';'
1.68      daniel   2588:  *
                   2589:  * Returns the value parsed
1.24      daniel   2590:  */
1.55      daniel   2591: CHAR *
                   2592: xmlParseCharRef(xmlParserCtxtPtr ctxt) {
1.29      daniel   2593:     int val = 0;
1.44      daniel   2594:     CHAR buf[2];
1.24      daniel   2595: 
1.40      daniel   2596:     if ((CUR == '&') && (NXT(1) == '#') &&
                   2597:         (NXT(2) == 'x')) {
                   2598:        SKIP(3);
                   2599:        while (CUR != ';') {
                   2600:            if ((CUR >= '0') && (CUR <= '9')) 
                   2601:                val = val * 16 + (CUR - '0');
                   2602:            else if ((CUR >= 'a') && (CUR <= 'f'))
                   2603:                val = val * 16 + (CUR - 'a') + 10;
                   2604:            else if ((CUR >= 'A') && (CUR <= 'F'))
                   2605:                val = val * 16 + (CUR - 'A') + 10;
1.24      daniel   2606:            else {
1.55      daniel   2607:                if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74    ! daniel   2608:                    ctxt->sax->error(ctxt->userData, 
1.59      daniel   2609:                         "xmlParseCharRef: invalid hexadecimal value\n");
                   2610:                ctxt->wellFormed = 0;
1.29      daniel   2611:                val = 0;
1.24      daniel   2612:                break;
                   2613:            }
1.47      daniel   2614:            NEXT;
1.24      daniel   2615:        }
1.55      daniel   2616:        if (CUR == ';')
1.40      daniel   2617:            NEXT;
                   2618:     } else if  ((CUR == '&') && (NXT(1) == '#')) {
                   2619:        SKIP(2);
                   2620:        while (CUR != ';') {
                   2621:            if ((CUR >= '0') && (CUR <= '9')) 
1.55      daniel   2622:                val = val * 10 + (CUR - '0');
1.24      daniel   2623:            else {
1.55      daniel   2624:                if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74    ! daniel   2625:                    ctxt->sax->error(ctxt->userData, 
1.58      daniel   2626:                         "xmlParseCharRef: invalid decimal value\n");
1.59      daniel   2627:                ctxt->wellFormed = 0;
1.29      daniel   2628:                val = 0;
1.24      daniel   2629:                break;
                   2630:            }
1.47      daniel   2631:            NEXT;
1.24      daniel   2632:        }
1.55      daniel   2633:        if (CUR == ';')
1.40      daniel   2634:            NEXT;
1.24      daniel   2635:     } else {
1.55      daniel   2636:        if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74    ! daniel   2637:            ctxt->sax->error(ctxt->userData, "xmlParseCharRef: invalid value\n");
1.59      daniel   2638:        ctxt->wellFormed = 0;
1.24      daniel   2639:     }
1.29      daniel   2640:     /*
                   2641:      * Check the value IS_CHAR ...
                   2642:      */
1.44      daniel   2643:     if (IS_CHAR(val)) {
                   2644:         buf[0] = (CHAR) val;
                   2645:        buf[1] = 0;
1.50      daniel   2646:        return(xmlStrndup(buf, 1));
1.44      daniel   2647:     } else {
1.55      daniel   2648:        if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74    ! daniel   2649:            ctxt->sax->error(ctxt->userData, "xmlParseCharRef: invalid CHAR value %d\n",
1.58      daniel   2650:                             val);
1.59      daniel   2651:        ctxt->wellFormed = 0;
1.29      daniel   2652:     }
1.46      daniel   2653:     return(NULL);
1.24      daniel   2654: }
                   2655: 
1.50      daniel   2656: /**
                   2657:  * xmlParseEntityRef:
                   2658:  * @ctxt:  an XML parser context
                   2659:  *
                   2660:  * parse ENTITY references declarations
1.24      daniel   2661:  *
                   2662:  * [68] EntityRef ::= '&' Name ';'
1.68      daniel   2663:  *
                   2664:  * Returns the entity ref string or NULL if directly as input stream.
1.24      daniel   2665:  */
1.55      daniel   2666: CHAR *
                   2667: xmlParseEntityRef(xmlParserCtxtPtr ctxt) {
1.46      daniel   2668:     CHAR *ret = NULL;
1.50      daniel   2669:     const CHAR *q;
1.24      daniel   2670:     CHAR *name;
1.72      daniel   2671:     xmlEntityPtr ent = NULL;
1.50      daniel   2672:     xmlParserInputPtr input = NULL;
1.24      daniel   2673: 
1.50      daniel   2674:     q = CUR_PTR;
1.40      daniel   2675:     if (CUR == '&') {
                   2676:         NEXT;
1.24      daniel   2677:         name = xmlParseName(ctxt);
                   2678:        if (name == NULL) {
1.55      daniel   2679:            if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74    ! daniel   2680:                ctxt->sax->error(ctxt->userData, "xmlParseEntityRef: no name\n");
1.59      daniel   2681:            ctxt->wellFormed = 0;
1.24      daniel   2682:        } else {
1.40      daniel   2683:            if (CUR == ';') {
                   2684:                NEXT;
1.24      daniel   2685:                /*
1.59      daniel   2686:                 * Well Formedness Constraint if:
                   2687:                 *   - standalone
                   2688:                 * or
                   2689:                 *   - no external subset and no external parameter entities
                   2690:                 *     referenced
                   2691:                 * then
                   2692:                 *   the entity referenced must have been declared
                   2693:                 *
1.72      daniel   2694:                 * TODO: to be double checked !!! This is wrong !
1.59      daniel   2695:                 */
1.72      daniel   2696:                if (ctxt->sax != NULL) {
                   2697:                    if (ctxt->sax->getEntity != NULL)
1.74    ! daniel   2698:                        ent = ctxt->sax->getEntity(ctxt->userData, name);
1.72      daniel   2699: 
                   2700:                    if (((ctxt->sax->isStandalone != NULL) &&
1.74    ! daniel   2701:                         ctxt->sax->isStandalone(ctxt->userData) == 1) ||
1.72      daniel   2702:                        (((ctxt->sax->hasInternalSubset == NULL) ||
1.74    ! daniel   2703:                          ctxt->sax->hasInternalSubset(ctxt->userData) == 0) &&
1.72      daniel   2704:                         ((ctxt->sax->hasExternalSubset == NULL) ||
1.74    ! daniel   2705:                          ctxt->sax->hasExternalSubset(ctxt->userData) == 0))) {
1.72      daniel   2706:                        if (ent == NULL) {
                   2707:                            if ((ctxt->sax != NULL) &&
                   2708:                                (ctxt->sax->error != NULL))
1.74    ! daniel   2709:                                ctxt->sax->error(ctxt->userData, 
1.72      daniel   2710:                                     "Entity '%s' not defined\n", name);
                   2711:                            ctxt->wellFormed = 0;
                   2712:                        }
1.59      daniel   2713:                    }
1.72      daniel   2714:                } else
                   2715:                    ctxt->wellFormed = 0;
1.59      daniel   2716: 
                   2717:                /*
                   2718:                 * Well Formedness Constraint :
                   2719:                 *   The referenced entity must be a parsed entity.
                   2720:                 */
                   2721:                if (ent != NULL) {
                   2722:                    switch (ent->type) {
                   2723:                        case XML_INTERNAL_PARAMETER_ENTITY:
                   2724:                        case XML_EXTERNAL_PARAMETER_ENTITY:
                   2725:                        if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74    ! daniel   2726:                            ctxt->sax->error(ctxt->userData, 
1.59      daniel   2727:                     "Attempt to reference the parameter entity '%s'\n", name);
                   2728:                        ctxt->wellFormed = 0;
                   2729:                        break;
                   2730:                         
                   2731:                        case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
                   2732:                        if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74    ! daniel   2733:                            ctxt->sax->error(ctxt->userData, 
1.59      daniel   2734:                     "Attempt to reference unparsed entity '%s'\n", name);
                   2735:                        ctxt->wellFormed = 0;
                   2736:                        break;
                   2737:                    }
                   2738:                }
                   2739: 
                   2740:                /*
                   2741:                 * Well Formedness Constraint :
                   2742:                 *   The referenced entity must not lead to recursion !
                   2743:                 */
                   2744:                 
                   2745:                /*
1.52      daniel   2746:                 * We parsed the entity reference correctly, call SAX
                   2747:                 * interface for the proper behaviour:
                   2748:                 *   - get a new input stream
                   2749:                 *   - or keep the reference inline
1.24      daniel   2750:                 */
1.72      daniel   2751:                if ((ctxt->sax) && (ctxt->sax->resolveEntity != NULL))
1.74    ! daniel   2752:                    input = ctxt->sax->resolveEntity(ctxt->userData, NULL, name);
1.52      daniel   2753:                if (input != NULL)
                   2754:                    xmlPushInput(ctxt, input);
                   2755:                else {
                   2756:                    ret = xmlStrndup(q, CUR_PTR - q);
                   2757:                }
1.24      daniel   2758:            } else {
1.46      daniel   2759:                char cst[2] = { '&', 0 };
                   2760: 
1.55      daniel   2761:                if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74    ! daniel   2762:                    ctxt->sax->error(ctxt->userData,
1.59      daniel   2763:                                     "xmlParseEntityRef: expecting ';'\n");
                   2764:                ctxt->wellFormed = 0;
1.46      daniel   2765:                ret = xmlStrndup(cst, 1);
                   2766:                ret = xmlStrcat(ret, name);
1.24      daniel   2767:            }
1.45      daniel   2768:            free(name);
1.24      daniel   2769:        }
                   2770:     }
1.46      daniel   2771:     return(ret);
1.24      daniel   2772: }
                   2773: 
1.50      daniel   2774: /**
                   2775:  * xmlParseReference:
                   2776:  * @ctxt:  an XML parser context
                   2777:  * 
                   2778:  * parse Reference declarations
1.24      daniel   2779:  *
                   2780:  * [67] Reference ::= EntityRef | CharRef
1.68      daniel   2781:  *
                   2782:  * Returns the entity string or NULL if handled directly by pushing
1.52      daniel   2783:  *      the entity value as the input.
1.24      daniel   2784:  */
1.55      daniel   2785: CHAR *
                   2786: xmlParseReference(xmlParserCtxtPtr ctxt) {
1.44      daniel   2787:     if ((CUR == '&') && (NXT(1) == '#')) {
1.59      daniel   2788:         CHAR *val = xmlParseCharRef(ctxt);
                   2789:        xmlParserInputPtr in;
                   2790: 
                   2791:        if (val != NULL) {
                   2792:            in = xmlNewStringInputStream(ctxt, val);
                   2793:            xmlPushInput(ctxt, in);
                   2794:        }
                   2795:        return(NULL);
1.44      daniel   2796:     } else if (CUR == '&') {
1.50      daniel   2797:         return(xmlParseEntityRef(ctxt));
1.24      daniel   2798:     }
1.46      daniel   2799:     return(NULL);
1.24      daniel   2800: }
                   2801: 
1.50      daniel   2802: /**
                   2803:  * xmlParsePEReference:
                   2804:  * @ctxt:  an XML parser context
                   2805:  *
                   2806:  * parse PEReference declarations
1.22      daniel   2807:  *
                   2808:  * [69] PEReference ::= '%' Name ';'
1.68      daniel   2809:  *
                   2810:  * Returns the entity content or NULL if handled directly.
1.22      daniel   2811:  */
1.55      daniel   2812: CHAR *
                   2813: xmlParsePEReference(xmlParserCtxtPtr ctxt) {
1.46      daniel   2814:     CHAR *ret = NULL;
1.22      daniel   2815:     CHAR *name;
1.72      daniel   2816:     xmlEntityPtr entity = NULL;
1.50      daniel   2817:     xmlParserInputPtr input;
1.22      daniel   2818: 
1.40      daniel   2819:     if (CUR == '%') {
                   2820:         NEXT;
1.22      daniel   2821:         name = xmlParseName(ctxt);
                   2822:        if (name == NULL) {
1.55      daniel   2823:            if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74    ! daniel   2824:                ctxt->sax->error(ctxt->userData, "xmlParsePEReference: no name\n");
1.59      daniel   2825:            ctxt->wellFormed = 0;
1.22      daniel   2826:        } else {
1.40      daniel   2827:            if (CUR == ';') {
                   2828:                NEXT;
1.72      daniel   2829:                if ((ctxt->sax != NULL) && (ctxt->sax->getEntity != NULL))
1.74    ! daniel   2830:                        entity = ctxt->sax->getEntity(ctxt->userData, name);
1.72      daniel   2831:                /* TODO !!!! Must check that it's of the proper type !!! */
1.45      daniel   2832:                if (entity == NULL) {
1.55      daniel   2833:                    if ((ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
1.74    ! daniel   2834:                        ctxt->sax->warning(ctxt->userData,
1.59      daniel   2835:                         "xmlParsePEReference: %%%s; not found\n", name);
1.50      daniel   2836:                } else {
                   2837:                    input = xmlNewEntityInputStream(ctxt, entity);
                   2838:                    xmlPushInput(ctxt, input);
1.45      daniel   2839:                }
1.22      daniel   2840:            } else {
1.50      daniel   2841:                char cst[2] = { '%', 0 };
1.46      daniel   2842: 
1.55      daniel   2843:                if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74    ! daniel   2844:                    ctxt->sax->error(ctxt->userData,
1.59      daniel   2845:                                     "xmlParsePEReference: expecting ';'\n");
                   2846:                ctxt->wellFormed = 0;
1.46      daniel   2847:                ret = xmlStrndup(cst, 1);
                   2848:                ret = xmlStrcat(ret, name);
1.22      daniel   2849:            }
1.45      daniel   2850:            free(name);
1.3       veillard 2851:        }
                   2852:     }
1.46      daniel   2853:     return(ret);
1.3       veillard 2854: }
                   2855: 
1.50      daniel   2856: /**
                   2857:  * xmlParseDocTypeDecl :
                   2858:  * @ctxt:  an XML parser context
                   2859:  *
                   2860:  * parse a DOCTYPE declaration
1.21      daniel   2861:  *
1.22      daniel   2862:  * [28] doctypedecl ::= '<!DOCTYPE' S Name (S ExternalID)? S? 
                   2863:  *                      ('[' (markupdecl | PEReference | S)* ']' S?)? '>'
1.21      daniel   2864:  */
                   2865: 
1.55      daniel   2866: void
                   2867: xmlParseDocTypeDecl(xmlParserCtxtPtr ctxt) {
1.21      daniel   2868:     CHAR *name;
                   2869:     CHAR *ExternalID = NULL;
1.39      daniel   2870:     CHAR *URI = NULL;
1.21      daniel   2871: 
                   2872:     /*
                   2873:      * We know that '<!DOCTYPE' has been detected.
                   2874:      */
1.40      daniel   2875:     SKIP(9);
1.21      daniel   2876: 
1.42      daniel   2877:     SKIP_BLANKS;
1.21      daniel   2878: 
                   2879:     /*
                   2880:      * Parse the DOCTYPE name.
                   2881:      */
                   2882:     name = xmlParseName(ctxt);
                   2883:     if (name == NULL) {
1.55      daniel   2884:        if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74    ! daniel   2885:            ctxt->sax->error(ctxt->userData, "xmlParseDocTypeDecl : no DOCTYPE name !\n");
1.59      daniel   2886:        ctxt->wellFormed = 0;
1.21      daniel   2887:     }
                   2888: 
1.42      daniel   2889:     SKIP_BLANKS;
1.21      daniel   2890: 
                   2891:     /*
1.22      daniel   2892:      * Check for SystemID and ExternalID
                   2893:      */
1.67      daniel   2894:     URI = xmlParseExternalID(ctxt, &ExternalID, 1);
1.42      daniel   2895:     SKIP_BLANKS;
1.36      daniel   2896: 
1.72      daniel   2897:     if ((ctxt->sax != NULL) && (ctxt->sax->internalSubset != NULL))
1.74    ! daniel   2898:        ctxt->sax->internalSubset(ctxt->userData, name, ExternalID, URI);
1.22      daniel   2899: 
                   2900:     /*
                   2901:      * Is there any DTD definition ?
                   2902:      */
1.40      daniel   2903:     if (CUR == '[') {
                   2904:         NEXT;
1.22      daniel   2905:        /*
                   2906:         * Parse the succession of Markup declarations and 
                   2907:         * PEReferences.
                   2908:         * Subsequence (markupdecl | PEReference | S)*
                   2909:         */
1.40      daniel   2910:        while (CUR != ']') {
                   2911:            const CHAR *check = CUR_PTR;
1.22      daniel   2912: 
1.42      daniel   2913:            SKIP_BLANKS;
1.22      daniel   2914:            xmlParseMarkupDecl(ctxt);
1.50      daniel   2915:            xmlParsePEReference(ctxt);
1.22      daniel   2916: 
1.40      daniel   2917:            if (CUR_PTR == check) {
1.55      daniel   2918:                if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74    ! daniel   2919:                    ctxt->sax->error(ctxt->userData, 
1.31      daniel   2920:                 "xmlParseDocTypeDecl: error detected in Markup declaration\n");
1.59      daniel   2921:                ctxt->wellFormed = 0;
1.22      daniel   2922:                break;
                   2923:            }
                   2924:        }
1.40      daniel   2925:        if (CUR == ']') NEXT;
1.22      daniel   2926:     }
                   2927: 
                   2928:     /*
                   2929:      * We should be at the end of the DOCTYPE declaration.
1.21      daniel   2930:      */
1.40      daniel   2931:     if (CUR != '>') {
1.55      daniel   2932:        if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74    ! daniel   2933:            ctxt->sax->error(ctxt->userData, "DOCTYPE unproperly terminated\n");
1.59      daniel   2934:        ctxt->wellFormed = 0;
1.22      daniel   2935:         /* We shouldn't try to resynchronize ... */
1.21      daniel   2936:     }
1.40      daniel   2937:     NEXT;
1.22      daniel   2938: 
                   2939:     /*
                   2940:      * Cleanup, since we don't use all those identifiers
                   2941:      * TODO : the DOCTYPE if available should be stored !
                   2942:      */
1.39      daniel   2943:     if (URI != NULL) free(URI);
1.22      daniel   2944:     if (ExternalID != NULL) free(ExternalID);
                   2945:     if (name != NULL) free(name);
1.21      daniel   2946: }
                   2947: 
1.50      daniel   2948: /**
                   2949:  * xmlParseAttribute:
                   2950:  * @ctxt:  an XML parser context
1.72      daniel   2951:  * @value:  a CHAR ** used to store the value of the attribute
1.50      daniel   2952:  *
                   2953:  * parse an attribute
1.3       veillard 2954:  *
1.22      daniel   2955:  * [41] Attribute ::= Name Eq AttValue
                   2956:  *
                   2957:  * [25] Eq ::= S? '=' S?
                   2958:  *
1.29      daniel   2959:  * With namespace:
                   2960:  *
                   2961:  * [NS 11] Attribute ::= QName Eq AttValue
1.43      daniel   2962:  *
                   2963:  * Also the case QName == xmlns:??? is handled independently as a namespace
                   2964:  * definition.
1.69      daniel   2965:  *
1.72      daniel   2966:  * Returns the attribute name, and the value in *value.
1.3       veillard 2967:  */
                   2968: 
1.72      daniel   2969: CHAR *
                   2970: xmlParseAttribute(xmlParserCtxtPtr ctxt, CHAR **value) {
1.59      daniel   2971:     CHAR *name, *val;
1.3       veillard 2972: 
1.72      daniel   2973:     *value = NULL;
                   2974:     name = xmlParseName(ctxt);
1.22      daniel   2975:     if (name == NULL) {
1.55      daniel   2976:        if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74    ! daniel   2977:            ctxt->sax->error(ctxt->userData, "error parsing attribute name\n");
1.59      daniel   2978:        ctxt->wellFormed = 0;
1.52      daniel   2979:         return(NULL);
1.3       veillard 2980:     }
                   2981: 
                   2982:     /*
1.29      daniel   2983:      * read the value
1.3       veillard 2984:      */
1.42      daniel   2985:     SKIP_BLANKS;
1.40      daniel   2986:     if (CUR == '=') {
                   2987:         NEXT;
1.42      daniel   2988:        SKIP_BLANKS;
1.72      daniel   2989:        val = xmlParseAttValue(ctxt);
1.29      daniel   2990:     } else {
1.55      daniel   2991:        if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74    ! daniel   2992:            ctxt->sax->error(ctxt->userData,
1.59      daniel   2993:               "Specification mandate value for attribute %s\n", name);
                   2994:        ctxt->wellFormed = 0;
1.52      daniel   2995:        return(NULL);
1.43      daniel   2996:     }
                   2997: 
1.72      daniel   2998:     *value = val;
                   2999:     return(name);
1.3       veillard 3000: }
                   3001: 
1.50      daniel   3002: /**
                   3003:  * xmlParseStartTag:
                   3004:  * @ctxt:  an XML parser context
                   3005:  * 
                   3006:  * parse a start of tag either for rule element or
                   3007:  * EmptyElement. In both case we don't parse the tag closing chars.
1.27      daniel   3008:  *
                   3009:  * [40] STag ::= '<' Name (S Attribute)* S? '>'
                   3010:  *
1.29      daniel   3011:  * [44] EmptyElemTag ::= '<' Name (S Attribute)* S? '/>'
                   3012:  *
                   3013:  * With namespace:
                   3014:  *
                   3015:  * [NS 8] STag ::= '<' QName (S Attribute)* S? '>'
                   3016:  *
                   3017:  * [NS 10] EmptyElement ::= '<' QName (S Attribute)* S? '/>'
1.2       veillard 3018:  */
                   3019: 
1.72      daniel   3020: void
1.69      daniel   3021: xmlParseStartTag(xmlParserCtxtPtr ctxt) {
1.72      daniel   3022:     CHAR *name;
                   3023:     CHAR *attname;
                   3024:     CHAR *attvalue;
                   3025:     const CHAR **atts = NULL;
                   3026:     int nbatts = 0;
                   3027:     int maxatts = 0;
                   3028:     int i;
1.2       veillard 3029: 
1.72      daniel   3030:     if (CUR != '<') return;
1.40      daniel   3031:     NEXT;
1.3       veillard 3032: 
1.72      daniel   3033:     name = xmlParseName(ctxt);
1.59      daniel   3034:     if (name == NULL) {
                   3035:        if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74    ! daniel   3036:            ctxt->sax->error(ctxt->userData, 
1.59      daniel   3037:             "xmlParseStartTag: invalid element name\n");
                   3038:        ctxt->wellFormed = 0;
1.72      daniel   3039:         return;
1.50      daniel   3040:     }
                   3041: 
                   3042:     /*
1.3       veillard 3043:      * Now parse the attributes, it ends up with the ending
                   3044:      *
                   3045:      * (S Attribute)* S?
                   3046:      */
1.42      daniel   3047:     SKIP_BLANKS;
1.40      daniel   3048:     while ((IS_CHAR(CUR)) &&
                   3049:            (CUR != '>') && 
                   3050:           ((CUR != '/') || (NXT(1) != '>'))) {
                   3051:        const CHAR *q = CUR_PTR;
1.29      daniel   3052: 
1.72      daniel   3053:        attname = xmlParseAttribute(ctxt, &attvalue);
                   3054:         if ((attname != NULL) && (attvalue != NULL)) {
                   3055:            /*
                   3056:             * Well formedness requires at most one declaration of an attribute
                   3057:             */
                   3058:            for (i = 0; i < nbatts;i += 2) {
                   3059:                if (!xmlStrcmp(atts[i], attname)) {
                   3060:                    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74    ! daniel   3061:                        ctxt->sax->error(ctxt->userData, "Attribute %s redefined\n",
1.72      daniel   3062:                                         name);
                   3063:                    ctxt->wellFormed = 0;
                   3064:                    free(attname);
                   3065:                    free(attvalue);
                   3066:                    break;
                   3067:                }
                   3068:            }
                   3069: 
                   3070:            /*
                   3071:             * Add the pair to atts
                   3072:             */
                   3073:            if (atts == NULL) {
                   3074:                maxatts = 10;
                   3075:                atts = (const CHAR **) malloc(maxatts * sizeof(CHAR *));
                   3076:                if (atts == NULL) {
                   3077:                    fprintf(stderr, "malloc of %d byte failed\n",
                   3078:                            maxatts * sizeof(CHAR *));
                   3079:                    return;
                   3080:                }
                   3081:            } else if (nbatts + 2 < maxatts) {
                   3082:                maxatts *= 2;
                   3083:                atts = (const CHAR **) realloc(atts, maxatts * sizeof(CHAR *));
                   3084:                if (atts == NULL) {
                   3085:                    fprintf(stderr, "realloc of %d byte failed\n",
                   3086:                            maxatts * sizeof(CHAR *));
                   3087:                    return;
                   3088:                }
                   3089:            }
                   3090:            atts[nbatts++] = attname;
                   3091:            atts[nbatts++] = attvalue;
                   3092:            atts[nbatts] = NULL;
                   3093:            atts[nbatts + 1] = NULL;
                   3094:        }
                   3095: 
1.42      daniel   3096:        SKIP_BLANKS;
1.40      daniel   3097:         if (q == CUR_PTR) {
1.55      daniel   3098:            if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74    ! daniel   3099:                ctxt->sax->error(ctxt->userData, 
1.31      daniel   3100:                 "xmlParseStartTag: problem parsing attributes\n");
1.59      daniel   3101:            ctxt->wellFormed = 0;
1.29      daniel   3102:            break;
1.3       veillard 3103:        }
                   3104:     }
                   3105: 
1.43      daniel   3106:     /*
1.72      daniel   3107:      * SAX: Start of Element !
1.43      daniel   3108:      */
1.72      daniel   3109:     if ((ctxt->sax != NULL) && (ctxt->sax->startElement != NULL))
1.74    ! daniel   3110:         ctxt->sax->startElement(ctxt->userData, name, atts);
1.43      daniel   3111: 
1.52      daniel   3112:     free(name);
1.72      daniel   3113:     if (atts != NULL) {
                   3114:         for (i = 0;i < nbatts;i++) free((CHAR *) atts[i]);
                   3115:        free(atts);
                   3116:     }
1.3       veillard 3117: }
                   3118: 
1.50      daniel   3119: /**
                   3120:  * xmlParseEndTag:
                   3121:  * @ctxt:  an XML parser context
                   3122:  *
                   3123:  * parse an end of tag
1.27      daniel   3124:  *
                   3125:  * [42] ETag ::= '</' Name S? '>'
1.29      daniel   3126:  *
                   3127:  * With namespace
                   3128:  *
1.72      daniel   3129:  * [NS 9] ETag ::= '</' QName S? '>'
1.7       veillard 3130:  */
                   3131: 
1.55      daniel   3132: void
1.72      daniel   3133: xmlParseEndTag(xmlParserCtxtPtr ctxt) {
                   3134:     CHAR *name;
1.7       veillard 3135: 
1.40      daniel   3136:     if ((CUR != '<') || (NXT(1) != '/')) {
1.55      daniel   3137:        if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74    ! daniel   3138:            ctxt->sax->error(ctxt->userData, "xmlParseEndTag: '</' not found\n");
1.59      daniel   3139:        ctxt->wellFormed = 0;
1.27      daniel   3140:        return;
                   3141:     }
1.40      daniel   3142:     SKIP(2);
1.7       veillard 3143: 
1.72      daniel   3144:     name = xmlParseName(ctxt);
1.7       veillard 3145: 
                   3146:     /*
                   3147:      * We should definitely be at the ending "S? '>'" part
                   3148:      */
1.42      daniel   3149:     SKIP_BLANKS;
1.40      daniel   3150:     if ((!IS_CHAR(CUR)) || (CUR != '>')) {
1.55      daniel   3151:        if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74    ! daniel   3152:            ctxt->sax->error(ctxt->userData, "End tag : expected '>'\n");
1.59      daniel   3153:        ctxt->wellFormed = 0;
1.7       veillard 3154:     } else
1.40      daniel   3155:        NEXT;
1.7       veillard 3156: 
1.72      daniel   3157:     /*
                   3158:      * SAX: End of Tag
                   3159:      */
                   3160:     if ((ctxt->sax != NULL) && (ctxt->sax->endElement != NULL))
1.74    ! daniel   3161:         ctxt->sax->endElement(ctxt->userData, name);
1.72      daniel   3162: 
                   3163:     if (name != NULL)
                   3164:        free(name);
                   3165: 
1.7       veillard 3166:     return;
                   3167: }
                   3168: 
1.50      daniel   3169: /**
                   3170:  * xmlParseCDSect:
                   3171:  * @ctxt:  an XML parser context
                   3172:  * 
                   3173:  * Parse escaped pure raw content.
1.29      daniel   3174:  *
                   3175:  * [18] CDSect ::= CDStart CData CDEnd
                   3176:  *
                   3177:  * [19] CDStart ::= '<![CDATA['
                   3178:  *
                   3179:  * [20] Data ::= (Char* - (Char* ']]>' Char*))
                   3180:  *
                   3181:  * [21] CDEnd ::= ']]>'
1.3       veillard 3182:  */
1.55      daniel   3183: void
                   3184: xmlParseCDSect(xmlParserCtxtPtr ctxt) {
1.17      daniel   3185:     const CHAR *r, *s, *base;
1.3       veillard 3186: 
1.40      daniel   3187:     if ((CUR == '<') && (NXT(1) == '!') &&
                   3188:        (NXT(2) == '[') && (NXT(3) == 'C') &&
                   3189:        (NXT(4) == 'D') && (NXT(5) == 'A') &&
                   3190:        (NXT(6) == 'T') && (NXT(7) == 'A') &&
                   3191:        (NXT(8) == '[')) {
                   3192:        SKIP(9);
1.29      daniel   3193:     } else
1.45      daniel   3194:         return;
1.40      daniel   3195:     base = CUR_PTR;
                   3196:     if (!IS_CHAR(CUR)) {
1.55      daniel   3197:        if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74    ! daniel   3198:            ctxt->sax->error(ctxt->userData, "CData section not finished\n%.50s\n", base);
1.59      daniel   3199:        ctxt->wellFormed = 0;
1.45      daniel   3200:         return;
1.3       veillard 3201:     }
1.40      daniel   3202:     r = NEXT;
                   3203:     if (!IS_CHAR(CUR)) {
1.55      daniel   3204:        if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74    ! daniel   3205:            ctxt->sax->error(ctxt->userData, "CData section not finished\n%.50s\n", base);
1.59      daniel   3206:        ctxt->wellFormed = 0;
1.45      daniel   3207:         return;
1.3       veillard 3208:     }
1.40      daniel   3209:     s = NEXT;
                   3210:     while (IS_CHAR(CUR) &&
                   3211:            ((*r != ']') || (*s != ']') || (CUR != '>'))) {
                   3212:         r++;s++;NEXT;
1.3       veillard 3213:     }
1.40      daniel   3214:     if (!IS_CHAR(CUR)) {
1.55      daniel   3215:        if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74    ! daniel   3216:            ctxt->sax->error(ctxt->userData, "CData section not finished\n%.50s\n", base);
1.59      daniel   3217:        ctxt->wellFormed = 0;
1.45      daniel   3218:         return;
1.3       veillard 3219:     }
1.16      daniel   3220: 
1.45      daniel   3221:     /*
                   3222:      * Ok the segment [base CUR_PTR] is to be consumed as chars.
                   3223:      */
                   3224:     if (ctxt->sax != NULL) {
1.72      daniel   3225:        if (areBlanks(ctxt, base, CUR_PTR - base)) {
                   3226:            if (ctxt->sax->ignorableWhitespace != NULL)
1.74    ! daniel   3227:                ctxt->sax->ignorableWhitespace(ctxt->userData, base,
1.72      daniel   3228:                                               (CUR_PTR - base) - 2);
                   3229:         } else {
                   3230:            if (ctxt->sax->characters != NULL)
1.74    ! daniel   3231:                ctxt->sax->characters(ctxt->userData, base, (CUR_PTR - base) - 2);
1.72      daniel   3232:         }
1.45      daniel   3233:     }
1.2       veillard 3234: }
                   3235: 
1.50      daniel   3236: /**
                   3237:  * xmlParseContent:
                   3238:  * @ctxt:  an XML parser context
                   3239:  *
                   3240:  * Parse a content:
1.2       veillard 3241:  *
1.27      daniel   3242:  * [43] content ::= (element | CharData | Reference | CDSect | PI | Comment)*
1.2       veillard 3243:  */
                   3244: 
1.55      daniel   3245: void
                   3246: xmlParseContent(xmlParserCtxtPtr ctxt) {
1.40      daniel   3247:     while ((CUR != '<') || (NXT(1) != '/')) {
                   3248:        const CHAR *test = CUR_PTR;
1.27      daniel   3249: 
                   3250:        /*
                   3251:         * First case : a Processing Instruction.
                   3252:         */
1.40      daniel   3253:        if ((CUR == '<') && (NXT(1) == '?')) {
1.27      daniel   3254:            xmlParsePI(ctxt);
                   3255:        }
1.72      daniel   3256: 
1.27      daniel   3257:        /*
                   3258:         * Second case : a CDSection
                   3259:         */
1.40      daniel   3260:        else if ((CUR == '<') && (NXT(1) == '!') &&
                   3261:            (NXT(2) == '[') && (NXT(3) == 'C') &&
                   3262:            (NXT(4) == 'D') && (NXT(5) == 'A') &&
                   3263:            (NXT(6) == 'T') && (NXT(7) == 'A') &&
                   3264:            (NXT(8) == '[')) {
1.45      daniel   3265:            xmlParseCDSect(ctxt);
1.27      daniel   3266:        }
1.72      daniel   3267: 
1.27      daniel   3268:        /*
                   3269:         * Third case :  a comment
                   3270:         */
1.40      daniel   3271:        else if ((CUR == '<') && (NXT(1) == '!') &&
                   3272:                 (NXT(2) == '-') && (NXT(3) == '-')) {
1.72      daniel   3273:            xmlParseComment(ctxt, 1);
1.27      daniel   3274:        }
1.72      daniel   3275: 
1.27      daniel   3276:        /*
                   3277:         * Fourth case :  a sub-element.
                   3278:         */
1.40      daniel   3279:        else if (CUR == '<') {
1.72      daniel   3280:            xmlParseElement(ctxt);
1.45      daniel   3281:        }
1.72      daniel   3282: 
1.45      daniel   3283:        /*
1.50      daniel   3284:         * Fifth case : a reference. If if has not been resolved,
                   3285:         *    parsing returns it's Name, create the node 
1.45      daniel   3286:         */
                   3287:        else if (CUR == '&') {
1.50      daniel   3288:            CHAR *val = xmlParseReference(ctxt);
                   3289:            if (val != NULL) {
                   3290:                if (val[0] != '&') {
                   3291:                    /*
                   3292:                     * inline predefined entity.
                   3293:                     */
1.72      daniel   3294:                     if ((ctxt->sax != NULL) && (ctxt->sax->characters != NULL))
1.74    ! daniel   3295:                        ctxt->sax->characters(ctxt->userData, val, xmlStrlen(val));
1.50      daniel   3296:                } else {
                   3297:                    /*
                   3298:                     * user defined entity, create a node.
                   3299:                     */
1.72      daniel   3300:                     if ((ctxt->sax != NULL) && (ctxt->sax->reference != NULL))
1.74    ! daniel   3301:                        ctxt->sax->reference(ctxt->userData, val);
1.50      daniel   3302:                }
                   3303:                free(val);
                   3304:            }
1.27      daniel   3305:        }
1.72      daniel   3306: 
1.27      daniel   3307:        /*
                   3308:         * Last case, text. Note that References are handled directly.
                   3309:         */
                   3310:        else {
1.45      daniel   3311:            xmlParseCharData(ctxt, 0);
1.3       veillard 3312:        }
1.14      veillard 3313: 
                   3314:        /*
1.45      daniel   3315:         * Pop-up of finished entities.
1.14      veillard 3316:         */
1.69      daniel   3317:        while ((CUR == 0) && (ctxt->inputNr > 1))
                   3318:            xmlPopInput(ctxt);
1.45      daniel   3319: 
1.40      daniel   3320:        if (test == CUR_PTR) {
1.55      daniel   3321:            if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74    ! daniel   3322:                ctxt->sax->error(ctxt->userData,
1.59      daniel   3323:                     "detected an error in element content\n");
                   3324:            ctxt->wellFormed = 0;
1.29      daniel   3325:             break;
                   3326:        }
1.3       veillard 3327:     }
1.2       veillard 3328: }
                   3329: 
1.50      daniel   3330: /**
                   3331:  * xmlParseElement:
                   3332:  * @ctxt:  an XML parser context
                   3333:  *
                   3334:  * parse an XML element, this is highly recursive
1.26      daniel   3335:  *
                   3336:  * [39] element ::= EmptyElemTag | STag content ETag
                   3337:  *
                   3338:  * [41] Attribute ::= Name Eq AttValue
1.2       veillard 3339:  */
1.26      daniel   3340: 
1.72      daniel   3341: void
1.69      daniel   3342: xmlParseElement(xmlParserCtxtPtr ctxt) {
1.40      daniel   3343:     const CHAR *openTag = CUR_PTR;
1.32      daniel   3344:     xmlParserNodeInfo node_info;
1.2       veillard 3345: 
1.32      daniel   3346:     /* Capture start position */
1.40      daniel   3347:     node_info.begin_pos = CUR_PTR - ctxt->input->base;
                   3348:     node_info.begin_line = ctxt->input->line;
1.32      daniel   3349: 
1.72      daniel   3350:     xmlParseStartTag(ctxt);
1.2       veillard 3351: 
                   3352:     /*
                   3353:      * Check for an Empty Element.
                   3354:      */
1.40      daniel   3355:     if ((CUR == '/') && (NXT(1) == '>')) {
                   3356:         SKIP(2);
1.72      daniel   3357:        if ((ctxt->sax != NULL) && (ctxt->sax->endElement != NULL))
1.74    ! daniel   3358:            ctxt->sax->endElement(ctxt->userData, NULL);
1.72      daniel   3359:        return;
1.2       veillard 3360:     }
1.40      daniel   3361:     if (CUR == '>') NEXT;
1.2       veillard 3362:     else {
1.55      daniel   3363:        if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74    ! daniel   3364:            ctxt->sax->error(ctxt->userData, "Couldn't find end of Start Tag\n%.30s\n",
1.57      daniel   3365:                             openTag);
1.59      daniel   3366:        ctxt->wellFormed = 0;
1.45      daniel   3367: 
                   3368:        /*
                   3369:         * end of parsing of this node.
1.72      daniel   3370:         * TODO !!!!!!!! check the macro in case of non DOM parsing
1.45      daniel   3371:         */
                   3372:        nodePop(ctxt);
                   3373: 
1.72      daniel   3374:        return;
1.2       veillard 3375:     }
                   3376: 
                   3377:     /*
                   3378:      * Parse the content of the element:
                   3379:      */
1.45      daniel   3380:     xmlParseContent(ctxt);
1.40      daniel   3381:     if (!IS_CHAR(CUR)) {
1.55      daniel   3382:        if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74    ! daniel   3383:            ctxt->sax->error(ctxt->userData,
1.57      daniel   3384:                 "Premature end of data in tag %.30s\n", openTag);
1.59      daniel   3385:        ctxt->wellFormed = 0;
1.45      daniel   3386: 
                   3387:        /*
                   3388:         * end of parsing of this node.
1.72      daniel   3389:         * TODO !!!!!!!! check the macro in case of non DOM parsing
1.45      daniel   3390:         */
                   3391:        nodePop(ctxt);
                   3392: 
1.72      daniel   3393:        return;
1.2       veillard 3394:     }
                   3395: 
                   3396:     /*
1.27      daniel   3397:      * parse the end of tag: '</' should be here.
1.2       veillard 3398:      */
1.72      daniel   3399:     xmlParseEndTag(ctxt);
1.2       veillard 3400: }
                   3401: 
1.50      daniel   3402: /**
                   3403:  * xmlParseVersionNum:
                   3404:  * @ctxt:  an XML parser context
                   3405:  *
                   3406:  * parse the XML version value.
1.29      daniel   3407:  *
                   3408:  * [26] VersionNum ::= ([a-zA-Z0-9_.:] | '-')+
1.68      daniel   3409:  *
                   3410:  * Returns the string giving the XML version number, or NULL
1.29      daniel   3411:  */
1.55      daniel   3412: CHAR *
                   3413: xmlParseVersionNum(xmlParserCtxtPtr ctxt) {
1.40      daniel   3414:     const CHAR *q = CUR_PTR;
1.29      daniel   3415:     CHAR *ret;
                   3416: 
1.40      daniel   3417:     while (IS_CHAR(CUR) &&
                   3418:            (((CUR >= 'a') && (CUR <= 'z')) ||
                   3419:             ((CUR >= 'A') && (CUR <= 'Z')) ||
                   3420:             ((CUR >= '0') && (CUR <= '9')) ||
                   3421:             (CUR == '_') || (CUR == '.') ||
                   3422:            (CUR == ':') || (CUR == '-'))) NEXT;
                   3423:     ret = xmlStrndup(q, CUR_PTR - q);
1.29      daniel   3424:     return(ret);
                   3425: }
                   3426: 
1.50      daniel   3427: /**
                   3428:  * xmlParseVersionInfo:
                   3429:  * @ctxt:  an XML parser context
                   3430:  * 
                   3431:  * parse the XML version.
1.29      daniel   3432:  *
                   3433:  * [24] VersionInfo ::= S 'version' Eq (' VersionNum ' | " VersionNum ")
                   3434:  * 
                   3435:  * [25] Eq ::= S? '=' S?
1.50      daniel   3436:  *
1.68      daniel   3437:  * Returns the version string, e.g. "1.0"
1.29      daniel   3438:  */
                   3439: 
1.55      daniel   3440: CHAR *
                   3441: xmlParseVersionInfo(xmlParserCtxtPtr ctxt) {
1.29      daniel   3442:     CHAR *version = NULL;
                   3443:     const CHAR *q;
                   3444: 
1.40      daniel   3445:     if ((CUR == 'v') && (NXT(1) == 'e') &&
                   3446:         (NXT(2) == 'r') && (NXT(3) == 's') &&
                   3447:        (NXT(4) == 'i') && (NXT(5) == 'o') &&
                   3448:        (NXT(6) == 'n')) {
                   3449:        SKIP(7);
1.42      daniel   3450:        SKIP_BLANKS;
1.40      daniel   3451:        if (CUR != '=') {
1.55      daniel   3452:            if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74    ! daniel   3453:                ctxt->sax->error(ctxt->userData, "xmlParseVersionInfo : expected '='\n");
1.59      daniel   3454:            ctxt->wellFormed = 0;
1.31      daniel   3455:            return(NULL);
                   3456:         }
1.40      daniel   3457:        NEXT;
1.42      daniel   3458:        SKIP_BLANKS;
1.40      daniel   3459:        if (CUR == '"') {
                   3460:            NEXT;
                   3461:            q = CUR_PTR;
1.29      daniel   3462:            version = xmlParseVersionNum(ctxt);
1.55      daniel   3463:            if (CUR != '"') {
                   3464:                if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74    ! daniel   3465:                    ctxt->sax->error(ctxt->userData, "String not closed\n%.50s\n", q);
1.59      daniel   3466:                ctxt->wellFormed = 0;
1.55      daniel   3467:            } else
1.40      daniel   3468:                NEXT;
                   3469:        } else if (CUR == '\''){
                   3470:            NEXT;
                   3471:            q = CUR_PTR;
1.29      daniel   3472:            version = xmlParseVersionNum(ctxt);
1.55      daniel   3473:            if (CUR != '\'') {
                   3474:                if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74    ! daniel   3475:                    ctxt->sax->error(ctxt->userData, "String not closed\n%.50s\n", q);
1.59      daniel   3476:                ctxt->wellFormed = 0;
1.55      daniel   3477:            } else
1.40      daniel   3478:                NEXT;
1.31      daniel   3479:        } else {
1.55      daniel   3480:            if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74    ! daniel   3481:                ctxt->sax->error(ctxt->userData,
1.59      daniel   3482:                      "xmlParseVersionInfo : expected ' or \"\n");
                   3483:                ctxt->wellFormed = 0;
1.29      daniel   3484:        }
                   3485:     }
                   3486:     return(version);
                   3487: }
                   3488: 
1.50      daniel   3489: /**
                   3490:  * xmlParseEncName:
                   3491:  * @ctxt:  an XML parser context
                   3492:  *
                   3493:  * parse the XML encoding name
1.29      daniel   3494:  *
                   3495:  * [81] EncName ::= [A-Za-z] ([A-Za-z0-9._] | '-')*
1.50      daniel   3496:  *
1.68      daniel   3497:  * Returns the encoding name value or NULL
1.29      daniel   3498:  */
1.55      daniel   3499: CHAR *
                   3500: xmlParseEncName(xmlParserCtxtPtr ctxt) {
1.40      daniel   3501:     const CHAR *q = CUR_PTR;
1.29      daniel   3502:     CHAR *ret = NULL;
                   3503: 
1.40      daniel   3504:     if (((CUR >= 'a') && (CUR <= 'z')) ||
                   3505:         ((CUR >= 'A') && (CUR <= 'Z'))) {
                   3506:        NEXT;
                   3507:        while (IS_CHAR(CUR) &&
                   3508:               (((CUR >= 'a') && (CUR <= 'z')) ||
                   3509:                ((CUR >= 'A') && (CUR <= 'Z')) ||
                   3510:                ((CUR >= '0') && (CUR <= '9')) ||
                   3511:                (CUR == '-'))) NEXT;
                   3512:        ret = xmlStrndup(q, CUR_PTR - q);
1.29      daniel   3513:     } else {
1.55      daniel   3514:        if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74    ! daniel   3515:            ctxt->sax->error(ctxt->userData, "Invalid XML encoding name\n");
1.59      daniel   3516:        ctxt->wellFormed = 0;
1.29      daniel   3517:     }
                   3518:     return(ret);
                   3519: }
                   3520: 
1.50      daniel   3521: /**
                   3522:  * xmlParseEncodingDecl:
                   3523:  * @ctxt:  an XML parser context
                   3524:  * 
                   3525:  * parse the XML encoding declaration
1.29      daniel   3526:  *
                   3527:  * [80] EncodingDecl ::= S 'encoding' Eq ('"' EncName '"' |  "'" EncName "'")
1.50      daniel   3528:  *
                   3529:  * TODO: this should setup the conversion filters.
                   3530:  *
1.68      daniel   3531:  * Returns the encoding value or NULL
1.29      daniel   3532:  */
                   3533: 
1.55      daniel   3534: CHAR *
                   3535: xmlParseEncodingDecl(xmlParserCtxtPtr ctxt) {
1.29      daniel   3536:     CHAR *encoding = NULL;
                   3537:     const CHAR *q;
                   3538: 
1.42      daniel   3539:     SKIP_BLANKS;
1.40      daniel   3540:     if ((CUR == 'e') && (NXT(1) == 'n') &&
                   3541:         (NXT(2) == 'c') && (NXT(3) == 'o') &&
                   3542:        (NXT(4) == 'd') && (NXT(5) == 'i') &&
                   3543:        (NXT(6) == 'n') && (NXT(7) == 'g')) {
                   3544:        SKIP(8);
1.42      daniel   3545:        SKIP_BLANKS;
1.40      daniel   3546:        if (CUR != '=') {
1.55      daniel   3547:            if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74    ! daniel   3548:                ctxt->sax->error(ctxt->userData, "xmlParseEncodingDecl : expected '='\n");
1.59      daniel   3549:            ctxt->wellFormed = 0;
1.31      daniel   3550:            return(NULL);
                   3551:         }
1.40      daniel   3552:        NEXT;
1.42      daniel   3553:        SKIP_BLANKS;
1.40      daniel   3554:        if (CUR == '"') {
                   3555:            NEXT;
                   3556:            q = CUR_PTR;
1.29      daniel   3557:            encoding = xmlParseEncName(ctxt);
1.55      daniel   3558:            if (CUR != '"') {
                   3559:                if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74    ! daniel   3560:                    ctxt->sax->error(ctxt->userData, "String not closed\n%.50s\n", q);
1.59      daniel   3561:                ctxt->wellFormed = 0;
1.55      daniel   3562:            } else
1.40      daniel   3563:                NEXT;
                   3564:        } else if (CUR == '\''){
                   3565:            NEXT;
                   3566:            q = CUR_PTR;
1.29      daniel   3567:            encoding = xmlParseEncName(ctxt);
1.55      daniel   3568:            if (CUR != '\'') {
                   3569:                if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74    ! daniel   3570:                    ctxt->sax->error(ctxt->userData, "String not closed\n%.50s\n", q);
1.59      daniel   3571:                ctxt->wellFormed = 0;
1.55      daniel   3572:            } else
1.40      daniel   3573:                NEXT;
                   3574:        } else if (CUR == '"'){
1.55      daniel   3575:            if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74    ! daniel   3576:                ctxt->sax->error(ctxt->userData,
1.59      daniel   3577:                     "xmlParseEncodingDecl : expected ' or \"\n");
                   3578:            ctxt->wellFormed = 0;
1.29      daniel   3579:        }
                   3580:     }
                   3581:     return(encoding);
                   3582: }
                   3583: 
1.50      daniel   3584: /**
                   3585:  * xmlParseSDDecl:
                   3586:  * @ctxt:  an XML parser context
                   3587:  *
                   3588:  * parse the XML standalone declaration
1.29      daniel   3589:  *
                   3590:  * [32] SDDecl ::= S 'standalone' Eq
                   3591:  *                 (("'" ('yes' | 'no') "'") | ('"' ('yes' | 'no')'"')) 
1.68      daniel   3592:  *
                   3593:  * Returns 1 if standalone, 0 otherwise
1.29      daniel   3594:  */
                   3595: 
1.55      daniel   3596: int
                   3597: xmlParseSDDecl(xmlParserCtxtPtr ctxt) {
1.29      daniel   3598:     int standalone = -1;
                   3599: 
1.42      daniel   3600:     SKIP_BLANKS;
1.40      daniel   3601:     if ((CUR == 's') && (NXT(1) == 't') &&
                   3602:         (NXT(2) == 'a') && (NXT(3) == 'n') &&
                   3603:        (NXT(4) == 'd') && (NXT(5) == 'a') &&
                   3604:        (NXT(6) == 'l') && (NXT(7) == 'o') &&
                   3605:        (NXT(8) == 'n') && (NXT(9) == 'e')) {
                   3606:        SKIP(10);
                   3607:        if (CUR != '=') {
1.55      daniel   3608:            if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74    ! daniel   3609:                ctxt->sax->error(ctxt->userData,
1.59      daniel   3610:                    "XML standalone declaration : expected '='\n");
                   3611:            ctxt->wellFormed = 0;
1.32      daniel   3612:            return(standalone);
                   3613:         }
1.40      daniel   3614:        NEXT;
1.42      daniel   3615:        SKIP_BLANKS;
1.40      daniel   3616:         if (CUR == '\''){
                   3617:            NEXT;
                   3618:            if ((CUR == 'n') && (NXT(1) == 'o')) {
1.29      daniel   3619:                standalone = 0;
1.40      daniel   3620:                 SKIP(2);
                   3621:            } else if ((CUR == 'y') && (NXT(1) == 'e') &&
                   3622:                       (NXT(2) == 's')) {
1.29      daniel   3623:                standalone = 1;
1.40      daniel   3624:                SKIP(3);
1.29      daniel   3625:             } else {
1.55      daniel   3626:                if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74    ! daniel   3627:                    ctxt->sax->error(ctxt->userData, "standalone accepts only 'yes' or 'no'\n");
1.59      daniel   3628:                ctxt->wellFormed = 0;
1.29      daniel   3629:            }
1.55      daniel   3630:            if (CUR != '\'') {
                   3631:                if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74    ! daniel   3632:                    ctxt->sax->error(ctxt->userData, "String not closed\n");
1.59      daniel   3633:                ctxt->wellFormed = 0;
1.55      daniel   3634:            } else
1.40      daniel   3635:                NEXT;
                   3636:        } else if (CUR == '"'){
                   3637:            NEXT;
                   3638:            if ((CUR == 'n') && (NXT(1) == 'o')) {
1.29      daniel   3639:                standalone = 0;
1.40      daniel   3640:                SKIP(2);
                   3641:            } else if ((CUR == 'y') && (NXT(1) == 'e') &&
                   3642:                       (NXT(2) == 's')) {
1.29      daniel   3643:                standalone = 1;
1.40      daniel   3644:                 SKIP(3);
1.29      daniel   3645:             } else {
1.55      daniel   3646:                if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74    ! daniel   3647:                    ctxt->sax->error(ctxt->userData,
1.59      daniel   3648:                        "standalone accepts only 'yes' or 'no'\n");
                   3649:                ctxt->wellFormed = 0;
1.29      daniel   3650:            }
1.55      daniel   3651:            if (CUR != '"') {
                   3652:                if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74    ! daniel   3653:                    ctxt->sax->error(ctxt->userData, "String not closed\n");
1.59      daniel   3654:                ctxt->wellFormed = 0;
1.55      daniel   3655:            } else
1.40      daniel   3656:                NEXT;
1.37      daniel   3657:        } else {
1.55      daniel   3658:             if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74    ! daniel   3659:                ctxt->sax->error(ctxt->userData, "Standalone value not found\n");
1.59      daniel   3660:            ctxt->wellFormed = 0;
1.37      daniel   3661:         }
1.29      daniel   3662:     }
                   3663:     return(standalone);
                   3664: }
                   3665: 
1.50      daniel   3666: /**
                   3667:  * xmlParseXMLDecl:
                   3668:  * @ctxt:  an XML parser context
                   3669:  * 
                   3670:  * parse an XML declaration header
1.29      daniel   3671:  *
                   3672:  * [23] XMLDecl ::= '<?xml' VersionInfo EncodingDecl? SDDecl? S? '?>'
1.1       veillard 3673:  */
                   3674: 
1.55      daniel   3675: void
                   3676: xmlParseXMLDecl(xmlParserCtxtPtr ctxt) {
1.1       veillard 3677:     CHAR *version;
                   3678: 
                   3679:     /*
1.19      daniel   3680:      * We know that '<?xml' is here.
1.1       veillard 3681:      */
1.40      daniel   3682:     SKIP(5);
1.1       veillard 3683: 
1.59      daniel   3684:     if (!IS_BLANK(CUR)) {
                   3685:        if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74    ! daniel   3686:            ctxt->sax->error(ctxt->userData, "Blank needed after '<?xml'\n");
1.59      daniel   3687:        ctxt->wellFormed = 0;
                   3688:     }
1.42      daniel   3689:     SKIP_BLANKS;
1.1       veillard 3690: 
                   3691:     /*
1.29      daniel   3692:      * We should have the VersionInfo here.
1.1       veillard 3693:      */
1.29      daniel   3694:     version = xmlParseVersionInfo(ctxt);
                   3695:     if (version == NULL)
1.45      daniel   3696:        version = xmlCharStrdup(XML_DEFAULT_VERSION);
1.72      daniel   3697:     ctxt->version = xmlStrdup(version);
1.45      daniel   3698:     free(version);
1.29      daniel   3699: 
                   3700:     /*
                   3701:      * We may have the encoding declaration
                   3702:      */
1.59      daniel   3703:     if (!IS_BLANK(CUR)) {
                   3704:         if ((CUR == '?') && (NXT(1) == '>')) {
                   3705:            SKIP(2);
                   3706:            return;
                   3707:        }
                   3708:        if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74    ! daniel   3709:            ctxt->sax->error(ctxt->userData, "Blank needed here\n");
1.59      daniel   3710:        ctxt->wellFormed = 0;
                   3711:     }
1.72      daniel   3712:     ctxt->encoding = xmlParseEncodingDecl(ctxt);
1.1       veillard 3713: 
                   3714:     /*
1.29      daniel   3715:      * We may have the standalone status.
1.1       veillard 3716:      */
1.72      daniel   3717:     if ((ctxt->encoding != NULL) && (!IS_BLANK(CUR))) {
1.59      daniel   3718:         if ((CUR == '?') && (NXT(1) == '>')) {
                   3719:            SKIP(2);
                   3720:            return;
                   3721:        }
                   3722:        if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74    ! daniel   3723:            ctxt->sax->error(ctxt->userData, "Blank needed here\n");
1.59      daniel   3724:        ctxt->wellFormed = 0;
                   3725:     }
                   3726:     SKIP_BLANKS;
1.72      daniel   3727:     ctxt->standalone = xmlParseSDDecl(ctxt);
1.1       veillard 3728: 
1.42      daniel   3729:     SKIP_BLANKS;
1.40      daniel   3730:     if ((CUR == '?') && (NXT(1) == '>')) {
                   3731:         SKIP(2);
                   3732:     } else if (CUR == '>') {
1.31      daniel   3733:         /* Deprecated old WD ... */
1.55      daniel   3734:        if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74    ! daniel   3735:            ctxt->sax->error(ctxt->userData, "XML declaration must end-up with '?>'\n");
1.59      daniel   3736:        ctxt->wellFormed = 0;
1.40      daniel   3737:        NEXT;
1.29      daniel   3738:     } else {
1.55      daniel   3739:        if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74    ! daniel   3740:            ctxt->sax->error(ctxt->userData, "parsing XML declaration: '?>' expected\n");
1.59      daniel   3741:        ctxt->wellFormed = 0;
1.40      daniel   3742:        MOVETO_ENDTAG(CUR_PTR);
                   3743:        NEXT;
1.29      daniel   3744:     }
1.1       veillard 3745: }
                   3746: 
1.50      daniel   3747: /**
                   3748:  * xmlParseMisc:
                   3749:  * @ctxt:  an XML parser context
                   3750:  * 
                   3751:  * parse an XML Misc* optionnal field.
1.21      daniel   3752:  *
1.22      daniel   3753:  * [27] Misc ::= Comment | PI |  S
1.1       veillard 3754:  */
                   3755: 
1.55      daniel   3756: void
                   3757: xmlParseMisc(xmlParserCtxtPtr ctxt) {
1.40      daniel   3758:     while (((CUR == '<') && (NXT(1) == '?')) ||
                   3759:            ((CUR == '<') && (NXT(1) == '!') &&
                   3760:            (NXT(2) == '-') && (NXT(3) == '-')) ||
                   3761:            IS_BLANK(CUR)) {
                   3762:         if ((CUR == '<') && (NXT(1) == '?')) {
1.16      daniel   3763:            xmlParsePI(ctxt);
1.40      daniel   3764:        } else if (IS_BLANK(CUR)) {
                   3765:            NEXT;
1.1       veillard 3766:        } else
1.31      daniel   3767:            xmlParseComment(ctxt, 0);
1.1       veillard 3768:     }
                   3769: }
                   3770: 
1.50      daniel   3771: /**
                   3772:  * xmlParseDocument :
                   3773:  * @ctxt:  an XML parser context
                   3774:  * 
                   3775:  * parse an XML document (and build a tree if using the standard SAX
                   3776:  * interface).
1.21      daniel   3777:  *
1.22      daniel   3778:  * [1] document ::= prolog element Misc*
1.29      daniel   3779:  *
                   3780:  * [22] prolog ::= XMLDecl? Misc* (doctypedecl Misc*)?
1.50      daniel   3781:  *
1.68      daniel   3782:  * Returns 0, -1 in case of error. the parser context is augmented
1.50      daniel   3783:  *                as a result of the parsing.
1.1       veillard 3784:  */
                   3785: 
1.55      daniel   3786: int
                   3787: xmlParseDocument(xmlParserCtxtPtr ctxt) {
1.45      daniel   3788:     xmlDefaultSAXHandlerInit();
                   3789: 
1.14      veillard 3790:     /*
1.44      daniel   3791:      * SAX: beginning of the document processing.
                   3792:      */
1.72      daniel   3793:     if ((ctxt->sax) && (ctxt->sax->setDocumentLocator))
1.74    ! daniel   3794:         ctxt->sax->setDocumentLocator(ctxt->userData, &xmlDefaultSAXLocator);
1.44      daniel   3795: 
                   3796:     /*
1.14      veillard 3797:      * We should check for encoding here and plug-in some
                   3798:      * conversion code TODO !!!!
                   3799:      */
1.1       veillard 3800: 
                   3801:     /*
                   3802:      * Wipe out everything which is before the first '<'
                   3803:      */
1.59      daniel   3804:     if (IS_BLANK(CUR)) {
                   3805:        if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74    ! daniel   3806:            ctxt->sax->error(ctxt->userData,
1.59      daniel   3807:            "Extra spaces at the beginning of the document are not allowed\n");
                   3808:        ctxt->wellFormed = 0;
                   3809:        SKIP_BLANKS;
                   3810:     }
                   3811: 
                   3812:     if (CUR == 0) {
                   3813:        if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74    ! daniel   3814:            ctxt->sax->error(ctxt->userData, "Document is empty\n");
1.59      daniel   3815:        ctxt->wellFormed = 0;
                   3816:     }
1.1       veillard 3817: 
                   3818:     /*
                   3819:      * Check for the XMLDecl in the Prolog.
                   3820:      */
1.40      daniel   3821:     if ((CUR == '<') && (NXT(1) == '?') &&
                   3822:         (NXT(2) == 'x') && (NXT(3) == 'm') &&
                   3823:        (NXT(4) == 'l')) {
1.19      daniel   3824:        xmlParseXMLDecl(ctxt);
                   3825:        /* SKIP_EOL(cur); */
1.42      daniel   3826:        SKIP_BLANKS;
1.40      daniel   3827:     } else if ((CUR == '<') && (NXT(1) == '?') &&
                   3828:         (NXT(2) == 'X') && (NXT(3) == 'M') &&
                   3829:        (NXT(4) == 'L')) {
1.19      daniel   3830:        /*
                   3831:         * The first drafts were using <?XML and the final W3C REC
                   3832:         * now use <?xml ...
                   3833:         */
1.16      daniel   3834:        xmlParseXMLDecl(ctxt);
1.1       veillard 3835:        /* SKIP_EOL(cur); */
1.42      daniel   3836:        SKIP_BLANKS;
1.1       veillard 3837:     } else {
1.72      daniel   3838:        ctxt->version = xmlCharStrdup(XML_DEFAULT_VERSION);
1.1       veillard 3839:     }
1.72      daniel   3840:     if ((ctxt->sax) && (ctxt->sax->startDocument))
1.74    ! daniel   3841:         ctxt->sax->startDocument(ctxt->userData);
1.1       veillard 3842: 
                   3843:     /*
                   3844:      * The Misc part of the Prolog
                   3845:      */
1.16      daniel   3846:     xmlParseMisc(ctxt);
1.1       veillard 3847: 
                   3848:     /*
1.29      daniel   3849:      * Then possibly doc type declaration(s) and more Misc
1.21      daniel   3850:      * (doctypedecl Misc*)?
                   3851:      */
1.40      daniel   3852:     if ((CUR == '<') && (NXT(1) == '!') &&
                   3853:        (NXT(2) == 'D') && (NXT(3) == 'O') &&
                   3854:        (NXT(4) == 'C') && (NXT(5) == 'T') &&
                   3855:        (NXT(6) == 'Y') && (NXT(7) == 'P') &&
                   3856:        (NXT(8) == 'E')) {
1.22      daniel   3857:        xmlParseDocTypeDecl(ctxt);
                   3858:        xmlParseMisc(ctxt);
1.21      daniel   3859:     }
                   3860: 
                   3861:     /*
                   3862:      * Time to start parsing the tree itself
1.1       veillard 3863:      */
1.72      daniel   3864:     xmlParseElement(ctxt);
1.33      daniel   3865: 
                   3866:     /*
                   3867:      * The Misc part at the end
                   3868:      */
                   3869:     xmlParseMisc(ctxt);
1.16      daniel   3870: 
1.59      daniel   3871:     if (CUR != 0) {
                   3872:        if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74    ! daniel   3873:            ctxt->sax->error(ctxt->userData,
1.59      daniel   3874:                "Extra content at the end of the document\n");
                   3875:        ctxt->wellFormed = 0;
                   3876:     }
                   3877: 
1.44      daniel   3878:     /*
                   3879:      * SAX: end of the document processing.
                   3880:      */
1.72      daniel   3881:     if ((ctxt->sax) && (ctxt->sax->endDocument != NULL))
1.74    ! daniel   3882:         ctxt->sax->endDocument(ctxt->userData);
1.59      daniel   3883:     if (! ctxt->wellFormed) return(-1);
1.16      daniel   3884:     return(0);
                   3885: }
                   3886: 
1.50      daniel   3887: /**
1.69      daniel   3888:  * xmlCreateFileParserCtxt :
1.50      daniel   3889:  * @cur:  a pointer to an array of CHAR
                   3890:  *
1.69      daniel   3891:  * Create a parser context for an XML in-memory document.
                   3892:  *
                   3893:  * Returns the new parser context or NULL
1.16      daniel   3894:  */
1.69      daniel   3895: xmlParserCtxtPtr
                   3896: xmlCreateDocParserCtxt(CHAR *cur) {
1.16      daniel   3897:     xmlParserCtxtPtr ctxt;
1.40      daniel   3898:     xmlParserInputPtr input;
1.16      daniel   3899: 
                   3900:     ctxt = (xmlParserCtxtPtr) malloc(sizeof(xmlParserCtxt));
                   3901:     if (ctxt == NULL) {
                   3902:         perror("malloc");
                   3903:        return(NULL);
                   3904:     }
1.40      daniel   3905:     xmlInitParserCtxt(ctxt);
                   3906:     input = (xmlParserInputPtr) malloc(sizeof(xmlParserInput));
                   3907:     if (input == NULL) {
                   3908:         perror("malloc");
                   3909:        free(ctxt);
                   3910:        return(NULL);
                   3911:     }
                   3912: 
                   3913:     input->filename = NULL;
                   3914:     input->line = 1;
                   3915:     input->col = 1;
                   3916:     input->base = cur;
                   3917:     input->cur = cur;
1.69      daniel   3918:     input->free = NULL;
1.40      daniel   3919: 
                   3920:     inputPush(ctxt, input);
1.69      daniel   3921:     return(ctxt);
                   3922: }
                   3923: 
                   3924: /**
                   3925:  * xmlSAXParseDoc :
                   3926:  * @sax:  the SAX handler block
                   3927:  * @cur:  a pointer to an array of CHAR
                   3928:  * @recovery:  work in recovery mode, i.e. tries to read no Well Formed
                   3929:  *             documents
                   3930:  *
                   3931:  * parse an XML in-memory document and build a tree.
                   3932:  * It use the given SAX function block to handle the parsing callback.
                   3933:  * If sax is NULL, fallback to the default DOM tree building routines.
                   3934:  * 
                   3935:  * Returns the resulting document tree
                   3936:  */
                   3937: 
                   3938: xmlDocPtr
                   3939: xmlSAXParseDoc(xmlSAXHandlerPtr sax, CHAR *cur, int recovery) {
                   3940:     xmlDocPtr ret;
                   3941:     xmlParserCtxtPtr ctxt;
                   3942: 
                   3943:     if (cur == NULL) return(NULL);
1.16      daniel   3944: 
                   3945: 
1.69      daniel   3946:     ctxt = xmlCreateDocParserCtxt(cur);
                   3947:     if (ctxt == NULL) return(NULL);
1.74    ! daniel   3948:     if (sax != NULL) { 
        !          3949:         ctxt->sax = sax;
        !          3950:         ctxt->userData = NULL;
        !          3951:     }
1.69      daniel   3952: 
1.16      daniel   3953:     xmlParseDocument(ctxt);
1.72      daniel   3954:     if ((ctxt->wellFormed) || recovery) ret = ctxt->myDoc;
1.59      daniel   3955:     else {
                   3956:        ret = NULL;
1.72      daniel   3957:        xmlFreeDoc(ctxt->myDoc);
                   3958:        ctxt->myDoc = NULL;
1.59      daniel   3959:     }
1.69      daniel   3960:     xmlFreeParserCtxt(ctxt);
1.16      daniel   3961:     
1.1       veillard 3962:     return(ret);
                   3963: }
                   3964: 
1.50      daniel   3965: /**
1.55      daniel   3966:  * xmlParseDoc :
                   3967:  * @cur:  a pointer to an array of CHAR
                   3968:  *
                   3969:  * parse an XML in-memory document and build a tree.
                   3970:  * 
1.68      daniel   3971:  * Returns the resulting document tree
1.55      daniel   3972:  */
                   3973: 
1.69      daniel   3974: xmlDocPtr
                   3975: xmlParseDoc(CHAR *cur) {
1.59      daniel   3976:     return(xmlSAXParseDoc(NULL, cur, 0));
                   3977: }
                   3978: 
                   3979: /**
                   3980:  * xmlRecoverDoc :
                   3981:  * @cur:  a pointer to an array of CHAR
                   3982:  *
                   3983:  * parse an XML in-memory document and build a tree.
                   3984:  * In the case the document is not Well Formed, a tree is built anyway
                   3985:  * 
1.68      daniel   3986:  * Returns the resulting document tree
1.59      daniel   3987:  */
                   3988: 
1.69      daniel   3989: xmlDocPtr
                   3990: xmlRecoverDoc(CHAR *cur) {
1.59      daniel   3991:     return(xmlSAXParseDoc(NULL, cur, 1));
1.55      daniel   3992: }
                   3993: 
                   3994: /**
1.69      daniel   3995:  * xmlCreateFileParserCtxt :
1.50      daniel   3996:  * @filename:  the filename
                   3997:  *
1.69      daniel   3998:  * Create a parser context for a file content. 
                   3999:  * Automatic support for ZLIB/Compress compressed document is provided
                   4000:  * by default if found at compile-time.
1.50      daniel   4001:  *
1.69      daniel   4002:  * Returns the new parser context or NULL
1.9       httpng   4003:  */
1.69      daniel   4004: xmlParserCtxtPtr
                   4005: xmlCreateFileParserCtxt(const char *filename)
                   4006: {
                   4007:     xmlParserCtxtPtr ctxt;
1.20      daniel   4008: #ifdef HAVE_ZLIB_H
                   4009:     gzFile input;
                   4010: #else
1.9       httpng   4011:     int input;
1.20      daniel   4012: #endif
1.9       httpng   4013:     int res;
1.55      daniel   4014:     int len;
1.9       httpng   4015:     struct stat buf;
                   4016:     char *buffer;
1.40      daniel   4017:     xmlParserInputPtr inputStream;
1.9       httpng   4018: 
1.11      veillard 4019:     res = stat(filename, &buf);
1.9       httpng   4020:     if (res < 0) return(NULL);
                   4021: 
1.20      daniel   4022: #ifdef HAVE_ZLIB_H
1.55      daniel   4023:     len = (buf.st_size * 8) + 1000;
1.20      daniel   4024: retry_bigger:
1.55      daniel   4025:     buffer = malloc(len);
1.20      daniel   4026: #else
1.55      daniel   4027:     len = buf.st_size + 100;
                   4028:     buffer = malloc(len);
1.20      daniel   4029: #endif
1.9       httpng   4030:     if (buffer == NULL) {
                   4031:        perror("malloc");
                   4032:         return(NULL);
                   4033:     }
                   4034: 
1.55      daniel   4035:     memset(buffer, 0, len);
1.20      daniel   4036: #ifdef HAVE_ZLIB_H
                   4037:     input = gzopen (filename, "r");
                   4038:     if (input == NULL) {
                   4039:         fprintf (stderr, "Cannot read file %s :\n", filename);
                   4040:        perror ("gzopen failed");
                   4041:        return(NULL);
                   4042:     }
                   4043: #else
1.72      daniel   4044: #ifdef WIN32
                   4045:     input = _open (filename, O_RDONLY | _O_BINARY);
                   4046: #else
1.9       httpng   4047:     input = open (filename, O_RDONLY);
1.72      daniel   4048: #endif
1.9       httpng   4049:     if (input < 0) {
                   4050:         fprintf (stderr, "Cannot read file %s :\n", filename);
                   4051:        perror ("open failed");
                   4052:        return(NULL);
                   4053:     }
1.20      daniel   4054: #endif
                   4055: #ifdef HAVE_ZLIB_H
1.55      daniel   4056:     res = gzread(input, buffer, len);
1.20      daniel   4057: #else
1.9       httpng   4058:     res = read(input, buffer, buf.st_size);
1.20      daniel   4059: #endif
1.9       httpng   4060:     if (res < 0) {
                   4061:         fprintf (stderr, "Cannot read file %s :\n", filename);
1.20      daniel   4062: #ifdef HAVE_ZLIB_H
                   4063:        perror ("gzread failed");
                   4064: #else
1.9       httpng   4065:        perror ("read failed");
1.20      daniel   4066: #endif
1.9       httpng   4067:        return(NULL);
                   4068:     }
1.20      daniel   4069: #ifdef HAVE_ZLIB_H
                   4070:     gzclose(input);
1.55      daniel   4071:     if (res >= len) {
1.20      daniel   4072:         free(buffer);
1.55      daniel   4073:        len *= 2;
1.20      daniel   4074:        goto retry_bigger;
                   4075:     }
                   4076:     buf.st_size = res;
                   4077: #else
1.9       httpng   4078:     close(input);
1.20      daniel   4079: #endif
                   4080: 
1.40      daniel   4081:     buffer[buf.st_size] = '\0';
1.9       httpng   4082: 
1.16      daniel   4083:     ctxt = (xmlParserCtxtPtr) malloc(sizeof(xmlParserCtxt));
                   4084:     if (ctxt == NULL) {
                   4085:         perror("malloc");
                   4086:        return(NULL);
                   4087:     }
1.40      daniel   4088:     xmlInitParserCtxt(ctxt);
                   4089:     inputStream = (xmlParserInputPtr) malloc(sizeof(xmlParserInput));
                   4090:     if (inputStream == NULL) {
                   4091:         perror("malloc");
                   4092:        free(ctxt);
                   4093:        return(NULL);
                   4094:     }
                   4095: 
                   4096:     inputStream->filename = strdup(filename);
                   4097:     inputStream->line = 1;
                   4098:     inputStream->col = 1;
1.45      daniel   4099: 
                   4100:     /*
                   4101:      * TODO : plug some encoding conversion routines here. !!!
                   4102:      */
1.40      daniel   4103:     inputStream->base = buffer;
                   4104:     inputStream->cur = buffer;
1.69      daniel   4105:     inputStream->free = (xmlParserInputDeallocate) free;
1.16      daniel   4106: 
1.40      daniel   4107:     inputPush(ctxt, inputStream);
1.69      daniel   4108:     return(ctxt);
                   4109: }
                   4110: 
                   4111: /**
                   4112:  * xmlSAXParseFile :
                   4113:  * @sax:  the SAX handler block
                   4114:  * @filename:  the filename
                   4115:  * @recovery:  work in recovery mode, i.e. tries to read no Well Formed
                   4116:  *             documents
                   4117:  *
                   4118:  * parse an XML file and build a tree. Automatic support for ZLIB/Compress
                   4119:  * compressed document is provided by default if found at compile-time.
                   4120:  * It use the given SAX function block to handle the parsing callback.
                   4121:  * If sax is NULL, fallback to the default DOM tree building routines.
                   4122:  *
                   4123:  * Returns the resulting document tree
                   4124:  */
                   4125: 
                   4126: xmlDocPtr xmlSAXParseFile(xmlSAXHandlerPtr sax, const char *filename,
                   4127:                           int recovery) {
                   4128:     xmlDocPtr ret;
                   4129:     xmlParserCtxtPtr ctxt;
                   4130: 
                   4131:     ctxt = xmlCreateFileParserCtxt(filename);
                   4132:     if (ctxt == NULL) return(NULL);
1.74    ! daniel   4133:     if (sax != NULL) {
        !          4134:         ctxt->sax = sax;
        !          4135:         ctxt->userData = NULL;
        !          4136:     }
1.16      daniel   4137: 
                   4138:     xmlParseDocument(ctxt);
1.40      daniel   4139: 
1.72      daniel   4140:     if ((ctxt->wellFormed) || recovery) ret = ctxt->myDoc;
1.59      daniel   4141:     else {
                   4142:        ret = NULL;
1.72      daniel   4143:        xmlFreeDoc(ctxt->myDoc);
                   4144:        ctxt->myDoc = NULL;
1.59      daniel   4145:     }
1.69      daniel   4146:     xmlFreeParserCtxt(ctxt);
1.20      daniel   4147:     
                   4148:     return(ret);
                   4149: }
                   4150: 
1.55      daniel   4151: /**
                   4152:  * xmlParseFile :
                   4153:  * @filename:  the filename
                   4154:  *
                   4155:  * parse an XML file and build a tree. Automatic support for ZLIB/Compress
                   4156:  * compressed document is provided by default if found at compile-time.
                   4157:  *
1.68      daniel   4158:  * Returns the resulting document tree
1.55      daniel   4159:  */
                   4160: 
                   4161: xmlDocPtr xmlParseFile(const char *filename) {
1.59      daniel   4162:     return(xmlSAXParseFile(NULL, filename, 0));
                   4163: }
                   4164: 
                   4165: /**
                   4166:  * xmlRecoverFile :
                   4167:  * @filename:  the filename
                   4168:  *
                   4169:  * parse an XML file and build a tree. Automatic support for ZLIB/Compress
                   4170:  * compressed document is provided by default if found at compile-time.
                   4171:  * In the case the document is not Well Formed, a tree is built anyway
                   4172:  *
1.68      daniel   4173:  * Returns the resulting document tree
1.59      daniel   4174:  */
                   4175: 
                   4176: xmlDocPtr xmlRecoverFile(const char *filename) {
                   4177:     return(xmlSAXParseFile(NULL, filename, 1));
1.55      daniel   4178: }
1.32      daniel   4179: 
1.50      daniel   4180: /**
1.69      daniel   4181:  * xmlCreateMemoryParserCtxt :
1.68      daniel   4182:  * @buffer:  an pointer to a char array
1.50      daniel   4183:  * @size:  the siwe of the array
                   4184:  *
1.69      daniel   4185:  * Create a parser context for an XML in-memory document.
1.50      daniel   4186:  *
1.69      daniel   4187:  * Returns the new parser context or NULL
1.20      daniel   4188:  */
1.69      daniel   4189: xmlParserCtxtPtr
                   4190: xmlCreateMemoryParserCtxt(char *buffer, int size) {
1.20      daniel   4191:     xmlParserCtxtPtr ctxt;
1.40      daniel   4192:     xmlParserInputPtr input;
                   4193: 
                   4194:     buffer[size - 1] = '\0';
                   4195: 
1.20      daniel   4196:     ctxt = (xmlParserCtxtPtr) malloc(sizeof(xmlParserCtxt));
                   4197:     if (ctxt == NULL) {
                   4198:         perror("malloc");
                   4199:        return(NULL);
                   4200:     }
1.40      daniel   4201:     xmlInitParserCtxt(ctxt);
                   4202:     input = (xmlParserInputPtr) malloc(sizeof(xmlParserInput));
                   4203:     if (input == NULL) {
                   4204:         perror("malloc");
1.50      daniel   4205:         free(ctxt->nodeTab);
                   4206:        free(ctxt->inputTab);
1.40      daniel   4207:        free(ctxt);
                   4208:        return(NULL);
                   4209:     }
1.20      daniel   4210: 
1.40      daniel   4211:     input->filename = NULL;
                   4212:     input->line = 1;
                   4213:     input->col = 1;
1.45      daniel   4214: 
                   4215:     /*
                   4216:      * TODO : plug some encoding conversion routines here. !!!
                   4217:      */
1.40      daniel   4218:     input->base = buffer;
                   4219:     input->cur = buffer;
1.69      daniel   4220:     input->free = NULL;
1.20      daniel   4221: 
1.40      daniel   4222:     inputPush(ctxt, input);
1.69      daniel   4223:     return(ctxt);
                   4224: }
                   4225: 
                   4226: /**
                   4227:  * xmlSAXParseMemory :
                   4228:  * @sax:  the SAX handler block
                   4229:  * @buffer:  an pointer to a char array
                   4230:  * @size:  the siwe of the array
                   4231:  * @recovery:  work in recovery mode, i.e. tries to read no Well Formed
                   4232:  *             documents
                   4233:  *
                   4234:  * parse an XML in-memory block and use the given SAX function block
                   4235:  * to handle the parsing callback. If sax is NULL, fallback to the default
                   4236:  * DOM tree building routines.
                   4237:  * 
                   4238:  * TODO : plug some encoding conversion routines here. !!!
                   4239:  *
                   4240:  * Returns the resulting document tree
                   4241:  */
                   4242: xmlDocPtr
                   4243: xmlSAXParseMemory(xmlSAXHandlerPtr sax, char *buffer, int size, int recovery) {
                   4244:     xmlDocPtr ret;
                   4245:     xmlParserCtxtPtr ctxt;
                   4246: 
                   4247:     ctxt = xmlCreateMemoryParserCtxt(buffer, size);
                   4248:     if (ctxt == NULL) return(NULL);
1.74    ! daniel   4249:     if (sax != NULL) {
        !          4250:         ctxt->sax = sax;
        !          4251:         ctxt->userData = NULL;
        !          4252:     }
1.20      daniel   4253: 
                   4254:     xmlParseDocument(ctxt);
1.40      daniel   4255: 
1.72      daniel   4256:     if ((ctxt->wellFormed) || recovery) ret = ctxt->myDoc;
1.59      daniel   4257:     else {
                   4258:        ret = NULL;
1.72      daniel   4259:        xmlFreeDoc(ctxt->myDoc);
                   4260:        ctxt->myDoc = NULL;
1.59      daniel   4261:     }
1.69      daniel   4262:     xmlFreeParserCtxt(ctxt);
1.16      daniel   4263:     
1.9       httpng   4264:     return(ret);
1.17      daniel   4265: }
                   4266: 
1.55      daniel   4267: /**
                   4268:  * xmlParseMemory :
1.68      daniel   4269:  * @buffer:  an pointer to a char array
1.55      daniel   4270:  * @size:  the size of the array
                   4271:  *
                   4272:  * parse an XML in-memory block and build a tree.
                   4273:  * 
1.68      daniel   4274:  * Returns the resulting document tree
1.55      daniel   4275:  */
                   4276: 
                   4277: xmlDocPtr xmlParseMemory(char *buffer, int size) {
1.59      daniel   4278:    return(xmlSAXParseMemory(NULL, buffer, size, 0));
                   4279: }
                   4280: 
                   4281: /**
                   4282:  * xmlRecoverMemory :
1.68      daniel   4283:  * @buffer:  an pointer to a char array
1.59      daniel   4284:  * @size:  the size of the array
                   4285:  *
                   4286:  * parse an XML in-memory block and build a tree.
                   4287:  * In the case the document is not Well Formed, a tree is built anyway
                   4288:  * 
1.68      daniel   4289:  * Returns the resulting document tree
1.59      daniel   4290:  */
                   4291: 
                   4292: xmlDocPtr xmlRecoverMemory(char *buffer, int size) {
                   4293:    return(xmlSAXParseMemory(NULL, buffer, size, 1));
1.55      daniel   4294: }
1.17      daniel   4295: 
1.50      daniel   4296: /**
                   4297:  * xmlInitParserCtxt:
                   4298:  * @ctxt:  an XML parser context
                   4299:  *
                   4300:  * Initialize a parser context
                   4301:  */
                   4302: 
1.55      daniel   4303: void
                   4304: xmlInitParserCtxt(xmlParserCtxtPtr ctxt)
1.17      daniel   4305: {
1.69      daniel   4306:     /* Allocate the Input stack */
                   4307:     ctxt->inputTab = (xmlParserInputPtr *) malloc(5 * sizeof(xmlParserInputPtr));
                   4308:     ctxt->inputNr = 0;
                   4309:     ctxt->inputMax = 5;
                   4310:     ctxt->input = NULL;
1.72      daniel   4311:     ctxt->version = NULL;
                   4312:     ctxt->encoding = NULL;
                   4313:     ctxt->standalone = -1;
1.69      daniel   4314: 
                   4315:     /* Allocate the Node stack */
                   4316:     ctxt->nodeTab = (xmlNodePtr *) malloc(10 * sizeof(xmlNodePtr));
                   4317:     ctxt->nodeNr = 0;
                   4318:     ctxt->nodeMax = 10;
                   4319:     ctxt->node = NULL;
                   4320: 
                   4321:     ctxt->sax = &xmlDefaultSAXHandler;
1.74    ! daniel   4322:     ctxt->userData = ctxt;
1.72      daniel   4323:     ctxt->myDoc = NULL;
1.69      daniel   4324:     ctxt->wellFormed = 1;
                   4325:     ctxt->record_info = 0;
                   4326:     xmlInitNodeInfoSeq(&ctxt->node_seq);
                   4327: }
                   4328: 
                   4329: /**
                   4330:  * xmlFreeParserCtxt:
                   4331:  * @ctxt:  an XML parser context
                   4332:  *
                   4333:  * Free all the memory used by a parser context. However the parsed
1.72      daniel   4334:  * document in ctxt->myDoc is not freed.
1.69      daniel   4335:  */
                   4336: 
                   4337: void
                   4338: xmlFreeParserCtxt(xmlParserCtxtPtr ctxt)
                   4339: {
                   4340:     xmlParserInputPtr input;
                   4341: 
                   4342:     if (ctxt == NULL) return;
                   4343: 
                   4344:     while ((input = inputPop(ctxt)) != NULL) {
                   4345:         xmlFreeInputStream(input);
                   4346:     }
                   4347: 
                   4348:     if (ctxt->nodeTab != NULL) free(ctxt->nodeTab);
                   4349:     if (ctxt->inputTab != NULL) free(ctxt->inputTab);
1.73      daniel   4350:     if (ctxt->version != NULL) free((char *) ctxt->version);
1.69      daniel   4351:     free(ctxt);
1.17      daniel   4352: }
                   4353: 
1.50      daniel   4354: /**
                   4355:  * xmlClearParserCtxt:
                   4356:  * @ctxt:  an XML parser context
                   4357:  *
                   4358:  * Clear (release owned resources) and reinitialize a parser context
                   4359:  */
1.17      daniel   4360: 
1.55      daniel   4361: void
                   4362: xmlClearParserCtxt(xmlParserCtxtPtr ctxt)
1.17      daniel   4363: {
1.32      daniel   4364:   xmlClearNodeInfoSeq(&ctxt->node_seq);
                   4365:   xmlInitParserCtxt(ctxt);
1.17      daniel   4366: }
                   4367: 
                   4368: 
1.50      daniel   4369: /**
                   4370:  * xmlSetupParserForBuffer:
                   4371:  * @ctxt:  an XML parser context
                   4372:  * @buffer:  a CHAR * buffer
                   4373:  * @filename:  a file name
                   4374:  *
1.19      daniel   4375:  * Setup the parser context to parse a new buffer; Clears any prior
                   4376:  * contents from the parser context. The buffer parameter must not be
                   4377:  * NULL, but the filename parameter can be
                   4378:  */
1.55      daniel   4379: void
                   4380: xmlSetupParserForBuffer(xmlParserCtxtPtr ctxt, const CHAR* buffer,
1.17      daniel   4381:                              const char* filename)
                   4382: {
1.40      daniel   4383:   xmlParserInputPtr input;
                   4384: 
                   4385:   input = (xmlParserInputPtr) malloc(sizeof(xmlParserInput));
                   4386:   if (input == NULL) {
                   4387:       perror("malloc");
                   4388:       free(ctxt);
                   4389:       exit(1);
                   4390:   }
                   4391: 
1.17      daniel   4392:   xmlClearParserCtxt(ctxt);
1.40      daniel   4393:   if (input->filename != NULL)
                   4394:       input->filename = strdup(filename);
                   4395:   else
                   4396:       input->filename = NULL;
                   4397:   input->line = 1;
                   4398:   input->col = 1;
                   4399:   input->base = buffer;
                   4400:   input->cur = buffer;
                   4401: 
                   4402:   inputPush(ctxt, input);
1.17      daniel   4403: }
                   4404: 
1.32      daniel   4405: 
1.50      daniel   4406: /**
                   4407:  * xmlParserFindNodeInfo:
                   4408:  * @ctxt:  an XML parser context
                   4409:  * @node:  an XML node within the tree
                   4410:  *
                   4411:  * Find the parser node info struct for a given node
                   4412:  * 
1.68      daniel   4413:  * Returns an xmlParserNodeInfo block pointer or NULL
1.32      daniel   4414:  */
                   4415: const xmlParserNodeInfo* xmlParserFindNodeInfo(const xmlParserCtxt* ctx,
                   4416:                                                const xmlNode* node)
                   4417: {
                   4418:   unsigned long pos;
                   4419: 
                   4420:   /* Find position where node should be at */
                   4421:   pos = xmlParserFindNodeInfoIndex(&ctx->node_seq, node);
                   4422:   if ( ctx->node_seq.buffer[pos].node == node )
                   4423:     return &ctx->node_seq.buffer[pos];
                   4424:   else
                   4425:     return NULL;
                   4426: }
                   4427: 
                   4428: 
1.50      daniel   4429: /**
                   4430:  * xmlInitNodeInfoSeq :
                   4431:  * @seq:  a node info sequence pointer
                   4432:  *
                   4433:  * -- Initialize (set to initial state) node info sequence
1.32      daniel   4434:  */
1.55      daniel   4435: void
                   4436: xmlInitNodeInfoSeq(xmlParserNodeInfoSeqPtr seq)
1.32      daniel   4437: {
                   4438:   seq->length = 0;
                   4439:   seq->maximum = 0;
                   4440:   seq->buffer = NULL;
                   4441: }
                   4442: 
1.50      daniel   4443: /**
                   4444:  * xmlClearNodeInfoSeq :
                   4445:  * @seq:  a node info sequence pointer
                   4446:  *
                   4447:  * -- Clear (release memory and reinitialize) node
1.32      daniel   4448:  *   info sequence
                   4449:  */
1.55      daniel   4450: void
                   4451: xmlClearNodeInfoSeq(xmlParserNodeInfoSeqPtr seq)
1.32      daniel   4452: {
                   4453:   if ( seq->buffer != NULL )
                   4454:     free(seq->buffer);
                   4455:   xmlInitNodeInfoSeq(seq);
                   4456: }
                   4457: 
                   4458: 
1.50      daniel   4459: /**
                   4460:  * xmlParserFindNodeInfoIndex:
                   4461:  * @seq:  a node info sequence pointer
                   4462:  * @node:  an XML node pointer
                   4463:  *
                   4464:  * 
1.32      daniel   4465:  * xmlParserFindNodeInfoIndex : Find the index that the info record for
                   4466:  *   the given node is or should be at in a sorted sequence
1.68      daniel   4467:  *
                   4468:  * Returns a long indicating the position of the record
1.32      daniel   4469:  */
                   4470: unsigned long xmlParserFindNodeInfoIndex(const xmlParserNodeInfoSeq* seq,
                   4471:                                          const xmlNode* node)
                   4472: {
                   4473:   unsigned long upper, lower, middle;
                   4474:   int found = 0;
                   4475: 
                   4476:   /* Do a binary search for the key */
                   4477:   lower = 1;
                   4478:   upper = seq->length;
                   4479:   middle = 0;
                   4480:   while ( lower <= upper && !found) {
                   4481:     middle = lower + (upper - lower) / 2;
                   4482:     if ( node == seq->buffer[middle - 1].node )
                   4483:       found = 1;
                   4484:     else if ( node < seq->buffer[middle - 1].node )
                   4485:       upper = middle - 1;
                   4486:     else
                   4487:       lower = middle + 1;
                   4488:   }
                   4489: 
                   4490:   /* Return position */
                   4491:   if ( middle == 0 || seq->buffer[middle - 1].node < node )
                   4492:     return middle;
                   4493:   else 
                   4494:     return middle - 1;
                   4495: }
                   4496: 
                   4497: 
1.50      daniel   4498: /**
                   4499:  * xmlParserAddNodeInfo:
                   4500:  * @ctxt:  an XML parser context
1.68      daniel   4501:  * @info:  a node info sequence pointer
1.50      daniel   4502:  *
                   4503:  * Insert node info record into the sorted sequence
1.32      daniel   4504:  */
1.55      daniel   4505: void
                   4506: xmlParserAddNodeInfo(xmlParserCtxtPtr ctxt, 
1.68      daniel   4507:                      const xmlParserNodeInfo* info)
1.32      daniel   4508: {
                   4509:   unsigned long pos;
                   4510:   static unsigned int block_size = 5;
                   4511: 
                   4512:   /* Find pos and check to see if node is already in the sequence */
1.55      daniel   4513:   pos = xmlParserFindNodeInfoIndex(&ctxt->node_seq, info->node);
                   4514:   if ( pos < ctxt->node_seq.length
                   4515:        && ctxt->node_seq.buffer[pos].node == info->node ) {
                   4516:     ctxt->node_seq.buffer[pos] = *info;
1.32      daniel   4517:   }
                   4518: 
                   4519:   /* Otherwise, we need to add new node to buffer */
                   4520:   else {
                   4521:     /* Expand buffer by 5 if needed */
1.55      daniel   4522:     if ( ctxt->node_seq.length + 1 > ctxt->node_seq.maximum ) {
1.32      daniel   4523:       xmlParserNodeInfo* tmp_buffer;
1.55      daniel   4524:       unsigned int byte_size = (sizeof(*ctxt->node_seq.buffer)
                   4525:                                 *(ctxt->node_seq.maximum + block_size));
1.32      daniel   4526: 
1.55      daniel   4527:       if ( ctxt->node_seq.buffer == NULL )
1.32      daniel   4528:         tmp_buffer = (xmlParserNodeInfo*)malloc(byte_size);
                   4529:       else 
1.55      daniel   4530:         tmp_buffer = (xmlParserNodeInfo*)realloc(ctxt->node_seq.buffer, byte_size);
1.32      daniel   4531: 
                   4532:       if ( tmp_buffer == NULL ) {
1.55      daniel   4533:         if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
1.74    ! daniel   4534:            ctxt->sax->error(ctxt->userData, "Out of memory\n");
1.32      daniel   4535:         return;
                   4536:       }
1.55      daniel   4537:       ctxt->node_seq.buffer = tmp_buffer;
                   4538:       ctxt->node_seq.maximum += block_size;
1.32      daniel   4539:     }
                   4540: 
                   4541:     /* If position is not at end, move elements out of the way */
1.55      daniel   4542:     if ( pos != ctxt->node_seq.length ) {
1.32      daniel   4543:       unsigned long i;
                   4544: 
1.55      daniel   4545:       for ( i = ctxt->node_seq.length; i > pos; i-- )
                   4546:         ctxt->node_seq.buffer[i] = ctxt->node_seq.buffer[i - 1];
1.32      daniel   4547:     }
                   4548:   
                   4549:     /* Copy element and increase length */
1.55      daniel   4550:     ctxt->node_seq.buffer[pos] = *info;
                   4551:     ctxt->node_seq.length++;
1.32      daniel   4552:   }   
                   4553: }

Webmaster