Annotation of XML/parser.c, revision 1.76

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

Webmaster