", xcp->pfout);
+- return 1;
+-}
+-
+-/* GetBaseDir gets path from string into
+- string (which must be allocated for strlen(fullfile)+1)*/
+-void GetBaseDir(unsigned char *fullfile, unsigned char *targetdir)
+-{
+- int slash = strlen(fullfile);
+- while(slash && *(fullfile+slash) != '/') slash--;
+- if (slash) {
+- memcpy(targetdir, fullfile, slash+1);
+- targetdir[slash+1] = '\0';
+- }
+- else {
+- targetdir[0] = '\0';
+- }
+-}
+-
+-int RunTestResolveEntity(void *UserData, LPXMLENTITY entity, LPBUFFEREDISTREAM reader)
+-{
+- char testuri[MAX_PATH];
+- FILE *f;
+-
+- strcpy(testuri, (XMLCH*)UserData); /* UserData contains testbasedir */
+- strcat(testuri, entity->systemID);
+-
+- if (!(f = fopen(testuri, "rb"))) {
+- fprintf(PFERR, "Error opening file %s\n", testuri);
+- return XML_ABORT;
+- }
+- reader->inputData = f;
+- return 0;
+-}
+-
+-void RunTestErrorHandler(LPXMLPARSER parser)
+-{} /* dummy, only for switching detailed error information on */
+-
+-/* RUNTEST PARSER END */
+-
+-int main(int argc, char* argv[])
+-{
+- LPXMLPARSER parser;
+- XMLCONFPARSER parserdata;
+- FILE *f;
+-
+- #ifdef _MSC_VER
+- #ifdef _DEBUG
+- int tmpFlag = _CrtSetDbgFlag( _CRTDBG_REPORT_FLAG );
+- // Turn on leak-checking bit
+- tmpFlag |= _CRTDBG_LEAK_CHECK_DF; /* dump leaks to output */
+- // Set flag to the new value
+- _CrtSetDbgFlag( tmpFlag );
+- #endif
+- #endif
+-
+- if (argc != 3) {
+- fprintf(PFERR, "Give filenames e.g. C:\\XMLCONF\\XMLCONF.XML RESULTS.HTML\n");
+- return 1;
+- }
+-
+- if (!XMLParser_Create(&parser)) {
+- fprintf(PFERR, "Error creating main parser in main()\n");
+- return 1;
+- }
+-
+- /* we could create new parser in RunTest every time we're running
+- new test, but for extra stress testing we're using the
+- same parser: */
+- if (!XMLParser_Create(&parserdata.runParser)) {
+- fprintf(PFERR, "Error creating runParser in main()\n");
+- return 1;
+- }
+-
+- if (!XMLVector_Create(&parserdata.stateStack, 6, sizeof(int))) {
+- fprintf(PFERR, "Error creating stack in main()\n");
+- return 1;
+- }
+-
+- parser->startElementHandler = StartElement;
+- parser->endElementHandler = EndElement;
+- parser->charactersHandler = Characters;
+- parser->errorHandler = ErrorHandler;
+- parser->resolveEntityHandler = ResolveEntity;
+- parser->externalEntityParsedHandler = FreeInputData;
+- parser->UserData = &parserdata;
+-
+- parserdata.parser = parser;
+- parserdata.inMixedContent = 0;
+- parserdata.testCount = 0;
+- parserdata.testSuccess = 0;
+-
+-
+- if (!(f = fopen(VERSIONFILE, "r"))) {
+- fprintf(PFERR, "Error opening VERSION file\n");
+- return 1;
+- }
+- fgets(parserdata.version, 20, f);
+- fclose(f);
+-
+- if (!(f = fopen(argv[1], "rb"))) {
+- fprintf(PFERR, "Error opening input file %s\n", argv[1]);
+- return 1;
+- }
+-
+- if (!(parserdata.pfout = fopen(argv[2], "wb"))) {
+- fprintf(PFERR, "Error opening output file %s\n", argv[2]);
+- return 1;
+- }
+-
+- fprintf(PFERR, "Running testsuite %s, please wait...", argv[1]);
+- fputs("", parserdata.pfout);
+-
+- XMLParser_Parse(parser, cstream, f, NULL);
+-
+- fprintf(parserdata.pfout, "
%d tests successful out of total %d.",
+- parserdata.testSuccess, parserdata.testCount);
+- fputs("", parserdata.pfout);
+-
+- fclose(f);
+- fclose(parserdata.pfout);
+- XMLVector_Free(parserdata.stateStack);
+- XMLParser_Free(parserdata.runParser);
+- XMLParser_Free(parser);
+- return 0;
+-}
+-
++#include
++#include
++#include
++#include "libparsifal/parsifal.h"
++
++#ifdef _MSC_VER
++ #ifdef _DEBUG
++ #include
++ #define _CRTDBG_MAP_ALLOC
++ #endif
++#endif
++
++#define OUTDIR "pxpout/"
++#define VERSIONFILE "VERSION"
++
++/* stack macros (from xmldef.h) */
++#define STACK_PUSH(stack,item) (XMLVector_Append((stack), (item)))
++#define STACK_PEEK(stack) (XMLVector_Get((stack),(stack)->length-1))
++#define STACK_REMOVE(stack) (XMLVector_Remove((stack), (stack)->length-1))
++#define STACK_POP(stack,item) \
++( ((stack)->length) ? (memcpy((item), STACK_PEEK((stack)), (stack)->itemSize), \
++STACK_REMOVE((stack)), (item)) : NULL)
++
++#define EMPTY_COLS(num, pfile) { int i; for (i=0; i<(num); i++) fputs(" | ", (pfile)); }
++
++#ifndef MAX_PATH
++#define MAX_PATH 256
++#endif
++
++enum tagSTATES { NONE, TESTSUITE, TESTCASES, TEST } STATES;
++
++#define PFOUT (((XMLCONFPARSER*)UserData)->pfout)
++#define PFERR stdout
++
++typedef struct tagXMLCONFPARSER {
++ LPXMLPARSER parser;
++ LPXMLVECTOR stateStack;
++ int state;
++ int inMixedContent;
++ /* these are xmlconf specific: */
++ LPXMLPARSER runParser;
++ int testCount;
++ int testSuccess;
++ FILE *pfout;
++ char version[20];
++} XMLCONFPARSER;
++
++/* common routines: */
++int cstream(BYTE *buf, int cBytes, int *cBytesActual, void *inputData);
++int FreeInputData(void *UserData, LPXMLENTITY entity, LPBUFFEREDISTREAM reader);
++
++/* TESTSUITE PARSER: */
++void PrintEsc(FILE *fp, const XMLCH *str, int len);
++int StartElement(void *UserData, const XMLCH *uri, const XMLCH *localName, const XMLCH *qName, LPXMLVECTOR atts);
++int EndElement(void *UserData, const XMLCH *uri, const XMLCH *localName, const XMLCH *qName);
++int Characters(void *UserData, const XMLCH *Chars, int cbChars);
++void ErrorHandler(LPXMLPARSER parser);
++int ResolveEntity(void *UserData, LPXMLENTITY entity, LPBUFFEREDISTREAM reader);
++
++/* RUNTEST PARSER: */
++int RunTest(XMLCONFPARSER *xcp, char *uri);
++int RunTestResolveEntity(void *UserData, LPXMLENTITY entity, LPBUFFEREDISTREAM reader);
++void RunTestErrorHandler(LPXMLPARSER parser);
++void GetBaseDir(unsigned char *fullfile, unsigned char *targetdir);
++extern int fcompare(const char *fnam1, const char *fnam2);
++
++int cstream(BYTE *buf, int cBytes, int *cBytesActual, void *inputData)
++{
++ *cBytesActual = fread(buf, 1, cBytes, (FILE*)inputData);
++ return (*cBytesActual < cBytes);
++}
++
++int FreeInputData(void *UserData, LPXMLENTITY entity, LPBUFFEREDISTREAM reader)
++{
++ fclose((FILE*)reader->inputData);
++ return 0;
++}
++
++/* TESTSUITE PARSER BEGIN */
++
++int StartElement(void *UserData, const XMLCH *uri, const XMLCH *localName, const XMLCH *qName, LPXMLVECTOR atts)
++{
++ XMLCONFPARSER *xcp = (XMLCONFPARSER*)UserData;
++ LPXMLRUNTIMEATT att;
++ int *pstate = STACK_PEEK(xcp->stateStack);
++ xcp->state = (pstate) ? *pstate : NONE;
++
++ if (xcp->inMixedContent || xcp->state == TEST) {
++ /* + other tags that allow mixed content tested here */
++ /* if we're in mixed content, we don't bother to use stack, just
++ incrementing (and decrementing in EndElement) the counter: */
++ xcp->inMixedContent++;
++ /* could call mixed content legal tag check routine here e.g.
++ if (!isvalidmixedcontent(state, qName)) return sin(); */
++ fprintf(PFOUT, "<%s>", qName);
++ return 0;
++ }
++
++ if (xcp->state == NONE && !strcmp(qName, "TESTSUITE")) {
++
++ if (att = XMLParser_GetNamedItem(xcp->parser, "PROFILE"))
++ fprintf(PFOUT, "%s
Parsifal XML Parser %s",
++ att->value, xcp->version);
++ xcp->state = TESTSUITE;
++ }
++ else if (xcp->state == TESTSUITE && !strcmp(qName, "TESTCASES")) {
++
++ if (att = XMLParser_GetNamedItem(xcp->parser, "PROFILE")) {
++ /* new testcase, spit out the profile header: */
++ fprintf(PFOUT, "
Testcase profile: %s ", att->value);
++ fputs("", PFOUT); /* open table for results */
++ }
++ xcp->state = TESTCASES;
++ }
++ else if (xcp->state == TESTCASES) {
++
++ if (!strcmp(qName, "TEST")) {
++ if (att = XMLParser_GetNamedItem(xcp->parser, "URI")) {
++ /* new test, run it: */
++ if (!RunTest(xcp, att->value)) {
++ fprintf(PFERR, "Fatal Error running test: %s\n", att->value);
++ return XML_ABORT;
++ }
++ }
++ xcp->state = TEST;
++ }
++ else if (!strcmp(qName, "TESTCASES")) { /* for some reason
++
++ there's TESTCASES inside TESTCASES in ibm tests,
++ so it must ust be handled here: */
++ xcp->state = TESTCASES;
++ }
++ }
++ else {
++ fprintf(PFERR, "Unexpected tag: %s\n", qName);
++ return XML_ABORT;
++ }
++
++ STACK_PUSH(xcp->stateStack, &xcp->state);
++ return 0;
++}
++
++int EndElement(void *UserData, const XMLCH *uri, const XMLCH *localName, const XMLCH *qName)
++{
++ XMLCONFPARSER *xcp = (XMLCONFPARSER*)UserData;
++ if (xcp->inMixedContent) {
++ xcp->inMixedContent--;
++ fprintf(PFOUT, "%s>", qName); /* EM or B tags */
++ }
++ else {
++ if (STACK_POP(xcp->stateStack, &xcp->state)) {
++ if (xcp->state == TEST) {
++ /* close TEST description column and row: */
++ fputs("", PFOUT);
++ EMPTY_COLS(3, PFOUT);
++ fputs("", PFOUT);
++ }
++ else if (xcp->state == TESTCASES) {
++ int *pstate = STACK_PEEK(xcp->stateStack);
++ /* check is needed 'cos there can be TESTCASES inside TESTCASES */
++ if (pstate && *pstate != TESTCASES) fputs(" ", PFOUT);
++ }
++ }
++ }
++ return 0;
++}
++
++void PrintEsc(FILE *fp, const XMLCH *str, int len)
++{
++ for (; len--; str++) {
++ switch(*str) {
++ case '&': fputs("&", fp); break;
++ case '\"': fputs(""", fp); break;
++ //case '\'': fprintf("'", fp); break;
++ case '<': fputs("<", fp); break;
++ case '>': fputs(">", fp); break;
++ case '\x9': fputs(" ", fp); break;
++ case '\xA': fputs("
", fp); break;
++ case '\xD': fputs("
", fp); break;
++ default: fputc(*str, fp); break;
++ }
++ }
++}
++
++int Characters(void *UserData, const XMLCH *Chars, int cbChars)
++{
++ XMLCONFPARSER *xcp = (XMLCONFPARSER*)UserData;
++ if (xcp->state == TEST)
++ PrintEsc(PFOUT, Chars, cbChars);
++ return 0;
++}
++
++void ErrorHandler(LPXMLPARSER parser)
++{
++ if (parser->ErrorCode != ERR_XMLP_ABORT) {
++ XMLCH *sysID = XMLParser_GetSystemID(parser);
++
++ if (sysID) fprintf(PFERR, "Parsing resource %s failed!\n", sysID);
++ fprintf(PFERR, "Error: %s\nCode: %d\nLine: %d\nColumn: %d\n",
++ parser->ErrorString, parser->ErrorCode,
++ parser->ErrorLine, parser->ErrorColumn);
++ }
++}
++
++int ResolveEntity(void *UserData, LPXMLENTITY entity, LPBUFFEREDISTREAM reader)
++{
++ FILE *f;
++ if (!(f = fopen(entity->systemID, "rb"))) {
++ fprintf(PFERR, "error opening file '%s'!\n", entity->systemID);
++ return XML_ABORT;
++ }
++ reader->inputData = f;
++ return 0;
++}
++/* TESTSUITE PARSER END */
++
++/* RUNTEST PARSER BEGIN */
++/* these are parser routines that run the test itself,
++ we don't need many event handlers for it only
++ resolveEntityHandler and related stuff */
++
++int RunTest(XMLCONFPARSER *xcp, char *uri)
++{
++ LPXMLRUNTIMEATT att;
++ XMLCH testuri[MAX_PATH];
++ XMLCH testbasedir[MAX_PATH];
++ XMLCH xmlbase[MAX_PATH];
++ XMLCH id[256];
++ XMLCH *s;
++ FILE *f;
++ int result, expect;
++ LPXMLPARSER parser = xcp->runParser;
++
++ xcp->testCount++;
++
++ if ((s = XMLParser_GetPrefixMapping(xcp->parser, "xml:base")))
++ strcpy(xmlbase, s); /* we save current xmlbase
++ (although it shouldn't get modified 'cos
++ main parser isn't running during RunTest()) */
++ else
++ xmlbase[0] = '\0';
++
++ strcpy(testuri, xmlbase);
++ strcat(testuri, uri);
++
++ puts(testuri);
++
++ /* make parsifal to report undefined entities and not to use skippedEntity: */
++ _XMLParser_SetFlag(parser, XMLFLAG_UNDEF_GENERAL_ENTITIES, 1);
++
++ /* assign handlers */
++ parser->errorHandler = RunTestErrorHandler;
++ parser->resolveEntityHandler = RunTestResolveEntity;
++ parser->externalEntityParsedHandler = FreeInputData;
++
++ /* resolve basedir for external entities, DTD and for canonxml */
++ GetBaseDir(testuri, testbasedir);
++ parser->UserData = testbasedir;
++
++ if ((f = fopen(testuri, "rb"))) {
++ result = XMLParser_Parse(parser, cstream, f, 0);
++ fclose(f);
++ }
++ else {
++ fprintf(PFERR, "Error opening file %s\n", testuri);
++ return 0;
++ }
++
++ /* 1 row columns: ID, TYPE, PASS/FAIL, ERRORSTRING
++ 2 row columns: ENTITIES + OUTPUT in one col, 3 empty cols
++ 3 row: test description, 3 empty cols
++ */
++ att = XMLParser_GetNamedItem(xcp->parser, "ID");
++ strcpy(id, (att) ? att->value : "unknown");
++ fputs((xcp->testCount % 2) ? "" : " ", xcp->pfout);
++ fprintf(xcp->pfout, "%s | ", testuri, id);
++
++ att = XMLParser_GetNamedItem(xcp->parser, "TYPE");
++ if (att) {
++ if (!strcmp(att->value, "valid")) expect = 1; /* hmm. we're not validating but... */
++ /* "Nonvalidating parsers must also accept "invalid" testcases,
++ but validating ones must reject them." */
++ else if (!strcmp(att->value, "invalid")) expect = 1;
++ else expect = 0; /* error, not-wf */
++ fprintf(xcp->pfout, "%s | ", att->value);
++ if (result == expect) xcp->testSuccess++;
++ }
++ else {
++ EMPTY_COLS(1, xcp->pfout);
++ }
++
++ fprintf(xcp->pfout, "", (result == expect) ? "#008000" : "#FF0000");
++ if (result)
++ fprintf(xcp->pfout, "PASS | | ");
++ else {
++ fputs("FAIL", xcp->pfout);
++ PrintEsc(xcp->pfout, parser->ErrorString, strlen(parser->ErrorString));
++ fputs(" | ", xcp->pfout);
++ }
++
++ fputs(" ", xcp->pfout);
++ fputs((xcp->testCount % 2) ? "" : " ", xcp->pfout);
++
++ if ((att = XMLParser_GetNamedItem(xcp->parser, "ENTITIES")))
++ fprintf(xcp->pfout, "entities: %s ", att->value);
++ else
++ fputs(" | ", xcp->pfout);
++
++ /* OUTPUT TEST */
++ att = XMLParser_GetNamedItem(xcp->parser, "OUTPUT");
++ if (att) {
++ int compres;
++ XMLCH cmd[2048];
++ XMLCH outfile1[MAX_PATH], outfile2[MAX_PATH];
++
++ strcpy(outfile1, xmlbase);
++ strcat(outfile1, att->value);
++
++ strcpy(outfile2, OUTDIR);
++ strcat(outfile2, id);
++ strcat(outfile2, ".xml");
++
++ strcpy(cmd, "canonxml ");
++ strcat(cmd, testuri);
++ strcat(cmd, " ");
++ strcat(cmd, outfile2);
++ strcat(cmd, " ");
++ strcat(cmd, testbasedir);
++ system(cmd);
++
++ compres = fcompare(outfile1, outfile2);
++
++ fprintf(xcp->pfout, "OUTPUT:",
++ (!compres) ? "#008000" : "#FF0000");
++ if (compres == -1)
++ fputs(" error", xcp->pfout);
++ else
++ fprintf(xcp->pfout, " 1 2", outfile1, outfile2);
++ }
++ else {
++ fputs(" | ", xcp->pfout);
++ }
++ /* OUTPUT TEST END */
++
++ if (!parser->ErrorCode) {
++ EMPTY_COLS(3, xcp->pfout);
++ }
++ else {
++ EMPTY_COLS(2, xcp->pfout);
++ fprintf(xcp->pfout, "Line: %d Col: %d | ", parser->ErrorLine, parser->ErrorColumn);
++ }
++
++ fputs(" ", xcp->pfout);
++ /* open new table row for test description (reported via Characters): */
++ fputs((xcp->testCount % 2) ? "" : " | ", xcp->pfout);
++ return 1;
++}
++
++/* GetBaseDir gets path from string into
++ string (which must be allocated for strlen(fullfile)+1)*/
++void GetBaseDir(unsigned char *fullfile, unsigned char *targetdir)
++{
++ int slash = strlen(fullfile);
++ while(slash && *(fullfile+slash) != '/') slash--;
++ if (slash) {
++ memcpy(targetdir, fullfile, slash+1);
++ targetdir[slash+1] = '\0';
++ }
++ else {
++ targetdir[0] = '\0';
++ }
++}
++
++int RunTestResolveEntity(void *UserData, LPXMLENTITY entity, LPBUFFEREDISTREAM reader)
++{
++ char testuri[MAX_PATH];
++ FILE *f;
++
++ strcpy(testuri, (XMLCH*)UserData); /* UserData contains testbasedir */
++ strcat(testuri, entity->systemID);
++
++ if (!(f = fopen(testuri, "rb"))) {
++ fprintf(PFERR, "Error opening file %s\n", testuri);
++ return XML_ABORT;
++ }
++ reader->inputData = f;
++ return 0;
++}
++
++void RunTestErrorHandler(LPXMLPARSER parser)
++{} /* dummy, only for switching detailed error information on */
++
++/* RUNTEST PARSER END */
++
++int main(int argc, char* argv[])
++{
++ LPXMLPARSER parser;
++ XMLCONFPARSER parserdata;
++ FILE *f;
++
++ #ifdef _MSC_VER
++ #ifdef _DEBUG
++ int tmpFlag = _CrtSetDbgFlag( _CRTDBG_REPORT_FLAG );
++ // Turn on leak-checking bit
++ tmpFlag |= _CRTDBG_LEAK_CHECK_DF; /* dump leaks to output */
++ // Set flag to the new value
++ _CrtSetDbgFlag( tmpFlag );
++ #endif
++ #endif
++
++ if (argc != 3) {
++ fprintf(PFERR, "Give filenames e.g. C:\\XMLCONF\\XMLCONF.XML RESULTS.HTML\n");
++ return 1;
++ }
++
++ if (!XMLParser_Create(&parser)) {
++ fprintf(PFERR, "Error creating main parser in main()\n");
++ return 1;
++ }
++
++ /* we could create new parser in RunTest every time we're running
++ new test, but for extra stress testing we're using the
++ same parser: */
++ if (!XMLParser_Create(&parserdata.runParser)) {
++ fprintf(PFERR, "Error creating runParser in main()\n");
++ return 1;
++ }
++
++ if (!XMLVector_Create(&parserdata.stateStack, 6, sizeof(int))) {
++ fprintf(PFERR, "Error creating stack in main()\n");
++ return 1;
++ }
++
++ parser->startElementHandler = StartElement;
++ parser->endElementHandler = EndElement;
++ parser->charactersHandler = Characters;
++ parser->errorHandler = ErrorHandler;
++ parser->resolveEntityHandler = ResolveEntity;
++ parser->externalEntityParsedHandler = FreeInputData;
++ parser->UserData = &parserdata;
++
++ parserdata.parser = parser;
++ parserdata.inMixedContent = 0;
++ parserdata.testCount = 0;
++ parserdata.testSuccess = 0;
++
++
++ if (!(f = fopen(VERSIONFILE, "r"))) {
++ fprintf(PFERR, "Error opening VERSION file\n");
++ return 1;
++ }
++ fgets(parserdata.version, 20, f);
++ fclose(f);
++
++ if (!(f = fopen(argv[1], "rb"))) {
++ fprintf(PFERR, "Error opening input file %s\n", argv[1]);
++ return 1;
++ }
++
++ if (!(parserdata.pfout = fopen(argv[2], "wb"))) {
++ fprintf(PFERR, "Error opening output file %s\n", argv[2]);
++ return 1;
++ }
++
++ fprintf(PFERR, "Running testsuite %s, please wait...", argv[1]);
++ fputs("", parserdata.pfout);
++
++ XMLParser_Parse(parser, cstream, f, NULL);
++
++ fprintf(parserdata.pfout, "
%d tests successful out of total %d.",
++ parserdata.testSuccess, parserdata.testCount);
++ fputs("", parserdata.pfout);
++
++ fclose(f);
++ fclose(parserdata.pfout);
++ XMLVector_Free(parserdata.stateStack);
++ XMLParser_Free(parserdata.runParser);
++ XMLParser_Free(parser);
++ return 0;
++}
++
+diff -r ../src.orig/samples/zenstory/zenstory.c ./samples/zenstory/zenstory.c
+--- ../src.orig/samples/zenstory/zenstory.c Fri Oct 3 19:47:27 2003
++++ ./samples/zenstory/zenstory.c Wed Jan 7 23:43:23 2004
+@@ -1,196 +1,196 @@
+-#include
+-#include
+-#include
+-#include "libparsifal/parsifal.h"
+-#include "zenstory.h"
+-
+-int StartElement(void *UserData, const XMLCH *uri, const XMLCH *localName, const XMLCH *qName, LPXMLVECTOR atts)
+-{
+- STORYPARSER *parser = (STORYPARSER*)UserData;
+-
+- if (parser->inMixedContent) {
+- parser->inMixedContent++;
+- /* could call mixed content legal tag check routine here e.g.
+- if (!isvalidmixedcontenttag(qName, parser->state)) return sin(); */
+- return XML_OK;
+- }
+- else {
+- int *pstate = STACK_PEEK(parser->stateStack);
+- parser->state = (pstate) ? *pstate : NONE;
+- }
+-
+- if (parser->state == NONE && !strcmp(qName, "stories")) {
+- parser->state = STORIES; /* set initial state (root element) */
+- }
+- else if (parser->state == STORIES && !strcmp(qName, "story")) {
+- /* initialize new story: */
+- parser->curStory = XMLVector_Append(parser->stories, NULL);
+- ASSERT_MEM_ABORT(parser->curStory);
+- parser->curStory->title = (char*)NULL;
+- parser->curStory->author = (char*)NULL;
+- parser->curStory->body = (char*)NULL;
+- parser->state = STORY;
+- }
+- /* these would normally be done with a little more short circuiting: */
+- else if (parser->state == STORY && !strcmp(qName, "title")) {
+- parser->inContent++; /* STORY_TITLE tag allows normal content */
+- parser->state = STORY_TITLE;
+- }
+- else if (parser->state == STORY && !strcmp(qName, "author")) {
+- parser->inContent++; /* STORY_AUTHOR tag allows normal content */
+- parser->state = STORY_AUTHOR;
+- }
+- else if (parser->state == STORY && !strcmp(qName, "body")) {
+- parser->inMixedContent++; /* STORY_BODY tag allows mixed content */
+- parser->state = STORY_BODY;
+- }
+- else {
+- printf("Unexpected tag: %s\nFile is not in zen story format!\n", qName);
+- return XML_ABORT;
+- }
+- /* push the new state: */
+- ASSERT_MEM_ABORT(STACK_PUSH(parser->stateStack, &parser->state));
+- return XML_OK;
+-}
+-
+-int EndElement(void *UserData, const XMLCH *uri, const XMLCH *localName, const XMLCH *qName)
+-{
+- STORYPARSER *parser = (STORYPARSER*)UserData;
+-
+- if (parser->inContent)
+- parser->inContent = 0;
+- else if (parser->inMixedContent) {
+- /* if this is last mixed content tag (the tag
+- that put us in mixed content), we POP the state,
+- otherwise we just decrement the counter and return OK: */
+- if ((--parser->inMixedContent) > 0) return XML_OK;
+- }
+-
+- if (STACK_POP(parser->stateStack, &parser->state)) {
+- /* test the endTag here by popping and testing parser->state
+- (which is the state that is ending) */
+- XMLCH *s = (XMLCH*)NULL;
+-
+- switch(parser->state) {
+- case STORY_TITLE: /* you should check duplicate title etc. here */
+- s = strdup(XMLStringbuf_ToString(&parser->textBuf));
+- ASSERT_MEM_ABORT(s);
+- parser->curStory->title = s;
+- break;
+- case STORY_AUTHOR:
+- s = strdup(XMLStringbuf_ToString(&parser->textBuf));
+- ASSERT_MEM_ABORT(s);
+- parser->curStory->author = s;
+- break;
+- case STORY_BODY:
+- s = strdup(XMLStringbuf_ToString(&parser->textBuf));
+- ASSERT_MEM_ABORT(s);
+- parser->curStory->body = s;
+- break;
+- }
+- if (s) {
+- /* normalize buffer, note that XMLNormalizeBuf doesn't nul terminate
+- nor trim (we don't trim at all here): */
+- int len = XMLNormalizeBuf(s, parser->textBuf.len);
+- if (len < parser->textBuf.len) s[len] = '\0';
+- /* we'll reuse Stringbuf just setting its length to 0: */
+- ASSERT_MEM_ABORT(XMLStringbuf_SetLength(&parser->textBuf, 0));
+- }
+- }
+- return XML_OK;
+-}
+-
+-int Characters(void *UserData, const XMLCH *Chars, int cbChars)
+-{
+- STORYPARSER *parser = (STORYPARSER*)UserData;
+-
+- if (parser->inContent || parser->inMixedContent) {
+- /* if either inContent or inMixedContent is set,
+- append data into Stringbuf: */
+- ASSERT_MEM_ABORT(XMLStringbuf_Append(&parser->textBuf,
+- (XMLCH*)Chars, cbChars));
+- }
+- else {
+- /* this tag cannot contain character data: */
+- puts("Character data was not expected here!");
+- return XML_ABORT;
+- }
+- return XML_OK;
+-}
+-
+-void ErrorHandler(LPXMLPARSER parser)
+-{
+- if (parser->ErrorCode != ERR_XMLP_ABORT)
+- printf("Parsing error: %s\n", parser->ErrorString);
+- printf("ErrorLine: %d ErrorColumn: %d\n", parser->ErrorLine, parser->ErrorColumn);
+-}
+-
+-int cstream(BYTE *buf, int cBytes, int *cBytesActual, void *inputData)
+-{
+- *cBytesActual = fread(buf, 1, cBytes, (FILE*)inputData);
+- return (*cBytesActual < cBytes);
+-}
+-
+-int main(int argc, char* argv[])
+-{
+- STORYPARSER sparser;
+- LPXMLPARSER parser;
+-
+- if (!XMLParser_Create(&parser)) {
+- puts("Error creating parser!");
+- return 1;
+- }
+-
+- if (!XMLVector_Create(&sparser.stateStack, 6, sizeof(int))) {
+- puts("Error creating stateStack in main()");
+- return 1;
+- }
+-
+- if (!XMLVector_Create(&sparser.stories, 6, sizeof(ZENSTORY))) {
+- puts("Error creating stories vector in main()");
+- return 1;
+- }
+-
+- /* init Stringbuf: blockSize 256, no pre-allocation: */
+- XMLStringbuf_Init(&sparser.textBuf, 256, 0);
+-
+- sparser.parser = parser;
+- sparser.inMixedContent = sparser.inContent = 0;
+- parser->UserData = &sparser;
+-
+- parser->errorHandler = ErrorHandler;
+- parser->startElementHandler = StartElement;
+- parser->endElementHandler = EndElement;
+- parser->charactersHandler = Characters;
+-
+- if (XMLParser_Parse(parser, cstream, stdin, 0)) {
+-
+- /* present the stories (we'll free the strings in the same loop) : */
+- int i;
+- ZENSTORY *story;
+- for (i=0; ilength; i++) {
+- story = XMLVector_Get(sparser.stories, i);
+- if (story) {
+- if (story->title) {
+- printf("title: %s\n", story->title);
+- free(story->title);
+- }
+- if (story->author) {
+- printf("author: %s\n", story->author);
+- free(story->author);
+- }
+- if (story->body) {
+- printf("story: %s\n",story->body);
+- free(story->body);
+- }
+- }
+- }
+- }
+-
+- XMLParser_Free(parser);
+- XMLStringbuf_Free(&sparser.textBuf);
+- XMLVector_Free(sparser.stories);
+- XMLVector_Free(sparser.stateStack);
+- return 0;
+-}
+-
++#include
++#include
++#include
++#include "libparsifal/parsifal.h"
++#include "zenstory.h"
++
++int StartElement(void *UserData, const XMLCH *uri, const XMLCH *localName, const XMLCH *qName, LPXMLVECTOR atts)
++{
++ STORYPARSER *parser = (STORYPARSER*)UserData;
++
++ if (parser->inMixedContent) {
++ parser->inMixedContent++;
++ /* could call mixed content legal tag check routine here e.g.
++ if (!isvalidmixedcontenttag(qName, parser->state)) return sin(); */
++ return XML_OK;
++ }
++ else {
++ int *pstate = STACK_PEEK(parser->stateStack);
++ parser->state = (pstate) ? *pstate : NONE;
++ }
++
++ if (parser->state == NONE && !strcmp(qName, "stories")) {
++ parser->state = STORIES; /* set initial state (root element) */
++ }
++ else if (parser->state == STORIES && !strcmp(qName, "story")) {
++ /* initialize new story: */
++ parser->curStory = XMLVector_Append(parser->stories, NULL);
++ ASSERT_MEM_ABORT(parser->curStory);
++ parser->curStory->title = (char*)NULL;
++ parser->curStory->author = (char*)NULL;
++ parser->curStory->body = (char*)NULL;
++ parser->state = STORY;
++ }
++ /* these would normally be done with a little more short circuiting: */
++ else if (parser->state == STORY && !strcmp(qName, "title")) {
++ parser->inContent++; /* STORY_TITLE tag allows normal content */
++ parser->state = STORY_TITLE;
++ }
++ else if (parser->state == STORY && !strcmp(qName, "author")) {
++ parser->inContent++; /* STORY_AUTHOR tag allows normal content */
++ parser->state = STORY_AUTHOR;
++ }
++ else if (parser->state == STORY && !strcmp(qName, "body")) {
++ parser->inMixedContent++; /* STORY_BODY tag allows mixed content */
++ parser->state = STORY_BODY;
++ }
++ else {
++ printf("Unexpected tag: %s\nFile is not in zen story format!\n", qName);
++ return XML_ABORT;
++ }
++ /* push the new state: */
++ ASSERT_MEM_ABORT(STACK_PUSH(parser->stateStack, &parser->state));
++ return XML_OK;
++}
++
++int EndElement(void *UserData, const XMLCH *uri, const XMLCH *localName, const XMLCH *qName)
++{
++ STORYPARSER *parser = (STORYPARSER*)UserData;
++
++ if (parser->inContent)
++ parser->inContent = 0;
++ else if (parser->inMixedContent) {
++ /* if this is last mixed content tag (the tag
++ that put us in mixed content), we POP the state,
++ otherwise we just decrement the counter and return OK: */
++ if ((--parser->inMixedContent) > 0) return XML_OK;
++ }
++
++ if (STACK_POP(parser->stateStack, &parser->state)) {
++ /* test the endTag here by popping and testing parser->state
++ (which is the state that is ending) */
++ XMLCH *s = (XMLCH*)NULL;
++
++ switch(parser->state) {
++ case STORY_TITLE: /* you should check duplicate title etc. here */
++ s = strdup(XMLStringbuf_ToString(&parser->textBuf));
++ ASSERT_MEM_ABORT(s);
++ parser->curStory->title = s;
++ break;
++ case STORY_AUTHOR:
++ s = strdup(XMLStringbuf_ToString(&parser->textBuf));
++ ASSERT_MEM_ABORT(s);
++ parser->curStory->author = s;
++ break;
++ case STORY_BODY:
++ s = strdup(XMLStringbuf_ToString(&parser->textBuf));
++ ASSERT_MEM_ABORT(s);
++ parser->curStory->body = s;
++ break;
++ }
++ if (s) {
++ /* normalize buffer, note that XMLNormalizeBuf doesn't nul terminate
++ nor trim (we don't trim at all here): */
++ int len = XMLNormalizeBuf(s, parser->textBuf.len);
++ if (len < parser->textBuf.len) s[len] = '\0';
++ /* we'll reuse Stringbuf just setting its length to 0: */
++ ASSERT_MEM_ABORT(XMLStringbuf_SetLength(&parser->textBuf, 0));
++ }
++ }
++ return XML_OK;
++}
++
++int Characters(void *UserData, const XMLCH *Chars, int cbChars)
++{
++ STORYPARSER *parser = (STORYPARSER*)UserData;
++
++ if (parser->inContent || parser->inMixedContent) {
++ /* if either inContent or inMixedContent is set,
++ append data into Stringbuf: */
++ ASSERT_MEM_ABORT(XMLStringbuf_Append(&parser->textBuf,
++ (XMLCH*)Chars, cbChars));
++ }
++ else {
++ /* this tag cannot contain character data: */
++ puts("Character data was not expected here!");
++ return XML_ABORT;
++ }
++ return XML_OK;
++}
++
++void ErrorHandler(LPXMLPARSER parser)
++{
++ if (parser->ErrorCode != ERR_XMLP_ABORT)
++ printf("Parsing error: %s\n", parser->ErrorString);
++ printf("ErrorLine: %d ErrorColumn: %d\n", parser->ErrorLine, parser->ErrorColumn);
++}
++
++int cstream(BYTE *buf, int cBytes, int *cBytesActual, void *inputData)
++{
++ *cBytesActual = fread(buf, 1, cBytes, (FILE*)inputData);
++ return (*cBytesActual < cBytes);
++}
++
++int main(int argc, char* argv[])
++{
++ STORYPARSER sparser;
++ LPXMLPARSER parser;
++
++ if (!XMLParser_Create(&parser)) {
++ puts("Error creating parser!");
++ return 1;
++ }
++
++ if (!XMLVector_Create(&sparser.stateStack, 6, sizeof(int))) {
++ puts("Error creating stateStack in main()");
++ return 1;
++ }
++
++ if (!XMLVector_Create(&sparser.stories, 6, sizeof(ZENSTORY))) {
++ puts("Error creating stories vector in main()");
++ return 1;
++ }
++
++ /* init Stringbuf: blockSize 256, no pre-allocation: */
++ XMLStringbuf_Init(&sparser.textBuf, 256, 0);
++
++ sparser.parser = parser;
++ sparser.inMixedContent = sparser.inContent = 0;
++ parser->UserData = &sparser;
++
++ parser->errorHandler = ErrorHandler;
++ parser->startElementHandler = StartElement;
++ parser->endElementHandler = EndElement;
++ parser->charactersHandler = Characters;
++
++ if (XMLParser_Parse(parser, cstream, stdin, 0)) {
++
++ /* present the stories (we'll free the strings in the same loop) : */
++ int i;
++ ZENSTORY *story;
++ for (i=0; ilength; i++) {
++ story = XMLVector_Get(sparser.stories, i);
++ if (story) {
++ if (story->title) {
++ printf("title: %s\n", story->title);
++ free(story->title);
++ }
++ if (story->author) {
++ printf("author: %s\n", story->author);
++ free(story->author);
++ }
++ if (story->body) {
++ printf("story: %s\n",story->body);
++ free(story->body);
++ }
++ }
++ }
++ }
++
++ XMLParser_Free(parser);
++ XMLStringbuf_Free(&sparser.textBuf);
++ XMLVector_Free(sparser.stories);
++ XMLVector_Free(sparser.stateStack);
++ return 0;
++}
++
+diff -r ../src.orig/samples/zenstory/zenstory.h ./samples/zenstory/zenstory.h
+--- ../src.orig/samples/zenstory/zenstory.h Fri Jul 4 15:00:50 2003
++++ ./samples/zenstory/zenstory.h Wed Jan 7 23:43:23 2004
+@@ -1,34 +1,34 @@
+-int StartElement(void *UserData, const XMLCH *uri, const XMLCH *localName, const XMLCH *qName, LPXMLVECTOR atts);
+-int EndElement(void *UserData, const XMLCH *uri, const XMLCH *localName, const XMLCH *qName);
+-int Characters(void *UserData, const XMLCH *Chars, int cbChars);
+-void ErrorHandler(LPXMLPARSER parser);
+-int cstream(BYTE *buf, int cBytes, int *cBytesActual, void *inputData);
+-
+-/* stack macros (from xmldef.h) */
+-#define STACK_PUSH(stack,item) (XMLVector_Append((stack), (item)))
+-#define STACK_PEEK(stack) (XMLVector_Get((stack),(stack)->length-1))
+-#define STACK_REMOVE(stack) (XMLVector_Remove((stack), (stack)->length-1))
+-#define STACK_POP(stack,item) \
+-( ((stack)->length) ? (memcpy((item), STACK_PEEK((stack)), (stack)->itemSize), \
+-STACK_REMOVE((stack)), (item)) : NULL)
+-
+-#define ASSERT_MEM_ABORT(p) if (!(p)) { printf("Out of memory! Line: %d\n", __LINE__); return XML_ABORT; }
+-
+-enum tagSTATES { NONE, STORIES, STORY, STORY_TITLE, STORY_AUTHOR, STORY_BODY } STATES;
+-
+-typedef struct tagZENSTORY {
+- char *title;
+- char *author;
+- char *body;
+-} ZENSTORY;
+-
+-typedef struct tagSTORYPARSER {
+- LPXMLPARSER parser;
+- XMLSTRINGBUF textBuf;
+- LPXMLVECTOR stateStack;
+- int state;
+- int inContent;
+- int inMixedContent;
+- LPXMLVECTOR stories;
+- ZENSTORY *curStory;
++int StartElement(void *UserData, const XMLCH *uri, const XMLCH *localName, const XMLCH *qName, LPXMLVECTOR atts);
++int EndElement(void *UserData, const XMLCH *uri, const XMLCH *localName, const XMLCH *qName);
++int Characters(void *UserData, const XMLCH *Chars, int cbChars);
++void ErrorHandler(LPXMLPARSER parser);
++int cstream(BYTE *buf, int cBytes, int *cBytesActual, void *inputData);
++
++/* stack macros (from xmldef.h) */
++#define STACK_PUSH(stack,item) (XMLVector_Append((stack), (item)))
++#define STACK_PEEK(stack) (XMLVector_Get((stack),(stack)->length-1))
++#define STACK_REMOVE(stack) (XMLVector_Remove((stack), (stack)->length-1))
++#define STACK_POP(stack,item) \
++( ((stack)->length) ? (memcpy((item), STACK_PEEK((stack)), (stack)->itemSize), \
++STACK_REMOVE((stack)), (item)) : NULL)
++
++#define ASSERT_MEM_ABORT(p) if (!(p)) { printf("Out of memory! Line: %d\n", __LINE__); return XML_ABORT; }
++
++enum tagSTATES { NONE, STORIES, STORY, STORY_TITLE, STORY_AUTHOR, STORY_BODY } STATES;
++
++typedef struct tagZENSTORY {
++ char *title;
++ char *author;
++ char *body;
++} ZENSTORY;
++
++typedef struct tagSTORYPARSER {
++ LPXMLPARSER parser;
++ XMLSTRINGBUF textBuf;
++ LPXMLVECTOR stateStack;
++ int state;
++ int inContent;
++ int inMixedContent;
++ LPXMLVECTOR stories;
++ ZENSTORY *curStory;
+ } STORYPARSER;
+\ No newline at end of file
+Only in ./src: .libs
+Only in ./src: Makefile
+diff -r ../src.orig/src/bistream.c ./src/bistream.c
+--- ../src.orig/src/bistream.c Thu Oct 2 20:03:48 2003
++++ ./src/bistream.c Wed Jan 7 23:43:23 2004
+@@ -1,165 +1,165 @@
+-/*===========================================================================
+- bistream.c
+- This module contains BufferedIStream (buffered inputstream reader)
+- for string tokenizing operations.
+- see parsifal.h for copyright info
+-===========================================================================*/
+-
+-#include
+-#include
+-#include
+-#include "bistream.h"
+-
+-#ifdef _MSC_VER
+-#pragma intrinsic(memcmp, memcpy, memset, strcmp, strlen)
+-#endif
+-
+-/* MEMCMP macro gives us about 20% performance increase!
+- note that MEMCMP tests for equality and return value must be ensured 0 or 1
+- after macro call */
+-#define MEMCMP(b1,b2,l) \
+-( ((l)==1) ? (*(b1)!=*(b2)) : (memcmp((b1),(b2),(l))) )
+-
+-#define HANDLE_ENCODE(offset) \
+-l = r->encode(r, r->buf + (offset), &cBytesActual); \
+-if (!l) { \
+- r->bytesavail += cBytesActual; \
+-} \
+-else { \
+- if (l < 0 || !r->ubuf) return (r->err=l); \
+- if (l > cBytesActual) { BISFIXBUF(r->bytesavail + l); } \
+- memcpy(r->buf + (offset), r->ubuf, l); \
+- r->bytesavail += l; \
+-}
+-
+-/*===========================================================================
+- FUNCTION
+- BufferedIStream_EncodeBuffer
+- DESC
+- Encodes current reader buffer
+- PARAMS
+- r this
+- offset bytes to skip from the start
+- NOTES
+- _Read and _Peek handles buffer encoding (if LPFNENCODE is specified)
+- so this isn't used very often but can be used for "late encoding"
+- i.e. you read data without encoding it and then encode only
+- some of it.
+-===========================================================================*/
+-int BufferedIStream_EncodeBuffer(LPBUFFEREDISTREAM r, int offset)
+-{
+- if (r->encode && offset <= r->bytesavail && offset >= 0) {
+- int l, NewBufSize, cBytesActual = r->bytesavail - offset;
+- if (cBytesActual) {
+- r->bytesavail -= cBytesActual;
+- HANDLE_ENCODE(offset);
+- }
+- return 0; /* success */
+- }
+- return BIS_ERR_ENCODING;
+-}
+-
+-/*===========================================================================
+- FUNCTION
+- BufferedIStream_Peek
+- DESC
+- Peeks current buffer position
+- PARAMS
+- r this
+- tok token to search (or NULL if you want to ensure len bytes)
+- len length of token
+- offset bytes to skip at current posision
+- RETURNS
+- 0 token found or len bytes ensured
+- -1 token not found
+- < -1 some error (see BISTREAM.H)
+-===========================================================================*/
+-int BufferedIStream_Peek(LPBUFFEREDISTREAM r,
+- const BYTE *tok,
+- int len,
+- int offset)
+-{
+- int pos;
+-
+- if (r->pos < 0) return r->pos;
+- if ((pos = r->pos + offset) < 0) return (r->err=BIS_ERR_INVALIDARG);
+-
+- if (r->buf == NULL || (pos + len) > r->bytesavail) {
+- int cBytesActual, NewBufSize, l;
+-
+- BISFIXBUF(pos + len);
+- r->eof = r->inputsrc(r->buf + r->bytesavail,
+- r->bufsize - r->bytesavail, &cBytesActual, r->inputData);
+-
+- if (cBytesActual) {
+- if (r->encode) {
+- HANDLE_ENCODE(r->bytesavail);
+- }
+- else {
+- r->bytesavail += cBytesActual;
+- }
+- }
+-
+- if ((pos + len) > r->bytesavail) return -1;
+- }
+- /* if tok is NULL, return 0 to signal successfull "ensured tok length of
+- bytes", otherwise perform memcmp AND return 0 (equal), 1 (not equal).
+- memcmp can return values lower than -1 that would falsely indicate "fatal error"
+- thanks to Keijiro Takahashi for pointing that out. */
+- return ((tok) ? (MEMCMP(r->buf + pos, tok, len) ? -1 : 0) : 0);
+-}
+-
+-/*===========================================================================
+- FUNCTION
+- BufferedIStream_ResetBuf
+- DESC
+- Resets BufferedIStream buffer
+- PARAMS
+- r this
+- numBytes bytes to skip from start of buffer (usually r->pos)
+- RETURNS
+- TRUE SUCCESS
+- 0 FAILURE
+- NOTES
+- _ResetBuf resets the position to 0 and ALWAYS
+- skip bytes from the start of reader buffer.
+-===========================================================================*/
+-int BufferedIStream_ResetBuf(LPBUFFEREDISTREAM r,
+- int numBytes)
+-{
+- int NewBufSize;
+- if (!numBytes) return 0;
+- if (numBytes > r->bytesavail) return BIS_ERR_INVALIDARG;
+- r->pos = 0;
+- r->bytesavail -= numBytes;
+- memmove(r->buf, r->buf+numBytes, r->bytesavail);
+- BISFIXBUF(r->bytesavail);
+- return 0;
+-}
+-
+-LPBUFFEREDISTREAM BufferedIStream_Init(LPBUFFEREDISTREAM r, int blocksize)
+-{
+- r->buf = r->ubuf = (BYTE*)NULL;
+- r->bufsize = r->bytesavail = r->pos = r->eof = 0;
+- r->err = r->usererr = 0;
+- r->inputData = NULL;
+- /* note that we don't initialize userdata */
+- r->inputsrc = (LPFNINPUTSRC)NULL;
+- r->encode = (LPFNENCODE)NULL;
+- r->blocksize = blocksize;
+- r->maxbufsize = BIS_DEFAULT_MAXBUFSIZE;
+- return r;
+-}
+-
+-void BufferedIStream_Free(LPBUFFEREDISTREAM r)
+-{
+- if (r->buf != (BYTE*)NULL) {
+- free(r->buf);
+- r->buf = (BYTE*)NULL;
+- }
+- if (r->ubuf != (BYTE*)NULL) {
+- free(r->ubuf);
+- r->ubuf = (BYTE*)NULL;
+- }
+-}
+-
++/*===========================================================================
++ bistream.c
++ This module contains BufferedIStream (buffered inputstream reader)
++ for string tokenizing operations.
++ see parsifal.h for copyright info
++===========================================================================*/
++
++#include
++#include
++#include
++#include "bistream.h"
++
++#ifdef _MSC_VER
++#pragma intrinsic(memcmp, memcpy, memset, strcmp, strlen)
++#endif
++
++/* MEMCMP macro gives us about 20% performance increase!
++ note that MEMCMP tests for equality and return value must be ensured 0 or 1
++ after macro call */
++#define MEMCMP(b1,b2,l) \
++( ((l)==1) ? (*(b1)!=*(b2)) : (memcmp((b1),(b2),(l))) )
++
++#define HANDLE_ENCODE(offset) \
++l = r->encode(r, r->buf + (offset), &cBytesActual); \
++if (!l) { \
++ r->bytesavail += cBytesActual; \
++} \
++else { \
++ if (l < 0 || !r->ubuf) return (r->err=l); \
++ if (l > cBytesActual) { BISFIXBUF(r->bytesavail + l); } \
++ memcpy(r->buf + (offset), r->ubuf, l); \
++ r->bytesavail += l; \
++}
++
++/*===========================================================================
++ FUNCTION
++ BufferedIStream_EncodeBuffer
++ DESC
++ Encodes current reader buffer
++ PARAMS
++ r this
++ offset bytes to skip from the start
++ NOTES
++ _Read and _Peek handles buffer encoding (if LPFNENCODE is specified)
++ so this isn't used very often but can be used for "late encoding"
++ i.e. you read data without encoding it and then encode only
++ some of it.
++===========================================================================*/
++int BufferedIStream_EncodeBuffer(LPBUFFEREDISTREAM r, int offset)
++{
++ if (r->encode && offset <= r->bytesavail && offset >= 0) {
++ int l, NewBufSize, cBytesActual = r->bytesavail - offset;
++ if (cBytesActual) {
++ r->bytesavail -= cBytesActual;
++ HANDLE_ENCODE(offset);
++ }
++ return 0; /* success */
++ }
++ return BIS_ERR_ENCODING;
++}
++
++/*===========================================================================
++ FUNCTION
++ BufferedIStream_Peek
++ DESC
++ Peeks current buffer position
++ PARAMS
++ r this
++ tok token to search (or NULL if you want to ensure len bytes)
++ len length of token
++ offset bytes to skip at current posision
++ RETURNS
++ 0 token found or len bytes ensured
++ -1 token not found
++ < -1 some error (see BISTREAM.H)
++===========================================================================*/
++int BufferedIStream_Peek(LPBUFFEREDISTREAM r,
++ const BYTE *tok,
++ int len,
++ int offset)
++{
++ int pos;
++
++ if (r->pos < 0) return r->pos;
++ if ((pos = r->pos + offset) < 0) return (r->err=BIS_ERR_INVALIDARG);
++
++ if (r->buf == NULL || (pos + len) > r->bytesavail) {
++ int cBytesActual, NewBufSize, l;
++
++ BISFIXBUF(pos + len);
++ r->eof = r->inputsrc(r->buf + r->bytesavail,
++ r->bufsize - r->bytesavail, &cBytesActual, r->inputData);
++
++ if (cBytesActual) {
++ if (r->encode) {
++ HANDLE_ENCODE(r->bytesavail);
++ }
++ else {
++ r->bytesavail += cBytesActual;
++ }
++ }
++
++ if ((pos + len) > r->bytesavail) return -1;
++ }
++ /* if tok is NULL, return 0 to signal successfull "ensured tok length of
++ bytes", otherwise perform memcmp AND return 0 (equal), 1 (not equal).
++ memcmp can return values lower than -1 that would falsely indicate "fatal error"
++ thanks to Keijiro Takahashi for pointing that out. */
++ return ((tok) ? (MEMCMP(r->buf + pos, tok, len) ? -1 : 0) : 0);
++}
++
++/*===========================================================================
++ FUNCTION
++ BufferedIStream_ResetBuf
++ DESC
++ Resets BufferedIStream buffer
++ PARAMS
++ r this
++ numBytes bytes to skip from start of buffer (usually r->pos)
++ RETURNS
++ TRUE SUCCESS
++ 0 FAILURE
++ NOTES
++ _ResetBuf resets the position to 0 and ALWAYS
++ skip bytes from the start of reader buffer.
++===========================================================================*/
++int BufferedIStream_ResetBuf(LPBUFFEREDISTREAM r,
++ int numBytes)
++{
++ int NewBufSize;
++ if (!numBytes) return 0;
++ if (numBytes > r->bytesavail) return BIS_ERR_INVALIDARG;
++ r->pos = 0;
++ r->bytesavail -= numBytes;
++ memmove(r->buf, r->buf+numBytes, r->bytesavail);
++ BISFIXBUF(r->bytesavail);
++ return 0;
++}
++
++LPBUFFEREDISTREAM BufferedIStream_Init(LPBUFFEREDISTREAM r, int blocksize)
++{
++ r->buf = r->ubuf = (BYTE*)NULL;
++ r->bufsize = r->bytesavail = r->pos = r->eof = 0;
++ r->err = r->usererr = 0;
++ r->inputData = NULL;
++ /* note that we don't initialize userdata */
++ r->inputsrc = (LPFNINPUTSRC)NULL;
++ r->encode = (LPFNENCODE)NULL;
++ r->blocksize = blocksize;
++ r->maxbufsize = BIS_DEFAULT_MAXBUFSIZE;
++ return r;
++}
++
++void BufferedIStream_Free(LPBUFFEREDISTREAM r)
++{
++ if (r->buf != (BYTE*)NULL) {
++ free(r->buf);
++ r->buf = (BYTE*)NULL;
++ }
++ if (r->ubuf != (BYTE*)NULL) {
++ free(r->ubuf);
++ r->ubuf = (BYTE*)NULL;
++ }
++}
++
+Only in ./src: bistream.lo
+Only in ./src: bistream.o
+diff -r ../src.orig/src/encoding.c ./src/encoding.c
+--- ../src.orig/src/encoding.c Thu Oct 2 20:03:39 2003
++++ ./src/encoding.c Wed Jan 7 23:43:23 2004
+@@ -1,157 +1,157 @@
+-/*===========================================================================
+- encoding.c
+- This module contains encoding "plug-ins" for BufferedIStream
+- see parsifal.h for copyright info
+-===========================================================================*/
+-
+-#include
+-#include
+-#include "parsifal.h"
+-#include "xmldef.h"
+-
+-extern const XMLCH illByte[32];
+-
+-/* encoding "plug-ins" for BufferedIStream: */
+-int Latin1ToUtf8(LPBUFFEREDISTREAM r, BYTE *bufp, int *cBytes);
+-int Utf8Validator(LPBUFFEREDISTREAM r, BYTE *bufp, int *cBytes);
+-
+-#define rd ((LPBISREADERDATA)r->userdata)
+-
+-int Latin1ToUtf8(LPBUFFEREDISTREAM r, BYTE *bufp, int *cBytes)
+-{
+- BYTE *p; /* pointer to output buffer */
+- int i;
+- int cbChars = 0; /* number of bytes in the output buf */
+- int encodedSome = 0; /* encoded char triggers this flag */
+-
+-
+- if (rd->ubufsize < *cBytes || ((rd->ubufsize - *cBytes) > 256)) {
+- /* fix the encoding buffer size: */
+- rd->ubufsize = COUNTBUFSIZE(*cBytes, 16);
+- r->ubuf = (BYTE*)realloc(r->ubuf, rd->ubufsize);
+- if (!r->ubuf) return BIS_ERR_MEMALLOC;
+- }
+-
+- for (p=r->ubuf, i=0; i < *cBytes; bufp++, i++)
+- {
+- if (*bufp & 0x80) { // > 127
+- if (!encodedSome) encodedSome = 1;
+-
+- if (cbChars + 2 > rd->ubufsize) {
+- rd->ubufsize += 16;
+- r->ubuf = (BYTE*)RESIZEBUFPOS(r->ubuf, rd->ubufsize, p, cbChars);
+- if (!r->ubuf) return BIS_ERR_MEMALLOC;
+- }
+- *(p++) = ((*bufp >> 6) | 0xc0);
+- *(p++) = ((*bufp & 0x3f) | 0x80);
+- cbChars += 2;
+- }
+- else {
+- if (ISILLBYTE(*bufp)) {
+- r->usererr = ERR_XMLP_ILLEGAL_CHAR;
+- rd->parser->ErrorCode = (int)*bufp; /* hack, see SetError in parsifal.c */
+- return BIS_ERR_USER;
+- }
+-
+- if (cbChars + 1 > rd->ubufsize) {
+- rd->ubufsize += 16;
+- r->ubuf = (BYTE*)RESIZEBUFPOS(r->ubuf, rd->ubufsize, p, cbChars);
+- if (!r->ubuf) return BIS_ERR_MEMALLOC;
+- }
+-
+- *(p++) = *bufp;
+- cbChars++;
+- }
+- }
+- return ((encodedSome) ? cbChars : 0);
+-}
+-
+-int Utf8Validator(LPBUFFEREDISTREAM r, BYTE *bufp, int *cBytes)
+-{
+- int c, more, min, l, i, NewBufSize;
+- i = NewBufSize = 0;
+-
+- while (i < *cBytes)
+- {
+- if (!(*bufp & 0x80)) {
+- if (ISILLBYTE(*bufp)) {
+- r->usererr = ERR_XMLP_ILLEGAL_CHAR;
+- rd->parser->ErrorCode = (int)*bufp; /* hack, see SetError in parsifal.c */
+- return BIS_ERR_USER;
+- }
+- bufp++;
+- i++;
+- continue; /* < 128 */
+- }
+-
+- c = (unsigned int)*bufp;
+-
+- if(c < 0xc0 || c >= 0xfe) return BIS_ERR_ENCODING;
+- /* printf("Illegal UTF-8 start byte"); */
+-
+- if(c <= 0xdf) {
+- c &= 0x1f;
+- more = 1;
+- min = 0x80;
+- }
+- else if(c <= 0xef) {
+- c &= 0x0f;
+- more = 2;
+- min = 0x800;
+- }
+- else if(c <= 0xf7) {
+- c &= 0x07;
+- more = 3;
+- min = 0x10000;
+- }
+- else if(c <= 0xfb){
+- c &= 0x03;
+- more = 4;
+- min = 0x200000;
+- }
+- else {
+- c &= 0x01;
+- more = 5;
+- min = 0x4000000;
+- }
+-
+- if((i + more + 1) > *cBytes)
+- { /* UTF-8 char is truncated, try to get missing part from inputsrc: */
+- /* (Using NewBufSize var as scratch var (also needed in BISFIXBUF macro)) */
+- int m = ((i + more) - *cBytes) + 1;
+- BISFIXBUF(r->bytesavail + *cBytes + m);
+- r->eof = r->inputsrc(r->buf+r->bytesavail+*cBytes, m, &NewBufSize, r->inputData);
+- if (NewBufSize != m) return BIS_ERR_ENCODING;
+- bufp = r->buf+r->bytesavail+i; /* pointer may be relocated... */
+- *cBytes += NewBufSize; /* must increase "BytesActual" thru *cBytes too */
+- NewBufSize = 1; /* we're done after checking newly read bytes */
+- }
+- bufp++; i++; /* go to next char of multibyte sequence */
+- for (l=0; lusererr = ERR_XMLP_ILLEGAL_CHAR;
+- rd->parser->ErrorCode = c;
+- return BIS_ERR_USER;
+- }
+- }
+- if (NewBufSize) return 0;
+- }
+- return 0;
+-}
+-
+-#undef rd
+-
++/*===========================================================================
++ encoding.c
++ This module contains encoding "plug-ins" for BufferedIStream
++ see parsifal.h for copyright info
++===========================================================================*/
++
++#include
++#include
++#include "parsifal.h"
++#include "xmldef.h"
++
++extern const XMLCH illByte[32];
++
++/* encoding "plug-ins" for BufferedIStream: */
++int Latin1ToUtf8(LPBUFFEREDISTREAM r, BYTE *bufp, int *cBytes);
++int Utf8Validator(LPBUFFEREDISTREAM r, BYTE *bufp, int *cBytes);
++
++#define rd ((LPBISREADERDATA)r->userdata)
++
++int Latin1ToUtf8(LPBUFFEREDISTREAM r, BYTE *bufp, int *cBytes)
++{
++ BYTE *p; /* pointer to output buffer */
++ int i;
++ int cbChars = 0; /* number of bytes in the output buf */
++ int encodedSome = 0; /* encoded char triggers this flag */
++
++
++ if (rd->ubufsize < *cBytes || ((rd->ubufsize - *cBytes) > 256)) {
++ /* fix the encoding buffer size: */
++ rd->ubufsize = COUNTBUFSIZE(*cBytes, 16);
++ r->ubuf = (BYTE*)realloc(r->ubuf, rd->ubufsize);
++ if (!r->ubuf) return BIS_ERR_MEMALLOC;
++ }
++
++ for (p=r->ubuf, i=0; i < *cBytes; bufp++, i++)
++ {
++ if (*bufp & 0x80) { // > 127
++ if (!encodedSome) encodedSome = 1;
++
++ if (cbChars + 2 > rd->ubufsize) {
++ rd->ubufsize += 16;
++ r->ubuf = (BYTE*)RESIZEBUFPOS(r->ubuf, rd->ubufsize, p, cbChars);
++ if (!r->ubuf) return BIS_ERR_MEMALLOC;
++ }
++ *(p++) = ((*bufp >> 6) | 0xc0);
++ *(p++) = ((*bufp & 0x3f) | 0x80);
++ cbChars += 2;
++ }
++ else {
++ if (ISILLBYTE(*bufp)) {
++ r->usererr = ERR_XMLP_ILLEGAL_CHAR;
++ rd->parser->ErrorCode = (int)*bufp; /* hack, see SetError in parsifal.c */
++ return BIS_ERR_USER;
++ }
++
++ if (cbChars + 1 > rd->ubufsize) {
++ rd->ubufsize += 16;
++ r->ubuf = (BYTE*)RESIZEBUFPOS(r->ubuf, rd->ubufsize, p, cbChars);
++ if (!r->ubuf) return BIS_ERR_MEMALLOC;
++ }
++
++ *(p++) = *bufp;
++ cbChars++;
++ }
++ }
++ return ((encodedSome) ? cbChars : 0);
++}
++
++int Utf8Validator(LPBUFFEREDISTREAM r, BYTE *bufp, int *cBytes)
++{
++ int c, more, min, l, i, NewBufSize;
++ i = NewBufSize = 0;
++
++ while (i < *cBytes)
++ {
++ if (!(*bufp & 0x80)) {
++ if (ISILLBYTE(*bufp)) {
++ r->usererr = ERR_XMLP_ILLEGAL_CHAR;
++ rd->parser->ErrorCode = (int)*bufp; /* hack, see SetError in parsifal.c */
++ return BIS_ERR_USER;
++ }
++ bufp++;
++ i++;
++ continue; /* < 128 */
++ }
++
++ c = (unsigned int)*bufp;
++
++ if(c < 0xc0 || c >= 0xfe) return BIS_ERR_ENCODING;
++ /* printf("Illegal UTF-8 start byte"); */
++
++ if(c <= 0xdf) {
++ c &= 0x1f;
++ more = 1;
++ min = 0x80;
++ }
++ else if(c <= 0xef) {
++ c &= 0x0f;
++ more = 2;
++ min = 0x800;
++ }
++ else if(c <= 0xf7) {
++ c &= 0x07;
++ more = 3;
++ min = 0x10000;
++ }
++ else if(c <= 0xfb){
++ c &= 0x03;
++ more = 4;
++ min = 0x200000;
++ }
++ else {
++ c &= 0x01;
++ more = 5;
++ min = 0x4000000;
++ }
++
++ if((i + more + 1) > *cBytes)
++ { /* UTF-8 char is truncated, try to get missing part from inputsrc: */
++ /* (Using NewBufSize var as scratch var (also needed in BISFIXBUF macro)) */
++ int m = ((i + more) - *cBytes) + 1;
++ BISFIXBUF(r->bytesavail + *cBytes + m);
++ r->eof = r->inputsrc(r->buf+r->bytesavail+*cBytes, m, &NewBufSize, r->inputData);
++ if (NewBufSize != m) return BIS_ERR_ENCODING;
++ bufp = r->buf+r->bytesavail+i; /* pointer may be relocated... */
++ *cBytes += NewBufSize; /* must increase "BytesActual" thru *cBytes too */
++ NewBufSize = 1; /* we're done after checking newly read bytes */
++ }
++ bufp++; i++; /* go to next char of multibyte sequence */
++ for (l=0; lusererr = ERR_XMLP_ILLEGAL_CHAR;
++ rd->parser->ErrorCode = c;
++ return BIS_ERR_USER;
++ }
++ }
++ if (NewBufSize) return 0;
++ }
++ return 0;
++}
++
++#undef rd
++
+Only in ./src: encoding.lo
+Only in ./src: encoding.o
+Only in ./src: libparsifal.la
+diff -r ../src.orig/src/parsifal.c ./src/parsifal.c
+--- ../src.orig/src/parsifal.c Thu Oct 23 19:32:44 2003
++++ ./src/parsifal.c Wed Jan 7 23:43:23 2004
+@@ -1,2759 +1,2759 @@
+-/*===========================================================================
+- parsifal.c
+- This module contains the main XML parser logic
+- see parsifal.h for copyright info
+-===========================================================================*/
+-
+-#include /* strtoul, malloc etc. */
+-#include /* memmove, strdup, strcmp */
+-#include /* vsnprintf */
+-#include
+-#include
+-#include "parsifal.h"
+-#include "nametab.h"
+-#include "xmldef.h"
+-#include "isrcmem.h" /* DTD_SUPPORT - defs only */
+-
+-#ifdef _MSC_VER
+- #ifdef _DEBUG
+- #include
+- #define _CRTDBG_MAP_ALLOC
+- #endif
+-#define vsnprintf _vsnprintf
+-#endif
+-
+-static int ParseContent(LPXMLPARSER parser);
+-static int ParseComment(LPXMLPARSER parser, int skip);
+-static int ParsePI(LPXMLPARSER parser, int skip);
+-static int ParseCData(LPXMLPARSER parser);
+-static int ParseStartTag(LPXMLPARSER parser);
+-static int ParseEndTag(LPXMLPARSER parser);
+-static int ParseAttributes(LPXMLPARSER parser, LPXMLRUNTIMETAG pTag, int *isEmpty);
+-static int ParseXmlDecl(LPXMLPARSER parser, int skip);
+-static int ParseTagNS(LPXMLPARSER parser, LPXMLRUNTIMETAG ptag, int namelen, int pos);
+-static int DetectEncoding(LPXMLPARSER parser, int skip, LPFNENCODE defaultEncoding);
+-static int SetEncoding(LPXMLPARSER parser, XMLCH *encodingName);
+-static void SetReaderFatal(LPXMLPARSER parser, int errval);
+-static const XMLCH *GetErrorString(XMLERRCODE code);
+-static int Err(LPXMLPARSER parser, XMLERRCODE code, ...);
+-static int ErrP(LPXMLPARSER parser, XMLERRCODE code, int posOffset);
+-static void ParseInput(LPXMLPARSER parser);
+-static int DestroyUriTableProc(char *key, void *data, void *userdata);
+-static int CopyUriTableProc(char *key, void *data, void *userdata);
+-static XMLCH* prepUri(XMLCH *uri, int declHere);
+-static int ParseNameTok(LPXMLPARSER parser, int *len,
+- int *prefixLen, XMLCH *endChars, int *cEndChars);
+-static int Require(LPXMLPARSER parser, XMLCH *tok,
+- XMLCH *endChars, int *cEndChars);
+-static XMLCH *ParseString(LPXMLPARSER parser, LPXMLSTRINGBUF sbuf,
+- LPXMLRUNTIMEATT pAtt, int Normalize, int entHandling);
+-static XMLCH *ReadCh(LPXMLPARSER parser, int *chSize);
+-static int SkipWS(LPXMLPARSER parser, XMLCH *expectedErr);
+-static int RequireCh(LPXMLPARSER parser, XMLCH ch, int allowWS);
+-
+-#ifdef DTD_SUPPORT
+-static int ParseDoctypeDecl(LPXMLPARSER parser);
+-static int ParseDTD(LPXMLPARSER parser, int isExternal);
+-static int ParseContentDTD(LPXMLPARSER parser, int isExternal);
+-static int ParseDTDMiscTag(LPXMLPARSER parser, int isExternal);
+-static void ParseEntityContent(LPXMLPARSER parser, LPXMLENTITY e);
+-static void ParseIntEntityAtt(LPXMLPARSER parser, LPXMLENTITY e, LPXMLRUNTIMEATT pAtt);
+-static int ParseEntityDecl(LPXMLPARSER parser);
+-static int GetEntityDecl(LPXMLPARSER parser, LPXMLENTITY e, LPXMLSTRINGBUF sbuf);
+-static int ResolveExternalDTD(LPXMLPARSER parser, LPXMLENTITY e);
+-static int MemInputsrc(BYTE *buf, int cBytes, int *cBytesActual, void *inputData);
+-#else
+-#define ParseDoctypeDecl(parser) (ErrP((parser), ERR_XMLP_INVALID_TOKEN, 1))
+-#endif
+-
+-/* util routines not necessarily specific to xml parsing: */
+-#ifndef HAS_STRICMP
+-static int stricmp(const char *s1, const char *s2);
+-#endif
+-static XMLCH* memdup(XMLCH *buf, int len);
+-
+-extern int Latin1ToUtf8(LPBUFFEREDISTREAM reader, BYTE *bufp, int *cBytes);
+-extern int Utf8Validator(LPBUFFEREDISTREAM reader, BYTE *bufp, int *cBytes);
+-
+-static const STDENTITIES stdEntities[6] = {
+- {"gt", '>', 2},
+- {"lt", '<', 2},
+- {"amp", '&', 3},
+- {"apos", '\'', 4},
+- {"quot", '\"', 4},
+- {NULL, 0x0, 0x0}
+-};
+-
+-static XMLCH EmptyStr[1] = {'\0'};
+-static XMLCH *uriXMLNS = "http://www.w3.org/2000/xmlns/";
+-static XMLCH *uriXML = "http://www.w3.org/XML/1998/namespace";
+-
+-#define ISFATAL(ret) (((ret) < -2) ? (SetReaderFatal(((LPXMLPARSER)parser), (ret)), 1) : 0)
+-#define ISXMLPREFIX(s) ((*(s) == 'x' && s[1] == 'm' && s[2] == 'l'))
+-#define ISXMLNSPREFIX(s) ((ISXMLPREFIX((s)) && s[3] == 'n' && s[4] == 's'))
+-#define ISQUOTE(c) ((c)=='\"' || (c)=='\'')
+-
+-#define DPOS(bytes) \
+- PREADER->pos-=(bytes); \
+- if (!PREADERDATA->noPos) PREADERDATA->col-=(bytes);
+-#define IPOS(bytes) \
+- PREADER->pos+=(bytes); \
+- if (!PREADERDATA->noPos) PREADERDATA->col+=(bytes);
+-
+-/* some shortcuts: */
+-#define RT parser->prt
+-#define PREADER ((LPBUFFEREDISTREAM)parser->reader)
+-#define PREADERDATA ((LPBISREADERDATA)PREADER->userdata)
+-#define HANDLER(n) parser->n##Handler
+-#define PEEKINPUT(str,len) BufferedIStream_Peek(PREADER,(str),(len),0)
+-
+-/* remove attributes from vector and
+- free memory associated with them: */
+-#define CLEANUP_ATTS \
+-if (RT->atts->length) \
+-{ \
+- int i; \
+- for (i=0; iatts->length; i++) { \
+- pAtt = XMLVector_Get(RT->atts, i); \
+- /* namedAtts data is allocated by atts vector, not Hashtable */ \
+- /* so we're removing only htable key, this is */ \
+- /* faster than calling XMLHTable_Destroy: */ \
+- XMLHTable_Remove(RT->namedAtts, pAtt->qname); \
+- if (!pAtt->nameBuf.useStatic) XMLStringbuf_Free(&pAtt->nameBuf); \
+- if (!pAtt->valBuf.useStatic) XMLStringbuf_Free(&pAtt->valBuf); \
+- /* uris will be freed by HashTable */ \
+- } \
+- _XMLVector_RemoveAll(RT->atts); \
+-}
+-
+-/* INIT_NSSCOPE is used in ParseAttributes.
+- initializes new scope for pTag->Scope, copies namespaces from pTag->prevScope
+- and sets RT->nsScope. After this we can refer to current namespace with
+- RT->nsScope. pTag->Scope is only preserved to indicate that later this scope
+- must be freed (at EndElement stage) */
+-#define INIT_NSSCOPE \
+-if (!pTag->Scope) { \
+- if (!( pTag->Scope = (LPXMLHTABLE) malloc(sizeof(XMLHTABLE)))) \
+- return Err(parser, ERR_XMLP_MEMORY_ALLOC); \
+- XMLHTable_Create(pTag->Scope, 64); \
+- if (!pTag->Scope->size) \
+- return Err(parser, ERR_XMLP_MEMORY_ALLOC); \
+- if (pTag->prevScope != NULL) { \
+- pTag->prevScope->userdata = pTag->Scope; \
+- if ((XMLHTable_Enumerate(pTag->prevScope, CopyUriTableProc))) \
+- return Err(parser, ERR_XMLP_MEMORY_ALLOC); \
+- } \
+- RT->nsScope = pTag->Scope; \
+-}
+-
+-static const XMLCH *GetErrorString(XMLERRCODE code)
+-{
+- static const XMLCH *ParserErrMsg[] = {
+- 0,
+- "Out of memory",
+- "Fatal error (code: %d)",
+- "Invalid token",
+- "Invalid name",
+- "End tag '%s' was not expected here",
+- "Reference to undefined entity '%s'",
+- "Whitespace not allowed here",
+- "Whitespace required",
+- "Tag '%s' was not closed",
+- "Expected '%s', found '%s'",
+- "Expected '%s'",
+- "Only one top level element is allowed",
+- "Invalid at the top level of the document",
+- "Undefined namespace prefix '%s'",
+- "Duplicate attribute '%s'",
+- "Encoding error",
+- "Unsupported encoding '%s'",
+- "Invalid %s declaration",
+- "Invalid value for attribute '%s'",
+- "Parsing aborted",
+- "Illegal character #x%04X",
+- "Recursive reference in entity '%s'",
+- };
+- return (ParserErrMsg[code]);
+-}
+-
+-/*===========================================================================
+- FUNCTION
+- Err
+- PARAMS
+- parser this
+- code error code
+- ... va_list for error string
+- RETURNS
+- 0
+- NOTES
+- Sets ErrorLine, ErrorString etc. only if errorHandler is specified.
+-===========================================================================*/
+-static int Err(LPXMLPARSER parser, XMLERRCODE code, ...)
+-{
+- parser->ErrorCode = code;
+- if (HANDLER(error)) {
+- va_list aptr;
+- va_start(aptr, code);
+-
+- if (vsnprintf((char*)parser->ErrorString, 128, GetErrorString(code), aptr) == -1)
+- parser->ErrorString[127] = '\0';
+- va_end(aptr);
+-
+- parser->ErrorColumn = XMLParser_GetCurrentColumn(parser);
+- parser->ErrorLine = XMLParser_GetCurrentLine(parser);
+- HANDLER(error)(parser);
+- }
+- return 0;
+-}
+-
+-/*===========================================================================
+- FUNCTION
+- ErrP
+- PARAMS
+- parser this
+- code error code
+- posOffset bytes to go back in the PREADER->buf (usually token/chSize)
+- NOTES
+- PREADERDATA->col can go below 0 when WS_NOT_ALLOWED and position
+- contains LF/CR, we cannot go to previous line cos PREADERDATA->col
+- for prev line isn't known.
+-===========================================================================*/
+-static int ErrP(LPXMLPARSER parser, XMLERRCODE code, int posOffset)
+-{
+- DPOS(posOffset);
+- if(PREADERDATA->col < 0) PREADERDATA->col = 0;
+- return Err(parser, code);
+-}
+-
+-/*===========================================================================
+- FUNCTION
+- SetReaderFatal
+- DESC
+- for ISFATAL macro
+-===========================================================================*/
+-static void SetReaderFatal(LPXMLPARSER parser, int code)
+-{
+- switch(code)
+- {
+- case BIS_ERR_MEMALLOC:
+- Err(parser, ERR_XMLP_MEMORY_ALLOC);
+- break;
+- case BIS_ERR_ENCODING:
+- Err(parser, ERR_XMLP_ENCODING);
+- break;
+- case BIS_ERR_USER:
+- /* must switch here when there's more possible
+- errors than ERR_XMLP_ILLEGAL_CHAR */
+- Err(parser, ERR_XMLP_ILLEGAL_CHAR, parser->ErrorCode);
+- break;
+- default:
+- Err(parser, ERR_XMLP_READER_FATAL, code);
+- }
+-}
+-
+-/*===========================================================================
+- FUNCTION
+- ParseCharRef
+- DESC
+- Parses character reference
+- PARAMS
+- parser this
+- ref out buffer for char ref (max 4 bytes UTF-8 char)
+- RETURNS
+- Success: 1
+- Failure: 0 (Error is set)
+-===========================================================================*/
+-static int ParseCharRef(LPXMLPARSER parser, XMLCH *ref)
+-{
+- int chSize, base, n, i = 0;
+- unsigned int code = 0;
+- XMLCH *c;
+-
+- if (!(c = ReadCh(parser, &chSize))) goto ExitErr;
+-
+- if (*c == 'x')
+- base = 16;
+- else {
+- DPOS(chSize);
+- base = 10;
+- }
+-
+- while ((c = ReadCh(parser, &chSize))) {
+- if (chSize != 1) goto ExitErr;
+-
+- if (*c == ';') {
+- if (!i) goto ExitErr;
+- break;
+- }
+- else if((*c >= '0' && *c <= '9') ||
+- (base == 16 && ((*c >= 'A' && *c <= 'F') ||
+- (*c >= 'a' && *c <= 'f'))))
+- i++;
+- else goto ExitErr;
+- }
+-
+- if (!c) return Err(parser, ERR_XMLP_EXPECTED_TOKEN, ";");
+- c = PREADER->buf+PREADER->pos-(i + 1);
+-
+- while(i--) {
+- n = *c++;
+- if(n >= '0' && n <= '9')
+- code = code * base + (n - '0');
+- else if(n >= 'A' && n <= 'F')
+- code = code * base + 10 + (n - 'A');
+- else
+- code = code * base + 10 + (n - 'a');
+- }
+-
+- if (code < 0x80) { /* < UTF_BYTE1 max */
+- if (ISILLBYTE(code))
+- return Err(parser, ERR_XMLP_ILLEGAL_CHAR, code);
+- ref[0] = (char)code;
+- return 1;
+- }
+- else if (code < 0x800) { /* < UTF_BYTE2 max */
+- if (ISILL2BYTE(code))
+- return Err(parser, ERR_XMLP_ILLEGAL_CHAR, code);
+- ref[0] = ((code >> 6) | UTF8_2BYTES);
+- ref[1] = ((code & 0x3f) | 0x80);
+- return 2;
+- }
+- else if (code < 0x10000) { /* < UTF_BYTE3 max */
+- ref[0] = ((code >> 12) | UTF8_3BYTES);
+- ref[1] = (((code >> 6) & 0x3f) | 0x80);
+- ref[2] = ((code & 0x3f) | 0x80);
+- return 3;
+- }
+- else if (code < 0x110000) { /* < UTF_BYTE4 max */
+- ref[0] = ((code >> 18) | UTF8_4BYTES);
+- ref[1] = (((code >> 12) & 0x3f) | 0x80);
+- ref[2] = (((code >> 6) & 0x3f) | 0x80);
+- ref[3] = ((code & 0x3f) | 0x80);
+- return 4;
+- }
+-
+- return Err(parser, ERR_XMLP_ILLEGAL_CHAR, code);
+-ExitErr:
+-if (!parser->ErrorCode)
+- ErrP(parser, ERR_XMLP_INVALID_TOKEN, (chSize) ? chSize : 1);
+-return 0;
+-}
+-
+-/*===========================================================================
+- FUNCTION
+- ParseEntityRef
+- DESC
+- Parses and expands entity references
+- PARAMS
+- parser this
+- sbuf output string buffer
+- pAtt indicates that current context is attribute value buffer
+- Context 1: expand only char refs
+- RETURNS
+- Success: 1
+- Failure: 0 (Error is set)
+-===========================================================================*/
+-static int ParseEntityRef(LPXMLPARSER parser, LPXMLSTRINGBUF sbuf,
+- LPXMLRUNTIMEATT pAtt, int Context)
+-{
+- int chSize, namepos, i;
+- XMLCH *c;
+-
+- if (!(c = ReadCh(parser, &chSize))) {
+- if (!parser->ErrorCode)
+- ErrP(parser, ERR_XMLP_INVALID_TOKEN, 1);
+- return 0;
+- }
+-
+- if (*c == '#') {
+- XMLCH ref[4];
+- namepos = PREADER->pos-2;
+- if (!(i = ParseCharRef(parser, ref))) return 0;
+- if (Context == 1 && i == 1 &&
+- (ref[0] == (XMLCH)0xA || ref[0] == (XMLCH)0xD)) {
+- /* expanding values in internal !ENTITY decl must preserve LF and CR
+- note that
can be something like
*/
+- if (ISNULLSTR(XMLStringbuf_Append(sbuf, PREADER->buf+namepos,
+- PREADER->pos-namepos)))
+- return Err(parser, ERR_XMLP_MEMORY_ALLOC);
+- }
+- else if (ISNULLSTR(XMLStringbuf_Append(sbuf, ref, i)))
+- return Err(parser, ERR_XMLP_MEMORY_ALLOC);
+- }
+- else {
+- int namelen, endChars=1;
+- DPOS(chSize);
+- namepos = ParseNameTok(parser, &namelen, (int*)NULL, ";", &endChars);
+- if (namepos == -1) return 0;
+- if (!endChars)
+- return ErrP(parser, ERR_XMLP_WS_NOT_ALLOWED, 1);
+-
+- if (Context == 1) {
+- if (ISNULLSTR(XMLStringbuf_Append(sbuf, PREADER->buf+(namepos-1), namelen+2)))
+- return Err(parser, ERR_XMLP_MEMORY_ALLOC);
+- return 1;
+- }
+-
+- /* we can use the actual buffer since name cannot end to CR or LF or
+- to char that is significant to position functions */
+- c = BUFTOSTR(PREADER->buf, namepos, namelen+namepos);
+-
+- if (namelen < 5) { /* some short circuiting */
+- /* expand predefined entities: */
+- const STDENTITIES *e = stdEntities;
+- for (; (*e).szEntity; e++) {
+- if (namelen == (*e).len && !memcmp(c, (*e).szEntity, namelen)) {
+- if (ISNULLSTR(XMLStringbuf_AppendCh(sbuf, (*e).chExpanded)))
+- return Err(parser, ERR_XMLP_MEMORY_ALLOC);
+- return 1;
+- }
+- }
+- }
+-#ifdef DTD_SUPPORT
+- if (_XMLParser_GetFlag(parser, XMLFLAG_PRESERVE_GENERAL_ENTITIES)) {
+-#endif
+- c = PREADER->buf+(namepos-1);
+- c[namelen+1] = ';';
+- if (ISNULLSTR(XMLStringbuf_Append(sbuf, c, namelen+2)))
+- return Err(parser, ERR_XMLP_MEMORY_ALLOC);
+- return 1;
+-#ifdef DTD_SUPPORT
+- }
+- else if ((i = (int)XMLHTable_Lookup(RT->entitiesTable, c))) {
+-
+- LPXMLENTITY e = XMLVector_Get(RT->entities, i-1);
+-
+- if (e->open)
+- return Err(parser, ERR_XMLP_RECURSIVE_ENTITY_REF, c);
+-
+- if (pAtt)
+- ParseIntEntityAtt(parser, e, pAtt);
+- else {
+- if (sbuf->len) {
+- if (HANDLER(characters)) {
+- if (HANDLER(characters)(parser->UserData, sbuf->str, sbuf->len)
+- == XML_ABORT) return Err(parser, ERR_XMLP_ABORT);
+- }
+- if (!XMLStringbuf_SetLength(sbuf, 0))
+- return Err(parser, ERR_XMLP_MEMORY_ALLOC);
+- }
+- if (e->type == XML_ENTITY_EXT_GEN &&
+- (!_XMLParser_GetFlag(parser, XMLFLAG_EXTERNAL_GENERAL_ENTITIES))) {
+- if (HANDLER(skippedEntity)) { /* report skippedEntity: */
+- if (HANDLER(skippedEntity)(parser->UserData, c)==XML_ABORT)
+- return Err(parser, ERR_XMLP_ABORT);
+- }
+- }
+- else {
+- ParseEntityContent(parser, e);
+- }
+- }
+- }
+- else { /* XMLHTable_Lookup didn't find entity: */
+- if (_XMLParser_GetFlag(parser, XMLFLAG_UNDEF_GENERAL_ENTITIES))
+- return Err(parser, ERR_XMLP_UNDEF_ENTITY, c);
+-
+- if (!pAtt) {
+- if (sbuf->len) {
+- if (HANDLER(characters)) {
+- if (HANDLER(characters)(parser->UserData, sbuf->str, sbuf->len)
+- == XML_ABORT) return Err(parser, ERR_XMLP_ABORT);
+- }
+- if (!XMLStringbuf_SetLength(sbuf, 0))
+- return Err(parser, ERR_XMLP_MEMORY_ALLOC);
+- }
+- if (HANDLER(skippedEntity)) { /* report skippedEntity: */
+- if (HANDLER(skippedEntity)(parser->UserData, c)==XML_ABORT)
+- return Err(parser, ERR_XMLP_ABORT);
+- }
+- }
+- }
+-#endif /* DTD_SUPPORT */
+- }
+- return (parser->ErrorCode == 0);
+-}
+-
+-/*===========================================================================
+- FUNCTION
+- ParseContent
+- DESC
+- Parses reader buffer "outside tags"
+- RETURNS
+- 0 failure
+- 1 success
+- NOTES
+- iLT is used as index of < char in PREADER->buf
+- iLF is used as index of last 0xA char in PREADER->buf
+- these are used as offsets in BufferedIStream_ResetBuf call.
+-===========================================================================*/
+-static int ParseContent(LPXMLPARSER parser)
+-{
+- int chSize, iLT, iLF, isWS=1;
+- XMLCH *c;
+- iLT = iLF = 0;
+-
+- while((c = ReadCh(parser, &chSize))) {
+-
+- if (chSize == 1) {
+- if (*c == (XMLCH)0xA) {
+- iLF = PREADER->pos;
+- }
+- else {
+- if (*c == '<') {
+- if (iLF) iLT = PREADER->pos - iLF;
+- else if (PREADER->pos > 4096) {
+- iLF = PREADER->pos-1;
+- iLT = 1;
+- }
+- break;
+- }
+-
+- if (isWS && !isspace(*c)) {
+- if (!RT->tagstack->length)
+- return ErrP(parser, ERR_XMLP_INVALID_AT_TOP, 1);
+- isWS = 0;
+- }
+-
+- if (*c == '&') {
+- if (!ParseEntityRef(parser, &RT->charsBuf,
+- (LPXMLRUNTIMEATT)NULL, 2)) return 0;
+- continue;
+- }
+- else if (*c == '>' && RT->charsBuf.len > 1) {
+- if (*(c-2) == ']' && *(c-1) == ']')
+- return ErrP(parser, ERR_XMLP_INVALID_TOKEN, 3);
+- }
+- }
+- }
+- else if (isWS) {
+- if (!RT->tagstack->length)
+- return ErrP(parser, ERR_XMLP_INVALID_AT_TOP, chSize);
+- isWS = 0;
+- }
+- if (ISNULLSTR(XMLStringbuf_Append(&RT->charsBuf, c, chSize)))
+- return Err(parser, ERR_XMLP_MEMORY_ALLOC);
+- }
+-
+- if (parser->ErrorCode) return 0;
+-
+- if (RT->charsBuf.len) {
+- if (isWS) {
+- if (HANDLER(ignorableWhitespace) && RT->tagstack->length) {
+- if (HANDLER(ignorableWhitespace)(parser->UserData, RT->charsBuf.str,
+- RT->charsBuf.len) == XML_ABORT)
+- return Err(parser, ERR_XMLP_ABORT);
+- }
+- }
+- else {
+- if (HANDLER(characters)) {
+- if (HANDLER(characters)(parser->UserData, RT->charsBuf.str, RT->charsBuf.len)
+- == XML_ABORT)
+- return Err(parser, ERR_XMLP_ABORT);
+- }
+- }
+- if (!XMLStringbuf_SetLength(&RT->charsBuf, 0))
+- return Err(parser, ERR_XMLP_MEMORY_ALLOC);
+- }
+-
+- if (iLT) {
+- if (ISFATAL(BufferedIStream_ResetBuf(PREADER, iLF))) return 0;
+- PREADER->pos+=iLT;
+- }
+- return (c != (XMLCH*)NULL);
+- /* NOTE: we can exit returning 0 at any time, RT->charsBuf is emptied
+- in error condition in _Parse. */
+-}
+-
+-/*===========================================================================
+- FUNCTION
+- ParseEndTag
+- DESC
+- Parses end tag and compares it to tag at the top of tagstack.
+- RETURNS
+- 0 failure
+- 1 success
+-===========================================================================*/
+-static int ParseEndTag(LPXMLPARSER parser)
+-{
+- int namepos, namelen, endChars = 1;
+- LPXMLRUNTIMETAG pTag;
+- XMLCH *s;
+-
+- IPOS(1); /* skip / */
+-
+- namepos = ParseNameTok(parser, &namelen, (int*)NULL, ">", &endChars);
+- if (namepos == -1) return 0;
+-
+- if (!endChars) {
+- if (!namelen)
+- return ErrP(parser, ERR_XMLP_WS_NOT_ALLOWED, 1);
+- if (!(RequireCh(parser, '>', 1))) return 0;
+- }
+-
+- /* we get significant performance boost using BUFTOSTR instead of
+- _ToString (no mallocs or frees) but have to be careful with these:
+- 1) no bounds checking
+- 2) buffer must have room for \0
+- 3) no _Read operations when using BUFTOSTR buffer */
+-
+- s = BUFTOSTR(PREADER->buf, namepos, namelen+namepos);
+-
+- if ((RT->tagstack->length-1) < PREADERDATA->stackLevel)
+- return Err(parser, ERR_XMLP_INVALID_END_TAG, s);
+-
+- if ((pTag = STACK_PEEK(RT->tagstack)))
+- {
+- if (!strcmp(pTag->qname, s)) {
+- if (HANDLER(endElement)) {
+- if (HANDLER(endElement)(parser->UserData, pTag->uri,
+- pTag->localName, pTag->qname) == XML_ABORT) {
+- Err(parser, ERR_XMLP_ABORT);
+- }
+- }
+- }
+- else {
+- Err(parser, ERR_XMLP_EXPECTED_FOUND, pTag->qname, s);
+- }
+-
+- XMLStringbuf_Free(&pTag->nameBuf); /* frees localName too */
+- if (pTag->Scope!=NULL) {
+- XMLHTable_Destroy(pTag->Scope, DestroyUriTableProc, 1);
+- free(pTag->Scope);
+- }
+- RT->nsScope = pTag->prevScope;
+- STACK_REMOVE(RT->tagstack);
+- }
+- else {
+- return Err(parser, ERR_XMLP_EXPECTED_TOKEN, s);
+- }
+-
+- return (parser->ErrorCode == 0);
+-}
+-
+-/*===========================================================================
+- FUNCTION
+- ParseString
+- DESC
+- Parses string literal
+- PARAMS
+- parser this
+- sbuf output string buffer
+- pAtt indicates that current context is attribute value buffer
+- Normalize whether to perform normalization
+- entHandling 0: expand none, 1: expand char refs 2: expand all
+- RETURNS
+- Success: String
+- Failure: NULL string (Error is set)
+-===========================================================================*/
+-static XMLCH *ParseString(LPXMLPARSER parser, LPXMLSTRINGBUF sbuf,
+- LPXMLRUNTIMEATT pAtt, int Normalize, int entHandling)
+-{
+- int chSize;
+- int startPos = sbuf->len;
+- XMLCH *c, quote;
+-
+- if (SkipWS(parser, "String") == -1)
+- return (XMLCH*)NULL;
+-
+- quote = PREADER->buf[PREADER->pos];
+-
+- if (ISQUOTE(quote)) {
+- IPOS(1);
+-
+- while((c = ReadCh(parser, &chSize))) {
+- if (chSize == 1) {
+- if (Normalize && isspace(*c)) {
+- if (sbuf->len == startPos) continue; /* trim start */
+- if (ISNULLSTR(XMLStringbuf_AppendCh(sbuf, ' '))) {
+- Err(parser, ERR_XMLP_MEMORY_ALLOC);
+- return (XMLCH*)NULL;
+- }
+- while((c = ReadCh(parser, &chSize))) { /* normalize */
+- if (chSize != 1) break;
+- if (!isspace(*c)) break;
+- }
+- if (!c) break;
+- if (chSize != 1) {
+- if (ISNULLSTR(XMLStringbuf_Append(sbuf, c, chSize))) {
+- Err(parser, ERR_XMLP_MEMORY_ALLOC);
+- return (XMLCH*)NULL;
+- }
+- continue;
+- }
+- }
+-
+- if (*c == quote) {
+- if (Normalize && sbuf->len && sbuf->str[sbuf->len-1] == ' ')
+- sbuf->len--; /* trim end */
+- if (ISNULLSTR(XMLStringbuf_ToString(sbuf))) {
+- Err(parser, ERR_XMLP_MEMORY_ALLOC);
+- return (XMLCH*)NULL;
+- }
+- return sbuf->str;
+- }
+- else if (entHandling && *c == '&') {
+- if (!ParseEntityRef(parser, sbuf, pAtt, entHandling))
+- return (XMLCH*)NULL;
+- continue;
+- }
+- else if (*c == '<' && pAtt) {
+- ErrP(parser, ERR_XMLP_INVALID_TOKEN, 1);
+- return (XMLCH*)NULL;
+- }
+- }
+- if (ISNULLSTR(XMLStringbuf_Append(sbuf, c, chSize))) {
+- Err(parser, ERR_XMLP_MEMORY_ALLOC);
+- return (XMLCH*)NULL;
+- }
+- }
+- }
+- if (!parser->ErrorCode)
+- Err(parser, ERR_XMLP_EXPECTED_TOKEN, "String");
+- return (XMLCH*)NULL;
+-}
+-
+-/*===========================================================================
+- FUNCTION
+- ReadCh
+- DESC
+- returns UTF-8 char from input
+- PARAMS
+- parser this
+- chSize out: length of char
+- RETURNS
+- Success: XMLCH* to character
+- Failure: NULL string (NOTE: Error might be set but not necessarily)
+- NOTES
+- ReadCh handles Carriage Return normalization +
+- line and col stuff
+-===========================================================================*/
+-static XMLCH *ReadCh(LPXMLPARSER parser, int *chSize)
+-{
+- XMLCH *c;
+- int ret;
+-
+- if (!PREADER->buf || PREADER->pos >= PREADER->bytesavail) {
+- ret = PEEKINPUT((const BYTE*)NULL, 1);
+- if (ISFATAL(ret) || ret) {
+- *chSize = 0;
+- return (XMLCH*)NULL;
+- }
+- }
+- c = PREADER->buf+PREADER->pos;
+- UTF8LEN(c,*chSize);
+-
+- if (*chSize == 1) {
+- PREADER->pos++;
+- if (*c == 0xD) {
+- if (!PREADERDATA->noPos) {
+- PREADERDATA->line++;
+- PREADERDATA->col=0;
+- }
+- PREADER->buf[PREADER->pos-1] = 0xA;
+- if (PREADER->pos >= PREADER->bytesavail) {
+- ret = PEEKINPUT((const BYTE*)NULL, 1);
+- if (ISFATAL(ret)) {
+- *chSize = 0;
+- return (XMLCH*)NULL;
+- }
+- c = PREADER->buf+(PREADER->pos-1);
+- if (ret) return(c);
+- }
+- if (PREADER->buf[PREADER->pos] == 0xA) PREADER->pos++;
+- }
+- else if (*c == 0xA && !PREADERDATA->noPos) {
+- PREADERDATA->line++;
+- PREADERDATA->col=0;
+- }
+- else if (!PREADERDATA->noPos) PREADERDATA->col++;
+- }
+- else {
+- PREADER->pos += *chSize;
+- if (!PREADERDATA->noPos) PREADERDATA->col += *chSize;
+- }
+- return(c);
+-}
+-
+-/*===========================================================================
+- FUNCTION
+- SkipWS
+- DESC
+- skips whitespace and is used to determine whitespace too
+- PARAMS
+- parser this
+- expectedErr if end of input is encoutered this error is triggered
+- RETURNS
+- Success: number of whitespace bytes
+- Failure: -1 (error is set)
+-===========================================================================*/
+-static int SkipWS(LPXMLPARSER parser, XMLCH *expectedErr)
+-{
+- int l=0, chSize;
+- XMLCH *c;
+- while((c = ReadCh(parser, &chSize))) {
+- if (chSize != 1 || !isspace(*c)) {
+- DPOS(chSize); /* ACHTUNG! */
+- return l;
+- }
+- l++;
+- }
+- if (!parser->ErrorCode && expectedErr)
+- Err(parser, ERR_XMLP_EXPECTED_TOKEN, expectedErr);
+- return -1;
+-}
+-
+-/*===========================================================================
+- FUNCTION
+- RequireCh
+- DESC
+- requires char in the input
+- PARAMS
+- parser this
+- ch character that's required
+- allowWS whether to allow whitespace to appear before char is found
+- RETURNS
+- Success: 1
+- Failure: 0 (error is set)
+-===========================================================================*/
+-static int RequireCh(LPXMLPARSER parser, XMLCH ch, int allowWS)
+-{
+- XMLCH *c;
+- int chSize;
+-
+- while((c = ReadCh(parser, &chSize))) {
+- if (chSize == 1) {
+- if (*c == ch) return 1;
+- else if (isspace(*c)) {
+- if (!allowWS)
+- return ErrP(parser, ERR_XMLP_WS_NOT_ALLOWED, 1);
+- continue;
+- }
+- }
+- break;
+- }
+- if (!parser->ErrorCode) {/* ReadCh might set parser err */
+- XMLCH tok[2];
+- tok[0] = ch;
+- tok[1] = '\0';
+- if (chSize) DPOS(chSize);
+- Err(parser, ERR_XMLP_EXPECTED_TOKEN, tok);
+- }
+- return 0;
+-}
+-
+-/*===========================================================================
+- FUNCTION
+- ParseNameTok
+- DESC
+- Parses name token
+- PARAMS
+- parser this
+- len out pointer - length of name
+- prefixLen out pointer - length of prefix. Can be NULL pointer when
+- prefix isn't needed
+- endChars chars that are legal to end name scanning (besides space chars)
+- cEndChars in/out pointer - in: count of endChars
+- out: position of endChar found or 0 if whitespace
+- was found instead
+- RETURNS
+- Success: start position of name in reader buffer
+- Failure: -1 (Error is set)
+- NOTES
+- len might be 0 if skipWS isn't called before ParseNameTok call.
+-===========================================================================*/
+-static int ParseNameTok(LPXMLPARSER parser, int *len,
+- int *prefixLen, XMLCH *endChars, int *cEndChars)
+-{
+- int chSize, spos = PREADER->pos;
+- int prefix = (prefixLen) ? 0 : -1;
+- XMLCH *c;
+- *len = 0;
+-
+- while ((c = ReadCh(parser, &chSize))) {
+- if (!*len || (prefix == *len)) {
+- if (chSize == 1) {
+- if (!ISMAPCH(nameStartAscii, *c)) break;
+- }
+- else if (chSize == 2) { // 2-byte sequence
+- if (!utf8_isNmstrt2(c)) break;
+- }
+- else if (chSize == 3) { // 3-byte sequence
+- if (!utf8_isNmstrt3(c)) break;
+- }
+- else break;
+- }
+- else {
+- if (chSize == 1) {
+- if (!ISMAPCH(nameAscii, *c)) break;
+- if (!prefix && *c == ':') prefix = *len+1;
+- }
+- else if (chSize == 2) { // 2-byte sequence
+- if (!utf8_isName2(c)) break;
+- }
+- else if (chSize == 3) { // 3-byte sequence
+- if (!utf8_isName3(c)) break;
+- }
+- /* else if ((*c & 0xf8) == 0xf0) { // 4-byte sequence */
+- else break;
+- }
+- (*len)+=chSize;
+- }
+-
+- if (!c) {
+- if (!parser->ErrorCode) {
+- XMLCH t[5] = "Name";
+- if (*cEndChars && *len) {
+- t[0] = endChars[(*cEndChars)-1];
+- t[1] = '\0';
+- }
+- Err(parser, ERR_XMLP_EXPECTED_TOKEN, t);
+- }
+- return -1;
+- }
+-
+- while (*cEndChars) {
+- if (*c == endChars[--(*cEndChars)]) {
+- (*cEndChars)++;
+- if (!*len) {
+- Err(parser, ERR_XMLP_EXPECTED_TOKEN, "Name");
+- return -1;
+- }
+- break;
+- }
+- }
+-
+- if (!*cEndChars) {
+- if (!isspace(*c)) {
+- ErrP(parser, ERR_XMLP_INVALID_NAME, chSize);
+- return -1;
+- }
+- }
+- if (prefixLen) *prefixLen = (prefix>0) ? prefix-1 : 0;
+- return spos;
+-}
+-
+-/*===========================================================================
+- FUNCTION
+- Require
+- DESC
+- Requires token in the input
+- PARAMS
+- parser this
+- tok token that is required
+- endChars see ParseNameTok
+- cEndChars see ParseNametok
+- RETURNS
+- Success: 1
+- Failure: 0 (Error is set)
+-===========================================================================*/
+-static int Require(LPXMLPARSER parser, XMLCH *tok,
+- XMLCH *endChars, int *cEndChars)
+-{
+- int chSize, bytesRead=0;
+- XMLCH *c, *token = tok;
+-
+- while(*tok) {
+- if (!(c = ReadCh(parser, &chSize))) goto ExitErr;
+- bytesRead+=chSize;
+- if (chSize > 1) goto ExitErr;
+- if (*c != *tok) break;
+- tok++;
+- }
+-
+- if (*tok) goto ExitErr;
+- if (!(c = ReadCh(parser, &chSize))) goto ExitErr;
+- bytesRead+=chSize;
+- if (chSize > 1) goto ExitErr;
+-
+- while (*cEndChars) {
+- if (*c == endChars[--(*cEndChars)]) {
+- (*cEndChars)++;
+- break;
+- }
+- }
+-
+- if (!*cEndChars && !isspace(*c)) goto ExitErr;
+-
+- return 1;
+-ExitErr:
+- if (bytesRead) DPOS(bytesRead);
+- if (!parser->ErrorCode)
+- Err(parser, ERR_XMLP_EXPECTED_TOKEN, token);
+- return 0;
+-}
+-
+-/*===========================================================================
+- FUNCTION
+- ParseStartTag
+- RETURNS
+- 0 failure
+- 1 success
+-===========================================================================*/
+-static int ParseStartTag(LPXMLPARSER parser)
+-{
+- int namepos, namelen, prefixlen, isEmpty;
+- int endChars = 2;
+- XMLCH *s;
+- LPXMLRUNTIMETAG pTag;
+- LPXMLRUNTIMEATT pAtt; /* for CLEANUPATTS */
+-
+- namepos = ParseNameTok(parser, &namelen, &prefixlen, "/>", &endChars);
+- if (namepos == -1) return 0;
+-
+- if (!endChars) {
+- if (!namelen) return ErrP(parser, ERR_XMLP_WS_NOT_ALLOWED, 1);
+- /* note that isEmpty doesn't have to be initialized, empty check
+- is handled by ParseAttributes */
+- }
+- else if (endChars == 1) {
+- if (!(RequireCh(parser, '>', 0))) return 0;
+- isEmpty = 1;
+- }
+- else isEmpty = 0; /* tag is simple start tag */
+-
+- if (!(pTag = STACK_PUSH(RT->tagstack, NULL)))
+- return Err(parser, ERR_XMLP_MEMORY_ALLOC);
+-
+- if (!(XMLStringbuf_Init(&pTag->nameBuf, 64, 0)))
+- return Err(parser, ERR_XMLP_MEMORY_ALLOC);
+-
+- pTag->localName = pTag->prefix = EmptyStr;
+- pTag->prevScope = RT->nsScope;
+- pTag->Scope = (LPXMLHTABLE)NULL;
+-
+- pTag->qname = XMLStringbuf_Append(&pTag->nameBuf, PREADER->buf+namepos, namelen+1);
+- if (ISNULLSTR(pTag->qname)) return Err(parser, ERR_XMLP_MEMORY_ALLOC);
+- pTag->qname[namelen] = '\0';
+-
+- if (ISNULLSTR(parser->DocumentElement)) {
+- if (RT->doctypeName) {
+- if (strcmp(pTag->qname, RT->doctypeName))
+- return Err(parser, ERR_XMLP_EXPECTED_FOUND, RT->doctypeName, pTag->qname);
+- parser->DocumentElement = RT->doctypeName;
+- }
+- else if (ISNULLSTR((parser->DocumentElement = memdup(pTag->qname, namelen+1))))
+- return Err(parser, ERR_XMLP_MEMORY_ALLOC);
+- }
+- else if (RT->tagstack->length == 1)
+- return Err(parser, ERR_XMLP_MULTIPLE_TOP);
+-
+- if (_XMLParser_GetFlag(parser, XMLFLAG_NAMESPACES)) {
+- if (!endChars) {
+- if (!(ParseAttributes(parser, pTag, &isEmpty))) return 0;
+- }
+-
+- if (prefixlen) {
+- if (!ParseTagNS(parser, pTag, namelen, prefixlen)) return 0;
+- }
+- else if (RT->nsScope != NULL &&
+- ((s = XMLHTable_Lookup(RT->nsScope, TOK_XMLNS))!=NULL)) {
+- pTag->uri = s;
+- }
+- else {
+- pTag->uri = EmptyStr;
+- }
+- }
+- else {
+- if (!endChars) {
+- if (!(ParseAttributes(parser, (LPXMLRUNTIMETAG)NULL, &isEmpty)))
+- return 0;
+- }
+- pTag->uri = EmptyStr;
+- }
+-
+- if (HANDLER(startElement)) {
+- if (HANDLER(startElement)(parser->UserData, pTag->uri,
+- pTag->localName, pTag->qname, RT->atts) == XML_ABORT)
+- return Err(parser, ERR_XMLP_ABORT);
+- }
+-
+- if (isEmpty) {
+- if (HANDLER(endElement)) {
+- if (HANDLER(endElement)(parser->UserData, pTag->uri,
+- pTag->localName, pTag->qname) == XML_ABORT)
+- return Err(parser, ERR_XMLP_ABORT);
+- }
+- XMLStringbuf_Free(&pTag->nameBuf);
+- if (pTag->Scope!=NULL) {
+- XMLHTable_Destroy(pTag->Scope, DestroyUriTableProc, 1);
+- free(pTag->Scope);
+- }
+- RT->nsScope = pTag->prevScope;
+- STACK_REMOVE(RT->tagstack);
+- }
+-
+- CLEANUP_ATTS;
+- return 1;
+-}
+-
+-/*===========================================================================
+- FUNCTION
+- ParseTagNS
+- DESC
+- Set tag's namespace uri, localName and prefix
+- PARAMS
+- parser this
+- pTag tag from ParseStartTag()
+- pos position of ':' character in pTag->qname
+- RETURNS
+- 0 failure
+- 1 success
+-===========================================================================*/
+-static int ParseTagNS(LPXMLPARSER parser, LPXMLRUNTIMETAG pTag, int namelen, int pos)
+-{
+- pTag->qname = XMLStringbuf_Append(&pTag->nameBuf, pTag->qname, namelen+1);
+- if (ISNULLSTR(pTag->qname)) return Err(parser, ERR_XMLP_MEMORY_ALLOC);
+- /* qname can be relocated! */
+-
+- pTag->prefix=pTag->qname+namelen+1;
+- if (pos == 3 && ISXMLPREFIX(pTag->prefix))
+- return ErrP(parser, ERR_XMLP_INVALID_NAME, 3);
+-
+- pTag->prefix[pos] = '\0';
+- pTag->localName = pTag->prefix+pos+1;
+-
+- if (RT->nsScope == NULL ||
+- ((pTag->uri = XMLHTable_Lookup(RT->nsScope, pTag->prefix))==NULL)) {
+- pTag->uri = EmptyStr;
+- return Err(parser, ERR_XMLP_UNDEF_NSPREFIX, pTag->prefix);
+- }
+- return 1;
+-}
+-
+-/*===========================================================================
+- FUNCTION
+- ParseAttributes
+- DESC
+- Parse attributes and resolve namespace declarations
+- PARAMS
+- parser this
+- pTag tag from ParseStartTag or NULL if ns handling isn't needed.
+- isEmpty for ParseStartTag to indicate that element doesn't have any
+- content.
+- RETURNS
+- 0 failure
+- 1 success
+- TODO
+- split into smaller routines? separate ns decl handling?
+-===========================================================================*/
+-static int ParseAttributes(LPXMLPARSER parser,
+- LPXMLRUNTIMETAG pTag, int *isEmpty)
+-{
+- int attCount, i, nsDefdecl, namepos, namelen, prefixlen, endChars;
+- int processNS = (pTag!=(LPXMLRUNTIMETAG)NULL);
+- int NSprefixes = _XMLParser_GetFlag(parser, XMLFLAG_NAMESPACE_PREFIXES);
+- XMLCH *uri, *s , c;
+- LPXMLRUNTIMEATT pAtt;
+- XMLATTRIBUTETYPE attType;
+-
+- attCount = nsDefdecl = *isEmpty = 0;
+-
+- while (1)
+- {
+- if ((i = SkipWS(parser, TOK_GT)) == -1) return 0;
+- c = PREADER->buf[PREADER->pos];
+-
+- if (c == '>') {
+- IPOS(1);
+- break;
+- }
+-
+- if (c == '/') {
+- IPOS(1);
+- if (!(RequireCh(parser, '>', 0))) return 0;
+- *isEmpty = 1;
+- break;
+- }
+-
+- if (attCount++ && !i)
+- return ErrP(parser, ERR_XMLP_WS_REQUIRED, 0);
+-
+- endChars = 1;
+- namepos = ParseNameTok(parser, &namelen, &prefixlen, "=", &endChars);
+- if (namepos == -1) return 0; /* error is set */
+-
+- if (!endChars && !namelen)
+- return Err(parser, ERR_XMLP_EXPECTED_TOKEN, TOK_GT);
+-
+- if(!(pAtt = XMLVector_Append(RT->atts, NULL)))
+- return Err(parser, ERR_XMLP_MEMORY_ALLOC);
+- pAtt->localName = pAtt->prefix = pAtt->uri = EmptyStr;
+-
+- if (!XMLStringbuf_Init(&pAtt->nameBuf, 64, 0))
+- return Err(parser, ERR_XMLP_MEMORY_ALLOC);
+- pAtt->qname = XMLStringbuf_Append(&pAtt->nameBuf, PREADER->buf+namepos, namelen+1);
+- if (ISNULLSTR(pAtt->qname))
+- return Err(parser, ERR_XMLP_MEMORY_ALLOC);
+- pAtt->qname[namelen] = '\0';
+-
+- if (!endChars) {
+- if (!(RequireCh(parser, '=', 1))) return 0;
+- }
+-
+- if (!XMLStringbuf_Init(&pAtt->valBuf, 64, 0))
+- return Err(parser, ERR_XMLP_MEMORY_ALLOC);
+- pAtt->value = ParseString(parser, &pAtt->valBuf, pAtt,
+- (!(_XMLParser_GetFlag(parser, XMLFLAG_PRESERVE_WS_ATTRIBUTES))), 2);
+- if (ISNULLSTR(pAtt->value)) return 0;
+-
+- /* determine the type of attribute: */
+- if (!processNS)
+- attType = XMLATT_NORMAL;
+- else {
+- if (prefixlen) {
+- if (prefixlen == 5 && ISXMLNSPREFIX(pAtt->qname))
+- attType = XMLATT_PREFIXDECL;
+- else if (prefixlen == 3 && ISXMLPREFIX(pAtt->qname))
+- attType = XMLATT_XMLPREFIXDECL;
+- else
+- attType = XMLATT_WITHNS;
+- }
+- else {
+- if (namelen == 5 && ISXMLNSPREFIX(pAtt->qname))
+- attType = XMLATT_DEFAULTDECL;
+- else
+- attType = XMLATT_NORMAL;
+- }
+- }
+-
+- if (processNS) {
+-
+- if (attType == XMLATT_PREFIXDECL) {
+- /* namespace declaration: */
+- if (!pAtt->valBuf.len)
+- return Err(parser, ERR_XMLP_INVALID_ATT_VALUE, pAtt->qname);
+-
+- INIT_NSSCOPE; /* initialize RT->nsScope */
+-
+- if (ISNULLSTR(uri = prepUri(pAtt->value, 1)))
+- return Err(parser, ERR_XMLP_MEMORY_ALLOC);
+-
+- s = XMLHTable_Insert(RT->nsScope,
+- pAtt->qname+prefixlen+1, (void*)uri);
+- if (!s) return Err(parser, ERR_XMLP_MEMORY_ALLOC);
+- else if (uri != s) {
+- if (*(s-1)) { /* check if declared in this element. see prepURI */
+- free((s-1));
+- return Err(parser, ERR_XMLP_DUPL_ATTRIBUTE, pAtt->qname);
+- }
+- free((s-1));
+- }
+- if (!NSprefixes) {
+- XMLStringbuf_Free(&pAtt->nameBuf);
+- XMLStringbuf_Free(&pAtt->valBuf);
+- XMLVector_Remove(RT->atts, RT->atts->length-1);
+- continue;
+- }
+- pAtt->uri = uriXMLNS; /* note that xmlns or xml prefixes aren't set,
+- only static uris */
+- }
+- else if (attType == XMLATT_XMLPREFIXDECL) {
+- /* predefined xml namespace: */
+- pAtt->localName = pAtt->qname+prefixlen+1;
+-
+- if (!strcmp(pAtt->localName, "space")) {
+- if (!(!strcmp(pAtt->value, "default") ||
+- !strcmp(pAtt->value, "preserve")))
+- return Err(parser, ERR_XMLP_INVALID_ATT_VALUE, pAtt->qname);
+- }
+-
+- INIT_NSSCOPE; /* initialize RT->nsScope */
+-
+- if (ISNULLSTR(uri = prepUri(pAtt->value, 1)))
+- return Err(parser, ERR_XMLP_MEMORY_ALLOC);
+-
+- s = XMLHTable_Insert(RT->nsScope, pAtt->qname, (void*)uri);
+- if (!s) return Err(parser, ERR_XMLP_MEMORY_ALLOC);
+- else if (uri != s) free((s-1)); /* note that pointer must be decremented */
+-
+- pAtt->uri = uriXML; /* static uri */
+- }
+- else if (attType == XMLATT_WITHNS) {
+- /* set prefix and localName (they will be examined later when
+- all atts are collected into vector) */
+- /* note that qname can be relocated */
+- pAtt->qname = XMLStringbuf_Append(&pAtt->nameBuf, pAtt->qname, namelen+1);
+- if (ISNULLSTR(pAtt->qname))
+- return Err(parser, ERR_XMLP_MEMORY_ALLOC);
+-
+- pAtt->prefix=pAtt->qname+namelen+1;
+- pAtt->prefix[prefixlen] = '\0';
+- pAtt->localName = pAtt->prefix+prefixlen+1;
+- }
+- /* test default declaration: */
+- else if (attType == XMLATT_DEFAULTDECL) {
+-
+- if (nsDefdecl)
+- return Err(parser, ERR_XMLP_DUPL_ATTRIBUTE, pAtt->qname);
+-
+- nsDefdecl = 1;
+- INIT_NSSCOPE;
+-
+- if (!pAtt->valBuf.len) { /* undeclaration: */
+- if ((uri = XMLHTable_Remove(RT->nsScope, TOK_XMLNS)) != NULL)
+- free((uri-1)); /* note that pointer must be decremented */
+- }
+- else {
+- if (ISNULLSTR(uri = prepUri(pAtt->value, 1)))
+- return Err(parser, ERR_XMLP_MEMORY_ALLOC);
+-
+- s = XMLHTable_Insert(RT->nsScope, TOK_XMLNS, (void*)uri);
+- if (!s) return Err(parser, ERR_XMLP_MEMORY_ALLOC);
+- else if (uri != s) free((s-1));
+- }
+- if (!NSprefixes) {
+- XMLStringbuf_Free(&pAtt->nameBuf);
+- XMLStringbuf_Free(&pAtt->valBuf);
+- XMLVector_Remove(RT->atts, RT->atts->length-1);
+- continue;
+- }
+- pAtt->uri = uriXMLNS;
+- }
+- } /* processNS (namespaces on) */
+- /* store attribute into namedAtts hashtable; we cannot store
+- direct pointer to Vector item 'cos it might get relocated thus
+- we have to store index to newly added
+- vector item. Same thing applies to RT->entitiesTable.
+- We just use void* hashtable item to hold index, this might change
+- when hashtable gets changed/optimized. */
+- i = (int)XMLHTable_Insert(RT->namedAtts, pAtt->qname, (void*)RT->atts->length);
+- if (RT->atts->length != i) {
+- if (!i) return Err(parser, ERR_XMLP_MEMORY_ALLOC);
+- return Err(parser, ERR_XMLP_DUPL_ATTRIBUTE, pAtt->qname);
+- }
+- }
+-
+- if (processNS && RT->atts->length) {
+- /* test Vector for declared namespace prefixes and set uris. Cannot
+- test attribute prefixes "on the fly" 'cos declaration can follow
+- the prefixed attribute i.e. x:att='val' xmlns:x='uri.org'
+- is legal. */
+- for (i=0; iatts->length; i++) {
+- pAtt = XMLVector_Get(RT->atts, i);
+- if (pAtt->prefix != EmptyStr) {
+- if (RT->nsScope == NULL ||
+- ((uri = XMLHTable_Lookup(RT->nsScope, pAtt->prefix))==NULL))
+- {
+- pAtt->uri = EmptyStr;
+- return Err(parser, ERR_XMLP_UNDEF_NSPREFIX, pAtt->prefix);
+- }
+- pAtt->uri = uri;
+- }
+- }
+- }
+- return 1;
+- /* NOTE: if there's attributes in the vector and error occurs,
+- vector will be emptied in XMLParser_Parse */
+-}
+-
+-/*===========================================================================
+- FUNCTION
+- ParseComment
+- DESC
+- Parses comment tag
+- PARAMS
+- parser this
+- skip TRUE when parsing External DTD
+- RETURNS
+- 0 failure
+- 1 success
+-===========================================================================*/
+-/* NOTE: RT->charsBuf will be emptied in _parse in error condition
+- thus we can return 0 at any time in ParseComment, ParseCData etc. */
+-static int ParseComment(LPXMLPARSER parser, int skip)
+-{
+- int chSize, startPos;
+- XMLCH *c;
+- int bReport = (!skip && HANDLER(comment));
+-
+- IPOS(3);
+- startPos = PREADER->pos + 1;
+-
+- while((c = ReadCh(parser, &chSize))) {
+- if (chSize == 1) {
+- if (*c == '-' && PREADER->pos > startPos) {
+- if (*(c-1) == '-') {
+- if (!RequireCh(parser, '>', 0)) break;
+- if (bReport) {
+- if (HANDLER(comment)(parser->UserData, RT->charsBuf.str,
+- RT->charsBuf.len-1) == XML_ABORT)
+- return Err(parser, ERR_XMLP_ABORT);
+- if (!XMLStringbuf_SetLength(&RT->charsBuf, 0))
+- return Err(parser, ERR_XMLP_MEMORY_ALLOC);
+- }
+- return 1;
+- }
+- }
+- }
+- if (bReport) {
+- if (ISNULLSTR(XMLStringbuf_Append(&RT->charsBuf, c, chSize)))
+- return Err(parser, ERR_XMLP_MEMORY_ALLOC);
+- }
+- }
+-
+- if (!parser->ErrorCode)
+- Err(parser, ERR_XMLP_EXPECTED_TOKEN, "-->");
+- return 0;
+-}
+-
+-/*===========================================================================
+- FUNCTION
+- ParseCData
+- DESC
+- Parses CData tag
+- RETURNS
+- 0 failure
+- 1 success
+-===========================================================================*/
+-static int ParseCData(LPXMLPARSER parser)
+-{
+- int chSize, startPos;
+- XMLCH *c;
+-
+- if (!RT->tagstack->length)
+- return ErrP(parser, ERR_XMLP_INVALID_AT_TOP, 1);
+-
+- IPOS(8);
+- startPos = PREADER->pos + 2; /* start testing ]] when > found */
+-
+- while((c = ReadCh(parser, &chSize))) {
+- if (chSize == 1) {
+- if (*c == '>' && PREADER->pos > startPos) {
+- if (*(c-1) == ']' && *(c-2) == ']') {
+- if (HANDLER(startCDATA)) {
+- if (HANDLER(startCDATA)(parser->UserData) == XML_ABORT)
+- return Err(parser, ERR_XMLP_ABORT);
+-
+- if (HANDLER(characters) && (RT->charsBuf.len - 2) > 0) {
+- if (HANDLER(characters)(parser->UserData,
+- RT->charsBuf.str, RT->charsBuf.len - 2) == XML_ABORT)
+- return Err(parser, ERR_XMLP_ABORT);
+- }
+- }
+-
+- if (HANDLER(endCDATA)) {
+- if (HANDLER(endCDATA)(parser->UserData) == XML_ABORT)
+- return Err(parser, ERR_XMLP_ABORT);
+- }
+- if (!XMLStringbuf_SetLength(&RT->charsBuf, 0))
+- return Err(parser, ERR_XMLP_MEMORY_ALLOC);
+- return 1;
+- }
+- }
+- }
+- if (ISNULLSTR(XMLStringbuf_Append(&RT->charsBuf, c, chSize)))
+- return Err(parser, ERR_XMLP_MEMORY_ALLOC);
+- }
+-
+- if (!parser->ErrorCode)
+- Err(parser, ERR_XMLP_EXPECTED_TOKEN, "]]>");
+- return 0;
+-}
+-
+-/*===========================================================================
+- FUNCTION
+- ParsePI
+- DESC
+- Parses processing instruction tag
+- RETURNS
+- 0 failure
+- 1 success
+-===========================================================================*/
+-static int ParsePI(LPXMLPARSER parser, int skip)
+-{
+- int l, namepos, namelen, endChars = 1;
+- int bReport = (!skip && HANDLER(processingInstruction));
+- XMLCH *target, *data = EmptyStr;
+-
+- IPOS(1);
+- if ((l = SkipWS(parser, TOK_END_PI)) == -1) return 0;
+- if (l) return ErrP(parser, ERR_XMLP_WS_NOT_ALLOWED, 1);
+-
+- namepos = ParseNameTok(parser, &namelen, (int*)NULL, "?", &endChars);
+- if (namepos == -1) return 0; /* error is set */
+-
+- target = BUFTOSTR(PREADER->buf, namepos, namepos+namelen);
+-
+- if (namelen == 3 && !stricmp(target, TOK_XML))
+- return Err(parser, ERR_XMLP_INVALID_DECL, TOK_XML);
+-
+- if (endChars) {
+- if (!RequireCh(parser, '>', 0)) return 0;
+- }
+- else {
+- int startPos, chSize;
+- XMLCH *c;
+-
+- if (SkipWS(parser, TOK_END_PI) == -1) return 0;
+- startPos = PREADER->pos + 1;
+-
+- while((c = ReadCh(parser, &chSize))) {
+- if (chSize == 1) {
+- if (*c == '>' && PREADER->pos > startPos) {
+- if (*(c-1) == '?') {
+- if (bReport && (RT->charsBuf.len - 1) > 0) {
+- data = RT->charsBuf.str;
+- data[RT->charsBuf.len-1] = '\0';
+- }
+- break;
+- }
+- }
+- }
+- if (bReport) {
+- if (ISNULLSTR(XMLStringbuf_Append(&RT->charsBuf, c, chSize)))
+- return Err(parser, ERR_XMLP_MEMORY_ALLOC);
+- }
+- }
+- if (parser->ErrorCode) return 0;
+- if (!c) return Err(parser, ERR_XMLP_EXPECTED_TOKEN, TOK_END_PI);
+- }
+-
+- if (bReport) {
+- if (HANDLER(processingInstruction)(parser->UserData,
+- target, data) == XML_ABORT) {
+- return Err(parser, ERR_XMLP_ABORT);
+- }
+- if (!XMLStringbuf_SetLength(&RT->charsBuf, 0))
+- return Err(parser, ERR_XMLP_MEMORY_ALLOC);
+- }
+- return 1;
+-}
+-
+-/*===========================================================================
+- FUNCTION
+- SetEncoding
+- DESC
+- Sets parser's BUFFEREDISTREAM encode handler
+- PARAMS
+- parser this
+- encodingName encoding name as string
+- RETURNS
+- 0 failure
+- 1 success
+-===========================================================================*/
+-static int SetEncoding(LPXMLPARSER parser, XMLCH *encodingName)
+-{
+- LPFNENCODE fnEncode;
+-
+- if (!stricmp(encodingName, "UTF-8"))
+- fnEncode = Utf8Validator;
+- else if (!stricmp(encodingName, "ISO-8859-1"))
+- fnEncode = Latin1ToUtf8;
+- else if (!stricmp(encodingName, "US-ASCII"))
+- fnEncode = Latin1ToUtf8; /* hmm */
+- else
+- return Err(parser, ERR_XMLP_UNSUP_ENCODING, encodingName);
+-
+- if (!PREADER->encode) PREADER->encode = fnEncode;
+- return 1;
+-}
+-
+-/*===========================================================================
+- FUNCTION
+- ParseXmlDecl
+- DESC
+- Parses xmldecl / textdecl
+- PARAMS
+- parser this
+- skip TRUE when parsing External entity or external DTD
+- RETURNS
+- 0 failure
+- 1 success
+- NOTES
+- Called from DetectEncoding.
+-===========================================================================*/
+-static int ParseXmlDecl(LPXMLPARSER parser, int skip)
+-{
+- int l, iver, ienc, ista, count=0;
+- XMLCH *enc, *sta, *ver, c;
+- iver = ienc = ista = -1;
+- IPOS(5); /* skip buf[PREADER->pos];
+-
+- if (c == '?') {
+- IPOS(1);
+- if (!(RequireCh(parser, '>', 0))) return 0;
+- break;
+- }
+-
+- if (!l)
+- return ErrP(parser, ERR_XMLP_WS_REQUIRED, 0);
+-
+- l = 1;
+- if (c == 'v') {
+- if (iver != -1 || count) return 0;
+- if (!Require(parser, "version", "=", &l)) return 0;
+- iver = RT->charsBuf.len;
+- }
+- else if (c == 'e') {
+- if (skip) {
+- if (ienc != -1) return 0;
+- }
+- else {
+- if (count != 1 || ienc != -1) return 0;
+- }
+- if (!Require(parser, "encoding", "=", &l)) return 0;
+- ienc = RT->charsBuf.len;
+- }
+- else if (c == 's') {
+- if (iver == -1 || ista != -1 || skip) return 0;
+- if (!Require(parser, "standalone", "=", &l)) return 0;
+- ista = RT->charsBuf.len;
+- }
+- else return 0;
+-
+- if (!l && !RequireCh(parser, '=', 1)) return 0;
+- if (!ParseString(parser, &RT->charsBuf, NULL, 0, 0)) return 0;
+- RT->charsBuf.len++; /* skip NUL in XMLStringbuf buffer */
+- count++;
+- }
+-
+- if (!count) return 0;
+-
+- ver = (iver == -1) ? (XMLCH*)NULL : RT->charsBuf.str+iver;
+- enc = (ienc == -1) ? (XMLCH*)NULL : RT->charsBuf.str+ienc;
+- sta = (ista == -1) ? (XMLCH*)NULL : RT->charsBuf.str+ista;
+-
+- if (ver) {
+- if (strcmp(ver, "1.0")) return 0;
+- }
+- else {
+- if (!skip) return 0;
+- }
+-
+- if (enc && !SetEncoding(parser, enc)) return 0;
+- if (sta) {
+- if (strcmp(sta, "no")) {
+- if (strcmp(sta, "yes")) return 0;
+- }
+- }
+-
+- if (!skip && HANDLER(xmlDecl)) {
+- if (HANDLER(xmlDecl)(parser->UserData, ver, enc, sta) == XML_ABORT)
+- return Err(parser, ERR_XMLP_ABORT);
+- }
+- return 1;
+-}
+-
+-/*===========================================================================
+- FUNCTION
+- DetectEncoding
+- DESC
+- Detects document encoding and xmldecl/textdecl
+- PARAMS
+- parser this
+- skip TRUE this is external entity/DTD
+- FALSE this is main document entity (report xmldecl)
+- defaultEncoding encoding to be used if none is detected
+- RETURNS
+- 0 failure
+- 1 success
+-===========================================================================*/
+-static int DetectEncoding(LPXMLPARSER parser, int skip, LPFNENCODE defaultEncoding)
+-{
+- int ret;
+- if (!(ret = PEEKINPUT((const XMLCH*)NULL, 4))) {
+- if (PREADER->buf[0]==(BYTE)0xEF &&
+- PREADER->buf[1]==(BYTE)0xBB &&
+- PREADER->buf[2]==(BYTE)0xBF) {
+- if (!PREADER->encode) PREADER->encode = Utf8Validator;
+- if (ISFATAL(BufferedIStream_ResetBuf(PREADER, 3))) return 0;
+- }
+- else {
+- /* hmmm atleast we give some kind of hint here -
+- testing only 1st byte of possible BOMs: */
+- if (PREADER->buf[0]==(BYTE)0x00 ||
+- PREADER->buf[0]==(BYTE)0xFE ||
+- PREADER->buf[0]==(BYTE)0xFF)
+- return Err(parser, ERR_XMLP_UNSUP_ENCODING, "UNKNOWN");
+- }
+- }
+- if (ISFATAL(ret)) return 0;
+-
+- if (!(ret = PEEKINPUT("ErrorCode)
+- Err(parser, ERR_XMLP_INVALID_DECL, "xml");
+- return 0;
+- }
+- if (!XMLStringbuf_SetLength(&RT->charsBuf, 0))
+- return Err(parser, ERR_XMLP_MEMORY_ALLOC);
+- }
+-
+- if (ISFATAL(ret)) return 0;
+- /* set default encoding if there isn't any specified: */
+- if (!PREADER->encode) PREADER->encode = defaultEncoding;
+-
+- if (PREADER->pos) {
+- if (ISFATAL(BufferedIStream_ResetBuf(PREADER, PREADER->pos))) return 0;
+- }
+-
+- if ((ret = BufferedIStream_EncodeBuffer(PREADER, 0))) {
+- SetReaderFatal(parser, ret);
+- return 0;
+- }
+- return 1;
+-}
+-
+-#ifndef HAS_STRICMP
+-/*===========================================================================
+- FUNCTION
+- stricmp
+- DESC
+- case-insensitive strcmp
+-===========================================================================*/
+-static int stricmp(const char *s1, const char *s2)
+-{
+- char c1, c2;
+- while(1)
+- {
+- c1 = toupper(*s1++);
+- c2 = toupper(*s2++);
+- if(c1 == 0 && c2 == 0)
+- return 0;
+- if(c1 == 0)
+- return -1;
+- if(c2 == 0)
+- return 1;
+- if(c1 < c2)
+- return -1;
+- if(c1 > c2)
+- return 1;
+- }
+-}
+-#endif /* HAS_STRICMP */
+-
+-static XMLCH* memdup(XMLCH *buf, int len)
+-{
+- XMLCH *d = (XMLCH*)malloc(len*sizeof(XMLCH));
+- if (!ISNULLSTR(d)) memcpy(d, buf, len);
+- return d;
+-}
+-
+-/*===========================================================================
+- FUNCTION
+- DestroyUriTableProc
+- DESC
+- enumeration callback for removing nsScope hashtable keys and data.
+- TODO
+- endPrefixMapping handler must be implemented here...
+-=================================c==========================================*/
+-static int DestroyUriTableProc(char *key, void *data, void *userdata)
+-{
+- char *d = (char*)data;
+- XMLHTable_Remove((LPXMLHTABLE)userdata, key);
+- if (d) free(--d);
+- return 0;
+-}
+-
+-/*===========================================================================
+- FUNCTION
+- prepUri
+- DESC
+- duplicates uri string and sets "declared here" flag
+- PARAMS
+- uri string to duplicate
+- declHere whether this is declared in this element (bool)
+- RETURNS
+- duplicate string, NULL if unsuccessful
+- NOTES
+- uri string's first char contains flag that specifies whether
+- this uri is declared in this element or copied from previous scope.
+- see CopyUriTableProc. Have to be careful with this hack...
+-===========================================================================*/
+-static XMLCH* prepUri(XMLCH *uri, int declHere)
+-{
+- int len = strlen(uri);
+- XMLCH *dup = (XMLCH*)malloc((len + 2) * sizeof(XMLCH));
+- if (ISNULLSTR(dup)) return (XMLCH*)NULL;
+- *(dup) = (char)declHere;
+- memcpy(++dup, uri, len+1);
+- return dup;
+-}
+-
+-/*===========================================================================
+- FUNCTION
+- CopyUriTableProc
+- DESC
+- enumeration callback for copying nsScope hashtable.
+-===========================================================================*/
+-static int CopyUriTableProc(char *key, void *data, void *userdata)
+-{
+- char *dup = prepUri((XMLCH*)data, 0);
+- if (!dup) return 1;
+- if (!(XMLHTable_Insert((LPXMLHTABLE)userdata, key, (void*)dup))) return 1;
+- return 0;
+-}
+-
+-/*===========================================================================
+- FUNCTION
+- XMLNormalizeBuf
+- DESC
+- Normalizes whitespace and line breaks in buffer
+- RETURNS
+- new length of normalized buf
+- NOTES
+- Doesn't trim values nor NUL terminate/truncate buf to new length.
+- This is part of XMLAPI and is exported as helper function
+-===========================================================================*/
+-int XMLAPI XMLNormalizeBuf(XMLCH *buf, int len)
+-{
+- int l, l2, numws;
+- for (l=0; lreader = (LPBUFFEREDISTREAM)
+- malloc(sizeof(BUFFEREDISTREAM)))) return (_pp=NULL);
+- _pp->reader->buf = _pp->reader->ubuf = (XMLCH*)NULL;
+-
+- if (!(_pp->reader->userdata = (LPBISREADERDATA)
+- malloc(sizeof(BISREADERDATA)))) return (_pp=NULL);
+-
+- if (!( _pp->prt = (LPXMLPARSERRUNTIME)
+- malloc(sizeof(XMLPARSERRUNTIME)))) return (_pp=NULL);
+-
+- _pp->XMLFlags = XMLFLAG_NAMESPACES | XMLFLAG_CONVERT_EOL |
+- XMLFLAG_EXTERNAL_GENERAL_ENTITIES;
+-
+- if (!( _pp->prt->atts = XMLVector_Create(&_pp->prt->atts, 16,
+- sizeof(XMLRUNTIMEATT)))) return (_pp=NULL);
+- _pp->prt->atts->capacityIncrement = 16;
+-
+- if (!( _pp->prt->tagstack = XMLVector_Create(&_pp->prt->tagstack, 16,
+- sizeof(XMLRUNTIMETAG)))) return (_pp=NULL);
+- _pp->prt->tagstack->capacityIncrement = 16;
+-
+- if (!( _pp->prt->namedAtts = (LPXMLHTABLE)
+- malloc(sizeof(XMLHTABLE)))) return (_pp=NULL);
+- XMLHTable_Create(_pp->prt->namedAtts, 255);
+- if (!_pp->prt->namedAtts->size) return (_pp=NULL);
+-
+-#ifdef DTD_SUPPORT
+- if (!( _pp->prt->entities = XMLVector_Create(&_pp->prt->entities, 16,
+- sizeof(XMLENTITY)))) return (_pp=NULL);
+- _pp->prt->entities->capacityIncrement = 16;
+-
+- if (!( _pp->prt->entitiesTable = (LPXMLHTABLE)
+- malloc(sizeof(XMLHTABLE)))) return (_pp=NULL);
+- XMLHTable_Create(_pp->prt->entitiesTable, 64);
+- if (!_pp->prt->entitiesTable->size) return (_pp=NULL);
+-#endif
+-
+- if (!XMLStringbuf_Init(&_pp->prt->charsBuf, 256, 0))
+- return (_pp=NULL);
+- return (_pp);
+- #undef _pp
+-}
+-
+-/*===========================================================================
+- FUNCTION
+- XMLParser_Free
+- DESC
+- XML parser free routine
+-===========================================================================*/
+-void XMLAPI XMLParser_Free(LPXMLPARSER parser)
+-{
+- free(PREADERDATA);
+- free(PREADER);
+- XMLVector_Free(RT->atts);
+- XMLVector_Free(RT->tagstack);
+- free(RT->namedAtts->table); /* should be empty by now so
+- we don't need to call XMLHTable_Destroy... */
+- free(RT->namedAtts);
+-#ifdef DTD_SUPPORT
+- XMLVector_Free(RT->entities);
+- free(RT->entitiesTable->table);
+- free(RT->entitiesTable);
+-#endif
+- SAFE_FREESTR(parser->DocumentElement);
+- XMLStringbuf_Free(&RT->charsBuf);
+- free(RT);
+- free(parser);
+-}
+-
+-/*===========================================================================
+- FUNCTION
+- XMLParser_GetNamedItem
+- DESC
+- Looks up an attribute by name
+- PARAMS
+- parser this
+- name name to look for
+- RETURNS
+- attribute or NULL if not found
+- NOTES
+- this should be called only in startElement
+-===========================================================================*/
+-LPXMLRUNTIMEATT XMLAPI XMLParser_GetNamedItem(LPXMLPARSER parser,
+- const XMLCH *name)
+-{
+- int index = (int)XMLHTable_Lookup(RT->namedAtts, (XMLCH*)name);
+- return ((index) ? (LPXMLRUNTIMEATT)XMLVector_Get(RT->atts, index-1) :
+- (LPXMLRUNTIMEATT)NULL);
+-}
+-
+-XMLCH XMLAPI *XMLParser_GetPrefixMapping(LPXMLPARSER parser, const XMLCH *prefix)
+-{
+- return (!parser || !RT->nsScope) ? (XMLCH*)NULL :
+- (XMLCH*)XMLHTable_Lookup(RT->nsScope, (XMLCH*)prefix);
+-}
+-
+-XMLCH XMLAPI *XMLParser_GetSystemID(LPXMLPARSER parser)
+-{
+-#ifdef DTD_SUPPORT
+- return (!parser || !PREADERDATA || !PREADERDATA->curEnt) ?
+- (XMLCH*)NULL : (PREADERDATA->curEnt->systemID);
+-#else
+- return (XMLCH*)NULL;
+-#endif
+-}
+-
+-XMLCH XMLAPI *XMLParser_GetPublicID(LPXMLPARSER parser)
+-{
+-#ifdef DTD_SUPPORT
+- return (!parser || !PREADERDATA || !PREADERDATA->curEnt) ?
+- (XMLCH*)NULL : (PREADERDATA->curEnt->publicID);
+-#else
+- return (XMLCH*)NULL;
+-#endif
+-}
+-
+-int XMLAPI XMLParser_GetCurrentLine(LPXMLPARSER parser)
+-{
+- return ((!parser || !PREADER->bytesavail) ? -1 : PREADERDATA->line+1);
+-}
+-
+-int XMLAPI XMLParser_GetCurrentColumn(LPXMLPARSER parser)
+-{
+- return ((!parser || !PREADER->bytesavail) ? -1 : PREADERDATA->col+1);
+-}
+-
+-/*===========================================================================
+- FUNCTION
+- XMLParser_Parse
+- PARAMS
+- parser this
+- inputSrc input source callback of type LPFNINPUTSRC
+- inputData to be passed to input source callback
+- encoding overrides xml declaration or BOM marker encoding
+- RETURNS
+- 0 failure (parser->ErrorCode was set)
+- 1 success
+-===========================================================================*/
+-int XMLAPI XMLParser_Parse(LPXMLPARSER parser, LPFNINPUTSRC inputSrc,
+- void *inputData, const XMLCH *encoding)
+-{
+- LPXMLRUNTIMETAG pTag;
+- BufferedIStream_Init(PREADER, BIS_DEFAULT_BLOCKSIZE);
+- PREADER->inputsrc = inputSrc;
+- PREADER->inputData = inputData;
+- PREADERDATA->line = PREADERDATA->col = PREADERDATA->noPos = 0;
+- PREADERDATA->ubufsize = PREADERDATA->stackLevel = 0;
+- PREADERDATA->parser = parser;
+- PREADERDATA->curEnt = (LPXMLENTITY)NULL;
+- RT->refReader = PREADER; /* save ref to main reader */
+- RT->nsScope = (LPXMLHTABLE)NULL;
+- RT->doctypeName = (XMLCH*)NULL;
+- SAFE_FREESTR(parser->DocumentElement);
+- if (*parser->ErrorString) *parser->ErrorString = '\0';
+- parser->ErrorCode = parser->ErrorLine = parser->ErrorColumn = 0;
+-
+- if (encoding) {
+- if (!SetEncoding(parser, (XMLCH*)encoding))
+- return (parser->ErrorCode == 0);
+- }
+-
+- if (HANDLER(startDocument)) {
+- if (HANDLER(startDocument)(parser->UserData) == XML_ABORT) {
+- Err(parser, ERR_XMLP_ABORT);
+- return (parser->ErrorCode == 0);
+- }
+- }
+-
+- if (DetectEncoding(parser, 0, Utf8Validator)) ParseInput(parser);
+-
+- while(RT->tagstack->length) {
+- pTag = STACK_PEEK(RT->tagstack);
+- if (!parser->ErrorCode) Err(parser, ERR_XMLP_UNCLOSED_TAG, pTag->qname);
+- XMLStringbuf_Free(&pTag->nameBuf); /* frees localName too */
+- if (pTag->Scope!=NULL) {
+- XMLHTable_Destroy(pTag->Scope, DestroyUriTableProc, 1);
+- free(pTag->Scope);
+- }
+- STACK_REMOVE(RT->tagstack);
+- }
+-
+- if (parser->ErrorCode) {
+- LPXMLRUNTIMEATT pAtt;
+- CLEANUP_ATTS;
+- XMLStringbuf_SetLength(&RT->charsBuf, 0);
+- }
+- else if (!parser->DocumentElement)
+- Err(parser, ERR_XMLP_EXPECTED_TOKEN, "document element");
+- else if (HANDLER(endDocument)) /* fire endDoc if there's no error */
+- HANDLER(endDocument)(parser->UserData);
+-
+-
+-#ifdef DTD_SUPPORT
+- if (RT->entities->length) {
+- LPXMLENTITY e;
+- int i;
+- for (i=0; ientities->length; i++) {
+- e = XMLVector_Get(RT->entities, i);
+- XMLHTable_Remove(RT->entitiesTable, e->name);
+- free(e->name);
+- }
+- _XMLVector_RemoveAll(RT->entities);
+- }
+- if (RT->doctypeName != parser->DocumentElement)
+- SAFE_FREESTR(RT->doctypeName);
+-#endif
+- BufferedIStream_Free(PREADER); /* doesn't free the parser->reader itself,
+- only buffers */
+- return (parser->ErrorCode == 0);
+-}
+-
+-/*===========================================================================
+- FUNCTION
+- ParseInput
+- DESC
+- Main parsing loop
+- PARAMS
+- parser this
+-===========================================================================*/
+-static void ParseInput(LPXMLPARSER parser)
+-{
+- int ret;
+-
+- while (ParseContent(parser))
+- {
+- if (!(ret = PEEKINPUT("![CDATA[", 8))) {
+- if (!ParseCData(parser)) break;
+- }
+- else if (ISFATAL(ret)) break; /* we need these tests 'cos we can't call
+- BufferedIStream_Peek if previous call returns fatal error */
+-
+- else if (!(ret = PEEKINPUT("?", 1))) {
+- if (!(ParsePI(parser, 0))) break;
+- }
+- else if (ISFATAL(ret)) break;
+-
+- else if (!(ret = PEEKINPUT("!--", 3))) {
+- if (!ParseComment(parser, 0)) break;
+- }
+- else if (ISFATAL(ret)) break;
+-
+- else if (!(ret = PEEKINPUT("/", 1))) {
+- if (!ParseEndTag(parser)) break;
+- }
+- else if (ISFATAL(ret)) break;
+-
+- else if (!RT->doctypeName &&
+- (!(ret = PEEKINPUT(TOK_DOCTYPE, 8)))) {
+- if (!ParseDoctypeDecl(parser)) break;
+- }
+- else if (ISFATAL(ret)) break;
+-
+- else {
+- if (!(ret = ParseStartTag(parser))) break;
+- }
+- }
+-}
+-
+-#ifdef DTD_SUPPORT
+-
+-/*===========================================================================
+- FUNCTION
+- ParseDoctypeDecl
+- DESC
+- Parses doctype declaration tag
+- RETURNS
+- 0 failure
+- 1 success
+- NOTES
+- Calls resolveEntityHandler to get inputsrc for parsing external DTD
+- (entity type XML_ENTITY_DOCTYPE). Internal subset is always parsed first.
+-===========================================================================*/
+-static int ParseDoctypeDecl(LPXMLPARSER parser)
+-{
+- int iSubset, l, namelen, prefixlen, endChars;
+- int iPublicID, iSystemID;
+- XMLSTRINGBUF sbuf;
+- XMLENTITY ent;
+- XMLCH c;
+-
+- iSubset = ent.type = 0;
+- iPublicID = iSystemID = -1;
+-
+- if (!ISNULLSTR(parser->DocumentElement))
+- return Err(parser, ERR_XMLP_INVALID_TOKEN, TOK_DOCTYPE);
+-
+- IPOS(8); /* skip !DOCTYPE */
+- if ((l = SkipWS(parser, TOK_GT)) == -1) return 0;
+- if (!l) return ErrP(parser, ERR_XMLP_WS_REQUIRED, 0);
+-
+- endChars = 1;
+- l = ParseNameTok(parser, &namelen, &prefixlen, "[", &endChars);
+- if (l == -1) return 0; /* error is set */
+-
+- if (!(RT->doctypeName = memdup(PREADER->buf+l, namelen+1)))
+- return Err(parser, ERR_XMLP_MEMORY_ALLOC);
+-
+- RT->doctypeName[namelen] = '\0';
+- ent.name = RT->doctypeName;
+- if (!XMLStringbuf_Init(&sbuf, 128, 0))
+- return Err(parser, ERR_XMLP_MEMORY_ALLOC);
+-
+- if (endChars) { /* name was ended by [ (w/o any whitespace - this
+- is legal) */
+- iSubset = 1;
+- }
+- else { /* parse doctype decl: */
+- while (1) {
+- if ((l = SkipWS(parser, TOK_GT)) == -1) goto ExitErr;
+- c = PREADER->buf[PREADER->pos];
+-
+- if (c == '>') {
+- IPOS(1);
+- break;
+- }
+-
+- if (c == '[') {
+- iSubset = 1;
+- if (!ent.type) ent.type = XML_ENTITY_DOCTYPE;
+- IPOS(1); /* skip [ */
+- break;
+- }
+-
+- if (ent.type) goto ExitErr;
+- endChars = 0;
+-
+- if (c == 'P') {
+- if (!Require(parser, "PUBLIC", NULL, &endChars))
+- goto ExitErr;
+- iPublicID = sbuf.len;
+- if (!ParseString(parser, &sbuf, NULL, 1, 0)) goto ExitErr;
+- if ((l = SkipWS(parser, TOK_GT)) == -1) goto ExitErr;
+- if (!l) {
+- ErrP(parser, ERR_XMLP_WS_REQUIRED, 0);
+- goto ExitErr;
+- }
+- sbuf.len++;
+- }
+- else if (c == 'S') {
+- if (!Require(parser, "SYSTEM", NULL, &endChars)) goto ExitErr;
+- }
+- else goto ExitErr;
+-
+- iSystemID = sbuf.len;
+- if (!ParseString(parser, &sbuf, NULL, 1, 0)) goto ExitErr;
+- ent.type = XML_ENTITY_DOCTYPE;
+- } /* while(1) */
+- }
+-
+- ent.publicID = (iPublicID == -1) ? (XMLCH*)NULL : sbuf.str+iPublicID;
+- ent.systemID = (iSystemID == -1) ? (XMLCH*)NULL : sbuf.str+iSystemID;
+-
+- if (HANDLER(startDTD)) {
+- if (HANDLER(startDTD)(parser->UserData, ent.name,
+- ent.publicID, ent.systemID, iSubset) == XML_ABORT)
+- {
+- Err(parser, ERR_XMLP_ABORT);
+- goto ExitErr;
+- }
+- }
+-
+- if (iSubset) {
+- if (!(ParseDTD(parser, 0))) goto ExitErr;
+- }
+-
+- if (ent.systemID) {
+- if (!ResolveExternalDTD(parser, &ent)) goto ExitErr;
+- }
+-
+- if (HANDLER(endDTD)) {
+- if (HANDLER(endDTD)(parser->UserData) == XML_ABORT) {
+- Err(parser, ERR_XMLP_ABORT);
+- goto ExitErr;
+- }
+- }
+-
+- XMLStringbuf_Free(&sbuf);
+- return 1;
+-ExitErr:
+- if (!parser->ErrorCode) Err(parser, ERR_XMLP_INVALID_DECL, "doctype");
+- XMLStringbuf_Free(&sbuf);
+- return 0;
+-}
+-
+-static int ResolveExternalDTD(LPXMLPARSER parser, LPXMLENTITY e)
+-{
+- BUFFEREDISTREAM dtdReader;
+-
+- if (HANDLER(resolveEntity)) {
+- /* Get inputsrc for external DTD: */
+- BISREADERDATA readerdata;
+- XMLCH *dtdEntName = "[dtd]";
+-
+- BufferedIStream_Init(&dtdReader, BIS_DEFAULT_BLOCKSIZE);
+- dtdReader.userdata = &readerdata;
+- readerdata.line = readerdata.col = readerdata.noPos =
+- readerdata.ubufsize = 0;
+- readerdata.curEnt = e;
+- readerdata.parser = parser;
+- e->name = dtdEntName;
+-
+- if (HANDLER(startEntity)) {
+- if (HANDLER(startEntity)(parser->UserData, e) == XML_ABORT) {
+- Err(parser, ERR_XMLP_ABORT);
+- goto ExitErr;
+- }
+- }
+-
+- if (HANDLER(resolveEntity)(parser->UserData, e, &dtdReader) == XML_ABORT) {
+- Err(parser, ERR_XMLP_ABORT);
+- goto ExitErr;
+- }
+-
+- if (dtdReader.inputData) {
+- if (!dtdReader.inputsrc)
+- dtdReader.inputsrc = PREADER->inputsrc;
+- PREADER = &dtdReader;
+- if (DetectEncoding(parser, 1, RT->refReader->encode)) ParseDTD(parser, 1);
+- if (HANDLER(externalEntityParsed)) {
+- if (HANDLER(externalEntityParsed)(parser->UserData, e,
+- &dtdReader) == XML_ABORT)
+- Err(parser, ERR_XMLP_ABORT);
+- }
+- PREADER = RT->refReader;
+- if (parser->ErrorCode) goto ExitErr;
+- }
+- if (HANDLER(endEntity)) {
+- if (HANDLER(endEntity)(parser->UserData, e) == XML_ABORT) {
+- Err(parser, ERR_XMLP_ABORT);
+- goto ExitErr;
+- }
+- }
+- BufferedIStream_Free(&dtdReader);
+- }
+- return 1;
+-ExitErr:
+- BufferedIStream_Free(&dtdReader);
+- return 0;
+-}
+-
+-static int ParseContentDTD(LPXMLPARSER parser, int isExternal)
+-{
+- int chSize, iLT, iLF;
+- int bReport = (!isExternal && HANDLER(default));
+- XMLCH *c;
+- iLT = iLF = 0;
+-
+- while((c = ReadCh(parser, &chSize))) {
+-
+- if (chSize == 1) {
+- if (*c == (XMLCH)0xA) {
+- iLF = PREADER->pos;
+- }
+- else if (*c == '<') {
+- if (iLF) iLT = PREADER->pos - iLF;
+- else if (PREADER->pos > 4096) {
+- iLF = PREADER->pos-1;
+- iLT = 1;
+- }
+- break;
+- }
+- else if (*c == '>')
+- return ErrP(parser, ERR_XMLP_INVALID_TOKEN, 1);
+- else if (*c == ']' && !isExternal) {
+- RequireCh(parser, '>', 1);
+- c = (XMLCH*)NULL;
+- break;
+- }
+- }
+- if (bReport) {
+- if (ISNULLSTR(XMLStringbuf_Append(&RT->charsBuf, c, chSize)))
+- return Err(parser, ERR_XMLP_MEMORY_ALLOC);
+- }
+- }
+-
+- if (parser->ErrorCode) return 0;
+-
+- if (RT->charsBuf.len) {
+- if (HANDLER(default)(parser->UserData, RT->charsBuf.str, RT->charsBuf.len)
+- == XML_ABORT)
+- return Err(parser, ERR_XMLP_ABORT);
+- if (!XMLStringbuf_SetLength(&RT->charsBuf, 0))
+- return Err(parser, ERR_XMLP_MEMORY_ALLOC);
+- }
+-
+- if (iLT) {
+- if (ISFATAL(BufferedIStream_ResetBuf(PREADER, iLF))) return 0;
+- PREADER->pos+=iLT;
+- }
+- return (c != (XMLCH*)NULL);
+- /* NOTE: we can exit returning 0 at any time, RT->charsBuf is emptied
+- in error condition in _Parse. */
+-}
+-
+-static int ParseDTDMiscTag(LPXMLPARSER parser, int isExternal)
+-{
+- int chSize;
+- int bReport = (!isExternal && HANDLER(default));
+- XMLCH *c, quote='\0';
+-
+- if (bReport) {
+- if (ISNULLSTR(XMLStringbuf_AppendCh(&RT->charsBuf, '<')))
+- return Err(parser, ERR_XMLP_MEMORY_ALLOC);
+- }
+-
+- while((c = ReadCh(parser, &chSize))) {
+- if (chSize == 1) {
+- if (ISQUOTE(*c)) {
+- if (!quote) quote = *c;
+- else if (*c == quote) quote = '\0';
+- }
+- else if (!quote && *c == '>') {
+- if (bReport) {
+- if (ISNULLSTR(XMLStringbuf_AppendCh(&RT->charsBuf, '>')))
+- return Err(parser, ERR_XMLP_MEMORY_ALLOC);
+- }
+- break;
+- }
+- }
+- if (bReport) {
+- if (ISNULLSTR(XMLStringbuf_Append(&RT->charsBuf, c, chSize)))
+- return Err(parser, ERR_XMLP_MEMORY_ALLOC);
+- }
+- }
+-
+- if (parser->ErrorCode) return 0;
+-
+- if (RT->charsBuf.len) {
+- if (HANDLER(default)(parser->UserData, RT->charsBuf.str, RT->charsBuf.len)
+- == XML_ABORT)
+- return Err(parser, ERR_XMLP_ABORT);
+-
+- if (!XMLStringbuf_SetLength(&RT->charsBuf, 0))
+- return Err(parser, ERR_XMLP_MEMORY_ALLOC);
+- }
+- if (!c) {
+- if (!parser->ErrorCode)
+- Err(parser, ERR_XMLP_EXPECTED_TOKEN, ">");
+- return 0;
+- }
+- return 1;
+-}
+-
+-/*===========================================================================
+- FUNCTION
+- ParseDTD
+- DESC
+- Main parsing loop for "DTD scanning"
+- RETURNS
+- 0 failure
+- 1 success
+- NOTES
+- Scans only !ENTITY declarations, when parsing internal subset
+- other tags are simply reported by default, comment or piHandler.
+- "Misc tags" that are reported by defaultHandler aren't checked
+- for well-formedness and content data (between tags) is just
+- outputted because it might be legal parameter entity decls etc.
+- TODO
+- Declaration handlers for DTD. A Bloat for simple parsing library?!
+-===========================================================================*/
+-static int ParseDTD(LPXMLPARSER parser, int isExternal)
+-{
+- int ret;
+-
+- while (ParseContentDTD(parser, isExternal))
+- {
+- if (!(ret = PEEKINPUT("?", 1))) {
+- if (!(ParsePI(parser, isExternal))) break;
+- }
+- else if (ISFATAL(ret)) break;
+-
+- else if (!(ret = PEEKINPUT("!--", 3))) {
+- if (!ParseComment(parser, isExternal)) break;
+- }
+- else if (ISFATAL(ret)) break;
+-
+- else if (!(ret = PEEKINPUT("!ENTITY", 7))) {
+- int i = PREADER->pos; /* store position to !ENTITY */
+- if (!ParseEntityDecl(parser)) break;
+- if (!isExternal && HANDLER(default)) {
+- PREADERDATA->noPos = 1;
+- PREADER->pos = i;
+- i = ParseDTDMiscTag(parser, isExternal); /* report !ENTITY */
+- PREADERDATA->noPos = 0;
+- if (!i) break;
+- }
+- }
+- else if (ISFATAL(ret)) break;
+- else {
+- if (!ParseDTDMiscTag(parser, isExternal)) break;
+- }
+- }
+- return (parser->ErrorCode == 0);
+-}
+-
+-static int GetEntityDecl(LPXMLPARSER parser, LPXMLENTITY e, LPXMLSTRINGBUF sbuf)
+-{
+- int l, isParam, iPublicID, iSystemID, iNotation;
+- int namepos, namelen;
+-
+- iPublicID = iSystemID = iNotation = -1;
+- IPOS(7);
+-
+- if ((l = SkipWS(parser, TOK_GT)) == -1) return 0;
+- if (!l) return ErrP(parser, ERR_XMLP_WS_REQUIRED, 0);
+-
+- if (PREADER->buf[PREADER->pos] == '%') {
+- IPOS(1);
+- isParam = 1;
+- if ((l = SkipWS(parser, TOK_GT)) == -1) return 0;
+- if (!l) return ErrP(parser, ERR_XMLP_WS_REQUIRED, 0);
+- }
+- else isParam = 0;
+-
+- l = 0;
+- namepos = ParseNameTok(parser, &namelen, (int*)NULL, (XMLCH*)NULL, &l);
+- if (namepos == -1) return 0; /* error is set */
+-
+- if (!(e->name = XMLStringbuf_Append(sbuf, PREADER->buf+namepos, namelen+1)))
+- return Err(parser, ERR_XMLP_MEMORY_ALLOC);
+- e->name[namelen] = '\0';
+-
+- if ((l = SkipWS(parser, TOK_GT)) == -1) return 0;
+-
+- if (ISQUOTE(PREADER->buf[PREADER->pos])) {
+- e->type = (isParam) ? XML_ENTITY_INT_PARAM : XML_ENTITY_INT_GEN;
+- l = sbuf->len;
+- if (!ParseString(parser, sbuf, NULL, 0, 1)) return 0;
+- if (!RequireCh(parser, '>', 1)) return 0;
+- if (!(e->name = memdup(sbuf->str, sbuf->len+1)))
+- return Err(parser, ERR_XMLP_MEMORY_ALLOC);
+- e->value = e->name+l;
+- e->len = sbuf->len-l;
+- return 1;
+- }
+-
+- l = 0;
+- if (PREADER->buf[PREADER->pos] == 'P') {
+- if (!Require(parser, "PUBLIC", (XMLCH*)NULL, &l)) return 0;
+- iPublicID = sbuf->len;
+- if (!ParseString(parser, sbuf, NULL, 1, 0)) return 0;
+- if ((l = SkipWS(parser, TOK_GT)) == -1) return 0;
+- if (!l) return ErrP(parser, ERR_XMLP_WS_REQUIRED, 0);
+- sbuf->len++;
+- }
+- else if (PREADER->buf[PREADER->pos] == 'S') {
+- if (!Require(parser, "SYSTEM", (XMLCH*)NULL, &l)) return 0;
+- }
+- else return Err(parser, ERR_XMLP_EXPECTED_TOKEN, "PUBLIC or SYSTEM");
+-
+- iSystemID = sbuf->len;
+- if (!ParseString(parser, sbuf, NULL, 1, 0)) return 0;
+-
+- if ((l = SkipWS(parser, TOK_GT)) == -1) return 0;
+-
+- if (PREADER->buf[PREADER->pos] != '>') {
+- e->type = XML_ENTITY_UNPARSED;
+- if (isParam)
+- return Err(parser, ERR_XMLP_EXPECTED_TOKEN, ">");
+-
+- if (!l) return ErrP(parser, ERR_XMLP_WS_REQUIRED, 0);
+- l = 0;
+- if (!Require(parser, "NDATA", (XMLCH*)NULL, &l)) return 0;
+- if ((l = SkipWS(parser, TOK_GT)) == -1) return 0;
+- l = 1;
+- namepos = ParseNameTok(parser, &namelen, (int*)NULL, ">", &l);
+- if (namepos == -1) return 0; /* error is set */
+-
+- iNotation = ++sbuf->len;
+- if (!XMLStringbuf_Append(sbuf, PREADER->buf+namepos, namelen))
+- return Err(parser, ERR_XMLP_MEMORY_ALLOC);
+- if (!XMLStringbuf_ToString(sbuf))
+- return Err(parser, ERR_XMLP_MEMORY_ALLOC);
+-
+- if (!l) {
+- if (!RequireCh(parser, '>', 1)) return 0;
+- }
+- }
+- else {
+- e->type = (isParam) ? XML_ENTITY_EXT_PARAM : XML_ENTITY_EXT_GEN;
+- IPOS(1);
+- }
+-
+- if (!(e->name = memdup(sbuf->str, sbuf->len+1)))
+- return Err(parser, ERR_XMLP_MEMORY_ALLOC);
+-
+- if (iPublicID != -1) e->publicID = e->name + iPublicID;
+- if (iSystemID != -1) e->systemID = e->name + iSystemID;
+- if (iNotation != -1) e->notation = e->name + iNotation;
+-
+- return 1;
+-}
+-
+-static int ParseEntityDecl(LPXMLPARSER parser)
+-{
+- XMLENTITY e;
+-
+- e.type = e.len = e.open = 0;
+- e.name = e.notation = e.publicID = e.systemID = e.value = (XMLCH*)NULL;
+-
+- if (!GetEntityDecl(parser, &e, &RT->charsBuf)) return 0;
+- XMLStringbuf_SetLength(&RT->charsBuf, 0);
+-
+- if (XMLHTable_Lookup(RT->entitiesTable, e.name) ||
+- (!(e.type == XML_ENTITY_INT_GEN || e.type == XML_ENTITY_EXT_GEN))) {
+- if (!ISNULLSTR(e.name)) free(e.name);
+- }
+- else {
+- /* append entity into RT->entities vector and
+- into RT->entitiesTable hashtable: */
+- if (!(XMLVector_Append(RT->entities, &e)))
+- return Err(parser, ERR_XMLP_MEMORY_ALLOC);
+- if (!(XMLHTable_Insert(RT->entitiesTable, e.name,
+- (void*)RT->entities->length)))
+- return Err(parser, ERR_XMLP_MEMORY_ALLOC);
+- }
+- return 1;
+-}
+-
+-/*===========================================================================
+- FUNCTION
+- ParseEntityContent
+- DESC
+- Prepares new reader and parses entity in content
+- PARAMS
+- parser this
+- e entity to be parsed
+- NOTES
+- Every parsed entity needs its own entityReader 'cos calls might be
+- recursive. There must also be tmpReader that saves PREADER and restores it
+- after ParseInput call. These are simply kept in local variable stack.
+-===========================================================================*/
+-static void ParseEntityContent(LPXMLPARSER parser, LPXMLENTITY e)
+-{
+- BUFFEREDISTREAM entityReader; /* these are */
+- BISREADERDATA readerdata; /* kept in local */
+- LPBUFFEREDISTREAM tmpReader = PREADER; /* stack while parsing entity */
+-
+- if (parser->ErrorCode) return;
+-
+- if (HANDLER(startEntity)) {
+- if (HANDLER(startEntity)(parser->UserData, e) == XML_ABORT) {
+- Err(parser, ERR_XMLP_ABORT);
+- return;
+- }
+- }
+-
+- BufferedIStream_Init(&entityReader, BIS_DEFAULT_BLOCKSIZE);
+- readerdata.line = readerdata.col = readerdata.noPos =
+- readerdata.ubufsize = 0;
+- readerdata.curEnt = e; /* for current systemID etc. */
+- readerdata.parser = parser;
+- readerdata.stackLevel = RT->tagstack->length;
+- entityReader.userdata = &readerdata;
+- PREADER = &entityReader;
+- e->open = 1; /* set open flag for recursion tracking */
+-
+- if (e->type == XML_ENTITY_INT_GEN) {
+- /* parse internal general entities from XMLMEMINPUTSRC: */
+- XMLMEMINPUTSRC mementityinput;
+- XML_CHARACTERS_HANDLER savedWShandler = HANDLER(ignorableWhitespace);
+-
+- XMLMEMINPUTSRC_INIT(&mementityinput, e->value, e->len);
+- entityReader.inputData = &mementityinput;
+- entityReader.inputsrc = MemInputsrc;
+- /* savedWShandler is used here to allow whitespace only internal entities
+- like
(CRLF) to be reported as content */
+- HANDLER(ignorableWhitespace) = HANDLER(characters);
+- ParseInput(parser);
+- HANDLER(ignorableWhitespace) = savedWShandler;
+- }
+- else /* if (e->type == XML_ENTITY_EXT_GEN)*/ {
+- /* parse external general entities from user inputsrc: */
+- if (HANDLER(resolveEntity)) {
+- if (HANDLER(resolveEntity)(parser->UserData, e,
+- &entityReader) == XML_ABORT) {
+- Err(parser, ERR_XMLP_ABORT);
+- }
+- else {
+- if (entityReader.inputData) { /* parse it: */
+- /* if inputsrc is NULL, using parser's main inputsrc */
+- if (!entityReader.inputsrc)
+- entityReader.inputsrc = RT->refReader->inputsrc;
+- if (DetectEncoding(parser, 1, RT->refReader->encode))
+- ParseInput(parser);
+- if (HANDLER(externalEntityParsed)) {
+- /* give user chance to do the cleaning up: */
+- if (HANDLER(externalEntityParsed)(parser->UserData, e,
+- &entityReader) == XML_ABORT)
+- Err(parser, ERR_XMLP_ABORT);
+- }
+- }
+- }
+- }
+- }
+-
+- if (!parser->ErrorCode) {
+- if (RT->tagstack->length > PREADERDATA->stackLevel) {
+- LPXMLRUNTIMETAG pTag = STACK_PEEK(RT->tagstack);
+- Err(parser, ERR_XMLP_UNCLOSED_TAG, pTag->qname);
+- }
+- else {
+- if (HANDLER(endEntity)) {
+- if (HANDLER(endEntity)(parser->UserData, e) == XML_ABORT)
+- Err(parser, ERR_XMLP_ABORT);
+- }
+- }
+- }
+-
+- e->open = 0;
+- BufferedIStream_Free(&entityReader);
+- PREADER = tmpReader; /* restore parser's previous reader */
+-}
+-
+-/* inputsrc for ParseEntityContent() internal entities: */
+-static int MemInputsrc(BYTE *buf, int cBytes, int *cBytesActual, void *inputData)
+-{
+- XMLMEMINPUTSRC_HANDLE
+-}
+-
+-/*===========================================================================
+- FUNCTION
+- ParseIntEntityAtt
+- DESC
+- Parses entities in attribute buffer
+- PARAMS
+- parser this
+- e entity to be parsed
+- pAtt attribute for buffer manipulation
+- NOTES
+- Possibly calls itself (thru ParseEntityRef)
+- recursively and appends data to pAtt's valBuf
+-===========================================================================*/
+-static void ParseIntEntityAtt(LPXMLPARSER parser, LPXMLENTITY e,
+- LPXMLRUNTIMEATT pAtt)
+-{
+- int chSize;
+- XMLCH *c;
+- XMLMEMINPUTSRC mementityinput;
+- BUFFEREDISTREAM entityReader;
+- BISREADERDATA readerdata;
+- LPBUFFEREDISTREAM tmpReader;
+-
+- if (parser->ErrorCode) return;
+-
+- if (e->type != XML_ENTITY_INT_GEN) {
+- Err(parser, ERR_XMLP_INVALID_ATT_VALUE, pAtt->qname);
+- return;
+- }
+-
+- e->open = 1; /* set open flag for recursion tracking */
+- XMLMEMINPUTSRC_INIT(&mementityinput, e->value, e->len);
+- BufferedIStream_Init(&entityReader, e->len);
+- entityReader.inputData = &mementityinput;
+- entityReader.inputsrc = MemInputsrc;
+- entityReader.userdata = &readerdata;
+- readerdata.line = readerdata.col = readerdata.noPos =
+- readerdata.ubufsize = 0;
+- readerdata.curEnt = e;
+- readerdata.parser = parser;
+- tmpReader = PREADER;
+- PREADER = &entityReader;
+-
+- while((c = ReadCh(parser, &chSize))) {
+- if (chSize == 1) {
+- if (isspace(*c)) {
+- if (!&pAtt->valBuf.len) continue; /* trim start */
+- if (ISNULLSTR(XMLStringbuf_AppendCh(&pAtt->valBuf, ' '))) {
+- Err(parser, ERR_XMLP_MEMORY_ALLOC);
+- break;
+- }
+- while((c = ReadCh(parser, &chSize))) { /* normalize */
+- if (chSize != 1) break;
+- if (!isspace(*c)) break;
+- }
+- if (!c) break;
+- }
+-
+- if (*c == '&') {
+- if (!(ParseEntityRef(parser, &pAtt->valBuf, pAtt, 2))) break;
+- continue;
+- }
+- else if (*c == '<') {
+- ErrP(parser, ERR_XMLP_INVALID_TOKEN, 1);
+- break;
+- }
+- }
+- if (ISNULLSTR(XMLStringbuf_Append(&pAtt->valBuf, c, chSize))) {
+- Err(parser, ERR_XMLP_MEMORY_ALLOC);
+- break;
+- }
+- }
+- if (!parser->ErrorCode) {
+- if (pAtt->valBuf.len && pAtt->valBuf.str[pAtt->valBuf.len-1] == ' ')
+- pAtt->valBuf.len--; /* trim end */
+- }
+- e->open = 0;
+- BufferedIStream_Free(&entityReader);
+- PREADER = tmpReader;
+-}
+-
+-#endif /* DTD_SUPPORT */
+-
++/*===========================================================================
++ parsifal.c
++ This module contains the main XML parser logic
++ see parsifal.h for copyright info
++===========================================================================*/
++
++#include /* strtoul, malloc etc. */
++#include /* memmove, strdup, strcmp */
++#include /* vsnprintf */
++#include
++#include
++#include "parsifal.h"
++#include "nametab.h"
++#include "xmldef.h"
++#include "isrcmem.h" /* DTD_SUPPORT - defs only */
++
++#ifdef _MSC_VER
++ #ifdef _DEBUG
++ #include
++ #define _CRTDBG_MAP_ALLOC
++ #endif
++#define vsnprintf _vsnprintf
++#endif
++
++static int ParseContent(LPXMLPARSER parser);
++static int ParseComment(LPXMLPARSER parser, int skip);
++static int ParsePI(LPXMLPARSER parser, int skip);
++static int ParseCData(LPXMLPARSER parser);
++static int ParseStartTag(LPXMLPARSER parser);
++static int ParseEndTag(LPXMLPARSER parser);
++static int ParseAttributes(LPXMLPARSER parser, LPXMLRUNTIMETAG pTag, int *isEmpty);
++static int ParseXmlDecl(LPXMLPARSER parser, int skip);
++static int ParseTagNS(LPXMLPARSER parser, LPXMLRUNTIMETAG ptag, int namelen, int pos);
++static int DetectEncoding(LPXMLPARSER parser, int skip, LPFNENCODE defaultEncoding);
++static int SetEncoding(LPXMLPARSER parser, XMLCH *encodingName);
++static void SetReaderFatal(LPXMLPARSER parser, int errval);
++static const XMLCH *GetErrorString(XMLERRCODE code);
++static int Err(LPXMLPARSER parser, XMLERRCODE code, ...);
++static int ErrP(LPXMLPARSER parser, XMLERRCODE code, int posOffset);
++static void ParseInput(LPXMLPARSER parser);
++static int DestroyUriTableProc(char *key, void *data, void *userdata);
++static int CopyUriTableProc(char *key, void *data, void *userdata);
++static XMLCH* prepUri(XMLCH *uri, int declHere);
++static int ParseNameTok(LPXMLPARSER parser, int *len,
++ int *prefixLen, XMLCH *endChars, int *cEndChars);
++static int Require(LPXMLPARSER parser, XMLCH *tok,
++ XMLCH *endChars, int *cEndChars);
++static XMLCH *ParseString(LPXMLPARSER parser, LPXMLSTRINGBUF sbuf,
++ LPXMLRUNTIMEATT pAtt, int Normalize, int entHandling);
++static XMLCH *ReadCh(LPXMLPARSER parser, int *chSize);
++static int SkipWS(LPXMLPARSER parser, XMLCH *expectedErr);
++static int RequireCh(LPXMLPARSER parser, XMLCH ch, int allowWS);
++
++#ifdef DTD_SUPPORT
++static int ParseDoctypeDecl(LPXMLPARSER parser);
++static int ParseDTD(LPXMLPARSER parser, int isExternal);
++static int ParseContentDTD(LPXMLPARSER parser, int isExternal);
++static int ParseDTDMiscTag(LPXMLPARSER parser, int isExternal);
++static void ParseEntityContent(LPXMLPARSER parser, LPXMLENTITY e);
++static void ParseIntEntityAtt(LPXMLPARSER parser, LPXMLENTITY e, LPXMLRUNTIMEATT pAtt);
++static int ParseEntityDecl(LPXMLPARSER parser);
++static int GetEntityDecl(LPXMLPARSER parser, LPXMLENTITY e, LPXMLSTRINGBUF sbuf);
++static int ResolveExternalDTD(LPXMLPARSER parser, LPXMLENTITY e);
++static int MemInputsrc(BYTE *buf, int cBytes, int *cBytesActual, void *inputData);
++#else
++#define ParseDoctypeDecl(parser) (ErrP((parser), ERR_XMLP_INVALID_TOKEN, 1))
++#endif
++
++/* util routines not necessarily specific to xml parsing: */
++#ifndef HAS_STRICMP
++static int stricmp(const char *s1, const char *s2);
++#endif
++static XMLCH* memdup(XMLCH *buf, int len);
++
++extern int Latin1ToUtf8(LPBUFFEREDISTREAM reader, BYTE *bufp, int *cBytes);
++extern int Utf8Validator(LPBUFFEREDISTREAM reader, BYTE *bufp, int *cBytes);
++
++static const STDENTITIES stdEntities[6] = {
++ {"gt", '>', 2},
++ {"lt", '<', 2},
++ {"amp", '&', 3},
++ {"apos", '\'', 4},
++ {"quot", '\"', 4},
++ {NULL, 0x0, 0x0}
++};
++
++static XMLCH EmptyStr[1] = {'\0'};
++static XMLCH *uriXMLNS = "http://www.w3.org/2000/xmlns/";
++static XMLCH *uriXML = "http://www.w3.org/XML/1998/namespace";
++
++#define ISFATAL(ret) (((ret) < -2) ? (SetReaderFatal(((LPXMLPARSER)parser), (ret)), 1) : 0)
++#define ISXMLPREFIX(s) ((*(s) == 'x' && s[1] == 'm' && s[2] == 'l'))
++#define ISXMLNSPREFIX(s) ((ISXMLPREFIX((s)) && s[3] == 'n' && s[4] == 's'))
++#define ISQUOTE(c) ((c)=='\"' || (c)=='\'')
++
++#define DPOS(bytes) \
++ PREADER->pos-=(bytes); \
++ if (!PREADERDATA->noPos) PREADERDATA->col-=(bytes);
++#define IPOS(bytes) \
++ PREADER->pos+=(bytes); \
++ if (!PREADERDATA->noPos) PREADERDATA->col+=(bytes);
++
++/* some shortcuts: */
++#define RT parser->prt
++#define PREADER ((LPBUFFEREDISTREAM)parser->reader)
++#define PREADERDATA ((LPBISREADERDATA)PREADER->userdata)
++#define HANDLER(n) parser->n##Handler
++#define PEEKINPUT(str,len) BufferedIStream_Peek(PREADER,(str),(len),0)
++
++/* remove attributes from vector and
++ free memory associated with them: */
++#define CLEANUP_ATTS \
++if (RT->atts->length) \
++{ \
++ int i; \
++ for (i=0; iatts->length; i++) { \
++ pAtt = XMLVector_Get(RT->atts, i); \
++ /* namedAtts data is allocated by atts vector, not Hashtable */ \
++ /* so we're removing only htable key, this is */ \
++ /* faster than calling XMLHTable_Destroy: */ \
++ XMLHTable_Remove(RT->namedAtts, pAtt->qname); \
++ if (!pAtt->nameBuf.useStatic) XMLStringbuf_Free(&pAtt->nameBuf); \
++ if (!pAtt->valBuf.useStatic) XMLStringbuf_Free(&pAtt->valBuf); \
++ /* uris will be freed by HashTable */ \
++ } \
++ _XMLVector_RemoveAll(RT->atts); \
++}
++
++/* INIT_NSSCOPE is used in ParseAttributes.
++ initializes new scope for pTag->Scope, copies namespaces from pTag->prevScope
++ and sets RT->nsScope. After this we can refer to current namespace with
++ RT->nsScope. pTag->Scope is only preserved to indicate that later this scope
++ must be freed (at EndElement stage) */
++#define INIT_NSSCOPE \
++if (!pTag->Scope) { \
++ if (!( pTag->Scope = (LPXMLHTABLE) malloc(sizeof(XMLHTABLE)))) \
++ return Err(parser, ERR_XMLP_MEMORY_ALLOC); \
++ XMLHTable_Create(pTag->Scope, 64); \
++ if (!pTag->Scope->size) \
++ return Err(parser, ERR_XMLP_MEMORY_ALLOC); \
++ if (pTag->prevScope != NULL) { \
++ pTag->prevScope->userdata = pTag->Scope; \
++ if ((XMLHTable_Enumerate(pTag->prevScope, CopyUriTableProc))) \
++ return Err(parser, ERR_XMLP_MEMORY_ALLOC); \
++ } \
++ RT->nsScope = pTag->Scope; \
++}
++
++static const XMLCH *GetErrorString(XMLERRCODE code)
++{
++ static const XMLCH *ParserErrMsg[] = {
++ 0,
++ "Out of memory",
++ "Fatal error (code: %d)",
++ "Invalid token",
++ "Invalid name",
++ "End tag '%s' was not expected here",
++ "Reference to undefined entity '%s'",
++ "Whitespace not allowed here",
++ "Whitespace required",
++ "Tag '%s' was not closed",
++ "Expected '%s', found '%s'",
++ "Expected '%s'",
++ "Only one top level element is allowed",
++ "Invalid at the top level of the document",
++ "Undefined namespace prefix '%s'",
++ "Duplicate attribute '%s'",
++ "Encoding error",
++ "Unsupported encoding '%s'",
++ "Invalid %s declaration",
++ "Invalid value for attribute '%s'",
++ "Parsing aborted",
++ "Illegal character #x%04X",
++ "Recursive reference in entity '%s'",
++ };
++ return (ParserErrMsg[code]);
++}
++
++/*===========================================================================
++ FUNCTION
++ Err
++ PARAMS
++ parser this
++ code error code
++ ... va_list for error string
++ RETURNS
++ 0
++ NOTES
++ Sets ErrorLine, ErrorString etc. only if errorHandler is specified.
++===========================================================================*/
++static int Err(LPXMLPARSER parser, XMLERRCODE code, ...)
++{
++ parser->ErrorCode = code;
++ if (HANDLER(error)) {
++ va_list aptr;
++ va_start(aptr, code);
++
++ if (vsnprintf((char*)parser->ErrorString, 128, GetErrorString(code), aptr) == -1)
++ parser->ErrorString[127] = '\0';
++ va_end(aptr);
++
++ parser->ErrorColumn = XMLParser_GetCurrentColumn(parser);
++ parser->ErrorLine = XMLParser_GetCurrentLine(parser);
++ HANDLER(error)(parser);
++ }
++ return 0;
++}
++
++/*===========================================================================
++ FUNCTION
++ ErrP
++ PARAMS
++ parser this
++ code error code
++ posOffset bytes to go back in the PREADER->buf (usually token/chSize)
++ NOTES
++ PREADERDATA->col can go below 0 when WS_NOT_ALLOWED and position
++ contains LF/CR, we cannot go to previous line cos PREADERDATA->col
++ for prev line isn't known.
++===========================================================================*/
++static int ErrP(LPXMLPARSER parser, XMLERRCODE code, int posOffset)
++{
++ DPOS(posOffset);
++ if(PREADERDATA->col < 0) PREADERDATA->col = 0;
++ return Err(parser, code);
++}
++
++/*===========================================================================
++ FUNCTION
++ SetReaderFatal
++ DESC
++ for ISFATAL macro
++===========================================================================*/
++static void SetReaderFatal(LPXMLPARSER parser, int code)
++{
++ switch(code)
++ {
++ case BIS_ERR_MEMALLOC:
++ Err(parser, ERR_XMLP_MEMORY_ALLOC);
++ break;
++ case BIS_ERR_ENCODING:
++ Err(parser, ERR_XMLP_ENCODING);
++ break;
++ case BIS_ERR_USER:
++ /* must switch here when there's more possible
++ errors than ERR_XMLP_ILLEGAL_CHAR */
++ Err(parser, ERR_XMLP_ILLEGAL_CHAR, parser->ErrorCode);
++ break;
++ default:
++ Err(parser, ERR_XMLP_READER_FATAL, code);
++ }
++}
++
++/*===========================================================================
++ FUNCTION
++ ParseCharRef
++ DESC
++ Parses character reference
++ PARAMS
++ parser this
++ ref out buffer for char ref (max 4 bytes UTF-8 char)
++ RETURNS
++ Success: 1
++ Failure: 0 (Error is set)
++===========================================================================*/
++static int ParseCharRef(LPXMLPARSER parser, XMLCH *ref)
++{
++ int chSize, base, n, i = 0;
++ unsigned int code = 0;
++ XMLCH *c;
++
++ if (!(c = ReadCh(parser, &chSize))) goto ExitErr;
++
++ if (*c == 'x')
++ base = 16;
++ else {
++ DPOS(chSize);
++ base = 10;
++ }
++
++ while ((c = ReadCh(parser, &chSize))) {
++ if (chSize != 1) goto ExitErr;
++
++ if (*c == ';') {
++ if (!i) goto ExitErr;
++ break;
++ }
++ else if((*c >= '0' && *c <= '9') ||
++ (base == 16 && ((*c >= 'A' && *c <= 'F') ||
++ (*c >= 'a' && *c <= 'f'))))
++ i++;
++ else goto ExitErr;
++ }
++
++ if (!c) return Err(parser, ERR_XMLP_EXPECTED_TOKEN, ";");
++ c = PREADER->buf+PREADER->pos-(i + 1);
++
++ while(i--) {
++ n = *c++;
++ if(n >= '0' && n <= '9')
++ code = code * base + (n - '0');
++ else if(n >= 'A' && n <= 'F')
++ code = code * base + 10 + (n - 'A');
++ else
++ code = code * base + 10 + (n - 'a');
++ }
++
++ if (code < 0x80) { /* < UTF_BYTE1 max */
++ if (ISILLBYTE(code))
++ return Err(parser, ERR_XMLP_ILLEGAL_CHAR, code);
++ ref[0] = (char)code;
++ return 1;
++ }
++ else if (code < 0x800) { /* < UTF_BYTE2 max */
++ if (ISILL2BYTE(code))
++ return Err(parser, ERR_XMLP_ILLEGAL_CHAR, code);
++ ref[0] = ((code >> 6) | UTF8_2BYTES);
++ ref[1] = ((code & 0x3f) | 0x80);
++ return 2;
++ }
++ else if (code < 0x10000) { /* < UTF_BYTE3 max */
++ ref[0] = ((code >> 12) | UTF8_3BYTES);
++ ref[1] = (((code >> 6) & 0x3f) | 0x80);
++ ref[2] = ((code & 0x3f) | 0x80);
++ return 3;
++ }
++ else if (code < 0x110000) { /* < UTF_BYTE4 max */
++ ref[0] = ((code >> 18) | UTF8_4BYTES);
++ ref[1] = (((code >> 12) & 0x3f) | 0x80);
++ ref[2] = (((code >> 6) & 0x3f) | 0x80);
++ ref[3] = ((code & 0x3f) | 0x80);
++ return 4;
++ }
++
++ return Err(parser, ERR_XMLP_ILLEGAL_CHAR, code);
++ExitErr:
++if (!parser->ErrorCode)
++ ErrP(parser, ERR_XMLP_INVALID_TOKEN, (chSize) ? chSize : 1);
++return 0;
++}
++
++/*===========================================================================
++ FUNCTION
++ ParseEntityRef
++ DESC
++ Parses and expands entity references
++ PARAMS
++ parser this
++ sbuf output string buffer
++ pAtt indicates that current context is attribute value buffer
++ Context 1: expand only char refs
++ RETURNS
++ Success: 1
++ Failure: 0 (Error is set)
++===========================================================================*/
++static int ParseEntityRef(LPXMLPARSER parser, LPXMLSTRINGBUF sbuf,
++ LPXMLRUNTIMEATT pAtt, int Context)
++{
++ int chSize, namepos, i;
++ XMLCH *c;
++
++ if (!(c = ReadCh(parser, &chSize))) {
++ if (!parser->ErrorCode)
++ ErrP(parser, ERR_XMLP_INVALID_TOKEN, 1);
++ return 0;
++ }
++
++ if (*c == '#') {
++ XMLCH ref[4];
++ namepos = PREADER->pos-2;
++ if (!(i = ParseCharRef(parser, ref))) return 0;
++ if (Context == 1 && i == 1 &&
++ (ref[0] == (XMLCH)0xA || ref[0] == (XMLCH)0xD)) {
++ /* expanding values in internal !ENTITY decl must preserve LF and CR
++ note that
can be something like
*/
++ if (ISNULLSTR(XMLStringbuf_Append(sbuf, PREADER->buf+namepos,
++ PREADER->pos-namepos)))
++ return Err(parser, ERR_XMLP_MEMORY_ALLOC);
++ }
++ else if (ISNULLSTR(XMLStringbuf_Append(sbuf, ref, i)))
++ return Err(parser, ERR_XMLP_MEMORY_ALLOC);
++ }
++ else {
++ int namelen, endChars=1;
++ DPOS(chSize);
++ namepos = ParseNameTok(parser, &namelen, (int*)NULL, ";", &endChars);
++ if (namepos == -1) return 0;
++ if (!endChars)
++ return ErrP(parser, ERR_XMLP_WS_NOT_ALLOWED, 1);
++
++ if (Context == 1) {
++ if (ISNULLSTR(XMLStringbuf_Append(sbuf, PREADER->buf+(namepos-1), namelen+2)))
++ return Err(parser, ERR_XMLP_MEMORY_ALLOC);
++ return 1;
++ }
++
++ /* we can use the actual buffer since name cannot end to CR or LF or
++ to char that is significant to position functions */
++ c = BUFTOSTR(PREADER->buf, namepos, namelen+namepos);
++
++ if (namelen < 5) { /* some short circuiting */
++ /* expand predefined entities: */
++ const STDENTITIES *e = stdEntities;
++ for (; (*e).szEntity; e++) {
++ if (namelen == (*e).len && !memcmp(c, (*e).szEntity, namelen)) {
++ if (ISNULLSTR(XMLStringbuf_AppendCh(sbuf, (*e).chExpanded)))
++ return Err(parser, ERR_XMLP_MEMORY_ALLOC);
++ return 1;
++ }
++ }
++ }
++#ifdef DTD_SUPPORT
++ if (_XMLParser_GetFlag(parser, XMLFLAG_PRESERVE_GENERAL_ENTITIES)) {
++#endif
++ c = PREADER->buf+(namepos-1);
++ c[namelen+1] = ';';
++ if (ISNULLSTR(XMLStringbuf_Append(sbuf, c, namelen+2)))
++ return Err(parser, ERR_XMLP_MEMORY_ALLOC);
++ return 1;
++#ifdef DTD_SUPPORT
++ }
++ else if ((i = (int)XMLHTable_Lookup(RT->entitiesTable, c))) {
++
++ LPXMLENTITY e = XMLVector_Get(RT->entities, i-1);
++
++ if (e->open)
++ return Err(parser, ERR_XMLP_RECURSIVE_ENTITY_REF, c);
++
++ if (pAtt)
++ ParseIntEntityAtt(parser, e, pAtt);
++ else {
++ if (sbuf->len) {
++ if (HANDLER(characters)) {
++ if (HANDLER(characters)(parser->UserData, sbuf->str, sbuf->len)
++ == XML_ABORT) return Err(parser, ERR_XMLP_ABORT);
++ }
++ if (!XMLStringbuf_SetLength(sbuf, 0))
++ return Err(parser, ERR_XMLP_MEMORY_ALLOC);
++ }
++ if (e->type == XML_ENTITY_EXT_GEN &&
++ (!_XMLParser_GetFlag(parser, XMLFLAG_EXTERNAL_GENERAL_ENTITIES))) {
++ if (HANDLER(skippedEntity)) { /* report skippedEntity: */
++ if (HANDLER(skippedEntity)(parser->UserData, c)==XML_ABORT)
++ return Err(parser, ERR_XMLP_ABORT);
++ }
++ }
++ else {
++ ParseEntityContent(parser, e);
++ }
++ }
++ }
++ else { /* XMLHTable_Lookup didn't find entity: */
++ if (_XMLParser_GetFlag(parser, XMLFLAG_UNDEF_GENERAL_ENTITIES))
++ return Err(parser, ERR_XMLP_UNDEF_ENTITY, c);
++
++ if (!pAtt) {
++ if (sbuf->len) {
++ if (HANDLER(characters)) {
++ if (HANDLER(characters)(parser->UserData, sbuf->str, sbuf->len)
++ == XML_ABORT) return Err(parser, ERR_XMLP_ABORT);
++ }
++ if (!XMLStringbuf_SetLength(sbuf, 0))
++ return Err(parser, ERR_XMLP_MEMORY_ALLOC);
++ }
++ if (HANDLER(skippedEntity)) { /* report skippedEntity: */
++ if (HANDLER(skippedEntity)(parser->UserData, c)==XML_ABORT)
++ return Err(parser, ERR_XMLP_ABORT);
++ }
++ }
++ }
++#endif /* DTD_SUPPORT */
++ }
++ return (parser->ErrorCode == 0);
++}
++
++/*===========================================================================
++ FUNCTION
++ ParseContent
++ DESC
++ Parses reader buffer "outside tags"
++ RETURNS
++ 0 failure
++ 1 success
++ NOTES
++ iLT is used as index of < char in PREADER->buf
++ iLF is used as index of last 0xA char in PREADER->buf
++ these are used as offsets in BufferedIStream_ResetBuf call.
++===========================================================================*/
++static int ParseContent(LPXMLPARSER parser)
++{
++ int chSize, iLT, iLF, isWS=1;
++ XMLCH *c;
++ iLT = iLF = 0;
++
++ while((c = ReadCh(parser, &chSize))) {
++
++ if (chSize == 1) {
++ if (*c == (XMLCH)0xA) {
++ iLF = PREADER->pos;
++ }
++ else {
++ if (*c == '<') {
++ if (iLF) iLT = PREADER->pos - iLF;
++ else if (PREADER->pos > 4096) {
++ iLF = PREADER->pos-1;
++ iLT = 1;
++ }
++ break;
++ }
++
++ if (isWS && !isspace(*c)) {
++ if (!RT->tagstack->length)
++ return ErrP(parser, ERR_XMLP_INVALID_AT_TOP, 1);
++ isWS = 0;
++ }
++
++ if (*c == '&') {
++ if (!ParseEntityRef(parser, &RT->charsBuf,
++ (LPXMLRUNTIMEATT)NULL, 2)) return 0;
++ continue;
++ }
++ else if (*c == '>' && RT->charsBuf.len > 1) {
++ if (*(c-2) == ']' && *(c-1) == ']')
++ return ErrP(parser, ERR_XMLP_INVALID_TOKEN, 3);
++ }
++ }
++ }
++ else if (isWS) {
++ if (!RT->tagstack->length)
++ return ErrP(parser, ERR_XMLP_INVALID_AT_TOP, chSize);
++ isWS = 0;
++ }
++ if (ISNULLSTR(XMLStringbuf_Append(&RT->charsBuf, c, chSize)))
++ return Err(parser, ERR_XMLP_MEMORY_ALLOC);
++ }
++
++ if (parser->ErrorCode) return 0;
++
++ if (RT->charsBuf.len) {
++ if (isWS) {
++ if (HANDLER(ignorableWhitespace) && RT->tagstack->length) {
++ if (HANDLER(ignorableWhitespace)(parser->UserData, RT->charsBuf.str,
++ RT->charsBuf.len) == XML_ABORT)
++ return Err(parser, ERR_XMLP_ABORT);
++ }
++ }
++ else {
++ if (HANDLER(characters)) {
++ if (HANDLER(characters)(parser->UserData, RT->charsBuf.str, RT->charsBuf.len)
++ == XML_ABORT)
++ return Err(parser, ERR_XMLP_ABORT);
++ }
++ }
++ if (!XMLStringbuf_SetLength(&RT->charsBuf, 0))
++ return Err(parser, ERR_XMLP_MEMORY_ALLOC);
++ }
++
++ if (iLT) {
++ if (ISFATAL(BufferedIStream_ResetBuf(PREADER, iLF))) return 0;
++ PREADER->pos+=iLT;
++ }
++ return (c != (XMLCH*)NULL);
++ /* NOTE: we can exit returning 0 at any time, RT->charsBuf is emptied
++ in error condition in _Parse. */
++}
++
++/*===========================================================================
++ FUNCTION
++ ParseEndTag
++ DESC
++ Parses end tag and compares it to tag at the top of tagstack.
++ RETURNS
++ 0 failure
++ 1 success
++===========================================================================*/
++static int ParseEndTag(LPXMLPARSER parser)
++{
++ int namepos, namelen, endChars = 1;
++ LPXMLRUNTIMETAG pTag;
++ XMLCH *s;
++
++ IPOS(1); /* skip / */
++
++ namepos = ParseNameTok(parser, &namelen, (int*)NULL, ">", &endChars);
++ if (namepos == -1) return 0;
++
++ if (!endChars) {
++ if (!namelen)
++ return ErrP(parser, ERR_XMLP_WS_NOT_ALLOWED, 1);
++ if (!(RequireCh(parser, '>', 1))) return 0;
++ }
++
++ /* we get significant performance boost using BUFTOSTR instead of
++ _ToString (no mallocs or frees) but have to be careful with these:
++ 1) no bounds checking
++ 2) buffer must have room for \0
++ 3) no _Read operations when using BUFTOSTR buffer */
++
++ s = BUFTOSTR(PREADER->buf, namepos, namelen+namepos);
++
++ if ((RT->tagstack->length-1) < PREADERDATA->stackLevel)
++ return Err(parser, ERR_XMLP_INVALID_END_TAG, s);
++
++ if ((pTag = STACK_PEEK(RT->tagstack)))
++ {
++ if (!strcmp(pTag->qname, s)) {
++ if (HANDLER(endElement)) {
++ if (HANDLER(endElement)(parser->UserData, pTag->uri,
++ pTag->localName, pTag->qname) == XML_ABORT) {
++ Err(parser, ERR_XMLP_ABORT);
++ }
++ }
++ }
++ else {
++ Err(parser, ERR_XMLP_EXPECTED_FOUND, pTag->qname, s);
++ }
++
++ XMLStringbuf_Free(&pTag->nameBuf); /* frees localName too */
++ if (pTag->Scope!=NULL) {
++ XMLHTable_Destroy(pTag->Scope, DestroyUriTableProc, 1);
++ free(pTag->Scope);
++ }
++ RT->nsScope = pTag->prevScope;
++ STACK_REMOVE(RT->tagstack);
++ }
++ else {
++ return Err(parser, ERR_XMLP_EXPECTED_TOKEN, s);
++ }
++
++ return (parser->ErrorCode == 0);
++}
++
++/*===========================================================================
++ FUNCTION
++ ParseString
++ DESC
++ Parses string literal
++ PARAMS
++ parser this
++ sbuf output string buffer
++ pAtt indicates that current context is attribute value buffer
++ Normalize whether to perform normalization
++ entHandling 0: expand none, 1: expand char refs 2: expand all
++ RETURNS
++ Success: String
++ Failure: NULL string (Error is set)
++===========================================================================*/
++static XMLCH *ParseString(LPXMLPARSER parser, LPXMLSTRINGBUF sbuf,
++ LPXMLRUNTIMEATT pAtt, int Normalize, int entHandling)
++{
++ int chSize;
++ int startPos = sbuf->len;
++ XMLCH *c, quote;
++
++ if (SkipWS(parser, "String") == -1)
++ return (XMLCH*)NULL;
++
++ quote = PREADER->buf[PREADER->pos];
++
++ if (ISQUOTE(quote)) {
++ IPOS(1);
++
++ while((c = ReadCh(parser, &chSize))) {
++ if (chSize == 1) {
++ if (Normalize && isspace(*c)) {
++ if (sbuf->len == startPos) continue; /* trim start */
++ if (ISNULLSTR(XMLStringbuf_AppendCh(sbuf, ' '))) {
++ Err(parser, ERR_XMLP_MEMORY_ALLOC);
++ return (XMLCH*)NULL;
++ }
++ while((c = ReadCh(parser, &chSize))) { /* normalize */
++ if (chSize != 1) break;
++ if (!isspace(*c)) break;
++ }
++ if (!c) break;
++ if (chSize != 1) {
++ if (ISNULLSTR(XMLStringbuf_Append(sbuf, c, chSize))) {
++ Err(parser, ERR_XMLP_MEMORY_ALLOC);
++ return (XMLCH*)NULL;
++ }
++ continue;
++ }
++ }
++
++ if (*c == quote) {
++ if (Normalize && sbuf->len && sbuf->str[sbuf->len-1] == ' ')
++ sbuf->len--; /* trim end */
++ if (ISNULLSTR(XMLStringbuf_ToString(sbuf))) {
++ Err(parser, ERR_XMLP_MEMORY_ALLOC);
++ return (XMLCH*)NULL;
++ }
++ return sbuf->str;
++ }
++ else if (entHandling && *c == '&') {
++ if (!ParseEntityRef(parser, sbuf, pAtt, entHandling))
++ return (XMLCH*)NULL;
++ continue;
++ }
++ else if (*c == '<' && pAtt) {
++ ErrP(parser, ERR_XMLP_INVALID_TOKEN, 1);
++ return (XMLCH*)NULL;
++ }
++ }
++ if (ISNULLSTR(XMLStringbuf_Append(sbuf, c, chSize))) {
++ Err(parser, ERR_XMLP_MEMORY_ALLOC);
++ return (XMLCH*)NULL;
++ }
++ }
++ }
++ if (!parser->ErrorCode)
++ Err(parser, ERR_XMLP_EXPECTED_TOKEN, "String");
++ return (XMLCH*)NULL;
++}
++
++/*===========================================================================
++ FUNCTION
++ ReadCh
++ DESC
++ returns UTF-8 char from input
++ PARAMS
++ parser this
++ chSize out: length of char
++ RETURNS
++ Success: XMLCH* to character
++ Failure: NULL string (NOTE: Error might be set but not necessarily)
++ NOTES
++ ReadCh handles Carriage Return normalization +
++ line and col stuff
++===========================================================================*/
++static XMLCH *ReadCh(LPXMLPARSER parser, int *chSize)
++{
++ XMLCH *c;
++ int ret;
++
++ if (!PREADER->buf || PREADER->pos >= PREADER->bytesavail) {
++ ret = PEEKINPUT((const BYTE*)NULL, 1);
++ if (ISFATAL(ret) || ret) {
++ *chSize = 0;
++ return (XMLCH*)NULL;
++ }
++ }
++ c = PREADER->buf+PREADER->pos;
++ UTF8LEN(c,*chSize);
++
++ if (*chSize == 1) {
++ PREADER->pos++;
++ if (*c == 0xD) {
++ if (!PREADERDATA->noPos) {
++ PREADERDATA->line++;
++ PREADERDATA->col=0;
++ }
++ PREADER->buf[PREADER->pos-1] = 0xA;
++ if (PREADER->pos >= PREADER->bytesavail) {
++ ret = PEEKINPUT((const BYTE*)NULL, 1);
++ if (ISFATAL(ret)) {
++ *chSize = 0;
++ return (XMLCH*)NULL;
++ }
++ c = PREADER->buf+(PREADER->pos-1);
++ if (ret) return(c);
++ }
++ if (PREADER->buf[PREADER->pos] == 0xA) PREADER->pos++;
++ }
++ else if (*c == 0xA && !PREADERDATA->noPos) {
++ PREADERDATA->line++;
++ PREADERDATA->col=0;
++ }
++ else if (!PREADERDATA->noPos) PREADERDATA->col++;
++ }
++ else {
++ PREADER->pos += *chSize;
++ if (!PREADERDATA->noPos) PREADERDATA->col += *chSize;
++ }
++ return(c);
++}
++
++/*===========================================================================
++ FUNCTION
++ SkipWS
++ DESC
++ skips whitespace and is used to determine whitespace too
++ PARAMS
++ parser this
++ expectedErr if end of input is encoutered this error is triggered
++ RETURNS
++ Success: number of whitespace bytes
++ Failure: -1 (error is set)
++===========================================================================*/
++static int SkipWS(LPXMLPARSER parser, XMLCH *expectedErr)
++{
++ int l=0, chSize;
++ XMLCH *c;
++ while((c = ReadCh(parser, &chSize))) {
++ if (chSize != 1 || !isspace(*c)) {
++ DPOS(chSize); /* ACHTUNG! */
++ return l;
++ }
++ l++;
++ }
++ if (!parser->ErrorCode && expectedErr)
++ Err(parser, ERR_XMLP_EXPECTED_TOKEN, expectedErr);
++ return -1;
++}
++
++/*===========================================================================
++ FUNCTION
++ RequireCh
++ DESC
++ requires char in the input
++ PARAMS
++ parser this
++ ch character that's required
++ allowWS whether to allow whitespace to appear before char is found
++ RETURNS
++ Success: 1
++ Failure: 0 (error is set)
++===========================================================================*/
++static int RequireCh(LPXMLPARSER parser, XMLCH ch, int allowWS)
++{
++ XMLCH *c;
++ int chSize;
++
++ while((c = ReadCh(parser, &chSize))) {
++ if (chSize == 1) {
++ if (*c == ch) return 1;
++ else if (isspace(*c)) {
++ if (!allowWS)
++ return ErrP(parser, ERR_XMLP_WS_NOT_ALLOWED, 1);
++ continue;
++ }
++ }
++ break;
++ }
++ if (!parser->ErrorCode) {/* ReadCh might set parser err */
++ XMLCH tok[2];
++ tok[0] = ch;
++ tok[1] = '\0';
++ if (chSize) DPOS(chSize);
++ Err(parser, ERR_XMLP_EXPECTED_TOKEN, tok);
++ }
++ return 0;
++}
++
++/*===========================================================================
++ FUNCTION
++ ParseNameTok
++ DESC
++ Parses name token
++ PARAMS
++ parser this
++ len out pointer - length of name
++ prefixLen out pointer - length of prefix. Can be NULL pointer when
++ prefix isn't needed
++ endChars chars that are legal to end name scanning (besides space chars)
++ cEndChars in/out pointer - in: count of endChars
++ out: position of endChar found or 0 if whitespace
++ was found instead
++ RETURNS
++ Success: start position of name in reader buffer
++ Failure: -1 (Error is set)
++ NOTES
++ len might be 0 if skipWS isn't called before ParseNameTok call.
++===========================================================================*/
++static int ParseNameTok(LPXMLPARSER parser, int *len,
++ int *prefixLen, XMLCH *endChars, int *cEndChars)
++{
++ int chSize, spos = PREADER->pos;
++ int prefix = (prefixLen) ? 0 : -1;
++ XMLCH *c;
++ *len = 0;
++
++ while ((c = ReadCh(parser, &chSize))) {
++ if (!*len || (prefix == *len)) {
++ if (chSize == 1) {
++ if (!ISMAPCH(nameStartAscii, *c)) break;
++ }
++ else if (chSize == 2) { // 2-byte sequence
++ if (!utf8_isNmstrt2(c)) break;
++ }
++ else if (chSize == 3) { // 3-byte sequence
++ if (!utf8_isNmstrt3(c)) break;
++ }
++ else break;
++ }
++ else {
++ if (chSize == 1) {
++ if (!ISMAPCH(nameAscii, *c)) break;
++ if (!prefix && *c == ':') prefix = *len+1;
++ }
++ else if (chSize == 2) { // 2-byte sequence
++ if (!utf8_isName2(c)) break;
++ }
++ else if (chSize == 3) { // 3-byte sequence
++ if (!utf8_isName3(c)) break;
++ }
++ /* else if ((*c & 0xf8) == 0xf0) { // 4-byte sequence */
++ else break;
++ }
++ (*len)+=chSize;
++ }
++
++ if (!c) {
++ if (!parser->ErrorCode) {
++ XMLCH t[5] = "Name";
++ if (*cEndChars && *len) {
++ t[0] = endChars[(*cEndChars)-1];
++ t[1] = '\0';
++ }
++ Err(parser, ERR_XMLP_EXPECTED_TOKEN, t);
++ }
++ return -1;
++ }
++
++ while (*cEndChars) {
++ if (*c == endChars[--(*cEndChars)]) {
++ (*cEndChars)++;
++ if (!*len) {
++ Err(parser, ERR_XMLP_EXPECTED_TOKEN, "Name");
++ return -1;
++ }
++ break;
++ }
++ }
++
++ if (!*cEndChars) {
++ if (!isspace(*c)) {
++ ErrP(parser, ERR_XMLP_INVALID_NAME, chSize);
++ return -1;
++ }
++ }
++ if (prefixLen) *prefixLen = (prefix>0) ? prefix-1 : 0;
++ return spos;
++}
++
++/*===========================================================================
++ FUNCTION
++ Require
++ DESC
++ Requires token in the input
++ PARAMS
++ parser this
++ tok token that is required
++ endChars see ParseNameTok
++ cEndChars see ParseNametok
++ RETURNS
++ Success: 1
++ Failure: 0 (Error is set)
++===========================================================================*/
++static int Require(LPXMLPARSER parser, XMLCH *tok,
++ XMLCH *endChars, int *cEndChars)
++{
++ int chSize, bytesRead=0;
++ XMLCH *c, *token = tok;
++
++ while(*tok) {
++ if (!(c = ReadCh(parser, &chSize))) goto ExitErr;
++ bytesRead+=chSize;
++ if (chSize > 1) goto ExitErr;
++ if (*c != *tok) break;
++ tok++;
++ }
++
++ if (*tok) goto ExitErr;
++ if (!(c = ReadCh(parser, &chSize))) goto ExitErr;
++ bytesRead+=chSize;
++ if (chSize > 1) goto ExitErr;
++
++ while (*cEndChars) {
++ if (*c == endChars[--(*cEndChars)]) {
++ (*cEndChars)++;
++ break;
++ }
++ }
++
++ if (!*cEndChars && !isspace(*c)) goto ExitErr;
++
++ return 1;
++ExitErr:
++ if (bytesRead) DPOS(bytesRead);
++ if (!parser->ErrorCode)
++ Err(parser, ERR_XMLP_EXPECTED_TOKEN, token);
++ return 0;
++}
++
++/*===========================================================================
++ FUNCTION
++ ParseStartTag
++ RETURNS
++ 0 failure
++ 1 success
++===========================================================================*/
++static int ParseStartTag(LPXMLPARSER parser)
++{
++ int namepos, namelen, prefixlen, isEmpty;
++ int endChars = 2;
++ XMLCH *s;
++ LPXMLRUNTIMETAG pTag;
++ LPXMLRUNTIMEATT pAtt; /* for CLEANUPATTS */
++
++ namepos = ParseNameTok(parser, &namelen, &prefixlen, "/>", &endChars);
++ if (namepos == -1) return 0;
++
++ if (!endChars) {
++ if (!namelen) return ErrP(parser, ERR_XMLP_WS_NOT_ALLOWED, 1);
++ /* note that isEmpty doesn't have to be initialized, empty check
++ is handled by ParseAttributes */
++ }
++ else if (endChars == 1) {
++ if (!(RequireCh(parser, '>', 0))) return 0;
++ isEmpty = 1;
++ }
++ else isEmpty = 0; /* tag is simple start tag */
++
++ if (!(pTag = STACK_PUSH(RT->tagstack, NULL)))
++ return Err(parser, ERR_XMLP_MEMORY_ALLOC);
++
++ if (!(XMLStringbuf_Init(&pTag->nameBuf, 64, 0)))
++ return Err(parser, ERR_XMLP_MEMORY_ALLOC);
++
++ pTag->localName = pTag->prefix = EmptyStr;
++ pTag->prevScope = RT->nsScope;
++ pTag->Scope = (LPXMLHTABLE)NULL;
++
++ pTag->qname = XMLStringbuf_Append(&pTag->nameBuf, PREADER->buf+namepos, namelen+1);
++ if (ISNULLSTR(pTag->qname)) return Err(parser, ERR_XMLP_MEMORY_ALLOC);
++ pTag->qname[namelen] = '\0';
++
++ if (ISNULLSTR(parser->DocumentElement)) {
++ if (RT->doctypeName) {
++ if (strcmp(pTag->qname, RT->doctypeName))
++ return Err(parser, ERR_XMLP_EXPECTED_FOUND, RT->doctypeName, pTag->qname);
++ parser->DocumentElement = RT->doctypeName;
++ }
++ else if (ISNULLSTR((parser->DocumentElement = memdup(pTag->qname, namelen+1))))
++ return Err(parser, ERR_XMLP_MEMORY_ALLOC);
++ }
++ else if (RT->tagstack->length == 1)
++ return Err(parser, ERR_XMLP_MULTIPLE_TOP);
++
++ if (_XMLParser_GetFlag(parser, XMLFLAG_NAMESPACES)) {
++ if (!endChars) {
++ if (!(ParseAttributes(parser, pTag, &isEmpty))) return 0;
++ }
++
++ if (prefixlen) {
++ if (!ParseTagNS(parser, pTag, namelen, prefixlen)) return 0;
++ }
++ else if (RT->nsScope != NULL &&
++ ((s = XMLHTable_Lookup(RT->nsScope, TOK_XMLNS))!=NULL)) {
++ pTag->uri = s;
++ }
++ else {
++ pTag->uri = EmptyStr;
++ }
++ }
++ else {
++ if (!endChars) {
++ if (!(ParseAttributes(parser, (LPXMLRUNTIMETAG)NULL, &isEmpty)))
++ return 0;
++ }
++ pTag->uri = EmptyStr;
++ }
++
++ if (HANDLER(startElement)) {
++ if (HANDLER(startElement)(parser->UserData, pTag->uri,
++ pTag->localName, pTag->qname, RT->atts) == XML_ABORT)
++ return Err(parser, ERR_XMLP_ABORT);
++ }
++
++ if (isEmpty) {
++ if (HANDLER(endElement)) {
++ if (HANDLER(endElement)(parser->UserData, pTag->uri,
++ pTag->localName, pTag->qname) == XML_ABORT)
++ return Err(parser, ERR_XMLP_ABORT);
++ }
++ XMLStringbuf_Free(&pTag->nameBuf);
++ if (pTag->Scope!=NULL) {
++ XMLHTable_Destroy(pTag->Scope, DestroyUriTableProc, 1);
++ free(pTag->Scope);
++ }
++ RT->nsScope = pTag->prevScope;
++ STACK_REMOVE(RT->tagstack);
++ }
++
++ CLEANUP_ATTS;
++ return 1;
++}
++
++/*===========================================================================
++ FUNCTION
++ ParseTagNS
++ DESC
++ Set tag's namespace uri, localName and prefix
++ PARAMS
++ parser this
++ pTag tag from ParseStartTag()
++ pos position of ':' character in pTag->qname
++ RETURNS
++ 0 failure
++ 1 success
++===========================================================================*/
++static int ParseTagNS(LPXMLPARSER parser, LPXMLRUNTIMETAG pTag, int namelen, int pos)
++{
++ pTag->qname = XMLStringbuf_Append(&pTag->nameBuf, pTag->qname, namelen+1);
++ if (ISNULLSTR(pTag->qname)) return Err(parser, ERR_XMLP_MEMORY_ALLOC);
++ /* qname can be relocated! */
++
++ pTag->prefix=pTag->qname+namelen+1;
++ if (pos == 3 && ISXMLPREFIX(pTag->prefix))
++ return ErrP(parser, ERR_XMLP_INVALID_NAME, 3);
++
++ pTag->prefix[pos] = '\0';
++ pTag->localName = pTag->prefix+pos+1;
++
++ if (RT->nsScope == NULL ||
++ ((pTag->uri = XMLHTable_Lookup(RT->nsScope, pTag->prefix))==NULL)) {
++ pTag->uri = EmptyStr;
++ return Err(parser, ERR_XMLP_UNDEF_NSPREFIX, pTag->prefix);
++ }
++ return 1;
++}
++
++/*===========================================================================
++ FUNCTION
++ ParseAttributes
++ DESC
++ Parse attributes and resolve namespace declarations
++ PARAMS
++ parser this
++ pTag tag from ParseStartTag or NULL if ns handling isn't needed.
++ isEmpty for ParseStartTag to indicate that element doesn't have any
++ content.
++ RETURNS
++ 0 failure
++ 1 success
++ TODO
++ split into smaller routines? separate ns decl handling?
++===========================================================================*/
++static int ParseAttributes(LPXMLPARSER parser,
++ LPXMLRUNTIMETAG pTag, int *isEmpty)
++{
++ int attCount, i, nsDefdecl, namepos, namelen, prefixlen, endChars;
++ int processNS = (pTag!=(LPXMLRUNTIMETAG)NULL);
++ int NSprefixes = _XMLParser_GetFlag(parser, XMLFLAG_NAMESPACE_PREFIXES);
++ XMLCH *uri, *s , c;
++ LPXMLRUNTIMEATT pAtt;
++ XMLATTRIBUTETYPE attType;
++
++ attCount = nsDefdecl = *isEmpty = 0;
++
++ while (1)
++ {
++ if ((i = SkipWS(parser, TOK_GT)) == -1) return 0;
++ c = PREADER->buf[PREADER->pos];
++
++ if (c == '>') {
++ IPOS(1);
++ break;
++ }
++
++ if (c == '/') {
++ IPOS(1);
++ if (!(RequireCh(parser, '>', 0))) return 0;
++ *isEmpty = 1;
++ break;
++ }
++
++ if (attCount++ && !i)
++ return ErrP(parser, ERR_XMLP_WS_REQUIRED, 0);
++
++ endChars = 1;
++ namepos = ParseNameTok(parser, &namelen, &prefixlen, "=", &endChars);
++ if (namepos == -1) return 0; /* error is set */
++
++ if (!endChars && !namelen)
++ return Err(parser, ERR_XMLP_EXPECTED_TOKEN, TOK_GT);
++
++ if(!(pAtt = XMLVector_Append(RT->atts, NULL)))
++ return Err(parser, ERR_XMLP_MEMORY_ALLOC);
++ pAtt->localName = pAtt->prefix = pAtt->uri = EmptyStr;
++
++ if (!XMLStringbuf_Init(&pAtt->nameBuf, 64, 0))
++ return Err(parser, ERR_XMLP_MEMORY_ALLOC);
++ pAtt->qname = XMLStringbuf_Append(&pAtt->nameBuf, PREADER->buf+namepos, namelen+1);
++ if (ISNULLSTR(pAtt->qname))
++ return Err(parser, ERR_XMLP_MEMORY_ALLOC);
++ pAtt->qname[namelen] = '\0';
++
++ if (!endChars) {
++ if (!(RequireCh(parser, '=', 1))) return 0;
++ }
++
++ if (!XMLStringbuf_Init(&pAtt->valBuf, 64, 0))
++ return Err(parser, ERR_XMLP_MEMORY_ALLOC);
++ pAtt->value = ParseString(parser, &pAtt->valBuf, pAtt,
++ (!(_XMLParser_GetFlag(parser, XMLFLAG_PRESERVE_WS_ATTRIBUTES))), 2);
++ if (ISNULLSTR(pAtt->value)) return 0;
++
++ /* determine the type of attribute: */
++ if (!processNS)
++ attType = XMLATT_NORMAL;
++ else {
++ if (prefixlen) {
++ if (prefixlen == 5 && ISXMLNSPREFIX(pAtt->qname))
++ attType = XMLATT_PREFIXDECL;
++ else if (prefixlen == 3 && ISXMLPREFIX(pAtt->qname))
++ attType = XMLATT_XMLPREFIXDECL;
++ else
++ attType = XMLATT_WITHNS;
++ }
++ else {
++ if (namelen == 5 && ISXMLNSPREFIX(pAtt->qname))
++ attType = XMLATT_DEFAULTDECL;
++ else
++ attType = XMLATT_NORMAL;
++ }
++ }
++
++ if (processNS) {
++
++ if (attType == XMLATT_PREFIXDECL) {
++ /* namespace declaration: */
++ if (!pAtt->valBuf.len)
++ return Err(parser, ERR_XMLP_INVALID_ATT_VALUE, pAtt->qname);
++
++ INIT_NSSCOPE; /* initialize RT->nsScope */
++
++ if (ISNULLSTR(uri = prepUri(pAtt->value, 1)))
++ return Err(parser, ERR_XMLP_MEMORY_ALLOC);
++
++ s = XMLHTable_Insert(RT->nsScope,
++ pAtt->qname+prefixlen+1, (void*)uri);
++ if (!s) return Err(parser, ERR_XMLP_MEMORY_ALLOC);
++ else if (uri != s) {
++ if (*(s-1)) { /* check if declared in this element. see prepURI */
++ free((s-1));
++ return Err(parser, ERR_XMLP_DUPL_ATTRIBUTE, pAtt->qname);
++ }
++ free((s-1));
++ }
++ if (!NSprefixes) {
++ XMLStringbuf_Free(&pAtt->nameBuf);
++ XMLStringbuf_Free(&pAtt->valBuf);
++ XMLVector_Remove(RT->atts, RT->atts->length-1);
++ continue;
++ }
++ pAtt->uri = uriXMLNS; /* note that xmlns or xml prefixes aren't set,
++ only static uris */
++ }
++ else if (attType == XMLATT_XMLPREFIXDECL) {
++ /* predefined xml namespace: */
++ pAtt->localName = pAtt->qname+prefixlen+1;
++
++ if (!strcmp(pAtt->localName, "space")) {
++ if (!(!strcmp(pAtt->value, "default") ||
++ !strcmp(pAtt->value, "preserve")))
++ return Err(parser, ERR_XMLP_INVALID_ATT_VALUE, pAtt->qname);
++ }
++
++ INIT_NSSCOPE; /* initialize RT->nsScope */
++
++ if (ISNULLSTR(uri = prepUri(pAtt->value, 1)))
++ return Err(parser, ERR_XMLP_MEMORY_ALLOC);
++
++ s = XMLHTable_Insert(RT->nsScope, pAtt->qname, (void*)uri);
++ if (!s) return Err(parser, ERR_XMLP_MEMORY_ALLOC);
++ else if (uri != s) free((s-1)); /* note that pointer must be decremented */
++
++ pAtt->uri = uriXML; /* static uri */
++ }
++ else if (attType == XMLATT_WITHNS) {
++ /* set prefix and localName (they will be examined later when
++ all atts are collected into vector) */
++ /* note that qname can be relocated */
++ pAtt->qname = XMLStringbuf_Append(&pAtt->nameBuf, pAtt->qname, namelen+1);
++ if (ISNULLSTR(pAtt->qname))
++ return Err(parser, ERR_XMLP_MEMORY_ALLOC);
++
++ pAtt->prefix=pAtt->qname+namelen+1;
++ pAtt->prefix[prefixlen] = '\0';
++ pAtt->localName = pAtt->prefix+prefixlen+1;
++ }
++ /* test default declaration: */
++ else if (attType == XMLATT_DEFAULTDECL) {
++
++ if (nsDefdecl)
++ return Err(parser, ERR_XMLP_DUPL_ATTRIBUTE, pAtt->qname);
++
++ nsDefdecl = 1;
++ INIT_NSSCOPE;
++
++ if (!pAtt->valBuf.len) { /* undeclaration: */
++ if ((uri = XMLHTable_Remove(RT->nsScope, TOK_XMLNS)) != NULL)
++ free((uri-1)); /* note that pointer must be decremented */
++ }
++ else {
++ if (ISNULLSTR(uri = prepUri(pAtt->value, 1)))
++ return Err(parser, ERR_XMLP_MEMORY_ALLOC);
++
++ s = XMLHTable_Insert(RT->nsScope, TOK_XMLNS, (void*)uri);
++ if (!s) return Err(parser, ERR_XMLP_MEMORY_ALLOC);
++ else if (uri != s) free((s-1));
++ }
++ if (!NSprefixes) {
++ XMLStringbuf_Free(&pAtt->nameBuf);
++ XMLStringbuf_Free(&pAtt->valBuf);
++ XMLVector_Remove(RT->atts, RT->atts->length-1);
++ continue;
++ }
++ pAtt->uri = uriXMLNS;
++ }
++ } /* processNS (namespaces on) */
++ /* store attribute into namedAtts hashtable; we cannot store
++ direct pointer to Vector item 'cos it might get relocated thus
++ we have to store index to newly added
++ vector item. Same thing applies to RT->entitiesTable.
++ We just use void* hashtable item to hold index, this might change
++ when hashtable gets changed/optimized. */
++ i = (int)XMLHTable_Insert(RT->namedAtts, pAtt->qname, (void*)RT->atts->length);
++ if (RT->atts->length != i) {
++ if (!i) return Err(parser, ERR_XMLP_MEMORY_ALLOC);
++ return Err(parser, ERR_XMLP_DUPL_ATTRIBUTE, pAtt->qname);
++ }
++ }
++
++ if (processNS && RT->atts->length) {
++ /* test Vector for declared namespace prefixes and set uris. Cannot
++ test attribute prefixes "on the fly" 'cos declaration can follow
++ the prefixed attribute i.e. x:att='val' xmlns:x='uri.org'
++ is legal. */
++ for (i=0; iatts->length; i++) {
++ pAtt = XMLVector_Get(RT->atts, i);
++ if (pAtt->prefix != EmptyStr) {
++ if (RT->nsScope == NULL ||
++ ((uri = XMLHTable_Lookup(RT->nsScope, pAtt->prefix))==NULL))
++ {
++ pAtt->uri = EmptyStr;
++ return Err(parser, ERR_XMLP_UNDEF_NSPREFIX, pAtt->prefix);
++ }
++ pAtt->uri = uri;
++ }
++ }
++ }
++ return 1;
++ /* NOTE: if there's attributes in the vector and error occurs,
++ vector will be emptied in XMLParser_Parse */
++}
++
++/*===========================================================================
++ FUNCTION
++ ParseComment
++ DESC
++ Parses comment tag
++ PARAMS
++ parser this
++ skip TRUE when parsing External DTD
++ RETURNS
++ 0 failure
++ 1 success
++===========================================================================*/
++/* NOTE: RT->charsBuf will be emptied in _parse in error condition
++ thus we can return 0 at any time in ParseComment, ParseCData etc. */
++static int ParseComment(LPXMLPARSER parser, int skip)
++{
++ int chSize, startPos;
++ XMLCH *c;
++ int bReport = (!skip && HANDLER(comment));
++
++ IPOS(3);
++ startPos = PREADER->pos + 1;
++
++ while((c = ReadCh(parser, &chSize))) {
++ if (chSize == 1) {
++ if (*c == '-' && PREADER->pos > startPos) {
++ if (*(c-1) == '-') {
++ if (!RequireCh(parser, '>', 0)) break;
++ if (bReport) {
++ if (HANDLER(comment)(parser->UserData, RT->charsBuf.str,
++ RT->charsBuf.len-1) == XML_ABORT)
++ return Err(parser, ERR_XMLP_ABORT);
++ if (!XMLStringbuf_SetLength(&RT->charsBuf, 0))
++ return Err(parser, ERR_XMLP_MEMORY_ALLOC);
++ }
++ return 1;
++ }
++ }
++ }
++ if (bReport) {
++ if (ISNULLSTR(XMLStringbuf_Append(&RT->charsBuf, c, chSize)))
++ return Err(parser, ERR_XMLP_MEMORY_ALLOC);
++ }
++ }
++
++ if (!parser->ErrorCode)
++ Err(parser, ERR_XMLP_EXPECTED_TOKEN, "-->");
++ return 0;
++}
++
++/*===========================================================================
++ FUNCTION
++ ParseCData
++ DESC
++ Parses CData tag
++ RETURNS
++ 0 failure
++ 1 success
++===========================================================================*/
++static int ParseCData(LPXMLPARSER parser)
++{
++ int chSize, startPos;
++ XMLCH *c;
++
++ if (!RT->tagstack->length)
++ return ErrP(parser, ERR_XMLP_INVALID_AT_TOP, 1);
++
++ IPOS(8);
++ startPos = PREADER->pos + 2; /* start testing ]] when > found */
++
++ while((c = ReadCh(parser, &chSize))) {
++ if (chSize == 1) {
++ if (*c == '>' && PREADER->pos > startPos) {
++ if (*(c-1) == ']' && *(c-2) == ']') {
++ if (HANDLER(startCDATA)) {
++ if (HANDLER(startCDATA)(parser->UserData) == XML_ABORT)
++ return Err(parser, ERR_XMLP_ABORT);
++
++ if (HANDLER(characters) && (RT->charsBuf.len - 2) > 0) {
++ if (HANDLER(characters)(parser->UserData,
++ RT->charsBuf.str, RT->charsBuf.len - 2) == XML_ABORT)
++ return Err(parser, ERR_XMLP_ABORT);
++ }
++ }
++
++ if (HANDLER(endCDATA)) {
++ if (HANDLER(endCDATA)(parser->UserData) == XML_ABORT)
++ return Err(parser, ERR_XMLP_ABORT);
++ }
++ if (!XMLStringbuf_SetLength(&RT->charsBuf, 0))
++ return Err(parser, ERR_XMLP_MEMORY_ALLOC);
++ return 1;
++ }
++ }
++ }
++ if (ISNULLSTR(XMLStringbuf_Append(&RT->charsBuf, c, chSize)))
++ return Err(parser, ERR_XMLP_MEMORY_ALLOC);
++ }
++
++ if (!parser->ErrorCode)
++ Err(parser, ERR_XMLP_EXPECTED_TOKEN, "]]>");
++ return 0;
++}
++
++/*===========================================================================
++ FUNCTION
++ ParsePI
++ DESC
++ Parses processing instruction tag
++ RETURNS
++ 0 failure
++ 1 success
++===========================================================================*/
++static int ParsePI(LPXMLPARSER parser, int skip)
++{
++ int l, namepos, namelen, endChars = 1;
++ int bReport = (!skip && HANDLER(processingInstruction));
++ XMLCH *target, *data = EmptyStr;
++
++ IPOS(1);
++ if ((l = SkipWS(parser, TOK_END_PI)) == -1) return 0;
++ if (l) return ErrP(parser, ERR_XMLP_WS_NOT_ALLOWED, 1);
++
++ namepos = ParseNameTok(parser, &namelen, (int*)NULL, "?", &endChars);
++ if (namepos == -1) return 0; /* error is set */
++
++ target = BUFTOSTR(PREADER->buf, namepos, namepos+namelen);
++
++ if (namelen == 3 && !stricmp(target, TOK_XML))
++ return Err(parser, ERR_XMLP_INVALID_DECL, TOK_XML);
++
++ if (endChars) {
++ if (!RequireCh(parser, '>', 0)) return 0;
++ }
++ else {
++ int startPos, chSize;
++ XMLCH *c;
++
++ if (SkipWS(parser, TOK_END_PI) == -1) return 0;
++ startPos = PREADER->pos + 1;
++
++ while((c = ReadCh(parser, &chSize))) {
++ if (chSize == 1) {
++ if (*c == '>' && PREADER->pos > startPos) {
++ if (*(c-1) == '?') {
++ if (bReport && (RT->charsBuf.len - 1) > 0) {
++ data = RT->charsBuf.str;
++ data[RT->charsBuf.len-1] = '\0';
++ }
++ break;
++ }
++ }
++ }
++ if (bReport) {
++ if (ISNULLSTR(XMLStringbuf_Append(&RT->charsBuf, c, chSize)))
++ return Err(parser, ERR_XMLP_MEMORY_ALLOC);
++ }
++ }
++ if (parser->ErrorCode) return 0;
++ if (!c) return Err(parser, ERR_XMLP_EXPECTED_TOKEN, TOK_END_PI);
++ }
++
++ if (bReport) {
++ if (HANDLER(processingInstruction)(parser->UserData,
++ target, data) == XML_ABORT) {
++ return Err(parser, ERR_XMLP_ABORT);
++ }
++ if (!XMLStringbuf_SetLength(&RT->charsBuf, 0))
++ return Err(parser, ERR_XMLP_MEMORY_ALLOC);
++ }
++ return 1;
++}
++
++/*===========================================================================
++ FUNCTION
++ SetEncoding
++ DESC
++ Sets parser's BUFFEREDISTREAM encode handler
++ PARAMS
++ parser this
++ encodingName encoding name as string
++ RETURNS
++ 0 failure
++ 1 success
++===========================================================================*/
++static int SetEncoding(LPXMLPARSER parser, XMLCH *encodingName)
++{
++ LPFNENCODE fnEncode;
++
++ if (!stricmp(encodingName, "UTF-8"))
++ fnEncode = Utf8Validator;
++ else if (!stricmp(encodingName, "ISO-8859-1"))
++ fnEncode = Latin1ToUtf8;
++ else if (!stricmp(encodingName, "US-ASCII"))
++ fnEncode = Latin1ToUtf8; /* hmm */
++ else
++ return Err(parser, ERR_XMLP_UNSUP_ENCODING, encodingName);
++
++ if (!PREADER->encode) PREADER->encode = fnEncode;
++ return 1;
++}
++
++/*===========================================================================
++ FUNCTION
++ ParseXmlDecl
++ DESC
++ Parses xmldecl / textdecl
++ PARAMS
++ parser this
++ skip TRUE when parsing External entity or external DTD
++ RETURNS
++ 0 failure
++ 1 success
++ NOTES
++ Called from DetectEncoding.
++===========================================================================*/
++static int ParseXmlDecl(LPXMLPARSER parser, int skip)
++{
++ int l, iver, ienc, ista, count=0;
++ XMLCH *enc, *sta, *ver, c;
++ iver = ienc = ista = -1;
++ IPOS(5); /* skip buf[PREADER->pos];
++
++ if (c == '?') {
++ IPOS(1);
++ if (!(RequireCh(parser, '>', 0))) return 0;
++ break;
++ }
++
++ if (!l)
++ return ErrP(parser, ERR_XMLP_WS_REQUIRED, 0);
++
++ l = 1;
++ if (c == 'v') {
++ if (iver != -1 || count) return 0;
++ if (!Require(parser, "version", "=", &l)) return 0;
++ iver = RT->charsBuf.len;
++ }
++ else if (c == 'e') {
++ if (skip) {
++ if (ienc != -1) return 0;
++ }
++ else {
++ if (count != 1 || ienc != -1) return 0;
++ }
++ if (!Require(parser, "encoding", "=", &l)) return 0;
++ ienc = RT->charsBuf.len;
++ }
++ else if (c == 's') {
++ if (iver == -1 || ista != -1 || skip) return 0;
++ if (!Require(parser, "standalone", "=", &l)) return 0;
++ ista = RT->charsBuf.len;
++ }
++ else return 0;
++
++ if (!l && !RequireCh(parser, '=', 1)) return 0;
++ if (!ParseString(parser, &RT->charsBuf, NULL, 0, 0)) return 0;
++ RT->charsBuf.len++; /* skip NUL in XMLStringbuf buffer */
++ count++;
++ }
++
++ if (!count) return 0;
++
++ ver = (iver == -1) ? (XMLCH*)NULL : RT->charsBuf.str+iver;
++ enc = (ienc == -1) ? (XMLCH*)NULL : RT->charsBuf.str+ienc;
++ sta = (ista == -1) ? (XMLCH*)NULL : RT->charsBuf.str+ista;
++
++ if (ver) {
++ if (strcmp(ver, "1.0")) return 0;
++ }
++ else {
++ if (!skip) return 0;
++ }
++
++ if (enc && !SetEncoding(parser, enc)) return 0;
++ if (sta) {
++ if (strcmp(sta, "no")) {
++ if (strcmp(sta, "yes")) return 0;
++ }
++ }
++
++ if (!skip && HANDLER(xmlDecl)) {
++ if (HANDLER(xmlDecl)(parser->UserData, ver, enc, sta) == XML_ABORT)
++ return Err(parser, ERR_XMLP_ABORT);
++ }
++ return 1;
++}
++
++/*===========================================================================
++ FUNCTION
++ DetectEncoding
++ DESC
++ Detects document encoding and xmldecl/textdecl
++ PARAMS
++ parser this
++ skip TRUE this is external entity/DTD
++ FALSE this is main document entity (report xmldecl)
++ defaultEncoding encoding to be used if none is detected
++ RETURNS
++ 0 failure
++ 1 success
++===========================================================================*/
++static int DetectEncoding(LPXMLPARSER parser, int skip, LPFNENCODE defaultEncoding)
++{
++ int ret;
++ if (!(ret = PEEKINPUT((const XMLCH*)NULL, 4))) {
++ if (PREADER->buf[0]==(BYTE)0xEF &&
++ PREADER->buf[1]==(BYTE)0xBB &&
++ PREADER->buf[2]==(BYTE)0xBF) {
++ if (!PREADER->encode) PREADER->encode = Utf8Validator;
++ if (ISFATAL(BufferedIStream_ResetBuf(PREADER, 3))) return 0;
++ }
++ else {
++ /* hmmm atleast we give some kind of hint here -
++ testing only 1st byte of possible BOMs: */
++ if (PREADER->buf[0]==(BYTE)0x00 ||
++ PREADER->buf[0]==(BYTE)0xFE ||
++ PREADER->buf[0]==(BYTE)0xFF)
++ return Err(parser, ERR_XMLP_UNSUP_ENCODING, "UNKNOWN");
++ }
++ }
++ if (ISFATAL(ret)) return 0;
++
++ if (!(ret = PEEKINPUT("ErrorCode)
++ Err(parser, ERR_XMLP_INVALID_DECL, "xml");
++ return 0;
++ }
++ if (!XMLStringbuf_SetLength(&RT->charsBuf, 0))
++ return Err(parser, ERR_XMLP_MEMORY_ALLOC);
++ }
++
++ if (ISFATAL(ret)) return 0;
++ /* set default encoding if there isn't any specified: */
++ if (!PREADER->encode) PREADER->encode = defaultEncoding;
++
++ if (PREADER->pos) {
++ if (ISFATAL(BufferedIStream_ResetBuf(PREADER, PREADER->pos))) return 0;
++ }
++
++ if ((ret = BufferedIStream_EncodeBuffer(PREADER, 0))) {
++ SetReaderFatal(parser, ret);
++ return 0;
++ }
++ return 1;
++}
++
++#ifndef HAS_STRICMP
++/*===========================================================================
++ FUNCTION
++ stricmp
++ DESC
++ case-insensitive strcmp
++===========================================================================*/
++static int stricmp(const char *s1, const char *s2)
++{
++ char c1, c2;
++ while(1)
++ {
++ c1 = toupper(*s1++);
++ c2 = toupper(*s2++);
++ if(c1 == 0 && c2 == 0)
++ return 0;
++ if(c1 == 0)
++ return -1;
++ if(c2 == 0)
++ return 1;
++ if(c1 < c2)
++ return -1;
++ if(c1 > c2)
++ return 1;
++ }
++}
++#endif /* HAS_STRICMP */
++
++static XMLCH* memdup(XMLCH *buf, int len)
++{
++ XMLCH *d = (XMLCH*)malloc(len*sizeof(XMLCH));
++ if (!ISNULLSTR(d)) memcpy(d, buf, len);
++ return d;
++}
++
++/*===========================================================================
++ FUNCTION
++ DestroyUriTableProc
++ DESC
++ enumeration callback for removing nsScope hashtable keys and data.
++ TODO
++ endPrefixMapping handler must be implemented here...
++=================================c==========================================*/
++static int DestroyUriTableProc(char *key, void *data, void *userdata)
++{
++ char *d = (char*)data;
++ XMLHTable_Remove((LPXMLHTABLE)userdata, key);
++ if (d) free(--d);
++ return 0;
++}
++
++/*===========================================================================
++ FUNCTION
++ prepUri
++ DESC
++ duplicates uri string and sets "declared here" flag
++ PARAMS
++ uri string to duplicate
++ declHere whether this is declared in this element (bool)
++ RETURNS
++ duplicate string, NULL if unsuccessful
++ NOTES
++ uri string's first char contains flag that specifies whether
++ this uri is declared in this element or copied from previous scope.
++ see CopyUriTableProc. Have to be careful with this hack...
++===========================================================================*/
++static XMLCH* prepUri(XMLCH *uri, int declHere)
++{
++ int len = strlen(uri);
++ XMLCH *dup = (XMLCH*)malloc((len + 2) * sizeof(XMLCH));
++ if (ISNULLSTR(dup)) return (XMLCH*)NULL;
++ *(dup) = (char)declHere;
++ memcpy(++dup, uri, len+1);
++ return dup;
++}
++
++/*===========================================================================
++ FUNCTION
++ CopyUriTableProc
++ DESC
++ enumeration callback for copying nsScope hashtable.
++===========================================================================*/
++static int CopyUriTableProc(char *key, void *data, void *userdata)
++{
++ char *dup = prepUri((XMLCH*)data, 0);
++ if (!dup) return 1;
++ if (!(XMLHTable_Insert((LPXMLHTABLE)userdata, key, (void*)dup))) return 1;
++ return 0;
++}
++
++/*===========================================================================
++ FUNCTION
++ XMLNormalizeBuf
++ DESC
++ Normalizes whitespace and line breaks in buffer
++ RETURNS
++ new length of normalized buf
++ NOTES
++ Doesn't trim values nor NUL terminate/truncate buf to new length.
++ This is part of XMLAPI and is exported as helper function
++===========================================================================*/
++int XMLAPI XMLNormalizeBuf(XMLCH *buf, int len)
++{
++ int l, l2, numws;
++ for (l=0; lreader = (LPBUFFEREDISTREAM)
++ malloc(sizeof(BUFFEREDISTREAM)))) return (_pp=NULL);
++ _pp->reader->buf = _pp->reader->ubuf = (XMLCH*)NULL;
++
++ if (!(_pp->reader->userdata = (LPBISREADERDATA)
++ malloc(sizeof(BISREADERDATA)))) return (_pp=NULL);
++
++ if (!( _pp->prt = (LPXMLPARSERRUNTIME)
++ malloc(sizeof(XMLPARSERRUNTIME)))) return (_pp=NULL);
++
++ _pp->XMLFlags = XMLFLAG_NAMESPACES | XMLFLAG_CONVERT_EOL |
++ XMLFLAG_EXTERNAL_GENERAL_ENTITIES;
++
++ if (!( _pp->prt->atts = XMLVector_Create(&_pp->prt->atts, 16,
++ sizeof(XMLRUNTIMEATT)))) return (_pp=NULL);
++ _pp->prt->atts->capacityIncrement = 16;
++
++ if (!( _pp->prt->tagstack = XMLVector_Create(&_pp->prt->tagstack, 16,
++ sizeof(XMLRUNTIMETAG)))) return (_pp=NULL);
++ _pp->prt->tagstack->capacityIncrement = 16;
++
++ if (!( _pp->prt->namedAtts = (LPXMLHTABLE)
++ malloc(sizeof(XMLHTABLE)))) return (_pp=NULL);
++ XMLHTable_Create(_pp->prt->namedAtts, 255);
++ if (!_pp->prt->namedAtts->size) return (_pp=NULL);
++
++#ifdef DTD_SUPPORT
++ if (!( _pp->prt->entities = XMLVector_Create(&_pp->prt->entities, 16,
++ sizeof(XMLENTITY)))) return (_pp=NULL);
++ _pp->prt->entities->capacityIncrement = 16;
++
++ if (!( _pp->prt->entitiesTable = (LPXMLHTABLE)
++ malloc(sizeof(XMLHTABLE)))) return (_pp=NULL);
++ XMLHTable_Create(_pp->prt->entitiesTable, 64);
++ if (!_pp->prt->entitiesTable->size) return (_pp=NULL);
++#endif
++
++ if (!XMLStringbuf_Init(&_pp->prt->charsBuf, 256, 0))
++ return (_pp=NULL);
++ return (_pp);
++ #undef _pp
++}
++
++/*===========================================================================
++ FUNCTION
++ XMLParser_Free
++ DESC
++ XML parser free routine
++===========================================================================*/
++void XMLAPI XMLParser_Free(LPXMLPARSER parser)
++{
++ free(PREADERDATA);
++ free(PREADER);
++ XMLVector_Free(RT->atts);
++ XMLVector_Free(RT->tagstack);
++ free(RT->namedAtts->table); /* should be empty by now so
++ we don't need to call XMLHTable_Destroy... */
++ free(RT->namedAtts);
++#ifdef DTD_SUPPORT
++ XMLVector_Free(RT->entities);
++ free(RT->entitiesTable->table);
++ free(RT->entitiesTable);
++#endif
++ SAFE_FREESTR(parser->DocumentElement);
++ XMLStringbuf_Free(&RT->charsBuf);
++ free(RT);
++ free(parser);
++}
++
++/*===========================================================================
++ FUNCTION
++ XMLParser_GetNamedItem
++ DESC
++ Looks up an attribute by name
++ PARAMS
++ parser this
++ name name to look for
++ RETURNS
++ attribute or NULL if not found
++ NOTES
++ this should be called only in startElement
++===========================================================================*/
++LPXMLRUNTIMEATT XMLAPI XMLParser_GetNamedItem(LPXMLPARSER parser,
++ const XMLCH *name)
++{
++ int index = (int)XMLHTable_Lookup(RT->namedAtts, (XMLCH*)name);
++ return ((index) ? (LPXMLRUNTIMEATT)XMLVector_Get(RT->atts, index-1) :
++ (LPXMLRUNTIMEATT)NULL);
++}
++
++XMLCH XMLAPI *XMLParser_GetPrefixMapping(LPXMLPARSER parser, const XMLCH *prefix)
++{
++ return (!parser || !RT->nsScope) ? (XMLCH*)NULL :
++ (XMLCH*)XMLHTable_Lookup(RT->nsScope, (XMLCH*)prefix);
++}
++
++XMLCH XMLAPI *XMLParser_GetSystemID(LPXMLPARSER parser)
++{
++#ifdef DTD_SUPPORT
++ return (!parser || !PREADERDATA || !PREADERDATA->curEnt) ?
++ (XMLCH*)NULL : (PREADERDATA->curEnt->systemID);
++#else
++ return (XMLCH*)NULL;
++#endif
++}
++
++XMLCH XMLAPI *XMLParser_GetPublicID(LPXMLPARSER parser)
++{
++#ifdef DTD_SUPPORT
++ return (!parser || !PREADERDATA || !PREADERDATA->curEnt) ?
++ (XMLCH*)NULL : (PREADERDATA->curEnt->publicID);
++#else
++ return (XMLCH*)NULL;
++#endif
++}
++
++int XMLAPI XMLParser_GetCurrentLine(LPXMLPARSER parser)
++{
++ return ((!parser || !PREADER->bytesavail) ? -1 : PREADERDATA->line+1);
++}
++
++int XMLAPI XMLParser_GetCurrentColumn(LPXMLPARSER parser)
++{
++ return ((!parser || !PREADER->bytesavail) ? -1 : PREADERDATA->col+1);
++}
++
++/*===========================================================================
++ FUNCTION
++ XMLParser_Parse
++ PARAMS
++ parser this
++ inputSrc input source callback of type LPFNINPUTSRC
++ inputData to be passed to input source callback
++ encoding overrides xml declaration or BOM marker encoding
++ RETURNS
++ 0 failure (parser->ErrorCode was set)
++ 1 success
++===========================================================================*/
++int XMLAPI XMLParser_Parse(LPXMLPARSER parser, LPFNINPUTSRC inputSrc,
++ void *inputData, const XMLCH *encoding)
++{
++ LPXMLRUNTIMETAG pTag;
++ BufferedIStream_Init(PREADER, BIS_DEFAULT_BLOCKSIZE);
++ PREADER->inputsrc = inputSrc;
++ PREADER->inputData = inputData;
++ PREADERDATA->line = PREADERDATA->col = PREADERDATA->noPos = 0;
++ PREADERDATA->ubufsize = PREADERDATA->stackLevel = 0;
++ PREADERDATA->parser = parser;
++ PREADERDATA->curEnt = (LPXMLENTITY)NULL;
++ RT->refReader = PREADER; /* save ref to main reader */
++ RT->nsScope = (LPXMLHTABLE)NULL;
++ RT->doctypeName = (XMLCH*)NULL;
++ SAFE_FREESTR(parser->DocumentElement);
++ if (*parser->ErrorString) *parser->ErrorString = '\0';
++ parser->ErrorCode = parser->ErrorLine = parser->ErrorColumn = 0;
++
++ if (encoding) {
++ if (!SetEncoding(parser, (XMLCH*)encoding))
++ return (parser->ErrorCode == 0);
++ }
++
++ if (HANDLER(startDocument)) {
++ if (HANDLER(startDocument)(parser->UserData) == XML_ABORT) {
++ Err(parser, ERR_XMLP_ABORT);
++ return (parser->ErrorCode == 0);
++ }
++ }
++
++ if (DetectEncoding(parser, 0, Utf8Validator)) ParseInput(parser);
++
++ while(RT->tagstack->length) {
++ pTag = STACK_PEEK(RT->tagstack);
++ if (!parser->ErrorCode) Err(parser, ERR_XMLP_UNCLOSED_TAG, pTag->qname);
++ XMLStringbuf_Free(&pTag->nameBuf); /* frees localName too */
++ if (pTag->Scope!=NULL) {
++ XMLHTable_Destroy(pTag->Scope, DestroyUriTableProc, 1);
++ free(pTag->Scope);
++ }
++ STACK_REMOVE(RT->tagstack);
++ }
++
++ if (parser->ErrorCode) {
++ LPXMLRUNTIMEATT pAtt;
++ CLEANUP_ATTS;
++ XMLStringbuf_SetLength(&RT->charsBuf, 0);
++ }
++ else if (!parser->DocumentElement)
++ Err(parser, ERR_XMLP_EXPECTED_TOKEN, "document element");
++ else if (HANDLER(endDocument)) /* fire endDoc if there's no error */
++ HANDLER(endDocument)(parser->UserData);
++
++
++#ifdef DTD_SUPPORT
++ if (RT->entities->length) {
++ LPXMLENTITY e;
++ int i;
++ for (i=0; ientities->length; i++) {
++ e = XMLVector_Get(RT->entities, i);
++ XMLHTable_Remove(RT->entitiesTable, e->name);
++ free(e->name);
++ }
++ _XMLVector_RemoveAll(RT->entities);
++ }
++ if (RT->doctypeName != parser->DocumentElement)
++ SAFE_FREESTR(RT->doctypeName);
++#endif
++ BufferedIStream_Free(PREADER); /* doesn't free the parser->reader itself,
++ only buffers */
++ return (parser->ErrorCode == 0);
++}
++
++/*===========================================================================
++ FUNCTION
++ ParseInput
++ DESC
++ Main parsing loop
++ PARAMS
++ parser this
++===========================================================================*/
++static void ParseInput(LPXMLPARSER parser)
++{
++ int ret;
++
++ while (ParseContent(parser))
++ {
++ if (!(ret = PEEKINPUT("![CDATA[", 8))) {
++ if (!ParseCData(parser)) break;
++ }
++ else if (ISFATAL(ret)) break; /* we need these tests 'cos we can't call
++ BufferedIStream_Peek if previous call returns fatal error */
++
++ else if (!(ret = PEEKINPUT("?", 1))) {
++ if (!(ParsePI(parser, 0))) break;
++ }
++ else if (ISFATAL(ret)) break;
++
++ else if (!(ret = PEEKINPUT("!--", 3))) {
++ if (!ParseComment(parser, 0)) break;
++ }
++ else if (ISFATAL(ret)) break;
++
++ else if (!(ret = PEEKINPUT("/", 1))) {
++ if (!ParseEndTag(parser)) break;
++ }
++ else if (ISFATAL(ret)) break;
++
++ else if (!RT->doctypeName &&
++ (!(ret = PEEKINPUT(TOK_DOCTYPE, 8)))) {
++ if (!ParseDoctypeDecl(parser)) break;
++ }
++ else if (ISFATAL(ret)) break;
++
++ else {
++ if (!(ret = ParseStartTag(parser))) break;
++ }
++ }
++}
++
++#ifdef DTD_SUPPORT
++
++/*===========================================================================
++ FUNCTION
++ ParseDoctypeDecl
++ DESC
++ Parses doctype declaration tag
++ RETURNS
++ 0 failure
++ 1 success
++ NOTES
++ Calls resolveEntityHandler to get inputsrc for parsing external DTD
++ (entity type XML_ENTITY_DOCTYPE). Internal subset is always parsed first.
++===========================================================================*/
++static int ParseDoctypeDecl(LPXMLPARSER parser)
++{
++ int iSubset, l, namelen, prefixlen, endChars;
++ int iPublicID, iSystemID;
++ XMLSTRINGBUF sbuf;
++ XMLENTITY ent;
++ XMLCH c;
++
++ iSubset = ent.type = 0;
++ iPublicID = iSystemID = -1;
++
++ if (!ISNULLSTR(parser->DocumentElement))
++ return Err(parser, ERR_XMLP_INVALID_TOKEN, TOK_DOCTYPE);
++
++ IPOS(8); /* skip !DOCTYPE */
++ if ((l = SkipWS(parser, TOK_GT)) == -1) return 0;
++ if (!l) return ErrP(parser, ERR_XMLP_WS_REQUIRED, 0);
++
++ endChars = 1;
++ l = ParseNameTok(parser, &namelen, &prefixlen, "[", &endChars);
++ if (l == -1) return 0; /* error is set */
++
++ if (!(RT->doctypeName = memdup(PREADER->buf+l, namelen+1)))
++ return Err(parser, ERR_XMLP_MEMORY_ALLOC);
++
++ RT->doctypeName[namelen] = '\0';
++ ent.name = RT->doctypeName;
++ if (!XMLStringbuf_Init(&sbuf, 128, 0))
++ return Err(parser, ERR_XMLP_MEMORY_ALLOC);
++
++ if (endChars) { /* name was ended by [ (w/o any whitespace - this
++ is legal) */
++ iSubset = 1;
++ }
++ else { /* parse doctype decl: */
++ while (1) {
++ if ((l = SkipWS(parser, TOK_GT)) == -1) goto ExitErr;
++ c = PREADER->buf[PREADER->pos];
++
++ if (c == '>') {
++ IPOS(1);
++ break;
++ }
++
++ if (c == '[') {
++ iSubset = 1;
++ if (!ent.type) ent.type = XML_ENTITY_DOCTYPE;
++ IPOS(1); /* skip [ */
++ break;
++ }
++
++ if (ent.type) goto ExitErr;
++ endChars = 0;
++
++ if (c == 'P') {
++ if (!Require(parser, "PUBLIC", NULL, &endChars))
++ goto ExitErr;
++ iPublicID = sbuf.len;
++ if (!ParseString(parser, &sbuf, NULL, 1, 0)) goto ExitErr;
++ if ((l = SkipWS(parser, TOK_GT)) == -1) goto ExitErr;
++ if (!l) {
++ ErrP(parser, ERR_XMLP_WS_REQUIRED, 0);
++ goto ExitErr;
++ }
++ sbuf.len++;
++ }
++ else if (c == 'S') {
++ if (!Require(parser, "SYSTEM", NULL, &endChars)) goto ExitErr;
++ }
++ else goto ExitErr;
++
++ iSystemID = sbuf.len;
++ if (!ParseString(parser, &sbuf, NULL, 1, 0)) goto ExitErr;
++ ent.type = XML_ENTITY_DOCTYPE;
++ } /* while(1) */
++ }
++
++ ent.publicID = (iPublicID == -1) ? (XMLCH*)NULL : sbuf.str+iPublicID;
++ ent.systemID = (iSystemID == -1) ? (XMLCH*)NULL : sbuf.str+iSystemID;
++
++ if (HANDLER(startDTD)) {
++ if (HANDLER(startDTD)(parser->UserData, ent.name,
++ ent.publicID, ent.systemID, iSubset) == XML_ABORT)
++ {
++ Err(parser, ERR_XMLP_ABORT);
++ goto ExitErr;
++ }
++ }
++
++ if (iSubset) {
++ if (!(ParseDTD(parser, 0))) goto ExitErr;
++ }
++
++ if (ent.systemID) {
++ if (!ResolveExternalDTD(parser, &ent)) goto ExitErr;
++ }
++
++ if (HANDLER(endDTD)) {
++ if (HANDLER(endDTD)(parser->UserData) == XML_ABORT) {
++ Err(parser, ERR_XMLP_ABORT);
++ goto ExitErr;
++ }
++ }
++
++ XMLStringbuf_Free(&sbuf);
++ return 1;
++ExitErr:
++ if (!parser->ErrorCode) Err(parser, ERR_XMLP_INVALID_DECL, "doctype");
++ XMLStringbuf_Free(&sbuf);
++ return 0;
++}
++
++static int ResolveExternalDTD(LPXMLPARSER parser, LPXMLENTITY e)
++{
++ BUFFEREDISTREAM dtdReader;
++
++ if (HANDLER(resolveEntity)) {
++ /* Get inputsrc for external DTD: */
++ BISREADERDATA readerdata;
++ XMLCH *dtdEntName = "[dtd]";
++
++ BufferedIStream_Init(&dtdReader, BIS_DEFAULT_BLOCKSIZE);
++ dtdReader.userdata = &readerdata;
++ readerdata.line = readerdata.col = readerdata.noPos =
++ readerdata.ubufsize = 0;
++ readerdata.curEnt = e;
++ readerdata.parser = parser;
++ e->name = dtdEntName;
++
++ if (HANDLER(startEntity)) {
++ if (HANDLER(startEntity)(parser->UserData, e) == XML_ABORT) {
++ Err(parser, ERR_XMLP_ABORT);
++ goto ExitErr;
++ }
++ }
++
++ if (HANDLER(resolveEntity)(parser->UserData, e, &dtdReader) == XML_ABORT) {
++ Err(parser, ERR_XMLP_ABORT);
++ goto ExitErr;
++ }
++
++ if (dtdReader.inputData) {
++ if (!dtdReader.inputsrc)
++ dtdReader.inputsrc = PREADER->inputsrc;
++ PREADER = &dtdReader;
++ if (DetectEncoding(parser, 1, RT->refReader->encode)) ParseDTD(parser, 1);
++ if (HANDLER(externalEntityParsed)) {
++ if (HANDLER(externalEntityParsed)(parser->UserData, e,
++ &dtdReader) == XML_ABORT)
++ Err(parser, ERR_XMLP_ABORT);
++ }
++ PREADER = RT->refReader;
++ if (parser->ErrorCode) goto ExitErr;
++ }
++ if (HANDLER(endEntity)) {
++ if (HANDLER(endEntity)(parser->UserData, e) == XML_ABORT) {
++ Err(parser, ERR_XMLP_ABORT);
++ goto ExitErr;
++ }
++ }
++ BufferedIStream_Free(&dtdReader);
++ }
++ return 1;
++ExitErr:
++ BufferedIStream_Free(&dtdReader);
++ return 0;
++}
++
++static int ParseContentDTD(LPXMLPARSER parser, int isExternal)
++{
++ int chSize, iLT, iLF;
++ int bReport = (!isExternal && HANDLER(default));
++ XMLCH *c;
++ iLT = iLF = 0;
++
++ while((c = ReadCh(parser, &chSize))) {
++
++ if (chSize == 1) {
++ if (*c == (XMLCH)0xA) {
++ iLF = PREADER->pos;
++ }
++ else if (*c == '<') {
++ if (iLF) iLT = PREADER->pos - iLF;
++ else if (PREADER->pos > 4096) {
++ iLF = PREADER->pos-1;
++ iLT = 1;
++ }
++ break;
++ }
++ else if (*c == '>')
++ return ErrP(parser, ERR_XMLP_INVALID_TOKEN, 1);
++ else if (*c == ']' && !isExternal) {
++ RequireCh(parser, '>', 1);
++ c = (XMLCH*)NULL;
++ break;
++ }
++ }
++ if (bReport) {
++ if (ISNULLSTR(XMLStringbuf_Append(&RT->charsBuf, c, chSize)))
++ return Err(parser, ERR_XMLP_MEMORY_ALLOC);
++ }
++ }
++
++ if (parser->ErrorCode) return 0;
++
++ if (RT->charsBuf.len) {
++ if (HANDLER(default)(parser->UserData, RT->charsBuf.str, RT->charsBuf.len)
++ == XML_ABORT)
++ return Err(parser, ERR_XMLP_ABORT);
++ if (!XMLStringbuf_SetLength(&RT->charsBuf, 0))
++ return Err(parser, ERR_XMLP_MEMORY_ALLOC);
++ }
++
++ if (iLT) {
++ if (ISFATAL(BufferedIStream_ResetBuf(PREADER, iLF))) return 0;
++ PREADER->pos+=iLT;
++ }
++ return (c != (XMLCH*)NULL);
++ /* NOTE: we can exit returning 0 at any time, RT->charsBuf is emptied
++ in error condition in _Parse. */
++}
++
++static int ParseDTDMiscTag(LPXMLPARSER parser, int isExternal)
++{
++ int chSize;
++ int bReport = (!isExternal && HANDLER(default));
++ XMLCH *c, quote='\0';
++
++ if (bReport) {
++ if (ISNULLSTR(XMLStringbuf_AppendCh(&RT->charsBuf, '<')))
++ return Err(parser, ERR_XMLP_MEMORY_ALLOC);
++ }
++
++ while((c = ReadCh(parser, &chSize))) {
++ if (chSize == 1) {
++ if (ISQUOTE(*c)) {
++ if (!quote) quote = *c;
++ else if (*c == quote) quote = '\0';
++ }
++ else if (!quote && *c == '>') {
++ if (bReport) {
++ if (ISNULLSTR(XMLStringbuf_AppendCh(&RT->charsBuf, '>')))
++ return Err(parser, ERR_XMLP_MEMORY_ALLOC);
++ }
++ break;
++ }
++ }
++ if (bReport) {
++ if (ISNULLSTR(XMLStringbuf_Append(&RT->charsBuf, c, chSize)))
++ return Err(parser, ERR_XMLP_MEMORY_ALLOC);
++ }
++ }
++
++ if (parser->ErrorCode) return 0;
++
++ if (RT->charsBuf.len) {
++ if (HANDLER(default)(parser->UserData, RT->charsBuf.str, RT->charsBuf.len)
++ == XML_ABORT)
++ return Err(parser, ERR_XMLP_ABORT);
++
++ if (!XMLStringbuf_SetLength(&RT->charsBuf, 0))
++ return Err(parser, ERR_XMLP_MEMORY_ALLOC);
++ }
++ if (!c) {
++ if (!parser->ErrorCode)
++ Err(parser, ERR_XMLP_EXPECTED_TOKEN, ">");
++ return 0;
++ }
++ return 1;
++}
++
++/*===========================================================================
++ FUNCTION
++ ParseDTD
++ DESC
++ Main parsing loop for "DTD scanning"
++ RETURNS
++ 0 failure
++ 1 success
++ NOTES
++ Scans only !ENTITY declarations, when parsing internal subset
++ other tags are simply reported by default, comment or piHandler.
++ "Misc tags" that are reported by defaultHandler aren't checked
++ for well-formedness and content data (between tags) is just
++ outputted because it might be legal parameter entity decls etc.
++ TODO
++ Declaration handlers for DTD. A Bloat for simple parsing library?!
++===========================================================================*/
++static int ParseDTD(LPXMLPARSER parser, int isExternal)
++{
++ int ret;
++
++ while (ParseContentDTD(parser, isExternal))
++ {
++ if (!(ret = PEEKINPUT("?", 1))) {
++ if (!(ParsePI(parser, isExternal))) break;
++ }
++ else if (ISFATAL(ret)) break;
++
++ else if (!(ret = PEEKINPUT("!--", 3))) {
++ if (!ParseComment(parser, isExternal)) break;
++ }
++ else if (ISFATAL(ret)) break;
++
++ else if (!(ret = PEEKINPUT("!ENTITY", 7))) {
++ int i = PREADER->pos; /* store position to !ENTITY */
++ if (!ParseEntityDecl(parser)) break;
++ if (!isExternal && HANDLER(default)) {
++ PREADERDATA->noPos = 1;
++ PREADER->pos = i;
++ i = ParseDTDMiscTag(parser, isExternal); /* report !ENTITY */
++ PREADERDATA->noPos = 0;
++ if (!i) break;
++ }
++ }
++ else if (ISFATAL(ret)) break;
++ else {
++ if (!ParseDTDMiscTag(parser, isExternal)) break;
++ }
++ }
++ return (parser->ErrorCode == 0);
++}
++
++static int GetEntityDecl(LPXMLPARSER parser, LPXMLENTITY e, LPXMLSTRINGBUF sbuf)
++{
++ int l, isParam, iPublicID, iSystemID, iNotation;
++ int namepos, namelen;
++
++ iPublicID = iSystemID = iNotation = -1;
++ IPOS(7);
++
++ if ((l = SkipWS(parser, TOK_GT)) == -1) return 0;
++ if (!l) return ErrP(parser, ERR_XMLP_WS_REQUIRED, 0);
++
++ if (PREADER->buf[PREADER->pos] == '%') {
++ IPOS(1);
++ isParam = 1;
++ if ((l = SkipWS(parser, TOK_GT)) == -1) return 0;
++ if (!l) return ErrP(parser, ERR_XMLP_WS_REQUIRED, 0);
++ }
++ else isParam = 0;
++
++ l = 0;
++ namepos = ParseNameTok(parser, &namelen, (int*)NULL, (XMLCH*)NULL, &l);
++ if (namepos == -1) return 0; /* error is set */
++
++ if (!(e->name = XMLStringbuf_Append(sbuf, PREADER->buf+namepos, namelen+1)))
++ return Err(parser, ERR_XMLP_MEMORY_ALLOC);
++ e->name[namelen] = '\0';
++
++ if ((l = SkipWS(parser, TOK_GT)) == -1) return 0;
++
++ if (ISQUOTE(PREADER->buf[PREADER->pos])) {
++ e->type = (isParam) ? XML_ENTITY_INT_PARAM : XML_ENTITY_INT_GEN;
++ l = sbuf->len;
++ if (!ParseString(parser, sbuf, NULL, 0, 1)) return 0;
++ if (!RequireCh(parser, '>', 1)) return 0;
++ if (!(e->name = memdup(sbuf->str, sbuf->len+1)))
++ return Err(parser, ERR_XMLP_MEMORY_ALLOC);
++ e->value = e->name+l;
++ e->len = sbuf->len-l;
++ return 1;
++ }
++
++ l = 0;
++ if (PREADER->buf[PREADER->pos] == 'P') {
++ if (!Require(parser, "PUBLIC", (XMLCH*)NULL, &l)) return 0;
++ iPublicID = sbuf->len;
++ if (!ParseString(parser, sbuf, NULL, 1, 0)) return 0;
++ if ((l = SkipWS(parser, TOK_GT)) == -1) return 0;
++ if (!l) return ErrP(parser, ERR_XMLP_WS_REQUIRED, 0);
++ sbuf->len++;
++ }
++ else if (PREADER->buf[PREADER->pos] == 'S') {
++ if (!Require(parser, "SYSTEM", (XMLCH*)NULL, &l)) return 0;
++ }
++ else return Err(parser, ERR_XMLP_EXPECTED_TOKEN, "PUBLIC or SYSTEM");
++
++ iSystemID = sbuf->len;
++ if (!ParseString(parser, sbuf, NULL, 1, 0)) return 0;
++
++ if ((l = SkipWS(parser, TOK_GT)) == -1) return 0;
++
++ if (PREADER->buf[PREADER->pos] != '>') {
++ e->type = XML_ENTITY_UNPARSED;
++ if (isParam)
++ return Err(parser, ERR_XMLP_EXPECTED_TOKEN, ">");
++
++ if (!l) return ErrP(parser, ERR_XMLP_WS_REQUIRED, 0);
++ l = 0;
++ if (!Require(parser, "NDATA", (XMLCH*)NULL, &l)) return 0;
++ if ((l = SkipWS(parser, TOK_GT)) == -1) return 0;
++ l = 1;
++ namepos = ParseNameTok(parser, &namelen, (int*)NULL, ">", &l);
++ if (namepos == -1) return 0; /* error is set */
++
++ iNotation = ++sbuf->len;
++ if (!XMLStringbuf_Append(sbuf, PREADER->buf+namepos, namelen))
++ return Err(parser, ERR_XMLP_MEMORY_ALLOC);
++ if (!XMLStringbuf_ToString(sbuf))
++ return Err(parser, ERR_XMLP_MEMORY_ALLOC);
++
++ if (!l) {
++ if (!RequireCh(parser, '>', 1)) return 0;
++ }
++ }
++ else {
++ e->type = (isParam) ? XML_ENTITY_EXT_PARAM : XML_ENTITY_EXT_GEN;
++ IPOS(1);
++ }
++
++ if (!(e->name = memdup(sbuf->str, sbuf->len+1)))
++ return Err(parser, ERR_XMLP_MEMORY_ALLOC);
++
++ if (iPublicID != -1) e->publicID = e->name + iPublicID;
++ if (iSystemID != -1) e->systemID = e->name + iSystemID;
++ if (iNotation != -1) e->notation = e->name + iNotation;
++
++ return 1;
++}
++
++static int ParseEntityDecl(LPXMLPARSER parser)
++{
++ XMLENTITY e;
++
++ e.type = e.len = e.open = 0;
++ e.name = e.notation = e.publicID = e.systemID = e.value = (XMLCH*)NULL;
++
++ if (!GetEntityDecl(parser, &e, &RT->charsBuf)) return 0;
++ XMLStringbuf_SetLength(&RT->charsBuf, 0);
++
++ if (XMLHTable_Lookup(RT->entitiesTable, e.name) ||
++ (!(e.type == XML_ENTITY_INT_GEN || e.type == XML_ENTITY_EXT_GEN))) {
++ if (!ISNULLSTR(e.name)) free(e.name);
++ }
++ else {
++ /* append entity into RT->entities vector and
++ into RT->entitiesTable hashtable: */
++ if (!(XMLVector_Append(RT->entities, &e)))
++ return Err(parser, ERR_XMLP_MEMORY_ALLOC);
++ if (!(XMLHTable_Insert(RT->entitiesTable, e.name,
++ (void*)RT->entities->length)))
++ return Err(parser, ERR_XMLP_MEMORY_ALLOC);
++ }
++ return 1;
++}
++
++/*===========================================================================
++ FUNCTION
++ ParseEntityContent
++ DESC
++ Prepares new reader and parses entity in content
++ PARAMS
++ parser this
++ e entity to be parsed
++ NOTES
++ Every parsed entity needs its own entityReader 'cos calls might be
++ recursive. There must also be tmpReader that saves PREADER and restores it
++ after ParseInput call. These are simply kept in local variable stack.
++===========================================================================*/
++static void ParseEntityContent(LPXMLPARSER parser, LPXMLENTITY e)
++{
++ BUFFEREDISTREAM entityReader; /* these are */
++ BISREADERDATA readerdata; /* kept in local */
++ LPBUFFEREDISTREAM tmpReader = PREADER; /* stack while parsing entity */
++
++ if (parser->ErrorCode) return;
++
++ if (HANDLER(startEntity)) {
++ if (HANDLER(startEntity)(parser->UserData, e) == XML_ABORT) {
++ Err(parser, ERR_XMLP_ABORT);
++ return;
++ }
++ }
++
++ BufferedIStream_Init(&entityReader, BIS_DEFAULT_BLOCKSIZE);
++ readerdata.line = readerdata.col = readerdata.noPos =
++ readerdata.ubufsize = 0;
++ readerdata.curEnt = e; /* for current systemID etc. */
++ readerdata.parser = parser;
++ readerdata.stackLevel = RT->tagstack->length;
++ entityReader.userdata = &readerdata;
++ PREADER = &entityReader;
++ e->open = 1; /* set open flag for recursion tracking */
++
++ if (e->type == XML_ENTITY_INT_GEN) {
++ /* parse internal general entities from XMLMEMINPUTSRC: */
++ XMLMEMINPUTSRC mementityinput;
++ XML_CHARACTERS_HANDLER savedWShandler = HANDLER(ignorableWhitespace);
++
++ XMLMEMINPUTSRC_INIT(&mementityinput, e->value, e->len);
++ entityReader.inputData = &mementityinput;
++ entityReader.inputsrc = MemInputsrc;
++ /* savedWShandler is used here to allow whitespace only internal entities
++ like
(CRLF) to be reported as content */
++ HANDLER(ignorableWhitespace) = HANDLER(characters);
++ ParseInput(parser);
++ HANDLER(ignorableWhitespace) = savedWShandler;
++ }
++ else /* if (e->type == XML_ENTITY_EXT_GEN)*/ {
++ /* parse external general entities from user inputsrc: */
++ if (HANDLER(resolveEntity)) {
++ if (HANDLER(resolveEntity)(parser->UserData, e,
++ &entityReader) == XML_ABORT) {
++ Err(parser, ERR_XMLP_ABORT);
++ }
++ else {
++ if (entityReader.inputData) { /* parse it: */
++ /* if inputsrc is NULL, using parser's main inputsrc */
++ if (!entityReader.inputsrc)
++ entityReader.inputsrc = RT->refReader->inputsrc;
++ if (DetectEncoding(parser, 1, RT->refReader->encode))
++ ParseInput(parser);
++ if (HANDLER(externalEntityParsed)) {
++ /* give user chance to do the cleaning up: */
++ if (HANDLER(externalEntityParsed)(parser->UserData, e,
++ &entityReader) == XML_ABORT)
++ Err(parser, ERR_XMLP_ABORT);
++ }
++ }
++ }
++ }
++ }
++
++ if (!parser->ErrorCode) {
++ if (RT->tagstack->length > PREADERDATA->stackLevel) {
++ LPXMLRUNTIMETAG pTag = STACK_PEEK(RT->tagstack);
++ Err(parser, ERR_XMLP_UNCLOSED_TAG, pTag->qname);
++ }
++ else {
++ if (HANDLER(endEntity)) {
++ if (HANDLER(endEntity)(parser->UserData, e) == XML_ABORT)
++ Err(parser, ERR_XMLP_ABORT);
++ }
++ }
++ }
++
++ e->open = 0;
++ BufferedIStream_Free(&entityReader);
++ PREADER = tmpReader; /* restore parser's previous reader */
++}
++
++/* inputsrc for ParseEntityContent() internal entities: */
++static int MemInputsrc(BYTE *buf, int cBytes, int *cBytesActual, void *inputData)
++{
++ XMLMEMINPUTSRC_HANDLE
++}
++
++/*===========================================================================
++ FUNCTION
++ ParseIntEntityAtt
++ DESC
++ Parses entities in attribute buffer
++ PARAMS
++ parser this
++ e entity to be parsed
++ pAtt attribute for buffer manipulation
++ NOTES
++ Possibly calls itself (thru ParseEntityRef)
++ recursively and appends data to pAtt's valBuf
++===========================================================================*/
++static void ParseIntEntityAtt(LPXMLPARSER parser, LPXMLENTITY e,
++ LPXMLRUNTIMEATT pAtt)
++{
++ int chSize;
++ XMLCH *c;
++ XMLMEMINPUTSRC mementityinput;
++ BUFFEREDISTREAM entityReader;
++ BISREADERDATA readerdata;
++ LPBUFFEREDISTREAM tmpReader;
++
++ if (parser->ErrorCode) return;
++
++ if (e->type != XML_ENTITY_INT_GEN) {
++ Err(parser, ERR_XMLP_INVALID_ATT_VALUE, pAtt->qname);
++ return;
++ }
++
++ e->open = 1; /* set open flag for recursion tracking */
++ XMLMEMINPUTSRC_INIT(&mementityinput, e->value, e->len);
++ BufferedIStream_Init(&entityReader, e->len);
++ entityReader.inputData = &mementityinput;
++ entityReader.inputsrc = MemInputsrc;
++ entityReader.userdata = &readerdata;
++ readerdata.line = readerdata.col = readerdata.noPos =
++ readerdata.ubufsize = 0;
++ readerdata.curEnt = e;
++ readerdata.parser = parser;
++ tmpReader = PREADER;
++ PREADER = &entityReader;
++
++ while((c = ReadCh(parser, &chSize))) {
++ if (chSize == 1) {
++ if (isspace(*c)) {
++ if (!&pAtt->valBuf.len) continue; /* trim start */
++ if (ISNULLSTR(XMLStringbuf_AppendCh(&pAtt->valBuf, ' '))) {
++ Err(parser, ERR_XMLP_MEMORY_ALLOC);
++ break;
++ }
++ while((c = ReadCh(parser, &chSize))) { /* normalize */
++ if (chSize != 1) break;
++ if (!isspace(*c)) break;
++ }
++ if (!c) break;
++ }
++
++ if (*c == '&') {
++ if (!(ParseEntityRef(parser, &pAtt->valBuf, pAtt, 2))) break;
++ continue;
++ }
++ else if (*c == '<') {
++ ErrP(parser, ERR_XMLP_INVALID_TOKEN, 1);
++ break;
++ }
++ }
++ if (ISNULLSTR(XMLStringbuf_Append(&pAtt->valBuf, c, chSize))) {
++ Err(parser, ERR_XMLP_MEMORY_ALLOC);
++ break;
++ }
++ }
++ if (!parser->ErrorCode) {
++ if (pAtt->valBuf.len && pAtt->valBuf.str[pAtt->valBuf.len-1] == ' ')
++ pAtt->valBuf.len--; /* trim end */
++ }
++ e->open = 0;
++ BufferedIStream_Free(&entityReader);
++ PREADER = tmpReader;
++}
++
++#endif /* DTD_SUPPORT */
++
+Only in ./src: parsifal.lo
+Only in ./src: parsifal.o
+diff -r ../src.orig/src/xmlhash.c ./src/xmlhash.c
+--- ../src.orig/src/xmlhash.c Fri Oct 3 19:19:55 2003
++++ ./src/xmlhash.c Wed Jan 7 23:43:23 2004
+@@ -1,352 +1,352 @@
+-/*
+-** public domain code by Jerry Coffin, with improvements by HenkJan Wolthuis.
+-**
+-** Tested with Visual C 1.0 and Borland C 3.1.
+-** Compiles without warnings, and seems like it should be pretty
+-** portable.
+-*/
+-/*
+- Improvements by T. Uusitalo:
+-
+- + Hash algorithm replaced by new one (stolen from somewhere, can't remember...)
+- + All names of "global" functions changed
+- to more appropriate
+- XMLHTable_ form + parameter
+- order changed to more logical form.
+- + Bug fixed in _Enumerate (see comment in _Enumerate)
+- + got rid of global variables to make code thread safe.
+- + XMLHTable_Destroy uses optional enumeration function
+- for freeing user memory
+-...
+- Still, most CREDITS GO TO COFFIN... ;)
+-*/
+-
+-#include
+-#include
+-#include "xmlhash.h"
+-
+-static unsigned char rand8[] = {
+- 41, 35,190,132,225,108,214,174,
+- 82,144, 73,241,187,233,235,179,
+- 166,219, 60,135, 12, 62,153, 36,
+- 94, 13, 28, 6,183, 71,222, 18,
+- 77,200, 67,139, 31, 3, 90,125,
+- 9, 56, 37, 93,212,203,252,150,
+- 245, 69, 59, 19,137, 10, 50, 32,
+- 154, 80,238, 64,120, 54,253,246,
+- 158,220,173, 79, 20,242, 68,102,
+- 208,107,196, 48,161, 34,145,157,
+- 218,176,202, 2,185,114, 44,128,
+- 126,197,213,178,234,201,204, 83,
+- 191,103, 45,142,131,239, 87, 97,
+- 255,105,143,205,209, 30,156, 22,
+- 230, 29,240, 74,119,215,232, 57,
+- 51,116,244,159,164, 89, 53,207,
+- 211, 72,117,217, 42,229,192,247,
+- 43,129, 14, 95, 0,141,123, 5,
+- 21, 7,130, 24,112,146,100, 84,
+- 206,177,133,248, 70,106, 4,115,
+- 47,104,118,250, 17,136,121,254,
+- 216, 40, 11, 96, 61,151, 39,138,
+- 194, 8,165,193,140,169,149,155,
+- 168,167,134,181,231, 85, 78,113,
+- 226,180,101,122, 99, 38,223,109,
+- 98,224, 52, 63,227, 65, 15, 27,
+- 243,160,127,170, 91,184, 58, 16,
+- 76,236, 49, 66,124,228, 33,147,
+- 175,111, 1, 23, 86,198,249, 55,
+- 189,110, 92,195,163,152,199,182,
+- 81, 25, 46,188,148, 75, 88,210,
+- 172, 26,162,237,251,221,186,171};
+-
+-/*
+-** Hashes a string to produce an unsigned short, which should be
+-** sufficient for most purposes.
+-*/
+-
+-static unsigned hash(char *str, size_t n)
+-{
+- if (n < 256) {
+- unsigned char h = 0;
+- while (*str) { h = rand8[h ^ *str]; str++; }
+- return h % n;
+- } else {
+- int h;
+- unsigned char h1, h2;
+-
+- if (*str == 0) return 0;
+- h1 = *str; h2 = *str + 1;
+- str++;
+- while (*str) {
+- h1 = rand8[h1 ^ *str];
+- h2 = rand8[h2 ^ *str];
+- str++;
+- }
+-
+- /* h is in range 0..65535 */
+- h = ((int)h1 << 8)|(int)h2;
+- /* use division method to scale */
+- return h % n;
+- }
+-}
+-
+-/* modified 072002 end */
+-
+-/* Initialize the XMLHTABLE to the size asked for. Allocates space
+-** for the correct number of pointers and sets them to NULL. If it
+-** can't allocate sufficient memory, signals error by setting the size
+-** of the table to 0.
+-*/
+-
+-LPXMLHTABLE XMLHTable_Create(LPXMLHTABLE table, size_t size)
+-{
+- size_t i;
+- XMLHTABLEBUCKET **temp;
+-
+- table -> size = size;
+- table -> table = (XMLHTABLEBUCKET * *)malloc(sizeof(XMLHTABLEBUCKET *) * size);
+- temp = table -> table;
+-
+- if ( temp == NULL )
+- {
+- table -> size = 0;
+- return table;
+- }
+-
+- for (i=0;isize); //hash(key) % table->size;
+- XMLHTABLEBUCKET *ptr;
+-
+- /*
+- ** NULL means this XMLHTABLEBUCKET hasn't been used yet. We'll simply
+- ** allocate space for our new XMLHTABLEBUCKET and put our data there, with
+- ** the table pointing at it.
+- */
+-
+- if (NULL == (table->table)[val])
+- {
+- (table->table)[val] = (XMLHTABLEBUCKET *)malloc(sizeof(XMLHTABLEBUCKET));
+- if (NULL==(table->table)[val])
+- return NULL;
+-
+- (table->table)[val] -> key = strdup(key);
+- (table->table)[val] -> next = NULL;
+- (table->table)[val] -> data = data;
+- return (table->table)[val] -> data;
+- }
+-
+- /*
+- ** This spot in the table is already in use. See if the current string
+- ** has already been inserted, and if so, increment its count.
+- */
+-
+- for (ptr = (table->table)[val];NULL != ptr; ptr = ptr -> next)
+- if (0 == strcmp(key, ptr->key))
+- {
+- void *old_data;
+-
+- old_data = ptr->data;
+- ptr -> data = data;
+- return old_data;
+- }
+-
+- /*
+- ** This key must not be in the table yet. We'll add it to the head of
+- ** the list at this spot in the hash table. Speed would be
+- ** slightly improved if the list was kept sorted instead. In this case,
+- ** this code would be moved into the loop above, and the insertion would
+- ** take place as soon as it was determined that the present key in the
+- ** list was larger than this one.
+- */
+-
+- ptr = (XMLHTABLEBUCKET *)malloc(sizeof(XMLHTABLEBUCKET));
+- if (NULL==ptr)
+- return 0;
+- ptr -> key = strdup(key);
+- ptr -> data = data;
+- ptr -> next = (table->table)[val];
+- (table->table)[val] = ptr;
+- return data;
+-}
+-
+-
+-/*
+-** Look up a key and return the associated data. Returns NULL if
+-** the key is not in the table.
+-*/
+-
+-void *XMLHTable_Lookup(LPXMLHTABLE table, char *key)
+-{
+- unsigned val = hash(key, table->size); //hash(key) % table->size;
+- XMLHTABLEBUCKET *ptr;
+-
+- if (NULL == (table->table)[val])
+- return NULL;
+-
+- for ( ptr = (table->table)[val];NULL != ptr; ptr = ptr->next )
+- {
+- if (0 == strcmp(key, ptr -> key ) )
+- return ptr->data;
+- }
+- return NULL;
+-}
+-
+-/*
+-** Delete a key from the hash table and return associated
+-** data, or NULL if not present.
+-*/
+-
+-void *XMLHTable_Remove(LPXMLHTABLE table, char *key)
+-{
+- unsigned val = hash(key, table->size); //hash(key) % table->size;
+- void *data;
+- XMLHTABLEBUCKET *ptr, *last = NULL;
+-
+- if (NULL == (table->table)[val])
+- return NULL;
+-
+- /*
+- ** Traverse the list, keeping track of the previous node in the list.
+- ** When we find the node to delete, we set the previous node's next
+- ** pointer to point to the node after ourself instead. We then delete
+- ** the key from the present node, and return a pointer to the data it
+- ** contains.
+- */
+-
+- for (last = NULL, ptr = (table->table)[val];
+- NULL != ptr;
+- last = ptr, ptr = ptr->next)
+- {
+- if (0 == strcmp(key, ptr -> key))
+- {
+- if (last != NULL )
+- {
+- data = ptr -> data;
+- last -> next = ptr -> next;
+- free(ptr->key);
+- free(ptr);
+- return data;
+- }
+-
+- /*
+- ** If 'last' still equals NULL, it means that we need to
+- ** delete the first node in the list. This simply consists
+- ** of putting our own 'next' pointer in the array holding
+- ** the head of the list. We then dispose of the current
+- ** node as above.
+- */
+-
+- else
+- {
+- data = ptr->data;
+- (table->table)[val] = ptr->next;
+- free(ptr->key);
+- free(ptr);
+- return data;
+- }
+- }
+- }
+-
+- /*
+- ** If we get here, it means we didn't find the item in the table.
+- ** Signal this by returning NULL.
+- */
+-
+- return NULL;
+-}
+-
+-/*
+-** free_table iterates the table, calling this repeatedly to free
+-** each individual node.
+-*/
+-
+-static int free_node(char *key, void *data, void *table)
+-{
+- XMLHTable_Remove((LPXMLHTABLE)table,key);
+- return 0;
+-}
+-
+-/*
+-** Frees a complete table by iterating over it and freeing each node.
+-** the second parameter is the address of a function similar to
+-** function param to _Enumerate (with exception of last param
+-** being the table itself), when spesified, function is
+-** responsible for freeing the item in table. For example the
+-** following function removes item from table and frees char data
+-** associated with it:
+-
+- void destroyTableProc(char *key, void *data, LPXMLHTABLE table)
+- {
+- XMLHTable_Remove(table, key);
+- if (data!=(char*)NULL) free(data);
+- }
+-
+-** if func param isn't spesified, _Destroy frees the table items
+-** which is suitable in situations where data isn't dynamically
+-** allocated and thus can't be freed.
+-*/
+-
+-int XMLHTable_Destroy(LPXMLHTABLE table, int (*func)(char *, void *, void *), int FreeTable)
+-{
+- int ret;
+- table->userdata = table; // can use userdata, since it will be trashed anyway...
+-
+- if (!func)
+- ret = XMLHTable_Enumerate(table, free_node);
+- else
+- ret = XMLHTable_Enumerate(table, func);
+-
+- table->userdata = NULL;
+-
+- if (FreeTable) {
+- free(table->table);
+- table->table = NULL;
+- table->size = 0;
+- }
+- return ret;
+-}
+-
+-/*
+-** Simply invokes the function given as the second parameter for each
+-** node in the table, passing it the key and the associated data +
+-** userdata (can be pointer to destination table if Enumerate is used
+-** for copying hashtable for example).
+-*/
+-
+-int XMLHTable_Enumerate(LPXMLHTABLE table, int (*func)(char *, void *, void *))
+-{
+- unsigned i, ret;
+- XMLHTABLEBUCKET *temp, *next;
+-
+- for (i=0;isize; i++)
+- {
+- if ((table->table)[i] != NULL)
+- {
+- for (temp = (table->table)[i];
+- NULL != temp;
+- /*temp = temp -> next
+- bug fix: have to save next>
+- to since it might get destroyed!
+- */
+- temp = next)
+- {
+- next = temp->next;
+- if ((ret = func(temp->key, (void*)temp->data, table->userdata))) return ret;
+- }
+- }
+- }
+- return 0;
+-}
+-
++/*
++** public domain code by Jerry Coffin, with improvements by HenkJan Wolthuis.
++**
++** Tested with Visual C 1.0 and Borland C 3.1.
++** Compiles without warnings, and seems like it should be pretty
++** portable.
++*/
++/*
++ Improvements by T. Uusitalo:
++
++ + Hash algorithm replaced by new one (stolen from somewhere, can't remember...)
++ + All names of "global" functions changed
++ to more appropriate
++ XMLHTable_ form + parameter
++ order changed to more logical form.
++ + Bug fixed in _Enumerate (see comment in _Enumerate)
++ + got rid of global variables to make code thread safe.
++ + XMLHTable_Destroy uses optional enumeration function
++ for freeing user memory
++...
++ Still, most CREDITS GO TO COFFIN... ;)
++*/
++
++#include
++#include
++#include "xmlhash.h"
++
++static unsigned char rand8[] = {
++ 41, 35,190,132,225,108,214,174,
++ 82,144, 73,241,187,233,235,179,
++ 166,219, 60,135, 12, 62,153, 36,
++ 94, 13, 28, 6,183, 71,222, 18,
++ 77,200, 67,139, 31, 3, 90,125,
++ 9, 56, 37, 93,212,203,252,150,
++ 245, 69, 59, 19,137, 10, 50, 32,
++ 154, 80,238, 64,120, 54,253,246,
++ 158,220,173, 79, 20,242, 68,102,
++ 208,107,196, 48,161, 34,145,157,
++ 218,176,202, 2,185,114, 44,128,
++ 126,197,213,178,234,201,204, 83,
++ 191,103, 45,142,131,239, 87, 97,
++ 255,105,143,205,209, 30,156, 22,
++ 230, 29,240, 74,119,215,232, 57,
++ 51,116,244,159,164, 89, 53,207,
++ 211, 72,117,217, 42,229,192,247,
++ 43,129, 14, 95, 0,141,123, 5,
++ 21, 7,130, 24,112,146,100, 84,
++ 206,177,133,248, 70,106, 4,115,
++ 47,104,118,250, 17,136,121,254,
++ 216, 40, 11, 96, 61,151, 39,138,
++ 194, 8,165,193,140,169,149,155,
++ 168,167,134,181,231, 85, 78,113,
++ 226,180,101,122, 99, 38,223,109,
++ 98,224, 52, 63,227, 65, 15, 27,
++ 243,160,127,170, 91,184, 58, 16,
++ 76,236, 49, 66,124,228, 33,147,
++ 175,111, 1, 23, 86,198,249, 55,
++ 189,110, 92,195,163,152,199,182,
++ 81, 25, 46,188,148, 75, 88,210,
++ 172, 26,162,237,251,221,186,171};
++
++/*
++** Hashes a string to produce an unsigned short, which should be
++** sufficient for most purposes.
++*/
++
++static unsigned hash(char *str, size_t n)
++{
++ if (n < 256) {
++ unsigned char h = 0;
++ while (*str) { h = rand8[h ^ *str]; str++; }
++ return h % n;
++ } else {
++ int h;
++ unsigned char h1, h2;
++
++ if (*str == 0) return 0;
++ h1 = *str; h2 = *str + 1;
++ str++;
++ while (*str) {
++ h1 = rand8[h1 ^ *str];
++ h2 = rand8[h2 ^ *str];
++ str++;
++ }
++
++ /* h is in range 0..65535 */
++ h = ((int)h1 << 8)|(int)h2;
++ /* use division method to scale */
++ return h % n;
++ }
++}
++
++/* modified 072002 end */
++
++/* Initialize the XMLHTABLE to the size asked for. Allocates space
++** for the correct number of pointers and sets them to NULL. If it
++** can't allocate sufficient memory, signals error by setting the size
++** of the table to 0.
++*/
++
++LPXMLHTABLE XMLHTable_Create(LPXMLHTABLE table, size_t size)
++{
++ size_t i;
++ XMLHTABLEBUCKET **temp;
++
++ table -> size = size;
++ table -> table = (XMLHTABLEBUCKET * *)malloc(sizeof(XMLHTABLEBUCKET *) * size);
++ temp = table -> table;
++
++ if ( temp == NULL )
++ {
++ table -> size = 0;
++ return table;
++ }
++
++ for (i=0;isize); //hash(key) % table->size;
++ XMLHTABLEBUCKET *ptr;
++
++ /*
++ ** NULL means this XMLHTABLEBUCKET hasn't been used yet. We'll simply
++ ** allocate space for our new XMLHTABLEBUCKET and put our data there, with
++ ** the table pointing at it.
++ */
++
++ if (NULL == (table->table)[val])
++ {
++ (table->table)[val] = (XMLHTABLEBUCKET *)malloc(sizeof(XMLHTABLEBUCKET));
++ if (NULL==(table->table)[val])
++ return NULL;
++
++ (table->table)[val] -> key = strdup(key);
++ (table->table)[val] -> next = NULL;
++ (table->table)[val] -> data = data;
++ return (table->table)[val] -> data;
++ }
++
++ /*
++ ** This spot in the table is already in use. See if the current string
++ ** has already been inserted, and if so, increment its count.
++ */
++
++ for (ptr = (table->table)[val];NULL != ptr; ptr = ptr -> next)
++ if (0 == strcmp(key, ptr->key))
++ {
++ void *old_data;
++
++ old_data = ptr->data;
++ ptr -> data = data;
++ return old_data;
++ }
++
++ /*
++ ** This key must not be in the table yet. We'll add it to the head of
++ ** the list at this spot in the hash table. Speed would be
++ ** slightly improved if the list was kept sorted instead. In this case,
++ ** this code would be moved into the loop above, and the insertion would
++ ** take place as soon as it was determined that the present key in the
++ ** list was larger than this one.
++ */
++
++ ptr = (XMLHTABLEBUCKET *)malloc(sizeof(XMLHTABLEBUCKET));
++ if (NULL==ptr)
++ return 0;
++ ptr -> key = strdup(key);
++ ptr -> data = data;
++ ptr -> next = (table->table)[val];
++ (table->table)[val] = ptr;
++ return data;
++}
++
++
++/*
++** Look up a key and return the associated data. Returns NULL if
++** the key is not in the table.
++*/
++
++void *XMLHTable_Lookup(LPXMLHTABLE table, char *key)
++{
++ unsigned val = hash(key, table->size); //hash(key) % table->size;
++ XMLHTABLEBUCKET *ptr;
++
++ if (NULL == (table->table)[val])
++ return NULL;
++
++ for ( ptr = (table->table)[val];NULL != ptr; ptr = ptr->next )
++ {
++ if (0 == strcmp(key, ptr -> key ) )
++ return ptr->data;
++ }
++ return NULL;
++}
++
++/*
++** Delete a key from the hash table and return associated
++** data, or NULL if not present.
++*/
++
++void *XMLHTable_Remove(LPXMLHTABLE table, char *key)
++{
++ unsigned val = hash(key, table->size); //hash(key) % table->size;
++ void *data;
++ XMLHTABLEBUCKET *ptr, *last = NULL;
++
++ if (NULL == (table->table)[val])
++ return NULL;
++
++ /*
++ ** Traverse the list, keeping track of the previous node in the list.
++ ** When we find the node to delete, we set the previous node's next
++ ** pointer to point to the node after ourself instead. We then delete
++ ** the key from the present node, and return a pointer to the data it
++ ** contains.
++ */
++
++ for (last = NULL, ptr = (table->table)[val];
++ NULL != ptr;
++ last = ptr, ptr = ptr->next)
++ {
++ if (0 == strcmp(key, ptr -> key))
++ {
++ if (last != NULL )
++ {
++ data = ptr -> data;
++ last -> next = ptr -> next;
++ free(ptr->key);
++ free(ptr);
++ return data;
++ }
++
++ /*
++ ** If 'last' still equals NULL, it means that we need to
++ ** delete the first node in the list. This simply consists
++ ** of putting our own 'next' pointer in the array holding
++ ** the head of the list. We then dispose of the current
++ ** node as above.
++ */
++
++ else
++ {
++ data = ptr->data;
++ (table->table)[val] = ptr->next;
++ free(ptr->key);
++ free(ptr);
++ return data;
++ }
++ }
++ }
++
++ /*
++ ** If we get here, it means we didn't find the item in the table.
++ ** Signal this by returning NULL.
++ */
++
++ return NULL;
++}
++
++/*
++** free_table iterates the table, calling this repeatedly to free
++** each individual node.
++*/
++
++static int free_node(char *key, void *data, void *table)
++{
++ XMLHTable_Remove((LPXMLHTABLE)table,key);
++ return 0;
++}
++
++/*
++** Frees a complete table by iterating over it and freeing each node.
++** the second parameter is the address of a function similar to
++** function param to _Enumerate (with exception of last param
++** being the table itself), when spesified, function is
++** responsible for freeing the item in table. For example the
++** following function removes item from table and frees char data
++** associated with it:
++
++ void destroyTableProc(char *key, void *data, LPXMLHTABLE table)
++ {
++ XMLHTable_Remove(table, key);
++ if (data!=(char*)NULL) free(data);
++ }
++
++** if func param isn't spesified, _Destroy frees the table items
++** which is suitable in situations where data isn't dynamically
++** allocated and thus can't be freed.
++*/
++
++int XMLHTable_Destroy(LPXMLHTABLE table, int (*func)(char *, void *, void *), int FreeTable)
++{
++ int ret;
++ table->userdata = table; // can use userdata, since it will be trashed anyway...
++
++ if (!func)
++ ret = XMLHTable_Enumerate(table, free_node);
++ else
++ ret = XMLHTable_Enumerate(table, func);
++
++ table->userdata = NULL;
++
++ if (FreeTable) {
++ free(table->table);
++ table->table = NULL;
++ table->size = 0;
++ }
++ return ret;
++}
++
++/*
++** Simply invokes the function given as the second parameter for each
++** node in the table, passing it the key and the associated data +
++** userdata (can be pointer to destination table if Enumerate is used
++** for copying hashtable for example).
++*/
++
++int XMLHTable_Enumerate(LPXMLHTABLE table, int (*func)(char *, void *, void *))
++{
++ unsigned i, ret;
++ XMLHTABLEBUCKET *temp, *next;
++
++ for (i=0;isize; i++)
++ {
++ if ((table->table)[i] != NULL)
++ {
++ for (temp = (table->table)[i];
++ NULL != temp;
++ /*temp = temp -> next
++ bug fix: have to save next>
++ to since it might get destroyed!
++ */
++ temp = next)
++ {
++ next = temp->next;
++ if ((ret = func(temp->key, (void*)temp->data, table->userdata))) return ret;
++ }
++ }
++ }
++ return 0;
++}
++
+Only in ./src: xmlhash.lo
+Only in ./src: xmlhash.o
+diff -r ../src.orig/src/xmlsbuf.c ./src/xmlsbuf.c
+--- ../src.orig/src/xmlsbuf.c Thu Oct 2 20:03:08 2003
++++ ./src/xmlsbuf.c Wed Jan 7 23:43:23 2004
+@@ -1,111 +1,111 @@
+-/*===========================================================================
+- xmlsbuf.c
+- This module contains simple StringBuffer for Parsifal XML Parser
+- see parsifal.h for copyright info
+-
+- USAGE
+- _Init buffer and _Append strings to it. when you're done, call:
+- XMLCH *mystr = XMLStringbuf_ToString(&sb);
+- if you want to keep the string and reuse StringBuf: call _Init again
+- (after that you must free mystr yourself of course) or
+- call _SetLength (see _SetLength comment).
+- NOTE: you might want to use strdup(XMLStringbuf_ToString(&sb))
+- to ensure that you get yourself string from local heap.
+-===========================================================================*/
+-
+-#include
+-#include
+-#include "xmlsbuf.h"
+-
+-#define GROWSBUF(l) \
+-if (sbuf->useStatic) { \
+- if ((sbuf->len + (l)) > XMLSTRINGBUF_STATICSIZE) { \
+- sbuf->useStatic = 0; \
+- sbuf->capacity = COUNTBUFSIZE((sbuf->len + (l)), sbuf->blocksize); \
+- sbuf->str = (XMLCH*)malloc(sbuf->capacity * sizeof(XMLCH)); \
+- if (!sbuf->str) return ((XMLCH*)NULL); \
+- memcpy(sbuf->str, sbuf->storage, sbuf->len); \
+- } \
+-} \
+-else if ((sbuf->len + (l)) > sbuf->capacity) { \
+- sbuf->capacity = COUNTBUFSIZE((sbuf->len + (l)), sbuf->blocksize); \
+- sbuf->str = (XMLCH*)realloc(sbuf->str, sbuf->capacity * sizeof(XMLCH)); \
+- if (!sbuf->str) return ((XMLCH*)NULL); \
+-}
+-
+-XMLCH XMLAPI *XMLStringbuf_Append(LPXMLSTRINGBUF sbuf, XMLCH *str, int len)
+-{
+- XMLCH *s;
+- GROWSBUF(len);
+- s = sbuf->str+sbuf->len;
+- sbuf->len += len;
+- while (len--)
+- *s++ = *str++;
+- return (sbuf->str);
+-}
+-
+-XMLCH XMLAPI *XMLStringbuf_AppendCh(LPXMLSTRINGBUF sbuf, XMLCH c)
+-{
+- GROWSBUF(1);
+- sbuf->str[sbuf->len] = c;
+- sbuf->len++;
+- return (sbuf->str);
+-}
+-
+-XMLCH XMLAPI *XMLStringbuf_Init(LPXMLSTRINGBUF sbuf, int blockSize, int initSize)
+-{
+- sbuf->len = 0;
+- sbuf->blocksize = blockSize;
+-
+- if (initSize > XMLSTRINGBUF_STATICSIZE) {
+- sbuf->useStatic = 0;
+- sbuf->capacity = initSize;
+- sbuf->str = (XMLCH*)malloc(sbuf->capacity * sizeof(XMLCH));
+- return sbuf->str;
+- }
+- else {
+- sbuf->capacity = 0;
+- sbuf->useStatic = 1;
+- sbuf->str = sbuf->storage;
+- return sbuf->str;
+- }
+-}
+-
+-void XMLAPI XMLStringbuf_Free(LPXMLSTRINGBUF sbuf)
+-{
+- sbuf->len = sbuf->capacity = 0;
+- if (!sbuf->useStatic) {
+- if (sbuf->str) free(sbuf->str);
+- sbuf->str = (XMLCH*)NULL;
+- }
+-}
+-
+-/* SetLength can be used to truncate buffer to certain length or to
+- initialize buffer to be reused (setting length to 0).
+- _SetLength adjusts stringbuffer capacity unlike setting sbuf.len member directly.
+- note: SetLength returns TRUE on success, FALSE on failure (mem alloc problem) */
+-int XMLAPI XMLStringbuf_SetLength(LPXMLSTRINGBUF sbuf, int len)
+-{
+- if (sbuf->useStatic) {
+- if (len > XMLSTRINGBUF_STATICSIZE) return 0;
+- sbuf->len = len;
+- }
+- else if (sbuf->str && len != sbuf->len) {
+- sbuf->len = len;
+- len = (len) ? (COUNTBUFSIZE(len, sbuf->blocksize)) : sbuf->blocksize;
+- if (len != sbuf->capacity) {
+- sbuf->capacity = len;
+- sbuf->str = (XMLCH*)realloc(sbuf->str, sbuf->capacity * sizeof(XMLCH));
+- return ((sbuf->str) ? -1 : 0);
+- }
+- }
+- return -1;
+-}
+-
+-XMLCH XMLAPI *XMLStringbuf_ToString(LPXMLSTRINGBUF sbuf)
+-{
+- GROWSBUF(1);
+- if (sbuf->str[sbuf->len]) sbuf->str[sbuf->len] = '\0';
+- return (sbuf->str);
+-}
+-
++/*===========================================================================
++ xmlsbuf.c
++ This module contains simple StringBuffer for Parsifal XML Parser
++ see parsifal.h for copyright info
++
++ USAGE
++ _Init buffer and _Append strings to it. when you're done, call:
++ XMLCH *mystr = XMLStringbuf_ToString(&sb);
++ if you want to keep the string and reuse StringBuf: call _Init again
++ (after that you must free mystr yourself of course) or
++ call _SetLength (see _SetLength comment).
++ NOTE: you might want to use strdup(XMLStringbuf_ToString(&sb))
++ to ensure that you get yourself string from local heap.
++===========================================================================*/
++
++#include
++#include
++#include "xmlsbuf.h"
++
++#define GROWSBUF(l) \
++if (sbuf->useStatic) { \
++ if ((sbuf->len + (l)) > XMLSTRINGBUF_STATICSIZE) { \
++ sbuf->useStatic = 0; \
++ sbuf->capacity = COUNTBUFSIZE((sbuf->len + (l)), sbuf->blocksize); \
++ sbuf->str = (XMLCH*)malloc(sbuf->capacity * sizeof(XMLCH)); \
++ if (!sbuf->str) return ((XMLCH*)NULL); \
++ memcpy(sbuf->str, sbuf->storage, sbuf->len); \
++ } \
++} \
++else if ((sbuf->len + (l)) > sbuf->capacity) { \
++ sbuf->capacity = COUNTBUFSIZE((sbuf->len + (l)), sbuf->blocksize); \
++ sbuf->str = (XMLCH*)realloc(sbuf->str, sbuf->capacity * sizeof(XMLCH)); \
++ if (!sbuf->str) return ((XMLCH*)NULL); \
++}
++
++XMLCH XMLAPI *XMLStringbuf_Append(LPXMLSTRINGBUF sbuf, XMLCH *str, int len)
++{
++ XMLCH *s;
++ GROWSBUF(len);
++ s = sbuf->str+sbuf->len;
++ sbuf->len += len;
++ while (len--)
++ *s++ = *str++;
++ return (sbuf->str);
++}
++
++XMLCH XMLAPI *XMLStringbuf_AppendCh(LPXMLSTRINGBUF sbuf, XMLCH c)
++{
++ GROWSBUF(1);
++ sbuf->str[sbuf->len] = c;
++ sbuf->len++;
++ return (sbuf->str);
++}
++
++XMLCH XMLAPI *XMLStringbuf_Init(LPXMLSTRINGBUF sbuf, int blockSize, int initSize)
++{
++ sbuf->len = 0;
++ sbuf->blocksize = blockSize;
++
++ if (initSize > XMLSTRINGBUF_STATICSIZE) {
++ sbuf->useStatic = 0;
++ sbuf->capacity = initSize;
++ sbuf->str = (XMLCH*)malloc(sbuf->capacity * sizeof(XMLCH));
++ return sbuf->str;
++ }
++ else {
++ sbuf->capacity = 0;
++ sbuf->useStatic = 1;
++ sbuf->str = sbuf->storage;
++ return sbuf->str;
++ }
++}
++
++void XMLAPI XMLStringbuf_Free(LPXMLSTRINGBUF sbuf)
++{
++ sbuf->len = sbuf->capacity = 0;
++ if (!sbuf->useStatic) {
++ if (sbuf->str) free(sbuf->str);
++ sbuf->str = (XMLCH*)NULL;
++ }
++}
++
++/* SetLength can be used to truncate buffer to certain length or to
++ initialize buffer to be reused (setting length to 0).
++ _SetLength adjusts stringbuffer capacity unlike setting sbuf.len member directly.
++ note: SetLength returns TRUE on success, FALSE on failure (mem alloc problem) */
++int XMLAPI XMLStringbuf_SetLength(LPXMLSTRINGBUF sbuf, int len)
++{
++ if (sbuf->useStatic) {
++ if (len > XMLSTRINGBUF_STATICSIZE) return 0;
++ sbuf->len = len;
++ }
++ else if (sbuf->str && len != sbuf->len) {
++ sbuf->len = len;
++ len = (len) ? (COUNTBUFSIZE(len, sbuf->blocksize)) : sbuf->blocksize;
++ if (len != sbuf->capacity) {
++ sbuf->capacity = len;
++ sbuf->str = (XMLCH*)realloc(sbuf->str, sbuf->capacity * sizeof(XMLCH));
++ return ((sbuf->str) ? -1 : 0);
++ }
++ }
++ return -1;
++}
++
++XMLCH XMLAPI *XMLStringbuf_ToString(LPXMLSTRINGBUF sbuf)
++{
++ GROWSBUF(1);
++ if (sbuf->str[sbuf->len]) sbuf->str[sbuf->len] = '\0';
++ return (sbuf->str);
++}
++
+Only in ./src: xmlsbuf.lo
+Only in ./src: xmlsbuf.o
+diff -r ../src.orig/src/xmlvect.c ./src/xmlvect.c
+--- ../src.orig/src/xmlvect.c Fri Sep 26 21:25:50 2003
++++ ./src/xmlvect.c Wed Jan 7 23:43:23 2004
+@@ -1,174 +1,174 @@
+-/*===========================================================================
+- xmlvect.c
+- see parsifal.h for copyright info
+-===========================================================================*/
+-
+-#include
+-#include /* memmove */
+-#include "xmlvect.h"
+-
+-#define SETCAPACITY _SetCapacity
+-#define _SetCapacity(v,newsize) \
+-( (((v)->array = (BYTE*)realloc((v)->array, \
+-((newsize) * (v)->itemSize))) == (BYTE*)NULL) ? (LPXMLVECTOR)NULL : ((v)->capacity=(newsize), (v)) )
+-/*static LPXMLVECTOR SetCapacity(LPXMLVECTOR vector, int newsize);*/
+-
+-/*
+- Creates new vector. initialCapacity 0 sets capacity to
+- default capacityIncrement which is 6.
+- If you want to change capacityIncrement to 2 for example call:
+- LPXMLVECTOR v = XMLVector_Create(&v, 2, sizeof(int));
+- and after that set
+- v->capacityIncrement = 2;
+-
+- NOTE: All indices are 0-based.
+-*/
+-LPXMLVECTOR XMLAPI XMLVector_Create(LPXMLVECTOR *vector, int initialCapacity, int itemSize)
+-{
+- if (((LPXMLVECTOR)*vector = (LPXMLVECTOR)malloc(sizeof(XMLVECTOR))) == NULL)
+- return (LPXMLVECTOR)NULL;
+-
+- ((LPXMLVECTOR)*vector)->length = 0;
+- ((LPXMLVECTOR)*vector)->capacityIncrement = 6;
+- ((LPXMLVECTOR)*vector)->array = (BYTE*)NULL;
+- ((LPXMLVECTOR)*vector)->itemSize = itemSize;
+- return SETCAPACITY((LPXMLVECTOR)*vector,
+- ((initialCapacity) ? initialCapacity : ((LPXMLVECTOR)*vector)->capacityIncrement));
+-}
+-
+-/*
+- Frees the vector and data associated with it.
+-*/
+-void XMLAPI XMLVector_Free(LPXMLVECTOR vector)
+-{
+- if (vector->array != (BYTE*)NULL) free(vector->array);
+- free(vector);
+-}
+-
+-/*
+- Resizes vector. Can be used to truncate Vector i.e. to remove
+- items from the end of the vector or to clear the whole thing,
+- in this case works as XMLVector_RemoveAll macro.
+- If you set newsize to 0, capacity will be set default 6.
+- XMLVector_Resize Can be used to ensure capacity of newsize too (capacity
+- will be set nearest blocksize (capacityIncrement) that can
+- hold newsize num of items)
+- returns 1 if succesful, 0 otherwise.
+-*/
+-int XMLAPI XMLVector_Resize(LPXMLVECTOR vector, int newsize)
+-{
+- int newCapacity;
+-
+- if (!newsize) {
+- if (vector->capacity > vector->capacityIncrement) {
+- if(!(vector = SETCAPACITY(vector, vector->capacityIncrement))) return 0;
+- }
+- vector->length = 0;
+- return 1;
+- }
+-
+- newCapacity = COUNTBUFSIZE(newsize, vector->capacityIncrement);
+- if (newCapacity != vector->capacity) {
+- if(!(vector = SETCAPACITY(vector, newCapacity))) return 0;
+- }
+-
+- if (vector->length > newsize) vector->length = newsize;
+- return 1;
+-}
+-
+-void XMLAPI *XMLVector_Get(LPXMLVECTOR vector, int index)
+-{
+- return(_XMLVector_Get(vector, index));
+-}
+-
+-/*
+- Appends item at the end of the vector
+- returns pointer to current item if succesful, NULL otherwise.
+-*/
+-void XMLAPI *XMLVector_Append(LPXMLVECTOR vector, void *item)
+-{
+- void *cur;
+- if ((vector->length + 1) > vector->capacity) {
+- vector->capacity = COUNTBUFSIZE(vector->length + 1,
+- vector->capacityIncrement);
+- if(!(vector = SETCAPACITY(vector, vector->capacity))) return NULL;
+- }
+- cur = vector->array+vector->length*vector->itemSize;
+- if (item != NULL) memcpy(cur, item, vector->itemSize);
+- vector->length++;
+- return(cur);
+-}
+-
+-/*
+- Inserts item before specified index.
+- returns pointer to current item if succesful, NULL otherwise.
+-*/
+-void XMLAPI *XMLVector_InsertBefore(LPXMLVECTOR vector, int index, void *item)
+-{
+- void *cur;
+- if (!index && !vector->length) return XMLVector_Append(vector, item);
+- if (index < 0 || index > (vector->length - 1)) return NULL;
+-
+- if ((vector->length + 1) > vector->capacity) {
+- vector->capacity = COUNTBUFSIZE(vector->length + 1,
+- vector->capacityIncrement);
+- if(!(vector = SETCAPACITY(vector, vector->capacity))) return NULL;
+- }
+-
+- vector->length++;
+- cur = vector->array+index*vector->itemSize;
+- memmove(vector->array+((index+1)*vector->itemSize),
+- cur, (vector->length - index) * vector->itemSize);
+- if (item != NULL) memcpy(cur, item, vector->itemSize);
+- return(cur);
+-}
+-
+-/*
+- Replaces item at specified index.
+- returns pointer to current item if succesful, NULL otherwise.
+-*/
+-void XMLAPI *XMLVector_Replace(LPXMLVECTOR vector, int index, void *item)
+-{
+- if (index < 0 || index > (vector->length - 1)) {
+- return NULL;
+- }
+- else {
+- void *cur;
+- cur = vector->array+index*vector->itemSize;
+- if (item != NULL) memcpy(cur, item, vector->itemSize);
+- return(cur);
+- }
+-}
+-
+-/*
+- Removes item at specified index.
+- returns 1 if succesful, 0 otherwise.
+-*/
+-int XMLAPI XMLVector_Remove(LPXMLVECTOR vector, int index)
+-{
+- int newCapacity;
+- if (index < 0 || index > (vector->length - 1)) return 0;
+-
+- if (index != (--vector->length)) {
+- memmove(vector->array+index*vector->itemSize,
+- vector->array+((index+1)*vector->itemSize),
+- ((vector->length - index) + 1) * vector->itemSize);
+- }
+-
+- newCapacity = COUNTBUFSIZE(vector->length, vector->capacityIncrement);
+- if (newCapacity != vector->capacity) {
+- vector->capacity = newCapacity;
+- if(!(vector = SETCAPACITY(vector, vector->capacity))) return 0;
+- }
+- return 1;
+-}
+-
+-/*static
+-LPXMLVECTOR SetCapacity(LPXMLVECTOR vector, int newsize)
+-{
+- if ((vector->array = (BYTE*)realloc(vector->array,
+- (newsize * vector->itemSize))) == (BYTE*)NULL) return NULL;
+- vector->capacity = newsize;
+- return vector;
+-}*/
+-
++/*===========================================================================
++ xmlvect.c
++ see parsifal.h for copyright info
++===========================================================================*/
++
++#include
++#include /* memmove */
++#include "xmlvect.h"
++
++#define SETCAPACITY _SetCapacity
++#define _SetCapacity(v,newsize) \
++( (((v)->array = (BYTE*)realloc((v)->array, \
++((newsize) * (v)->itemSize))) == (BYTE*)NULL) ? (LPXMLVECTOR)NULL : ((v)->capacity=(newsize), (v)) )
++/*static LPXMLVECTOR SetCapacity(LPXMLVECTOR vector, int newsize);*/
++
++/*
++ Creates new vector. initialCapacity 0 sets capacity to
++ default capacityIncrement which is 6.
++ If you want to change capacityIncrement to 2 for example call:
++ LPXMLVECTOR v = XMLVector_Create(&v, 2, sizeof(int));
++ and after that set
++ v->capacityIncrement = 2;
++
++ NOTE: All indices are 0-based.
++*/
++LPXMLVECTOR XMLAPI XMLVector_Create(LPXMLVECTOR *vector, int initialCapacity, int itemSize)
++{
++ if (((LPXMLVECTOR)*vector = (LPXMLVECTOR)malloc(sizeof(XMLVECTOR))) == NULL)
++ return (LPXMLVECTOR)NULL;
++
++ ((LPXMLVECTOR)*vector)->length = 0;
++ ((LPXMLVECTOR)*vector)->capacityIncrement = 6;
++ ((LPXMLVECTOR)*vector)->array = (BYTE*)NULL;
++ ((LPXMLVECTOR)*vector)->itemSize = itemSize;
++ return SETCAPACITY((LPXMLVECTOR)*vector,
++ ((initialCapacity) ? initialCapacity : ((LPXMLVECTOR)*vector)->capacityIncrement));
++}
++
++/*
++ Frees the vector and data associated with it.
++*/
++void XMLAPI XMLVector_Free(LPXMLVECTOR vector)
++{
++ if (vector->array != (BYTE*)NULL) free(vector->array);
++ free(vector);
++}
++
++/*
++ Resizes vector. Can be used to truncate Vector i.e. to remove
++ items from the end of the vector or to clear the whole thing,
++ in this case works as XMLVector_RemoveAll macro.
++ If you set newsize to 0, capacity will be set default 6.
++ XMLVector_Resize Can be used to ensure capacity of newsize too (capacity
++ will be set nearest blocksize (capacityIncrement) that can
++ hold newsize num of items)
++ returns 1 if succesful, 0 otherwise.
++*/
++int XMLAPI XMLVector_Resize(LPXMLVECTOR vector, int newsize)
++{
++ int newCapacity;
++
++ if (!newsize) {
++ if (vector->capacity > vector->capacityIncrement) {
++ if(!(vector = SETCAPACITY(vector, vector->capacityIncrement))) return 0;
++ }
++ vector->length = 0;
++ return 1;
++ }
++
++ newCapacity = COUNTBUFSIZE(newsize, vector->capacityIncrement);
++ if (newCapacity != vector->capacity) {
++ if(!(vector = SETCAPACITY(vector, newCapacity))) return 0;
++ }
++
++ if (vector->length > newsize) vector->length = newsize;
++ return 1;
++}
++
++void XMLAPI *XMLVector_Get(LPXMLVECTOR vector, int index)
++{
++ return(_XMLVector_Get(vector, index));
++}
++
++/*
++ Appends item at the end of the vector
++ returns pointer to current item if succesful, NULL otherwise.
++*/
++void XMLAPI *XMLVector_Append(LPXMLVECTOR vector, void *item)
++{
++ void *cur;
++ if ((vector->length + 1) > vector->capacity) {
++ vector->capacity = COUNTBUFSIZE(vector->length + 1,
++ vector->capacityIncrement);
++ if(!(vector = SETCAPACITY(vector, vector->capacity))) return NULL;
++ }
++ cur = vector->array+vector->length*vector->itemSize;
++ if (item != NULL) memcpy(cur, item, vector->itemSize);
++ vector->length++;
++ return(cur);
++}
++
++/*
++ Inserts item before specified index.
++ returns pointer to current item if succesful, NULL otherwise.
++*/
++void XMLAPI *XMLVector_InsertBefore(LPXMLVECTOR vector, int index, void *item)
++{
++ void *cur;
++ if (!index && !vector->length) return XMLVector_Append(vector, item);
++ if (index < 0 || index > (vector->length - 1)) return NULL;
++
++ if ((vector->length + 1) > vector->capacity) {
++ vector->capacity = COUNTBUFSIZE(vector->length + 1,
++ vector->capacityIncrement);
++ if(!(vector = SETCAPACITY(vector, vector->capacity))) return NULL;
++ }
++
++ vector->length++;
++ cur = vector->array+index*vector->itemSize;
++ memmove(vector->array+((index+1)*vector->itemSize),
++ cur, (vector->length - index) * vector->itemSize);
++ if (item != NULL) memcpy(cur, item, vector->itemSize);
++ return(cur);
++}
++
++/*
++ Replaces item at specified index.
++ returns pointer to current item if succesful, NULL otherwise.
++*/
++void XMLAPI *XMLVector_Replace(LPXMLVECTOR vector, int index, void *item)
++{
++ if (index < 0 || index > (vector->length - 1)) {
++ return NULL;
++ }
++ else {
++ void *cur;
++ cur = vector->array+index*vector->itemSize;
++ if (item != NULL) memcpy(cur, item, vector->itemSize);
++ return(cur);
++ }
++}
++
++/*
++ Removes item at specified index.
++ returns 1 if succesful, 0 otherwise.
++*/
++int XMLAPI XMLVector_Remove(LPXMLVECTOR vector, int index)
++{
++ int newCapacity;
++ if (index < 0 || index > (vector->length - 1)) return 0;
++
++ if (index != (--vector->length)) {
++ memmove(vector->array+index*vector->itemSize,
++ vector->array+((index+1)*vector->itemSize),
++ ((vector->length - index) + 1) * vector->itemSize);
++ }
++
++ newCapacity = COUNTBUFSIZE(vector->length, vector->capacityIncrement);
++ if (newCapacity != vector->capacity) {
++ vector->capacity = newCapacity;
++ if(!(vector = SETCAPACITY(vector, vector->capacity))) return 0;
++ }
++ return 1;
++}
++
++/*static
++LPXMLVECTOR SetCapacity(LPXMLVECTOR vector, int newsize)
++{
++ if ((vector->array = (BYTE*)realloc(vector->array,
++ (newsize * vector->itemSize))) == (BYTE*)NULL) return NULL;
++ vector->capacity = newsize;
++ return vector;
++}*/
++
+Only in ./src: xmlvect.lo
+Only in ./src: xmlvect.o
+diff -r ../src.orig/win32/vc6/dllmain.c ./win32/vc6/dllmain.c
+--- ../src.orig/win32/vc6/dllmain.c Fri Nov 15 01:06:04 2002
++++ ./win32/vc6/dllmain.c Wed Jan 7 23:43:23 2004
+@@ -1,10 +1,10 @@
+-#define STRICT 1
+-#define WIN32_LEAN_AND_MEAN 1
+-
+-#include
+-
+-BOOL WINAPI DllMain(HANDLE hInst, ULONG ul_reason_for_call, LPVOID lpReserved)
+-{
+- return TRUE;
+-}
+-
++#define STRICT 1
++#define WIN32_LEAN_AND_MEAN 1
++
++#include
++
++BOOL WINAPI DllMain(HANDLE hInst, ULONG ul_reason_for_call, LPVOID lpReserved)
++{
++ return TRUE;
++}
++
| |