Annotation of embedaddon/libxml2/HTMLparser.c, revision 1.1.1.2

1.1       misho       1: /*
                      2:  * HTMLparser.c : an HTML 4.0 non-verifying parser
                      3:  *
                      4:  * See Copyright for the status of this software.
                      5:  *
                      6:  * daniel@veillard.com
                      7:  */
                      8: 
                      9: #define IN_LIBXML
                     10: #include "libxml.h"
                     11: #ifdef LIBXML_HTML_ENABLED
                     12: 
                     13: #include <string.h>
                     14: #ifdef HAVE_CTYPE_H
                     15: #include <ctype.h>
                     16: #endif
                     17: #ifdef HAVE_STDLIB_H
                     18: #include <stdlib.h>
                     19: #endif
                     20: #ifdef HAVE_SYS_STAT_H
                     21: #include <sys/stat.h>
                     22: #endif
                     23: #ifdef HAVE_FCNTL_H
                     24: #include <fcntl.h>
                     25: #endif
                     26: #ifdef HAVE_UNISTD_H
                     27: #include <unistd.h>
                     28: #endif
                     29: #ifdef HAVE_ZLIB_H
                     30: #include <zlib.h>
                     31: #endif
                     32: 
                     33: #include <libxml/xmlmemory.h>
                     34: #include <libxml/tree.h>
                     35: #include <libxml/parser.h>
                     36: #include <libxml/parserInternals.h>
                     37: #include <libxml/xmlerror.h>
                     38: #include <libxml/HTMLparser.h>
                     39: #include <libxml/HTMLtree.h>
                     40: #include <libxml/entities.h>
                     41: #include <libxml/encoding.h>
                     42: #include <libxml/valid.h>
                     43: #include <libxml/xmlIO.h>
                     44: #include <libxml/globals.h>
                     45: #include <libxml/uri.h>
                     46: 
                     47: #define HTML_MAX_NAMELEN 1000
                     48: #define HTML_PARSER_BIG_BUFFER_SIZE 1000
                     49: #define HTML_PARSER_BUFFER_SIZE 100
                     50: 
                     51: /* #define DEBUG */
                     52: /* #define DEBUG_PUSH */
                     53: 
                     54: static int htmlOmittedDefaultValue = 1;
                     55: 
                     56: xmlChar * htmlDecodeEntities(htmlParserCtxtPtr ctxt, int len,
                     57:                             xmlChar end, xmlChar  end2, xmlChar end3);
                     58: static void htmlParseComment(htmlParserCtxtPtr ctxt);
                     59: 
                     60: /************************************************************************
                     61:  *                                                                     *
                     62:  *             Some factorized error routines                          *
                     63:  *                                                                     *
                     64:  ************************************************************************/
                     65: 
                     66: /**
                     67:  * htmlErrMemory:
                     68:  * @ctxt:  an HTML parser context
                     69:  * @extra:  extra informations
                     70:  *
                     71:  * Handle a redefinition of attribute error
                     72:  */
                     73: static void
                     74: htmlErrMemory(xmlParserCtxtPtr ctxt, const char *extra)
                     75: {
                     76:     if ((ctxt != NULL) && (ctxt->disableSAX != 0) &&
                     77:         (ctxt->instate == XML_PARSER_EOF))
                     78:        return;
                     79:     if (ctxt != NULL) {
                     80:         ctxt->errNo = XML_ERR_NO_MEMORY;
                     81:         ctxt->instate = XML_PARSER_EOF;
                     82:         ctxt->disableSAX = 1;
                     83:     }
                     84:     if (extra)
                     85:         __xmlRaiseError(NULL, NULL, NULL, ctxt, NULL, XML_FROM_PARSER,
                     86:                         XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, extra,
                     87:                         NULL, NULL, 0, 0,
                     88:                         "Memory allocation failed : %s\n", extra);
                     89:     else
                     90:         __xmlRaiseError(NULL, NULL, NULL, ctxt, NULL, XML_FROM_PARSER,
                     91:                         XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, NULL,
                     92:                         NULL, NULL, 0, 0, "Memory allocation failed\n");
                     93: }
                     94: 
                     95: /**
                     96:  * htmlParseErr:
                     97:  * @ctxt:  an HTML parser context
                     98:  * @error:  the error number
                     99:  * @msg:  the error message
                    100:  * @str1:  string infor
                    101:  * @str2:  string infor
                    102:  *
                    103:  * Handle a fatal parser error, i.e. violating Well-Formedness constraints
                    104:  */
                    105: static void
                    106: htmlParseErr(xmlParserCtxtPtr ctxt, xmlParserErrors error,
                    107:              const char *msg, const xmlChar *str1, const xmlChar *str2)
                    108: {
                    109:     if ((ctxt != NULL) && (ctxt->disableSAX != 0) &&
                    110:         (ctxt->instate == XML_PARSER_EOF))
                    111:        return;
                    112:     if (ctxt != NULL)
                    113:        ctxt->errNo = error;
                    114:     __xmlRaiseError(NULL, NULL, NULL, ctxt, NULL, XML_FROM_HTML, error,
                    115:                     XML_ERR_ERROR, NULL, 0,
                    116:                    (const char *) str1, (const char *) str2,
                    117:                    NULL, 0, 0,
                    118:                    msg, str1, str2);
                    119:     if (ctxt != NULL)
                    120:        ctxt->wellFormed = 0;
                    121: }
                    122: 
                    123: /**
                    124:  * htmlParseErrInt:
                    125:  * @ctxt:  an HTML parser context
                    126:  * @error:  the error number
                    127:  * @msg:  the error message
                    128:  * @val:  integer info
                    129:  *
                    130:  * Handle a fatal parser error, i.e. violating Well-Formedness constraints
                    131:  */
                    132: static void
                    133: htmlParseErrInt(xmlParserCtxtPtr ctxt, xmlParserErrors error,
                    134:              const char *msg, int val)
                    135: {
                    136:     if ((ctxt != NULL) && (ctxt->disableSAX != 0) &&
                    137:         (ctxt->instate == XML_PARSER_EOF))
                    138:        return;
                    139:     if (ctxt != NULL)
                    140:        ctxt->errNo = error;
                    141:     __xmlRaiseError(NULL, NULL, NULL, ctxt, NULL, XML_FROM_HTML, error,
                    142:                     XML_ERR_ERROR, NULL, 0, NULL, NULL,
                    143:                    NULL, val, 0, msg, val);
                    144:     if (ctxt != NULL)
                    145:        ctxt->wellFormed = 0;
                    146: }
                    147: 
                    148: /************************************************************************
                    149:  *                                                                     *
                    150:  *     Parser stacks related functions and macros              *
                    151:  *                                                                     *
                    152:  ************************************************************************/
                    153: 
                    154: /**
                    155:  * htmlnamePush:
                    156:  * @ctxt:  an HTML parser context
                    157:  * @value:  the element name
                    158:  *
                    159:  * Pushes a new element name on top of the name stack
                    160:  *
                    161:  * Returns 0 in case of error, the index in the stack otherwise
                    162:  */
                    163: static int
                    164: htmlnamePush(htmlParserCtxtPtr ctxt, const xmlChar * value)
                    165: {
                    166:     if ((ctxt->html < 3) && (xmlStrEqual(value, BAD_CAST "head")))
                    167:         ctxt->html = 3;
                    168:     if ((ctxt->html < 10) && (xmlStrEqual(value, BAD_CAST "body")))
                    169:         ctxt->html = 10;
                    170:     if (ctxt->nameNr >= ctxt->nameMax) {
                    171:         ctxt->nameMax *= 2;
                    172:         ctxt->nameTab = (const xmlChar * *)
                    173:                          xmlRealloc((xmlChar * *)ctxt->nameTab,
                    174:                                     ctxt->nameMax *
                    175:                                     sizeof(ctxt->nameTab[0]));
                    176:         if (ctxt->nameTab == NULL) {
                    177:             htmlErrMemory(ctxt, NULL);
                    178:             return (0);
                    179:         }
                    180:     }
                    181:     ctxt->nameTab[ctxt->nameNr] = value;
                    182:     ctxt->name = value;
                    183:     return (ctxt->nameNr++);
                    184: }
                    185: /**
                    186:  * htmlnamePop:
                    187:  * @ctxt: an HTML parser context
                    188:  *
                    189:  * Pops the top element name from the name stack
                    190:  *
                    191:  * Returns the name just removed
                    192:  */
                    193: static const xmlChar *
                    194: htmlnamePop(htmlParserCtxtPtr ctxt)
                    195: {
                    196:     const xmlChar *ret;
                    197: 
                    198:     if (ctxt->nameNr <= 0)
                    199:         return (NULL);
                    200:     ctxt->nameNr--;
                    201:     if (ctxt->nameNr < 0)
                    202:         return (NULL);
                    203:     if (ctxt->nameNr > 0)
                    204:         ctxt->name = ctxt->nameTab[ctxt->nameNr - 1];
                    205:     else
                    206:         ctxt->name = NULL;
                    207:     ret = ctxt->nameTab[ctxt->nameNr];
                    208:     ctxt->nameTab[ctxt->nameNr] = NULL;
                    209:     return (ret);
                    210: }
                    211: 
                    212: /**
                    213:  * htmlNodeInfoPush:
                    214:  * @ctxt:  an HTML parser context
                    215:  * @value:  the node info
                    216:  *
                    217:  * Pushes a new element name on top of the node info stack
                    218:  *
                    219:  * Returns 0 in case of error, the index in the stack otherwise
                    220:  */
                    221: static int
                    222: htmlNodeInfoPush(htmlParserCtxtPtr ctxt, htmlParserNodeInfo *value)
                    223: {
                    224:     if (ctxt->nodeInfoNr >= ctxt->nodeInfoMax) {
                    225:         if (ctxt->nodeInfoMax == 0)
                    226:                 ctxt->nodeInfoMax = 5;
                    227:         ctxt->nodeInfoMax *= 2;
                    228:         ctxt->nodeInfoTab = (htmlParserNodeInfo *)
                    229:                          xmlRealloc((htmlParserNodeInfo *)ctxt->nodeInfoTab,
                    230:                                     ctxt->nodeInfoMax *
                    231:                                     sizeof(ctxt->nodeInfoTab[0]));
                    232:         if (ctxt->nodeInfoTab == NULL) {
                    233:             htmlErrMemory(ctxt, NULL);
                    234:             return (0);
                    235:         }
                    236:     }
                    237:     ctxt->nodeInfoTab[ctxt->nodeInfoNr] = *value;
                    238:     ctxt->nodeInfo = &ctxt->nodeInfoTab[ctxt->nodeInfoNr];
                    239:     return (ctxt->nodeInfoNr++);
                    240: }
                    241: 
                    242: /**
                    243:  * htmlNodeInfoPop:
                    244:  * @ctxt:  an HTML parser context
                    245:  *
                    246:  * Pops the top element name from the node info stack
                    247:  *
                    248:  * Returns 0 in case of error, the pointer to NodeInfo otherwise
                    249:  */
                    250: static htmlParserNodeInfo *
                    251: htmlNodeInfoPop(htmlParserCtxtPtr ctxt)
                    252: {
                    253:     if (ctxt->nodeInfoNr <= 0)
                    254:         return (NULL);
                    255:     ctxt->nodeInfoNr--;
                    256:     if (ctxt->nodeInfoNr < 0)
                    257:         return (NULL);
                    258:     if (ctxt->nodeInfoNr > 0)
                    259:         ctxt->nodeInfo = &ctxt->nodeInfoTab[ctxt->nodeInfoNr - 1];
                    260:     else
                    261:         ctxt->nodeInfo = NULL;
                    262:     return &ctxt->nodeInfoTab[ctxt->nodeInfoNr];
                    263: }
                    264: 
                    265: /*
                    266:  * Macros for accessing the content. Those should be used only by the parser,
                    267:  * and not exported.
                    268:  *
                    269:  * Dirty macros, i.e. one need to make assumption on the context to use them
                    270:  *
                    271:  *   CUR_PTR return the current pointer to the xmlChar to be parsed.
                    272:  *   CUR     returns the current xmlChar value, i.e. a 8 bit value if compiled
                    273:  *           in ISO-Latin or UTF-8, and the current 16 bit value if compiled
                    274:  *           in UNICODE mode. This should be used internally by the parser
                    275:  *           only to compare to ASCII values otherwise it would break when
                    276:  *           running with UTF-8 encoding.
                    277:  *   NXT(n)  returns the n'th next xmlChar. Same as CUR is should be used only
                    278:  *           to compare on ASCII based substring.
                    279:  *   UPP(n)  returns the n'th next xmlChar converted to uppercase. Same as CUR
                    280:  *           it should be used only to compare on ASCII based substring.
                    281:  *   SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
                    282:  *           strings without newlines within the parser.
                    283:  *
                    284:  * Clean macros, not dependent of an ASCII context, expect UTF-8 encoding
                    285:  *
                    286:  *   CURRENT Returns the current char value, with the full decoding of
                    287:  *           UTF-8 if we are using this mode. It returns an int.
                    288:  *   NEXT    Skip to the next character, this does the proper decoding
                    289:  *           in UTF-8 mode. It also pop-up unfinished entities on the fly.
                    290:  *   NEXTL(l) Skip the current unicode character of l xmlChars long.
                    291:  *   COPY(to) copy one char to *to, increment CUR_PTR and to accordingly
                    292:  */
                    293: 
                    294: #define UPPER (toupper(*ctxt->input->cur))
                    295: 
                    296: #define SKIP(val) ctxt->nbChars += (val),ctxt->input->cur += (val),ctxt->input->col+=(val)
                    297: 
                    298: #define NXT(val) ctxt->input->cur[(val)]
                    299: 
                    300: #define UPP(val) (toupper(ctxt->input->cur[(val)]))
                    301: 
                    302: #define CUR_PTR ctxt->input->cur
                    303: 
                    304: #define SHRINK if ((ctxt->input->cur - ctxt->input->base > 2 * INPUT_CHUNK) && \
                    305:                   (ctxt->input->end - ctxt->input->cur < 2 * INPUT_CHUNK)) \
                    306:        xmlParserInputShrink(ctxt->input)
                    307: 
                    308: #define GROW if ((ctxt->progressive == 0) &&                           \
                    309:                 (ctxt->input->end - ctxt->input->cur < INPUT_CHUNK))   \
                    310:        xmlParserInputGrow(ctxt->input, INPUT_CHUNK)
                    311: 
                    312: #define CURRENT ((int) (*ctxt->input->cur))
                    313: 
                    314: #define SKIP_BLANKS htmlSkipBlankChars(ctxt)
                    315: 
                    316: /* Inported from XML */
                    317: 
                    318: /* #define CUR (ctxt->token ? ctxt->token : (int) (*ctxt->input->cur)) */
                    319: #define CUR ((int) (*ctxt->input->cur))
                    320: #define NEXT xmlNextChar(ctxt)
                    321: 
                    322: #define RAW (ctxt->token ? -1 : (*ctxt->input->cur))
                    323: 
                    324: 
                    325: #define NEXTL(l) do {                                                  \
                    326:     if (*(ctxt->input->cur) == '\n') {                                 \
                    327:        ctxt->input->line++; ctxt->input->col = 1;                      \
                    328:     } else ctxt->input->col++;                                         \
                    329:     ctxt->token = 0; ctxt->input->cur += l; ctxt->nbChars++;           \
                    330:   } while (0)
                    331: 
                    332: /************
                    333:     \
                    334:     if (*ctxt->input->cur == '%') xmlParserHandlePEReference(ctxt);    \
                    335:     if (*ctxt->input->cur == '&') xmlParserHandleReference(ctxt);
                    336:  ************/
                    337: 
                    338: #define CUR_CHAR(l) htmlCurrentChar(ctxt, &l)
                    339: #define CUR_SCHAR(s, l) xmlStringCurrentChar(ctxt, s, &l)
                    340: 
                    341: #define COPY_BUF(l,b,i,v)                                              \
                    342:     if (l == 1) b[i++] = (xmlChar) v;                                  \
                    343:     else i += xmlCopyChar(l,&b[i],v)
                    344: 
                    345: /**
                    346:  * htmlFindEncoding:
                    347:  * @the HTML parser context
                    348:  *
                    349:  * Ty to find and encoding in the current data available in the input
                    350:  * buffer this is needed to try to switch to the proper encoding when
                    351:  * one face a character error.
                    352:  * That's an heuristic, since it's operating outside of parsing it could
                    353:  * try to use a meta which had been commented out, that's the reason it
                    354:  * should only be used in case of error, not as a default.
                    355:  *
                    356:  * Returns an encoding string or NULL if not found, the string need to
                    357:  *   be freed
                    358:  */
                    359: static xmlChar *
                    360: htmlFindEncoding(xmlParserCtxtPtr ctxt) {
                    361:     const xmlChar *start, *cur, *end;
                    362: 
                    363:     if ((ctxt == NULL) || (ctxt->input == NULL) ||
                    364:         (ctxt->input->encoding != NULL) || (ctxt->input->buf == NULL) ||
                    365:         (ctxt->input->buf->encoder != NULL))
                    366:         return(NULL);
                    367:     if ((ctxt->input->cur == NULL) || (ctxt->input->end == NULL))
                    368:         return(NULL);
                    369: 
                    370:     start = ctxt->input->cur;
                    371:     end = ctxt->input->end;
                    372:     /* we also expect the input buffer to be zero terminated */
                    373:     if (*end != 0)
                    374:         return(NULL);
                    375: 
                    376:     cur = xmlStrcasestr(start, BAD_CAST "HTTP-EQUIV");
                    377:     if (cur == NULL)
                    378:         return(NULL);
                    379:     cur = xmlStrcasestr(cur, BAD_CAST  "CONTENT");
                    380:     if (cur == NULL)
                    381:         return(NULL);
                    382:     cur = xmlStrcasestr(cur, BAD_CAST  "CHARSET=");
                    383:     if (cur == NULL)
                    384:         return(NULL);
                    385:     cur += 8;
                    386:     start = cur;
                    387:     while (((*cur >= 'A') && (*cur <= 'Z')) ||
                    388:            ((*cur >= 'a') && (*cur <= 'z')) ||
                    389:            ((*cur >= '0') && (*cur <= '9')) ||
                    390:            (*cur == '-') || (*cur == '_') || (*cur == ':') || (*cur == '/'))
                    391:            cur++;
                    392:     if (cur == start)
                    393:         return(NULL);
                    394:     return(xmlStrndup(start, cur - start));
                    395: }
                    396: 
                    397: /**
                    398:  * htmlCurrentChar:
                    399:  * @ctxt:  the HTML parser context
                    400:  * @len:  pointer to the length of the char read
                    401:  *
                    402:  * The current char value, if using UTF-8 this may actually span multiple
                    403:  * bytes in the input buffer. Implement the end of line normalization:
                    404:  * 2.11 End-of-Line Handling
                    405:  * If the encoding is unspecified, in the case we find an ISO-Latin-1
                    406:  * char, then the encoding converter is plugged in automatically.
                    407:  *
                    408:  * Returns the current char value and its length
                    409:  */
                    410: 
                    411: static int
                    412: htmlCurrentChar(xmlParserCtxtPtr ctxt, int *len) {
                    413:     if (ctxt->instate == XML_PARSER_EOF)
                    414:        return(0);
                    415: 
                    416:     if (ctxt->token != 0) {
                    417:        *len = 0;
                    418:        return(ctxt->token);
                    419:     }
                    420:     if (ctxt->charset == XML_CHAR_ENCODING_UTF8) {
                    421:        /*
                    422:         * We are supposed to handle UTF8, check it's valid
                    423:         * From rfc2044: encoding of the Unicode values on UTF-8:
                    424:         *
                    425:         * UCS-4 range (hex.)           UTF-8 octet sequence (binary)
                    426:         * 0000 0000-0000 007F   0xxxxxxx
                    427:         * 0000 0080-0000 07FF   110xxxxx 10xxxxxx
                    428:         * 0000 0800-0000 FFFF   1110xxxx 10xxxxxx 10xxxxxx
                    429:         *
                    430:         * Check for the 0x110000 limit too
                    431:         */
                    432:        const unsigned char *cur = ctxt->input->cur;
                    433:        unsigned char c;
                    434:        unsigned int val;
                    435: 
                    436:        c = *cur;
                    437:        if (c & 0x80) {
                    438:            if (cur[1] == 0) {
                    439:                xmlParserInputGrow(ctxt->input, INPUT_CHUNK);
                    440:                 cur = ctxt->input->cur;
                    441:             }
                    442:            if ((cur[1] & 0xc0) != 0x80)
                    443:                goto encoding_error;
                    444:            if ((c & 0xe0) == 0xe0) {
                    445: 
                    446:                if (cur[2] == 0) {
                    447:                    xmlParserInputGrow(ctxt->input, INPUT_CHUNK);
                    448:                     cur = ctxt->input->cur;
                    449:                 }
                    450:                if ((cur[2] & 0xc0) != 0x80)
                    451:                    goto encoding_error;
                    452:                if ((c & 0xf0) == 0xf0) {
                    453:                    if (cur[3] == 0) {
                    454:                        xmlParserInputGrow(ctxt->input, INPUT_CHUNK);
                    455:                         cur = ctxt->input->cur;
                    456:                     }
                    457:                    if (((c & 0xf8) != 0xf0) ||
                    458:                        ((cur[3] & 0xc0) != 0x80))
                    459:                        goto encoding_error;
                    460:                    /* 4-byte code */
                    461:                    *len = 4;
                    462:                    val = (cur[0] & 0x7) << 18;
                    463:                    val |= (cur[1] & 0x3f) << 12;
                    464:                    val |= (cur[2] & 0x3f) << 6;
                    465:                    val |= cur[3] & 0x3f;
                    466:                } else {
                    467:                  /* 3-byte code */
                    468:                    *len = 3;
                    469:                    val = (cur[0] & 0xf) << 12;
                    470:                    val |= (cur[1] & 0x3f) << 6;
                    471:                    val |= cur[2] & 0x3f;
                    472:                }
                    473:            } else {
                    474:              /* 2-byte code */
                    475:                *len = 2;
                    476:                val = (cur[0] & 0x1f) << 6;
                    477:                val |= cur[1] & 0x3f;
                    478:            }
                    479:            if (!IS_CHAR(val)) {
                    480:                htmlParseErrInt(ctxt, XML_ERR_INVALID_CHAR,
                    481:                                "Char 0x%X out of allowed range\n", val);
                    482:            }
                    483:            return(val);
                    484:        } else {
                    485:             if ((*ctxt->input->cur == 0) &&
                    486:                 (ctxt->input->cur < ctxt->input->end)) {
                    487:                     htmlParseErrInt(ctxt, XML_ERR_INVALID_CHAR,
                    488:                                "Char 0x%X out of allowed range\n", 0);
                    489:                 *len = 1;
                    490:                 return(' ');
                    491:             }
                    492:            /* 1-byte code */
                    493:            *len = 1;
                    494:            return((int) *ctxt->input->cur);
                    495:        }
                    496:     }
                    497:     /*
                    498:      * Assume it's a fixed length encoding (1) with
                    499:      * a compatible encoding for the ASCII set, since
                    500:      * XML constructs only use < 128 chars
                    501:      */
                    502:     *len = 1;
                    503:     if ((int) *ctxt->input->cur < 0x80)
                    504:        return((int) *ctxt->input->cur);
                    505: 
                    506:     /*
                    507:      * Humm this is bad, do an automatic flow conversion
                    508:      */
                    509:     {
                    510:         xmlChar * guess;
                    511:         xmlCharEncodingHandlerPtr handler;
                    512: 
                    513:         guess = htmlFindEncoding(ctxt);
                    514:         if (guess == NULL) {
                    515:             xmlSwitchEncoding(ctxt, XML_CHAR_ENCODING_8859_1);
                    516:         } else {
                    517:             if (ctxt->input->encoding != NULL)
                    518:                 xmlFree((xmlChar *) ctxt->input->encoding);
                    519:             ctxt->input->encoding = guess;
                    520:             handler = xmlFindCharEncodingHandler((const char *) guess);
                    521:             if (handler != NULL) {
                    522:                 xmlSwitchToEncoding(ctxt, handler);
                    523:             } else {
                    524:                 htmlParseErr(ctxt, XML_ERR_INVALID_ENCODING,
                    525:                              "Unsupported encoding %s", guess, NULL);
                    526:             }
                    527:         }
                    528:         ctxt->charset = XML_CHAR_ENCODING_UTF8;
                    529:     }
                    530: 
                    531:     return(xmlCurrentChar(ctxt, len));
                    532: 
                    533: encoding_error:
                    534:     /*
                    535:      * If we detect an UTF8 error that probably mean that the
                    536:      * input encoding didn't get properly advertized in the
                    537:      * declaration header. Report the error and switch the encoding
                    538:      * to ISO-Latin-1 (if you don't like this policy, just declare the
                    539:      * encoding !)
                    540:      */
                    541:     {
                    542:         char buffer[150];
                    543: 
                    544:        if (ctxt->input->end - ctxt->input->cur >= 4) {
                    545:            snprintf(buffer, 149, "Bytes: 0x%02X 0x%02X 0x%02X 0x%02X\n",
                    546:                            ctxt->input->cur[0], ctxt->input->cur[1],
                    547:                            ctxt->input->cur[2], ctxt->input->cur[3]);
                    548:        } else {
                    549:            snprintf(buffer, 149, "Bytes: 0x%02X\n", ctxt->input->cur[0]);
                    550:        }
                    551:        htmlParseErr(ctxt, XML_ERR_INVALID_ENCODING,
                    552:                     "Input is not proper UTF-8, indicate encoding !\n",
                    553:                     BAD_CAST buffer, NULL);
                    554:     }
                    555: 
                    556:     ctxt->charset = XML_CHAR_ENCODING_8859_1;
                    557:     *len = 1;
                    558:     return((int) *ctxt->input->cur);
                    559: }
                    560: 
                    561: /**
                    562:  * htmlSkipBlankChars:
                    563:  * @ctxt:  the HTML parser context
                    564:  *
                    565:  * skip all blanks character found at that point in the input streams.
                    566:  *
                    567:  * Returns the number of space chars skipped
                    568:  */
                    569: 
                    570: static int
                    571: htmlSkipBlankChars(xmlParserCtxtPtr ctxt) {
                    572:     int res = 0;
                    573: 
                    574:     while (IS_BLANK_CH(*(ctxt->input->cur))) {
                    575:        if ((*ctxt->input->cur == 0) &&
                    576:            (xmlParserInputGrow(ctxt->input, INPUT_CHUNK) <= 0)) {
                    577:                xmlPopInput(ctxt);
                    578:        } else {
                    579:            if (*(ctxt->input->cur) == '\n') {
                    580:                ctxt->input->line++; ctxt->input->col = 1;
                    581:            } else ctxt->input->col++;
                    582:            ctxt->input->cur++;
                    583:            ctxt->nbChars++;
                    584:            if (*ctxt->input->cur == 0)
                    585:                xmlParserInputGrow(ctxt->input, INPUT_CHUNK);
                    586:        }
                    587:        res++;
                    588:     }
                    589:     return(res);
                    590: }
                    591: 
                    592: 
                    593: 
                    594: /************************************************************************
                    595:  *                                                                     *
                    596:  *     The list of HTML elements and their properties          *
                    597:  *                                                                     *
                    598:  ************************************************************************/
                    599: 
                    600: /*
                    601:  *  Start Tag: 1 means the start tag can be ommited
                    602:  *  End Tag:   1 means the end tag can be ommited
                    603:  *             2 means it's forbidden (empty elements)
                    604:  *             3 means the tag is stylistic and should be closed easily
                    605:  *  Depr:      this element is deprecated
                    606:  *  DTD:       1 means that this element is valid only in the Loose DTD
                    607:  *             2 means that this element is valid only in the Frameset DTD
                    608:  *
                    609:  * Name,Start Tag,End Tag,Save End,Empty,Deprecated,DTD,inline,Description
                    610:        , subElements , impliedsubelt , Attributes, userdata
                    611:  */
                    612: 
                    613: /* Definitions and a couple of vars for HTML Elements */
                    614: 
                    615: #define FONTSTYLE "tt", "i", "b", "u", "s", "strike", "big", "small"
                    616: #define NB_FONTSTYLE 8
                    617: #define PHRASE "em", "strong", "dfn", "code", "samp", "kbd", "var", "cite", "abbr", "acronym"
                    618: #define NB_PHRASE 10
                    619: #define SPECIAL "a", "img", "applet", "embed", "object", "font", "basefont", "br", "script", "map", "q", "sub", "sup", "span", "bdo", "iframe"
                    620: #define NB_SPECIAL 16
                    621: #define INLINE FONTSTYLE, PHRASE, SPECIAL, FORMCTRL
                    622: #define NB_INLINE NB_PCDATA + NB_FONTSTYLE + NB_PHRASE + NB_SPECIAL + NB_FORMCTRL
                    623: #define BLOCK HEADING, LIST, "pre", "p", "dl", "div", "center", "noscript", "noframes", "blockquote", "form", "isindex", "hr", "table", "fieldset", "address"
                    624: #define NB_BLOCK NB_HEADING + NB_LIST + 14
                    625: #define FORMCTRL "input", "select", "textarea", "label", "button"
                    626: #define NB_FORMCTRL 5
                    627: #define PCDATA
                    628: #define NB_PCDATA 0
                    629: #define HEADING "h1", "h2", "h3", "h4", "h5", "h6"
                    630: #define NB_HEADING 6
                    631: #define LIST "ul", "ol", "dir", "menu"
                    632: #define NB_LIST 4
                    633: #define MODIFIER
                    634: #define NB_MODIFIER 0
                    635: #define FLOW BLOCK,INLINE
                    636: #define NB_FLOW NB_BLOCK + NB_INLINE
                    637: #define EMPTY NULL
                    638: 
                    639: 
                    640: static const char* const html_flow[] = { FLOW, NULL } ;
                    641: static const char* const html_inline[] = { INLINE, NULL } ;
                    642: 
                    643: /* placeholders: elts with content but no subelements */
                    644: static const char* const html_pcdata[] = { NULL } ;
                    645: #define html_cdata html_pcdata
                    646: 
                    647: 
                    648: /* ... and for HTML Attributes */
                    649: 
                    650: #define COREATTRS "id", "class", "style", "title"
                    651: #define NB_COREATTRS 4
                    652: #define I18N "lang", "dir"
                    653: #define NB_I18N 2
                    654: #define EVENTS "onclick", "ondblclick", "onmousedown", "onmouseup", "onmouseover", "onmouseout", "onkeypress", "onkeydown", "onkeyup"
                    655: #define NB_EVENTS 9
                    656: #define ATTRS COREATTRS,I18N,EVENTS
                    657: #define NB_ATTRS NB_NB_COREATTRS + NB_I18N + NB_EVENTS
                    658: #define CELLHALIGN "align", "char", "charoff"
                    659: #define NB_CELLHALIGN 3
                    660: #define CELLVALIGN "valign"
                    661: #define NB_CELLVALIGN 1
                    662: 
                    663: static const char* const html_attrs[] = { ATTRS, NULL } ;
                    664: static const char* const core_i18n_attrs[] = { COREATTRS, I18N, NULL } ;
                    665: static const char* const core_attrs[] = { COREATTRS, NULL } ;
                    666: static const char* const i18n_attrs[] = { I18N, NULL } ;
                    667: 
                    668: 
                    669: /* Other declarations that should go inline ... */
                    670: static const char* const a_attrs[] = { ATTRS, "charset", "type", "name",
                    671:        "href", "hreflang", "rel", "rev", "accesskey", "shape", "coords",
                    672:        "tabindex", "onfocus", "onblur", NULL } ;
                    673: static const char* const target_attr[] = { "target", NULL } ;
                    674: static const char* const rows_cols_attr[] = { "rows", "cols", NULL } ;
                    675: static const char* const alt_attr[] = { "alt", NULL } ;
                    676: static const char* const src_alt_attrs[] = { "src", "alt", NULL } ;
                    677: static const char* const href_attrs[] = { "href", NULL } ;
                    678: static const char* const clear_attrs[] = { "clear", NULL } ;
                    679: static const char* const inline_p[] = { INLINE, "p", NULL } ;
                    680: 
                    681: static const char* const flow_param[] = { FLOW, "param", NULL } ;
                    682: static const char* const applet_attrs[] = { COREATTRS , "codebase",
                    683:                "archive", "alt", "name", "height", "width", "align",
                    684:                "hspace", "vspace", NULL } ;
                    685: static const char* const area_attrs[] = { "shape", "coords", "href", "nohref",
                    686:        "tabindex", "accesskey", "onfocus", "onblur", NULL } ;
                    687: static const char* const basefont_attrs[] =
                    688:        { "id", "size", "color", "face", NULL } ;
                    689: static const char* const quote_attrs[] = { ATTRS, "cite", NULL } ;
                    690: static const char* const body_contents[] = { FLOW, "ins", "del", NULL } ;
                    691: static const char* const body_attrs[] = { ATTRS, "onload", "onunload", NULL } ;
                    692: static const char* const body_depr[] = { "background", "bgcolor", "text",
                    693:        "link", "vlink", "alink", NULL } ;
                    694: static const char* const button_attrs[] = { ATTRS, "name", "value", "type",
                    695:        "disabled", "tabindex", "accesskey", "onfocus", "onblur", NULL } ;
                    696: 
                    697: 
                    698: static const char* const col_attrs[] = { ATTRS, "span", "width", CELLHALIGN, CELLVALIGN, NULL } ;
                    699: static const char* const col_elt[] = { "col", NULL } ;
                    700: static const char* const edit_attrs[] = { ATTRS, "datetime", "cite", NULL } ;
                    701: static const char* const compact_attrs[] = { ATTRS, "compact", NULL } ;
                    702: static const char* const dl_contents[] = { "dt", "dd", NULL } ;
                    703: static const char* const compact_attr[] = { "compact", NULL } ;
                    704: static const char* const label_attr[] = { "label", NULL } ;
                    705: static const char* const fieldset_contents[] = { FLOW, "legend" } ;
                    706: static const char* const font_attrs[] = { COREATTRS, I18N, "size", "color", "face" , NULL } ;
                    707: static const char* const form_contents[] = { HEADING, LIST, INLINE, "pre", "p", "div", "center", "noscript", "noframes", "blockquote", "isindex", "hr", "table", "fieldset", "address", NULL } ;
                    708: static const char* const form_attrs[] = { ATTRS, "method", "enctype", "accept", "name", "onsubmit", "onreset", "accept-charset", NULL } ;
                    709: static const char* const frame_attrs[] = { COREATTRS, "longdesc", "name", "src", "frameborder", "marginwidth", "marginheight", "noresize", "scrolling" , NULL } ;
                    710: static const char* const frameset_attrs[] = { COREATTRS, "rows", "cols", "onload", "onunload", NULL } ;
                    711: static const char* const frameset_contents[] = { "frameset", "frame", "noframes", NULL } ;
                    712: static const char* const head_attrs[] = { I18N, "profile", NULL } ;
                    713: static const char* const head_contents[] = { "title", "isindex", "base", "script", "style", "meta", "link", "object", NULL } ;
                    714: static const char* const hr_depr[] = { "align", "noshade", "size", "width", NULL } ;
                    715: static const char* const version_attr[] = { "version", NULL } ;
                    716: static const char* const html_content[] = { "head", "body", "frameset", NULL } ;
                    717: static const char* const iframe_attrs[] = { COREATTRS, "longdesc", "name", "src", "frameborder", "marginwidth", "marginheight", "scrolling", "align", "height", "width", NULL } ;
                    718: static const char* const img_attrs[] = { ATTRS, "longdesc", "name", "height", "width", "usemap", "ismap", NULL } ;
                    719: static const char* const embed_attrs[] = { COREATTRS, "align", "alt", "border", "code", "codebase", "frameborder", "height", "hidden", "hspace", "name", "palette", "pluginspace", "pluginurl", "src", "type", "units", "vspace", "width", NULL } ;
                    720: static const char* const input_attrs[] = { ATTRS, "type", "name", "value", "checked", "disabled", "readonly", "size", "maxlength", "src", "alt", "usemap", "ismap", "tabindex", "accesskey", "onfocus", "onblur", "onselect", "onchange", "accept", NULL } ;
                    721: static const char* const prompt_attrs[] = { COREATTRS, I18N, "prompt", NULL } ;
                    722: static const char* const label_attrs[] = { ATTRS, "for", "accesskey", "onfocus", "onblur", NULL } ;
                    723: static const char* const legend_attrs[] = { ATTRS, "accesskey", NULL } ;
                    724: static const char* const align_attr[] = { "align", NULL } ;
                    725: static const char* const link_attrs[] = { ATTRS, "charset", "href", "hreflang", "type", "rel", "rev", "media", NULL } ;
                    726: static const char* const map_contents[] = { BLOCK, "area", NULL } ;
                    727: static const char* const name_attr[] = { "name", NULL } ;
                    728: static const char* const action_attr[] = { "action", NULL } ;
                    729: static const char* const blockli_elt[] = { BLOCK, "li", NULL } ;
1.1.1.2 ! misho     730: static const char* const meta_attrs[] = { I18N, "http-equiv", "name", "scheme", "charset", NULL } ;
1.1       misho     731: static const char* const content_attr[] = { "content", NULL } ;
                    732: static const char* const type_attr[] = { "type", NULL } ;
                    733: static const char* const noframes_content[] = { "body", FLOW MODIFIER, NULL } ;
                    734: static const char* const object_contents[] = { FLOW, "param", NULL } ;
                    735: static const char* const object_attrs[] = { ATTRS, "declare", "classid", "codebase", "data", "type", "codetype", "archive", "standby", "height", "width", "usemap", "name", "tabindex", NULL } ;
                    736: static const char* const object_depr[] = { "align", "border", "hspace", "vspace", NULL } ;
                    737: static const char* const ol_attrs[] = { "type", "compact", "start", NULL} ;
                    738: static const char* const option_elt[] = { "option", NULL } ;
                    739: static const char* const optgroup_attrs[] = { ATTRS, "disabled", NULL } ;
                    740: static const char* const option_attrs[] = { ATTRS, "disabled", "label", "selected", "value", NULL } ;
                    741: static const char* const param_attrs[] = { "id", "value", "valuetype", "type", NULL } ;
                    742: static const char* const width_attr[] = { "width", NULL } ;
                    743: static const char* const pre_content[] = { PHRASE, "tt", "i", "b", "u", "s", "strike", "a", "br", "script", "map", "q", "span", "bdo", "iframe", NULL } ;
                    744: static const char* const script_attrs[] = { "charset", "src", "defer", "event", "for", NULL } ;
                    745: static const char* const language_attr[] = { "language", NULL } ;
                    746: static const char* const select_content[] = { "optgroup", "option", NULL } ;
                    747: static const char* const select_attrs[] = { ATTRS, "name", "size", "multiple", "disabled", "tabindex", "onfocus", "onblur", "onchange", NULL } ;
                    748: static const char* const style_attrs[] = { I18N, "media", "title", NULL } ;
                    749: static const char* const table_attrs[] = { ATTRS, "summary", "width", "border", "frame", "rules", "cellspacing", "cellpadding", "datapagesize", NULL } ;
                    750: static const char* const table_depr[] = { "align", "bgcolor", NULL } ;
                    751: static const char* const table_contents[] = { "caption", "col", "colgroup", "thead", "tfoot", "tbody", "tr", NULL} ;
                    752: static const char* const tr_elt[] = { "tr", NULL } ;
                    753: static const char* const talign_attrs[] = { ATTRS, CELLHALIGN, CELLVALIGN, NULL} ;
                    754: static const char* const th_td_depr[] = { "nowrap", "bgcolor", "width", "height", NULL } ;
                    755: static const char* const th_td_attr[] = { ATTRS, "abbr", "axis", "headers", "scope", "rowspan", "colspan", CELLHALIGN, CELLVALIGN, NULL } ;
                    756: static const char* const textarea_attrs[] = { ATTRS, "name", "disabled", "readonly", "tabindex", "accesskey", "onfocus", "onblur", "onselect", "onchange", NULL } ;
                    757: static const char* const tr_contents[] = { "th", "td", NULL } ;
                    758: static const char* const bgcolor_attr[] = { "bgcolor", NULL } ;
                    759: static const char* const li_elt[] = { "li", NULL } ;
                    760: static const char* const ul_depr[] = { "type", "compact", NULL} ;
                    761: static const char* const dir_attr[] = { "dir", NULL} ;
                    762: 
                    763: #define DECL (const char**)
                    764: 
                    765: static const htmlElemDesc
                    766: html40ElementTable[] = {
                    767: { "a",         0, 0, 0, 0, 0, 0, 1, "anchor ",
                    768:        DECL html_inline , NULL , DECL a_attrs , DECL target_attr, NULL
                    769: },
                    770: { "abbr",      0, 0, 0, 0, 0, 0, 1, "abbreviated form",
                    771:        DECL html_inline , NULL , DECL html_attrs, NULL, NULL
                    772: },
                    773: { "acronym",   0, 0, 0, 0, 0, 0, 1, "",
                    774:        DECL html_inline , NULL , DECL html_attrs, NULL, NULL
                    775: },
                    776: { "address",   0, 0, 0, 0, 0, 0, 0, "information on author ",
                    777:        DECL inline_p  , NULL , DECL html_attrs, NULL, NULL
                    778: },
                    779: { "applet",    0, 0, 0, 0, 1, 1, 2, "java applet ",
                    780:        DECL flow_param , NULL , NULL , DECL applet_attrs, NULL
                    781: },
                    782: { "area",      0, 2, 2, 1, 0, 0, 0, "client-side image map area ",
                    783:        EMPTY ,  NULL , DECL area_attrs , DECL target_attr, DECL alt_attr
                    784: },
                    785: { "b",         0, 3, 0, 0, 0, 0, 1, "bold text style",
                    786:        DECL html_inline , NULL , DECL html_attrs, NULL, NULL
                    787: },
                    788: { "base",      0, 2, 2, 1, 0, 0, 0, "document base uri ",
                    789:        EMPTY , NULL , NULL , DECL target_attr, DECL href_attrs
                    790: },
                    791: { "basefont",  0, 2, 2, 1, 1, 1, 1, "base font size " ,
                    792:        EMPTY , NULL , NULL, DECL basefont_attrs, NULL
                    793: },
                    794: { "bdo",       0, 0, 0, 0, 0, 0, 1, "i18n bidi over-ride ",
                    795:        DECL html_inline , NULL , DECL core_i18n_attrs, NULL, DECL dir_attr
                    796: },
                    797: { "big",       0, 3, 0, 0, 0, 0, 1, "large text style",
                    798:        DECL html_inline , NULL , DECL html_attrs, NULL, NULL
                    799: },
                    800: { "blockquote",        0, 0, 0, 0, 0, 0, 0, "long quotation ",
                    801:        DECL html_flow , NULL , DECL quote_attrs , NULL, NULL
                    802: },
                    803: { "body",      1, 1, 0, 0, 0, 0, 0, "document body ",
                    804:        DECL body_contents , "div" , DECL body_attrs, DECL body_depr, NULL
                    805: },
                    806: { "br",                0, 2, 2, 1, 0, 0, 1, "forced line break ",
                    807:        EMPTY , NULL , DECL core_attrs, DECL clear_attrs , NULL
                    808: },
                    809: { "button",    0, 0, 0, 0, 0, 0, 2, "push button ",
                    810:        DECL html_flow MODIFIER , NULL , DECL button_attrs, NULL, NULL
                    811: },
                    812: { "caption",   0, 0, 0, 0, 0, 0, 0, "table caption ",
                    813:        DECL html_inline , NULL , DECL html_attrs, NULL, NULL
                    814: },
                    815: { "center",    0, 3, 0, 0, 1, 1, 0, "shorthand for div align=center ",
                    816:        DECL html_flow , NULL , NULL, DECL html_attrs, NULL
                    817: },
                    818: { "cite",      0, 0, 0, 0, 0, 0, 1, "citation",
                    819:        DECL html_inline , NULL , DECL html_attrs, NULL, NULL
                    820: },
                    821: { "code",      0, 0, 0, 0, 0, 0, 1, "computer code fragment",
                    822:        DECL html_inline , NULL , DECL html_attrs, NULL, NULL
                    823: },
                    824: { "col",       0, 2, 2, 1, 0, 0, 0, "table column ",
                    825:        EMPTY , NULL , DECL col_attrs , NULL, NULL
                    826: },
                    827: { "colgroup",  0, 1, 0, 0, 0, 0, 0, "table column group ",
                    828:        DECL col_elt , "col" , DECL col_attrs , NULL, NULL
                    829: },
                    830: { "dd",                0, 1, 0, 0, 0, 0, 0, "definition description ",
                    831:        DECL html_flow , NULL , DECL html_attrs, NULL, NULL
                    832: },
                    833: { "del",       0, 0, 0, 0, 0, 0, 2, "deleted text ",
                    834:        DECL html_flow , NULL , DECL edit_attrs , NULL, NULL
                    835: },
                    836: { "dfn",       0, 0, 0, 0, 0, 0, 1, "instance definition",
                    837:        DECL html_inline , NULL , DECL html_attrs, NULL, NULL
                    838: },
                    839: { "dir",       0, 0, 0, 0, 1, 1, 0, "directory list",
                    840:        DECL blockli_elt, "li" , NULL, DECL compact_attrs, NULL
                    841: },
                    842: { "div",       0, 0, 0, 0, 0, 0, 0, "generic language/style container",
                    843:        DECL html_flow, NULL, DECL html_attrs, DECL align_attr, NULL
                    844: },
                    845: { "dl",                0, 0, 0, 0, 0, 0, 0, "definition list ",
                    846:        DECL dl_contents , "dd" , DECL html_attrs, DECL compact_attr, NULL
                    847: },
                    848: { "dt",                0, 1, 0, 0, 0, 0, 0, "definition term ",
                    849:        DECL html_inline, NULL, DECL html_attrs, NULL, NULL
                    850: },
                    851: { "em",                0, 3, 0, 0, 0, 0, 1, "emphasis",
                    852:        DECL html_inline, NULL, DECL html_attrs, NULL, NULL
                    853: },
                    854: { "embed",     0, 1, 0, 0, 1, 1, 1, "generic embedded object ",
                    855:        EMPTY, NULL, DECL embed_attrs, NULL, NULL
                    856: },
                    857: { "fieldset",  0, 0, 0, 0, 0, 0, 0, "form control group ",
                    858:        DECL fieldset_contents , NULL, DECL html_attrs, NULL, NULL
                    859: },
                    860: { "font",      0, 3, 0, 0, 1, 1, 1, "local change to font ",
                    861:        DECL html_inline, NULL, NULL, DECL font_attrs, NULL
                    862: },
                    863: { "form",      0, 0, 0, 0, 0, 0, 0, "interactive form ",
                    864:        DECL form_contents, "fieldset", DECL form_attrs , DECL target_attr, DECL action_attr
                    865: },
                    866: { "frame",     0, 2, 2, 1, 0, 2, 0, "subwindow " ,
                    867:        EMPTY, NULL, NULL, DECL frame_attrs, NULL
                    868: },
                    869: { "frameset",  0, 0, 0, 0, 0, 2, 0, "window subdivision" ,
                    870:        DECL frameset_contents, "noframes" , NULL , DECL frameset_attrs, NULL
                    871: },
                    872: { "h1",                0, 0, 0, 0, 0, 0, 0, "heading ",
                    873:        DECL html_inline, NULL, DECL html_attrs, DECL align_attr, NULL
                    874: },
                    875: { "h2",                0, 0, 0, 0, 0, 0, 0, "heading ",
                    876:        DECL html_inline, NULL, DECL html_attrs, DECL align_attr, NULL
                    877: },
                    878: { "h3",                0, 0, 0, 0, 0, 0, 0, "heading ",
                    879:        DECL html_inline, NULL, DECL html_attrs, DECL align_attr, NULL
                    880: },
                    881: { "h4",                0, 0, 0, 0, 0, 0, 0, "heading ",
                    882:        DECL html_inline, NULL, DECL html_attrs, DECL align_attr, NULL
                    883: },
                    884: { "h5",                0, 0, 0, 0, 0, 0, 0, "heading ",
                    885:        DECL html_inline, NULL, DECL html_attrs, DECL align_attr, NULL
                    886: },
                    887: { "h6",                0, 0, 0, 0, 0, 0, 0, "heading ",
                    888:        DECL html_inline, NULL, DECL html_attrs, DECL align_attr, NULL
                    889: },
                    890: { "head",      1, 1, 0, 0, 0, 0, 0, "document head ",
                    891:        DECL head_contents, NULL, DECL head_attrs, NULL, NULL
                    892: },
                    893: { "hr",                0, 2, 2, 1, 0, 0, 0, "horizontal rule " ,
                    894:        EMPTY, NULL, DECL html_attrs, DECL hr_depr, NULL
                    895: },
                    896: { "html",      1, 1, 0, 0, 0, 0, 0, "document root element ",
                    897:        DECL html_content , NULL , DECL i18n_attrs, DECL version_attr, NULL
                    898: },
                    899: { "i",         0, 3, 0, 0, 0, 0, 1, "italic text style",
                    900:        DECL html_inline, NULL, DECL html_attrs, NULL, NULL
                    901: },
                    902: { "iframe",    0, 0, 0, 0, 0, 1, 2, "inline subwindow ",
                    903:        DECL html_flow, NULL, NULL, DECL iframe_attrs, NULL
                    904: },
                    905: { "img",       0, 2, 2, 1, 0, 0, 1, "embedded image ",
                    906:        EMPTY, NULL, DECL img_attrs, DECL align_attr, DECL src_alt_attrs
                    907: },
                    908: { "input",     0, 2, 2, 1, 0, 0, 1, "form control ",
                    909:        EMPTY, NULL, DECL input_attrs , DECL align_attr, NULL
                    910: },
                    911: { "ins",       0, 0, 0, 0, 0, 0, 2, "inserted text",
                    912:        DECL html_flow, NULL, DECL edit_attrs, NULL, NULL
                    913: },
                    914: { "isindex",   0, 2, 2, 1, 1, 1, 0, "single line prompt ",
                    915:        EMPTY, NULL, NULL, DECL prompt_attrs, NULL
                    916: },
                    917: { "kbd",       0, 0, 0, 0, 0, 0, 1, "text to be entered by the user",
                    918:        DECL html_inline, NULL, DECL html_attrs, NULL, NULL
                    919: },
                    920: { "label",     0, 0, 0, 0, 0, 0, 1, "form field label text ",
                    921:        DECL html_inline MODIFIER, NULL, DECL label_attrs , NULL, NULL
                    922: },
                    923: { "legend",    0, 0, 0, 0, 0, 0, 0, "fieldset legend ",
                    924:        DECL html_inline, NULL, DECL legend_attrs , DECL align_attr, NULL
                    925: },
                    926: { "li",                0, 1, 1, 0, 0, 0, 0, "list item ",
                    927:        DECL html_flow, NULL, DECL html_attrs, NULL, NULL
                    928: },
                    929: { "link",      0, 2, 2, 1, 0, 0, 0, "a media-independent link ",
                    930:        EMPTY, NULL, DECL link_attrs, DECL target_attr, NULL
                    931: },
                    932: { "map",       0, 0, 0, 0, 0, 0, 2, "client-side image map ",
                    933:        DECL map_contents , NULL, DECL html_attrs , NULL, DECL name_attr
                    934: },
                    935: { "menu",      0, 0, 0, 0, 1, 1, 0, "menu list ",
                    936:        DECL blockli_elt , NULL, NULL, DECL compact_attrs, NULL
                    937: },
                    938: { "meta",      0, 2, 2, 1, 0, 0, 0, "generic metainformation ",
                    939:        EMPTY, NULL, DECL meta_attrs , NULL , DECL content_attr
                    940: },
                    941: { "noframes",  0, 0, 0, 0, 0, 2, 0, "alternate content container for non frame-based rendering ",
                    942:        DECL noframes_content, "body" , DECL html_attrs, NULL, NULL
                    943: },
                    944: { "noscript",  0, 0, 0, 0, 0, 0, 0, "alternate content container for non script-based rendering ",
                    945:        DECL html_flow, "div", DECL html_attrs, NULL, NULL
                    946: },
                    947: { "object",    0, 0, 0, 0, 0, 0, 2, "generic embedded object ",
                    948:        DECL object_contents , "div" , DECL object_attrs, DECL object_depr, NULL
                    949: },
                    950: { "ol",                0, 0, 0, 0, 0, 0, 0, "ordered list ",
                    951:        DECL li_elt , "li" , DECL html_attrs, DECL ol_attrs, NULL
                    952: },
                    953: { "optgroup",  0, 0, 0, 0, 0, 0, 0, "option group ",
                    954:        DECL option_elt , "option", DECL optgroup_attrs, NULL, DECL label_attr
                    955: },
                    956: { "option",    0, 1, 0, 0, 0, 0, 0, "selectable choice " ,
                    957:        DECL html_pcdata, NULL, DECL option_attrs, NULL, NULL
                    958: },
                    959: { "p",         0, 1, 0, 0, 0, 0, 0, "paragraph ",
                    960:        DECL html_inline, NULL, DECL html_attrs, DECL align_attr, NULL
                    961: },
                    962: { "param",     0, 2, 2, 1, 0, 0, 0, "named property value ",
                    963:        EMPTY, NULL, DECL param_attrs, NULL, DECL name_attr
                    964: },
                    965: { "pre",       0, 0, 0, 0, 0, 0, 0, "preformatted text ",
                    966:        DECL pre_content, NULL, DECL html_attrs, DECL width_attr, NULL
                    967: },
                    968: { "q",         0, 0, 0, 0, 0, 0, 1, "short inline quotation ",
                    969:        DECL html_inline, NULL, DECL quote_attrs, NULL, NULL
                    970: },
                    971: { "s",         0, 3, 0, 0, 1, 1, 1, "strike-through text style",
                    972:        DECL html_inline, NULL, NULL, DECL html_attrs, NULL
                    973: },
                    974: { "samp",      0, 0, 0, 0, 0, 0, 1, "sample program output, scripts, etc.",
                    975:        DECL html_inline, NULL, DECL html_attrs, NULL, NULL
                    976: },
                    977: { "script",    0, 0, 0, 0, 0, 0, 2, "script statements ",
                    978:        DECL html_cdata, NULL, DECL script_attrs, DECL language_attr, DECL type_attr
                    979: },
                    980: { "select",    0, 0, 0, 0, 0, 0, 1, "option selector ",
                    981:        DECL select_content, NULL, DECL select_attrs, NULL, NULL
                    982: },
                    983: { "small",     0, 3, 0, 0, 0, 0, 1, "small text style",
                    984:        DECL html_inline, NULL, DECL html_attrs, NULL, NULL
                    985: },
                    986: { "span",      0, 0, 0, 0, 0, 0, 1, "generic language/style container ",
                    987:        DECL html_inline, NULL, DECL html_attrs, NULL, NULL
                    988: },
                    989: { "strike",    0, 3, 0, 0, 1, 1, 1, "strike-through text",
                    990:        DECL html_inline, NULL, NULL, DECL html_attrs, NULL
                    991: },
                    992: { "strong",    0, 3, 0, 0, 0, 0, 1, "strong emphasis",
                    993:        DECL html_inline, NULL, DECL html_attrs, NULL, NULL
                    994: },
                    995: { "style",     0, 0, 0, 0, 0, 0, 0, "style info ",
                    996:        DECL html_cdata, NULL, DECL style_attrs, NULL, DECL type_attr
                    997: },
                    998: { "sub",       0, 3, 0, 0, 0, 0, 1, "subscript",
                    999:        DECL html_inline, NULL, DECL html_attrs, NULL, NULL
                   1000: },
                   1001: { "sup",       0, 3, 0, 0, 0, 0, 1, "superscript ",
                   1002:        DECL html_inline, NULL, DECL html_attrs, NULL, NULL
                   1003: },
                   1004: { "table",     0, 0, 0, 0, 0, 0, 0, "",
                   1005:        DECL table_contents , "tr" , DECL table_attrs , DECL table_depr, NULL
                   1006: },
                   1007: { "tbody",     1, 0, 0, 0, 0, 0, 0, "table body ",
                   1008:        DECL tr_elt , "tr" , DECL talign_attrs, NULL, NULL
                   1009: },
                   1010: { "td",                0, 0, 0, 0, 0, 0, 0, "table data cell",
                   1011:        DECL html_flow, NULL, DECL th_td_attr, DECL th_td_depr, NULL
                   1012: },
                   1013: { "textarea",  0, 0, 0, 0, 0, 0, 1, "multi-line text field ",
                   1014:        DECL html_pcdata, NULL, DECL textarea_attrs, NULL, DECL rows_cols_attr
                   1015: },
                   1016: { "tfoot",     0, 1, 0, 0, 0, 0, 0, "table footer ",
                   1017:        DECL tr_elt , "tr" , DECL talign_attrs, NULL, NULL
                   1018: },
                   1019: { "th",                0, 1, 0, 0, 0, 0, 0, "table header cell",
                   1020:        DECL html_flow, NULL, DECL th_td_attr, DECL th_td_depr, NULL
                   1021: },
                   1022: { "thead",     0, 1, 0, 0, 0, 0, 0, "table header ",
                   1023:        DECL tr_elt , "tr" , DECL talign_attrs, NULL, NULL
                   1024: },
                   1025: { "title",     0, 0, 0, 0, 0, 0, 0, "document title ",
                   1026:        DECL html_pcdata, NULL, DECL i18n_attrs, NULL, NULL
                   1027: },
                   1028: { "tr",                0, 0, 0, 0, 0, 0, 0, "table row ",
                   1029:        DECL tr_contents , "td" , DECL talign_attrs, DECL bgcolor_attr, NULL
                   1030: },
                   1031: { "tt",                0, 3, 0, 0, 0, 0, 1, "teletype or monospaced text style",
                   1032:        DECL html_inline, NULL, DECL html_attrs, NULL, NULL
                   1033: },
                   1034: { "u",         0, 3, 0, 0, 1, 1, 1, "underlined text style",
                   1035:        DECL html_inline, NULL, NULL, DECL html_attrs, NULL
                   1036: },
                   1037: { "ul",                0, 0, 0, 0, 0, 0, 0, "unordered list ",
                   1038:        DECL li_elt , "li" , DECL html_attrs, DECL ul_depr, NULL
                   1039: },
                   1040: { "var",       0, 0, 0, 0, 0, 0, 1, "instance of a variable or program argument",
                   1041:        DECL html_inline, NULL, DECL html_attrs, NULL, NULL
                   1042: }
                   1043: };
                   1044: 
                   1045: /*
                   1046:  * start tags that imply the end of current element
                   1047:  */
                   1048: static const char * const htmlStartClose[] = {
                   1049: "form",                "form", "p", "hr", "h1", "h2", "h3", "h4", "h5", "h6",
                   1050:                "dl", "ul", "ol", "menu", "dir", "address", "pre",
                   1051:                "listing", "xmp", "head", NULL,
                   1052: "head",                "p", NULL,
                   1053: "title",       "p", NULL,
                   1054: "body",                "head", "style", "link", "title", "p", NULL,
                   1055: "frameset",    "head", "style", "link", "title", "p", NULL,
                   1056: "li",          "p", "h1", "h2", "h3", "h4", "h5", "h6", "dl", "address",
                   1057:                "pre", "listing", "xmp", "head", "li", NULL,
                   1058: "hr",          "p", "head", NULL,
                   1059: "h1",          "p", "head", NULL,
                   1060: "h2",          "p", "head", NULL,
                   1061: "h3",          "p", "head", NULL,
                   1062: "h4",          "p", "head", NULL,
                   1063: "h5",          "p", "head", NULL,
                   1064: "h6",          "p", "head", NULL,
                   1065: "dir",         "p", "head", NULL,
                   1066: "address",     "p", "head", "ul", NULL,
                   1067: "pre",         "p", "head", "ul", NULL,
                   1068: "listing",     "p", "head", NULL,
                   1069: "xmp",         "p", "head", NULL,
                   1070: "blockquote",  "p", "head", NULL,
                   1071: "dl",          "p", "dt", "menu", "dir", "address", "pre", "listing",
                   1072:                "xmp", "head", NULL,
                   1073: "dt",          "p", "menu", "dir", "address", "pre", "listing", "xmp",
                   1074:                 "head", "dd", NULL,
                   1075: "dd",          "p", "menu", "dir", "address", "pre", "listing", "xmp",
                   1076:                 "head", "dt", NULL,
                   1077: "ul",          "p", "head", "ol", "menu", "dir", "address", "pre",
                   1078:                "listing", "xmp", NULL,
                   1079: "ol",          "p", "head", "ul", NULL,
                   1080: "menu",                "p", "head", "ul", NULL,
                   1081: "p",           "p", "head", "h1", "h2", "h3", "h4", "h5", "h6", FONTSTYLE, NULL,
                   1082: "div",         "p", "head", NULL,
1.1.1.2 ! misho    1083: "noscript",    "p", NULL,
1.1       misho    1084: "center",      "font", "b", "i", "p", "head", NULL,
                   1085: "a",           "a", NULL,
                   1086: "caption",     "p", NULL,
                   1087: "colgroup",    "caption", "colgroup", "col", "p", NULL,
                   1088: "col",         "caption", "col", "p", NULL,
                   1089: "table",       "p", "head", "h1", "h2", "h3", "h4", "h5", "h6", "pre",
                   1090:                "listing", "xmp", "a", NULL,
                   1091: "th",          "th", "td", "p", "span", "font", "a", "b", "i", "u", NULL,
                   1092: "td",          "th", "td", "p", "span", "font", "a", "b", "i", "u", NULL,
                   1093: "tr",          "th", "td", "tr", "caption", "col", "colgroup", "p", NULL,
                   1094: "thead",       "caption", "col", "colgroup", NULL,
                   1095: "tfoot",       "th", "td", "tr", "caption", "col", "colgroup", "thead",
                   1096:                "tbody", "p", NULL,
                   1097: "tbody",       "th", "td", "tr", "caption", "col", "colgroup", "thead",
                   1098:                "tfoot", "tbody", "p", NULL,
                   1099: "optgroup",    "option", NULL,
                   1100: "option",      "option", NULL,
                   1101: "fieldset",    "legend", "p", "head", "h1", "h2", "h3", "h4", "h5", "h6",
                   1102:                "pre", "listing", "xmp", "a", NULL,
                   1103: NULL
                   1104: };
                   1105: 
                   1106: /*
                   1107:  * The list of HTML elements which are supposed not to have
                   1108:  * CDATA content and where a p element will be implied
                   1109:  *
                   1110:  * TODO: extend that list by reading the HTML SGML DTD on
                   1111:  *       implied paragraph
                   1112:  */
                   1113: static const char *const htmlNoContentElements[] = {
                   1114:     "html",
                   1115:     "head",
                   1116:     NULL
                   1117: };
                   1118: 
                   1119: /*
                   1120:  * The list of HTML attributes which are of content %Script;
                   1121:  * NOTE: when adding ones, check htmlIsScriptAttribute() since
                   1122:  *       it assumes the name starts with 'on'
                   1123:  */
                   1124: static const char *const htmlScriptAttributes[] = {
                   1125:     "onclick",
                   1126:     "ondblclick",
                   1127:     "onmousedown",
                   1128:     "onmouseup",
                   1129:     "onmouseover",
                   1130:     "onmousemove",
                   1131:     "onmouseout",
                   1132:     "onkeypress",
                   1133:     "onkeydown",
                   1134:     "onkeyup",
                   1135:     "onload",
                   1136:     "onunload",
                   1137:     "onfocus",
                   1138:     "onblur",
                   1139:     "onsubmit",
                   1140:     "onrest",
                   1141:     "onchange",
                   1142:     "onselect"
                   1143: };
                   1144: 
                   1145: /*
                   1146:  * This table is used by the htmlparser to know what to do with
                   1147:  * broken html pages. By assigning different priorities to different
                   1148:  * elements the parser can decide how to handle extra endtags.
                   1149:  * Endtags are only allowed to close elements with lower or equal
                   1150:  * priority.
                   1151:  */
                   1152: 
                   1153: typedef struct {
                   1154:     const char *name;
                   1155:     int priority;
                   1156: } elementPriority;
                   1157: 
                   1158: static const elementPriority htmlEndPriority[] = {
                   1159:     {"div",   150},
                   1160:     {"td",    160},
                   1161:     {"th",    160},
                   1162:     {"tr",    170},
                   1163:     {"thead", 180},
                   1164:     {"tbody", 180},
                   1165:     {"tfoot", 180},
                   1166:     {"table", 190},
                   1167:     {"head",  200},
                   1168:     {"body",  200},
                   1169:     {"html",  220},
                   1170:     {NULL,    100} /* Default priority */
                   1171: };
                   1172: 
                   1173: static const char** htmlStartCloseIndex[100];
                   1174: static int htmlStartCloseIndexinitialized = 0;
                   1175: 
                   1176: /************************************************************************
                   1177:  *                                                                     *
                   1178:  *     functions to handle HTML specific data                  *
                   1179:  *                                                                     *
                   1180:  ************************************************************************/
                   1181: 
                   1182: /**
                   1183:  * htmlInitAutoClose:
                   1184:  *
                   1185:  * Initialize the htmlStartCloseIndex for fast lookup of closing tags names.
                   1186:  * This is not reentrant. Call xmlInitParser() once before processing in
                   1187:  * case of use in multithreaded programs.
                   1188:  */
                   1189: void
                   1190: htmlInitAutoClose(void) {
                   1191:     int indx, i = 0;
                   1192: 
                   1193:     if (htmlStartCloseIndexinitialized) return;
                   1194: 
                   1195:     for (indx = 0;indx < 100;indx ++) htmlStartCloseIndex[indx] = NULL;
                   1196:     indx = 0;
                   1197:     while ((htmlStartClose[i] != NULL) && (indx < 100 - 1)) {
                   1198:         htmlStartCloseIndex[indx++] = (const char**) &htmlStartClose[i];
                   1199:        while (htmlStartClose[i] != NULL) i++;
                   1200:        i++;
                   1201:     }
                   1202:     htmlStartCloseIndexinitialized = 1;
                   1203: }
                   1204: 
                   1205: /**
                   1206:  * htmlTagLookup:
                   1207:  * @tag:  The tag name in lowercase
                   1208:  *
                   1209:  * Lookup the HTML tag in the ElementTable
                   1210:  *
                   1211:  * Returns the related htmlElemDescPtr or NULL if not found.
                   1212:  */
                   1213: const htmlElemDesc *
                   1214: htmlTagLookup(const xmlChar *tag) {
                   1215:     unsigned int i;
                   1216: 
                   1217:     for (i = 0; i < (sizeof(html40ElementTable) /
                   1218:                      sizeof(html40ElementTable[0]));i++) {
                   1219:         if (!xmlStrcasecmp(tag, BAD_CAST html40ElementTable[i].name))
                   1220:            return((htmlElemDescPtr) &html40ElementTable[i]);
                   1221:     }
                   1222:     return(NULL);
                   1223: }
                   1224: 
                   1225: /**
                   1226:  * htmlGetEndPriority:
                   1227:  * @name: The name of the element to look up the priority for.
                   1228:  *
                   1229:  * Return value: The "endtag" priority.
                   1230:  **/
                   1231: static int
                   1232: htmlGetEndPriority (const xmlChar *name) {
                   1233:     int i = 0;
                   1234: 
                   1235:     while ((htmlEndPriority[i].name != NULL) &&
                   1236:           (!xmlStrEqual((const xmlChar *)htmlEndPriority[i].name, name)))
                   1237:        i++;
                   1238: 
                   1239:     return(htmlEndPriority[i].priority);
                   1240: }
                   1241: 
                   1242: 
                   1243: /**
                   1244:  * htmlCheckAutoClose:
                   1245:  * @newtag:  The new tag name
                   1246:  * @oldtag:  The old tag name
                   1247:  *
                   1248:  * Checks whether the new tag is one of the registered valid tags for
                   1249:  * closing old.
                   1250:  * Initialize the htmlStartCloseIndex for fast lookup of closing tags names.
                   1251:  *
                   1252:  * Returns 0 if no, 1 if yes.
                   1253:  */
                   1254: static int
                   1255: htmlCheckAutoClose(const xmlChar * newtag, const xmlChar * oldtag)
                   1256: {
                   1257:     int i, indx;
                   1258:     const char **closed = NULL;
                   1259: 
                   1260:     if (htmlStartCloseIndexinitialized == 0)
                   1261:         htmlInitAutoClose();
                   1262: 
                   1263:     /* inefficient, but not a big deal */
                   1264:     for (indx = 0; indx < 100; indx++) {
                   1265:         closed = htmlStartCloseIndex[indx];
                   1266:         if (closed == NULL)
                   1267:             return (0);
                   1268:         if (xmlStrEqual(BAD_CAST * closed, newtag))
                   1269:             break;
                   1270:     }
                   1271: 
                   1272:     i = closed - htmlStartClose;
                   1273:     i++;
                   1274:     while (htmlStartClose[i] != NULL) {
                   1275:         if (xmlStrEqual(BAD_CAST htmlStartClose[i], oldtag)) {
                   1276:             return (1);
                   1277:         }
                   1278:         i++;
                   1279:     }
                   1280:     return (0);
                   1281: }
                   1282: 
                   1283: /**
                   1284:  * htmlAutoCloseOnClose:
                   1285:  * @ctxt:  an HTML parser context
                   1286:  * @newtag:  The new tag name
                   1287:  * @force:  force the tag closure
                   1288:  *
                   1289:  * The HTML DTD allows an ending tag to implicitly close other tags.
                   1290:  */
                   1291: static void
                   1292: htmlAutoCloseOnClose(htmlParserCtxtPtr ctxt, const xmlChar * newtag)
                   1293: {
                   1294:     const htmlElemDesc *info;
                   1295:     int i, priority;
                   1296: 
                   1297:     priority = htmlGetEndPriority(newtag);
                   1298: 
                   1299:     for (i = (ctxt->nameNr - 1); i >= 0; i--) {
                   1300: 
                   1301:         if (xmlStrEqual(newtag, ctxt->nameTab[i]))
                   1302:             break;
                   1303:         /*
                   1304:          * A missplaced endtag can only close elements with lower
                   1305:          * or equal priority, so if we find an element with higher
                   1306:          * priority before we find an element with
                   1307:          * matching name, we just ignore this endtag
                   1308:          */
                   1309:         if (htmlGetEndPriority(ctxt->nameTab[i]) > priority)
                   1310:             return;
                   1311:     }
                   1312:     if (i < 0)
                   1313:         return;
                   1314: 
                   1315:     while (!xmlStrEqual(newtag, ctxt->name)) {
                   1316:         info = htmlTagLookup(ctxt->name);
                   1317:         if ((info != NULL) && (info->endTag == 3)) {
                   1318:             htmlParseErr(ctxt, XML_ERR_TAG_NAME_MISMATCH,
                   1319:                         "Opening and ending tag mismatch: %s and %s\n",
                   1320:                         newtag, ctxt->name);
                   1321:         }
                   1322:         if ((ctxt->sax != NULL) && (ctxt->sax->endElement != NULL))
                   1323:             ctxt->sax->endElement(ctxt->userData, ctxt->name);
                   1324:        htmlnamePop(ctxt);
                   1325:     }
                   1326: }
                   1327: 
                   1328: /**
                   1329:  * htmlAutoCloseOnEnd:
                   1330:  * @ctxt:  an HTML parser context
                   1331:  *
                   1332:  * Close all remaining tags at the end of the stream
                   1333:  */
                   1334: static void
                   1335: htmlAutoCloseOnEnd(htmlParserCtxtPtr ctxt)
                   1336: {
                   1337:     int i;
                   1338: 
                   1339:     if (ctxt->nameNr == 0)
                   1340:         return;
                   1341:     for (i = (ctxt->nameNr - 1); i >= 0; i--) {
                   1342:         if ((ctxt->sax != NULL) && (ctxt->sax->endElement != NULL))
                   1343:             ctxt->sax->endElement(ctxt->userData, ctxt->name);
                   1344:        htmlnamePop(ctxt);
                   1345:     }
                   1346: }
                   1347: 
                   1348: /**
                   1349:  * htmlAutoClose:
                   1350:  * @ctxt:  an HTML parser context
                   1351:  * @newtag:  The new tag name or NULL
                   1352:  *
                   1353:  * The HTML DTD allows a tag to implicitly close other tags.
                   1354:  * The list is kept in htmlStartClose array. This function is
                   1355:  * called when a new tag has been detected and generates the
                   1356:  * appropriates closes if possible/needed.
                   1357:  * If newtag is NULL this mean we are at the end of the resource
                   1358:  * and we should check
                   1359:  */
                   1360: static void
                   1361: htmlAutoClose(htmlParserCtxtPtr ctxt, const xmlChar * newtag)
                   1362: {
                   1363:     while ((newtag != NULL) && (ctxt->name != NULL) &&
                   1364:            (htmlCheckAutoClose(newtag, ctxt->name))) {
                   1365:         if ((ctxt->sax != NULL) && (ctxt->sax->endElement != NULL))
                   1366:             ctxt->sax->endElement(ctxt->userData, ctxt->name);
                   1367:        htmlnamePop(ctxt);
                   1368:     }
                   1369:     if (newtag == NULL) {
                   1370:         htmlAutoCloseOnEnd(ctxt);
                   1371:         return;
                   1372:     }
                   1373:     while ((newtag == NULL) && (ctxt->name != NULL) &&
                   1374:            ((xmlStrEqual(ctxt->name, BAD_CAST "head")) ||
                   1375:             (xmlStrEqual(ctxt->name, BAD_CAST "body")) ||
                   1376:             (xmlStrEqual(ctxt->name, BAD_CAST "html")))) {
                   1377:         if ((ctxt->sax != NULL) && (ctxt->sax->endElement != NULL))
                   1378:             ctxt->sax->endElement(ctxt->userData, ctxt->name);
                   1379:        htmlnamePop(ctxt);
                   1380:     }
                   1381: }
                   1382: 
                   1383: /**
                   1384:  * htmlAutoCloseTag:
                   1385:  * @doc:  the HTML document
                   1386:  * @name:  The tag name
                   1387:  * @elem:  the HTML element
                   1388:  *
                   1389:  * The HTML DTD allows a tag to implicitly close other tags.
                   1390:  * The list is kept in htmlStartClose array. This function checks
                   1391:  * if the element or one of it's children would autoclose the
                   1392:  * given tag.
                   1393:  *
                   1394:  * Returns 1 if autoclose, 0 otherwise
                   1395:  */
                   1396: int
                   1397: htmlAutoCloseTag(htmlDocPtr doc, const xmlChar *name, htmlNodePtr elem) {
                   1398:     htmlNodePtr child;
                   1399: 
                   1400:     if (elem == NULL) return(1);
                   1401:     if (xmlStrEqual(name, elem->name)) return(0);
                   1402:     if (htmlCheckAutoClose(elem->name, name)) return(1);
                   1403:     child = elem->children;
                   1404:     while (child != NULL) {
                   1405:         if (htmlAutoCloseTag(doc, name, child)) return(1);
                   1406:        child = child->next;
                   1407:     }
                   1408:     return(0);
                   1409: }
                   1410: 
                   1411: /**
                   1412:  * htmlIsAutoClosed:
                   1413:  * @doc:  the HTML document
                   1414:  * @elem:  the HTML element
                   1415:  *
                   1416:  * The HTML DTD allows a tag to implicitly close other tags.
                   1417:  * The list is kept in htmlStartClose array. This function checks
                   1418:  * if a tag is autoclosed by one of it's child
                   1419:  *
                   1420:  * Returns 1 if autoclosed, 0 otherwise
                   1421:  */
                   1422: int
                   1423: htmlIsAutoClosed(htmlDocPtr doc, htmlNodePtr elem) {
                   1424:     htmlNodePtr child;
                   1425: 
                   1426:     if (elem == NULL) return(1);
                   1427:     child = elem->children;
                   1428:     while (child != NULL) {
                   1429:        if (htmlAutoCloseTag(doc, elem->name, child)) return(1);
                   1430:        child = child->next;
                   1431:     }
                   1432:     return(0);
                   1433: }
                   1434: 
                   1435: /**
                   1436:  * htmlCheckImplied:
                   1437:  * @ctxt:  an HTML parser context
                   1438:  * @newtag:  The new tag name
                   1439:  *
                   1440:  * The HTML DTD allows a tag to exists only implicitly
                   1441:  * called when a new tag has been detected and generates the
                   1442:  * appropriates implicit tags if missing
                   1443:  */
                   1444: static void
                   1445: htmlCheckImplied(htmlParserCtxtPtr ctxt, const xmlChar *newtag) {
                   1446:     int i;
                   1447: 
                   1448:     if (ctxt->options & HTML_PARSE_NOIMPLIED)
                   1449:         return;
                   1450:     if (!htmlOmittedDefaultValue)
                   1451:        return;
                   1452:     if (xmlStrEqual(newtag, BAD_CAST"html"))
                   1453:        return;
                   1454:     if (ctxt->nameNr <= 0) {
                   1455:        htmlnamePush(ctxt, BAD_CAST"html");
                   1456:        if ((ctxt->sax != NULL) && (ctxt->sax->startElement != NULL))
                   1457:            ctxt->sax->startElement(ctxt->userData, BAD_CAST"html", NULL);
                   1458:     }
                   1459:     if ((xmlStrEqual(newtag, BAD_CAST"body")) || (xmlStrEqual(newtag, BAD_CAST"head")))
                   1460:         return;
                   1461:     if ((ctxt->nameNr <= 1) &&
                   1462:         ((xmlStrEqual(newtag, BAD_CAST"script")) ||
                   1463:         (xmlStrEqual(newtag, BAD_CAST"style")) ||
                   1464:         (xmlStrEqual(newtag, BAD_CAST"meta")) ||
                   1465:         (xmlStrEqual(newtag, BAD_CAST"link")) ||
                   1466:         (xmlStrEqual(newtag, BAD_CAST"title")) ||
                   1467:         (xmlStrEqual(newtag, BAD_CAST"base")))) {
                   1468:         if (ctxt->html >= 3) {
                   1469:             /* we already saw or generated an <head> before */
                   1470:             return;
                   1471:         }
                   1472:         /*
                   1473:          * dropped OBJECT ... i you put it first BODY will be
                   1474:          * assumed !
                   1475:          */
                   1476:         htmlnamePush(ctxt, BAD_CAST"head");
                   1477:         if ((ctxt->sax != NULL) && (ctxt->sax->startElement != NULL))
                   1478:             ctxt->sax->startElement(ctxt->userData, BAD_CAST"head", NULL);
                   1479:     } else if ((!xmlStrEqual(newtag, BAD_CAST"noframes")) &&
                   1480:               (!xmlStrEqual(newtag, BAD_CAST"frame")) &&
                   1481:               (!xmlStrEqual(newtag, BAD_CAST"frameset"))) {
                   1482:         if (ctxt->html >= 10) {
                   1483:             /* we already saw or generated a <body> before */
                   1484:             return;
                   1485:         }
                   1486:        for (i = 0;i < ctxt->nameNr;i++) {
                   1487:            if (xmlStrEqual(ctxt->nameTab[i], BAD_CAST"body")) {
                   1488:                return;
                   1489:            }
                   1490:            if (xmlStrEqual(ctxt->nameTab[i], BAD_CAST"head")) {
                   1491:                return;
                   1492:            }
                   1493:        }
                   1494: 
                   1495:        htmlnamePush(ctxt, BAD_CAST"body");
                   1496:        if ((ctxt->sax != NULL) && (ctxt->sax->startElement != NULL))
                   1497:            ctxt->sax->startElement(ctxt->userData, BAD_CAST"body", NULL);
                   1498:     }
                   1499: }
                   1500: 
                   1501: /**
                   1502:  * htmlCheckParagraph
                   1503:  * @ctxt:  an HTML parser context
                   1504:  *
                   1505:  * Check whether a p element need to be implied before inserting
                   1506:  * characters in the current element.
                   1507:  *
                   1508:  * Returns 1 if a paragraph has been inserted, 0 if not and -1
                   1509:  *         in case of error.
                   1510:  */
                   1511: 
                   1512: static int
                   1513: htmlCheckParagraph(htmlParserCtxtPtr ctxt) {
                   1514:     const xmlChar *tag;
                   1515:     int i;
                   1516: 
                   1517:     if (ctxt == NULL)
                   1518:        return(-1);
                   1519:     tag = ctxt->name;
                   1520:     if (tag == NULL) {
                   1521:        htmlAutoClose(ctxt, BAD_CAST"p");
                   1522:        htmlCheckImplied(ctxt, BAD_CAST"p");
                   1523:        htmlnamePush(ctxt, BAD_CAST"p");
                   1524:        if ((ctxt->sax != NULL) && (ctxt->sax->startElement != NULL))
                   1525:            ctxt->sax->startElement(ctxt->userData, BAD_CAST"p", NULL);
                   1526:        return(1);
                   1527:     }
                   1528:     if (!htmlOmittedDefaultValue)
                   1529:        return(0);
                   1530:     for (i = 0; htmlNoContentElements[i] != NULL; i++) {
                   1531:        if (xmlStrEqual(tag, BAD_CAST htmlNoContentElements[i])) {
                   1532:            htmlAutoClose(ctxt, BAD_CAST"p");
                   1533:            htmlCheckImplied(ctxt, BAD_CAST"p");
                   1534:            htmlnamePush(ctxt, BAD_CAST"p");
                   1535:            if ((ctxt->sax != NULL) && (ctxt->sax->startElement != NULL))
                   1536:                ctxt->sax->startElement(ctxt->userData, BAD_CAST"p", NULL);
                   1537:            return(1);
                   1538:        }
                   1539:     }
                   1540:     return(0);
                   1541: }
                   1542: 
                   1543: /**
                   1544:  * htmlIsScriptAttribute:
                   1545:  * @name:  an attribute name
                   1546:  *
                   1547:  * Check if an attribute is of content type Script
                   1548:  *
                   1549:  * Returns 1 is the attribute is a script 0 otherwise
                   1550:  */
                   1551: int
                   1552: htmlIsScriptAttribute(const xmlChar *name) {
                   1553:     unsigned int i;
                   1554: 
                   1555:     if (name == NULL)
                   1556:       return(0);
                   1557:     /*
                   1558:      * all script attributes start with 'on'
                   1559:      */
                   1560:     if ((name[0] != 'o') || (name[1] != 'n'))
                   1561:       return(0);
                   1562:     for (i = 0;
                   1563:         i < sizeof(htmlScriptAttributes)/sizeof(htmlScriptAttributes[0]);
                   1564:         i++) {
                   1565:        if (xmlStrEqual(name, (const xmlChar *) htmlScriptAttributes[i]))
                   1566:            return(1);
                   1567:     }
                   1568:     return(0);
                   1569: }
                   1570: 
                   1571: /************************************************************************
                   1572:  *                                                                     *
                   1573:  *     The list of HTML predefined entities                    *
                   1574:  *                                                                     *
                   1575:  ************************************************************************/
                   1576: 
                   1577: 
                   1578: static const htmlEntityDesc  html40EntitiesTable[] = {
                   1579: /*
                   1580:  * the 4 absolute ones, plus apostrophe.
                   1581:  */
                   1582: { 34,  "quot", "quotation mark = APL quote, U+0022 ISOnum" },
                   1583: { 38,  "amp",  "ampersand, U+0026 ISOnum" },
                   1584: { 39,  "apos", "single quote" },
                   1585: { 60,  "lt",   "less-than sign, U+003C ISOnum" },
                   1586: { 62,  "gt",   "greater-than sign, U+003E ISOnum" },
                   1587: 
                   1588: /*
                   1589:  * A bunch still in the 128-255 range
                   1590:  * Replacing them depend really on the charset used.
                   1591:  */
                   1592: { 160, "nbsp", "no-break space = non-breaking space, U+00A0 ISOnum" },
                   1593: { 161, "iexcl","inverted exclamation mark, U+00A1 ISOnum" },
                   1594: { 162, "cent", "cent sign, U+00A2 ISOnum" },
                   1595: { 163, "pound","pound sign, U+00A3 ISOnum" },
                   1596: { 164, "curren","currency sign, U+00A4 ISOnum" },
                   1597: { 165, "yen",  "yen sign = yuan sign, U+00A5 ISOnum" },
                   1598: { 166, "brvbar","broken bar = broken vertical bar, U+00A6 ISOnum" },
                   1599: { 167, "sect", "section sign, U+00A7 ISOnum" },
                   1600: { 168, "uml",  "diaeresis = spacing diaeresis, U+00A8 ISOdia" },
                   1601: { 169, "copy", "copyright sign, U+00A9 ISOnum" },
                   1602: { 170, "ordf", "feminine ordinal indicator, U+00AA ISOnum" },
                   1603: { 171, "laquo","left-pointing double angle quotation mark = left pointing guillemet, U+00AB ISOnum" },
                   1604: { 172, "not",  "not sign, U+00AC ISOnum" },
                   1605: { 173, "shy",  "soft hyphen = discretionary hyphen, U+00AD ISOnum" },
                   1606: { 174, "reg",  "registered sign = registered trade mark sign, U+00AE ISOnum" },
                   1607: { 175, "macr", "macron = spacing macron = overline = APL overbar, U+00AF ISOdia" },
                   1608: { 176, "deg",  "degree sign, U+00B0 ISOnum" },
                   1609: { 177, "plusmn","plus-minus sign = plus-or-minus sign, U+00B1 ISOnum" },
                   1610: { 178, "sup2", "superscript two = superscript digit two = squared, U+00B2 ISOnum" },
                   1611: { 179, "sup3", "superscript three = superscript digit three = cubed, U+00B3 ISOnum" },
                   1612: { 180, "acute","acute accent = spacing acute, U+00B4 ISOdia" },
                   1613: { 181, "micro","micro sign, U+00B5 ISOnum" },
                   1614: { 182, "para", "pilcrow sign = paragraph sign, U+00B6 ISOnum" },
                   1615: { 183, "middot","middle dot = Georgian comma Greek middle dot, U+00B7 ISOnum" },
                   1616: { 184, "cedil","cedilla = spacing cedilla, U+00B8 ISOdia" },
                   1617: { 185, "sup1", "superscript one = superscript digit one, U+00B9 ISOnum" },
                   1618: { 186, "ordm", "masculine ordinal indicator, U+00BA ISOnum" },
                   1619: { 187, "raquo","right-pointing double angle quotation mark right pointing guillemet, U+00BB ISOnum" },
                   1620: { 188, "frac14","vulgar fraction one quarter = fraction one quarter, U+00BC ISOnum" },
                   1621: { 189, "frac12","vulgar fraction one half = fraction one half, U+00BD ISOnum" },
                   1622: { 190, "frac34","vulgar fraction three quarters = fraction three quarters, U+00BE ISOnum" },
                   1623: { 191, "iquest","inverted question mark = turned question mark, U+00BF ISOnum" },
                   1624: { 192, "Agrave","latin capital letter A with grave = latin capital letter A grave, U+00C0 ISOlat1" },
                   1625: { 193, "Aacute","latin capital letter A with acute, U+00C1 ISOlat1" },
                   1626: { 194, "Acirc","latin capital letter A with circumflex, U+00C2 ISOlat1" },
                   1627: { 195, "Atilde","latin capital letter A with tilde, U+00C3 ISOlat1" },
                   1628: { 196, "Auml", "latin capital letter A with diaeresis, U+00C4 ISOlat1" },
                   1629: { 197, "Aring","latin capital letter A with ring above = latin capital letter A ring, U+00C5 ISOlat1" },
                   1630: { 198, "AElig","latin capital letter AE = latin capital ligature AE, U+00C6 ISOlat1" },
                   1631: { 199, "Ccedil","latin capital letter C with cedilla, U+00C7 ISOlat1" },
                   1632: { 200, "Egrave","latin capital letter E with grave, U+00C8 ISOlat1" },
                   1633: { 201, "Eacute","latin capital letter E with acute, U+00C9 ISOlat1" },
                   1634: { 202, "Ecirc","latin capital letter E with circumflex, U+00CA ISOlat1" },
                   1635: { 203, "Euml", "latin capital letter E with diaeresis, U+00CB ISOlat1" },
                   1636: { 204, "Igrave","latin capital letter I with grave, U+00CC ISOlat1" },
                   1637: { 205, "Iacute","latin capital letter I with acute, U+00CD ISOlat1" },
                   1638: { 206, "Icirc","latin capital letter I with circumflex, U+00CE ISOlat1" },
                   1639: { 207, "Iuml", "latin capital letter I with diaeresis, U+00CF ISOlat1" },
                   1640: { 208, "ETH",  "latin capital letter ETH, U+00D0 ISOlat1" },
                   1641: { 209, "Ntilde","latin capital letter N with tilde, U+00D1 ISOlat1" },
                   1642: { 210, "Ograve","latin capital letter O with grave, U+00D2 ISOlat1" },
                   1643: { 211, "Oacute","latin capital letter O with acute, U+00D3 ISOlat1" },
                   1644: { 212, "Ocirc","latin capital letter O with circumflex, U+00D4 ISOlat1" },
                   1645: { 213, "Otilde","latin capital letter O with tilde, U+00D5 ISOlat1" },
                   1646: { 214, "Ouml", "latin capital letter O with diaeresis, U+00D6 ISOlat1" },
                   1647: { 215, "times","multiplication sign, U+00D7 ISOnum" },
                   1648: { 216, "Oslash","latin capital letter O with stroke latin capital letter O slash, U+00D8 ISOlat1" },
                   1649: { 217, "Ugrave","latin capital letter U with grave, U+00D9 ISOlat1" },
                   1650: { 218, "Uacute","latin capital letter U with acute, U+00DA ISOlat1" },
                   1651: { 219, "Ucirc","latin capital letter U with circumflex, U+00DB ISOlat1" },
                   1652: { 220, "Uuml", "latin capital letter U with diaeresis, U+00DC ISOlat1" },
                   1653: { 221, "Yacute","latin capital letter Y with acute, U+00DD ISOlat1" },
                   1654: { 222, "THORN","latin capital letter THORN, U+00DE ISOlat1" },
                   1655: { 223, "szlig","latin small letter sharp s = ess-zed, U+00DF ISOlat1" },
                   1656: { 224, "agrave","latin small letter a with grave = latin small letter a grave, U+00E0 ISOlat1" },
                   1657: { 225, "aacute","latin small letter a with acute, U+00E1 ISOlat1" },
                   1658: { 226, "acirc","latin small letter a with circumflex, U+00E2 ISOlat1" },
                   1659: { 227, "atilde","latin small letter a with tilde, U+00E3 ISOlat1" },
                   1660: { 228, "auml", "latin small letter a with diaeresis, U+00E4 ISOlat1" },
                   1661: { 229, "aring","latin small letter a with ring above = latin small letter a ring, U+00E5 ISOlat1" },
                   1662: { 230, "aelig","latin small letter ae = latin small ligature ae, U+00E6 ISOlat1" },
                   1663: { 231, "ccedil","latin small letter c with cedilla, U+00E7 ISOlat1" },
                   1664: { 232, "egrave","latin small letter e with grave, U+00E8 ISOlat1" },
                   1665: { 233, "eacute","latin small letter e with acute, U+00E9 ISOlat1" },
                   1666: { 234, "ecirc","latin small letter e with circumflex, U+00EA ISOlat1" },
                   1667: { 235, "euml", "latin small letter e with diaeresis, U+00EB ISOlat1" },
                   1668: { 236, "igrave","latin small letter i with grave, U+00EC ISOlat1" },
                   1669: { 237, "iacute","latin small letter i with acute, U+00ED ISOlat1" },
                   1670: { 238, "icirc","latin small letter i with circumflex, U+00EE ISOlat1" },
                   1671: { 239, "iuml", "latin small letter i with diaeresis, U+00EF ISOlat1" },
                   1672: { 240, "eth",  "latin small letter eth, U+00F0 ISOlat1" },
                   1673: { 241, "ntilde","latin small letter n with tilde, U+00F1 ISOlat1" },
                   1674: { 242, "ograve","latin small letter o with grave, U+00F2 ISOlat1" },
                   1675: { 243, "oacute","latin small letter o with acute, U+00F3 ISOlat1" },
                   1676: { 244, "ocirc","latin small letter o with circumflex, U+00F4 ISOlat1" },
                   1677: { 245, "otilde","latin small letter o with tilde, U+00F5 ISOlat1" },
                   1678: { 246, "ouml", "latin small letter o with diaeresis, U+00F6 ISOlat1" },
                   1679: { 247, "divide","division sign, U+00F7 ISOnum" },
                   1680: { 248, "oslash","latin small letter o with stroke, = latin small letter o slash, U+00F8 ISOlat1" },
                   1681: { 249, "ugrave","latin small letter u with grave, U+00F9 ISOlat1" },
                   1682: { 250, "uacute","latin small letter u with acute, U+00FA ISOlat1" },
                   1683: { 251, "ucirc","latin small letter u with circumflex, U+00FB ISOlat1" },
                   1684: { 252, "uuml", "latin small letter u with diaeresis, U+00FC ISOlat1" },
                   1685: { 253, "yacute","latin small letter y with acute, U+00FD ISOlat1" },
                   1686: { 254, "thorn","latin small letter thorn with, U+00FE ISOlat1" },
                   1687: { 255, "yuml", "latin small letter y with diaeresis, U+00FF ISOlat1" },
                   1688: 
                   1689: { 338, "OElig","latin capital ligature OE, U+0152 ISOlat2" },
                   1690: { 339, "oelig","latin small ligature oe, U+0153 ISOlat2" },
                   1691: { 352, "Scaron","latin capital letter S with caron, U+0160 ISOlat2" },
                   1692: { 353, "scaron","latin small letter s with caron, U+0161 ISOlat2" },
                   1693: { 376, "Yuml", "latin capital letter Y with diaeresis, U+0178 ISOlat2" },
                   1694: 
                   1695: /*
                   1696:  * Anything below should really be kept as entities references
                   1697:  */
                   1698: { 402, "fnof", "latin small f with hook = function = florin, U+0192 ISOtech" },
                   1699: 
                   1700: { 710, "circ", "modifier letter circumflex accent, U+02C6 ISOpub" },
                   1701: { 732, "tilde","small tilde, U+02DC ISOdia" },
                   1702: 
                   1703: { 913, "Alpha","greek capital letter alpha, U+0391" },
                   1704: { 914, "Beta", "greek capital letter beta, U+0392" },
                   1705: { 915, "Gamma","greek capital letter gamma, U+0393 ISOgrk3" },
                   1706: { 916, "Delta","greek capital letter delta, U+0394 ISOgrk3" },
                   1707: { 917, "Epsilon","greek capital letter epsilon, U+0395" },
                   1708: { 918, "Zeta", "greek capital letter zeta, U+0396" },
                   1709: { 919, "Eta",  "greek capital letter eta, U+0397" },
                   1710: { 920, "Theta","greek capital letter theta, U+0398 ISOgrk3" },
                   1711: { 921, "Iota", "greek capital letter iota, U+0399" },
                   1712: { 922, "Kappa","greek capital letter kappa, U+039A" },
                   1713: { 923, "Lambda", "greek capital letter lambda, U+039B ISOgrk3" },
                   1714: { 924, "Mu",   "greek capital letter mu, U+039C" },
                   1715: { 925, "Nu",   "greek capital letter nu, U+039D" },
                   1716: { 926, "Xi",   "greek capital letter xi, U+039E ISOgrk3" },
                   1717: { 927, "Omicron","greek capital letter omicron, U+039F" },
                   1718: { 928, "Pi",   "greek capital letter pi, U+03A0 ISOgrk3" },
                   1719: { 929, "Rho",  "greek capital letter rho, U+03A1" },
                   1720: { 931, "Sigma","greek capital letter sigma, U+03A3 ISOgrk3" },
                   1721: { 932, "Tau",  "greek capital letter tau, U+03A4" },
                   1722: { 933, "Upsilon","greek capital letter upsilon, U+03A5 ISOgrk3" },
                   1723: { 934, "Phi",  "greek capital letter phi, U+03A6 ISOgrk3" },
                   1724: { 935, "Chi",  "greek capital letter chi, U+03A7" },
                   1725: { 936, "Psi",  "greek capital letter psi, U+03A8 ISOgrk3" },
                   1726: { 937, "Omega","greek capital letter omega, U+03A9 ISOgrk3" },
                   1727: 
                   1728: { 945, "alpha","greek small letter alpha, U+03B1 ISOgrk3" },
                   1729: { 946, "beta", "greek small letter beta, U+03B2 ISOgrk3" },
                   1730: { 947, "gamma","greek small letter gamma, U+03B3 ISOgrk3" },
                   1731: { 948, "delta","greek small letter delta, U+03B4 ISOgrk3" },
                   1732: { 949, "epsilon","greek small letter epsilon, U+03B5 ISOgrk3" },
                   1733: { 950, "zeta", "greek small letter zeta, U+03B6 ISOgrk3" },
                   1734: { 951, "eta",  "greek small letter eta, U+03B7 ISOgrk3" },
                   1735: { 952, "theta","greek small letter theta, U+03B8 ISOgrk3" },
                   1736: { 953, "iota", "greek small letter iota, U+03B9 ISOgrk3" },
                   1737: { 954, "kappa","greek small letter kappa, U+03BA ISOgrk3" },
                   1738: { 955, "lambda","greek small letter lambda, U+03BB ISOgrk3" },
                   1739: { 956, "mu",   "greek small letter mu, U+03BC ISOgrk3" },
                   1740: { 957, "nu",   "greek small letter nu, U+03BD ISOgrk3" },
                   1741: { 958, "xi",   "greek small letter xi, U+03BE ISOgrk3" },
                   1742: { 959, "omicron","greek small letter omicron, U+03BF NEW" },
                   1743: { 960, "pi",   "greek small letter pi, U+03C0 ISOgrk3" },
                   1744: { 961, "rho",  "greek small letter rho, U+03C1 ISOgrk3" },
                   1745: { 962, "sigmaf","greek small letter final sigma, U+03C2 ISOgrk3" },
                   1746: { 963, "sigma","greek small letter sigma, U+03C3 ISOgrk3" },
                   1747: { 964, "tau",  "greek small letter tau, U+03C4 ISOgrk3" },
                   1748: { 965, "upsilon","greek small letter upsilon, U+03C5 ISOgrk3" },
                   1749: { 966, "phi",  "greek small letter phi, U+03C6 ISOgrk3" },
                   1750: { 967, "chi",  "greek small letter chi, U+03C7 ISOgrk3" },
                   1751: { 968, "psi",  "greek small letter psi, U+03C8 ISOgrk3" },
                   1752: { 969, "omega","greek small letter omega, U+03C9 ISOgrk3" },
                   1753: { 977, "thetasym","greek small letter theta symbol, U+03D1 NEW" },
                   1754: { 978, "upsih","greek upsilon with hook symbol, U+03D2 NEW" },
                   1755: { 982, "piv",  "greek pi symbol, U+03D6 ISOgrk3" },
                   1756: 
                   1757: { 8194,        "ensp", "en space, U+2002 ISOpub" },
                   1758: { 8195,        "emsp", "em space, U+2003 ISOpub" },
                   1759: { 8201,        "thinsp","thin space, U+2009 ISOpub" },
                   1760: { 8204,        "zwnj", "zero width non-joiner, U+200C NEW RFC 2070" },
                   1761: { 8205,        "zwj",  "zero width joiner, U+200D NEW RFC 2070" },
                   1762: { 8206,        "lrm",  "left-to-right mark, U+200E NEW RFC 2070" },
                   1763: { 8207,        "rlm",  "right-to-left mark, U+200F NEW RFC 2070" },
                   1764: { 8211,        "ndash","en dash, U+2013 ISOpub" },
                   1765: { 8212,        "mdash","em dash, U+2014 ISOpub" },
                   1766: { 8216,        "lsquo","left single quotation mark, U+2018 ISOnum" },
                   1767: { 8217,        "rsquo","right single quotation mark, U+2019 ISOnum" },
                   1768: { 8218,        "sbquo","single low-9 quotation mark, U+201A NEW" },
                   1769: { 8220,        "ldquo","left double quotation mark, U+201C ISOnum" },
                   1770: { 8221,        "rdquo","right double quotation mark, U+201D ISOnum" },
                   1771: { 8222,        "bdquo","double low-9 quotation mark, U+201E NEW" },
                   1772: { 8224,        "dagger","dagger, U+2020 ISOpub" },
                   1773: { 8225,        "Dagger","double dagger, U+2021 ISOpub" },
                   1774: 
                   1775: { 8226,        "bull", "bullet = black small circle, U+2022 ISOpub" },
                   1776: { 8230,        "hellip","horizontal ellipsis = three dot leader, U+2026 ISOpub" },
                   1777: 
                   1778: { 8240,        "permil","per mille sign, U+2030 ISOtech" },
                   1779: 
                   1780: { 8242,        "prime","prime = minutes = feet, U+2032 ISOtech" },
                   1781: { 8243,        "Prime","double prime = seconds = inches, U+2033 ISOtech" },
                   1782: 
                   1783: { 8249,        "lsaquo","single left-pointing angle quotation mark, U+2039 ISO proposed" },
                   1784: { 8250,        "rsaquo","single right-pointing angle quotation mark, U+203A ISO proposed" },
                   1785: 
                   1786: { 8254,        "oline","overline = spacing overscore, U+203E NEW" },
                   1787: { 8260,        "frasl","fraction slash, U+2044 NEW" },
                   1788: 
                   1789: { 8364,        "euro", "euro sign, U+20AC NEW" },
                   1790: 
                   1791: { 8465,        "image","blackletter capital I = imaginary part, U+2111 ISOamso" },
                   1792: { 8472,        "weierp","script capital P = power set = Weierstrass p, U+2118 ISOamso" },
                   1793: { 8476,        "real", "blackletter capital R = real part symbol, U+211C ISOamso" },
                   1794: { 8482,        "trade","trade mark sign, U+2122 ISOnum" },
                   1795: { 8501,        "alefsym","alef symbol = first transfinite cardinal, U+2135 NEW" },
                   1796: { 8592,        "larr", "leftwards arrow, U+2190 ISOnum" },
                   1797: { 8593,        "uarr", "upwards arrow, U+2191 ISOnum" },
                   1798: { 8594,        "rarr", "rightwards arrow, U+2192 ISOnum" },
                   1799: { 8595,        "darr", "downwards arrow, U+2193 ISOnum" },
                   1800: { 8596,        "harr", "left right arrow, U+2194 ISOamsa" },
                   1801: { 8629,        "crarr","downwards arrow with corner leftwards = carriage return, U+21B5 NEW" },
                   1802: { 8656,        "lArr", "leftwards double arrow, U+21D0 ISOtech" },
                   1803: { 8657,        "uArr", "upwards double arrow, U+21D1 ISOamsa" },
                   1804: { 8658,        "rArr", "rightwards double arrow, U+21D2 ISOtech" },
                   1805: { 8659,        "dArr", "downwards double arrow, U+21D3 ISOamsa" },
                   1806: { 8660,        "hArr", "left right double arrow, U+21D4 ISOamsa" },
                   1807: 
                   1808: { 8704,        "forall","for all, U+2200 ISOtech" },
                   1809: { 8706,        "part", "partial differential, U+2202 ISOtech" },
                   1810: { 8707,        "exist","there exists, U+2203 ISOtech" },
                   1811: { 8709,        "empty","empty set = null set = diameter, U+2205 ISOamso" },
                   1812: { 8711,        "nabla","nabla = backward difference, U+2207 ISOtech" },
                   1813: { 8712,        "isin", "element of, U+2208 ISOtech" },
                   1814: { 8713,        "notin","not an element of, U+2209 ISOtech" },
                   1815: { 8715,        "ni",   "contains as member, U+220B ISOtech" },
                   1816: { 8719,        "prod", "n-ary product = product sign, U+220F ISOamsb" },
                   1817: { 8721,        "sum",  "n-ary summation, U+2211 ISOamsb" },
                   1818: { 8722,        "minus","minus sign, U+2212 ISOtech" },
                   1819: { 8727,        "lowast","asterisk operator, U+2217 ISOtech" },
                   1820: { 8730,        "radic","square root = radical sign, U+221A ISOtech" },
                   1821: { 8733,        "prop", "proportional to, U+221D ISOtech" },
                   1822: { 8734,        "infin","infinity, U+221E ISOtech" },
                   1823: { 8736,        "ang",  "angle, U+2220 ISOamso" },
                   1824: { 8743,        "and",  "logical and = wedge, U+2227 ISOtech" },
                   1825: { 8744,        "or",   "logical or = vee, U+2228 ISOtech" },
                   1826: { 8745,        "cap",  "intersection = cap, U+2229 ISOtech" },
                   1827: { 8746,        "cup",  "union = cup, U+222A ISOtech" },
                   1828: { 8747,        "int",  "integral, U+222B ISOtech" },
                   1829: { 8756,        "there4","therefore, U+2234 ISOtech" },
                   1830: { 8764,        "sim",  "tilde operator = varies with = similar to, U+223C ISOtech" },
                   1831: { 8773,        "cong", "approximately equal to, U+2245 ISOtech" },
                   1832: { 8776,        "asymp","almost equal to = asymptotic to, U+2248 ISOamsr" },
                   1833: { 8800,        "ne",   "not equal to, U+2260 ISOtech" },
                   1834: { 8801,        "equiv","identical to, U+2261 ISOtech" },
                   1835: { 8804,        "le",   "less-than or equal to, U+2264 ISOtech" },
                   1836: { 8805,        "ge",   "greater-than or equal to, U+2265 ISOtech" },
                   1837: { 8834,        "sub",  "subset of, U+2282 ISOtech" },
                   1838: { 8835,        "sup",  "superset of, U+2283 ISOtech" },
                   1839: { 8836,        "nsub", "not a subset of, U+2284 ISOamsn" },
                   1840: { 8838,        "sube", "subset of or equal to, U+2286 ISOtech" },
                   1841: { 8839,        "supe", "superset of or equal to, U+2287 ISOtech" },
                   1842: { 8853,        "oplus","circled plus = direct sum, U+2295 ISOamsb" },
                   1843: { 8855,        "otimes","circled times = vector product, U+2297 ISOamsb" },
                   1844: { 8869,        "perp", "up tack = orthogonal to = perpendicular, U+22A5 ISOtech" },
                   1845: { 8901,        "sdot", "dot operator, U+22C5 ISOamsb" },
                   1846: { 8968,        "lceil","left ceiling = apl upstile, U+2308 ISOamsc" },
                   1847: { 8969,        "rceil","right ceiling, U+2309 ISOamsc" },
                   1848: { 8970,        "lfloor","left floor = apl downstile, U+230A ISOamsc" },
                   1849: { 8971,        "rfloor","right floor, U+230B ISOamsc" },
                   1850: { 9001,        "lang", "left-pointing angle bracket = bra, U+2329 ISOtech" },
                   1851: { 9002,        "rang", "right-pointing angle bracket = ket, U+232A ISOtech" },
                   1852: { 9674,        "loz",  "lozenge, U+25CA ISOpub" },
                   1853: 
                   1854: { 9824,        "spades","black spade suit, U+2660 ISOpub" },
                   1855: { 9827,        "clubs","black club suit = shamrock, U+2663 ISOpub" },
                   1856: { 9829,        "hearts","black heart suit = valentine, U+2665 ISOpub" },
                   1857: { 9830,        "diams","black diamond suit, U+2666 ISOpub" },
                   1858: 
                   1859: };
                   1860: 
                   1861: /************************************************************************
                   1862:  *                                                                     *
                   1863:  *             Commodity functions to handle entities                  *
                   1864:  *                                                                     *
                   1865:  ************************************************************************/
                   1866: 
                   1867: /*
                   1868:  * Macro used to grow the current buffer.
                   1869:  */
                   1870: #define growBuffer(buffer) {                                           \
                   1871:     xmlChar *tmp;                                                      \
                   1872:     buffer##_size *= 2;                                                        \
                   1873:     tmp = (xmlChar *) xmlRealloc(buffer, buffer##_size * sizeof(xmlChar)); \
                   1874:     if (tmp == NULL) {                                         \
                   1875:        htmlErrMemory(ctxt, "growing buffer\n");                        \
                   1876:        xmlFree(buffer);                                                \
                   1877:        return(NULL);                                                   \
                   1878:     }                                                                  \
                   1879:     buffer = tmp;                                                      \
                   1880: }
                   1881: 
                   1882: /**
                   1883:  * htmlEntityLookup:
                   1884:  * @name: the entity name
                   1885:  *
                   1886:  * Lookup the given entity in EntitiesTable
                   1887:  *
                   1888:  * TODO: the linear scan is really ugly, an hash table is really needed.
                   1889:  *
                   1890:  * Returns the associated htmlEntityDescPtr if found, NULL otherwise.
                   1891:  */
                   1892: const htmlEntityDesc *
                   1893: htmlEntityLookup(const xmlChar *name) {
                   1894:     unsigned int i;
                   1895: 
                   1896:     for (i = 0;i < (sizeof(html40EntitiesTable)/
                   1897:                     sizeof(html40EntitiesTable[0]));i++) {
                   1898:         if (xmlStrEqual(name, BAD_CAST html40EntitiesTable[i].name)) {
                   1899:             return((htmlEntityDescPtr) &html40EntitiesTable[i]);
                   1900:        }
                   1901:     }
                   1902:     return(NULL);
                   1903: }
                   1904: 
                   1905: /**
                   1906:  * htmlEntityValueLookup:
                   1907:  * @value: the entity's unicode value
                   1908:  *
                   1909:  * Lookup the given entity in EntitiesTable
                   1910:  *
                   1911:  * TODO: the linear scan is really ugly, an hash table is really needed.
                   1912:  *
                   1913:  * Returns the associated htmlEntityDescPtr if found, NULL otherwise.
                   1914:  */
                   1915: const htmlEntityDesc *
                   1916: htmlEntityValueLookup(unsigned int value) {
                   1917:     unsigned int i;
                   1918: 
                   1919:     for (i = 0;i < (sizeof(html40EntitiesTable)/
                   1920:                     sizeof(html40EntitiesTable[0]));i++) {
                   1921:         if (html40EntitiesTable[i].value >= value) {
                   1922:            if (html40EntitiesTable[i].value > value)
                   1923:                break;
                   1924:             return((htmlEntityDescPtr) &html40EntitiesTable[i]);
                   1925:        }
                   1926:     }
                   1927:     return(NULL);
                   1928: }
                   1929: 
                   1930: /**
                   1931:  * UTF8ToHtml:
                   1932:  * @out:  a pointer to an array of bytes to store the result
                   1933:  * @outlen:  the length of @out
                   1934:  * @in:  a pointer to an array of UTF-8 chars
                   1935:  * @inlen:  the length of @in
                   1936:  *
                   1937:  * Take a block of UTF-8 chars in and try to convert it to an ASCII
                   1938:  * plus HTML entities block of chars out.
                   1939:  *
                   1940:  * Returns 0 if success, -2 if the transcoding fails, or -1 otherwise
                   1941:  * The value of @inlen after return is the number of octets consumed
                   1942:  *     as the return value is positive, else unpredictable.
                   1943:  * The value of @outlen after return is the number of octets consumed.
                   1944:  */
                   1945: int
                   1946: UTF8ToHtml(unsigned char* out, int *outlen,
                   1947:               const unsigned char* in, int *inlen) {
                   1948:     const unsigned char* processed = in;
                   1949:     const unsigned char* outend;
                   1950:     const unsigned char* outstart = out;
                   1951:     const unsigned char* instart = in;
                   1952:     const unsigned char* inend;
                   1953:     unsigned int c, d;
                   1954:     int trailing;
                   1955: 
                   1956:     if ((out == NULL) || (outlen == NULL) || (inlen == NULL)) return(-1);
                   1957:     if (in == NULL) {
                   1958:         /*
                   1959:         * initialization nothing to do
                   1960:         */
                   1961:        *outlen = 0;
                   1962:        *inlen = 0;
                   1963:        return(0);
                   1964:     }
                   1965:     inend = in + (*inlen);
                   1966:     outend = out + (*outlen);
                   1967:     while (in < inend) {
                   1968:        d = *in++;
                   1969:        if      (d < 0x80)  { c= d; trailing= 0; }
                   1970:        else if (d < 0xC0) {
                   1971:            /* trailing byte in leading position */
                   1972:            *outlen = out - outstart;
                   1973:            *inlen = processed - instart;
                   1974:            return(-2);
                   1975:         } else if (d < 0xE0)  { c= d & 0x1F; trailing= 1; }
                   1976:         else if (d < 0xF0)  { c= d & 0x0F; trailing= 2; }
                   1977:         else if (d < 0xF8)  { c= d & 0x07; trailing= 3; }
                   1978:        else {
                   1979:            /* no chance for this in Ascii */
                   1980:            *outlen = out - outstart;
                   1981:            *inlen = processed - instart;
                   1982:            return(-2);
                   1983:        }
                   1984: 
                   1985:        if (inend - in < trailing) {
                   1986:            break;
                   1987:        }
                   1988: 
                   1989:        for ( ; trailing; trailing--) {
                   1990:            if ((in >= inend) || (((d= *in++) & 0xC0) != 0x80))
                   1991:                break;
                   1992:            c <<= 6;
                   1993:            c |= d & 0x3F;
                   1994:        }
                   1995: 
                   1996:        /* assertion: c is a single UTF-4 value */
                   1997:        if (c < 0x80) {
                   1998:            if (out + 1 >= outend)
                   1999:                break;
                   2000:            *out++ = c;
                   2001:        } else {
                   2002:            int len;
                   2003:            const htmlEntityDesc * ent;
                   2004:            const char *cp;
                   2005:            char nbuf[16];
                   2006: 
                   2007:            /*
                   2008:             * Try to lookup a predefined HTML entity for it
                   2009:             */
                   2010: 
                   2011:            ent = htmlEntityValueLookup(c);
                   2012:            if (ent == NULL) {
                   2013:              snprintf(nbuf, sizeof(nbuf), "#%u", c);
                   2014:              cp = nbuf;
                   2015:            }
                   2016:            else
                   2017:              cp = ent->name;
                   2018:            len = strlen(cp);
                   2019:            if (out + 2 + len >= outend)
                   2020:                break;
                   2021:            *out++ = '&';
                   2022:            memcpy(out, cp, len);
                   2023:            out += len;
                   2024:            *out++ = ';';
                   2025:        }
                   2026:        processed = in;
                   2027:     }
                   2028:     *outlen = out - outstart;
                   2029:     *inlen = processed - instart;
                   2030:     return(0);
                   2031: }
                   2032: 
                   2033: /**
                   2034:  * htmlEncodeEntities:
                   2035:  * @out:  a pointer to an array of bytes to store the result
                   2036:  * @outlen:  the length of @out
                   2037:  * @in:  a pointer to an array of UTF-8 chars
                   2038:  * @inlen:  the length of @in
                   2039:  * @quoteChar: the quote character to escape (' or ") or zero.
                   2040:  *
                   2041:  * Take a block of UTF-8 chars in and try to convert it to an ASCII
                   2042:  * plus HTML entities block of chars out.
                   2043:  *
                   2044:  * Returns 0 if success, -2 if the transcoding fails, or -1 otherwise
                   2045:  * The value of @inlen after return is the number of octets consumed
                   2046:  *     as the return value is positive, else unpredictable.
                   2047:  * The value of @outlen after return is the number of octets consumed.
                   2048:  */
                   2049: int
                   2050: htmlEncodeEntities(unsigned char* out, int *outlen,
                   2051:                   const unsigned char* in, int *inlen, int quoteChar) {
                   2052:     const unsigned char* processed = in;
                   2053:     const unsigned char* outend;
                   2054:     const unsigned char* outstart = out;
                   2055:     const unsigned char* instart = in;
                   2056:     const unsigned char* inend;
                   2057:     unsigned int c, d;
                   2058:     int trailing;
                   2059: 
                   2060:     if ((out == NULL) || (outlen == NULL) || (inlen == NULL) || (in == NULL))
                   2061:         return(-1);
                   2062:     outend = out + (*outlen);
                   2063:     inend = in + (*inlen);
                   2064:     while (in < inend) {
                   2065:        d = *in++;
                   2066:        if      (d < 0x80)  { c= d; trailing= 0; }
                   2067:        else if (d < 0xC0) {
                   2068:            /* trailing byte in leading position */
                   2069:            *outlen = out - outstart;
                   2070:            *inlen = processed - instart;
                   2071:            return(-2);
                   2072:         } else if (d < 0xE0)  { c= d & 0x1F; trailing= 1; }
                   2073:         else if (d < 0xF0)  { c= d & 0x0F; trailing= 2; }
                   2074:         else if (d < 0xF8)  { c= d & 0x07; trailing= 3; }
                   2075:        else {
                   2076:            /* no chance for this in Ascii */
                   2077:            *outlen = out - outstart;
                   2078:            *inlen = processed - instart;
                   2079:            return(-2);
                   2080:        }
                   2081: 
                   2082:        if (inend - in < trailing)
                   2083:            break;
                   2084: 
                   2085:        while (trailing--) {
                   2086:            if (((d= *in++) & 0xC0) != 0x80) {
                   2087:                *outlen = out - outstart;
                   2088:                *inlen = processed - instart;
                   2089:                return(-2);
                   2090:            }
                   2091:            c <<= 6;
                   2092:            c |= d & 0x3F;
                   2093:        }
                   2094: 
                   2095:        /* assertion: c is a single UTF-4 value */
                   2096:        if ((c < 0x80) && (c != (unsigned int) quoteChar) &&
                   2097:            (c != '&') && (c != '<') && (c != '>')) {
                   2098:            if (out >= outend)
                   2099:                break;
                   2100:            *out++ = c;
                   2101:        } else {
                   2102:            const htmlEntityDesc * ent;
                   2103:            const char *cp;
                   2104:            char nbuf[16];
                   2105:            int len;
                   2106: 
                   2107:            /*
                   2108:             * Try to lookup a predefined HTML entity for it
                   2109:             */
                   2110:            ent = htmlEntityValueLookup(c);
                   2111:            if (ent == NULL) {
                   2112:                snprintf(nbuf, sizeof(nbuf), "#%u", c);
                   2113:                cp = nbuf;
                   2114:            }
                   2115:            else
                   2116:                cp = ent->name;
                   2117:            len = strlen(cp);
                   2118:            if (out + 2 + len > outend)
                   2119:                break;
                   2120:            *out++ = '&';
                   2121:            memcpy(out, cp, len);
                   2122:            out += len;
                   2123:            *out++ = ';';
                   2124:        }
                   2125:        processed = in;
                   2126:     }
                   2127:     *outlen = out - outstart;
                   2128:     *inlen = processed - instart;
                   2129:     return(0);
                   2130: }
                   2131: 
                   2132: /************************************************************************
                   2133:  *                                                                     *
                   2134:  *             Commodity functions to handle streams                   *
                   2135:  *                                                                     *
                   2136:  ************************************************************************/
                   2137: 
                   2138: /**
                   2139:  * htmlNewInputStream:
                   2140:  * @ctxt:  an HTML parser context
                   2141:  *
                   2142:  * Create a new input stream structure
                   2143:  * Returns the new input stream or NULL
                   2144:  */
                   2145: static htmlParserInputPtr
                   2146: htmlNewInputStream(htmlParserCtxtPtr ctxt) {
                   2147:     htmlParserInputPtr input;
                   2148: 
                   2149:     input = (xmlParserInputPtr) xmlMalloc(sizeof(htmlParserInput));
                   2150:     if (input == NULL) {
                   2151:         htmlErrMemory(ctxt, "couldn't allocate a new input stream\n");
                   2152:        return(NULL);
                   2153:     }
                   2154:     memset(input, 0, sizeof(htmlParserInput));
                   2155:     input->filename = NULL;
                   2156:     input->directory = NULL;
                   2157:     input->base = NULL;
                   2158:     input->cur = NULL;
                   2159:     input->buf = NULL;
                   2160:     input->line = 1;
                   2161:     input->col = 1;
                   2162:     input->buf = NULL;
                   2163:     input->free = NULL;
                   2164:     input->version = NULL;
                   2165:     input->consumed = 0;
                   2166:     input->length = 0;
                   2167:     return(input);
                   2168: }
                   2169: 
                   2170: 
                   2171: /************************************************************************
                   2172:  *                                                                     *
                   2173:  *             Commodity functions, cleanup needed ?                   *
                   2174:  *                                                                     *
                   2175:  ************************************************************************/
                   2176: /*
                   2177:  * all tags allowing pc data from the html 4.01 loose dtd
                   2178:  * NOTE: it might be more apropriate to integrate this information
                   2179:  * into the html40ElementTable array but I don't want to risk any
                   2180:  * binary incomptibility
                   2181:  */
                   2182: static const char *allowPCData[] = {
                   2183:     "a", "abbr", "acronym", "address", "applet", "b", "bdo", "big",
                   2184:     "blockquote", "body", "button", "caption", "center", "cite", "code",
                   2185:     "dd", "del", "dfn", "div", "dt", "em", "font", "form", "h1", "h2",
                   2186:     "h3", "h4", "h5", "h6", "i", "iframe", "ins", "kbd", "label", "legend",
                   2187:     "li", "noframes", "noscript", "object", "p", "pre", "q", "s", "samp",
                   2188:     "small", "span", "strike", "strong", "td", "th", "tt", "u", "var"
                   2189: };
                   2190: 
                   2191: /**
                   2192:  * areBlanks:
                   2193:  * @ctxt:  an HTML parser context
                   2194:  * @str:  a xmlChar *
                   2195:  * @len:  the size of @str
                   2196:  *
                   2197:  * Is this a sequence of blank chars that one can ignore ?
                   2198:  *
                   2199:  * Returns 1 if ignorable 0 otherwise.
                   2200:  */
                   2201: 
                   2202: static int areBlanks(htmlParserCtxtPtr ctxt, const xmlChar *str, int len) {
                   2203:     unsigned int i;
                   2204:     int j;
                   2205:     xmlNodePtr lastChild;
                   2206:     xmlDtdPtr dtd;
                   2207: 
                   2208:     for (j = 0;j < len;j++)
                   2209:         if (!(IS_BLANK_CH(str[j]))) return(0);
                   2210: 
                   2211:     if (CUR == 0) return(1);
                   2212:     if (CUR != '<') return(0);
                   2213:     if (ctxt->name == NULL)
                   2214:        return(1);
                   2215:     if (xmlStrEqual(ctxt->name, BAD_CAST"html"))
                   2216:        return(1);
                   2217:     if (xmlStrEqual(ctxt->name, BAD_CAST"head"))
                   2218:        return(1);
                   2219: 
                   2220:     /* Only strip CDATA children of the body tag for strict HTML DTDs */
                   2221:     if (xmlStrEqual(ctxt->name, BAD_CAST "body") && ctxt->myDoc != NULL) {
                   2222:         dtd = xmlGetIntSubset(ctxt->myDoc);
                   2223:         if (dtd != NULL && dtd->ExternalID != NULL) {
                   2224:             if (!xmlStrcasecmp(dtd->ExternalID, BAD_CAST "-//W3C//DTD HTML 4.01//EN") ||
                   2225:                     !xmlStrcasecmp(dtd->ExternalID, BAD_CAST "-//W3C//DTD HTML 4//EN"))
                   2226:                 return(1);
                   2227:         }
                   2228:     }
                   2229: 
                   2230:     if (ctxt->node == NULL) return(0);
                   2231:     lastChild = xmlGetLastChild(ctxt->node);
                   2232:     while ((lastChild) && (lastChild->type == XML_COMMENT_NODE))
                   2233:        lastChild = lastChild->prev;
                   2234:     if (lastChild == NULL) {
                   2235:         if ((ctxt->node->type != XML_ELEMENT_NODE) &&
                   2236:             (ctxt->node->content != NULL)) return(0);
                   2237:        /* keep ws in constructs like ...<b> </b>...
                   2238:           for all tags "b" allowing PCDATA */
                   2239:        for ( i = 0; i < sizeof(allowPCData)/sizeof(allowPCData[0]); i++ ) {
                   2240:            if ( xmlStrEqual(ctxt->name, BAD_CAST allowPCData[i]) ) {
                   2241:                return(0);
                   2242:            }
                   2243:        }
                   2244:     } else if (xmlNodeIsText(lastChild)) {
                   2245:         return(0);
                   2246:     } else {
                   2247:        /* keep ws in constructs like <p><b>xy</b> <i>z</i><p>
                   2248:           for all tags "p" allowing PCDATA */
                   2249:        for ( i = 0; i < sizeof(allowPCData)/sizeof(allowPCData[0]); i++ ) {
                   2250:            if ( xmlStrEqual(lastChild->name, BAD_CAST allowPCData[i]) ) {
                   2251:                return(0);
                   2252:            }
                   2253:        }
                   2254:     }
                   2255:     return(1);
                   2256: }
                   2257: 
                   2258: /**
                   2259:  * htmlNewDocNoDtD:
                   2260:  * @URI:  URI for the dtd, or NULL
                   2261:  * @ExternalID:  the external ID of the DTD, or NULL
                   2262:  *
                   2263:  * Creates a new HTML document without a DTD node if @URI and @ExternalID
                   2264:  * are NULL
                   2265:  *
                   2266:  * Returns a new document, do not initialize the DTD if not provided
                   2267:  */
                   2268: htmlDocPtr
                   2269: htmlNewDocNoDtD(const xmlChar *URI, const xmlChar *ExternalID) {
                   2270:     xmlDocPtr cur;
                   2271: 
                   2272:     /*
                   2273:      * Allocate a new document and fill the fields.
                   2274:      */
                   2275:     cur = (xmlDocPtr) xmlMalloc(sizeof(xmlDoc));
                   2276:     if (cur == NULL) {
                   2277:        htmlErrMemory(NULL, "HTML document creation failed\n");
                   2278:        return(NULL);
                   2279:     }
                   2280:     memset(cur, 0, sizeof(xmlDoc));
                   2281: 
                   2282:     cur->type = XML_HTML_DOCUMENT_NODE;
                   2283:     cur->version = NULL;
                   2284:     cur->intSubset = NULL;
                   2285:     cur->doc = cur;
                   2286:     cur->name = NULL;
                   2287:     cur->children = NULL;
                   2288:     cur->extSubset = NULL;
                   2289:     cur->oldNs = NULL;
                   2290:     cur->encoding = NULL;
                   2291:     cur->standalone = 1;
                   2292:     cur->compression = 0;
                   2293:     cur->ids = NULL;
                   2294:     cur->refs = NULL;
                   2295:     cur->_private = NULL;
                   2296:     cur->charset = XML_CHAR_ENCODING_UTF8;
                   2297:     cur->properties = XML_DOC_HTML | XML_DOC_USERBUILT;
                   2298:     if ((ExternalID != NULL) ||
                   2299:        (URI != NULL))
                   2300:        xmlCreateIntSubset(cur, BAD_CAST "html", ExternalID, URI);
                   2301:     return(cur);
                   2302: }
                   2303: 
                   2304: /**
                   2305:  * htmlNewDoc:
                   2306:  * @URI:  URI for the dtd, or NULL
                   2307:  * @ExternalID:  the external ID of the DTD, or NULL
                   2308:  *
                   2309:  * Creates a new HTML document
                   2310:  *
                   2311:  * Returns a new document
                   2312:  */
                   2313: htmlDocPtr
                   2314: htmlNewDoc(const xmlChar *URI, const xmlChar *ExternalID) {
                   2315:     if ((URI == NULL) && (ExternalID == NULL))
                   2316:        return(htmlNewDocNoDtD(
                   2317:                    BAD_CAST "http://www.w3.org/TR/REC-html40/loose.dtd",
                   2318:                    BAD_CAST "-//W3C//DTD HTML 4.0 Transitional//EN"));
                   2319: 
                   2320:     return(htmlNewDocNoDtD(URI, ExternalID));
                   2321: }
                   2322: 
                   2323: 
                   2324: /************************************************************************
                   2325:  *                                                                     *
                   2326:  *                     The parser itself                               *
                   2327:  *     Relates to http://www.w3.org/TR/html40                          *
                   2328:  *                                                                     *
                   2329:  ************************************************************************/
                   2330: 
                   2331: /************************************************************************
                   2332:  *                                                                     *
                   2333:  *                     The parser itself                               *
                   2334:  *                                                                     *
                   2335:  ************************************************************************/
                   2336: 
                   2337: static const xmlChar * htmlParseNameComplex(xmlParserCtxtPtr ctxt);
                   2338: 
                   2339: /**
                   2340:  * htmlParseHTMLName:
                   2341:  * @ctxt:  an HTML parser context
                   2342:  *
                   2343:  * parse an HTML tag or attribute name, note that we convert it to lowercase
                   2344:  * since HTML names are not case-sensitive.
                   2345:  *
                   2346:  * Returns the Tag Name parsed or NULL
                   2347:  */
                   2348: 
                   2349: static const xmlChar *
                   2350: htmlParseHTMLName(htmlParserCtxtPtr ctxt) {
                   2351:     int i = 0;
                   2352:     xmlChar loc[HTML_PARSER_BUFFER_SIZE];
                   2353: 
                   2354:     if (!IS_ASCII_LETTER(CUR) && (CUR != '_') &&
                   2355:         (CUR != ':') && (CUR != '.')) return(NULL);
                   2356: 
                   2357:     while ((i < HTML_PARSER_BUFFER_SIZE) &&
                   2358:            ((IS_ASCII_LETTER(CUR)) || (IS_ASCII_DIGIT(CUR)) ||
                   2359:           (CUR == ':') || (CUR == '-') || (CUR == '_') ||
                   2360:            (CUR == '.'))) {
                   2361:        if ((CUR >= 'A') && (CUR <= 'Z')) loc[i] = CUR + 0x20;
                   2362:         else loc[i] = CUR;
                   2363:        i++;
                   2364: 
                   2365:        NEXT;
                   2366:     }
                   2367: 
                   2368:     return(xmlDictLookup(ctxt->dict, loc, i));
                   2369: }
                   2370: 
                   2371: 
                   2372: /**
                   2373:  * htmlParseHTMLName_nonInvasive:
                   2374:  * @ctxt:  an HTML parser context
                   2375:  *
                   2376:  * parse an HTML tag or attribute name, note that we convert it to lowercase
                   2377:  * since HTML names are not case-sensitive, this doesn't consume the data
                   2378:  * from the stream, it's a look-ahead
                   2379:  *
                   2380:  * Returns the Tag Name parsed or NULL
                   2381:  */
                   2382: 
                   2383: static const xmlChar *
                   2384: htmlParseHTMLName_nonInvasive(htmlParserCtxtPtr ctxt) {
                   2385:     int i = 0;
                   2386:     xmlChar loc[HTML_PARSER_BUFFER_SIZE];
                   2387: 
                   2388:     if (!IS_ASCII_LETTER(NXT(1)) && (NXT(1) != '_') &&
                   2389:         (NXT(1) != ':')) return(NULL);
                   2390: 
                   2391:     while ((i < HTML_PARSER_BUFFER_SIZE) &&
                   2392:            ((IS_ASCII_LETTER(NXT(1+i))) || (IS_ASCII_DIGIT(NXT(1+i))) ||
                   2393:           (NXT(1+i) == ':') || (NXT(1+i) == '-') || (NXT(1+i) == '_'))) {
                   2394:        if ((NXT(1+i) >= 'A') && (NXT(1+i) <= 'Z')) loc[i] = NXT(1+i) + 0x20;
                   2395:         else loc[i] = NXT(1+i);
                   2396:        i++;
                   2397:     }
                   2398: 
                   2399:     return(xmlDictLookup(ctxt->dict, loc, i));
                   2400: }
                   2401: 
                   2402: 
                   2403: /**
                   2404:  * htmlParseName:
                   2405:  * @ctxt:  an HTML parser context
                   2406:  *
                   2407:  * parse an HTML name, this routine is case sensitive.
                   2408:  *
                   2409:  * Returns the Name parsed or NULL
                   2410:  */
                   2411: 
                   2412: static const xmlChar *
                   2413: htmlParseName(htmlParserCtxtPtr ctxt) {
                   2414:     const xmlChar *in;
                   2415:     const xmlChar *ret;
                   2416:     int count = 0;
                   2417: 
                   2418:     GROW;
                   2419: 
                   2420:     /*
                   2421:      * Accelerator for simple ASCII names
                   2422:      */
                   2423:     in = ctxt->input->cur;
                   2424:     if (((*in >= 0x61) && (*in <= 0x7A)) ||
                   2425:        ((*in >= 0x41) && (*in <= 0x5A)) ||
                   2426:        (*in == '_') || (*in == ':')) {
                   2427:        in++;
                   2428:        while (((*in >= 0x61) && (*in <= 0x7A)) ||
                   2429:               ((*in >= 0x41) && (*in <= 0x5A)) ||
                   2430:               ((*in >= 0x30) && (*in <= 0x39)) ||
                   2431:               (*in == '_') || (*in == '-') ||
                   2432:               (*in == ':') || (*in == '.'))
                   2433:            in++;
                   2434:        if ((*in > 0) && (*in < 0x80)) {
                   2435:            count = in - ctxt->input->cur;
                   2436:            ret = xmlDictLookup(ctxt->dict, ctxt->input->cur, count);
                   2437:            ctxt->input->cur = in;
                   2438:            ctxt->nbChars += count;
                   2439:            ctxt->input->col += count;
                   2440:            return(ret);
                   2441:        }
                   2442:     }
                   2443:     return(htmlParseNameComplex(ctxt));
                   2444: }
                   2445: 
                   2446: static const xmlChar *
                   2447: htmlParseNameComplex(xmlParserCtxtPtr ctxt) {
                   2448:     int len = 0, l;
                   2449:     int c;
                   2450:     int count = 0;
                   2451: 
                   2452:     /*
                   2453:      * Handler for more complex cases
                   2454:      */
                   2455:     GROW;
                   2456:     c = CUR_CHAR(l);
                   2457:     if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
                   2458:        (!IS_LETTER(c) && (c != '_') &&
                   2459:          (c != ':'))) {
                   2460:        return(NULL);
                   2461:     }
                   2462: 
                   2463:     while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
                   2464:           ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
                   2465:             (c == '.') || (c == '-') ||
                   2466:            (c == '_') || (c == ':') ||
                   2467:            (IS_COMBINING(c)) ||
                   2468:            (IS_EXTENDER(c)))) {
                   2469:        if (count++ > 100) {
                   2470:            count = 0;
                   2471:            GROW;
                   2472:        }
                   2473:        len += l;
                   2474:        NEXTL(l);
                   2475:        c = CUR_CHAR(l);
                   2476:     }
                   2477:     return(xmlDictLookup(ctxt->dict, ctxt->input->cur - len, len));
                   2478: }
                   2479: 
                   2480: 
                   2481: /**
                   2482:  * htmlParseHTMLAttribute:
                   2483:  * @ctxt:  an HTML parser context
                   2484:  * @stop:  a char stop value
                   2485:  *
                   2486:  * parse an HTML attribute value till the stop (quote), if
                   2487:  * stop is 0 then it stops at the first space
                   2488:  *
                   2489:  * Returns the attribute parsed or NULL
                   2490:  */
                   2491: 
                   2492: static xmlChar *
                   2493: htmlParseHTMLAttribute(htmlParserCtxtPtr ctxt, const xmlChar stop) {
                   2494:     xmlChar *buffer = NULL;
                   2495:     int buffer_size = 0;
                   2496:     xmlChar *out = NULL;
                   2497:     const xmlChar *name = NULL;
                   2498:     const xmlChar *cur = NULL;
                   2499:     const htmlEntityDesc * ent;
                   2500: 
                   2501:     /*
                   2502:      * allocate a translation buffer.
                   2503:      */
                   2504:     buffer_size = HTML_PARSER_BUFFER_SIZE;
                   2505:     buffer = (xmlChar *) xmlMallocAtomic(buffer_size * sizeof(xmlChar));
                   2506:     if (buffer == NULL) {
                   2507:        htmlErrMemory(ctxt, "buffer allocation failed\n");
                   2508:        return(NULL);
                   2509:     }
                   2510:     out = buffer;
                   2511: 
                   2512:     /*
                   2513:      * Ok loop until we reach one of the ending chars
                   2514:      */
                   2515:     while ((CUR != 0) && (CUR != stop)) {
                   2516:        if ((stop == 0) && (CUR == '>')) break;
                   2517:        if ((stop == 0) && (IS_BLANK_CH(CUR))) break;
                   2518:         if (CUR == '&') {
                   2519:            if (NXT(1) == '#') {
                   2520:                unsigned int c;
                   2521:                int bits;
                   2522: 
                   2523:                c = htmlParseCharRef(ctxt);
                   2524:                if      (c <    0x80)
                   2525:                        { *out++  = c;                bits= -6; }
                   2526:                else if (c <   0x800)
                   2527:                        { *out++  =((c >>  6) & 0x1F) | 0xC0;  bits=  0; }
                   2528:                else if (c < 0x10000)
                   2529:                        { *out++  =((c >> 12) & 0x0F) | 0xE0;  bits=  6; }
                   2530:                else
                   2531:                        { *out++  =((c >> 18) & 0x07) | 0xF0;  bits= 12; }
                   2532: 
                   2533:                for ( ; bits >= 0; bits-= 6) {
                   2534:                    *out++  = ((c >> bits) & 0x3F) | 0x80;
                   2535:                }
                   2536: 
                   2537:                if (out - buffer > buffer_size - 100) {
                   2538:                        int indx = out - buffer;
                   2539: 
                   2540:                        growBuffer(buffer);
                   2541:                        out = &buffer[indx];
                   2542:                }
                   2543:            } else {
                   2544:                ent = htmlParseEntityRef(ctxt, &name);
                   2545:                if (name == NULL) {
                   2546:                    *out++ = '&';
                   2547:                    if (out - buffer > buffer_size - 100) {
                   2548:                        int indx = out - buffer;
                   2549: 
                   2550:                        growBuffer(buffer);
                   2551:                        out = &buffer[indx];
                   2552:                    }
                   2553:                } else if (ent == NULL) {
                   2554:                    *out++ = '&';
                   2555:                    cur = name;
                   2556:                    while (*cur != 0) {
                   2557:                        if (out - buffer > buffer_size - 100) {
                   2558:                            int indx = out - buffer;
                   2559: 
                   2560:                            growBuffer(buffer);
                   2561:                            out = &buffer[indx];
                   2562:                        }
                   2563:                        *out++ = *cur++;
                   2564:                    }
                   2565:                } else {
                   2566:                    unsigned int c;
                   2567:                    int bits;
                   2568: 
                   2569:                    if (out - buffer > buffer_size - 100) {
                   2570:                        int indx = out - buffer;
                   2571: 
                   2572:                        growBuffer(buffer);
                   2573:                        out = &buffer[indx];
                   2574:                    }
                   2575:                    c = ent->value;
                   2576:                    if      (c <    0x80)
                   2577:                        { *out++  = c;                bits= -6; }
                   2578:                    else if (c <   0x800)
                   2579:                        { *out++  =((c >>  6) & 0x1F) | 0xC0;  bits=  0; }
                   2580:                    else if (c < 0x10000)
                   2581:                        { *out++  =((c >> 12) & 0x0F) | 0xE0;  bits=  6; }
                   2582:                    else
                   2583:                        { *out++  =((c >> 18) & 0x07) | 0xF0;  bits= 12; }
                   2584: 
                   2585:                    for ( ; bits >= 0; bits-= 6) {
                   2586:                        *out++  = ((c >> bits) & 0x3F) | 0x80;
                   2587:                    }
                   2588:                }
                   2589:            }
                   2590:        } else {
                   2591:            unsigned int c;
                   2592:            int bits, l;
                   2593: 
                   2594:            if (out - buffer > buffer_size - 100) {
                   2595:                int indx = out - buffer;
                   2596: 
                   2597:                growBuffer(buffer);
                   2598:                out = &buffer[indx];
                   2599:            }
                   2600:            c = CUR_CHAR(l);
                   2601:            if      (c <    0x80)
                   2602:                    { *out++  = c;                bits= -6; }
                   2603:            else if (c <   0x800)
                   2604:                    { *out++  =((c >>  6) & 0x1F) | 0xC0;  bits=  0; }
                   2605:            else if (c < 0x10000)
                   2606:                    { *out++  =((c >> 12) & 0x0F) | 0xE0;  bits=  6; }
                   2607:            else
                   2608:                    { *out++  =((c >> 18) & 0x07) | 0xF0;  bits= 12; }
                   2609: 
                   2610:            for ( ; bits >= 0; bits-= 6) {
                   2611:                *out++  = ((c >> bits) & 0x3F) | 0x80;
                   2612:            }
                   2613:            NEXT;
                   2614:        }
                   2615:     }
                   2616:     *out = 0;
                   2617:     return(buffer);
                   2618: }
                   2619: 
                   2620: /**
                   2621:  * htmlParseEntityRef:
                   2622:  * @ctxt:  an HTML parser context
                   2623:  * @str:  location to store the entity name
                   2624:  *
                   2625:  * parse an HTML ENTITY references
                   2626:  *
                   2627:  * [68] EntityRef ::= '&' Name ';'
                   2628:  *
                   2629:  * Returns the associated htmlEntityDescPtr if found, or NULL otherwise,
                   2630:  *         if non-NULL *str will have to be freed by the caller.
                   2631:  */
                   2632: const htmlEntityDesc *
                   2633: htmlParseEntityRef(htmlParserCtxtPtr ctxt, const xmlChar **str) {
                   2634:     const xmlChar *name;
                   2635:     const htmlEntityDesc * ent = NULL;
                   2636: 
                   2637:     if (str != NULL) *str = NULL;
                   2638:     if ((ctxt == NULL) || (ctxt->input == NULL)) return(NULL);
                   2639: 
                   2640:     if (CUR == '&') {
                   2641:         NEXT;
                   2642:         name = htmlParseName(ctxt);
                   2643:        if (name == NULL) {
                   2644:            htmlParseErr(ctxt, XML_ERR_NAME_REQUIRED,
                   2645:                         "htmlParseEntityRef: no name\n", NULL, NULL);
                   2646:        } else {
                   2647:            GROW;
                   2648:            if (CUR == ';') {
                   2649:                if (str != NULL)
                   2650:                    *str = name;
                   2651: 
                   2652:                /*
                   2653:                 * Lookup the entity in the table.
                   2654:                 */
                   2655:                ent = htmlEntityLookup(name);
                   2656:                if (ent != NULL) /* OK that's ugly !!! */
                   2657:                    NEXT;
                   2658:            } else {
                   2659:                htmlParseErr(ctxt, XML_ERR_ENTITYREF_SEMICOL_MISSING,
                   2660:                             "htmlParseEntityRef: expecting ';'\n",
                   2661:                             NULL, NULL);
                   2662:                if (str != NULL)
                   2663:                    *str = name;
                   2664:            }
                   2665:        }
                   2666:     }
                   2667:     return(ent);
                   2668: }
                   2669: 
                   2670: /**
                   2671:  * htmlParseAttValue:
                   2672:  * @ctxt:  an HTML parser context
                   2673:  *
                   2674:  * parse a value for an attribute
                   2675:  * Note: the parser won't do substitution of entities here, this
                   2676:  * will be handled later in xmlStringGetNodeList, unless it was
                   2677:  * asked for ctxt->replaceEntities != 0
                   2678:  *
                   2679:  * Returns the AttValue parsed or NULL.
                   2680:  */
                   2681: 
                   2682: static xmlChar *
                   2683: htmlParseAttValue(htmlParserCtxtPtr ctxt) {
                   2684:     xmlChar *ret = NULL;
                   2685: 
                   2686:     if (CUR == '"') {
                   2687:         NEXT;
                   2688:        ret = htmlParseHTMLAttribute(ctxt, '"');
                   2689:         if (CUR != '"') {
                   2690:            htmlParseErr(ctxt, XML_ERR_ATTRIBUTE_NOT_FINISHED,
                   2691:                         "AttValue: \" expected\n", NULL, NULL);
                   2692:        } else
                   2693:            NEXT;
                   2694:     } else if (CUR == '\'') {
                   2695:         NEXT;
                   2696:        ret = htmlParseHTMLAttribute(ctxt, '\'');
                   2697:         if (CUR != '\'') {
                   2698:            htmlParseErr(ctxt, XML_ERR_ATTRIBUTE_NOT_FINISHED,
                   2699:                         "AttValue: ' expected\n", NULL, NULL);
                   2700:        } else
                   2701:            NEXT;
                   2702:     } else {
                   2703:         /*
                   2704:         * That's an HTMLism, the attribute value may not be quoted
                   2705:         */
                   2706:        ret = htmlParseHTMLAttribute(ctxt, 0);
                   2707:        if (ret == NULL) {
                   2708:            htmlParseErr(ctxt, XML_ERR_ATTRIBUTE_WITHOUT_VALUE,
                   2709:                         "AttValue: no value found\n", NULL, NULL);
                   2710:        }
                   2711:     }
                   2712:     return(ret);
                   2713: }
                   2714: 
                   2715: /**
                   2716:  * htmlParseSystemLiteral:
                   2717:  * @ctxt:  an HTML parser context
                   2718:  *
                   2719:  * parse an HTML Literal
                   2720:  *
                   2721:  * [11] SystemLiteral ::= ('"' [^"]* '"') | ("'" [^']* "'")
                   2722:  *
                   2723:  * Returns the SystemLiteral parsed or NULL
                   2724:  */
                   2725: 
                   2726: static xmlChar *
                   2727: htmlParseSystemLiteral(htmlParserCtxtPtr ctxt) {
                   2728:     const xmlChar *q;
                   2729:     xmlChar *ret = NULL;
                   2730: 
                   2731:     if (CUR == '"') {
                   2732:         NEXT;
                   2733:        q = CUR_PTR;
                   2734:        while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
                   2735:            NEXT;
                   2736:        if (!IS_CHAR_CH(CUR)) {
                   2737:            htmlParseErr(ctxt, XML_ERR_LITERAL_NOT_FINISHED,
                   2738:                         "Unfinished SystemLiteral\n", NULL, NULL);
                   2739:        } else {
                   2740:            ret = xmlStrndup(q, CUR_PTR - q);
                   2741:            NEXT;
                   2742:         }
                   2743:     } else if (CUR == '\'') {
                   2744:         NEXT;
                   2745:        q = CUR_PTR;
                   2746:        while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
                   2747:            NEXT;
                   2748:        if (!IS_CHAR_CH(CUR)) {
                   2749:            htmlParseErr(ctxt, XML_ERR_LITERAL_NOT_FINISHED,
                   2750:                         "Unfinished SystemLiteral\n", NULL, NULL);
                   2751:        } else {
                   2752:            ret = xmlStrndup(q, CUR_PTR - q);
                   2753:            NEXT;
                   2754:         }
                   2755:     } else {
                   2756:        htmlParseErr(ctxt, XML_ERR_LITERAL_NOT_STARTED,
                   2757:                     " or ' expected\n", NULL, NULL);
                   2758:     }
                   2759: 
                   2760:     return(ret);
                   2761: }
                   2762: 
                   2763: /**
                   2764:  * htmlParsePubidLiteral:
                   2765:  * @ctxt:  an HTML parser context
                   2766:  *
                   2767:  * parse an HTML public literal
                   2768:  *
                   2769:  * [12] PubidLiteral ::= '"' PubidChar* '"' | "'" (PubidChar - "'")* "'"
                   2770:  *
                   2771:  * Returns the PubidLiteral parsed or NULL.
                   2772:  */
                   2773: 
                   2774: static xmlChar *
                   2775: htmlParsePubidLiteral(htmlParserCtxtPtr ctxt) {
                   2776:     const xmlChar *q;
                   2777:     xmlChar *ret = NULL;
                   2778:     /*
                   2779:      * Name ::= (Letter | '_') (NameChar)*
                   2780:      */
                   2781:     if (CUR == '"') {
                   2782:         NEXT;
                   2783:        q = CUR_PTR;
                   2784:        while (IS_PUBIDCHAR_CH(CUR)) NEXT;
                   2785:        if (CUR != '"') {
                   2786:            htmlParseErr(ctxt, XML_ERR_LITERAL_NOT_FINISHED,
                   2787:                         "Unfinished PubidLiteral\n", NULL, NULL);
                   2788:        } else {
                   2789:            ret = xmlStrndup(q, CUR_PTR - q);
                   2790:            NEXT;
                   2791:        }
                   2792:     } else if (CUR == '\'') {
                   2793:         NEXT;
                   2794:        q = CUR_PTR;
                   2795:        while ((IS_PUBIDCHAR_CH(CUR)) && (CUR != '\''))
                   2796:            NEXT;
                   2797:        if (CUR != '\'') {
                   2798:            htmlParseErr(ctxt, XML_ERR_LITERAL_NOT_FINISHED,
                   2799:                         "Unfinished PubidLiteral\n", NULL, NULL);
                   2800:        } else {
                   2801:            ret = xmlStrndup(q, CUR_PTR - q);
                   2802:            NEXT;
                   2803:        }
                   2804:     } else {
                   2805:        htmlParseErr(ctxt, XML_ERR_LITERAL_NOT_STARTED,
                   2806:                     "PubidLiteral \" or ' expected\n", NULL, NULL);
                   2807:     }
                   2808: 
                   2809:     return(ret);
                   2810: }
                   2811: 
                   2812: /**
                   2813:  * htmlParseScript:
                   2814:  * @ctxt:  an HTML parser context
                   2815:  *
                   2816:  * parse the content of an HTML SCRIPT or STYLE element
                   2817:  * http://www.w3.org/TR/html4/sgml/dtd.html#Script
                   2818:  * http://www.w3.org/TR/html4/sgml/dtd.html#StyleSheet
                   2819:  * http://www.w3.org/TR/html4/types.html#type-script
                   2820:  * http://www.w3.org/TR/html4/types.html#h-6.15
                   2821:  * http://www.w3.org/TR/html4/appendix/notes.html#h-B.3.2.1
                   2822:  *
                   2823:  * Script data ( %Script; in the DTD) can be the content of the SCRIPT
                   2824:  * element and the value of intrinsic event attributes. User agents must
                   2825:  * not evaluate script data as HTML markup but instead must pass it on as
                   2826:  * data to a script engine.
                   2827:  * NOTES:
                   2828:  * - The content is passed like CDATA
                   2829:  * - the attributes for style and scripting "onXXX" are also described
                   2830:  *   as CDATA but SGML allows entities references in attributes so their
                   2831:  *   processing is identical as other attributes
                   2832:  */
                   2833: static void
                   2834: htmlParseScript(htmlParserCtxtPtr ctxt) {
                   2835:     xmlChar buf[HTML_PARSER_BIG_BUFFER_SIZE + 5];
                   2836:     int nbchar = 0;
                   2837:     int cur,l;
                   2838: 
                   2839:     SHRINK;
                   2840:     cur = CUR_CHAR(l);
                   2841:     while (IS_CHAR_CH(cur)) {
                   2842:        if ((cur == '<') && (NXT(1) == '/')) {
                   2843:             /*
                   2844:              * One should break here, the specification is clear:
                   2845:              * Authors should therefore escape "</" within the content.
                   2846:              * Escape mechanisms are specific to each scripting or
                   2847:              * style sheet language.
                   2848:              *
                   2849:              * In recovery mode, only break if end tag match the
                   2850:              * current tag, effectively ignoring all tags inside the
                   2851:              * script/style block and treating the entire block as
                   2852:              * CDATA.
                   2853:              */
                   2854:             if (ctxt->recovery) {
                   2855:                 if (xmlStrncasecmp(ctxt->name, ctxt->input->cur+2,
                   2856:                                   xmlStrlen(ctxt->name)) == 0)
                   2857:                 {
                   2858:                     break; /* while */
                   2859:                 } else {
                   2860:                    htmlParseErr(ctxt, XML_ERR_TAG_NAME_MISMATCH,
                   2861:                                 "Element %s embeds close tag\n",
                   2862:                                 ctxt->name, NULL);
                   2863:                }
                   2864:             } else {
                   2865:                 if (((NXT(2) >= 'A') && (NXT(2) <= 'Z')) ||
                   2866:                     ((NXT(2) >= 'a') && (NXT(2) <= 'z')))
                   2867:                 {
                   2868:                     break; /* while */
                   2869:                 }
                   2870:             }
                   2871:        }
                   2872:        COPY_BUF(l,buf,nbchar,cur);
                   2873:        if (nbchar >= HTML_PARSER_BIG_BUFFER_SIZE) {
                   2874:            if (ctxt->sax->cdataBlock!= NULL) {
                   2875:                /*
                   2876:                 * Insert as CDATA, which is the same as HTML_PRESERVE_NODE
                   2877:                 */
                   2878:                ctxt->sax->cdataBlock(ctxt->userData, buf, nbchar);
                   2879:            } else if (ctxt->sax->characters != NULL) {
                   2880:                ctxt->sax->characters(ctxt->userData, buf, nbchar);
                   2881:            }
                   2882:            nbchar = 0;
                   2883:        }
                   2884:        GROW;
                   2885:        NEXTL(l);
                   2886:        cur = CUR_CHAR(l);
                   2887:     }
                   2888: 
                   2889:     if ((!(IS_CHAR_CH(cur))) && (!((cur == 0) && (ctxt->progressive)))) {
                   2890:         htmlParseErrInt(ctxt, XML_ERR_INVALID_CHAR,
                   2891:                     "Invalid char in CDATA 0x%X\n", cur);
                   2892:         if (ctxt->input->cur < ctxt->input->end) {
                   2893:             NEXT;
                   2894:         }
                   2895:     }
                   2896: 
                   2897:     if ((nbchar != 0) && (ctxt->sax != NULL) && (!ctxt->disableSAX)) {
                   2898:        if (ctxt->sax->cdataBlock!= NULL) {
                   2899:            /*
                   2900:             * Insert as CDATA, which is the same as HTML_PRESERVE_NODE
                   2901:             */
                   2902:            ctxt->sax->cdataBlock(ctxt->userData, buf, nbchar);
                   2903:        } else if (ctxt->sax->characters != NULL) {
                   2904:            ctxt->sax->characters(ctxt->userData, buf, nbchar);
                   2905:        }
                   2906:     }
                   2907: }
                   2908: 
                   2909: 
                   2910: /**
                   2911:  * htmlParseCharData:
                   2912:  * @ctxt:  an HTML parser context
                   2913:  *
                   2914:  * parse a CharData section.
                   2915:  * if we are within a CDATA section ']]>' marks an end of section.
                   2916:  *
                   2917:  * [14] CharData ::= [^<&]* - ([^<&]* ']]>' [^<&]*)
                   2918:  */
                   2919: 
                   2920: static void
                   2921: htmlParseCharData(htmlParserCtxtPtr ctxt) {
                   2922:     xmlChar buf[HTML_PARSER_BIG_BUFFER_SIZE + 5];
                   2923:     int nbchar = 0;
                   2924:     int cur, l;
                   2925:     int chunk = 0;
                   2926: 
                   2927:     SHRINK;
                   2928:     cur = CUR_CHAR(l);
                   2929:     while (((cur != '<') || (ctxt->token == '<')) &&
                   2930:            ((cur != '&') || (ctxt->token == '&')) &&
                   2931:           (cur != 0)) {
                   2932:        if (!(IS_CHAR(cur))) {
                   2933:            htmlParseErrInt(ctxt, XML_ERR_INVALID_CHAR,
                   2934:                        "Invalid char in CDATA 0x%X\n", cur);
                   2935:        } else {
                   2936:            COPY_BUF(l,buf,nbchar,cur);
                   2937:        }
                   2938:        if (nbchar >= HTML_PARSER_BIG_BUFFER_SIZE) {
                   2939:            /*
                   2940:             * Ok the segment is to be consumed as chars.
                   2941:             */
                   2942:            if ((ctxt->sax != NULL) && (!ctxt->disableSAX)) {
                   2943:                if (areBlanks(ctxt, buf, nbchar)) {
                   2944:                    if (ctxt->sax->ignorableWhitespace != NULL)
                   2945:                        ctxt->sax->ignorableWhitespace(ctxt->userData,
                   2946:                                                       buf, nbchar);
                   2947:                } else {
                   2948:                    htmlCheckParagraph(ctxt);
                   2949:                    if (ctxt->sax->characters != NULL)
                   2950:                        ctxt->sax->characters(ctxt->userData, buf, nbchar);
                   2951:                }
                   2952:            }
                   2953:            nbchar = 0;
                   2954:        }
                   2955:        NEXTL(l);
                   2956:         chunk++;
                   2957:         if (chunk > HTML_PARSER_BUFFER_SIZE) {
                   2958:             chunk = 0;
                   2959:             SHRINK;
                   2960:             GROW;
                   2961:         }
                   2962:        cur = CUR_CHAR(l);
                   2963:        if (cur == 0) {
                   2964:            SHRINK;
                   2965:            GROW;
                   2966:            cur = CUR_CHAR(l);
                   2967:        }
                   2968:     }
                   2969:     if (nbchar != 0) {
                   2970:         buf[nbchar] = 0;
                   2971: 
                   2972:        /*
                   2973:         * Ok the segment is to be consumed as chars.
                   2974:         */
                   2975:        if ((ctxt->sax != NULL) && (!ctxt->disableSAX)) {
                   2976:            if (areBlanks(ctxt, buf, nbchar)) {
                   2977:                if (ctxt->sax->ignorableWhitespace != NULL)
                   2978:                    ctxt->sax->ignorableWhitespace(ctxt->userData, buf, nbchar);
                   2979:            } else {
                   2980:                htmlCheckParagraph(ctxt);
                   2981:                if (ctxt->sax->characters != NULL)
                   2982:                    ctxt->sax->characters(ctxt->userData, buf, nbchar);
                   2983:            }
                   2984:        }
                   2985:     } else {
                   2986:        /*
                   2987:         * Loop detection
                   2988:         */
                   2989:        if (cur == 0)
                   2990:            ctxt->instate = XML_PARSER_EOF;
                   2991:     }
                   2992: }
                   2993: 
                   2994: /**
                   2995:  * htmlParseExternalID:
                   2996:  * @ctxt:  an HTML parser context
                   2997:  * @publicID:  a xmlChar** receiving PubidLiteral
                   2998:  *
                   2999:  * Parse an External ID or a Public ID
                   3000:  *
                   3001:  * [75] ExternalID ::= 'SYSTEM' S SystemLiteral
                   3002:  *                   | 'PUBLIC' S PubidLiteral S SystemLiteral
                   3003:  *
                   3004:  * [83] PublicID ::= 'PUBLIC' S PubidLiteral
                   3005:  *
                   3006:  * Returns the function returns SystemLiteral and in the second
                   3007:  *                case publicID receives PubidLiteral, is strict is off
                   3008:  *                it is possible to return NULL and have publicID set.
                   3009:  */
                   3010: 
                   3011: static xmlChar *
                   3012: htmlParseExternalID(htmlParserCtxtPtr ctxt, xmlChar **publicID) {
                   3013:     xmlChar *URI = NULL;
                   3014: 
                   3015:     if ((UPPER == 'S') && (UPP(1) == 'Y') &&
                   3016:          (UPP(2) == 'S') && (UPP(3) == 'T') &&
                   3017:         (UPP(4) == 'E') && (UPP(5) == 'M')) {
                   3018:         SKIP(6);
                   3019:        if (!IS_BLANK_CH(CUR)) {
                   3020:            htmlParseErr(ctxt, XML_ERR_SPACE_REQUIRED,
                   3021:                         "Space required after 'SYSTEM'\n", NULL, NULL);
                   3022:        }
                   3023:         SKIP_BLANKS;
                   3024:        URI = htmlParseSystemLiteral(ctxt);
                   3025:        if (URI == NULL) {
                   3026:            htmlParseErr(ctxt, XML_ERR_URI_REQUIRED,
                   3027:                         "htmlParseExternalID: SYSTEM, no URI\n", NULL, NULL);
                   3028:         }
                   3029:     } else if ((UPPER == 'P') && (UPP(1) == 'U') &&
                   3030:               (UPP(2) == 'B') && (UPP(3) == 'L') &&
                   3031:               (UPP(4) == 'I') && (UPP(5) == 'C')) {
                   3032:         SKIP(6);
                   3033:        if (!IS_BLANK_CH(CUR)) {
                   3034:            htmlParseErr(ctxt, XML_ERR_SPACE_REQUIRED,
                   3035:                         "Space required after 'PUBLIC'\n", NULL, NULL);
                   3036:        }
                   3037:         SKIP_BLANKS;
                   3038:        *publicID = htmlParsePubidLiteral(ctxt);
                   3039:        if (*publicID == NULL) {
                   3040:            htmlParseErr(ctxt, XML_ERR_PUBID_REQUIRED,
                   3041:                         "htmlParseExternalID: PUBLIC, no Public Identifier\n",
                   3042:                         NULL, NULL);
                   3043:        }
                   3044:         SKIP_BLANKS;
                   3045:         if ((CUR == '"') || (CUR == '\'')) {
                   3046:            URI = htmlParseSystemLiteral(ctxt);
                   3047:        }
                   3048:     }
                   3049:     return(URI);
                   3050: }
                   3051: 
                   3052: /**
                   3053:  * xmlParsePI:
                   3054:  * @ctxt:  an XML parser context
                   3055:  *
                   3056:  * parse an XML Processing Instruction.
                   3057:  *
                   3058:  * [16] PI ::= '<?' PITarget (S (Char* - (Char* '?>' Char*)))? '?>'
                   3059:  */
                   3060: static void
                   3061: htmlParsePI(htmlParserCtxtPtr ctxt) {
                   3062:     xmlChar *buf = NULL;
                   3063:     int len = 0;
                   3064:     int size = HTML_PARSER_BUFFER_SIZE;
                   3065:     int cur, l;
                   3066:     const xmlChar *target;
                   3067:     xmlParserInputState state;
                   3068:     int count = 0;
                   3069: 
                   3070:     if ((RAW == '<') && (NXT(1) == '?')) {
                   3071:        state = ctxt->instate;
                   3072:         ctxt->instate = XML_PARSER_PI;
                   3073:        /*
                   3074:         * this is a Processing Instruction.
                   3075:         */
                   3076:        SKIP(2);
                   3077:        SHRINK;
                   3078: 
                   3079:        /*
                   3080:         * Parse the target name and check for special support like
                   3081:         * namespace.
                   3082:         */
                   3083:         target = htmlParseName(ctxt);
                   3084:        if (target != NULL) {
                   3085:            if (RAW == '>') {
                   3086:                SKIP(1);
                   3087: 
                   3088:                /*
                   3089:                 * SAX: PI detected.
                   3090:                 */
                   3091:                if ((ctxt->sax) && (!ctxt->disableSAX) &&
                   3092:                    (ctxt->sax->processingInstruction != NULL))
                   3093:                    ctxt->sax->processingInstruction(ctxt->userData,
                   3094:                                                     target, NULL);
                   3095:                ctxt->instate = state;
                   3096:                return;
                   3097:            }
                   3098:            buf = (xmlChar *) xmlMallocAtomic(size * sizeof(xmlChar));
                   3099:            if (buf == NULL) {
                   3100:                htmlErrMemory(ctxt, NULL);
                   3101:                ctxt->instate = state;
                   3102:                return;
                   3103:            }
                   3104:            cur = CUR;
                   3105:            if (!IS_BLANK(cur)) {
                   3106:                htmlParseErr(ctxt, XML_ERR_SPACE_REQUIRED,
                   3107:                          "ParsePI: PI %s space expected\n", target, NULL);
                   3108:            }
                   3109:             SKIP_BLANKS;
                   3110:            cur = CUR_CHAR(l);
                   3111:            while (IS_CHAR(cur) && (cur != '>')) {
                   3112:                if (len + 5 >= size) {
                   3113:                    xmlChar *tmp;
                   3114: 
                   3115:                    size *= 2;
                   3116:                    tmp = (xmlChar *) xmlRealloc(buf, size * sizeof(xmlChar));
                   3117:                    if (tmp == NULL) {
                   3118:                        htmlErrMemory(ctxt, NULL);
                   3119:                        xmlFree(buf);
                   3120:                        ctxt->instate = state;
                   3121:                        return;
                   3122:                    }
                   3123:                    buf = tmp;
                   3124:                }
                   3125:                count++;
                   3126:                if (count > 50) {
                   3127:                    GROW;
                   3128:                    count = 0;
                   3129:                }
                   3130:                COPY_BUF(l,buf,len,cur);
                   3131:                NEXTL(l);
                   3132:                cur = CUR_CHAR(l);
                   3133:                if (cur == 0) {
                   3134:                    SHRINK;
                   3135:                    GROW;
                   3136:                    cur = CUR_CHAR(l);
                   3137:                }
                   3138:            }
                   3139:            buf[len] = 0;
                   3140:            if (cur != '>') {
                   3141:                htmlParseErr(ctxt, XML_ERR_PI_NOT_FINISHED,
                   3142:                      "ParsePI: PI %s never end ...\n", target, NULL);
                   3143:            } else {
                   3144:                SKIP(1);
                   3145: 
                   3146:                /*
                   3147:                 * SAX: PI detected.
                   3148:                 */
                   3149:                if ((ctxt->sax) && (!ctxt->disableSAX) &&
                   3150:                    (ctxt->sax->processingInstruction != NULL))
                   3151:                    ctxt->sax->processingInstruction(ctxt->userData,
                   3152:                                                     target, buf);
                   3153:            }
                   3154:            xmlFree(buf);
                   3155:        } else {
                   3156:            htmlParseErr(ctxt, XML_ERR_PI_NOT_STARTED,
                   3157:                          "PI is not started correctly", NULL, NULL);
                   3158:        }
                   3159:        ctxt->instate = state;
                   3160:     }
                   3161: }
                   3162: 
                   3163: /**
                   3164:  * htmlParseComment:
                   3165:  * @ctxt:  an HTML parser context
                   3166:  *
                   3167:  * Parse an XML (SGML) comment <!-- .... -->
                   3168:  *
                   3169:  * [15] Comment ::= '<!--' ((Char - '-') | ('-' (Char - '-')))* '-->'
                   3170:  */
                   3171: static void
                   3172: htmlParseComment(htmlParserCtxtPtr ctxt) {
                   3173:     xmlChar *buf = NULL;
                   3174:     int len;
                   3175:     int size = HTML_PARSER_BUFFER_SIZE;
                   3176:     int q, ql;
                   3177:     int r, rl;
                   3178:     int cur, l;
                   3179:     xmlParserInputState state;
                   3180: 
                   3181:     /*
                   3182:      * Check that there is a comment right here.
                   3183:      */
                   3184:     if ((RAW != '<') || (NXT(1) != '!') ||
                   3185:         (NXT(2) != '-') || (NXT(3) != '-')) return;
                   3186: 
                   3187:     state = ctxt->instate;
                   3188:     ctxt->instate = XML_PARSER_COMMENT;
                   3189:     SHRINK;
                   3190:     SKIP(4);
                   3191:     buf = (xmlChar *) xmlMallocAtomic(size * sizeof(xmlChar));
                   3192:     if (buf == NULL) {
                   3193:         htmlErrMemory(ctxt, "buffer allocation failed\n");
                   3194:        ctxt->instate = state;
                   3195:        return;
                   3196:     }
                   3197:     q = CUR_CHAR(ql);
                   3198:     NEXTL(ql);
                   3199:     r = CUR_CHAR(rl);
                   3200:     NEXTL(rl);
                   3201:     cur = CUR_CHAR(l);
                   3202:     len = 0;
                   3203:     while (IS_CHAR(cur) &&
                   3204:            ((cur != '>') ||
                   3205:            (r != '-') || (q != '-'))) {
                   3206:        if (len + 5 >= size) {
                   3207:            xmlChar *tmp;
                   3208: 
                   3209:            size *= 2;
                   3210:            tmp = (xmlChar *) xmlRealloc(buf, size * sizeof(xmlChar));
                   3211:            if (tmp == NULL) {
                   3212:                xmlFree(buf);
                   3213:                htmlErrMemory(ctxt, "growing buffer failed\n");
                   3214:                ctxt->instate = state;
                   3215:                return;
                   3216:            }
                   3217:            buf = tmp;
                   3218:        }
                   3219:        COPY_BUF(ql,buf,len,q);
                   3220:        q = r;
                   3221:        ql = rl;
                   3222:        r = cur;
                   3223:        rl = l;
                   3224:        NEXTL(l);
                   3225:        cur = CUR_CHAR(l);
                   3226:        if (cur == 0) {
                   3227:            SHRINK;
                   3228:            GROW;
                   3229:            cur = CUR_CHAR(l);
                   3230:        }
                   3231:     }
                   3232:     buf[len] = 0;
                   3233:     if (!IS_CHAR(cur)) {
                   3234:        htmlParseErr(ctxt, XML_ERR_COMMENT_NOT_FINISHED,
                   3235:                     "Comment not terminated \n<!--%.50s\n", buf, NULL);
                   3236:        xmlFree(buf);
                   3237:     } else {
                   3238:         NEXT;
                   3239:        if ((ctxt->sax != NULL) && (ctxt->sax->comment != NULL) &&
                   3240:            (!ctxt->disableSAX))
                   3241:            ctxt->sax->comment(ctxt->userData, buf);
                   3242:        xmlFree(buf);
                   3243:     }
                   3244:     ctxt->instate = state;
                   3245: }
                   3246: 
                   3247: /**
                   3248:  * htmlParseCharRef:
                   3249:  * @ctxt:  an HTML parser context
                   3250:  *
                   3251:  * parse Reference declarations
                   3252:  *
                   3253:  * [66] CharRef ::= '&#' [0-9]+ ';' |
                   3254:  *                  '&#x' [0-9a-fA-F]+ ';'
                   3255:  *
                   3256:  * Returns the value parsed (as an int)
                   3257:  */
                   3258: int
                   3259: htmlParseCharRef(htmlParserCtxtPtr ctxt) {
                   3260:     int val = 0;
                   3261: 
                   3262:     if ((ctxt == NULL) || (ctxt->input == NULL)) {
                   3263:        htmlParseErr(ctxt, XML_ERR_INTERNAL_ERROR,
                   3264:                     "htmlParseCharRef: context error\n",
                   3265:                     NULL, NULL);
                   3266:         return(0);
                   3267:     }
                   3268:     if ((CUR == '&') && (NXT(1) == '#') &&
                   3269:         ((NXT(2) == 'x') || NXT(2) == 'X')) {
                   3270:        SKIP(3);
                   3271:        while (CUR != ';') {
                   3272:            if ((CUR >= '0') && (CUR <= '9'))
                   3273:                val = val * 16 + (CUR - '0');
                   3274:            else if ((CUR >= 'a') && (CUR <= 'f'))
                   3275:                val = val * 16 + (CUR - 'a') + 10;
                   3276:            else if ((CUR >= 'A') && (CUR <= 'F'))
                   3277:                val = val * 16 + (CUR - 'A') + 10;
                   3278:            else {
                   3279:                htmlParseErr(ctxt, XML_ERR_INVALID_HEX_CHARREF,
                   3280:                             "htmlParseCharRef: missing semicolon\n",
                   3281:                             NULL, NULL);
                   3282:                break;
                   3283:            }
                   3284:            NEXT;
                   3285:        }
                   3286:        if (CUR == ';')
                   3287:            NEXT;
                   3288:     } else if  ((CUR == '&') && (NXT(1) == '#')) {
                   3289:        SKIP(2);
                   3290:        while (CUR != ';') {
                   3291:            if ((CUR >= '0') && (CUR <= '9'))
                   3292:                val = val * 10 + (CUR - '0');
                   3293:            else {
                   3294:                htmlParseErr(ctxt, XML_ERR_INVALID_DEC_CHARREF,
                   3295:                             "htmlParseCharRef: missing semicolon\n",
                   3296:                             NULL, NULL);
                   3297:                break;
                   3298:            }
                   3299:            NEXT;
                   3300:        }
                   3301:        if (CUR == ';')
                   3302:            NEXT;
                   3303:     } else {
                   3304:        htmlParseErr(ctxt, XML_ERR_INVALID_CHARREF,
                   3305:                     "htmlParseCharRef: invalid value\n", NULL, NULL);
                   3306:     }
                   3307:     /*
                   3308:      * Check the value IS_CHAR ...
                   3309:      */
                   3310:     if (IS_CHAR(val)) {
                   3311:         return(val);
                   3312:     } else {
                   3313:        htmlParseErrInt(ctxt, XML_ERR_INVALID_CHAR,
                   3314:                        "htmlParseCharRef: invalid xmlChar value %d\n",
                   3315:                        val);
                   3316:     }
                   3317:     return(0);
                   3318: }
                   3319: 
                   3320: 
                   3321: /**
                   3322:  * htmlParseDocTypeDecl:
                   3323:  * @ctxt:  an HTML parser context
                   3324:  *
                   3325:  * parse a DOCTYPE declaration
                   3326:  *
                   3327:  * [28] doctypedecl ::= '<!DOCTYPE' S Name (S ExternalID)? S?
                   3328:  *                      ('[' (markupdecl | PEReference | S)* ']' S?)? '>'
                   3329:  */
                   3330: 
                   3331: static void
                   3332: htmlParseDocTypeDecl(htmlParserCtxtPtr ctxt) {
                   3333:     const xmlChar *name;
                   3334:     xmlChar *ExternalID = NULL;
                   3335:     xmlChar *URI = NULL;
                   3336: 
                   3337:     /*
                   3338:      * We know that '<!DOCTYPE' has been detected.
                   3339:      */
                   3340:     SKIP(9);
                   3341: 
                   3342:     SKIP_BLANKS;
                   3343: 
                   3344:     /*
                   3345:      * Parse the DOCTYPE name.
                   3346:      */
                   3347:     name = htmlParseName(ctxt);
                   3348:     if (name == NULL) {
                   3349:        htmlParseErr(ctxt, XML_ERR_NAME_REQUIRED,
                   3350:                     "htmlParseDocTypeDecl : no DOCTYPE name !\n",
                   3351:                     NULL, NULL);
                   3352:     }
                   3353:     /*
                   3354:      * Check that upper(name) == "HTML" !!!!!!!!!!!!!
                   3355:      */
                   3356: 
                   3357:     SKIP_BLANKS;
                   3358: 
                   3359:     /*
                   3360:      * Check for SystemID and ExternalID
                   3361:      */
                   3362:     URI = htmlParseExternalID(ctxt, &ExternalID);
                   3363:     SKIP_BLANKS;
                   3364: 
                   3365:     /*
                   3366:      * We should be at the end of the DOCTYPE declaration.
                   3367:      */
                   3368:     if (CUR != '>') {
                   3369:        htmlParseErr(ctxt, XML_ERR_DOCTYPE_NOT_FINISHED,
                   3370:                     "DOCTYPE improperly terminated\n", NULL, NULL);
                   3371:         /* We shouldn't try to resynchronize ... */
                   3372:     }
                   3373:     NEXT;
                   3374: 
                   3375:     /*
                   3376:      * Create or update the document accordingly to the DOCTYPE
                   3377:      */
                   3378:     if ((ctxt->sax != NULL) && (ctxt->sax->internalSubset != NULL) &&
                   3379:        (!ctxt->disableSAX))
                   3380:        ctxt->sax->internalSubset(ctxt->userData, name, ExternalID, URI);
                   3381: 
                   3382:     /*
                   3383:      * Cleanup, since we don't use all those identifiers
                   3384:      */
                   3385:     if (URI != NULL) xmlFree(URI);
                   3386:     if (ExternalID != NULL) xmlFree(ExternalID);
                   3387: }
                   3388: 
                   3389: /**
                   3390:  * htmlParseAttribute:
                   3391:  * @ctxt:  an HTML parser context
                   3392:  * @value:  a xmlChar ** used to store the value of the attribute
                   3393:  *
                   3394:  * parse an attribute
                   3395:  *
                   3396:  * [41] Attribute ::= Name Eq AttValue
                   3397:  *
                   3398:  * [25] Eq ::= S? '=' S?
                   3399:  *
                   3400:  * With namespace:
                   3401:  *
                   3402:  * [NS 11] Attribute ::= QName Eq AttValue
                   3403:  *
                   3404:  * Also the case QName == xmlns:??? is handled independently as a namespace
                   3405:  * definition.
                   3406:  *
                   3407:  * Returns the attribute name, and the value in *value.
                   3408:  */
                   3409: 
                   3410: static const xmlChar *
                   3411: htmlParseAttribute(htmlParserCtxtPtr ctxt, xmlChar **value) {
                   3412:     const xmlChar *name;
                   3413:     xmlChar *val = NULL;
                   3414: 
                   3415:     *value = NULL;
                   3416:     name = htmlParseHTMLName(ctxt);
                   3417:     if (name == NULL) {
                   3418:        htmlParseErr(ctxt, XML_ERR_NAME_REQUIRED,
                   3419:                     "error parsing attribute name\n", NULL, NULL);
                   3420:         return(NULL);
                   3421:     }
                   3422: 
                   3423:     /*
                   3424:      * read the value
                   3425:      */
                   3426:     SKIP_BLANKS;
                   3427:     if (CUR == '=') {
                   3428:         NEXT;
                   3429:        SKIP_BLANKS;
                   3430:        val = htmlParseAttValue(ctxt);
                   3431:     }
                   3432: 
                   3433:     *value = val;
                   3434:     return(name);
                   3435: }
                   3436: 
                   3437: /**
1.1.1.2 ! misho    3438:  * htmlCheckEncodingDirect:
1.1       misho    3439:  * @ctxt:  an HTML parser context
                   3440:  * @attvalue: the attribute value
                   3441:  *
1.1.1.2 ! misho    3442:  * Checks an attribute value to detect
1.1       misho    3443:  * the encoding
                   3444:  * If a new encoding is detected the parser is switched to decode
                   3445:  * it and pass UTF8
                   3446:  */
                   3447: static void
1.1.1.2 ! misho    3448: htmlCheckEncodingDirect(htmlParserCtxtPtr ctxt, const xmlChar *encoding) {
1.1       misho    3449: 
1.1.1.2 ! misho    3450:     if ((ctxt == NULL) || (encoding == NULL) ||
        !          3451:         (ctxt->options & HTML_PARSE_IGNORE_ENC))
1.1       misho    3452:        return;
                   3453: 
                   3454:     /* do not change encoding */
                   3455:     if (ctxt->input->encoding != NULL)
                   3456:         return;
                   3457: 
                   3458:     if (encoding != NULL) {
                   3459:        xmlCharEncoding enc;
                   3460:        xmlCharEncodingHandlerPtr handler;
                   3461: 
                   3462:        while ((*encoding == ' ') || (*encoding == '\t')) encoding++;
                   3463: 
                   3464:        if (ctxt->input->encoding != NULL)
                   3465:            xmlFree((xmlChar *) ctxt->input->encoding);
                   3466:        ctxt->input->encoding = xmlStrdup(encoding);
                   3467: 
                   3468:        enc = xmlParseCharEncoding((const char *) encoding);
                   3469:        /*
                   3470:         * registered set of known encodings
                   3471:         */
                   3472:        if (enc != XML_CHAR_ENCODING_ERROR) {
                   3473:            if (((enc == XML_CHAR_ENCODING_UTF16LE) ||
                   3474:                 (enc == XML_CHAR_ENCODING_UTF16BE) ||
                   3475:                 (enc == XML_CHAR_ENCODING_UCS4LE) ||
                   3476:                 (enc == XML_CHAR_ENCODING_UCS4BE)) &&
                   3477:                (ctxt->input->buf != NULL) &&
                   3478:                (ctxt->input->buf->encoder == NULL)) {
                   3479:                htmlParseErr(ctxt, XML_ERR_INVALID_ENCODING,
                   3480:                             "htmlCheckEncoding: wrong encoding meta\n",
                   3481:                             NULL, NULL);
                   3482:            } else {
                   3483:                xmlSwitchEncoding(ctxt, enc);
                   3484:            }
                   3485:            ctxt->charset = XML_CHAR_ENCODING_UTF8;
                   3486:        } else {
                   3487:            /*
                   3488:             * fallback for unknown encodings
                   3489:             */
                   3490:            handler = xmlFindCharEncodingHandler((const char *) encoding);
                   3491:            if (handler != NULL) {
                   3492:                xmlSwitchToEncoding(ctxt, handler);
                   3493:                ctxt->charset = XML_CHAR_ENCODING_UTF8;
                   3494:            } else {
1.1.1.2 ! misho    3495:                htmlParseErr(ctxt, XML_ERR_UNSUPPORTED_ENCODING,
        !          3496:                             "htmlCheckEncoding: unknown encoding %s\n",
        !          3497:                             encoding, NULL);
1.1       misho    3498:            }
                   3499:        }
                   3500: 
                   3501:        if ((ctxt->input->buf != NULL) &&
                   3502:            (ctxt->input->buf->encoder != NULL) &&
                   3503:            (ctxt->input->buf->raw != NULL) &&
                   3504:            (ctxt->input->buf->buffer != NULL)) {
                   3505:            int nbchars;
                   3506:            int processed;
                   3507: 
                   3508:            /*
                   3509:             * convert as much as possible to the parser reading buffer.
                   3510:             */
                   3511:            processed = ctxt->input->cur - ctxt->input->base;
                   3512:            xmlBufferShrink(ctxt->input->buf->buffer, processed);
                   3513:            nbchars = xmlCharEncInFunc(ctxt->input->buf->encoder,
                   3514:                                       ctxt->input->buf->buffer,
                   3515:                                       ctxt->input->buf->raw);
                   3516:            if (nbchars < 0) {
                   3517:                htmlParseErr(ctxt, XML_ERR_INVALID_ENCODING,
                   3518:                             "htmlCheckEncoding: encoder error\n",
                   3519:                             NULL, NULL);
                   3520:            }
                   3521:            ctxt->input->base =
                   3522:            ctxt->input->cur = ctxt->input->buf->buffer->content;
                   3523:             ctxt->input->end =
                   3524:                           &ctxt->input->base[ctxt->input->buf->buffer->use];
                   3525:        }
                   3526:     }
                   3527: }
                   3528: 
                   3529: /**
1.1.1.2 ! misho    3530:  * htmlCheckEncoding:
        !          3531:  * @ctxt:  an HTML parser context
        !          3532:  * @attvalue: the attribute value
        !          3533:  *
        !          3534:  * Checks an http-equiv attribute from a Meta tag to detect
        !          3535:  * the encoding
        !          3536:  * If a new encoding is detected the parser is switched to decode
        !          3537:  * it and pass UTF8
        !          3538:  */
        !          3539: static void
        !          3540: htmlCheckEncoding(htmlParserCtxtPtr ctxt, const xmlChar *attvalue) {
        !          3541:     const xmlChar *encoding;
        !          3542: 
        !          3543:     if (!attvalue)
        !          3544:        return;
        !          3545: 
        !          3546:     encoding = xmlStrcasestr(attvalue, BAD_CAST"charset");
        !          3547:     if (encoding != NULL) {
        !          3548:        encoding += 7;
        !          3549:     }
        !          3550:     /*
        !          3551:      * skip blank
        !          3552:      */
        !          3553:     if (encoding && IS_BLANK_CH(*encoding))
        !          3554:        encoding = xmlStrcasestr(attvalue, BAD_CAST"=");
        !          3555:     if (encoding && *encoding == '=') {
        !          3556:        encoding ++;
        !          3557:        htmlCheckEncodingDirect(ctxt, encoding);
        !          3558:     }
        !          3559: }
        !          3560: 
        !          3561: /**
1.1       misho    3562:  * htmlCheckMeta:
                   3563:  * @ctxt:  an HTML parser context
                   3564:  * @atts:  the attributes values
                   3565:  *
                   3566:  * Checks an attributes from a Meta tag
                   3567:  */
                   3568: static void
                   3569: htmlCheckMeta(htmlParserCtxtPtr ctxt, const xmlChar **atts) {
                   3570:     int i;
                   3571:     const xmlChar *att, *value;
                   3572:     int http = 0;
                   3573:     const xmlChar *content = NULL;
                   3574: 
                   3575:     if ((ctxt == NULL) || (atts == NULL))
                   3576:        return;
                   3577: 
                   3578:     i = 0;
                   3579:     att = atts[i++];
                   3580:     while (att != NULL) {
                   3581:        value = atts[i++];
                   3582:        if ((value != NULL) && (!xmlStrcasecmp(att, BAD_CAST"http-equiv"))
                   3583:         && (!xmlStrcasecmp(value, BAD_CAST"Content-Type")))
                   3584:            http = 1;
1.1.1.2 ! misho    3585:        else if ((value != NULL) && (!xmlStrcasecmp(att, BAD_CAST"charset")))
        !          3586:            htmlCheckEncodingDirect(ctxt, value);
1.1       misho    3587:        else if ((value != NULL) && (!xmlStrcasecmp(att, BAD_CAST"content")))
                   3588:            content = value;
                   3589:        att = atts[i++];
                   3590:     }
                   3591:     if ((http) && (content != NULL))
                   3592:        htmlCheckEncoding(ctxt, content);
                   3593: 
                   3594: }
                   3595: 
                   3596: /**
                   3597:  * htmlParseStartTag:
                   3598:  * @ctxt:  an HTML parser context
                   3599:  *
                   3600:  * parse a start of tag either for rule element or
                   3601:  * EmptyElement. In both case we don't parse the tag closing chars.
                   3602:  *
                   3603:  * [40] STag ::= '<' Name (S Attribute)* S? '>'
                   3604:  *
                   3605:  * [44] EmptyElemTag ::= '<' Name (S Attribute)* S? '/>'
                   3606:  *
                   3607:  * With namespace:
                   3608:  *
                   3609:  * [NS 8] STag ::= '<' QName (S Attribute)* S? '>'
                   3610:  *
                   3611:  * [NS 10] EmptyElement ::= '<' QName (S Attribute)* S? '/>'
                   3612:  *
                   3613:  * Returns 0 in case of success, -1 in case of error and 1 if discarded
                   3614:  */
                   3615: 
                   3616: static int
                   3617: htmlParseStartTag(htmlParserCtxtPtr ctxt) {
                   3618:     const xmlChar *name;
                   3619:     const xmlChar *attname;
                   3620:     xmlChar *attvalue;
                   3621:     const xmlChar **atts;
                   3622:     int nbatts = 0;
                   3623:     int maxatts;
                   3624:     int meta = 0;
                   3625:     int i;
                   3626:     int discardtag = 0;
                   3627: 
                   3628:     if (ctxt->instate == XML_PARSER_EOF)
                   3629:         return(-1);
                   3630:     if ((ctxt == NULL) || (ctxt->input == NULL)) {
                   3631:        htmlParseErr(ctxt, XML_ERR_INTERNAL_ERROR,
                   3632:                     "htmlParseStartTag: context error\n", NULL, NULL);
                   3633:        return -1;
                   3634:     }
                   3635:     if (CUR != '<') return -1;
                   3636:     NEXT;
                   3637: 
                   3638:     atts = ctxt->atts;
                   3639:     maxatts = ctxt->maxatts;
                   3640: 
                   3641:     GROW;
                   3642:     name = htmlParseHTMLName(ctxt);
                   3643:     if (name == NULL) {
                   3644:        htmlParseErr(ctxt, XML_ERR_NAME_REQUIRED,
                   3645:                     "htmlParseStartTag: invalid element name\n",
                   3646:                     NULL, NULL);
                   3647:        /* Dump the bogus tag like browsers do */
                   3648:        while ((IS_CHAR_CH(CUR)) && (CUR != '>') &&
                   3649:                (ctxt->instate != XML_PARSER_EOF))
                   3650:            NEXT;
                   3651:         return -1;
                   3652:     }
                   3653:     if (xmlStrEqual(name, BAD_CAST"meta"))
                   3654:        meta = 1;
                   3655: 
                   3656:     /*
                   3657:      * Check for auto-closure of HTML elements.
                   3658:      */
                   3659:     htmlAutoClose(ctxt, name);
                   3660: 
                   3661:     /*
                   3662:      * Check for implied HTML elements.
                   3663:      */
                   3664:     htmlCheckImplied(ctxt, name);
                   3665: 
                   3666:     /*
                   3667:      * Avoid html at any level > 0, head at any level != 1
                   3668:      * or any attempt to recurse body
                   3669:      */
                   3670:     if ((ctxt->nameNr > 0) && (xmlStrEqual(name, BAD_CAST"html"))) {
                   3671:        htmlParseErr(ctxt, XML_HTML_STRUCURE_ERROR,
                   3672:                     "htmlParseStartTag: misplaced <html> tag\n",
                   3673:                     name, NULL);
                   3674:        discardtag = 1;
                   3675:        ctxt->depth++;
                   3676:     }
                   3677:     if ((ctxt->nameNr != 1) &&
                   3678:        (xmlStrEqual(name, BAD_CAST"head"))) {
                   3679:        htmlParseErr(ctxt, XML_HTML_STRUCURE_ERROR,
                   3680:                     "htmlParseStartTag: misplaced <head> tag\n",
                   3681:                     name, NULL);
                   3682:        discardtag = 1;
                   3683:        ctxt->depth++;
                   3684:     }
                   3685:     if (xmlStrEqual(name, BAD_CAST"body")) {
                   3686:        int indx;
                   3687:        for (indx = 0;indx < ctxt->nameNr;indx++) {
                   3688:            if (xmlStrEqual(ctxt->nameTab[indx], BAD_CAST"body")) {
                   3689:                htmlParseErr(ctxt, XML_HTML_STRUCURE_ERROR,
                   3690:                             "htmlParseStartTag: misplaced <body> tag\n",
                   3691:                             name, NULL);
                   3692:                discardtag = 1;
                   3693:                ctxt->depth++;
                   3694:            }
                   3695:        }
                   3696:     }
                   3697: 
                   3698:     /*
                   3699:      * Now parse the attributes, it ends up with the ending
                   3700:      *
                   3701:      * (S Attribute)* S?
                   3702:      */
                   3703:     SKIP_BLANKS;
                   3704:     while ((IS_CHAR_CH(CUR)) &&
                   3705:            (CUR != '>') &&
                   3706:           ((CUR != '/') || (NXT(1) != '>'))) {
                   3707:        long cons = ctxt->nbChars;
                   3708: 
                   3709:        GROW;
                   3710:        attname = htmlParseAttribute(ctxt, &attvalue);
                   3711:         if (attname != NULL) {
                   3712: 
                   3713:            /*
                   3714:             * Well formedness requires at most one declaration of an attribute
                   3715:             */
                   3716:            for (i = 0; i < nbatts;i += 2) {
                   3717:                if (xmlStrEqual(atts[i], attname)) {
                   3718:                    htmlParseErr(ctxt, XML_ERR_ATTRIBUTE_REDEFINED,
                   3719:                                 "Attribute %s redefined\n", attname, NULL);
                   3720:                    if (attvalue != NULL)
                   3721:                        xmlFree(attvalue);
                   3722:                    goto failed;
                   3723:                }
                   3724:            }
                   3725: 
                   3726:            /*
                   3727:             * Add the pair to atts
                   3728:             */
                   3729:            if (atts == NULL) {
                   3730:                maxatts = 22; /* allow for 10 attrs by default */
                   3731:                atts = (const xmlChar **)
                   3732:                       xmlMalloc(maxatts * sizeof(xmlChar *));
                   3733:                if (atts == NULL) {
                   3734:                    htmlErrMemory(ctxt, NULL);
                   3735:                    if (attvalue != NULL)
                   3736:                        xmlFree(attvalue);
                   3737:                    goto failed;
                   3738:                }
                   3739:                ctxt->atts = atts;
                   3740:                ctxt->maxatts = maxatts;
                   3741:            } else if (nbatts + 4 > maxatts) {
                   3742:                const xmlChar **n;
                   3743: 
                   3744:                maxatts *= 2;
                   3745:                n = (const xmlChar **) xmlRealloc((void *) atts,
                   3746:                                             maxatts * sizeof(const xmlChar *));
                   3747:                if (n == NULL) {
                   3748:                    htmlErrMemory(ctxt, NULL);
                   3749:                    if (attvalue != NULL)
                   3750:                        xmlFree(attvalue);
                   3751:                    goto failed;
                   3752:                }
                   3753:                atts = n;
                   3754:                ctxt->atts = atts;
                   3755:                ctxt->maxatts = maxatts;
                   3756:            }
                   3757:            atts[nbatts++] = attname;
                   3758:            atts[nbatts++] = attvalue;
                   3759:            atts[nbatts] = NULL;
                   3760:            atts[nbatts + 1] = NULL;
                   3761:        }
                   3762:        else {
                   3763:            if (attvalue != NULL)
                   3764:                xmlFree(attvalue);
                   3765:            /* Dump the bogus attribute string up to the next blank or
                   3766:             * the end of the tag. */
                   3767:            while ((IS_CHAR_CH(CUR)) &&
                   3768:                   !(IS_BLANK_CH(CUR)) && (CUR != '>') &&
                   3769:                   ((CUR != '/') || (NXT(1) != '>')))
                   3770:                NEXT;
                   3771:        }
                   3772: 
                   3773: failed:
                   3774:        SKIP_BLANKS;
                   3775:         if (cons == ctxt->nbChars) {
                   3776:            htmlParseErr(ctxt, XML_ERR_INTERNAL_ERROR,
                   3777:                         "htmlParseStartTag: problem parsing attributes\n",
                   3778:                         NULL, NULL);
                   3779:            break;
                   3780:        }
                   3781:     }
                   3782: 
                   3783:     /*
                   3784:      * Handle specific association to the META tag
                   3785:      */
                   3786:     if (meta && (nbatts != 0))
                   3787:        htmlCheckMeta(ctxt, atts);
                   3788: 
                   3789:     /*
                   3790:      * SAX: Start of Element !
                   3791:      */
                   3792:     if (!discardtag) {
                   3793:        htmlnamePush(ctxt, name);
                   3794:        if ((ctxt->sax != NULL) && (ctxt->sax->startElement != NULL)) {
                   3795:            if (nbatts != 0)
                   3796:                ctxt->sax->startElement(ctxt->userData, name, atts);
                   3797:            else
                   3798:                ctxt->sax->startElement(ctxt->userData, name, NULL);
                   3799:        }
                   3800:     }
                   3801: 
                   3802:     if (atts != NULL) {
                   3803:         for (i = 1;i < nbatts;i += 2) {
                   3804:            if (atts[i] != NULL)
                   3805:                xmlFree((xmlChar *) atts[i]);
                   3806:        }
                   3807:     }
                   3808: 
                   3809:     return(discardtag);
                   3810: }
                   3811: 
                   3812: /**
                   3813:  * htmlParseEndTag:
                   3814:  * @ctxt:  an HTML parser context
                   3815:  *
                   3816:  * parse an end of tag
                   3817:  *
                   3818:  * [42] ETag ::= '</' Name S? '>'
                   3819:  *
                   3820:  * With namespace
                   3821:  *
                   3822:  * [NS 9] ETag ::= '</' QName S? '>'
                   3823:  *
                   3824:  * Returns 1 if the current level should be closed.
                   3825:  */
                   3826: 
                   3827: static int
                   3828: htmlParseEndTag(htmlParserCtxtPtr ctxt)
                   3829: {
                   3830:     const xmlChar *name;
                   3831:     const xmlChar *oldname;
                   3832:     int i, ret;
                   3833: 
                   3834:     if ((CUR != '<') || (NXT(1) != '/')) {
                   3835:         htmlParseErr(ctxt, XML_ERR_LTSLASH_REQUIRED,
                   3836:                     "htmlParseEndTag: '</' not found\n", NULL, NULL);
                   3837:         return (0);
                   3838:     }
                   3839:     SKIP(2);
                   3840: 
                   3841:     name = htmlParseHTMLName(ctxt);
                   3842:     if (name == NULL)
                   3843:         return (0);
                   3844:     /*
                   3845:      * We should definitely be at the ending "S? '>'" part
                   3846:      */
                   3847:     SKIP_BLANKS;
                   3848:     if ((!IS_CHAR_CH(CUR)) || (CUR != '>')) {
                   3849:         htmlParseErr(ctxt, XML_ERR_GT_REQUIRED,
                   3850:                     "End tag : expected '>'\n", NULL, NULL);
                   3851:        if (ctxt->recovery) {
                   3852:            /*
                   3853:             * We're not at the ending > !!
                   3854:             * Error, unless in recover mode where we search forwards
                   3855:             * until we find a >
                   3856:             */
                   3857:            while (CUR != '\0' && CUR != '>') NEXT;
                   3858:            NEXT;
                   3859:        }
                   3860:     } else
                   3861:         NEXT;
                   3862: 
                   3863:     /*
                   3864:      * if we ignored misplaced tags in htmlParseStartTag don't pop them
                   3865:      * out now.
                   3866:      */
                   3867:     if ((ctxt->depth > 0) &&
                   3868:         (xmlStrEqual(name, BAD_CAST "html") ||
                   3869:          xmlStrEqual(name, BAD_CAST "body") ||
                   3870:         xmlStrEqual(name, BAD_CAST "head"))) {
                   3871:        ctxt->depth--;
                   3872:        return (0);
                   3873:     }
                   3874: 
                   3875:     /*
                   3876:      * If the name read is not one of the element in the parsing stack
                   3877:      * then return, it's just an error.
                   3878:      */
                   3879:     for (i = (ctxt->nameNr - 1); i >= 0; i--) {
                   3880:         if (xmlStrEqual(name, ctxt->nameTab[i]))
                   3881:             break;
                   3882:     }
                   3883:     if (i < 0) {
                   3884:         htmlParseErr(ctxt, XML_ERR_TAG_NAME_MISMATCH,
                   3885:                     "Unexpected end tag : %s\n", name, NULL);
                   3886:         return (0);
                   3887:     }
                   3888: 
                   3889: 
                   3890:     /*
                   3891:      * Check for auto-closure of HTML elements.
                   3892:      */
                   3893: 
                   3894:     htmlAutoCloseOnClose(ctxt, name);
                   3895: 
                   3896:     /*
                   3897:      * Well formedness constraints, opening and closing must match.
                   3898:      * With the exception that the autoclose may have popped stuff out
                   3899:      * of the stack.
                   3900:      */
                   3901:     if (!xmlStrEqual(name, ctxt->name)) {
                   3902:         if ((ctxt->name != NULL) && (!xmlStrEqual(ctxt->name, name))) {
                   3903:             htmlParseErr(ctxt, XML_ERR_TAG_NAME_MISMATCH,
                   3904:                         "Opening and ending tag mismatch: %s and %s\n",
                   3905:                         name, ctxt->name);
                   3906:         }
                   3907:     }
                   3908: 
                   3909:     /*
                   3910:      * SAX: End of Tag
                   3911:      */
                   3912:     oldname = ctxt->name;
                   3913:     if ((oldname != NULL) && (xmlStrEqual(oldname, name))) {
                   3914:         if ((ctxt->sax != NULL) && (ctxt->sax->endElement != NULL))
                   3915:             ctxt->sax->endElement(ctxt->userData, name);
1.1.1.2 ! misho    3916:        htmlNodeInfoPop(ctxt);
1.1       misho    3917:         htmlnamePop(ctxt);
                   3918:         ret = 1;
                   3919:     } else {
                   3920:         ret = 0;
                   3921:     }
                   3922: 
                   3923:     return (ret);
                   3924: }
                   3925: 
                   3926: 
                   3927: /**
                   3928:  * htmlParseReference:
                   3929:  * @ctxt:  an HTML parser context
                   3930:  *
                   3931:  * parse and handle entity references in content,
                   3932:  * this will end-up in a call to character() since this is either a
                   3933:  * CharRef, or a predefined entity.
                   3934:  */
                   3935: static void
                   3936: htmlParseReference(htmlParserCtxtPtr ctxt) {
                   3937:     const htmlEntityDesc * ent;
                   3938:     xmlChar out[6];
                   3939:     const xmlChar *name;
                   3940:     if (CUR != '&') return;
                   3941: 
                   3942:     if (NXT(1) == '#') {
                   3943:        unsigned int c;
                   3944:        int bits, i = 0;
                   3945: 
                   3946:        c = htmlParseCharRef(ctxt);
                   3947:        if (c == 0)
                   3948:            return;
                   3949: 
                   3950:         if      (c <    0x80) { out[i++]= c;                bits= -6; }
                   3951:         else if (c <   0x800) { out[i++]=((c >>  6) & 0x1F) | 0xC0;  bits=  0; }
                   3952:         else if (c < 0x10000) { out[i++]=((c >> 12) & 0x0F) | 0xE0;  bits=  6; }
                   3953:         else                  { out[i++]=((c >> 18) & 0x07) | 0xF0;  bits= 12; }
                   3954: 
                   3955:         for ( ; bits >= 0; bits-= 6) {
                   3956:             out[i++]= ((c >> bits) & 0x3F) | 0x80;
                   3957:         }
                   3958:        out[i] = 0;
                   3959: 
                   3960:        htmlCheckParagraph(ctxt);
                   3961:        if ((ctxt->sax != NULL) && (ctxt->sax->characters != NULL))
                   3962:            ctxt->sax->characters(ctxt->userData, out, i);
                   3963:     } else {
                   3964:        ent = htmlParseEntityRef(ctxt, &name);
                   3965:        if (name == NULL) {
                   3966:            htmlCheckParagraph(ctxt);
                   3967:            if ((ctxt->sax != NULL) && (ctxt->sax->characters != NULL))
                   3968:                ctxt->sax->characters(ctxt->userData, BAD_CAST "&", 1);
                   3969:            return;
                   3970:        }
                   3971:        if ((ent == NULL) || !(ent->value > 0)) {
                   3972:            htmlCheckParagraph(ctxt);
                   3973:            if ((ctxt->sax != NULL) && (ctxt->sax->characters != NULL)) {
                   3974:                ctxt->sax->characters(ctxt->userData, BAD_CAST "&", 1);
                   3975:                ctxt->sax->characters(ctxt->userData, name, xmlStrlen(name));
                   3976:                /* ctxt->sax->characters(ctxt->userData, BAD_CAST ";", 1); */
                   3977:            }
                   3978:        } else {
                   3979:            unsigned int c;
                   3980:            int bits, i = 0;
                   3981: 
                   3982:            c = ent->value;
                   3983:            if      (c <    0x80)
                   3984:                    { out[i++]= c;                bits= -6; }
                   3985:            else if (c <   0x800)
                   3986:                    { out[i++]=((c >>  6) & 0x1F) | 0xC0;  bits=  0; }
                   3987:            else if (c < 0x10000)
                   3988:                    { out[i++]=((c >> 12) & 0x0F) | 0xE0;  bits=  6; }
                   3989:            else
                   3990:                    { out[i++]=((c >> 18) & 0x07) | 0xF0;  bits= 12; }
                   3991: 
                   3992:            for ( ; bits >= 0; bits-= 6) {
                   3993:                out[i++]= ((c >> bits) & 0x3F) | 0x80;
                   3994:            }
                   3995:            out[i] = 0;
                   3996: 
                   3997:            htmlCheckParagraph(ctxt);
                   3998:            if ((ctxt->sax != NULL) && (ctxt->sax->characters != NULL))
                   3999:                ctxt->sax->characters(ctxt->userData, out, i);
                   4000:        }
                   4001:     }
                   4002: }
                   4003: 
                   4004: /**
                   4005:  * htmlParseContent:
                   4006:  * @ctxt:  an HTML parser context
                   4007:  *
                   4008:  * Parse a content: comment, sub-element, reference or text.
                   4009:  * Kept for compatibility with old code
                   4010:  */
                   4011: 
                   4012: static void
                   4013: htmlParseContent(htmlParserCtxtPtr ctxt) {
                   4014:     xmlChar *currentNode;
                   4015:     int depth;
                   4016:     const xmlChar *name;
                   4017: 
                   4018:     currentNode = xmlStrdup(ctxt->name);
                   4019:     depth = ctxt->nameNr;
                   4020:     while (1) {
                   4021:        long cons = ctxt->nbChars;
                   4022: 
                   4023:         GROW;
                   4024: 
                   4025:         if (ctxt->instate == XML_PARSER_EOF)
                   4026:             break;
                   4027: 
                   4028:        /*
                   4029:         * Our tag or one of it's parent or children is ending.
                   4030:         */
                   4031:         if ((CUR == '<') && (NXT(1) == '/')) {
                   4032:            if (htmlParseEndTag(ctxt) &&
                   4033:                ((currentNode != NULL) || (ctxt->nameNr == 0))) {
                   4034:                if (currentNode != NULL)
                   4035:                    xmlFree(currentNode);
                   4036:                return;
                   4037:            }
                   4038:            continue; /* while */
                   4039:         }
                   4040: 
                   4041:        else if ((CUR == '<') &&
                   4042:                 ((IS_ASCII_LETTER(NXT(1))) ||
                   4043:                  (NXT(1) == '_') || (NXT(1) == ':'))) {
                   4044:            name = htmlParseHTMLName_nonInvasive(ctxt);
                   4045:            if (name == NULL) {
                   4046:                htmlParseErr(ctxt, XML_ERR_NAME_REQUIRED,
                   4047:                         "htmlParseStartTag: invalid element name\n",
                   4048:                         NULL, NULL);
                   4049:                /* Dump the bogus tag like browsers do */
                   4050:         while ((IS_CHAR_CH(CUR)) && (CUR != '>'))
                   4051:                    NEXT;
                   4052: 
                   4053:                if (currentNode != NULL)
                   4054:                    xmlFree(currentNode);
                   4055:                return;
                   4056:            }
                   4057: 
                   4058:            if (ctxt->name != NULL) {
                   4059:                if (htmlCheckAutoClose(name, ctxt->name) == 1) {
                   4060:                    htmlAutoClose(ctxt, name);
                   4061:                    continue;
                   4062:                }
                   4063:            }
                   4064:        }
                   4065: 
                   4066:        /*
                   4067:         * Has this node been popped out during parsing of
                   4068:         * the next element
                   4069:         */
                   4070:         if ((ctxt->nameNr > 0) && (depth >= ctxt->nameNr) &&
                   4071:            (!xmlStrEqual(currentNode, ctxt->name)))
                   4072:             {
                   4073:            if (currentNode != NULL) xmlFree(currentNode);
                   4074:            return;
                   4075:        }
                   4076: 
                   4077:        if ((CUR != 0) && ((xmlStrEqual(currentNode, BAD_CAST"script")) ||
                   4078:            (xmlStrEqual(currentNode, BAD_CAST"style")))) {
                   4079:            /*
                   4080:             * Handle SCRIPT/STYLE separately
                   4081:             */
                   4082:            htmlParseScript(ctxt);
                   4083:        } else {
                   4084:            /*
                   4085:             * Sometimes DOCTYPE arrives in the middle of the document
                   4086:             */
                   4087:            if ((CUR == '<') && (NXT(1) == '!') &&
                   4088:                (UPP(2) == 'D') && (UPP(3) == 'O') &&
                   4089:                (UPP(4) == 'C') && (UPP(5) == 'T') &&
                   4090:                (UPP(6) == 'Y') && (UPP(7) == 'P') &&
                   4091:                (UPP(8) == 'E')) {
                   4092:                htmlParseErr(ctxt, XML_HTML_STRUCURE_ERROR,
                   4093:                             "Misplaced DOCTYPE declaration\n",
                   4094:                             BAD_CAST "DOCTYPE" , NULL);
                   4095:                htmlParseDocTypeDecl(ctxt);
                   4096:            }
                   4097: 
                   4098:            /*
                   4099:             * First case :  a comment
                   4100:             */
                   4101:            if ((CUR == '<') && (NXT(1) == '!') &&
                   4102:                (NXT(2) == '-') && (NXT(3) == '-')) {
                   4103:                htmlParseComment(ctxt);
                   4104:            }
                   4105: 
                   4106:            /*
                   4107:             * Second case : a Processing Instruction.
                   4108:             */
                   4109:            else if ((CUR == '<') && (NXT(1) == '?')) {
                   4110:                htmlParsePI(ctxt);
                   4111:            }
                   4112: 
                   4113:            /*
                   4114:             * Third case :  a sub-element.
                   4115:             */
                   4116:            else if (CUR == '<') {
                   4117:                htmlParseElement(ctxt);
                   4118:            }
                   4119: 
                   4120:            /*
                   4121:             * Fourth case : a reference. If if has not been resolved,
                   4122:             *    parsing returns it's Name, create the node
                   4123:             */
                   4124:            else if (CUR == '&') {
                   4125:                htmlParseReference(ctxt);
                   4126:            }
                   4127: 
                   4128:            /*
                   4129:             * Fifth case : end of the resource
                   4130:             */
                   4131:            else if (CUR == 0) {
                   4132:                htmlAutoCloseOnEnd(ctxt);
                   4133:                break;
                   4134:            }
                   4135: 
                   4136:            /*
                   4137:             * Last case, text. Note that References are handled directly.
                   4138:             */
                   4139:            else {
                   4140:                htmlParseCharData(ctxt);
                   4141:            }
                   4142: 
                   4143:            if (cons == ctxt->nbChars) {
                   4144:                if (ctxt->node != NULL) {
                   4145:                    htmlParseErr(ctxt, XML_ERR_INTERNAL_ERROR,
                   4146:                                 "detected an error in element content\n",
                   4147:                                 NULL, NULL);
                   4148:                }
                   4149:                break;
                   4150:            }
                   4151:        }
                   4152:         GROW;
                   4153:     }
                   4154:     if (currentNode != NULL) xmlFree(currentNode);
                   4155: }
                   4156: 
                   4157: /**
                   4158:  * htmlParseElement:
                   4159:  * @ctxt:  an HTML parser context
                   4160:  *
                   4161:  * parse an HTML element, this is highly recursive
                   4162:  * this is kept for compatibility with previous code versions
                   4163:  *
                   4164:  * [39] element ::= EmptyElemTag | STag content ETag
                   4165:  *
                   4166:  * [41] Attribute ::= Name Eq AttValue
                   4167:  */
                   4168: 
                   4169: void
                   4170: htmlParseElement(htmlParserCtxtPtr ctxt) {
                   4171:     const xmlChar *name;
                   4172:     xmlChar *currentNode = NULL;
                   4173:     const htmlElemDesc * info;
                   4174:     htmlParserNodeInfo node_info;
                   4175:     int failed;
                   4176:     int depth;
                   4177:     const xmlChar *oldptr;
                   4178: 
                   4179:     if ((ctxt == NULL) || (ctxt->input == NULL)) {
                   4180:        htmlParseErr(ctxt, XML_ERR_INTERNAL_ERROR,
                   4181:                     "htmlParseElement: context error\n", NULL, NULL);
                   4182:        return;
                   4183:     }
                   4184: 
                   4185:     if (ctxt->instate == XML_PARSER_EOF)
                   4186:         return;
                   4187: 
                   4188:     /* Capture start position */
                   4189:     if (ctxt->record_info) {
                   4190:         node_info.begin_pos = ctxt->input->consumed +
                   4191:                           (CUR_PTR - ctxt->input->base);
                   4192:        node_info.begin_line = ctxt->input->line;
                   4193:     }
                   4194: 
                   4195:     failed = htmlParseStartTag(ctxt);
                   4196:     name = ctxt->name;
                   4197:     if ((failed == -1) || (name == NULL)) {
                   4198:        if (CUR == '>')
                   4199:            NEXT;
                   4200:         return;
                   4201:     }
                   4202: 
                   4203:     /*
                   4204:      * Lookup the info for that element.
                   4205:      */
                   4206:     info = htmlTagLookup(name);
                   4207:     if (info == NULL) {
                   4208:        htmlParseErr(ctxt, XML_HTML_UNKNOWN_TAG,
                   4209:                     "Tag %s invalid\n", name, NULL);
                   4210:     }
                   4211: 
                   4212:     /*
                   4213:      * Check for an Empty Element labeled the XML/SGML way
                   4214:      */
                   4215:     if ((CUR == '/') && (NXT(1) == '>')) {
                   4216:         SKIP(2);
                   4217:        if ((ctxt->sax != NULL) && (ctxt->sax->endElement != NULL))
                   4218:            ctxt->sax->endElement(ctxt->userData, name);
                   4219:        htmlnamePop(ctxt);
                   4220:        return;
                   4221:     }
                   4222: 
                   4223:     if (CUR == '>') {
                   4224:         NEXT;
                   4225:     } else {
                   4226:        htmlParseErr(ctxt, XML_ERR_GT_REQUIRED,
                   4227:                     "Couldn't find end of Start Tag %s\n", name, NULL);
                   4228: 
                   4229:        /*
                   4230:         * end of parsing of this node.
                   4231:         */
                   4232:        if (xmlStrEqual(name, ctxt->name)) {
                   4233:            nodePop(ctxt);
                   4234:            htmlnamePop(ctxt);
                   4235:        }
                   4236: 
                   4237:        /*
                   4238:         * Capture end position and add node
                   4239:         */
                   4240:        if (ctxt->record_info) {
                   4241:           node_info.end_pos = ctxt->input->consumed +
                   4242:                              (CUR_PTR - ctxt->input->base);
                   4243:           node_info.end_line = ctxt->input->line;
                   4244:           node_info.node = ctxt->node;
                   4245:           xmlParserAddNodeInfo(ctxt, &node_info);
                   4246:        }
                   4247:        return;
                   4248:     }
                   4249: 
                   4250:     /*
                   4251:      * Check for an Empty Element from DTD definition
                   4252:      */
                   4253:     if ((info != NULL) && (info->empty)) {
                   4254:        if ((ctxt->sax != NULL) && (ctxt->sax->endElement != NULL))
                   4255:            ctxt->sax->endElement(ctxt->userData, name);
                   4256:        htmlnamePop(ctxt);
                   4257:        return;
                   4258:     }
                   4259: 
                   4260:     /*
                   4261:      * Parse the content of the element:
                   4262:      */
                   4263:     currentNode = xmlStrdup(ctxt->name);
                   4264:     depth = ctxt->nameNr;
                   4265:     while (IS_CHAR_CH(CUR)) {
                   4266:        oldptr = ctxt->input->cur;
                   4267:        htmlParseContent(ctxt);
                   4268:        if (oldptr==ctxt->input->cur) break;
                   4269:        if (ctxt->nameNr < depth) break;
                   4270:     }
                   4271: 
                   4272:     /*
                   4273:      * Capture end position and add node
                   4274:      */
                   4275:     if ( currentNode != NULL && ctxt->record_info ) {
                   4276:        node_info.end_pos = ctxt->input->consumed +
                   4277:                           (CUR_PTR - ctxt->input->base);
                   4278:        node_info.end_line = ctxt->input->line;
                   4279:        node_info.node = ctxt->node;
                   4280:        xmlParserAddNodeInfo(ctxt, &node_info);
                   4281:     }
                   4282:     if (!IS_CHAR_CH(CUR)) {
                   4283:        htmlAutoCloseOnEnd(ctxt);
                   4284:     }
                   4285: 
                   4286:     if (currentNode != NULL)
                   4287:        xmlFree(currentNode);
                   4288: }
                   4289: 
                   4290: static void
                   4291: htmlParserFinishElementParsing(htmlParserCtxtPtr ctxt) {
                   4292:     /*
                   4293:      * Capture end position and add node
                   4294:      */
                   4295:     if ( ctxt->node != NULL && ctxt->record_info ) {
                   4296:        ctxt->nodeInfo->end_pos = ctxt->input->consumed +
                   4297:                                 (CUR_PTR - ctxt->input->base);
                   4298:        ctxt->nodeInfo->end_line = ctxt->input->line;
                   4299:        ctxt->nodeInfo->node = ctxt->node;
                   4300:        xmlParserAddNodeInfo(ctxt, ctxt->nodeInfo);
                   4301:        htmlNodeInfoPop(ctxt);
                   4302:     }
                   4303:     if (!IS_CHAR_CH(CUR)) {
                   4304:        htmlAutoCloseOnEnd(ctxt);
                   4305:     }
                   4306: }
                   4307: 
                   4308: /**
                   4309:  * htmlParseElementInternal:
                   4310:  * @ctxt:  an HTML parser context
                   4311:  *
                   4312:  * parse an HTML element, new version, non recursive
                   4313:  *
                   4314:  * [39] element ::= EmptyElemTag | STag content ETag
                   4315:  *
                   4316:  * [41] Attribute ::= Name Eq AttValue
                   4317:  */
                   4318: 
                   4319: static void
                   4320: htmlParseElementInternal(htmlParserCtxtPtr ctxt) {
                   4321:     const xmlChar *name;
                   4322:     const htmlElemDesc * info;
                   4323:     htmlParserNodeInfo node_info;
                   4324:     int failed;
                   4325: 
                   4326:     if ((ctxt == NULL) || (ctxt->input == NULL)) {
                   4327:        htmlParseErr(ctxt, XML_ERR_INTERNAL_ERROR,
                   4328:                     "htmlParseElementInternal: context error\n", NULL, NULL);
                   4329:        return;
                   4330:     }
                   4331: 
                   4332:     if (ctxt->instate == XML_PARSER_EOF)
                   4333:         return;
                   4334: 
                   4335:     /* Capture start position */
                   4336:     if (ctxt->record_info) {
                   4337:         node_info.begin_pos = ctxt->input->consumed +
                   4338:                           (CUR_PTR - ctxt->input->base);
                   4339:        node_info.begin_line = ctxt->input->line;
                   4340:     }
                   4341: 
                   4342:     failed = htmlParseStartTag(ctxt);
                   4343:     name = ctxt->name;
                   4344:     if ((failed == -1) || (name == NULL)) {
                   4345:        if (CUR == '>')
                   4346:            NEXT;
                   4347:         return;
                   4348:     }
                   4349: 
                   4350:     /*
                   4351:      * Lookup the info for that element.
                   4352:      */
                   4353:     info = htmlTagLookup(name);
                   4354:     if (info == NULL) {
                   4355:        htmlParseErr(ctxt, XML_HTML_UNKNOWN_TAG,
                   4356:                     "Tag %s invalid\n", name, NULL);
                   4357:     }
                   4358: 
                   4359:     /*
                   4360:      * Check for an Empty Element labeled the XML/SGML way
                   4361:      */
                   4362:     if ((CUR == '/') && (NXT(1) == '>')) {
                   4363:         SKIP(2);
                   4364:        if ((ctxt->sax != NULL) && (ctxt->sax->endElement != NULL))
                   4365:            ctxt->sax->endElement(ctxt->userData, name);
                   4366:        htmlnamePop(ctxt);
                   4367:        return;
                   4368:     }
                   4369: 
                   4370:     if (CUR == '>') {
                   4371:         NEXT;
                   4372:     } else {
                   4373:        htmlParseErr(ctxt, XML_ERR_GT_REQUIRED,
                   4374:                     "Couldn't find end of Start Tag %s\n", name, NULL);
                   4375: 
                   4376:        /*
                   4377:         * end of parsing of this node.
                   4378:         */
                   4379:        if (xmlStrEqual(name, ctxt->name)) {
                   4380:            nodePop(ctxt);
                   4381:            htmlnamePop(ctxt);
                   4382:        }
                   4383: 
                   4384:         if (ctxt->record_info)
                   4385:             htmlNodeInfoPush(ctxt, &node_info);
                   4386:         htmlParserFinishElementParsing(ctxt);
                   4387:        return;
                   4388:     }
                   4389: 
                   4390:     /*
                   4391:      * Check for an Empty Element from DTD definition
                   4392:      */
                   4393:     if ((info != NULL) && (info->empty)) {
                   4394:        if ((ctxt->sax != NULL) && (ctxt->sax->endElement != NULL))
                   4395:            ctxt->sax->endElement(ctxt->userData, name);
                   4396:        htmlnamePop(ctxt);
                   4397:        return;
                   4398:     }
                   4399: 
                   4400:     if (ctxt->record_info)
                   4401:         htmlNodeInfoPush(ctxt, &node_info);
                   4402: }
                   4403: 
                   4404: /**
                   4405:  * htmlParseContentInternal:
                   4406:  * @ctxt:  an HTML parser context
                   4407:  *
                   4408:  * Parse a content: comment, sub-element, reference or text.
                   4409:  * New version for non recursive htmlParseElementInternal
                   4410:  */
                   4411: 
                   4412: static void
                   4413: htmlParseContentInternal(htmlParserCtxtPtr ctxt) {
                   4414:     xmlChar *currentNode;
                   4415:     int depth;
                   4416:     const xmlChar *name;
                   4417: 
                   4418:     currentNode = xmlStrdup(ctxt->name);
                   4419:     depth = ctxt->nameNr;
                   4420:     while (1) {
                   4421:        long cons = ctxt->nbChars;
                   4422: 
                   4423:         GROW;
                   4424: 
                   4425:         if (ctxt->instate == XML_PARSER_EOF)
                   4426:             break;
                   4427: 
                   4428:        /*
                   4429:         * Our tag or one of it's parent or children is ending.
                   4430:         */
                   4431:         if ((CUR == '<') && (NXT(1) == '/')) {
                   4432:            if (htmlParseEndTag(ctxt) &&
                   4433:                ((currentNode != NULL) || (ctxt->nameNr == 0))) {
                   4434:                if (currentNode != NULL)
                   4435:                    xmlFree(currentNode);
                   4436: 
                   4437:                currentNode = xmlStrdup(ctxt->name);
                   4438:                depth = ctxt->nameNr;
                   4439:            }
                   4440:            continue; /* while */
                   4441:         }
                   4442: 
                   4443:        else if ((CUR == '<') &&
                   4444:                 ((IS_ASCII_LETTER(NXT(1))) ||
                   4445:                  (NXT(1) == '_') || (NXT(1) == ':'))) {
                   4446:            name = htmlParseHTMLName_nonInvasive(ctxt);
                   4447:            if (name == NULL) {
                   4448:                htmlParseErr(ctxt, XML_ERR_NAME_REQUIRED,
                   4449:                         "htmlParseStartTag: invalid element name\n",
                   4450:                         NULL, NULL);
                   4451:                /* Dump the bogus tag like browsers do */
                   4452:                while ((IS_CHAR_CH(CUR)) && (CUR != '>'))
                   4453:                    NEXT;
                   4454: 
                   4455:                htmlParserFinishElementParsing(ctxt);
                   4456:                if (currentNode != NULL)
                   4457:                    xmlFree(currentNode);
                   4458: 
                   4459:                currentNode = xmlStrdup(ctxt->name);
                   4460:                depth = ctxt->nameNr;
                   4461:                continue;
                   4462:            }
                   4463: 
                   4464:            if (ctxt->name != NULL) {
                   4465:                if (htmlCheckAutoClose(name, ctxt->name) == 1) {
                   4466:                    htmlAutoClose(ctxt, name);
                   4467:                    continue;
                   4468:                }
                   4469:            }
                   4470:        }
                   4471: 
                   4472:        /*
                   4473:         * Has this node been popped out during parsing of
                   4474:         * the next element
                   4475:         */
                   4476:         if ((ctxt->nameNr > 0) && (depth >= ctxt->nameNr) &&
                   4477:            (!xmlStrEqual(currentNode, ctxt->name)))
                   4478:             {
                   4479:            htmlParserFinishElementParsing(ctxt);
                   4480:            if (currentNode != NULL) xmlFree(currentNode);
                   4481: 
                   4482:            currentNode = xmlStrdup(ctxt->name);
                   4483:            depth = ctxt->nameNr;
                   4484:            continue;
                   4485:        }
                   4486: 
                   4487:        if ((CUR != 0) && ((xmlStrEqual(currentNode, BAD_CAST"script")) ||
                   4488:            (xmlStrEqual(currentNode, BAD_CAST"style")))) {
                   4489:            /*
                   4490:             * Handle SCRIPT/STYLE separately
                   4491:             */
                   4492:            htmlParseScript(ctxt);
                   4493:        } else {
                   4494:            /*
                   4495:             * Sometimes DOCTYPE arrives in the middle of the document
                   4496:             */
                   4497:            if ((CUR == '<') && (NXT(1) == '!') &&
                   4498:                (UPP(2) == 'D') && (UPP(3) == 'O') &&
                   4499:                (UPP(4) == 'C') && (UPP(5) == 'T') &&
                   4500:                (UPP(6) == 'Y') && (UPP(7) == 'P') &&
                   4501:                (UPP(8) == 'E')) {
                   4502:                htmlParseErr(ctxt, XML_HTML_STRUCURE_ERROR,
                   4503:                             "Misplaced DOCTYPE declaration\n",
                   4504:                             BAD_CAST "DOCTYPE" , NULL);
                   4505:                htmlParseDocTypeDecl(ctxt);
                   4506:            }
                   4507: 
                   4508:            /*
                   4509:             * First case :  a comment
                   4510:             */
                   4511:            if ((CUR == '<') && (NXT(1) == '!') &&
                   4512:                (NXT(2) == '-') && (NXT(3) == '-')) {
                   4513:                htmlParseComment(ctxt);
                   4514:            }
                   4515: 
                   4516:            /*
                   4517:             * Second case : a Processing Instruction.
                   4518:             */
                   4519:            else if ((CUR == '<') && (NXT(1) == '?')) {
                   4520:                htmlParsePI(ctxt);
                   4521:            }
                   4522: 
                   4523:            /*
                   4524:             * Third case :  a sub-element.
                   4525:             */
                   4526:            else if (CUR == '<') {
                   4527:                htmlParseElementInternal(ctxt);
                   4528:                if (currentNode != NULL) xmlFree(currentNode);
                   4529: 
                   4530:                currentNode = xmlStrdup(ctxt->name);
                   4531:                depth = ctxt->nameNr;
                   4532:            }
                   4533: 
                   4534:            /*
                   4535:             * Fourth case : a reference. If if has not been resolved,
                   4536:             *    parsing returns it's Name, create the node
                   4537:             */
                   4538:            else if (CUR == '&') {
                   4539:                htmlParseReference(ctxt);
                   4540:            }
                   4541: 
                   4542:            /*
                   4543:             * Fifth case : end of the resource
                   4544:             */
                   4545:            else if (CUR == 0) {
                   4546:                htmlAutoCloseOnEnd(ctxt);
                   4547:                break;
                   4548:            }
                   4549: 
                   4550:            /*
                   4551:             * Last case, text. Note that References are handled directly.
                   4552:             */
                   4553:            else {
                   4554:                htmlParseCharData(ctxt);
                   4555:            }
                   4556: 
                   4557:            if (cons == ctxt->nbChars) {
                   4558:                if (ctxt->node != NULL) {
                   4559:                    htmlParseErr(ctxt, XML_ERR_INTERNAL_ERROR,
                   4560:                                 "detected an error in element content\n",
                   4561:                                 NULL, NULL);
                   4562:                }
                   4563:                break;
                   4564:            }
                   4565:        }
                   4566:         GROW;
                   4567:     }
                   4568:     if (currentNode != NULL) xmlFree(currentNode);
                   4569: }
                   4570: 
                   4571: /**
                   4572:  * htmlParseContent:
                   4573:  * @ctxt:  an HTML parser context
                   4574:  *
                   4575:  * Parse a content: comment, sub-element, reference or text.
                   4576:  * This is the entry point when called from parser.c
                   4577:  */
                   4578: 
                   4579: void
                   4580: __htmlParseContent(void *ctxt) {
                   4581:     if (ctxt != NULL)
                   4582:        htmlParseContentInternal((htmlParserCtxtPtr) ctxt);
                   4583: }
                   4584: 
                   4585: /**
                   4586:  * htmlParseDocument:
                   4587:  * @ctxt:  an HTML parser context
                   4588:  *
                   4589:  * parse an HTML document (and build a tree if using the standard SAX
                   4590:  * interface).
                   4591:  *
                   4592:  * Returns 0, -1 in case of error. the parser context is augmented
                   4593:  *                as a result of the parsing.
                   4594:  */
                   4595: 
                   4596: int
                   4597: htmlParseDocument(htmlParserCtxtPtr ctxt) {
                   4598:     xmlChar start[4];
                   4599:     xmlCharEncoding enc;
                   4600:     xmlDtdPtr dtd;
                   4601: 
                   4602:     xmlInitParser();
                   4603: 
                   4604:     htmlDefaultSAXHandlerInit();
                   4605: 
                   4606:     if ((ctxt == NULL) || (ctxt->input == NULL)) {
                   4607:        htmlParseErr(ctxt, XML_ERR_INTERNAL_ERROR,
                   4608:                     "htmlParseDocument: context error\n", NULL, NULL);
                   4609:        return(XML_ERR_INTERNAL_ERROR);
                   4610:     }
                   4611:     ctxt->html = 1;
                   4612:     ctxt->linenumbers = 1;
                   4613:     GROW;
                   4614:     /*
                   4615:      * SAX: beginning of the document processing.
                   4616:      */
                   4617:     if ((ctxt->sax) && (ctxt->sax->setDocumentLocator))
                   4618:         ctxt->sax->setDocumentLocator(ctxt->userData, &xmlDefaultSAXLocator);
                   4619: 
                   4620:     if ((ctxt->encoding == (const xmlChar *)XML_CHAR_ENCODING_NONE) &&
                   4621:         ((ctxt->input->end - ctxt->input->cur) >= 4)) {
                   4622:        /*
                   4623:         * Get the 4 first bytes and decode the charset
                   4624:         * if enc != XML_CHAR_ENCODING_NONE
                   4625:         * plug some encoding conversion routines.
                   4626:         */
                   4627:        start[0] = RAW;
                   4628:        start[1] = NXT(1);
                   4629:        start[2] = NXT(2);
                   4630:        start[3] = NXT(3);
                   4631:        enc = xmlDetectCharEncoding(&start[0], 4);
                   4632:        if (enc != XML_CHAR_ENCODING_NONE) {
                   4633:            xmlSwitchEncoding(ctxt, enc);
                   4634:        }
                   4635:     }
                   4636: 
                   4637:     /*
                   4638:      * Wipe out everything which is before the first '<'
                   4639:      */
                   4640:     SKIP_BLANKS;
                   4641:     if (CUR == 0) {
                   4642:        htmlParseErr(ctxt, XML_ERR_DOCUMENT_EMPTY,
                   4643:                     "Document is empty\n", NULL, NULL);
                   4644:     }
                   4645: 
                   4646:     if ((ctxt->sax) && (ctxt->sax->startDocument) && (!ctxt->disableSAX))
                   4647:        ctxt->sax->startDocument(ctxt->userData);
                   4648: 
                   4649: 
                   4650:     /*
                   4651:      * Parse possible comments and PIs before any content
                   4652:      */
                   4653:     while (((CUR == '<') && (NXT(1) == '!') &&
                   4654:             (NXT(2) == '-') && (NXT(3) == '-')) ||
                   4655:           ((CUR == '<') && (NXT(1) == '?'))) {
                   4656:         htmlParseComment(ctxt);
                   4657:         htmlParsePI(ctxt);
                   4658:        SKIP_BLANKS;
                   4659:     }
                   4660: 
                   4661: 
                   4662:     /*
                   4663:      * Then possibly doc type declaration(s) and more Misc
                   4664:      * (doctypedecl Misc*)?
                   4665:      */
                   4666:     if ((CUR == '<') && (NXT(1) == '!') &&
                   4667:        (UPP(2) == 'D') && (UPP(3) == 'O') &&
                   4668:        (UPP(4) == 'C') && (UPP(5) == 'T') &&
                   4669:        (UPP(6) == 'Y') && (UPP(7) == 'P') &&
                   4670:        (UPP(8) == 'E')) {
                   4671:        htmlParseDocTypeDecl(ctxt);
                   4672:     }
                   4673:     SKIP_BLANKS;
                   4674: 
                   4675:     /*
                   4676:      * Parse possible comments and PIs before any content
                   4677:      */
                   4678:     while (((CUR == '<') && (NXT(1) == '!') &&
                   4679:             (NXT(2) == '-') && (NXT(3) == '-')) ||
                   4680:           ((CUR == '<') && (NXT(1) == '?'))) {
                   4681:         htmlParseComment(ctxt);
                   4682:         htmlParsePI(ctxt);
                   4683:        SKIP_BLANKS;
                   4684:     }
                   4685: 
                   4686:     /*
                   4687:      * Time to start parsing the tree itself
                   4688:      */
                   4689:     htmlParseContentInternal(ctxt);
                   4690: 
                   4691:     /*
                   4692:      * autoclose
                   4693:      */
                   4694:     if (CUR == 0)
                   4695:        htmlAutoCloseOnEnd(ctxt);
                   4696: 
                   4697: 
                   4698:     /*
                   4699:      * SAX: end of the document processing.
                   4700:      */
                   4701:     if ((ctxt->sax) && (ctxt->sax->endDocument != NULL))
                   4702:         ctxt->sax->endDocument(ctxt->userData);
                   4703: 
                   4704:     if ((!(ctxt->options & HTML_PARSE_NODEFDTD)) && (ctxt->myDoc != NULL)) {
                   4705:        dtd = xmlGetIntSubset(ctxt->myDoc);
                   4706:        if (dtd == NULL)
                   4707:            ctxt->myDoc->intSubset =
                   4708:                xmlCreateIntSubset(ctxt->myDoc, BAD_CAST "html",
                   4709:                    BAD_CAST "-//W3C//DTD HTML 4.0 Transitional//EN",
                   4710:                    BAD_CAST "http://www.w3.org/TR/REC-html40/loose.dtd");
                   4711:     }
                   4712:     if (! ctxt->wellFormed) return(-1);
                   4713:     return(0);
                   4714: }
                   4715: 
                   4716: 
                   4717: /************************************************************************
                   4718:  *                                                                     *
                   4719:  *                     Parser contexts handling                        *
                   4720:  *                                                                     *
                   4721:  ************************************************************************/
                   4722: 
                   4723: /**
                   4724:  * htmlInitParserCtxt:
                   4725:  * @ctxt:  an HTML parser context
                   4726:  *
                   4727:  * Initialize a parser context
                   4728:  *
                   4729:  * Returns 0 in case of success and -1 in case of error
                   4730:  */
                   4731: 
                   4732: static int
                   4733: htmlInitParserCtxt(htmlParserCtxtPtr ctxt)
                   4734: {
                   4735:     htmlSAXHandler *sax;
                   4736: 
                   4737:     if (ctxt == NULL) return(-1);
                   4738:     memset(ctxt, 0, sizeof(htmlParserCtxt));
                   4739: 
                   4740:     ctxt->dict = xmlDictCreate();
                   4741:     if (ctxt->dict == NULL) {
                   4742:         htmlErrMemory(NULL, "htmlInitParserCtxt: out of memory\n");
                   4743:        return(-1);
                   4744:     }
                   4745:     sax = (htmlSAXHandler *) xmlMalloc(sizeof(htmlSAXHandler));
                   4746:     if (sax == NULL) {
                   4747:         htmlErrMemory(NULL, "htmlInitParserCtxt: out of memory\n");
                   4748:        return(-1);
                   4749:     }
                   4750:     else
                   4751:         memset(sax, 0, sizeof(htmlSAXHandler));
                   4752: 
                   4753:     /* Allocate the Input stack */
                   4754:     ctxt->inputTab = (htmlParserInputPtr *)
                   4755:                       xmlMalloc(5 * sizeof(htmlParserInputPtr));
                   4756:     if (ctxt->inputTab == NULL) {
                   4757:         htmlErrMemory(NULL, "htmlInitParserCtxt: out of memory\n");
                   4758:        ctxt->inputNr = 0;
                   4759:        ctxt->inputMax = 0;
                   4760:        ctxt->input = NULL;
                   4761:        return(-1);
                   4762:     }
                   4763:     ctxt->inputNr = 0;
                   4764:     ctxt->inputMax = 5;
                   4765:     ctxt->input = NULL;
                   4766:     ctxt->version = NULL;
                   4767:     ctxt->encoding = NULL;
                   4768:     ctxt->standalone = -1;
                   4769:     ctxt->instate = XML_PARSER_START;
                   4770: 
                   4771:     /* Allocate the Node stack */
                   4772:     ctxt->nodeTab = (htmlNodePtr *) xmlMalloc(10 * sizeof(htmlNodePtr));
                   4773:     if (ctxt->nodeTab == NULL) {
                   4774:         htmlErrMemory(NULL, "htmlInitParserCtxt: out of memory\n");
                   4775:        ctxt->nodeNr = 0;
                   4776:        ctxt->nodeMax = 0;
                   4777:        ctxt->node = NULL;
                   4778:        ctxt->inputNr = 0;
                   4779:        ctxt->inputMax = 0;
                   4780:        ctxt->input = NULL;
                   4781:        return(-1);
                   4782:     }
                   4783:     ctxt->nodeNr = 0;
                   4784:     ctxt->nodeMax = 10;
                   4785:     ctxt->node = NULL;
                   4786: 
                   4787:     /* Allocate the Name stack */
                   4788:     ctxt->nameTab = (const xmlChar **) xmlMalloc(10 * sizeof(xmlChar *));
                   4789:     if (ctxt->nameTab == NULL) {
                   4790:         htmlErrMemory(NULL, "htmlInitParserCtxt: out of memory\n");
                   4791:        ctxt->nameNr = 0;
                   4792:        ctxt->nameMax = 0;
                   4793:        ctxt->name = NULL;
                   4794:        ctxt->nodeNr = 0;
                   4795:        ctxt->nodeMax = 0;
                   4796:        ctxt->node = NULL;
                   4797:        ctxt->inputNr = 0;
                   4798:        ctxt->inputMax = 0;
                   4799:        ctxt->input = NULL;
                   4800:        return(-1);
                   4801:     }
                   4802:     ctxt->nameNr = 0;
                   4803:     ctxt->nameMax = 10;
                   4804:     ctxt->name = NULL;
                   4805: 
                   4806:     ctxt->nodeInfoTab = NULL;
                   4807:     ctxt->nodeInfoNr  = 0;
                   4808:     ctxt->nodeInfoMax = 0;
                   4809: 
                   4810:     if (sax == NULL) ctxt->sax = (xmlSAXHandlerPtr) &htmlDefaultSAXHandler;
                   4811:     else {
                   4812:         ctxt->sax = sax;
                   4813:        memcpy(sax, &htmlDefaultSAXHandler, sizeof(xmlSAXHandlerV1));
                   4814:     }
                   4815:     ctxt->userData = ctxt;
                   4816:     ctxt->myDoc = NULL;
                   4817:     ctxt->wellFormed = 1;
                   4818:     ctxt->replaceEntities = 0;
                   4819:     ctxt->linenumbers = xmlLineNumbersDefaultValue;
                   4820:     ctxt->html = 1;
                   4821:     ctxt->vctxt.finishDtd = XML_CTXT_FINISH_DTD_0;
                   4822:     ctxt->vctxt.userData = ctxt;
                   4823:     ctxt->vctxt.error = xmlParserValidityError;
                   4824:     ctxt->vctxt.warning = xmlParserValidityWarning;
                   4825:     ctxt->record_info = 0;
                   4826:     ctxt->validate = 0;
                   4827:     ctxt->nbChars = 0;
                   4828:     ctxt->checkIndex = 0;
                   4829:     ctxt->catalogs = NULL;
                   4830:     xmlInitNodeInfoSeq(&ctxt->node_seq);
                   4831:     return(0);
                   4832: }
                   4833: 
                   4834: /**
                   4835:  * htmlFreeParserCtxt:
                   4836:  * @ctxt:  an HTML parser context
                   4837:  *
                   4838:  * Free all the memory used by a parser context. However the parsed
                   4839:  * document in ctxt->myDoc is not freed.
                   4840:  */
                   4841: 
                   4842: void
                   4843: htmlFreeParserCtxt(htmlParserCtxtPtr ctxt)
                   4844: {
                   4845:     xmlFreeParserCtxt(ctxt);
                   4846: }
                   4847: 
                   4848: /**
                   4849:  * htmlNewParserCtxt:
                   4850:  *
                   4851:  * Allocate and initialize a new parser context.
                   4852:  *
                   4853:  * Returns the htmlParserCtxtPtr or NULL in case of allocation error
                   4854:  */
                   4855: 
                   4856: htmlParserCtxtPtr
                   4857: htmlNewParserCtxt(void)
                   4858: {
                   4859:     xmlParserCtxtPtr ctxt;
                   4860: 
                   4861:     ctxt = (xmlParserCtxtPtr) xmlMalloc(sizeof(xmlParserCtxt));
                   4862:     if (ctxt == NULL) {
                   4863:         htmlErrMemory(NULL, "NewParserCtxt: out of memory\n");
                   4864:        return(NULL);
                   4865:     }
                   4866:     memset(ctxt, 0, sizeof(xmlParserCtxt));
                   4867:     if (htmlInitParserCtxt(ctxt) < 0) {
                   4868:         htmlFreeParserCtxt(ctxt);
                   4869:        return(NULL);
                   4870:     }
                   4871:     return(ctxt);
                   4872: }
                   4873: 
                   4874: /**
                   4875:  * htmlCreateMemoryParserCtxt:
                   4876:  * @buffer:  a pointer to a char array
                   4877:  * @size:  the size of the array
                   4878:  *
                   4879:  * Create a parser context for an HTML in-memory document.
                   4880:  *
                   4881:  * Returns the new parser context or NULL
                   4882:  */
                   4883: htmlParserCtxtPtr
                   4884: htmlCreateMemoryParserCtxt(const char *buffer, int size) {
                   4885:     xmlParserCtxtPtr ctxt;
                   4886:     xmlParserInputPtr input;
                   4887:     xmlParserInputBufferPtr buf;
                   4888: 
                   4889:     if (buffer == NULL)
                   4890:        return(NULL);
                   4891:     if (size <= 0)
                   4892:        return(NULL);
                   4893: 
                   4894:     ctxt = htmlNewParserCtxt();
                   4895:     if (ctxt == NULL)
                   4896:        return(NULL);
                   4897: 
                   4898:     buf = xmlParserInputBufferCreateMem(buffer, size, XML_CHAR_ENCODING_NONE);
                   4899:     if (buf == NULL) return(NULL);
                   4900: 
                   4901:     input = xmlNewInputStream(ctxt);
                   4902:     if (input == NULL) {
                   4903:        xmlFreeParserCtxt(ctxt);
                   4904:        return(NULL);
                   4905:     }
                   4906: 
                   4907:     input->filename = NULL;
                   4908:     input->buf = buf;
                   4909:     input->base = input->buf->buffer->content;
                   4910:     input->cur = input->buf->buffer->content;
                   4911:     input->end = &input->buf->buffer->content[input->buf->buffer->use];
                   4912: 
                   4913:     inputPush(ctxt, input);
                   4914:     return(ctxt);
                   4915: }
                   4916: 
                   4917: /**
                   4918:  * htmlCreateDocParserCtxt:
                   4919:  * @cur:  a pointer to an array of xmlChar
                   4920:  * @encoding:  a free form C string describing the HTML document encoding, or NULL
                   4921:  *
                   4922:  * Create a parser context for an HTML document.
                   4923:  *
                   4924:  * TODO: check the need to add encoding handling there
                   4925:  *
                   4926:  * Returns the new parser context or NULL
                   4927:  */
                   4928: static htmlParserCtxtPtr
                   4929: htmlCreateDocParserCtxt(const xmlChar *cur, const char *encoding) {
                   4930:     int len;
                   4931:     htmlParserCtxtPtr ctxt;
                   4932: 
                   4933:     if (cur == NULL)
                   4934:        return(NULL);
                   4935:     len = xmlStrlen(cur);
                   4936:     ctxt = htmlCreateMemoryParserCtxt((char *)cur, len);
                   4937:     if (ctxt == NULL)
                   4938:        return(NULL);
                   4939: 
                   4940:     if (encoding != NULL) {
                   4941:        xmlCharEncoding enc;
                   4942:        xmlCharEncodingHandlerPtr handler;
                   4943: 
                   4944:        if (ctxt->input->encoding != NULL)
                   4945:            xmlFree((xmlChar *) ctxt->input->encoding);
                   4946:        ctxt->input->encoding = xmlStrdup((const xmlChar *) encoding);
                   4947: 
                   4948:        enc = xmlParseCharEncoding(encoding);
                   4949:        /*
                   4950:         * registered set of known encodings
                   4951:         */
                   4952:        if (enc != XML_CHAR_ENCODING_ERROR) {
                   4953:            xmlSwitchEncoding(ctxt, enc);
                   4954:            if (ctxt->errNo == XML_ERR_UNSUPPORTED_ENCODING) {
                   4955:                htmlParseErr(ctxt, XML_ERR_UNSUPPORTED_ENCODING,
                   4956:                             "Unsupported encoding %s\n",
                   4957:                             (const xmlChar *) encoding, NULL);
                   4958:            }
                   4959:        } else {
                   4960:            /*
                   4961:             * fallback for unknown encodings
                   4962:             */
                   4963:            handler = xmlFindCharEncodingHandler((const char *) encoding);
                   4964:            if (handler != NULL) {
                   4965:                xmlSwitchToEncoding(ctxt, handler);
                   4966:            } else {
                   4967:                htmlParseErr(ctxt, XML_ERR_UNSUPPORTED_ENCODING,
                   4968:                             "Unsupported encoding %s\n",
                   4969:                             (const xmlChar *) encoding, NULL);
                   4970:            }
                   4971:        }
                   4972:     }
                   4973:     return(ctxt);
                   4974: }
                   4975: 
                   4976: #ifdef LIBXML_PUSH_ENABLED
                   4977: /************************************************************************
                   4978:  *                                                                     *
                   4979:  *     Progressive parsing interfaces                          *
                   4980:  *                                                                     *
                   4981:  ************************************************************************/
                   4982: 
                   4983: /**
                   4984:  * htmlParseLookupSequence:
                   4985:  * @ctxt:  an HTML parser context
                   4986:  * @first:  the first char to lookup
                   4987:  * @next:  the next char to lookup or zero
                   4988:  * @third:  the next char to lookup or zero
                   4989:  * @comment: flag to force checking inside comments
                   4990:  *
                   4991:  * Try to find if a sequence (first, next, third) or  just (first next) or
                   4992:  * (first) is available in the input stream.
                   4993:  * This function has a side effect of (possibly) incrementing ctxt->checkIndex
                   4994:  * to avoid rescanning sequences of bytes, it DOES change the state of the
                   4995:  * parser, do not use liberally.
                   4996:  * This is basically similar to xmlParseLookupSequence()
                   4997:  *
                   4998:  * Returns the index to the current parsing point if the full sequence
                   4999:  *      is available, -1 otherwise.
                   5000:  */
                   5001: static int
                   5002: htmlParseLookupSequence(htmlParserCtxtPtr ctxt, xmlChar first,
                   5003:                         xmlChar next, xmlChar third, int iscomment,
                   5004:                         int ignoreattrval)
                   5005: {
                   5006:     int base, len;
                   5007:     htmlParserInputPtr in;
                   5008:     const xmlChar *buf;
                   5009:     int incomment = 0;
                   5010:     int invalue = 0;
                   5011:     char valdellim = 0x0;
                   5012: 
                   5013:     in = ctxt->input;
                   5014:     if (in == NULL)
                   5015:         return (-1);
                   5016: 
                   5017:     base = in->cur - in->base;
                   5018:     if (base < 0)
                   5019:         return (-1);
                   5020: 
                   5021:     if (ctxt->checkIndex > base)
                   5022:         base = ctxt->checkIndex;
                   5023: 
                   5024:     if (in->buf == NULL) {
                   5025:         buf = in->base;
                   5026:         len = in->length;
                   5027:     } else {
                   5028:         buf = in->buf->buffer->content;
                   5029:         len = in->buf->buffer->use;
                   5030:     }
                   5031: 
                   5032:     /* take into account the sequence length */
                   5033:     if (third)
                   5034:         len -= 2;
                   5035:     else if (next)
                   5036:         len--;
                   5037:     for (; base < len; base++) {
                   5038:         if ((!incomment) && (base + 4 < len) && (!iscomment)) {
                   5039:             if ((buf[base] == '<') && (buf[base + 1] == '!') &&
                   5040:                 (buf[base + 2] == '-') && (buf[base + 3] == '-')) {
                   5041:                 incomment = 1;
                   5042:                 /* do not increment past <! - some people use <!--> */
                   5043:                 base += 2;
                   5044:             }
                   5045:         }
                   5046:         if (ignoreattrval) {
                   5047:             if (buf[base] == '"' || buf[base] == '\'') {
                   5048:                 if (invalue) {
                   5049:                     if (buf[base] == valdellim) {
                   5050:                         invalue = 0;
                   5051:                         continue;
                   5052:                     }
                   5053:                 } else {
                   5054:                     valdellim = buf[base];
                   5055:                     invalue = 1;
                   5056:                     continue;
                   5057:                 }
                   5058:             } else if (invalue) {
                   5059:                 continue;
                   5060:             }
                   5061:         }
                   5062:         if (incomment) {
                   5063:             if (base + 3 > len)
                   5064:                 return (-1);
                   5065:             if ((buf[base] == '-') && (buf[base + 1] == '-') &&
                   5066:                 (buf[base + 2] == '>')) {
                   5067:                 incomment = 0;
                   5068:                 base += 2;
                   5069:             }
                   5070:             continue;
                   5071:         }
                   5072:         if (buf[base] == first) {
                   5073:             if (third != 0) {
                   5074:                 if ((buf[base + 1] != next) || (buf[base + 2] != third))
                   5075:                     continue;
                   5076:             } else if (next != 0) {
                   5077:                 if (buf[base + 1] != next)
                   5078:                     continue;
                   5079:             }
                   5080:             ctxt->checkIndex = 0;
                   5081: #ifdef DEBUG_PUSH
                   5082:             if (next == 0)
                   5083:                 xmlGenericError(xmlGenericErrorContext,
                   5084:                                 "HPP: lookup '%c' found at %d\n",
                   5085:                                 first, base);
                   5086:             else if (third == 0)
                   5087:                 xmlGenericError(xmlGenericErrorContext,
                   5088:                                 "HPP: lookup '%c%c' found at %d\n",
                   5089:                                 first, next, base);
                   5090:             else
                   5091:                 xmlGenericError(xmlGenericErrorContext,
                   5092:                                 "HPP: lookup '%c%c%c' found at %d\n",
                   5093:                                 first, next, third, base);
                   5094: #endif
                   5095:             return (base - (in->cur - in->base));
                   5096:         }
                   5097:     }
                   5098:     if ((!incomment) && (!invalue))
                   5099:         ctxt->checkIndex = base;
                   5100: #ifdef DEBUG_PUSH
                   5101:     if (next == 0)
                   5102:         xmlGenericError(xmlGenericErrorContext,
                   5103:                         "HPP: lookup '%c' failed\n", first);
                   5104:     else if (third == 0)
                   5105:         xmlGenericError(xmlGenericErrorContext,
                   5106:                         "HPP: lookup '%c%c' failed\n", first, next);
                   5107:     else
                   5108:         xmlGenericError(xmlGenericErrorContext,
                   5109:                         "HPP: lookup '%c%c%c' failed\n", first, next,
                   5110:                         third);
                   5111: #endif
                   5112:     return (-1);
                   5113: }
                   5114: 
                   5115: /**
                   5116:  * htmlParseLookupChars:
                   5117:  * @ctxt: an HTML parser context
                   5118:  * @stop: Array of chars, which stop the lookup.
                   5119:  * @stopLen: Length of stop-Array
                   5120:  *
                   5121:  * Try to find if any char of the stop-Array is available in the input 
                   5122:  * stream.
                   5123:  * This function has a side effect of (possibly) incrementing ctxt->checkIndex
                   5124:  * to avoid rescanning sequences of bytes, it DOES change the state of the
                   5125:  * parser, do not use liberally.
                   5126:  *
                   5127:  * Returns the index to the current parsing point if a stopChar 
                   5128:  *      is available, -1 otherwise.
                   5129:  */
                   5130: static int
                   5131: htmlParseLookupChars(htmlParserCtxtPtr ctxt, const xmlChar * stop,
                   5132:                      int stopLen)
                   5133: {
                   5134:     int base, len;
                   5135:     htmlParserInputPtr in;
                   5136:     const xmlChar *buf;
                   5137:     int incomment = 0;
                   5138:     int i;
                   5139: 
                   5140:     in = ctxt->input;
                   5141:     if (in == NULL)
                   5142:         return (-1);
                   5143: 
                   5144:     base = in->cur - in->base;
                   5145:     if (base < 0)
                   5146:         return (-1);
                   5147: 
                   5148:     if (ctxt->checkIndex > base)
                   5149:         base = ctxt->checkIndex;
                   5150: 
                   5151:     if (in->buf == NULL) {
                   5152:         buf = in->base;
                   5153:         len = in->length;
                   5154:     } else {
                   5155:         buf = in->buf->buffer->content;
                   5156:         len = in->buf->buffer->use;
                   5157:     }
                   5158: 
                   5159:     for (; base < len; base++) {
                   5160:         if (!incomment && (base + 4 < len)) {
                   5161:             if ((buf[base] == '<') && (buf[base + 1] == '!') &&
                   5162:                 (buf[base + 2] == '-') && (buf[base + 3] == '-')) {
                   5163:                 incomment = 1;
                   5164:                 /* do not increment past <! - some people use <!--> */
                   5165:                 base += 2;
                   5166:             }
                   5167:         }
                   5168:         if (incomment) {
                   5169:             if (base + 3 > len)
                   5170:                 return (-1);
                   5171:             if ((buf[base] == '-') && (buf[base + 1] == '-') &&
                   5172:                 (buf[base + 2] == '>')) {
                   5173:                 incomment = 0;
                   5174:                 base += 2;
                   5175:             }
                   5176:             continue;
                   5177:         }
                   5178:         for (i = 0; i < stopLen; ++i) {
                   5179:             if (buf[base] == stop[i]) {
                   5180:                 ctxt->checkIndex = 0;
                   5181:                 return (base - (in->cur - in->base));
                   5182:             }
                   5183:         }
                   5184:     }
                   5185:     ctxt->checkIndex = base;
                   5186:     return (-1);
                   5187: }
                   5188: 
                   5189: /**
                   5190:  * htmlParseTryOrFinish:
                   5191:  * @ctxt:  an HTML parser context
                   5192:  * @terminate:  last chunk indicator
                   5193:  *
                   5194:  * Try to progress on parsing
                   5195:  *
                   5196:  * Returns zero if no parsing was possible
                   5197:  */
                   5198: static int
                   5199: htmlParseTryOrFinish(htmlParserCtxtPtr ctxt, int terminate) {
                   5200:     int ret = 0;
                   5201:     htmlParserInputPtr in;
                   5202:     int avail = 0;
                   5203:     xmlChar cur, next;
                   5204: 
1.1.1.2 ! misho    5205:     htmlParserNodeInfo node_info;
        !          5206: 
1.1       misho    5207: #ifdef DEBUG_PUSH
                   5208:     switch (ctxt->instate) {
                   5209:        case XML_PARSER_EOF:
                   5210:            xmlGenericError(xmlGenericErrorContext,
                   5211:                    "HPP: try EOF\n"); break;
                   5212:        case XML_PARSER_START:
                   5213:            xmlGenericError(xmlGenericErrorContext,
                   5214:                    "HPP: try START\n"); break;
                   5215:        case XML_PARSER_MISC:
                   5216:            xmlGenericError(xmlGenericErrorContext,
                   5217:                    "HPP: try MISC\n");break;
                   5218:        case XML_PARSER_COMMENT:
                   5219:            xmlGenericError(xmlGenericErrorContext,
                   5220:                    "HPP: try COMMENT\n");break;
                   5221:        case XML_PARSER_PROLOG:
                   5222:            xmlGenericError(xmlGenericErrorContext,
                   5223:                    "HPP: try PROLOG\n");break;
                   5224:        case XML_PARSER_START_TAG:
                   5225:            xmlGenericError(xmlGenericErrorContext,
                   5226:                    "HPP: try START_TAG\n");break;
                   5227:        case XML_PARSER_CONTENT:
                   5228:            xmlGenericError(xmlGenericErrorContext,
                   5229:                    "HPP: try CONTENT\n");break;
                   5230:        case XML_PARSER_CDATA_SECTION:
                   5231:            xmlGenericError(xmlGenericErrorContext,
                   5232:                    "HPP: try CDATA_SECTION\n");break;
                   5233:        case XML_PARSER_END_TAG:
                   5234:            xmlGenericError(xmlGenericErrorContext,
                   5235:                    "HPP: try END_TAG\n");break;
                   5236:        case XML_PARSER_ENTITY_DECL:
                   5237:            xmlGenericError(xmlGenericErrorContext,
                   5238:                    "HPP: try ENTITY_DECL\n");break;
                   5239:        case XML_PARSER_ENTITY_VALUE:
                   5240:            xmlGenericError(xmlGenericErrorContext,
                   5241:                    "HPP: try ENTITY_VALUE\n");break;
                   5242:        case XML_PARSER_ATTRIBUTE_VALUE:
                   5243:            xmlGenericError(xmlGenericErrorContext,
                   5244:                    "HPP: try ATTRIBUTE_VALUE\n");break;
                   5245:        case XML_PARSER_DTD:
                   5246:            xmlGenericError(xmlGenericErrorContext,
                   5247:                    "HPP: try DTD\n");break;
                   5248:        case XML_PARSER_EPILOG:
                   5249:            xmlGenericError(xmlGenericErrorContext,
                   5250:                    "HPP: try EPILOG\n");break;
                   5251:        case XML_PARSER_PI:
                   5252:            xmlGenericError(xmlGenericErrorContext,
                   5253:                    "HPP: try PI\n");break;
                   5254:        case XML_PARSER_SYSTEM_LITERAL:
                   5255:            xmlGenericError(xmlGenericErrorContext,
                   5256:                    "HPP: try SYSTEM_LITERAL\n");break;
                   5257:     }
                   5258: #endif
                   5259: 
                   5260:     while (1) {
                   5261: 
                   5262:        in = ctxt->input;
                   5263:        if (in == NULL) break;
                   5264:        if (in->buf == NULL)
                   5265:            avail = in->length - (in->cur - in->base);
                   5266:        else
                   5267:            avail = in->buf->buffer->use - (in->cur - in->base);
                   5268:        if ((avail == 0) && (terminate)) {
                   5269:            htmlAutoCloseOnEnd(ctxt);
                   5270:            if ((ctxt->nameNr == 0) && (ctxt->instate != XML_PARSER_EOF)) {
                   5271:                /*
                   5272:                 * SAX: end of the document processing.
                   5273:                 */
                   5274:                ctxt->instate = XML_PARSER_EOF;
                   5275:                if ((ctxt->sax) && (ctxt->sax->endDocument != NULL))
                   5276:                    ctxt->sax->endDocument(ctxt->userData);
                   5277:            }
                   5278:        }
                   5279:         if (avail < 1)
                   5280:            goto done;
                   5281:        cur = in->cur[0];
                   5282:        if (cur == 0) {
                   5283:            SKIP(1);
                   5284:            continue;
                   5285:        }
                   5286: 
                   5287:         switch (ctxt->instate) {
                   5288:             case XML_PARSER_EOF:
                   5289:                /*
                   5290:                 * Document parsing is done !
                   5291:                 */
                   5292:                goto done;
                   5293:             case XML_PARSER_START:
                   5294:                /*
                   5295:                 * Very first chars read from the document flow.
                   5296:                 */
                   5297:                cur = in->cur[0];
                   5298:                if (IS_BLANK_CH(cur)) {
                   5299:                    SKIP_BLANKS;
                   5300:                    if (in->buf == NULL)
                   5301:                        avail = in->length - (in->cur - in->base);
                   5302:                    else
                   5303:                        avail = in->buf->buffer->use - (in->cur - in->base);
                   5304:                }
                   5305:                if ((ctxt->sax) && (ctxt->sax->setDocumentLocator))
                   5306:                    ctxt->sax->setDocumentLocator(ctxt->userData,
                   5307:                                                  &xmlDefaultSAXLocator);
                   5308:                if ((ctxt->sax) && (ctxt->sax->startDocument) &&
                   5309:                    (!ctxt->disableSAX))
                   5310:                    ctxt->sax->startDocument(ctxt->userData);
                   5311: 
                   5312:                cur = in->cur[0];
                   5313:                next = in->cur[1];
                   5314:                if ((cur == '<') && (next == '!') &&
                   5315:                    (UPP(2) == 'D') && (UPP(3) == 'O') &&
                   5316:                    (UPP(4) == 'C') && (UPP(5) == 'T') &&
                   5317:                    (UPP(6) == 'Y') && (UPP(7) == 'P') &&
                   5318:                    (UPP(8) == 'E')) {
                   5319:                    if ((!terminate) &&
                   5320:                        (htmlParseLookupSequence(ctxt, '>', 0, 0, 0, 1) < 0))
                   5321:                        goto done;
                   5322: #ifdef DEBUG_PUSH
                   5323:                    xmlGenericError(xmlGenericErrorContext,
                   5324:                            "HPP: Parsing internal subset\n");
                   5325: #endif
                   5326:                    htmlParseDocTypeDecl(ctxt);
                   5327:                    ctxt->instate = XML_PARSER_PROLOG;
                   5328: #ifdef DEBUG_PUSH
                   5329:                    xmlGenericError(xmlGenericErrorContext,
                   5330:                            "HPP: entering PROLOG\n");
                   5331: #endif
                   5332:                 } else {
                   5333:                    ctxt->instate = XML_PARSER_MISC;
                   5334: #ifdef DEBUG_PUSH
                   5335:                    xmlGenericError(xmlGenericErrorContext,
                   5336:                            "HPP: entering MISC\n");
                   5337: #endif
                   5338:                }
                   5339:                break;
                   5340:             case XML_PARSER_MISC:
                   5341:                SKIP_BLANKS;
                   5342:                if (in->buf == NULL)
                   5343:                    avail = in->length - (in->cur - in->base);
                   5344:                else
                   5345:                    avail = in->buf->buffer->use - (in->cur - in->base);
1.1.1.2 ! misho    5346:                /*
        !          5347:                 * no chars in buffer
        !          5348:                 */
        !          5349:                if (avail < 1)
1.1       misho    5350:                    goto done;
1.1.1.2 ! misho    5351:                /*
        !          5352:                 * not enouth chars in buffer
        !          5353:                 */
        !          5354:                if (avail < 2) {
        !          5355:                    if (!terminate)
        !          5356:                        goto done;
        !          5357:                    else
        !          5358:                        next = ' ';
        !          5359:                } else {
        !          5360:                    next = in->cur[1];
        !          5361:                }
1.1       misho    5362:                cur = in->cur[0];
                   5363:                if ((cur == '<') && (next == '!') &&
                   5364:                    (in->cur[2] == '-') && (in->cur[3] == '-')) {
                   5365:                    if ((!terminate) &&
                   5366:                        (htmlParseLookupSequence(ctxt, '-', '-', '>', 1, 1) < 0))
                   5367:                        goto done;
                   5368: #ifdef DEBUG_PUSH
                   5369:                    xmlGenericError(xmlGenericErrorContext,
                   5370:                            "HPP: Parsing Comment\n");
                   5371: #endif
                   5372:                    htmlParseComment(ctxt);
                   5373:                    ctxt->instate = XML_PARSER_MISC;
                   5374:                } else if ((cur == '<') && (next == '?')) {
                   5375:                    if ((!terminate) &&
                   5376:                        (htmlParseLookupSequence(ctxt, '>', 0, 0, 0, 1) < 0))
                   5377:                        goto done;
                   5378: #ifdef DEBUG_PUSH
                   5379:                    xmlGenericError(xmlGenericErrorContext,
                   5380:                            "HPP: Parsing PI\n");
                   5381: #endif
                   5382:                    htmlParsePI(ctxt);
                   5383:                    ctxt->instate = XML_PARSER_MISC;
                   5384:                } else if ((cur == '<') && (next == '!') &&
                   5385:                    (UPP(2) == 'D') && (UPP(3) == 'O') &&
                   5386:                    (UPP(4) == 'C') && (UPP(5) == 'T') &&
                   5387:                    (UPP(6) == 'Y') && (UPP(7) == 'P') &&
                   5388:                    (UPP(8) == 'E')) {
                   5389:                    if ((!terminate) &&
                   5390:                        (htmlParseLookupSequence(ctxt, '>', 0, 0, 0, 1) < 0))
                   5391:                        goto done;
                   5392: #ifdef DEBUG_PUSH
                   5393:                    xmlGenericError(xmlGenericErrorContext,
                   5394:                            "HPP: Parsing internal subset\n");
                   5395: #endif
                   5396:                    htmlParseDocTypeDecl(ctxt);
                   5397:                    ctxt->instate = XML_PARSER_PROLOG;
                   5398: #ifdef DEBUG_PUSH
                   5399:                    xmlGenericError(xmlGenericErrorContext,
                   5400:                            "HPP: entering PROLOG\n");
                   5401: #endif
                   5402:                } else if ((cur == '<') && (next == '!') &&
                   5403:                           (avail < 9)) {
                   5404:                    goto done;
                   5405:                } else {
                   5406:                    ctxt->instate = XML_PARSER_START_TAG;
                   5407: #ifdef DEBUG_PUSH
                   5408:                    xmlGenericError(xmlGenericErrorContext,
                   5409:                            "HPP: entering START_TAG\n");
                   5410: #endif
                   5411:                }
                   5412:                break;
                   5413:             case XML_PARSER_PROLOG:
                   5414:                SKIP_BLANKS;
                   5415:                if (in->buf == NULL)
                   5416:                    avail = in->length - (in->cur - in->base);
                   5417:                else
                   5418:                    avail = in->buf->buffer->use - (in->cur - in->base);
                   5419:                if (avail < 2)
                   5420:                    goto done;
                   5421:                cur = in->cur[0];
                   5422:                next = in->cur[1];
                   5423:                if ((cur == '<') && (next == '!') &&
                   5424:                    (in->cur[2] == '-') && (in->cur[3] == '-')) {
                   5425:                    if ((!terminate) &&
                   5426:                        (htmlParseLookupSequence(ctxt, '-', '-', '>', 1, 1) < 0))
                   5427:                        goto done;
                   5428: #ifdef DEBUG_PUSH
                   5429:                    xmlGenericError(xmlGenericErrorContext,
                   5430:                            "HPP: Parsing Comment\n");
                   5431: #endif
                   5432:                    htmlParseComment(ctxt);
                   5433:                    ctxt->instate = XML_PARSER_PROLOG;
                   5434:                } else if ((cur == '<') && (next == '?')) {
                   5435:                    if ((!terminate) &&
                   5436:                        (htmlParseLookupSequence(ctxt, '>', 0, 0, 0, 1) < 0))
                   5437:                        goto done;
                   5438: #ifdef DEBUG_PUSH
                   5439:                    xmlGenericError(xmlGenericErrorContext,
                   5440:                            "HPP: Parsing PI\n");
                   5441: #endif
                   5442:                    htmlParsePI(ctxt);
                   5443:                    ctxt->instate = XML_PARSER_PROLOG;
                   5444:                } else if ((cur == '<') && (next == '!') &&
                   5445:                           (avail < 4)) {
                   5446:                    goto done;
                   5447:                } else {
                   5448:                    ctxt->instate = XML_PARSER_START_TAG;
                   5449: #ifdef DEBUG_PUSH
                   5450:                    xmlGenericError(xmlGenericErrorContext,
                   5451:                            "HPP: entering START_TAG\n");
                   5452: #endif
                   5453:                }
                   5454:                break;
                   5455:             case XML_PARSER_EPILOG:
                   5456:                if (in->buf == NULL)
                   5457:                    avail = in->length - (in->cur - in->base);
                   5458:                else
                   5459:                    avail = in->buf->buffer->use - (in->cur - in->base);
                   5460:                if (avail < 1)
                   5461:                    goto done;
                   5462:                cur = in->cur[0];
                   5463:                if (IS_BLANK_CH(cur)) {
                   5464:                    htmlParseCharData(ctxt);
                   5465:                    goto done;
                   5466:                }
                   5467:                if (avail < 2)
                   5468:                    goto done;
                   5469:                next = in->cur[1];
                   5470:                if ((cur == '<') && (next == '!') &&
                   5471:                    (in->cur[2] == '-') && (in->cur[3] == '-')) {
                   5472:                    if ((!terminate) &&
                   5473:                        (htmlParseLookupSequence(ctxt, '-', '-', '>', 1, 1) < 0))
                   5474:                        goto done;
                   5475: #ifdef DEBUG_PUSH
                   5476:                    xmlGenericError(xmlGenericErrorContext,
                   5477:                            "HPP: Parsing Comment\n");
                   5478: #endif
                   5479:                    htmlParseComment(ctxt);
                   5480:                    ctxt->instate = XML_PARSER_EPILOG;
                   5481:                } else if ((cur == '<') && (next == '?')) {
                   5482:                    if ((!terminate) &&
                   5483:                        (htmlParseLookupSequence(ctxt, '>', 0, 0, 0, 1) < 0))
                   5484:                        goto done;
                   5485: #ifdef DEBUG_PUSH
                   5486:                    xmlGenericError(xmlGenericErrorContext,
                   5487:                            "HPP: Parsing PI\n");
                   5488: #endif
                   5489:                    htmlParsePI(ctxt);
                   5490:                    ctxt->instate = XML_PARSER_EPILOG;
                   5491:                } else if ((cur == '<') && (next == '!') &&
                   5492:                           (avail < 4)) {
                   5493:                    goto done;
                   5494:                } else {
                   5495:                    ctxt->errNo = XML_ERR_DOCUMENT_END;
                   5496:                    ctxt->wellFormed = 0;
                   5497:                    ctxt->instate = XML_PARSER_EOF;
                   5498: #ifdef DEBUG_PUSH
                   5499:                    xmlGenericError(xmlGenericErrorContext,
                   5500:                            "HPP: entering EOF\n");
                   5501: #endif
                   5502:                    if ((ctxt->sax) && (ctxt->sax->endDocument != NULL))
                   5503:                        ctxt->sax->endDocument(ctxt->userData);
                   5504:                    goto done;
                   5505:                }
                   5506:                break;
                   5507:             case XML_PARSER_START_TAG: {
                   5508:                const xmlChar *name;
                   5509:                int failed;
                   5510:                const htmlElemDesc * info;
                   5511: 
1.1.1.2 ! misho    5512:                /*
        !          5513:                 * no chars in buffer
        !          5514:                 */
        !          5515:                if (avail < 1)
1.1       misho    5516:                    goto done;
1.1.1.2 ! misho    5517:                /*
        !          5518:                 * not enouth chars in buffer
        !          5519:                 */
        !          5520:                if (avail < 2) {
        !          5521:                    if (!terminate)
        !          5522:                        goto done;
        !          5523:                    else
        !          5524:                        next = ' ';
        !          5525:                } else {
        !          5526:                    next = in->cur[1];
        !          5527:                }
1.1       misho    5528:                cur = in->cur[0];
                   5529:                if (cur != '<') {
                   5530:                    ctxt->instate = XML_PARSER_CONTENT;
                   5531: #ifdef DEBUG_PUSH
                   5532:                    xmlGenericError(xmlGenericErrorContext,
                   5533:                            "HPP: entering CONTENT\n");
                   5534: #endif
                   5535:                    break;
                   5536:                }
1.1.1.2 ! misho    5537:                if (next == '/') {
1.1       misho    5538:                    ctxt->instate = XML_PARSER_END_TAG;
                   5539:                    ctxt->checkIndex = 0;
                   5540: #ifdef DEBUG_PUSH
                   5541:                    xmlGenericError(xmlGenericErrorContext,
                   5542:                            "HPP: entering END_TAG\n");
                   5543: #endif
                   5544:                    break;
                   5545:                }
                   5546:                if ((!terminate) &&
                   5547:                    (htmlParseLookupSequence(ctxt, '>', 0, 0, 0, 1) < 0))
                   5548:                    goto done;
                   5549: 
1.1.1.2 ! misho    5550:                 /* Capture start position */
        !          5551:                if (ctxt->record_info) {
        !          5552:                     node_info.begin_pos = ctxt->input->consumed +
        !          5553:                                        (CUR_PTR - ctxt->input->base);
        !          5554:                     node_info.begin_line = ctxt->input->line;
        !          5555:                }
        !          5556: 
        !          5557: 
1.1       misho    5558:                failed = htmlParseStartTag(ctxt);
                   5559:                name = ctxt->name;
                   5560:                if ((failed == -1) ||
                   5561:                    (name == NULL)) {
                   5562:                    if (CUR == '>')
                   5563:                        NEXT;
                   5564:                    break;
                   5565:                }
                   5566: 
                   5567:                /*
                   5568:                 * Lookup the info for that element.
                   5569:                 */
                   5570:                info = htmlTagLookup(name);
                   5571:                if (info == NULL) {
                   5572:                    htmlParseErr(ctxt, XML_HTML_UNKNOWN_TAG,
                   5573:                                 "Tag %s invalid\n", name, NULL);
                   5574:                }
                   5575: 
                   5576:                /*
                   5577:                 * Check for an Empty Element labeled the XML/SGML way
                   5578:                 */
                   5579:                if ((CUR == '/') && (NXT(1) == '>')) {
                   5580:                    SKIP(2);
                   5581:                    if ((ctxt->sax != NULL) && (ctxt->sax->endElement != NULL))
                   5582:                        ctxt->sax->endElement(ctxt->userData, name);
                   5583:                    htmlnamePop(ctxt);
                   5584:                    ctxt->instate = XML_PARSER_CONTENT;
                   5585: #ifdef DEBUG_PUSH
                   5586:                    xmlGenericError(xmlGenericErrorContext,
                   5587:                            "HPP: entering CONTENT\n");
                   5588: #endif
                   5589:                    break;
                   5590:                }
                   5591: 
                   5592:                if (CUR == '>') {
                   5593:                    NEXT;
                   5594:                } else {
                   5595:                    htmlParseErr(ctxt, XML_ERR_GT_REQUIRED,
                   5596:                                 "Couldn't find end of Start Tag %s\n",
                   5597:                                 name, NULL);
                   5598: 
                   5599:                    /*
                   5600:                     * end of parsing of this node.
                   5601:                     */
                   5602:                    if (xmlStrEqual(name, ctxt->name)) {
                   5603:                        nodePop(ctxt);
                   5604:                        htmlnamePop(ctxt);
                   5605:                    }
                   5606: 
1.1.1.2 ! misho    5607:                    if (ctxt->record_info)
        !          5608:                        htmlNodeInfoPush(ctxt, &node_info);
        !          5609: 
1.1       misho    5610:                    ctxt->instate = XML_PARSER_CONTENT;
                   5611: #ifdef DEBUG_PUSH
                   5612:                    xmlGenericError(xmlGenericErrorContext,
                   5613:                            "HPP: entering CONTENT\n");
                   5614: #endif
                   5615:                    break;
                   5616:                }
                   5617: 
                   5618:                /*
                   5619:                 * Check for an Empty Element from DTD definition
                   5620:                 */
                   5621:                if ((info != NULL) && (info->empty)) {
                   5622:                    if ((ctxt->sax != NULL) && (ctxt->sax->endElement != NULL))
                   5623:                        ctxt->sax->endElement(ctxt->userData, name);
                   5624:                    htmlnamePop(ctxt);
                   5625:                }
1.1.1.2 ! misho    5626: 
        !          5627:                 if (ctxt->record_info)
        !          5628:                    htmlNodeInfoPush(ctxt, &node_info);
        !          5629: 
1.1       misho    5630:                ctxt->instate = XML_PARSER_CONTENT;
                   5631: #ifdef DEBUG_PUSH
                   5632:                xmlGenericError(xmlGenericErrorContext,
                   5633:                        "HPP: entering CONTENT\n");
                   5634: #endif
                   5635:                 break;
                   5636:            }
                   5637:             case XML_PARSER_CONTENT: {
                   5638:                long cons;
                   5639:                 /*
                   5640:                 * Handle preparsed entities and charRef
                   5641:                 */
                   5642:                if (ctxt->token != 0) {
                   5643:                    xmlChar chr[2] = { 0 , 0 } ;
                   5644: 
                   5645:                    chr[0] = (xmlChar) ctxt->token;
                   5646:                    htmlCheckParagraph(ctxt);
                   5647:                    if ((ctxt->sax != NULL) && (ctxt->sax->characters != NULL))
                   5648:                        ctxt->sax->characters(ctxt->userData, chr, 1);
                   5649:                    ctxt->token = 0;
                   5650:                    ctxt->checkIndex = 0;
                   5651:                }
                   5652:                if ((avail == 1) && (terminate)) {
                   5653:                    cur = in->cur[0];
                   5654:                    if ((cur != '<') && (cur != '&')) {
                   5655:                        if (ctxt->sax != NULL) {
                   5656:                            if (IS_BLANK_CH(cur)) {
                   5657:                                if (ctxt->sax->ignorableWhitespace != NULL)
                   5658:                                    ctxt->sax->ignorableWhitespace(
                   5659:                                            ctxt->userData, &cur, 1);
                   5660:                            } else {
                   5661:                                htmlCheckParagraph(ctxt);
                   5662:                                if (ctxt->sax->characters != NULL)
                   5663:                                    ctxt->sax->characters(
                   5664:                                            ctxt->userData, &cur, 1);
                   5665:                            }
                   5666:                        }
                   5667:                        ctxt->token = 0;
                   5668:                        ctxt->checkIndex = 0;
                   5669:                        in->cur++;
                   5670:                        break;
                   5671:                    }
                   5672:                }
                   5673:                if (avail < 2)
                   5674:                    goto done;
                   5675:                cur = in->cur[0];
                   5676:                next = in->cur[1];
                   5677:                cons = ctxt->nbChars;
                   5678:                if ((xmlStrEqual(ctxt->name, BAD_CAST"script")) ||
                   5679:                    (xmlStrEqual(ctxt->name, BAD_CAST"style"))) {
                   5680:                    /*
                   5681:                     * Handle SCRIPT/STYLE separately
                   5682:                     */
                   5683:                    if (!terminate) {
                   5684:                        int idx;
                   5685:                        xmlChar val;
                   5686: 
                   5687:                        idx = htmlParseLookupSequence(ctxt, '<', '/', 0, 0, 0);
                   5688:                        if (idx < 0)
                   5689:                            goto done;
                   5690:                        val = in->cur[idx + 2];
                   5691:                        if (val == 0) /* bad cut of input */
                   5692:                            goto done;
                   5693:                    }
                   5694:                    htmlParseScript(ctxt);
                   5695:                    if ((cur == '<') && (next == '/')) {
                   5696:                        ctxt->instate = XML_PARSER_END_TAG;
                   5697:                        ctxt->checkIndex = 0;
                   5698: #ifdef DEBUG_PUSH
                   5699:                        xmlGenericError(xmlGenericErrorContext,
                   5700:                                "HPP: entering END_TAG\n");
                   5701: #endif
                   5702:                        break;
                   5703:                    }
                   5704:                } else {
                   5705:                    /*
                   5706:                     * Sometimes DOCTYPE arrives in the middle of the document
                   5707:                     */
                   5708:                    if ((cur == '<') && (next == '!') &&
                   5709:                        (UPP(2) == 'D') && (UPP(3) == 'O') &&
                   5710:                        (UPP(4) == 'C') && (UPP(5) == 'T') &&
                   5711:                        (UPP(6) == 'Y') && (UPP(7) == 'P') &&
                   5712:                        (UPP(8) == 'E')) {
                   5713:                        if ((!terminate) &&
                   5714:                            (htmlParseLookupSequence(ctxt, '>', 0, 0, 0, 1) < 0))
                   5715:                            goto done;
                   5716:                        htmlParseErr(ctxt, XML_HTML_STRUCURE_ERROR,
                   5717:                                     "Misplaced DOCTYPE declaration\n",
                   5718:                                     BAD_CAST "DOCTYPE" , NULL);
                   5719:                        htmlParseDocTypeDecl(ctxt);
                   5720:                    } else if ((cur == '<') && (next == '!') &&
                   5721:                        (in->cur[2] == '-') && (in->cur[3] == '-')) {
                   5722:                        if ((!terminate) &&
                   5723:                            (htmlParseLookupSequence(
                   5724:                                ctxt, '-', '-', '>', 1, 1) < 0))
                   5725:                            goto done;
                   5726: #ifdef DEBUG_PUSH
                   5727:                        xmlGenericError(xmlGenericErrorContext,
                   5728:                                "HPP: Parsing Comment\n");
                   5729: #endif
                   5730:                        htmlParseComment(ctxt);
                   5731:                        ctxt->instate = XML_PARSER_CONTENT;
                   5732:                    } else if ((cur == '<') && (next == '?')) {
                   5733:                        if ((!terminate) &&
                   5734:                            (htmlParseLookupSequence(ctxt, '>', 0, 0, 0, 1) < 0))
                   5735:                            goto done;
                   5736: #ifdef DEBUG_PUSH
                   5737:                        xmlGenericError(xmlGenericErrorContext,
                   5738:                                "HPP: Parsing PI\n");
                   5739: #endif
                   5740:                        htmlParsePI(ctxt);
                   5741:                        ctxt->instate = XML_PARSER_CONTENT;
                   5742:                    } else if ((cur == '<') && (next == '!') && (avail < 4)) {
                   5743:                        goto done;
                   5744:                    } else if ((cur == '<') && (next == '/')) {
                   5745:                        ctxt->instate = XML_PARSER_END_TAG;
                   5746:                        ctxt->checkIndex = 0;
                   5747: #ifdef DEBUG_PUSH
                   5748:                        xmlGenericError(xmlGenericErrorContext,
                   5749:                                "HPP: entering END_TAG\n");
                   5750: #endif
                   5751:                        break;
                   5752:                    } else if (cur == '<') {
                   5753:                        ctxt->instate = XML_PARSER_START_TAG;
                   5754:                        ctxt->checkIndex = 0;
                   5755: #ifdef DEBUG_PUSH
                   5756:                        xmlGenericError(xmlGenericErrorContext,
                   5757:                                "HPP: entering START_TAG\n");
                   5758: #endif
                   5759:                        break;
                   5760:                    } else if (cur == '&') {
                   5761:                        if ((!terminate) &&
                   5762:                            (htmlParseLookupChars(ctxt,
                   5763:                                                   BAD_CAST "; >/", 4) < 0))
                   5764:                            goto done;
                   5765: #ifdef DEBUG_PUSH
                   5766:                        xmlGenericError(xmlGenericErrorContext,
                   5767:                                "HPP: Parsing Reference\n");
                   5768: #endif
                   5769:                        /* TODO: check generation of subtrees if noent !!! */
                   5770:                        htmlParseReference(ctxt);
                   5771:                    } else {
                   5772:                        /*
                   5773:                         * check that the text sequence is complete
                   5774:                         * before handing out the data to the parser
                   5775:                         * to avoid problems with erroneous end of
                   5776:                         * data detection.
                   5777:                         */
                   5778:                        if ((!terminate) &&
                   5779:                             (htmlParseLookupChars(ctxt, BAD_CAST "<&", 2) < 0))
                   5780:                            goto done;
                   5781:                        ctxt->checkIndex = 0;
                   5782: #ifdef DEBUG_PUSH
                   5783:                        xmlGenericError(xmlGenericErrorContext,
                   5784:                                "HPP: Parsing char data\n");
                   5785: #endif
                   5786:                        htmlParseCharData(ctxt);
                   5787:                    }
                   5788:                }
                   5789:                if (cons == ctxt->nbChars) {
                   5790:                    if (ctxt->node != NULL) {
                   5791:                        htmlParseErr(ctxt, XML_ERR_INTERNAL_ERROR,
                   5792:                                     "detected an error in element content\n",
                   5793:                                     NULL, NULL);
                   5794:                    }
                   5795:                    NEXT;
                   5796:                    break;
                   5797:                }
                   5798: 
                   5799:                break;
                   5800:            }
                   5801:             case XML_PARSER_END_TAG:
                   5802:                if (avail < 2)
                   5803:                    goto done;
                   5804:                if ((!terminate) &&
                   5805:                    (htmlParseLookupSequence(ctxt, '>', 0, 0, 0, 1) < 0))
                   5806:                    goto done;
                   5807:                htmlParseEndTag(ctxt);
                   5808:                if (ctxt->nameNr == 0) {
                   5809:                    ctxt->instate = XML_PARSER_EPILOG;
                   5810:                } else {
                   5811:                    ctxt->instate = XML_PARSER_CONTENT;
                   5812:                }
                   5813:                ctxt->checkIndex = 0;
                   5814: #ifdef DEBUG_PUSH
                   5815:                xmlGenericError(xmlGenericErrorContext,
                   5816:                        "HPP: entering CONTENT\n");
                   5817: #endif
                   5818:                break;
                   5819:             case XML_PARSER_CDATA_SECTION:
                   5820:                htmlParseErr(ctxt, XML_ERR_INTERNAL_ERROR,
                   5821:                        "HPP: internal error, state == CDATA\n",
                   5822:                             NULL, NULL);
                   5823:                ctxt->instate = XML_PARSER_CONTENT;
                   5824:                ctxt->checkIndex = 0;
                   5825: #ifdef DEBUG_PUSH
                   5826:                xmlGenericError(xmlGenericErrorContext,
                   5827:                        "HPP: entering CONTENT\n");
                   5828: #endif
                   5829:                break;
                   5830:             case XML_PARSER_DTD:
                   5831:                htmlParseErr(ctxt, XML_ERR_INTERNAL_ERROR,
                   5832:                        "HPP: internal error, state == DTD\n",
                   5833:                             NULL, NULL);
                   5834:                ctxt->instate = XML_PARSER_CONTENT;
                   5835:                ctxt->checkIndex = 0;
                   5836: #ifdef DEBUG_PUSH
                   5837:                xmlGenericError(xmlGenericErrorContext,
                   5838:                        "HPP: entering CONTENT\n");
                   5839: #endif
                   5840:                break;
                   5841:             case XML_PARSER_COMMENT:
                   5842:                htmlParseErr(ctxt, XML_ERR_INTERNAL_ERROR,
                   5843:                        "HPP: internal error, state == COMMENT\n",
                   5844:                             NULL, NULL);
                   5845:                ctxt->instate = XML_PARSER_CONTENT;
                   5846:                ctxt->checkIndex = 0;
                   5847: #ifdef DEBUG_PUSH
                   5848:                xmlGenericError(xmlGenericErrorContext,
                   5849:                        "HPP: entering CONTENT\n");
                   5850: #endif
                   5851:                break;
                   5852:             case XML_PARSER_PI:
                   5853:                htmlParseErr(ctxt, XML_ERR_INTERNAL_ERROR,
                   5854:                        "HPP: internal error, state == PI\n",
                   5855:                             NULL, NULL);
                   5856:                ctxt->instate = XML_PARSER_CONTENT;
                   5857:                ctxt->checkIndex = 0;
                   5858: #ifdef DEBUG_PUSH
                   5859:                xmlGenericError(xmlGenericErrorContext,
                   5860:                        "HPP: entering CONTENT\n");
                   5861: #endif
                   5862:                break;
                   5863:             case XML_PARSER_ENTITY_DECL:
                   5864:                htmlParseErr(ctxt, XML_ERR_INTERNAL_ERROR,
                   5865:                        "HPP: internal error, state == ENTITY_DECL\n",
                   5866:                             NULL, NULL);
                   5867:                ctxt->instate = XML_PARSER_CONTENT;
                   5868:                ctxt->checkIndex = 0;
                   5869: #ifdef DEBUG_PUSH
                   5870:                xmlGenericError(xmlGenericErrorContext,
                   5871:                        "HPP: entering CONTENT\n");
                   5872: #endif
                   5873:                break;
                   5874:             case XML_PARSER_ENTITY_VALUE:
                   5875:                htmlParseErr(ctxt, XML_ERR_INTERNAL_ERROR,
                   5876:                        "HPP: internal error, state == ENTITY_VALUE\n",
                   5877:                             NULL, NULL);
                   5878:                ctxt->instate = XML_PARSER_CONTENT;
                   5879:                ctxt->checkIndex = 0;
                   5880: #ifdef DEBUG_PUSH
                   5881:                xmlGenericError(xmlGenericErrorContext,
                   5882:                        "HPP: entering DTD\n");
                   5883: #endif
                   5884:                break;
                   5885:             case XML_PARSER_ATTRIBUTE_VALUE:
                   5886:                htmlParseErr(ctxt, XML_ERR_INTERNAL_ERROR,
                   5887:                        "HPP: internal error, state == ATTRIBUTE_VALUE\n",
                   5888:                             NULL, NULL);
                   5889:                ctxt->instate = XML_PARSER_START_TAG;
                   5890:                ctxt->checkIndex = 0;
                   5891: #ifdef DEBUG_PUSH
                   5892:                xmlGenericError(xmlGenericErrorContext,
                   5893:                        "HPP: entering START_TAG\n");
                   5894: #endif
                   5895:                break;
                   5896:            case XML_PARSER_SYSTEM_LITERAL:
                   5897:                htmlParseErr(ctxt, XML_ERR_INTERNAL_ERROR,
                   5898:                    "HPP: internal error, state == XML_PARSER_SYSTEM_LITERAL\n",
                   5899:                             NULL, NULL);
                   5900:                ctxt->instate = XML_PARSER_CONTENT;
                   5901:                ctxt->checkIndex = 0;
                   5902: #ifdef DEBUG_PUSH
                   5903:                xmlGenericError(xmlGenericErrorContext,
                   5904:                        "HPP: entering CONTENT\n");
                   5905: #endif
                   5906:                break;
                   5907:            case XML_PARSER_IGNORE:
                   5908:                htmlParseErr(ctxt, XML_ERR_INTERNAL_ERROR,
                   5909:                        "HPP: internal error, state == XML_PARSER_IGNORE\n",
                   5910:                             NULL, NULL);
                   5911:                ctxt->instate = XML_PARSER_CONTENT;
                   5912:                ctxt->checkIndex = 0;
                   5913: #ifdef DEBUG_PUSH
                   5914:                xmlGenericError(xmlGenericErrorContext,
                   5915:                        "HPP: entering CONTENT\n");
                   5916: #endif
                   5917:                break;
                   5918:            case XML_PARSER_PUBLIC_LITERAL:
                   5919:                htmlParseErr(ctxt, XML_ERR_INTERNAL_ERROR,
                   5920:                        "HPP: internal error, state == XML_PARSER_LITERAL\n",
                   5921:                             NULL, NULL);
                   5922:                ctxt->instate = XML_PARSER_CONTENT;
                   5923:                ctxt->checkIndex = 0;
                   5924: #ifdef DEBUG_PUSH
                   5925:                xmlGenericError(xmlGenericErrorContext,
                   5926:                        "HPP: entering CONTENT\n");
                   5927: #endif
                   5928:                break;
                   5929: 
                   5930:        }
                   5931:     }
                   5932: done:
                   5933:     if ((avail == 0) && (terminate)) {
                   5934:        htmlAutoCloseOnEnd(ctxt);
                   5935:        if ((ctxt->nameNr == 0) && (ctxt->instate != XML_PARSER_EOF)) {
                   5936:            /*
                   5937:             * SAX: end of the document processing.
                   5938:             */
                   5939:            ctxt->instate = XML_PARSER_EOF;
                   5940:            if ((ctxt->sax) && (ctxt->sax->endDocument != NULL))
                   5941:                ctxt->sax->endDocument(ctxt->userData);
                   5942:        }
                   5943:     }
                   5944:     if ((ctxt->myDoc != NULL) &&
                   5945:        ((terminate) || (ctxt->instate == XML_PARSER_EOF) ||
                   5946:         (ctxt->instate == XML_PARSER_EPILOG))) {
                   5947:        xmlDtdPtr dtd;
                   5948:        dtd = xmlGetIntSubset(ctxt->myDoc);
                   5949:        if (dtd == NULL)
                   5950:            ctxt->myDoc->intSubset =
                   5951:                xmlCreateIntSubset(ctxt->myDoc, BAD_CAST "html",
                   5952:                    BAD_CAST "-//W3C//DTD HTML 4.0 Transitional//EN",
                   5953:                    BAD_CAST "http://www.w3.org/TR/REC-html40/loose.dtd");
                   5954:     }
                   5955: #ifdef DEBUG_PUSH
                   5956:     xmlGenericError(xmlGenericErrorContext, "HPP: done %d\n", ret);
                   5957: #endif
                   5958:     return(ret);
                   5959: }
                   5960: 
                   5961: /**
                   5962:  * htmlParseChunk:
                   5963:  * @ctxt:  an HTML parser context
                   5964:  * @chunk:  an char array
                   5965:  * @size:  the size in byte of the chunk
                   5966:  * @terminate:  last chunk indicator
                   5967:  *
                   5968:  * Parse a Chunk of memory
                   5969:  *
                   5970:  * Returns zero if no error, the xmlParserErrors otherwise.
                   5971:  */
                   5972: int
                   5973: htmlParseChunk(htmlParserCtxtPtr ctxt, const char *chunk, int size,
                   5974:               int terminate) {
                   5975:     if ((ctxt == NULL) || (ctxt->input == NULL)) {
                   5976:        htmlParseErr(ctxt, XML_ERR_INTERNAL_ERROR,
                   5977:                     "htmlParseChunk: context error\n", NULL, NULL);
                   5978:        return(XML_ERR_INTERNAL_ERROR);
                   5979:     }
                   5980:     if ((size > 0) && (chunk != NULL) && (ctxt->input != NULL) &&
                   5981:         (ctxt->input->buf != NULL) && (ctxt->instate != XML_PARSER_EOF))  {
                   5982:        int base = ctxt->input->base - ctxt->input->buf->buffer->content;
                   5983:        int cur = ctxt->input->cur - ctxt->input->base;
                   5984:        int res;
                   5985: 
                   5986:        res = xmlParserInputBufferPush(ctxt->input->buf, size, chunk);
                   5987:        if (res < 0) {
                   5988:            ctxt->errNo = XML_PARSER_EOF;
                   5989:            ctxt->disableSAX = 1;
                   5990:            return (XML_PARSER_EOF);
                   5991:        }
                   5992:        ctxt->input->base = ctxt->input->buf->buffer->content + base;
                   5993:        ctxt->input->cur = ctxt->input->base + cur;
                   5994:        ctxt->input->end =
                   5995:          &ctxt->input->buf->buffer->content[ctxt->input->buf->buffer->use];
                   5996: #ifdef DEBUG_PUSH
                   5997:        xmlGenericError(xmlGenericErrorContext, "HPP: pushed %d\n", size);
                   5998: #endif
                   5999: 
                   6000: #if 0
                   6001:        if ((terminate) || (ctxt->input->buf->buffer->use > 80))
                   6002:            htmlParseTryOrFinish(ctxt, terminate);
                   6003: #endif
                   6004:     } else if (ctxt->instate != XML_PARSER_EOF) {
                   6005:        if ((ctxt->input != NULL) && ctxt->input->buf != NULL) {
                   6006:            xmlParserInputBufferPtr in = ctxt->input->buf;
                   6007:            if ((in->encoder != NULL) && (in->buffer != NULL) &&
                   6008:                    (in->raw != NULL)) {
                   6009:                int nbchars;
                   6010: 
                   6011:                nbchars = xmlCharEncInFunc(in->encoder, in->buffer, in->raw);
                   6012:                if (nbchars < 0) {
                   6013:                    htmlParseErr(ctxt, XML_ERR_INVALID_ENCODING,
                   6014:                                 "encoder error\n", NULL, NULL);
                   6015:                    return(XML_ERR_INVALID_ENCODING);
                   6016:                }
                   6017:            }
                   6018:        }
                   6019:     }
                   6020:     htmlParseTryOrFinish(ctxt, terminate);
                   6021:     if (terminate) {
                   6022:        if ((ctxt->instate != XML_PARSER_EOF) &&
                   6023:            (ctxt->instate != XML_PARSER_EPILOG) &&
                   6024:            (ctxt->instate != XML_PARSER_MISC)) {
                   6025:            ctxt->errNo = XML_ERR_DOCUMENT_END;
                   6026:            ctxt->wellFormed = 0;
                   6027:        }
                   6028:        if (ctxt->instate != XML_PARSER_EOF) {
                   6029:            if ((ctxt->sax) && (ctxt->sax->endDocument != NULL))
                   6030:                ctxt->sax->endDocument(ctxt->userData);
                   6031:        }
                   6032:        ctxt->instate = XML_PARSER_EOF;
                   6033:     }
                   6034:     return((xmlParserErrors) ctxt->errNo);
                   6035: }
                   6036: 
                   6037: /************************************************************************
                   6038:  *                                                                     *
                   6039:  *                     User entry points                               *
                   6040:  *                                                                     *
                   6041:  ************************************************************************/
                   6042: 
                   6043: /**
                   6044:  * htmlCreatePushParserCtxt:
                   6045:  * @sax:  a SAX handler
                   6046:  * @user_data:  The user data returned on SAX callbacks
                   6047:  * @chunk:  a pointer to an array of chars
                   6048:  * @size:  number of chars in the array
                   6049:  * @filename:  an optional file name or URI
                   6050:  * @enc:  an optional encoding
                   6051:  *
                   6052:  * Create a parser context for using the HTML parser in push mode
                   6053:  * The value of @filename is used for fetching external entities
                   6054:  * and error/warning reports.
                   6055:  *
                   6056:  * Returns the new parser context or NULL
                   6057:  */
                   6058: htmlParserCtxtPtr
                   6059: htmlCreatePushParserCtxt(htmlSAXHandlerPtr sax, void *user_data,
                   6060:                          const char *chunk, int size, const char *filename,
                   6061:                         xmlCharEncoding enc) {
                   6062:     htmlParserCtxtPtr ctxt;
                   6063:     htmlParserInputPtr inputStream;
                   6064:     xmlParserInputBufferPtr buf;
                   6065: 
                   6066:     xmlInitParser();
                   6067: 
                   6068:     buf = xmlAllocParserInputBuffer(enc);
                   6069:     if (buf == NULL) return(NULL);
                   6070: 
                   6071:     ctxt = htmlNewParserCtxt();
                   6072:     if (ctxt == NULL) {
                   6073:        xmlFreeParserInputBuffer(buf);
                   6074:        return(NULL);
                   6075:     }
                   6076:     if(enc==XML_CHAR_ENCODING_UTF8 || buf->encoder)
                   6077:        ctxt->charset=XML_CHAR_ENCODING_UTF8;
                   6078:     if (sax != NULL) {
                   6079:        if (ctxt->sax != (xmlSAXHandlerPtr) &htmlDefaultSAXHandler)
                   6080:            xmlFree(ctxt->sax);
                   6081:        ctxt->sax = (htmlSAXHandlerPtr) xmlMalloc(sizeof(htmlSAXHandler));
                   6082:        if (ctxt->sax == NULL) {
                   6083:            xmlFree(buf);
                   6084:            xmlFree(ctxt);
                   6085:            return(NULL);
                   6086:        }
                   6087:        memcpy(ctxt->sax, sax, sizeof(htmlSAXHandler));
                   6088:        if (user_data != NULL)
                   6089:            ctxt->userData = user_data;
                   6090:     }
                   6091:     if (filename == NULL) {
                   6092:        ctxt->directory = NULL;
                   6093:     } else {
                   6094:         ctxt->directory = xmlParserGetDirectory(filename);
                   6095:     }
                   6096: 
                   6097:     inputStream = htmlNewInputStream(ctxt);
                   6098:     if (inputStream == NULL) {
                   6099:        xmlFreeParserCtxt(ctxt);
                   6100:        xmlFree(buf);
                   6101:        return(NULL);
                   6102:     }
                   6103: 
                   6104:     if (filename == NULL)
                   6105:        inputStream->filename = NULL;
                   6106:     else
                   6107:        inputStream->filename = (char *)
                   6108:            xmlCanonicPath((const xmlChar *) filename);
                   6109:     inputStream->buf = buf;
                   6110:     inputStream->base = inputStream->buf->buffer->content;
                   6111:     inputStream->cur = inputStream->buf->buffer->content;
                   6112:     inputStream->end =
                   6113:        &inputStream->buf->buffer->content[inputStream->buf->buffer->use];
                   6114: 
                   6115:     inputPush(ctxt, inputStream);
                   6116: 
                   6117:     if ((size > 0) && (chunk != NULL) && (ctxt->input != NULL) &&
                   6118:         (ctxt->input->buf != NULL))  {
                   6119:        int base = ctxt->input->base - ctxt->input->buf->buffer->content;
                   6120:        int cur = ctxt->input->cur - ctxt->input->base;
                   6121: 
                   6122:        xmlParserInputBufferPush(ctxt->input->buf, size, chunk);
                   6123: 
                   6124:        ctxt->input->base = ctxt->input->buf->buffer->content + base;
                   6125:        ctxt->input->cur = ctxt->input->base + cur;
                   6126:        ctxt->input->end =
                   6127:            &ctxt->input->buf->buffer->content[ctxt->input->buf->buffer->use];
                   6128: #ifdef DEBUG_PUSH
                   6129:        xmlGenericError(xmlGenericErrorContext, "HPP: pushed %d\n", size);
                   6130: #endif
                   6131:     }
                   6132:     ctxt->progressive = 1;
                   6133: 
                   6134:     return(ctxt);
                   6135: }
                   6136: #endif /* LIBXML_PUSH_ENABLED */
                   6137: 
                   6138: /**
                   6139:  * htmlSAXParseDoc:
                   6140:  * @cur:  a pointer to an array of xmlChar
                   6141:  * @encoding:  a free form C string describing the HTML document encoding, or NULL
                   6142:  * @sax:  the SAX handler block
                   6143:  * @userData: if using SAX, this pointer will be provided on callbacks.
                   6144:  *
                   6145:  * Parse an HTML in-memory document. If sax is not NULL, use the SAX callbacks
                   6146:  * to handle parse events. If sax is NULL, fallback to the default DOM
                   6147:  * behavior and return a tree.
                   6148:  *
                   6149:  * Returns the resulting document tree unless SAX is NULL or the document is
                   6150:  *     not well formed.
                   6151:  */
                   6152: 
                   6153: htmlDocPtr
                   6154: htmlSAXParseDoc(xmlChar *cur, const char *encoding, htmlSAXHandlerPtr sax, void *userData) {
                   6155:     htmlDocPtr ret;
                   6156:     htmlParserCtxtPtr ctxt;
                   6157: 
                   6158:     xmlInitParser();
                   6159: 
                   6160:     if (cur == NULL) return(NULL);
                   6161: 
                   6162: 
                   6163:     ctxt = htmlCreateDocParserCtxt(cur, encoding);
                   6164:     if (ctxt == NULL) return(NULL);
                   6165:     if (sax != NULL) {
                   6166:         if (ctxt->sax != NULL) xmlFree (ctxt->sax);
                   6167:         ctxt->sax = sax;
                   6168:         ctxt->userData = userData;
                   6169:     }
                   6170: 
                   6171:     htmlParseDocument(ctxt);
                   6172:     ret = ctxt->myDoc;
                   6173:     if (sax != NULL) {
                   6174:        ctxt->sax = NULL;
                   6175:        ctxt->userData = NULL;
                   6176:     }
                   6177:     htmlFreeParserCtxt(ctxt);
                   6178: 
                   6179:     return(ret);
                   6180: }
                   6181: 
                   6182: /**
                   6183:  * htmlParseDoc:
                   6184:  * @cur:  a pointer to an array of xmlChar
                   6185:  * @encoding:  a free form C string describing the HTML document encoding, or NULL
                   6186:  *
                   6187:  * parse an HTML in-memory document and build a tree.
                   6188:  *
                   6189:  * Returns the resulting document tree
                   6190:  */
                   6191: 
                   6192: htmlDocPtr
                   6193: htmlParseDoc(xmlChar *cur, const char *encoding) {
                   6194:     return(htmlSAXParseDoc(cur, encoding, NULL, NULL));
                   6195: }
                   6196: 
                   6197: 
                   6198: /**
                   6199:  * htmlCreateFileParserCtxt:
                   6200:  * @filename:  the filename
                   6201:  * @encoding:  a free form C string describing the HTML document encoding, or NULL
                   6202:  *
                   6203:  * Create a parser context for a file content.
                   6204:  * Automatic support for ZLIB/Compress compressed document is provided
                   6205:  * by default if found at compile-time.
                   6206:  *
                   6207:  * Returns the new parser context or NULL
                   6208:  */
                   6209: htmlParserCtxtPtr
                   6210: htmlCreateFileParserCtxt(const char *filename, const char *encoding)
                   6211: {
                   6212:     htmlParserCtxtPtr ctxt;
                   6213:     htmlParserInputPtr inputStream;
                   6214:     char *canonicFilename;
                   6215:     /* htmlCharEncoding enc; */
                   6216:     xmlChar *content, *content_line = (xmlChar *) "charset=";
                   6217: 
                   6218:     if (filename == NULL)
                   6219:         return(NULL);
                   6220: 
                   6221:     ctxt = htmlNewParserCtxt();
                   6222:     if (ctxt == NULL) {
                   6223:        return(NULL);
                   6224:     }
                   6225:     canonicFilename = (char *) xmlCanonicPath((const xmlChar *) filename);
                   6226:     if (canonicFilename == NULL) {
                   6227: #ifdef LIBXML_SAX1_ENABLED
                   6228:        if (xmlDefaultSAXHandler.error != NULL) {
                   6229:            xmlDefaultSAXHandler.error(NULL, "out of memory\n");
                   6230:        }
                   6231: #endif
                   6232:        xmlFreeParserCtxt(ctxt);
                   6233:        return(NULL);
                   6234:     }
                   6235: 
                   6236:     inputStream = xmlLoadExternalEntity(canonicFilename, NULL, ctxt);
                   6237:     xmlFree(canonicFilename);
                   6238:     if (inputStream == NULL) {
                   6239:        xmlFreeParserCtxt(ctxt);
                   6240:        return(NULL);
                   6241:     }
                   6242: 
                   6243:     inputPush(ctxt, inputStream);
                   6244: 
                   6245:     /* set encoding */
                   6246:     if (encoding) {
                   6247:         content = xmlMallocAtomic (xmlStrlen(content_line) + strlen(encoding) + 1);
                   6248:        if (content) {
                   6249:            strcpy ((char *)content, (char *)content_line);
                   6250:             strcat ((char *)content, (char *)encoding);
                   6251:             htmlCheckEncoding (ctxt, content);
                   6252:            xmlFree (content);
                   6253:        }
                   6254:     }
                   6255: 
                   6256:     return(ctxt);
                   6257: }
                   6258: 
                   6259: /**
                   6260:  * htmlSAXParseFile:
                   6261:  * @filename:  the filename
                   6262:  * @encoding:  a free form C string describing the HTML document encoding, or NULL
                   6263:  * @sax:  the SAX handler block
                   6264:  * @userData: if using SAX, this pointer will be provided on callbacks.
                   6265:  *
                   6266:  * parse an HTML file and build a tree. Automatic support for ZLIB/Compress
                   6267:  * compressed document is provided by default if found at compile-time.
                   6268:  * It use the given SAX function block to handle the parsing callback.
                   6269:  * If sax is NULL, fallback to the default DOM tree building routines.
                   6270:  *
                   6271:  * Returns the resulting document tree unless SAX is NULL or the document is
                   6272:  *     not well formed.
                   6273:  */
                   6274: 
                   6275: htmlDocPtr
                   6276: htmlSAXParseFile(const char *filename, const char *encoding, htmlSAXHandlerPtr sax,
                   6277:                  void *userData) {
                   6278:     htmlDocPtr ret;
                   6279:     htmlParserCtxtPtr ctxt;
                   6280:     htmlSAXHandlerPtr oldsax = NULL;
                   6281: 
                   6282:     xmlInitParser();
                   6283: 
                   6284:     ctxt = htmlCreateFileParserCtxt(filename, encoding);
                   6285:     if (ctxt == NULL) return(NULL);
                   6286:     if (sax != NULL) {
                   6287:        oldsax = ctxt->sax;
                   6288:         ctxt->sax = sax;
                   6289:         ctxt->userData = userData;
                   6290:     }
                   6291: 
                   6292:     htmlParseDocument(ctxt);
                   6293: 
                   6294:     ret = ctxt->myDoc;
                   6295:     if (sax != NULL) {
                   6296:         ctxt->sax = oldsax;
                   6297:         ctxt->userData = NULL;
                   6298:     }
                   6299:     htmlFreeParserCtxt(ctxt);
                   6300: 
                   6301:     return(ret);
                   6302: }
                   6303: 
                   6304: /**
                   6305:  * htmlParseFile:
                   6306:  * @filename:  the filename
                   6307:  * @encoding:  a free form C string describing the HTML document encoding, or NULL
                   6308:  *
                   6309:  * parse an HTML file and build a tree. Automatic support for ZLIB/Compress
                   6310:  * compressed document is provided by default if found at compile-time.
                   6311:  *
                   6312:  * Returns the resulting document tree
                   6313:  */
                   6314: 
                   6315: htmlDocPtr
                   6316: htmlParseFile(const char *filename, const char *encoding) {
                   6317:     return(htmlSAXParseFile(filename, encoding, NULL, NULL));
                   6318: }
                   6319: 
                   6320: /**
                   6321:  * htmlHandleOmittedElem:
                   6322:  * @val:  int 0 or 1
                   6323:  *
                   6324:  * Set and return the previous value for handling HTML omitted tags.
                   6325:  *
                   6326:  * Returns the last value for 0 for no handling, 1 for auto insertion.
                   6327:  */
                   6328: 
                   6329: int
                   6330: htmlHandleOmittedElem(int val) {
                   6331:     int old = htmlOmittedDefaultValue;
                   6332: 
                   6333:     htmlOmittedDefaultValue = val;
                   6334:     return(old);
                   6335: }
                   6336: 
                   6337: /**
                   6338:  * htmlElementAllowedHere:
                   6339:  * @parent: HTML parent element
                   6340:  * @elt: HTML element
                   6341:  *
                   6342:  * Checks whether an HTML element may be a direct child of a parent element.
                   6343:  * Note - doesn't check for deprecated elements
                   6344:  *
                   6345:  * Returns 1 if allowed; 0 otherwise.
                   6346:  */
                   6347: int
                   6348: htmlElementAllowedHere(const htmlElemDesc* parent, const xmlChar* elt) {
                   6349:   const char** p ;
                   6350: 
                   6351:   if ( ! elt || ! parent || ! parent->subelts )
                   6352:        return 0 ;
                   6353: 
                   6354:   for ( p = parent->subelts; *p; ++p )
                   6355:     if ( !xmlStrcmp((const xmlChar *)*p, elt) )
                   6356:       return 1 ;
                   6357: 
                   6358:   return 0 ;
                   6359: }
                   6360: /**
                   6361:  * htmlElementStatusHere:
                   6362:  * @parent: HTML parent element
                   6363:  * @elt: HTML element
                   6364:  *
                   6365:  * Checks whether an HTML element may be a direct child of a parent element.
                   6366:  * and if so whether it is valid or deprecated.
                   6367:  *
                   6368:  * Returns one of HTML_VALID, HTML_DEPRECATED, HTML_INVALID
                   6369:  */
                   6370: htmlStatus
                   6371: htmlElementStatusHere(const htmlElemDesc* parent, const htmlElemDesc* elt) {
                   6372:   if ( ! parent || ! elt )
                   6373:     return HTML_INVALID ;
                   6374:   if ( ! htmlElementAllowedHere(parent, (const xmlChar*) elt->name ) )
                   6375:     return HTML_INVALID ;
                   6376: 
                   6377:   return ( elt->dtd == 0 ) ? HTML_VALID : HTML_DEPRECATED ;
                   6378: }
                   6379: /**
                   6380:  * htmlAttrAllowed:
                   6381:  * @elt: HTML element
                   6382:  * @attr: HTML attribute
                   6383:  * @legacy: whether to allow deprecated attributes
                   6384:  *
                   6385:  * Checks whether an attribute is valid for an element
                   6386:  * Has full knowledge of Required and Deprecated attributes
                   6387:  *
                   6388:  * Returns one of HTML_REQUIRED, HTML_VALID, HTML_DEPRECATED, HTML_INVALID
                   6389:  */
                   6390: htmlStatus
                   6391: htmlAttrAllowed(const htmlElemDesc* elt, const xmlChar* attr, int legacy) {
                   6392:   const char** p ;
                   6393: 
                   6394:   if ( !elt || ! attr )
                   6395:        return HTML_INVALID ;
                   6396: 
                   6397:   if ( elt->attrs_req )
                   6398:     for ( p = elt->attrs_req; *p; ++p)
                   6399:       if ( !xmlStrcmp((const xmlChar*)*p, attr) )
                   6400:         return HTML_REQUIRED ;
                   6401: 
                   6402:   if ( elt->attrs_opt )
                   6403:     for ( p = elt->attrs_opt; *p; ++p)
                   6404:       if ( !xmlStrcmp((const xmlChar*)*p, attr) )
                   6405:         return HTML_VALID ;
                   6406: 
                   6407:   if ( legacy && elt->attrs_depr )
                   6408:     for ( p = elt->attrs_depr; *p; ++p)
                   6409:       if ( !xmlStrcmp((const xmlChar*)*p, attr) )
                   6410:         return HTML_DEPRECATED ;
                   6411: 
                   6412:   return HTML_INVALID ;
                   6413: }
                   6414: /**
                   6415:  * htmlNodeStatus:
                   6416:  * @node: an htmlNodePtr in a tree
                   6417:  * @legacy: whether to allow deprecated elements (YES is faster here
                   6418:  *     for Element nodes)
                   6419:  *
                   6420:  * Checks whether the tree node is valid.  Experimental (the author
                   6421:  *     only uses the HTML enhancements in a SAX parser)
                   6422:  *
                   6423:  * Return: for Element nodes, a return from htmlElementAllowedHere (if
                   6424:  *     legacy allowed) or htmlElementStatusHere (otherwise).
                   6425:  *     for Attribute nodes, a return from htmlAttrAllowed
                   6426:  *     for other nodes, HTML_NA (no checks performed)
                   6427:  */
                   6428: htmlStatus
                   6429: htmlNodeStatus(const htmlNodePtr node, int legacy) {
                   6430:   if ( ! node )
                   6431:     return HTML_INVALID ;
                   6432: 
                   6433:   switch ( node->type ) {
                   6434:     case XML_ELEMENT_NODE:
                   6435:       return legacy
                   6436:        ? ( htmlElementAllowedHere (
                   6437:                htmlTagLookup(node->parent->name) , node->name
                   6438:                ) ? HTML_VALID : HTML_INVALID )
                   6439:        : htmlElementStatusHere(
                   6440:                htmlTagLookup(node->parent->name) ,
                   6441:                htmlTagLookup(node->name) )
                   6442:        ;
                   6443:     case XML_ATTRIBUTE_NODE:
                   6444:       return htmlAttrAllowed(
                   6445:        htmlTagLookup(node->parent->name) , node->name, legacy) ;
                   6446:     default: return HTML_NA ;
                   6447:   }
                   6448: }
                   6449: /************************************************************************
                   6450:  *                                                                     *
                   6451:  *     New set (2.6.0) of simpler and more flexible APIs               *
                   6452:  *                                                                     *
                   6453:  ************************************************************************/
                   6454: /**
                   6455:  * DICT_FREE:
                   6456:  * @str:  a string
                   6457:  *
                   6458:  * Free a string if it is not owned by the "dict" dictionnary in the
                   6459:  * current scope
                   6460:  */
                   6461: #define DICT_FREE(str)                                         \
                   6462:        if ((str) && ((!dict) ||                                \
                   6463:            (xmlDictOwns(dict, (const xmlChar *)(str)) == 0)))  \
                   6464:            xmlFree((char *)(str));
                   6465: 
                   6466: /**
                   6467:  * htmlCtxtReset:
                   6468:  * @ctxt: an HTML parser context
                   6469:  *
                   6470:  * Reset a parser context
                   6471:  */
                   6472: void
                   6473: htmlCtxtReset(htmlParserCtxtPtr ctxt)
                   6474: {
                   6475:     xmlParserInputPtr input;
                   6476:     xmlDictPtr dict;
                   6477: 
                   6478:     if (ctxt == NULL)
                   6479:         return;
                   6480: 
                   6481:     xmlInitParser();
                   6482:     dict = ctxt->dict;
                   6483: 
                   6484:     while ((input = inputPop(ctxt)) != NULL) { /* Non consuming */
                   6485:         xmlFreeInputStream(input);
                   6486:     }
                   6487:     ctxt->inputNr = 0;
                   6488:     ctxt->input = NULL;
                   6489: 
                   6490:     ctxt->spaceNr = 0;
                   6491:     if (ctxt->spaceTab != NULL) {
                   6492:        ctxt->spaceTab[0] = -1;
                   6493:        ctxt->space = &ctxt->spaceTab[0];
                   6494:     } else {
                   6495:        ctxt->space = NULL;
                   6496:     }
                   6497: 
                   6498: 
                   6499:     ctxt->nodeNr = 0;
                   6500:     ctxt->node = NULL;
                   6501: 
                   6502:     ctxt->nameNr = 0;
                   6503:     ctxt->name = NULL;
                   6504: 
                   6505:     DICT_FREE(ctxt->version);
                   6506:     ctxt->version = NULL;
                   6507:     DICT_FREE(ctxt->encoding);
                   6508:     ctxt->encoding = NULL;
                   6509:     DICT_FREE(ctxt->directory);
                   6510:     ctxt->directory = NULL;
                   6511:     DICT_FREE(ctxt->extSubURI);
                   6512:     ctxt->extSubURI = NULL;
                   6513:     DICT_FREE(ctxt->extSubSystem);
                   6514:     ctxt->extSubSystem = NULL;
                   6515:     if (ctxt->myDoc != NULL)
                   6516:         xmlFreeDoc(ctxt->myDoc);
                   6517:     ctxt->myDoc = NULL;
                   6518: 
                   6519:     ctxt->standalone = -1;
                   6520:     ctxt->hasExternalSubset = 0;
                   6521:     ctxt->hasPErefs = 0;
                   6522:     ctxt->html = 1;
                   6523:     ctxt->external = 0;
                   6524:     ctxt->instate = XML_PARSER_START;
                   6525:     ctxt->token = 0;
                   6526: 
                   6527:     ctxt->wellFormed = 1;
                   6528:     ctxt->nsWellFormed = 1;
                   6529:     ctxt->disableSAX = 0;
                   6530:     ctxt->valid = 1;
                   6531:     ctxt->vctxt.userData = ctxt;
                   6532:     ctxt->vctxt.error = xmlParserValidityError;
                   6533:     ctxt->vctxt.warning = xmlParserValidityWarning;
                   6534:     ctxt->record_info = 0;
                   6535:     ctxt->nbChars = 0;
                   6536:     ctxt->checkIndex = 0;
                   6537:     ctxt->inSubset = 0;
                   6538:     ctxt->errNo = XML_ERR_OK;
                   6539:     ctxt->depth = 0;
                   6540:     ctxt->charset = XML_CHAR_ENCODING_NONE;
                   6541:     ctxt->catalogs = NULL;
                   6542:     xmlInitNodeInfoSeq(&ctxt->node_seq);
                   6543: 
                   6544:     if (ctxt->attsDefault != NULL) {
                   6545:         xmlHashFree(ctxt->attsDefault, (xmlHashDeallocator) xmlFree);
                   6546:         ctxt->attsDefault = NULL;
                   6547:     }
                   6548:     if (ctxt->attsSpecial != NULL) {
                   6549:         xmlHashFree(ctxt->attsSpecial, NULL);
                   6550:         ctxt->attsSpecial = NULL;
                   6551:     }
                   6552: }
                   6553: 
                   6554: /**
                   6555:  * htmlCtxtUseOptions:
                   6556:  * @ctxt: an HTML parser context
                   6557:  * @options:  a combination of htmlParserOption(s)
                   6558:  *
                   6559:  * Applies the options to the parser context
                   6560:  *
                   6561:  * Returns 0 in case of success, the set of unknown or unimplemented options
                   6562:  *         in case of error.
                   6563:  */
                   6564: int
                   6565: htmlCtxtUseOptions(htmlParserCtxtPtr ctxt, int options)
                   6566: {
                   6567:     if (ctxt == NULL)
                   6568:         return(-1);
                   6569: 
                   6570:     if (options & HTML_PARSE_NOWARNING) {
                   6571:         ctxt->sax->warning = NULL;
                   6572:         ctxt->vctxt.warning = NULL;
                   6573:         options -= XML_PARSE_NOWARNING;
                   6574:        ctxt->options |= XML_PARSE_NOWARNING;
                   6575:     }
                   6576:     if (options & HTML_PARSE_NOERROR) {
                   6577:         ctxt->sax->error = NULL;
                   6578:         ctxt->vctxt.error = NULL;
                   6579:         ctxt->sax->fatalError = NULL;
                   6580:         options -= XML_PARSE_NOERROR;
                   6581:        ctxt->options |= XML_PARSE_NOERROR;
                   6582:     }
                   6583:     if (options & HTML_PARSE_PEDANTIC) {
                   6584:         ctxt->pedantic = 1;
                   6585:         options -= XML_PARSE_PEDANTIC;
                   6586:        ctxt->options |= XML_PARSE_PEDANTIC;
                   6587:     } else
                   6588:         ctxt->pedantic = 0;
                   6589:     if (options & XML_PARSE_NOBLANKS) {
                   6590:         ctxt->keepBlanks = 0;
                   6591:         ctxt->sax->ignorableWhitespace = xmlSAX2IgnorableWhitespace;
                   6592:         options -= XML_PARSE_NOBLANKS;
                   6593:        ctxt->options |= XML_PARSE_NOBLANKS;
                   6594:     } else
                   6595:         ctxt->keepBlanks = 1;
                   6596:     if (options & HTML_PARSE_RECOVER) {
                   6597:         ctxt->recovery = 1;
                   6598:        options -= HTML_PARSE_RECOVER;
                   6599:     } else
                   6600:         ctxt->recovery = 0;
                   6601:     if (options & HTML_PARSE_COMPACT) {
                   6602:        ctxt->options |= HTML_PARSE_COMPACT;
                   6603:         options -= HTML_PARSE_COMPACT;
                   6604:     }
                   6605:     if (options & XML_PARSE_HUGE) {
                   6606:        ctxt->options |= XML_PARSE_HUGE;
                   6607:         options -= XML_PARSE_HUGE;
                   6608:     }
                   6609:     if (options & HTML_PARSE_NODEFDTD) {
                   6610:        ctxt->options |= HTML_PARSE_NODEFDTD;
                   6611:         options -= HTML_PARSE_NODEFDTD;
                   6612:     }
1.1.1.2 ! misho    6613:     if (options & HTML_PARSE_IGNORE_ENC) {
        !          6614:        ctxt->options |= HTML_PARSE_IGNORE_ENC;
        !          6615:         options -= HTML_PARSE_IGNORE_ENC;
        !          6616:     }
        !          6617:     if (options & HTML_PARSE_NOIMPLIED) {
        !          6618:         ctxt->options |= HTML_PARSE_NOIMPLIED;
        !          6619:         options -= HTML_PARSE_NOIMPLIED;
        !          6620:     }
1.1       misho    6621:     ctxt->dictNames = 0;
                   6622:     return (options);
                   6623: }
                   6624: 
                   6625: /**
                   6626:  * htmlDoRead:
                   6627:  * @ctxt:  an HTML parser context
                   6628:  * @URL:  the base URL to use for the document
                   6629:  * @encoding:  the document encoding, or NULL
                   6630:  * @options:  a combination of htmlParserOption(s)
                   6631:  * @reuse:  keep the context for reuse
                   6632:  *
                   6633:  * Common front-end for the htmlRead functions
                   6634:  *
                   6635:  * Returns the resulting document tree or NULL
                   6636:  */
                   6637: static htmlDocPtr
                   6638: htmlDoRead(htmlParserCtxtPtr ctxt, const char *URL, const char *encoding,
                   6639:           int options, int reuse)
                   6640: {
                   6641:     htmlDocPtr ret;
                   6642: 
                   6643:     htmlCtxtUseOptions(ctxt, options);
                   6644:     ctxt->html = 1;
                   6645:     if (encoding != NULL) {
                   6646:         xmlCharEncodingHandlerPtr hdlr;
                   6647: 
                   6648:        hdlr = xmlFindCharEncodingHandler(encoding);
                   6649:        if (hdlr != NULL) {
                   6650:            xmlSwitchToEncoding(ctxt, hdlr);
                   6651:            if (ctxt->input->encoding != NULL)
                   6652:              xmlFree((xmlChar *) ctxt->input->encoding);
                   6653:             ctxt->input->encoding = xmlStrdup((xmlChar *)encoding);
                   6654:         }
                   6655:     }
                   6656:     if ((URL != NULL) && (ctxt->input != NULL) &&
                   6657:         (ctxt->input->filename == NULL))
                   6658:         ctxt->input->filename = (char *) xmlStrdup((const xmlChar *) URL);
                   6659:     htmlParseDocument(ctxt);
                   6660:     ret = ctxt->myDoc;
                   6661:     ctxt->myDoc = NULL;
                   6662:     if (!reuse) {
                   6663:         if ((ctxt->dictNames) &&
                   6664:            (ret != NULL) &&
                   6665:            (ret->dict == ctxt->dict))
                   6666:            ctxt->dict = NULL;
                   6667:        xmlFreeParserCtxt(ctxt);
                   6668:     }
                   6669:     return (ret);
                   6670: }
                   6671: 
                   6672: /**
                   6673:  * htmlReadDoc:
                   6674:  * @cur:  a pointer to a zero terminated string
                   6675:  * @URL:  the base URL to use for the document
                   6676:  * @encoding:  the document encoding, or NULL
                   6677:  * @options:  a combination of htmlParserOption(s)
                   6678:  *
                   6679:  * parse an XML in-memory document and build a tree.
                   6680:  *
                   6681:  * Returns the resulting document tree
                   6682:  */
                   6683: htmlDocPtr
                   6684: htmlReadDoc(const xmlChar * cur, const char *URL, const char *encoding, int options)
                   6685: {
                   6686:     htmlParserCtxtPtr ctxt;
                   6687: 
                   6688:     if (cur == NULL)
                   6689:         return (NULL);
                   6690: 
                   6691:     xmlInitParser();
                   6692:     ctxt = htmlCreateDocParserCtxt(cur, NULL);
                   6693:     if (ctxt == NULL)
                   6694:         return (NULL);
                   6695:     return (htmlDoRead(ctxt, URL, encoding, options, 0));
                   6696: }
                   6697: 
                   6698: /**
                   6699:  * htmlReadFile:
                   6700:  * @filename:  a file or URL
                   6701:  * @encoding:  the document encoding, or NULL
                   6702:  * @options:  a combination of htmlParserOption(s)
                   6703:  *
                   6704:  * parse an XML file from the filesystem or the network.
                   6705:  *
                   6706:  * Returns the resulting document tree
                   6707:  */
                   6708: htmlDocPtr
                   6709: htmlReadFile(const char *filename, const char *encoding, int options)
                   6710: {
                   6711:     htmlParserCtxtPtr ctxt;
                   6712: 
                   6713:     xmlInitParser();
                   6714:     ctxt = htmlCreateFileParserCtxt(filename, encoding);
                   6715:     if (ctxt == NULL)
                   6716:         return (NULL);
                   6717:     return (htmlDoRead(ctxt, NULL, NULL, options, 0));
                   6718: }
                   6719: 
                   6720: /**
                   6721:  * htmlReadMemory:
                   6722:  * @buffer:  a pointer to a char array
                   6723:  * @size:  the size of the array
                   6724:  * @URL:  the base URL to use for the document
                   6725:  * @encoding:  the document encoding, or NULL
                   6726:  * @options:  a combination of htmlParserOption(s)
                   6727:  *
                   6728:  * parse an XML in-memory document and build a tree.
                   6729:  *
                   6730:  * Returns the resulting document tree
                   6731:  */
                   6732: htmlDocPtr
                   6733: htmlReadMemory(const char *buffer, int size, const char *URL, const char *encoding, int options)
                   6734: {
                   6735:     htmlParserCtxtPtr ctxt;
                   6736: 
                   6737:     xmlInitParser();
                   6738:     ctxt = xmlCreateMemoryParserCtxt(buffer, size);
                   6739:     if (ctxt == NULL)
                   6740:         return (NULL);
                   6741:     htmlDefaultSAXHandlerInit();
                   6742:     if (ctxt->sax != NULL)
                   6743:         memcpy(ctxt->sax, &htmlDefaultSAXHandler, sizeof(xmlSAXHandlerV1));
                   6744:     return (htmlDoRead(ctxt, URL, encoding, options, 0));
                   6745: }
                   6746: 
                   6747: /**
                   6748:  * htmlReadFd:
                   6749:  * @fd:  an open file descriptor
                   6750:  * @URL:  the base URL to use for the document
                   6751:  * @encoding:  the document encoding, or NULL
                   6752:  * @options:  a combination of htmlParserOption(s)
                   6753:  *
                   6754:  * parse an XML from a file descriptor and build a tree.
                   6755:  *
                   6756:  * Returns the resulting document tree
                   6757:  */
                   6758: htmlDocPtr
                   6759: htmlReadFd(int fd, const char *URL, const char *encoding, int options)
                   6760: {
                   6761:     htmlParserCtxtPtr ctxt;
                   6762:     xmlParserInputBufferPtr input;
                   6763:     xmlParserInputPtr stream;
                   6764: 
                   6765:     if (fd < 0)
                   6766:         return (NULL);
                   6767: 
                   6768:     xmlInitParser();
                   6769:     input = xmlParserInputBufferCreateFd(fd, XML_CHAR_ENCODING_NONE);
                   6770:     if (input == NULL)
                   6771:         return (NULL);
                   6772:     ctxt = xmlNewParserCtxt();
                   6773:     if (ctxt == NULL) {
                   6774:         xmlFreeParserInputBuffer(input);
                   6775:         return (NULL);
                   6776:     }
                   6777:     stream = xmlNewIOInputStream(ctxt, input, XML_CHAR_ENCODING_NONE);
                   6778:     if (stream == NULL) {
                   6779:         xmlFreeParserInputBuffer(input);
                   6780:        xmlFreeParserCtxt(ctxt);
                   6781:         return (NULL);
                   6782:     }
                   6783:     inputPush(ctxt, stream);
                   6784:     return (htmlDoRead(ctxt, URL, encoding, options, 0));
                   6785: }
                   6786: 
                   6787: /**
                   6788:  * htmlReadIO:
                   6789:  * @ioread:  an I/O read function
                   6790:  * @ioclose:  an I/O close function
                   6791:  * @ioctx:  an I/O handler
                   6792:  * @URL:  the base URL to use for the document
                   6793:  * @encoding:  the document encoding, or NULL
                   6794:  * @options:  a combination of htmlParserOption(s)
                   6795:  *
                   6796:  * parse an HTML document from I/O functions and source and build a tree.
                   6797:  *
                   6798:  * Returns the resulting document tree
                   6799:  */
                   6800: htmlDocPtr
                   6801: htmlReadIO(xmlInputReadCallback ioread, xmlInputCloseCallback ioclose,
                   6802:           void *ioctx, const char *URL, const char *encoding, int options)
                   6803: {
                   6804:     htmlParserCtxtPtr ctxt;
                   6805:     xmlParserInputBufferPtr input;
                   6806:     xmlParserInputPtr stream;
                   6807: 
                   6808:     if (ioread == NULL)
                   6809:         return (NULL);
                   6810:     xmlInitParser();
                   6811: 
                   6812:     input = xmlParserInputBufferCreateIO(ioread, ioclose, ioctx,
                   6813:                                          XML_CHAR_ENCODING_NONE);
1.1.1.2 ! misho    6814:     if (input == NULL) {
        !          6815:         if (ioclose != NULL)
        !          6816:             ioclose(ioctx);
1.1       misho    6817:         return (NULL);
1.1.1.2 ! misho    6818:     }
1.1       misho    6819:     ctxt = htmlNewParserCtxt();
                   6820:     if (ctxt == NULL) {
                   6821:         xmlFreeParserInputBuffer(input);
                   6822:         return (NULL);
                   6823:     }
                   6824:     stream = xmlNewIOInputStream(ctxt, input, XML_CHAR_ENCODING_NONE);
                   6825:     if (stream == NULL) {
                   6826:         xmlFreeParserInputBuffer(input);
                   6827:        xmlFreeParserCtxt(ctxt);
                   6828:         return (NULL);
                   6829:     }
                   6830:     inputPush(ctxt, stream);
                   6831:     return (htmlDoRead(ctxt, URL, encoding, options, 0));
                   6832: }
                   6833: 
                   6834: /**
                   6835:  * htmlCtxtReadDoc:
                   6836:  * @ctxt:  an HTML parser context
                   6837:  * @cur:  a pointer to a zero terminated string
                   6838:  * @URL:  the base URL to use for the document
                   6839:  * @encoding:  the document encoding, or NULL
                   6840:  * @options:  a combination of htmlParserOption(s)
                   6841:  *
                   6842:  * parse an XML in-memory document and build a tree.
                   6843:  * This reuses the existing @ctxt parser context
                   6844:  *
                   6845:  * Returns the resulting document tree
                   6846:  */
                   6847: htmlDocPtr
                   6848: htmlCtxtReadDoc(htmlParserCtxtPtr ctxt, const xmlChar * cur,
                   6849:                const char *URL, const char *encoding, int options)
                   6850: {
                   6851:     xmlParserInputPtr stream;
                   6852: 
                   6853:     if (cur == NULL)
                   6854:         return (NULL);
                   6855:     if (ctxt == NULL)
                   6856:         return (NULL);
                   6857: 
                   6858:     htmlCtxtReset(ctxt);
                   6859: 
                   6860:     stream = xmlNewStringInputStream(ctxt, cur);
                   6861:     if (stream == NULL) {
                   6862:         return (NULL);
                   6863:     }
                   6864:     inputPush(ctxt, stream);
                   6865:     return (htmlDoRead(ctxt, URL, encoding, options, 1));
                   6866: }
                   6867: 
                   6868: /**
                   6869:  * htmlCtxtReadFile:
                   6870:  * @ctxt:  an HTML parser context
                   6871:  * @filename:  a file or URL
                   6872:  * @encoding:  the document encoding, or NULL
                   6873:  * @options:  a combination of htmlParserOption(s)
                   6874:  *
                   6875:  * parse an XML file from the filesystem or the network.
                   6876:  * This reuses the existing @ctxt parser context
                   6877:  *
                   6878:  * Returns the resulting document tree
                   6879:  */
                   6880: htmlDocPtr
                   6881: htmlCtxtReadFile(htmlParserCtxtPtr ctxt, const char *filename,
                   6882:                 const char *encoding, int options)
                   6883: {
                   6884:     xmlParserInputPtr stream;
                   6885: 
                   6886:     if (filename == NULL)
                   6887:         return (NULL);
                   6888:     if (ctxt == NULL)
                   6889:         return (NULL);
                   6890: 
                   6891:     htmlCtxtReset(ctxt);
                   6892: 
                   6893:     stream = xmlLoadExternalEntity(filename, NULL, ctxt);
                   6894:     if (stream == NULL) {
                   6895:         return (NULL);
                   6896:     }
                   6897:     inputPush(ctxt, stream);
                   6898:     return (htmlDoRead(ctxt, NULL, encoding, options, 1));
                   6899: }
                   6900: 
                   6901: /**
                   6902:  * htmlCtxtReadMemory:
                   6903:  * @ctxt:  an HTML parser context
                   6904:  * @buffer:  a pointer to a char array
                   6905:  * @size:  the size of the array
                   6906:  * @URL:  the base URL to use for the document
                   6907:  * @encoding:  the document encoding, or NULL
                   6908:  * @options:  a combination of htmlParserOption(s)
                   6909:  *
                   6910:  * parse an XML in-memory document and build a tree.
                   6911:  * This reuses the existing @ctxt parser context
                   6912:  *
                   6913:  * Returns the resulting document tree
                   6914:  */
                   6915: htmlDocPtr
                   6916: htmlCtxtReadMemory(htmlParserCtxtPtr ctxt, const char *buffer, int size,
                   6917:                   const char *URL, const char *encoding, int options)
                   6918: {
                   6919:     xmlParserInputBufferPtr input;
                   6920:     xmlParserInputPtr stream;
                   6921: 
                   6922:     if (ctxt == NULL)
                   6923:         return (NULL);
                   6924:     if (buffer == NULL)
                   6925:         return (NULL);
                   6926: 
                   6927:     htmlCtxtReset(ctxt);
                   6928: 
                   6929:     input = xmlParserInputBufferCreateMem(buffer, size, XML_CHAR_ENCODING_NONE);
                   6930:     if (input == NULL) {
                   6931:        return(NULL);
                   6932:     }
                   6933: 
                   6934:     stream = xmlNewIOInputStream(ctxt, input, XML_CHAR_ENCODING_NONE);
                   6935:     if (stream == NULL) {
                   6936:        xmlFreeParserInputBuffer(input);
                   6937:        return(NULL);
                   6938:     }
                   6939: 
                   6940:     inputPush(ctxt, stream);
                   6941:     return (htmlDoRead(ctxt, URL, encoding, options, 1));
                   6942: }
                   6943: 
                   6944: /**
                   6945:  * htmlCtxtReadFd:
                   6946:  * @ctxt:  an HTML parser context
                   6947:  * @fd:  an open file descriptor
                   6948:  * @URL:  the base URL to use for the document
                   6949:  * @encoding:  the document encoding, or NULL
                   6950:  * @options:  a combination of htmlParserOption(s)
                   6951:  *
                   6952:  * parse an XML from a file descriptor and build a tree.
                   6953:  * This reuses the existing @ctxt parser context
                   6954:  *
                   6955:  * Returns the resulting document tree
                   6956:  */
                   6957: htmlDocPtr
                   6958: htmlCtxtReadFd(htmlParserCtxtPtr ctxt, int fd,
                   6959:               const char *URL, const char *encoding, int options)
                   6960: {
                   6961:     xmlParserInputBufferPtr input;
                   6962:     xmlParserInputPtr stream;
                   6963: 
                   6964:     if (fd < 0)
                   6965:         return (NULL);
                   6966:     if (ctxt == NULL)
                   6967:         return (NULL);
                   6968: 
                   6969:     htmlCtxtReset(ctxt);
                   6970: 
                   6971: 
                   6972:     input = xmlParserInputBufferCreateFd(fd, XML_CHAR_ENCODING_NONE);
                   6973:     if (input == NULL)
                   6974:         return (NULL);
                   6975:     stream = xmlNewIOInputStream(ctxt, input, XML_CHAR_ENCODING_NONE);
                   6976:     if (stream == NULL) {
                   6977:         xmlFreeParserInputBuffer(input);
                   6978:         return (NULL);
                   6979:     }
                   6980:     inputPush(ctxt, stream);
                   6981:     return (htmlDoRead(ctxt, URL, encoding, options, 1));
                   6982: }
                   6983: 
                   6984: /**
                   6985:  * htmlCtxtReadIO:
                   6986:  * @ctxt:  an HTML parser context
                   6987:  * @ioread:  an I/O read function
                   6988:  * @ioclose:  an I/O close function
                   6989:  * @ioctx:  an I/O handler
                   6990:  * @URL:  the base URL to use for the document
                   6991:  * @encoding:  the document encoding, or NULL
                   6992:  * @options:  a combination of htmlParserOption(s)
                   6993:  *
                   6994:  * parse an HTML document from I/O functions and source and build a tree.
                   6995:  * This reuses the existing @ctxt parser context
                   6996:  *
                   6997:  * Returns the resulting document tree
                   6998:  */
                   6999: htmlDocPtr
                   7000: htmlCtxtReadIO(htmlParserCtxtPtr ctxt, xmlInputReadCallback ioread,
                   7001:               xmlInputCloseCallback ioclose, void *ioctx,
                   7002:              const char *URL,
                   7003:               const char *encoding, int options)
                   7004: {
                   7005:     xmlParserInputBufferPtr input;
                   7006:     xmlParserInputPtr stream;
                   7007: 
                   7008:     if (ioread == NULL)
                   7009:         return (NULL);
                   7010:     if (ctxt == NULL)
                   7011:         return (NULL);
                   7012: 
                   7013:     htmlCtxtReset(ctxt);
                   7014: 
                   7015:     input = xmlParserInputBufferCreateIO(ioread, ioclose, ioctx,
                   7016:                                          XML_CHAR_ENCODING_NONE);
1.1.1.2 ! misho    7017:     if (input == NULL) {
        !          7018:         if (ioclose != NULL)
        !          7019:             ioclose(ioctx);
1.1       misho    7020:         return (NULL);
1.1.1.2 ! misho    7021:     }
1.1       misho    7022:     stream = xmlNewIOInputStream(ctxt, input, XML_CHAR_ENCODING_NONE);
                   7023:     if (stream == NULL) {
                   7024:         xmlFreeParserInputBuffer(input);
                   7025:         return (NULL);
                   7026:     }
                   7027:     inputPush(ctxt, stream);
                   7028:     return (htmlDoRead(ctxt, URL, encoding, options, 1));
                   7029: }
                   7030: 
                   7031: #define bottom_HTMLparser
                   7032: #include "elfgcchack.h"
                   7033: #endif /* LIBXML_HTML_ENABLED */

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>