Annotation of XML/parser.c, revision 1.96

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

Webmaster